mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-15 02:11:05 +00:00
DatePicker rework (#737)
* fix(date-picker): append calendar to date picker element #345 Fixes #345 * fix(date-picker): do not import rangePlugin from esm folder * fix(date-picker): correctly type change event for single/range types * feat(date-picker): add valueFrom, valueTo for range datepicker * docs(date-picker): add range type example * docs(date-picker): extract range example to iframe * docs(date-picker): extract single type to iframe
This commit is contained in:
parent
569d7021cb
commit
edefd6429b
11 changed files with 139 additions and 56 deletions
|
@ -1048,10 +1048,11 @@ None.
|
||||||
### Props
|
### Props
|
||||||
|
|
||||||
| Prop name | Kind | Reactive | Type | Default value | Description |
|
| Prop name | Kind | Reactive | Type | Default value | Description |
|
||||||
| :------------- | :--------------- | :------- | :--------------------------------------------------- | ------------------------------------------------ | --------------------------------------------- |
|
| :------------- | :--------------- | :------- | :--------------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
|
||||||
|
| valueTo | <code>let</code> | Yes | <code>string</code> | <code>""</code> | Specify the date picker end date value (to)<br />Only works with the "range" date picker type |
|
||||||
|
| valueFrom | <code>let</code> | Yes | <code>string</code> | <code>""</code> | Specify the date picker start date value (from)<br />Only works with the "range" date picker type |
|
||||||
| value | <code>let</code> | Yes | <code>number | string</code> | <code>""</code> | Specify the date picker input value |
|
| value | <code>let</code> | Yes | <code>number | string</code> | <code>""</code> | Specify the date picker input value |
|
||||||
| datePickerType | <code>let</code> | No | <code>"simple" | "single" | "range"</code> | <code>"simple"</code> | Specify the date picker type |
|
| datePickerType | <code>let</code> | No | <code>"simple" | "single" | "range"</code> | <code>"simple"</code> | Specify the date picker type |
|
||||||
| appendTo | <code>let</code> | No | <code>HTMLElement</code> | -- | Specify the element to append the calendar to |
|
|
||||||
| dateFormat | <code>let</code> | No | <code>string</code> | <code>"m/d/Y"</code> | Specify the date format |
|
| dateFormat | <code>let</code> | No | <code>string</code> | <code>"m/d/Y"</code> | Specify the date format |
|
||||||
| maxDate | <code>let</code> | No | <code>null | string | Date</code> | <code>null</code> | Specify the maximum date |
|
| maxDate | <code>let</code> | No | <code>null | string | Date</code> | <code>null</code> | Specify the maximum date |
|
||||||
| minDate | <code>let</code> | No | <code>null | string | Date</code> | <code>null</code> | Specify the minimum date |
|
| minDate | <code>let</code> | No | <code>null | string | Date</code> | <code>null</code> | Specify the minimum date |
|
||||||
|
@ -1069,12 +1070,12 @@ None.
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
| Event name | Type | Detail |
|
| Event name | Type | Detail |
|
||||||
| :--------- | :--------- | :----- |
|
| :--------- | :--------- | :---------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| change | dispatched | <code>string | { selectedDates: [dateFrom: Date, dateTo?: Date]; dateStr: string | { from: string; to: string; } }</code> |
|
||||||
| click | forwarded | -- |
|
| click | forwarded | -- |
|
||||||
| mouseover | forwarded | -- |
|
| mouseover | forwarded | -- |
|
||||||
| mouseenter | forwarded | -- |
|
| mouseenter | forwarded | -- |
|
||||||
| mouseleave | forwarded | -- |
|
| mouseleave | forwarded | -- |
|
||||||
| change | dispatched | -- |
|
|
||||||
|
|
||||||
## `DatePickerInput`
|
## `DatePickerInput`
|
||||||
|
|
||||||
|
|
|
@ -2393,13 +2393,24 @@
|
||||||
"reactive": true
|
"reactive": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "appendTo",
|
"name": "valueFrom",
|
||||||
"kind": "let",
|
"kind": "let",
|
||||||
"description": "Specify the element to append the calendar to",
|
"description": "Specify the date picker start date value (from)\nOnly works with the \"range\" date picker type",
|
||||||
"type": "HTMLElement",
|
"type": "string",
|
||||||
|
"value": "\"\"",
|
||||||
"isFunction": false,
|
"isFunction": false,
|
||||||
"constant": false,
|
"constant": false,
|
||||||
"reactive": false
|
"reactive": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "valueTo",
|
||||||
|
"kind": "let",
|
||||||
|
"description": "Specify the date picker end date value (to)\nOnly works with the \"range\" date picker type",
|
||||||
|
"type": "string",
|
||||||
|
"value": "\"\"",
|
||||||
|
"isFunction": false,
|
||||||
|
"constant": false,
|
||||||
|
"reactive": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "dateFormat",
|
"name": "dateFormat",
|
||||||
|
@ -2474,11 +2485,15 @@
|
||||||
],
|
],
|
||||||
"slots": [{ "name": "__default__", "default": true, "slot_props": "{}" }],
|
"slots": [{ "name": "__default__", "default": true, "slot_props": "{}" }],
|
||||||
"events": [
|
"events": [
|
||||||
|
{
|
||||||
|
"type": "dispatched",
|
||||||
|
"name": "change",
|
||||||
|
"detail": "string | { selectedDates: [dateFrom: Date, dateTo?: Date]; dateStr: string | { from: string; to: string; } }"
|
||||||
|
},
|
||||||
{ "type": "forwarded", "name": "click", "element": "div" },
|
{ "type": "forwarded", "name": "click", "element": "div" },
|
||||||
{ "type": "forwarded", "name": "mouseover", "element": "div" },
|
{ "type": "forwarded", "name": "mouseover", "element": "div" },
|
||||||
{ "type": "forwarded", "name": "mouseenter", "element": "div" },
|
{ "type": "forwarded", "name": "mouseenter", "element": "div" },
|
||||||
{ "type": "forwarded", "name": "mouseleave", "element": "div" },
|
{ "type": "forwarded", "name": "mouseleave", "element": "div" }
|
||||||
{ "type": "dispatched", "name": "change" }
|
|
||||||
],
|
],
|
||||||
"typedefs": [],
|
"typedefs": [],
|
||||||
"rest_props": { "type": "Element", "name": "div" }
|
"rest_props": { "type": "Element", "name": "div" }
|
||||||
|
|
|
@ -57,9 +57,11 @@ components: ["DatePicker", "DatePickerInput", "DatePickerSkeleton"]
|
||||||
|
|
||||||
### Single
|
### Single
|
||||||
|
|
||||||
<DatePicker datePickerType="single">
|
<FileSource src="/framed/DatePicker/DatePickerSingle" />
|
||||||
<DatePickerInput labelText="Schedule a meeting" placeholder="mm/dd/yyyy" />
|
|
||||||
</DatePicker>
|
### Range
|
||||||
|
|
||||||
|
<FileSource src="/framed/DatePicker/DatePickerRange" />
|
||||||
|
|
||||||
### Skeleton
|
### Skeleton
|
||||||
|
|
||||||
|
|
8
docs/src/pages/framed/DatePicker/DatePickerRange.svelte
Normal file
8
docs/src/pages/framed/DatePicker/DatePickerRange.svelte
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<script>
|
||||||
|
import { DatePicker, DatePickerInput } from "carbon-components-svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DatePicker datePickerType="range" on:change>
|
||||||
|
<DatePickerInput labelText="Start date" placeholder="mm/dd/yyyy" />
|
||||||
|
<DatePickerInput labelText="End date" placeholder="mm/dd/yyyy" />
|
||||||
|
</DatePicker>
|
7
docs/src/pages/framed/DatePicker/DatePickerSingle.svelte
Normal file
7
docs/src/pages/framed/DatePicker/DatePickerSingle.svelte
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<script>
|
||||||
|
import { DatePicker, DatePickerInput } from "carbon-components-svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DatePicker datePickerType="single" on:change>
|
||||||
|
<DatePickerInput labelText="Meeting date" placeholder="mm/dd/yyyy" />
|
||||||
|
</DatePicker>
|
|
@ -1,6 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
include: ["clipboard-copy"],
|
include: ["clipboard-copy", "flatpickr/dist/plugins/rangePlugin"],
|
||||||
exclude: ["@sveltech/routify"],
|
exclude: ["@sveltech/routify"],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
/**
|
/**
|
||||||
* @dispatch {string} change
|
* @event {string | { selectedDates: [dateFrom: Date, dateTo?: Date]; dateStr: string | { from: string; to: string; } }} change
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,10 +16,18 @@
|
||||||
export let value = "";
|
export let value = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the element to append the calendar to
|
* Specify the date picker start date value (from)
|
||||||
* @type {HTMLElement}
|
* Only works with the "range" date picker type
|
||||||
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
export let appendTo = document.body;
|
export let valueFrom = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the date picker end date value (to)
|
||||||
|
* Only works with the "range" date picker type
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
export let valueTo = "";
|
||||||
|
|
||||||
/** Specify the date format */
|
/** Specify the date format */
|
||||||
export let dateFormat = "m/d/Y";
|
export let dateFormat = "m/d/Y";
|
||||||
|
@ -65,18 +73,23 @@
|
||||||
(_) => _.filter(({ labelText }) => !!labelText).length === 0
|
(_) => _.filter(({ labelText }) => !!labelText).length === 0
|
||||||
);
|
);
|
||||||
const inputValue = writable(value);
|
const inputValue = writable(value);
|
||||||
|
const inputValueFrom = writable(valueFrom);
|
||||||
|
const inputValueTo = writable(valueTo);
|
||||||
const mode = writable(datePickerType);
|
const mode = writable(datePickerType);
|
||||||
const range = derived(mode, (_) => _ === "range");
|
const range = derived(mode, (_) => _ === "range");
|
||||||
const hasCalendar = derived(mode, (_) => _ === "single" || _ === "range");
|
const hasCalendar = derived(mode, (_) => _ === "single" || _ === "range");
|
||||||
|
|
||||||
let calendar = undefined;
|
let calendar = null;
|
||||||
let datePickerRef = undefined;
|
let datePickerRef = null;
|
||||||
let inputRef = undefined;
|
let inputRef = null;
|
||||||
let inputRefTo = undefined;
|
let inputRefTo = null;
|
||||||
|
|
||||||
setContext("DatePicker", {
|
setContext("DatePicker", {
|
||||||
range,
|
range,
|
||||||
inputValue,
|
inputValue,
|
||||||
|
inputValueFrom,
|
||||||
|
inputValueTo,
|
||||||
|
inputIds,
|
||||||
hasCalendar,
|
hasCalendar,
|
||||||
add: (data) => {
|
add: (data) => {
|
||||||
inputs.update((_) => [..._, data]);
|
inputs.update((_) => [..._, data]);
|
||||||
|
@ -119,7 +132,7 @@
|
||||||
if ($hasCalendar && !calendar) {
|
if ($hasCalendar && !calendar) {
|
||||||
calendar = createCalendar({
|
calendar = createCalendar({
|
||||||
options: {
|
options: {
|
||||||
appendTo,
|
appendTo: datePickerRef,
|
||||||
dateFormat,
|
dateFormat,
|
||||||
defaultDate: $inputValue,
|
defaultDate: $inputValue,
|
||||||
locale,
|
locale,
|
||||||
|
@ -133,10 +146,16 @@
|
||||||
const detail = { selectedDates: calendar.selectedDates };
|
const detail = { selectedDates: calendar.selectedDates };
|
||||||
|
|
||||||
if ($range) {
|
if ($range) {
|
||||||
|
const from = inputRef.value;
|
||||||
|
const to = inputRefTo.value;
|
||||||
|
|
||||||
detail.dateStr = {
|
detail.dateStr = {
|
||||||
from: inputRef.value,
|
from: inputRef.value,
|
||||||
to: inputRefTo.value,
|
to: inputRefTo.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
valueFrom = from;
|
||||||
|
valueTo = to;
|
||||||
} else {
|
} else {
|
||||||
detail.dateStr = inputRef.value;
|
detail.dateStr = inputRef.value;
|
||||||
}
|
}
|
||||||
|
@ -146,9 +165,16 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calendar && !$range) {
|
if (calendar) {
|
||||||
|
if ($range) {
|
||||||
|
calendar.setDate([$inputValueFrom, $inputValueTo]);
|
||||||
|
|
||||||
|
// workaround to remove the default range plugin separator "to"
|
||||||
|
inputRef.value = $inputValueFrom;
|
||||||
|
} else {
|
||||||
calendar.setDate($inputValue);
|
calendar.setDate($inputValue);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
|
@ -159,19 +185,17 @@
|
||||||
|
|
||||||
$: inputValue.set(value);
|
$: inputValue.set(value);
|
||||||
$: value = $inputValue;
|
$: value = $inputValue;
|
||||||
|
$: inputValueFrom.set(valueFrom);
|
||||||
|
$: valueFrom = $inputValueFrom;
|
||||||
|
$: inputValueTo.set(valueTo);
|
||||||
|
$: valueTo = $inputValueTo;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:body
|
<svelte:body
|
||||||
on:click="{({ target }) => {
|
on:click="{({ target }) => {
|
||||||
if (!calendar || !calendar.isOpen) {
|
if (!calendar || !calendar.isOpen) return;
|
||||||
return;
|
if (datePickerRef && datePickerRef.contains(target)) return;
|
||||||
}
|
if (!calendar.calendarContainer.contains(target)) calendar.close();
|
||||||
if (datePickerRef && datePickerRef.contains(target)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!calendar.calendarContainer.contains(target)) {
|
|
||||||
calendar.close();
|
|
||||||
}
|
|
||||||
}}" />
|
}}" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -60,11 +60,14 @@
|
||||||
add,
|
add,
|
||||||
hasCalendar,
|
hasCalendar,
|
||||||
declareRef,
|
declareRef,
|
||||||
|
inputIds,
|
||||||
updateValue,
|
updateValue,
|
||||||
blurInput,
|
blurInput,
|
||||||
openCalendar,
|
openCalendar,
|
||||||
focusCalendar,
|
focusCalendar,
|
||||||
inputValue,
|
inputValue,
|
||||||
|
inputValueFrom,
|
||||||
|
inputValueTo,
|
||||||
} = getContext("DatePicker");
|
} = getContext("DatePicker");
|
||||||
|
|
||||||
add({ id, labelText });
|
add({ id, labelText });
|
||||||
|
@ -105,7 +108,11 @@
|
||||||
pattern="{pattern}"
|
pattern="{pattern}"
|
||||||
disabled="{disabled}"
|
disabled="{disabled}"
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
value="{!$range ? $inputValue : undefined}"
|
value="{$range
|
||||||
|
? $inputIds.indexOf(id) === 0
|
||||||
|
? $inputValueFrom
|
||||||
|
: $inputValueTo
|
||||||
|
: $inputValue}"
|
||||||
class:bx--date-picker__input="{true}"
|
class:bx--date-picker__input="{true}"
|
||||||
class:bx--date-picker__input--invalid="{invalid}"
|
class:bx--date-picker__input--invalid="{invalid}"
|
||||||
class="{size && `bx--date-picker__input--${size}`}"
|
class="{size && `bx--date-picker__input--${size}`}"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import flatpickr from "flatpickr";
|
import flatpickr from "flatpickr";
|
||||||
import rangePlugin from "flatpickr/dist/esm/plugins/rangePlugin";
|
import rangePlugin from "flatpickr/dist/plugins/rangePlugin";
|
||||||
|
|
||||||
let l10n;
|
let l10n;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
import { DatePicker, DatePickerSkeleton, DatePickerInput } from "../types";
|
import { DatePicker, DatePickerSkeleton, DatePickerInput } from "../types";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<DatePicker>
|
<DatePicker
|
||||||
|
on:change="{(e) => {
|
||||||
|
console.log(e.detail);
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<DatePickerInput labelText="Date of birth" placeholder="mm/dd/yyyy" />
|
<DatePickerInput labelText="Date of birth" placeholder="mm/dd/yyyy" />
|
||||||
</DatePicker>
|
</DatePicker>
|
||||||
|
|
||||||
|
@ -51,7 +55,7 @@
|
||||||
/>
|
/>
|
||||||
</DatePicker>
|
</DatePicker>
|
||||||
|
|
||||||
<DatePicker datePickerType="single">
|
<DatePicker valueFrom="" valueTo="" datePickerType="single">
|
||||||
<DatePickerInput labelText="Schedule a meeting" placeholder="mm/dd/yyyy" />
|
<DatePickerInput labelText="Schedule a meeting" placeholder="mm/dd/yyyy" />
|
||||||
</DatePicker>
|
</DatePicker>
|
||||||
|
|
||||||
|
|
21
types/DatePicker/DatePicker.d.ts
vendored
21
types/DatePicker/DatePicker.d.ts
vendored
|
@ -16,9 +16,18 @@ export interface DatePickerProps
|
||||||
value?: number | string;
|
value?: number | string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the element to append the calendar to
|
* Specify the date picker start date value (from)
|
||||||
|
* Only works with the "range" date picker type
|
||||||
|
* @default ""
|
||||||
*/
|
*/
|
||||||
appendTo?: HTMLElement;
|
valueFrom?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the date picker end date value (to)
|
||||||
|
* Only works with the "range" date picker type
|
||||||
|
* @default ""
|
||||||
|
*/
|
||||||
|
valueTo?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the date format
|
* Specify the date format
|
||||||
|
@ -66,11 +75,17 @@ export interface DatePickerProps
|
||||||
export default class DatePicker extends SvelteComponentTyped<
|
export default class DatePicker extends SvelteComponentTyped<
|
||||||
DatePickerProps,
|
DatePickerProps,
|
||||||
{
|
{
|
||||||
|
change: CustomEvent<
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
selectedDates: [dateFrom: Date, dateTo?: Date];
|
||||||
|
dateStr: string | { from: string; to: string };
|
||||||
|
}
|
||||||
|
>;
|
||||||
click: WindowEventMap["click"];
|
click: WindowEventMap["click"];
|
||||||
mouseover: WindowEventMap["mouseover"];
|
mouseover: WindowEventMap["mouseover"];
|
||||||
mouseenter: WindowEventMap["mouseenter"];
|
mouseenter: WindowEventMap["mouseenter"];
|
||||||
mouseleave: WindowEventMap["mouseleave"];
|
mouseleave: WindowEventMap["mouseleave"];
|
||||||
change: CustomEvent<any>;
|
|
||||||
},
|
},
|
||||||
{ default: {} }
|
{ default: {} }
|
||||||
> {}
|
> {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue