@proyecto-viviana/solid-stately 0.2.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -283
- package/dist/autocomplete/createAutocompleteState.d.ts +2 -2
- package/dist/autocomplete/index.d.ts +1 -1
- package/dist/calendar/IncompleteDate.d.ts +61 -0
- package/dist/calendar/createCalendarState.d.ts +41 -16
- package/dist/calendar/createDateFieldState.d.ts +39 -9
- package/dist/calendar/createDatePickerState.d.ts +60 -0
- package/dist/calendar/createRangeCalendarState.d.ts +37 -10
- package/dist/calendar/createTimeFieldState.d.ts +34 -7
- package/dist/calendar/index.d.ts +7 -6
- package/dist/checkbox/createCheckboxGroupState.d.ts +6 -6
- package/dist/checkbox/index.d.ts +1 -1
- package/dist/collections/ListCollection.d.ts +1 -1
- package/dist/collections/createListState.d.ts +11 -8
- package/dist/collections/createMenuState.d.ts +7 -7
- package/dist/collections/createSelectionState.d.ts +22 -10
- package/dist/collections/getChildNodes.d.ts +11 -0
- package/dist/collections/index.d.ts +6 -5
- package/dist/collections/types.d.ts +12 -12
- package/dist/color/Color.d.ts +1 -1
- package/dist/color/createColorAreaState.d.ts +4 -2
- package/dist/color/createColorFieldState.d.ts +38 -12
- package/dist/color/createColorSliderState.d.ts +9 -2
- package/dist/color/createColorWheelState.d.ts +13 -2
- package/dist/color/getColorChannels.d.ts +1 -1
- package/dist/color/index.d.ts +6 -6
- package/dist/color/types.d.ts +4 -4
- package/dist/combobox/createComboBoxState.d.ts +34 -13
- package/dist/combobox/index.d.ts +1 -1
- package/dist/data/createAsyncList.d.ts +4 -4
- package/dist/data/createListData.d.ts +2 -2
- package/dist/data/createTreeData.d.ts +6 -2
- package/dist/data/index.d.ts +3 -3
- package/dist/datepicker/index.d.ts +2 -4
- package/dist/disclosure/createDisclosureState.d.ts +2 -2
- package/dist/disclosure/index.d.ts +1 -1
- package/dist/dnd/createDragState.d.ts +2 -2
- package/dist/dnd/createDraggableCollectionState.d.ts +2 -2
- package/dist/dnd/createDropState.d.ts +2 -2
- package/dist/dnd/createDroppableCollectionState.d.ts +3 -3
- package/dist/dnd/index.d.ts +5 -5
- package/dist/dnd/types.d.ts +19 -17
- package/dist/form/createFormValidationState.d.ts +3 -3
- package/dist/form/index.d.ts +1 -1
- package/dist/grid/createGridState.d.ts +2 -2
- package/dist/grid/index.d.ts +2 -2
- package/dist/grid/types.d.ts +27 -11
- package/dist/index.d.ts +31 -30
- package/dist/index.js +9077 -7246
- package/dist/index.js.map +1 -1
- package/dist/menu/index.d.ts +2 -2
- package/dist/numberfield/createNumberFieldState.d.ts +2 -2
- package/dist/numberfield/index.d.ts +1 -1
- package/dist/overlays/createOverlayTriggerState.d.ts +2 -2
- package/dist/overlays/index.d.ts +1 -1
- package/dist/radio/createRadioGroupState.d.ts +7 -7
- package/dist/radio/index.d.ts +1 -1
- package/dist/searchfield/createSearchFieldState.d.ts +2 -2
- package/dist/searchfield/index.d.ts +2 -2
- package/dist/select/createSelectState.d.ts +14 -8
- package/dist/select/index.d.ts +1 -1
- package/dist/selection/Selection.d.ts +16 -0
- package/dist/selection/SelectionManager.d.ts +110 -0
- package/dist/selection/createMultipleSelectionState.d.ts +59 -0
- package/dist/selection/index.d.ts +6 -5
- package/dist/slider/createSliderState.d.ts +3 -3
- package/dist/slider/index.d.ts +2 -2
- package/dist/steplist/createStepListState.d.ts +48 -0
- package/dist/steplist/index.d.ts +1 -0
- package/dist/table/TableCollection.d.ts +33 -3
- package/dist/table/createTableColumnResizeState.d.ts +54 -0
- package/dist/table/createTableState.d.ts +2 -2
- package/dist/table/createTreeGridState.d.ts +15 -0
- package/dist/table/index.d.ts +6 -3
- package/dist/table/types.d.ts +68 -10
- package/dist/tabs/createTabListState.d.ts +5 -5
- package/dist/tabs/index.d.ts +1 -1
- package/dist/textfield/createTextFieldState.d.ts +2 -2
- package/dist/textfield/index.d.ts +1 -1
- package/dist/toast/createToastState.d.ts +24 -2
- package/dist/toast/index.d.ts +1 -1
- package/dist/toggle/createToggleGroupState.d.ts +4 -4
- package/dist/toggle/createToggleState.d.ts +2 -2
- package/dist/toggle/index.d.ts +2 -2
- package/dist/tooltip/createTooltipTriggerState.d.ts +2 -2
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tree/TreeCollection.d.ts +2 -2
- package/dist/tree/createTreeState.d.ts +2 -2
- package/dist/tree/index.d.ts +3 -3
- package/dist/tree/types.d.ts +27 -13
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/reactivity.d.ts +1 -1
- package/package.json +29 -30
- package/src/autocomplete/createAutocompleteState.d.ts +19 -17
- package/src/autocomplete/createAutocompleteState.ts +24 -30
- package/src/autocomplete/index.d.ts +6 -2
- package/src/autocomplete/index.ts +1 -1
- package/src/calendar/IncompleteDate.ts +430 -0
- package/src/calendar/createCalendarState.d.ts +139 -117
- package/src/calendar/createCalendarState.ts +308 -94
- package/src/calendar/createDateFieldState.d.ts +130 -95
- package/src/calendar/createDateFieldState.ts +447 -334
- package/src/calendar/createDatePickerState.ts +347 -0
- package/src/calendar/createRangeCalendarState.d.ts +154 -129
- package/src/calendar/createRangeCalendarState.ts +411 -85
- package/src/calendar/createTimeFieldState.d.ts +81 -79
- package/src/calendar/createTimeFieldState.ts +187 -108
- package/src/calendar/index.d.ts +80 -7
- package/src/calendar/index.ts +23 -12
- package/src/checkbox/createCheckboxGroupState.d.ts +57 -55
- package/src/checkbox/createCheckboxGroupState.ts +20 -29
- package/src/checkbox/index.d.ts +6 -2
- package/src/checkbox/index.ts +1 -1
- package/src/collections/ListCollection.d.ts +25 -22
- package/src/collections/ListCollection.ts +6 -6
- package/src/collections/createListState.d.ts +73 -58
- package/src/collections/createListState.ts +67 -35
- package/src/collections/createMenuState.d.ts +36 -31
- package/src/collections/createMenuState.ts +21 -12
- package/src/collections/createSelectionState.d.ts +78 -65
- package/src/collections/createSelectionState.ts +66 -52
- package/src/collections/getChildNodes.ts +98 -0
- package/src/collections/index.d.ts +38 -6
- package/src/collections/index.ts +14 -10
- package/src/collections/types.d.ts +101 -101
- package/src/collections/types.ts +12 -12
- package/src/color/Color.d.ts +20 -5
- package/src/color/Color.ts +357 -254
- package/src/color/createColorAreaState.d.ts +67 -65
- package/src/color/createColorAreaState.ts +21 -13
- package/src/color/createColorFieldState.d.ts +46 -44
- package/src/color/createColorFieldState.ts +285 -149
- package/src/color/createColorSliderState.d.ts +58 -56
- package/src/color/createColorSliderState.ts +45 -14
- package/src/color/createColorWheelState.d.ts +42 -40
- package/src/color/createColorWheelState.ts +101 -64
- package/src/color/getColorChannels.ts +7 -5
- package/src/color/index.d.ts +36 -7
- package/src/color/index.ts +6 -9
- package/src/color/types.d.ts +68 -63
- package/src/color/types.ts +11 -19
- package/src/combobox/createComboBoxState.d.ts +107 -105
- package/src/combobox/createComboBoxState.ts +184 -89
- package/src/combobox/index.d.ts +10 -2
- package/src/combobox/index.ts +1 -1
- package/src/data/createAsyncList.ts +89 -63
- package/src/data/createListData.ts +67 -67
- package/src/data/createTreeData.ts +304 -91
- package/src/data/index.ts +3 -3
- package/src/datepicker/index.ts +6 -10
- package/src/disclosure/createDisclosureState.d.ts +47 -43
- package/src/disclosure/createDisclosureState.ts +7 -21
- package/src/disclosure/index.d.ts +10 -2
- package/src/disclosure/index.ts +1 -1
- package/src/dnd/createDragState.d.ts +51 -42
- package/src/dnd/createDragState.ts +12 -14
- package/src/dnd/createDraggableCollectionState.d.ts +52 -41
- package/src/dnd/createDraggableCollectionState.ts +14 -21
- package/src/dnd/createDropState.d.ts +64 -45
- package/src/dnd/createDropState.ts +22 -32
- package/src/dnd/createDroppableCollectionState.d.ts +88 -59
- package/src/dnd/createDroppableCollectionState.ts +40 -43
- package/src/dnd/index.d.ts +55 -6
- package/src/dnd/index.ts +6 -18
- package/src/dnd/types.d.ts +170 -157
- package/src/dnd/types.ts +24 -22
- package/src/form/createFormValidationState.d.ts +47 -45
- package/src/form/createFormValidationState.ts +30 -63
- package/src/form/index.d.ts +16 -2
- package/src/form/index.ts +1 -1
- package/src/grid/createGridState.d.ts +7 -4
- package/src/grid/createGridState.ts +78 -51
- package/src/grid/index.d.ts +3 -3
- package/src/grid/index.ts +2 -8
- package/src/grid/types.d.ts +136 -129
- package/src/grid/types.ts +34 -18
- package/src/index.d.ts +311 -26
- package/src/index.ts +59 -89
- package/src/menu/index.ts +2 -4
- package/src/numberfield/createNumberFieldState.d.ts +56 -54
- package/src/numberfield/createNumberFieldState.ts +26 -31
- package/src/numberfield/index.d.ts +6 -2
- package/src/numberfield/index.ts +1 -1
- package/src/overlays/createOverlayTriggerState.d.ts +22 -20
- package/src/overlays/createOverlayTriggerState.ts +3 -4
- package/src/overlays/index.d.ts +6 -2
- package/src/overlays/index.ts +1 -1
- package/src/radio/createRadioGroupState.d.ts +54 -52
- package/src/radio/createRadioGroupState.ts +27 -29
- package/src/radio/index.d.ts +7 -2
- package/src/radio/index.ts +1 -1
- package/src/searchfield/createSearchFieldState.d.ts +16 -14
- package/src/searchfield/createSearchFieldState.ts +5 -11
- package/src/searchfield/index.d.ts +3 -3
- package/src/searchfield/index.ts +2 -5
- package/src/select/createSelectState.d.ts +63 -61
- package/src/select/createSelectState.ts +42 -29
- package/src/select/index.d.ts +2 -2
- package/src/select/index.ts +1 -5
- package/src/selection/Selection.ts +28 -0
- package/src/selection/SelectionManager.ts +526 -0
- package/src/selection/createMultipleSelectionState.ts +247 -0
- package/src/selection/index.ts +12 -7
- package/src/slider/createSliderState.d.ts +60 -60
- package/src/slider/createSliderState.ts +55 -33
- package/src/slider/index.d.ts +3 -3
- package/src/slider/index.ts +2 -6
- package/src/ssr/index.d.ts +1 -1
- package/src/ssr/index.ts +2 -2
- package/src/steplist/createStepListState.ts +191 -0
- package/src/steplist/index.ts +5 -0
- package/src/table/TableCollection.d.ts +42 -40
- package/src/table/TableCollection.ts +266 -99
- package/src/table/createTableColumnResizeState.ts +242 -0
- package/src/table/createTableState.d.ts +7 -4
- package/src/table/createTableState.ts +30 -7
- package/src/table/createTreeGridState.ts +146 -0
- package/src/table/index.d.ts +14 -4
- package/src/table/index.ts +13 -3
- package/src/table/types.d.ts +98 -92
- package/src/table/types.ts +83 -13
- package/src/tabs/createTabListState.d.ts +59 -57
- package/src/tabs/createTabListState.ts +34 -39
- package/src/tabs/index.d.ts +8 -2
- package/src/tabs/index.ts +1 -1
- package/src/textfield/createTextFieldState.d.ts +16 -14
- package/src/textfield/createTextFieldState.ts +7 -18
- package/src/textfield/index.d.ts +6 -2
- package/src/textfield/index.ts +1 -1
- package/src/toast/createToastState.d.ts +92 -86
- package/src/toast/createToastState.ts +90 -52
- package/src/toast/index.d.ts +12 -2
- package/src/toast/index.ts +2 -1
- package/src/toggle/createToggleGroupState.ts +11 -21
- package/src/toggle/createToggleState.d.ts +19 -19
- package/src/toggle/createToggleState.ts +2 -16
- package/src/toggle/index.d.ts +2 -2
- package/src/toggle/index.ts +2 -6
- package/src/tooltip/createTooltipTriggerState.d.ts +17 -17
- package/src/tooltip/createTooltipTriggerState.ts +12 -11
- package/src/tooltip/index.d.ts +7 -2
- package/src/tooltip/index.ts +1 -1
- package/src/tree/TreeCollection.d.ts +26 -23
- package/src/tree/TreeCollection.ts +29 -22
- package/src/tree/createTreeState.d.ts +7 -4
- package/src/tree/createTreeState.ts +70 -41
- package/src/tree/index.d.ts +10 -4
- package/src/tree/index.ts +3 -3
- package/src/tree/types.d.ts +131 -126
- package/src/tree/types.ts +30 -13
- package/src/utils/index.d.ts +2 -2
- package/src/utils/index.ts +1 -1
- package/src/utils/reactivity.d.ts +2 -2
- package/src/utils/reactivity.ts +3 -3
|
@@ -5,37 +5,53 @@
|
|
|
5
5
|
* Based on @react-stately/calendar useCalendarState
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { createSignal, createMemo, type Accessor } from
|
|
8
|
+
import { createSignal, createMemo, createEffect, type Accessor } from "solid-js";
|
|
9
9
|
import {
|
|
10
|
+
type Calendar as InternationalizedCalendar,
|
|
10
11
|
type CalendarDate,
|
|
12
|
+
type CalendarIdentifier,
|
|
11
13
|
type DateValue,
|
|
14
|
+
GregorianCalendar,
|
|
12
15
|
today,
|
|
13
16
|
getLocalTimeZone,
|
|
17
|
+
isEqualCalendar,
|
|
14
18
|
isSameDay,
|
|
15
19
|
isSameMonth,
|
|
16
20
|
startOfMonth,
|
|
17
21
|
endOfMonth,
|
|
18
22
|
startOfWeek,
|
|
19
23
|
getWeeksInMonth,
|
|
20
|
-
getDayOfWeek,
|
|
21
24
|
DateFormatter,
|
|
25
|
+
createCalendar as intlCreateCalendar,
|
|
26
|
+
toCalendar as intlToCalendar,
|
|
22
27
|
toCalendarDate as intlToCalendarDate,
|
|
23
|
-
} from
|
|
24
|
-
import { access, type MaybeAccessor } from
|
|
28
|
+
} from "@internationalized/date";
|
|
29
|
+
import { access, type MaybeAccessor } from "../utils";
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
export type ValidationState = "valid" | "invalid";
|
|
32
|
+
export type CalendarPageBehavior = "single" | "visible";
|
|
33
|
+
export type CalendarSelectionAlignment = "start" | "center" | "end";
|
|
34
|
+
export type CalendarDayOfWeek = "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "sat";
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
const dayOfWeekNames: CalendarDayOfWeek[] = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
31
37
|
|
|
32
|
-
export
|
|
38
|
+
export type CalendarSelectionMode = "single" | "multiple";
|
|
39
|
+
export type CalendarValueType<T, M extends CalendarSelectionMode> = M extends "single"
|
|
40
|
+
? T
|
|
41
|
+
: readonly T[];
|
|
42
|
+
|
|
43
|
+
export interface CalendarStateProps<
|
|
44
|
+
T extends DateValue = DateValue,
|
|
45
|
+
M extends CalendarSelectionMode = "single",
|
|
46
|
+
> {
|
|
33
47
|
/** The current value (controlled). */
|
|
34
|
-
value?: MaybeAccessor<T | null>;
|
|
48
|
+
value?: MaybeAccessor<CalendarValueType<T | null, M> | undefined>;
|
|
35
49
|
/** The default value (uncontrolled). */
|
|
36
|
-
defaultValue?: T | null;
|
|
50
|
+
defaultValue?: CalendarValueType<T | null, M> | null;
|
|
37
51
|
/** Handler called when the value changes. */
|
|
38
|
-
onChange?: (value: T) => void;
|
|
52
|
+
onChange?: (value: CalendarValueType<T | null, M>) => void;
|
|
53
|
+
/** Whether single or multiple date selection is enabled. */
|
|
54
|
+
selectionMode?: MaybeAccessor<M>;
|
|
39
55
|
/** The minimum allowed date. */
|
|
40
56
|
minValue?: MaybeAccessor<DateValue | undefined>;
|
|
41
57
|
/** The maximum allowed date. */
|
|
@@ -47,17 +63,23 @@ export interface CalendarStateProps<T extends DateValue = DateValue> {
|
|
|
47
63
|
/** Whether dates outside the visible range are automatically focused. */
|
|
48
64
|
autoFocus?: boolean;
|
|
49
65
|
/** The date that is focused when the calendar first mounts. */
|
|
50
|
-
focusedValue?: MaybeAccessor<DateValue | undefined>;
|
|
66
|
+
focusedValue?: MaybeAccessor<DateValue | null | undefined>;
|
|
51
67
|
/** The default focused date (uncontrolled). */
|
|
52
68
|
defaultFocusedValue?: DateValue;
|
|
53
69
|
/** Handler called when the focused date changes. */
|
|
54
70
|
onFocusChange?: (date: CalendarDate) => void;
|
|
55
71
|
/** The locale to use for formatting. */
|
|
56
|
-
locale?: string
|
|
72
|
+
locale?: MaybeAccessor<string | undefined>;
|
|
73
|
+
/** Creates a calendar object for a locale calendar identifier. */
|
|
74
|
+
createCalendar?: (identifier: CalendarIdentifier) => InternationalizedCalendar;
|
|
57
75
|
/** Callback that is called for each date in the calendar to determine if it is unavailable. */
|
|
58
76
|
isDateUnavailable?: (date: DateValue) => boolean;
|
|
59
77
|
/** The number of months to display at once. */
|
|
60
78
|
visibleMonths?: number;
|
|
79
|
+
/** Controls whether paging advances by one month or by the visible month range. */
|
|
80
|
+
pageBehavior?: CalendarPageBehavior;
|
|
81
|
+
/** Determines how the visible months align around the initial focused date. */
|
|
82
|
+
selectionAlignment?: CalendarSelectionAlignment;
|
|
61
83
|
/** Whether to automatically focus the calendar when it is mounted. */
|
|
62
84
|
autoFocusOnMount?: boolean;
|
|
63
85
|
/** Controls which days are disabled. */
|
|
@@ -70,15 +92,24 @@ export interface CalendarStateProps<T extends DateValue = DateValue> {
|
|
|
70
92
|
firstDayOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
71
93
|
}
|
|
72
94
|
|
|
73
|
-
export interface CalendarState<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
95
|
+
export interface CalendarState<
|
|
96
|
+
T extends DateValue = DateValue,
|
|
97
|
+
M extends CalendarSelectionMode = "single",
|
|
98
|
+
> {
|
|
99
|
+
/** Whether single or multiple selection is enabled. */
|
|
100
|
+
selectionMode: Accessor<CalendarSelectionMode>;
|
|
101
|
+
/** The currently selected date(s). */
|
|
102
|
+
value: Accessor<CalendarValueType<T | null, M>>;
|
|
103
|
+
/** Sets the selected date(s). */
|
|
104
|
+
setValue: (value: CalendarValueType<T | null, M>) => void;
|
|
78
105
|
/** The currently focused date. */
|
|
79
106
|
focusedDate: Accessor<CalendarDate>;
|
|
80
107
|
/** Sets the focused date. */
|
|
81
108
|
setFocusedDate: (date: CalendarDate) => void;
|
|
109
|
+
/** The minimum allowed date that a user may select. */
|
|
110
|
+
minValue: Accessor<DateValue | null>;
|
|
111
|
+
/** The maximum allowed date that a user may select. */
|
|
112
|
+
maxValue: Accessor<DateValue | null>;
|
|
82
113
|
/** Whether the calendar is disabled. */
|
|
83
114
|
isDisabled: Accessor<boolean>;
|
|
84
115
|
/** Whether the calendar is read-only. */
|
|
@@ -87,8 +118,14 @@ export interface CalendarState<T extends DateValue = DateValue> {
|
|
|
87
118
|
visibleRange: Accessor<{ start: CalendarDate; end: CalendarDate }>;
|
|
88
119
|
/** The timezone used for date calculations. */
|
|
89
120
|
timeZone: string;
|
|
121
|
+
/** The locale used for formatting and locale-specific week starts. */
|
|
122
|
+
locale: Accessor<string>;
|
|
123
|
+
/** The explicitly requested first weekday, or undefined for the locale default. */
|
|
124
|
+
firstDayOfWeek: Accessor<CalendarDayOfWeek | undefined>;
|
|
90
125
|
/** The validation state. */
|
|
91
126
|
validationState: Accessor<ValidationState | undefined>;
|
|
127
|
+
/** Whether the current value is invalid according to validation state. */
|
|
128
|
+
isValueInvalid: Accessor<boolean>;
|
|
92
129
|
/** Whether a date is selected. */
|
|
93
130
|
isSelected: (date: DateValue) => boolean;
|
|
94
131
|
/** Whether a date is focused. */
|
|
@@ -143,84 +180,210 @@ export interface CalendarState<T extends DateValue = DateValue> {
|
|
|
143
180
|
isPaginating: Accessor<boolean>;
|
|
144
181
|
}
|
|
145
182
|
|
|
146
|
-
// ============================================
|
|
147
|
-
// IMPLEMENTATION
|
|
148
|
-
// ============================================
|
|
149
|
-
|
|
150
183
|
/**
|
|
151
184
|
* Provides state management for a calendar component.
|
|
152
185
|
*/
|
|
153
|
-
export function createCalendarState<
|
|
154
|
-
|
|
155
|
-
|
|
186
|
+
export function createCalendarState<
|
|
187
|
+
T extends DateValue = CalendarDate,
|
|
188
|
+
M extends CalendarSelectionMode = "single",
|
|
189
|
+
>(props: CalendarStateProps<T, M> = {}): CalendarState<T, M> {
|
|
156
190
|
const timeZone = getLocalTimeZone();
|
|
157
|
-
const locale = props.locale ??
|
|
191
|
+
const locale = createMemo(() => access(props.locale) ?? "en-US");
|
|
192
|
+
const minValueState = createMemo(() => access(props.minValue) ?? null);
|
|
193
|
+
const maxValueState = createMemo(() => access(props.maxValue) ?? null);
|
|
194
|
+
const selectionMode = createMemo<CalendarSelectionMode>(
|
|
195
|
+
() => access(props.selectionMode) ?? "single",
|
|
196
|
+
);
|
|
197
|
+
const resolvedOptions = createMemo(() => new DateFormatter(locale()).resolvedOptions());
|
|
198
|
+
const calendar = createMemo(() =>
|
|
199
|
+
(props.createCalendar ?? intlCreateCalendar)(resolvedOptions().calendar as CalendarIdentifier),
|
|
200
|
+
);
|
|
158
201
|
const visibleMonths = props.visibleMonths ?? 1;
|
|
202
|
+
const firstDayOfWeekName = (): CalendarDayOfWeek | undefined =>
|
|
203
|
+
props.firstDayOfWeek == null ? undefined : dayOfWeekNames[props.firstDayOfWeek];
|
|
204
|
+
|
|
205
|
+
const toDisplayCalendarDate = (date: DateValue): CalendarDate =>
|
|
206
|
+
intlToCalendar(toCalendarDate(date), calendar());
|
|
207
|
+
|
|
208
|
+
const selectionAlignmentOffset = (): number => {
|
|
209
|
+
// Mirrors @react-stately/calendar useCalendarState, where selectionAlignment
|
|
210
|
+
// defaults to "center" (alignCenter) when not provided.
|
|
211
|
+
switch (props.selectionAlignment) {
|
|
212
|
+
case "start":
|
|
213
|
+
return 0;
|
|
214
|
+
case "end":
|
|
215
|
+
return Math.max(visibleMonths - 1, 0);
|
|
216
|
+
case "center":
|
|
217
|
+
default: {
|
|
218
|
+
let halfDuration = Math.floor(visibleMonths / 2);
|
|
219
|
+
if (halfDuration > 0 && visibleMonths % 2 === 0) {
|
|
220
|
+
halfDuration--;
|
|
221
|
+
}
|
|
222
|
+
return halfDuration;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const alignVisibleRangeStart = (date: CalendarDate): CalendarDate => {
|
|
228
|
+
const offset = selectionAlignmentOffset();
|
|
229
|
+
return startOfMonth(offset > 0 ? date.subtract({ months: offset }) : date);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const visibleRangeEnd = (start: CalendarDate): CalendarDate => {
|
|
233
|
+
let end = endOfMonth(start);
|
|
234
|
+
|
|
235
|
+
for (let i = 1; i < visibleMonths; i++) {
|
|
236
|
+
end = endOfMonth(end.add({ months: 1 }));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return end;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const constrainDate = (date: CalendarDate): CalendarDate => {
|
|
243
|
+
const minValue = access(props.minValue);
|
|
244
|
+
const maxValue = access(props.maxValue);
|
|
245
|
+
|
|
246
|
+
let constrained = date;
|
|
247
|
+
|
|
248
|
+
if (minValue && constrained.compare(toDisplayCalendarDate(minValue)) < 0) {
|
|
249
|
+
constrained = toDisplayCalendarDate(minValue);
|
|
250
|
+
}
|
|
251
|
+
if (maxValue && constrained.compare(toDisplayCalendarDate(maxValue)) > 0) {
|
|
252
|
+
constrained = toDisplayCalendarDate(maxValue);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return constrained;
|
|
256
|
+
};
|
|
159
257
|
|
|
160
258
|
// Determine the initially focused date
|
|
161
259
|
const getInitialFocusedDate = (): CalendarDate => {
|
|
162
260
|
const controlledFocused = access(props.focusedValue);
|
|
163
261
|
if (controlledFocused) {
|
|
164
|
-
return
|
|
262
|
+
return toDisplayCalendarDate(controlledFocused);
|
|
165
263
|
}
|
|
166
264
|
if (props.defaultFocusedValue) {
|
|
167
|
-
return
|
|
265
|
+
return toDisplayCalendarDate(props.defaultFocusedValue);
|
|
168
266
|
}
|
|
169
267
|
const controlledValue = access(props.value);
|
|
170
|
-
|
|
171
|
-
|
|
268
|
+
const controlledFirst = Array.isArray(controlledValue) ? controlledValue[0] : controlledValue;
|
|
269
|
+
if (controlledFirst) {
|
|
270
|
+
return toDisplayCalendarDate(controlledFirst);
|
|
172
271
|
}
|
|
173
|
-
|
|
174
|
-
|
|
272
|
+
const defaultFirst = Array.isArray(props.defaultValue)
|
|
273
|
+
? props.defaultValue[0]
|
|
274
|
+
: props.defaultValue;
|
|
275
|
+
if (defaultFirst) {
|
|
276
|
+
return toDisplayCalendarDate(defaultFirst);
|
|
175
277
|
}
|
|
176
|
-
return today(timeZone);
|
|
278
|
+
return intlToCalendar(today(timeZone), calendar());
|
|
177
279
|
};
|
|
178
280
|
|
|
179
281
|
// State signals
|
|
180
|
-
const
|
|
181
|
-
|
|
282
|
+
const initialFocusedDate = constrainDate(getInitialFocusedDate());
|
|
283
|
+
const [internalValue, setInternalValue] = createSignal<T | T[] | null>(
|
|
284
|
+
(props.defaultValue as T | T[] | null) ?? null,
|
|
182
285
|
);
|
|
183
|
-
const [focusedDate, setFocusedDateInternal] = createSignal<CalendarDate>(
|
|
184
|
-
|
|
286
|
+
const [focusedDate, setFocusedDateInternal] = createSignal<CalendarDate>(initialFocusedDate);
|
|
287
|
+
const [visibleRangeStart, setVisibleRangeStart] = createSignal<CalendarDate>(
|
|
288
|
+
alignVisibleRangeStart(initialFocusedDate),
|
|
185
289
|
);
|
|
186
290
|
const [isFocused, setFocused] = createSignal(false);
|
|
187
291
|
const [isPaginating, setIsPaginating] = createSignal(false);
|
|
188
292
|
|
|
189
293
|
// Controlled vs uncontrolled value
|
|
190
|
-
const
|
|
294
|
+
const sourceValue = createMemo<T | T[] | null>(() => {
|
|
191
295
|
const controlled = access(props.value);
|
|
192
|
-
return controlled !== undefined ? controlled : internalValue();
|
|
296
|
+
return controlled !== undefined ? (controlled as T | T[] | null) : internalValue();
|
|
297
|
+
});
|
|
298
|
+
const value = createMemo<T | T[] | null>(() => {
|
|
299
|
+
const currentValue = sourceValue();
|
|
300
|
+
if (Array.isArray(currentValue)) {
|
|
301
|
+
return currentValue.map((v) => toDisplayCalendarDate(v) as unknown as T);
|
|
302
|
+
}
|
|
303
|
+
return currentValue ? (toDisplayCalendarDate(currentValue) as unknown as T) : null;
|
|
193
304
|
});
|
|
194
305
|
|
|
195
306
|
// Derived states
|
|
196
307
|
const isDisabled = createMemo(() => access(props.isDisabled) ?? false);
|
|
197
308
|
const isReadOnly = createMemo(() => access(props.isReadOnly) ?? false);
|
|
198
309
|
const validationState = createMemo(() => access(props.validationState));
|
|
310
|
+
const isValueInvalid = createMemo(() => validationState() === "invalid");
|
|
199
311
|
|
|
200
|
-
// Visible range based on
|
|
312
|
+
// Visible range based on the paged range start.
|
|
201
313
|
const visibleRange = createMemo(() => {
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
let end = endOfMonth(focused);
|
|
314
|
+
const start = visibleRangeStart();
|
|
315
|
+
const end = visibleRangeEnd(start);
|
|
205
316
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
317
|
+
return { start, end };
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const syncVisibleRangeForFocusedDate = (nextFocusedDate: CalendarDate) => {
|
|
321
|
+
const range = visibleRange();
|
|
322
|
+
|
|
323
|
+
if (nextFocusedDate.compare(range.start) < 0) {
|
|
324
|
+
setVisibleRangeStart(startOfMonth(nextFocusedDate.subtract({ months: visibleMonths - 1 })));
|
|
325
|
+
} else if (nextFocusedDate.compare(range.end) > 0) {
|
|
326
|
+
setVisibleRangeStart(startOfMonth(nextFocusedDate));
|
|
209
327
|
}
|
|
328
|
+
};
|
|
210
329
|
|
|
211
|
-
|
|
330
|
+
createEffect(() => {
|
|
331
|
+
const controlledFocused = access(props.focusedValue);
|
|
332
|
+
if (!controlledFocused) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const nextFocusedDate = constrainDate(toDisplayCalendarDate(controlledFocused));
|
|
337
|
+
|
|
338
|
+
const currentFocusedDate = focusedDate();
|
|
339
|
+
if (
|
|
340
|
+
nextFocusedDate.compare(currentFocusedDate) !== 0 ||
|
|
341
|
+
!isEqualCalendar(nextFocusedDate.calendar, currentFocusedDate.calendar)
|
|
342
|
+
) {
|
|
343
|
+
setFocusedDateInternal(nextFocusedDate);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
syncVisibleRangeForFocusedDate(nextFocusedDate);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
createEffect(() => {
|
|
350
|
+
const controlledFocused = access(props.focusedValue);
|
|
351
|
+
if (controlledFocused) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const currentFocusedDate = focusedDate();
|
|
356
|
+
const nextFocusedDate = constrainDate(currentFocusedDate);
|
|
357
|
+
|
|
358
|
+
if (
|
|
359
|
+
nextFocusedDate.compare(currentFocusedDate) === 0 &&
|
|
360
|
+
isEqualCalendar(nextFocusedDate.calendar, currentFocusedDate.calendar)
|
|
361
|
+
) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
syncVisibleRangeForFocusedDate(nextFocusedDate);
|
|
366
|
+
setFocusedDateInternal(nextFocusedDate);
|
|
367
|
+
props.onFocusChange?.(nextFocusedDate);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
createEffect(() => {
|
|
371
|
+
const currentFocusedDate = focusedDate();
|
|
372
|
+
const nextFocusedDate = toDisplayCalendarDate(currentFocusedDate);
|
|
373
|
+
|
|
374
|
+
if (isEqualCalendar(currentFocusedDate.calendar, nextFocusedDate.calendar)) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
setFocusedDateInternal(nextFocusedDate);
|
|
379
|
+
setVisibleRangeStart(alignVisibleRangeStart(nextFocusedDate));
|
|
212
380
|
});
|
|
213
381
|
|
|
214
382
|
// Format week days for headers
|
|
215
383
|
const weekDays = createMemo(() => {
|
|
216
|
-
const formatter = new DateFormatter(locale, { weekday:
|
|
217
|
-
const startDay = props.firstDayOfWeek ?? 0;
|
|
384
|
+
const formatter = new DateFormatter(locale(), { weekday: "narrow" });
|
|
218
385
|
const days: string[] = [];
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
// Find the start of the week
|
|
222
|
-
const dayOfWeek = getDayOfWeek(base, locale);
|
|
223
|
-
const weekStart = base.subtract({ days: (dayOfWeek - startDay + 7) % 7 });
|
|
386
|
+
const weekStart = startOfWeek(today(timeZone), locale(), firstDayOfWeekName());
|
|
224
387
|
|
|
225
388
|
for (let i = 0; i < 7; i++) {
|
|
226
389
|
const day = weekStart.add({ days: i });
|
|
@@ -232,41 +395,53 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
232
395
|
|
|
233
396
|
// Title (formatted month/year)
|
|
234
397
|
const title = createMemo(() => {
|
|
235
|
-
const formatter = new DateFormatter(locale, {
|
|
236
|
-
month:
|
|
237
|
-
year:
|
|
398
|
+
const formatter = new DateFormatter(locale(), {
|
|
399
|
+
month: "long",
|
|
400
|
+
year: "numeric",
|
|
401
|
+
calendar: focusedDate().calendar.identifier,
|
|
238
402
|
});
|
|
239
|
-
|
|
403
|
+
const date = focusedDate();
|
|
404
|
+
const formattableMonth = date.calendar.getFormattableMonth?.(date) ?? date;
|
|
405
|
+
return formatter.format(formattableMonth.toDate(timeZone));
|
|
240
406
|
});
|
|
241
407
|
|
|
242
408
|
// Set value with onChange callback
|
|
243
|
-
const setValue = (newValue: T | null) => {
|
|
409
|
+
const setValue = (newValue: T | T[] | null) => {
|
|
244
410
|
if (isDisabled() || isReadOnly()) return;
|
|
245
411
|
|
|
412
|
+
const oldValue = sourceValue();
|
|
413
|
+
const referenceValue = Array.isArray(oldValue) ? (oldValue[0] ?? null) : oldValue;
|
|
414
|
+
|
|
415
|
+
let nextValue: T | T[] | null;
|
|
416
|
+
if (newValue == null) {
|
|
417
|
+
nextValue = selectionMode() === "multiple" ? ([] as T[]) : null;
|
|
418
|
+
} else if (Array.isArray(newValue)) {
|
|
419
|
+
nextValue = newValue.map(
|
|
420
|
+
(v) => convertValue(constrainDate(toDisplayCalendarDate(v)), referenceValue) as T,
|
|
421
|
+
);
|
|
422
|
+
} else {
|
|
423
|
+
nextValue = convertValue(constrainDate(toDisplayCalendarDate(newValue)), referenceValue) as T;
|
|
424
|
+
}
|
|
425
|
+
|
|
246
426
|
const controlled = access(props.value);
|
|
247
427
|
if (controlled === undefined) {
|
|
248
|
-
setInternalValue(() =>
|
|
428
|
+
setInternalValue(() => nextValue);
|
|
249
429
|
}
|
|
250
430
|
|
|
251
|
-
if (
|
|
252
|
-
props.onChange(
|
|
431
|
+
if (!Object.is(oldValue, nextValue) && props.onChange) {
|
|
432
|
+
props.onChange(nextValue as CalendarValueType<T | null, M>);
|
|
253
433
|
}
|
|
254
434
|
};
|
|
255
435
|
|
|
256
436
|
// Set focused date with constraints
|
|
257
437
|
const setFocusedDate = (date: CalendarDate) => {
|
|
258
|
-
const
|
|
259
|
-
const maxValue = access(props.maxValue);
|
|
260
|
-
|
|
261
|
-
let constrained = date;
|
|
438
|
+
const constrained = constrainDate(date);
|
|
262
439
|
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
if (maxValue && date.compare(toCalendarDate(maxValue)) > 0) {
|
|
267
|
-
constrained = toCalendarDate(maxValue);
|
|
440
|
+
if (Object.is(constrained, focusedDate())) {
|
|
441
|
+
return;
|
|
268
442
|
}
|
|
269
443
|
|
|
444
|
+
syncVisibleRangeForFocusedDate(constrained);
|
|
270
445
|
setFocusedDateInternal(constrained);
|
|
271
446
|
props.onFocusChange?.(constrained);
|
|
272
447
|
};
|
|
@@ -274,13 +449,17 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
274
449
|
// Check if a date is selected
|
|
275
450
|
const isSelected = (date: DateValue): boolean => {
|
|
276
451
|
const v = value();
|
|
277
|
-
if (
|
|
278
|
-
|
|
452
|
+
if (v == null) return false;
|
|
453
|
+
const target = toDisplayCalendarDate(date);
|
|
454
|
+
if (Array.isArray(v)) {
|
|
455
|
+
return v.some((d) => isSameDay(target, toDisplayCalendarDate(d)));
|
|
456
|
+
}
|
|
457
|
+
return isSameDay(target, toDisplayCalendarDate(v));
|
|
279
458
|
};
|
|
280
459
|
|
|
281
460
|
// Check if a date is focused
|
|
282
461
|
const isCellFocused = (date: DateValue): boolean => {
|
|
283
|
-
return isSameDay(
|
|
462
|
+
return isSameDay(toDisplayCalendarDate(date), focusedDate());
|
|
284
463
|
};
|
|
285
464
|
|
|
286
465
|
// Check if a date is unavailable
|
|
@@ -295,10 +474,10 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
295
474
|
|
|
296
475
|
const minValue = access(props.minValue);
|
|
297
476
|
const maxValue = access(props.maxValue);
|
|
298
|
-
const calDate =
|
|
477
|
+
const calDate = toDisplayCalendarDate(date);
|
|
299
478
|
|
|
300
|
-
if (minValue && calDate.compare(
|
|
301
|
-
if (maxValue && calDate.compare(
|
|
479
|
+
if (minValue && calDate.compare(toDisplayCalendarDate(minValue)) < 0) return true;
|
|
480
|
+
if (maxValue && calDate.compare(toDisplayCalendarDate(maxValue)) > 0) return true;
|
|
302
481
|
|
|
303
482
|
return false;
|
|
304
483
|
};
|
|
@@ -306,7 +485,7 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
306
485
|
// Check if a date is outside the visible range
|
|
307
486
|
const isOutsideVisibleRange = (date: DateValue): boolean => {
|
|
308
487
|
const range = visibleRange();
|
|
309
|
-
const calDate =
|
|
488
|
+
const calDate = toDisplayCalendarDate(date);
|
|
310
489
|
return !isSameMonth(calDate, range.start) && !isSameMonth(calDate, range.end);
|
|
311
490
|
};
|
|
312
491
|
|
|
@@ -318,13 +497,21 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
318
497
|
// Navigation methods
|
|
319
498
|
const focusPreviousPage = () => {
|
|
320
499
|
setIsPaginating(true);
|
|
321
|
-
|
|
500
|
+
const pageMonths = props.pageBehavior === "single" ? 1 : visibleMonths;
|
|
501
|
+
const nextFocusedDate = constrainDate(focusedDate().subtract({ months: pageMonths }));
|
|
502
|
+
setFocusedDateInternal(nextFocusedDate);
|
|
503
|
+
setVisibleRangeStart(startOfMonth(visibleRangeStart().subtract({ months: pageMonths })));
|
|
504
|
+
props.onFocusChange?.(nextFocusedDate);
|
|
322
505
|
setIsPaginating(false);
|
|
323
506
|
};
|
|
324
507
|
|
|
325
508
|
const focusNextPage = () => {
|
|
326
509
|
setIsPaginating(true);
|
|
327
|
-
|
|
510
|
+
const pageMonths = props.pageBehavior === "single" ? 1 : visibleMonths;
|
|
511
|
+
const nextFocusedDate = constrainDate(focusedDate().add({ months: pageMonths }));
|
|
512
|
+
setFocusedDateInternal(nextFocusedDate);
|
|
513
|
+
setVisibleRangeStart(startOfMonth(visibleRangeStart().add({ months: pageMonths })));
|
|
514
|
+
props.onFocusChange?.(nextFocusedDate);
|
|
328
515
|
setIsPaginating(false);
|
|
329
516
|
};
|
|
330
517
|
|
|
@@ -364,28 +551,43 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
364
551
|
const selectFocusedDate = () => {
|
|
365
552
|
if (isReadOnly() || isDisabled()) return;
|
|
366
553
|
const date = focusedDate();
|
|
367
|
-
if (!
|
|
368
|
-
|
|
554
|
+
if (!isCellUnavailable(date)) {
|
|
555
|
+
selectDate(date);
|
|
369
556
|
}
|
|
370
557
|
};
|
|
371
558
|
|
|
372
559
|
const selectDate = (date: CalendarDate) => {
|
|
373
560
|
if (isReadOnly() || isDisabled()) return;
|
|
374
|
-
if (
|
|
561
|
+
if (isCellDisabled(date) || isCellUnavailable(date)) return;
|
|
562
|
+
|
|
563
|
+
if (selectionMode() === "multiple") {
|
|
564
|
+
const current = value();
|
|
565
|
+
const base: CalendarDate[] = Array.isArray(current)
|
|
566
|
+
? current.map((v) => toDisplayCalendarDate(v))
|
|
567
|
+
: current != null
|
|
568
|
+
? [toDisplayCalendarDate(current)]
|
|
569
|
+
: [];
|
|
570
|
+
const target = toDisplayCalendarDate(date);
|
|
571
|
+
const index = base.findIndex((d) => isSameDay(d, target));
|
|
572
|
+
const nextValue =
|
|
573
|
+
index >= 0 ? [...base.slice(0, index), ...base.slice(index + 1)] : [...base, target];
|
|
574
|
+
setValue(nextValue as unknown as T[]);
|
|
575
|
+
} else {
|
|
375
576
|
setValue(date as unknown as T);
|
|
376
|
-
setFocusedDate(date);
|
|
377
577
|
}
|
|
578
|
+
|
|
579
|
+
setFocusedDate(date);
|
|
378
580
|
};
|
|
379
581
|
|
|
380
582
|
// Get dates in a specific week
|
|
381
583
|
const getDatesInWeek = (
|
|
382
584
|
weekIndex: number,
|
|
383
|
-
monthStartDate?: CalendarDate
|
|
585
|
+
monthStartDate?: CalendarDate,
|
|
384
586
|
): (CalendarDate | null)[] => {
|
|
385
587
|
const startDate = monthStartDate ?? visibleRange().start;
|
|
386
588
|
|
|
387
589
|
const monthStart = startOfMonth(startDate);
|
|
388
|
-
const weekStart = startOfWeek(monthStart, locale);
|
|
590
|
+
const weekStart = startOfWeek(monthStart, locale(), firstDayOfWeekName());
|
|
389
591
|
|
|
390
592
|
const week: (CalendarDate | null)[] = [];
|
|
391
593
|
const firstDayOfWeek = weekStart.add({ weeks: weekIndex });
|
|
@@ -406,19 +608,25 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
406
608
|
// Get number of weeks in a month
|
|
407
609
|
const getWeeksInMonthFn = (date?: CalendarDate): number => {
|
|
408
610
|
const monthDate = date ?? focusedDate();
|
|
409
|
-
return getWeeksInMonth(monthDate, locale);
|
|
611
|
+
return getWeeksInMonth(monthDate, locale(), firstDayOfWeekName());
|
|
410
612
|
};
|
|
411
613
|
|
|
412
614
|
return {
|
|
413
|
-
|
|
414
|
-
|
|
615
|
+
selectionMode,
|
|
616
|
+
value: value as unknown as Accessor<CalendarValueType<T | null, M>>,
|
|
617
|
+
setValue: setValue as unknown as (value: CalendarValueType<T | null, M>) => void,
|
|
415
618
|
focusedDate,
|
|
416
619
|
setFocusedDate,
|
|
417
620
|
isDisabled,
|
|
418
621
|
isReadOnly,
|
|
419
622
|
visibleRange,
|
|
420
623
|
timeZone,
|
|
624
|
+
locale,
|
|
625
|
+
minValue: minValueState,
|
|
626
|
+
maxValue: maxValueState,
|
|
627
|
+
firstDayOfWeek: firstDayOfWeekName,
|
|
421
628
|
validationState,
|
|
629
|
+
isValueInvalid,
|
|
422
630
|
isSelected,
|
|
423
631
|
isCellFocused,
|
|
424
632
|
isCellUnavailable,
|
|
@@ -448,10 +656,6 @@ export function createCalendarState<T extends DateValue = CalendarDate>(
|
|
|
448
656
|
};
|
|
449
657
|
}
|
|
450
658
|
|
|
451
|
-
// ============================================
|
|
452
|
-
// HELPER FUNCTIONS
|
|
453
|
-
// ============================================
|
|
454
|
-
|
|
455
659
|
/**
|
|
456
660
|
* Converts a DateValue to a CalendarDate.
|
|
457
661
|
*/
|
|
@@ -459,3 +663,13 @@ function toCalendarDate(date: DateValue): CalendarDate {
|
|
|
459
663
|
// Use the library function to convert
|
|
460
664
|
return intlToCalendarDate(date);
|
|
461
665
|
}
|
|
666
|
+
|
|
667
|
+
function convertValue(newValue: CalendarDate, oldValue?: DateValue | null): DateValue {
|
|
668
|
+
const localValue = intlToCalendar(newValue, oldValue?.calendar ?? new GregorianCalendar());
|
|
669
|
+
|
|
670
|
+
if (oldValue && "hour" in oldValue) {
|
|
671
|
+
return oldValue.set(localValue);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
return localValue;
|
|
675
|
+
}
|