@proyecto-viviana/solidaria-components 0.2.9 → 0.3.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 +39 -272
- package/dist/ActionBar.d.ts +21 -13
- package/dist/ActionBar.d.ts.map +1 -1
- package/dist/ActionGroup.d.ts +8 -8
- package/dist/ActionGroup.d.ts.map +1 -1
- package/dist/Alert.d.ts +5 -5
- package/dist/Alert.d.ts.map +1 -1
- package/dist/Autocomplete.d.ts +5 -5
- package/dist/Autocomplete.d.ts.map +1 -1
- package/dist/Breadcrumbs.d.ts +18 -7
- package/dist/Breadcrumbs.d.ts.map +1 -1
- package/dist/Button.d.ts +24 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Calendar.d.ts +38 -7
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +32 -7
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Collection.d.ts +19 -14
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Color.d.ts +103 -14
- package/dist/Color.d.ts.map +1 -1
- package/dist/ColorEditor.d.ts +6 -6
- package/dist/ColorEditor.d.ts.map +1 -1
- package/dist/ComboBox.d.ts +85 -19
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/ContextualHelpTrigger.d.ts +2 -2
- package/dist/ContextualHelpTrigger.d.ts.map +1 -1
- package/dist/DateField.d.ts +8 -6
- package/dist/DateField.d.ts.map +1 -1
- package/dist/DatePicker.d.ts +53 -22
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/DateRangePickerContext.d.ts +30 -0
- package/dist/DateRangePickerContext.d.ts.map +1 -0
- package/dist/Dialog.d.ts +5 -5
- package/dist/Dialog.d.ts.map +1 -1
- package/dist/Disclosure.d.ts +23 -5
- package/dist/Disclosure.d.ts.map +1 -1
- package/dist/DragAndDrop.d.ts +6 -6
- package/dist/DragAndDrop.d.ts.map +1 -1
- package/dist/DragPreview.d.ts +2 -2
- package/dist/DragPreview.d.ts.map +1 -1
- package/dist/DropZone.d.ts +4 -4
- package/dist/DropZone.d.ts.map +1 -1
- package/dist/FieldError.d.ts +9 -5
- package/dist/FieldError.d.ts.map +1 -1
- package/dist/FileTrigger.d.ts +3 -3
- package/dist/FileTrigger.d.ts.map +1 -1
- package/dist/Focusable.d.ts +2 -2
- package/dist/Focusable.d.ts.map +1 -1
- package/dist/Form.d.ts +18 -4
- package/dist/Form.d.ts.map +1 -1
- package/dist/GridList.d.ts +32 -12
- package/dist/GridList.d.ts.map +1 -1
- package/dist/HiddenDateInput.d.ts +26 -0
- package/dist/HiddenDateInput.d.ts.map +1 -0
- package/dist/HiddenTimeInput.d.ts +25 -0
- package/dist/HiddenTimeInput.d.ts.map +1 -0
- package/dist/Icon.d.ts +5 -5
- package/dist/Icon.d.ts.map +1 -1
- package/dist/Keyboard.d.ts +1 -1
- package/dist/Landmark.d.ts +3 -3
- package/dist/Landmark.d.ts.map +1 -1
- package/dist/Link.d.ts +10 -4
- package/dist/Link.d.ts.map +1 -1
- package/dist/ListBox.d.ts +32 -12
- package/dist/ListBox.d.ts.map +1 -1
- package/dist/ListDropTargetDelegate.d.ts +6 -6
- package/dist/ListDropTargetDelegate.d.ts.map +1 -1
- package/dist/Menu.d.ts +65 -14
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Meter.d.ts +3 -3
- package/dist/Meter.d.ts.map +1 -1
- package/dist/Modal.d.ts +5 -5
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts +8 -12
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts +28 -5
- package/dist/Popover.d.ts.map +1 -1
- package/dist/Pressable.d.ts +2 -2
- package/dist/Pressable.d.ts.map +1 -1
- package/dist/ProgressBar.d.ts +5 -3
- package/dist/ProgressBar.d.ts.map +1 -1
- package/dist/RadioGroup.d.ts +43 -9
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RangeCalendar.d.ts +34 -7
- package/dist/RangeCalendar.d.ts.map +1 -1
- package/dist/RouterProvider.d.ts +2 -2
- package/dist/RouterProvider.d.ts.map +1 -1
- package/dist/SearchField.d.ts +23 -20
- package/dist/SearchField.d.ts.map +1 -1
- package/dist/Select.d.ts +41 -11
- package/dist/Select.d.ts.map +1 -1
- package/dist/SelectionIndicator.d.ts +3 -3
- package/dist/SelectionIndicator.d.ts.map +1 -1
- package/dist/Separator.d.ts +9 -3
- package/dist/Separator.d.ts.map +1 -1
- package/dist/SharedElementTransition.d.ts +6 -4
- package/dist/SharedElementTransition.d.ts.map +1 -1
- package/dist/Slider.d.ts +12 -8
- package/dist/Slider.d.ts.map +1 -1
- package/dist/StepList.d.ts +90 -0
- package/dist/StepList.d.ts.map +1 -0
- package/dist/Switch.d.ts +11 -5
- package/dist/Switch.d.ts.map +1 -1
- package/dist/Table.d.ts +187 -23
- package/dist/Table.d.ts.map +1 -1
- package/dist/Tabs.d.ts +45 -9
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/TagGroup.d.ts +12 -10
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/Text.d.ts +2 -2
- package/dist/TextField.d.ts +15 -11
- package/dist/TextField.d.ts.map +1 -1
- package/dist/TimeField.d.ts +6 -6
- package/dist/TimeField.d.ts.map +1 -1
- package/dist/Toast.d.ts +29 -14
- package/dist/Toast.d.ts.map +1 -1
- package/dist/ToggleButton.d.ts +11 -5
- package/dist/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButtonGroup.d.ts +7 -7
- package/dist/ToggleButtonGroup.d.ts.map +1 -1
- package/dist/Toolbar.d.ts +7 -3
- package/dist/Toolbar.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +50 -8
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/Tree.d.ts +66 -17
- package/dist/Tree.d.ts.map +1 -1
- package/dist/Virtualizer.d.ts +12 -12
- package/dist/Virtualizer.d.ts.map +1 -1
- package/dist/VirtualizerLayouts.d.ts +2 -2
- package/dist/VirtualizerLayouts.d.ts.map +1 -1
- package/dist/VisuallyHidden.d.ts +1 -1
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/contexts.d.ts +5 -1
- package/dist/contexts.d.ts.map +1 -1
- package/dist/index.d.ts +73 -71
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23247 -18564
- package/dist/index.js.map +1 -1
- package/dist/index.jsx +18110 -0
- package/dist/index.jsx.map +1 -0
- package/dist/useDragAndDrop.d.ts +13 -13
- package/dist/useDragAndDrop.d.ts.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/virtualizer/Layout.d.ts +1 -1
- package/dist/virtualizer/Layout.d.ts.map +1 -1
- package/package.json +31 -32
- package/src/ActionBar.tsx +75 -72
- package/src/ActionGroup.tsx +53 -61
- package/src/Alert.tsx +17 -42
- package/src/Autocomplete.tsx +39 -44
- package/src/Breadcrumbs.tsx +149 -80
- package/src/Button.tsx +267 -70
- package/src/Calendar.tsx +218 -138
- package/src/Checkbox.tsx +413 -121
- package/src/Collection.tsx +67 -58
- package/src/Color.tsx +803 -380
- package/src/ColorEditor.tsx +131 -149
- package/src/ComboBox.tsx +414 -249
- package/src/ContextualHelpTrigger.tsx +86 -74
- package/src/DateField.tsx +185 -91
- package/src/DatePicker.tsx +524 -213
- package/src/DateRangePickerContext.tsx +44 -0
- package/src/Dialog.tsx +156 -118
- package/src/Disclosure.tsx +127 -80
- package/src/DragAndDrop.tsx +60 -54
- package/src/DragPreview.tsx +13 -11
- package/src/DropZone.tsx +42 -22
- package/src/FieldError.tsx +45 -23
- package/src/FileTrigger.tsx +19 -19
- package/src/Focusable.tsx +21 -24
- package/src/Form.tsx +71 -16
- package/src/GridList.tsx +273 -197
- package/src/HiddenDateInput.tsx +153 -0
- package/src/HiddenTimeInput.tsx +133 -0
- package/src/Icon.tsx +22 -43
- package/src/Keyboard.tsx +3 -3
- package/src/Landmark.tsx +37 -63
- package/src/Link.tsx +125 -75
- package/src/ListBox.tsx +332 -233
- package/src/ListDropTargetDelegate.ts +81 -80
- package/src/Menu.tsx +1023 -274
- package/src/Meter.tsx +38 -56
- package/src/Modal.tsx +243 -175
- package/src/NumberField.tsx +139 -143
- package/src/Popover.tsx +386 -233
- package/src/Pressable.tsx +21 -21
- package/src/ProgressBar.tsx +48 -57
- package/src/RadioGroup.tsx +524 -122
- package/src/RangeCalendar.tsx +157 -90
- package/src/RouterProvider.tsx +30 -47
- package/src/SearchField.tsx +362 -143
- package/src/Select.tsx +656 -233
- package/src/SelectionIndicator.tsx +18 -15
- package/src/Separator.tsx +47 -49
- package/src/SharedElementTransition.tsx +103 -97
- package/src/Slider.tsx +138 -98
- package/src/StepList.tsx +272 -0
- package/src/Switch.tsx +93 -46
- package/src/Table.tsx +1308 -342
- package/src/Tabs.tsx +324 -103
- package/src/TagGroup.tsx +139 -126
- package/src/Text.tsx +3 -3
- package/src/TextField.tsx +389 -79
- package/src/TimeField.tsx +136 -76
- package/src/Toast.tsx +209 -157
- package/src/ToggleButton.tsx +47 -37
- package/src/ToggleButtonGroup.tsx +39 -34
- package/src/Toolbar.tsx +54 -69
- package/src/Tooltip.tsx +387 -119
- package/src/Tree.tsx +651 -368
- package/src/Virtualizer.tsx +208 -180
- package/src/VirtualizerLayouts.ts +45 -30
- package/src/VisuallyHidden.tsx +19 -19
- package/src/contexts.ts +29 -37
- package/src/index.ts +110 -195
- package/src/useDragAndDrop.ts +87 -71
- package/src/utils.tsx +40 -55
- package/src/virtualizer/Layout.ts +14 -22
- package/dist/index.ssr.js +0 -16996
- package/dist/index.ssr.js.map +0 -1
package/src/DatePicker.tsx
CHANGED
|
@@ -11,11 +11,12 @@ import {
|
|
|
11
11
|
createEffect,
|
|
12
12
|
createMemo,
|
|
13
13
|
createSignal,
|
|
14
|
+
onCleanup,
|
|
14
15
|
splitProps,
|
|
15
16
|
useContext,
|
|
16
17
|
Show,
|
|
17
|
-
} from
|
|
18
|
-
import { Portal } from
|
|
18
|
+
} from "solid-js";
|
|
19
|
+
import { Portal } from "solid-js/web";
|
|
19
20
|
import {
|
|
20
21
|
createDatePicker,
|
|
21
22
|
createDateRangePicker,
|
|
@@ -25,12 +26,16 @@ import {
|
|
|
25
26
|
type AriaDatePickerProps,
|
|
26
27
|
type AriaDateRangePickerProps,
|
|
27
28
|
type DatePickerState as AriaDatePickerState,
|
|
28
|
-
} from
|
|
29
|
+
} from "@proyecto-viviana/solidaria";
|
|
29
30
|
import {
|
|
30
31
|
createDateFieldState,
|
|
31
32
|
createCalendarState,
|
|
32
33
|
createRangeCalendarState,
|
|
34
|
+
createDatePickerState,
|
|
35
|
+
access,
|
|
33
36
|
type DateFieldState,
|
|
37
|
+
type DatePickerState,
|
|
38
|
+
type CalendarStateProps,
|
|
34
39
|
type CalendarState,
|
|
35
40
|
type RangeCalendarState,
|
|
36
41
|
type DateFieldStateProps,
|
|
@@ -38,7 +43,7 @@ import {
|
|
|
38
43
|
type DateValue,
|
|
39
44
|
type RangeCalendarStateProps,
|
|
40
45
|
type RangeValue,
|
|
41
|
-
} from
|
|
46
|
+
} from "@proyecto-viviana/solid-stately";
|
|
42
47
|
import {
|
|
43
48
|
type RenderChildren,
|
|
44
49
|
type ClassNameOrFunction,
|
|
@@ -47,14 +52,18 @@ import {
|
|
|
47
52
|
useRenderProps,
|
|
48
53
|
dataAttr,
|
|
49
54
|
useIsHydrated,
|
|
50
|
-
} from
|
|
51
|
-
import { DateFieldContext } from
|
|
52
|
-
import { CalendarContext } from
|
|
53
|
-
import { RangeCalendarContext } from
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
} from "./utils";
|
|
56
|
+
import { DateFieldContext } from "./DateField";
|
|
57
|
+
import { CalendarContext } from "./Calendar";
|
|
58
|
+
import { RangeCalendarContext } from "./RangeCalendar";
|
|
59
|
+
import { HiddenDateInput } from "./HiddenDateInput";
|
|
60
|
+
import { FormContext, type FormProps } from "./Form";
|
|
61
|
+
import {
|
|
62
|
+
DateRangePickerContext,
|
|
63
|
+
useDateRangePickerContext,
|
|
64
|
+
type DateRangePickerContextValue,
|
|
65
|
+
type DateRangePickerFieldContextValue,
|
|
66
|
+
} from "./DateRangePickerContext";
|
|
58
67
|
|
|
59
68
|
export interface DatePickerRenderProps {
|
|
60
69
|
/** Whether the picker is disabled. */
|
|
@@ -69,13 +78,13 @@ export interface DatePickerRenderProps {
|
|
|
69
78
|
isOpen: boolean;
|
|
70
79
|
}
|
|
71
80
|
|
|
72
|
-
export interface DateRangePickerRenderProps
|
|
73
|
-
extends Omit<DatePickerRenderProps, 'isInvalid'> {
|
|
81
|
+
export interface DateRangePickerRenderProps extends Omit<DatePickerRenderProps, "isInvalid"> {
|
|
74
82
|
isInvalid: boolean;
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
export interface DatePickerContextValue {
|
|
78
86
|
fieldState: DateFieldState<DateValue>;
|
|
87
|
+
datePickerState: DatePickerState<DateValue>;
|
|
79
88
|
calendarState: CalendarState<DateValue>;
|
|
80
89
|
overlayState: {
|
|
81
90
|
isOpen: boolean;
|
|
@@ -88,44 +97,74 @@ export interface DatePickerContextValue {
|
|
|
88
97
|
pickerAria: ReturnType<typeof createDatePicker>;
|
|
89
98
|
}
|
|
90
99
|
|
|
91
|
-
export
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
export type DatePickerProps<T extends DateValue = DateValue> = Omit<
|
|
101
|
+
AriaDatePickerProps,
|
|
102
|
+
"id" | "isDisabled" | "isReadOnly" | "isRequired" | "minValue" | "maxValue"
|
|
103
|
+
> &
|
|
104
|
+
Omit<DateFieldStateProps<T>, "locale"> &
|
|
105
|
+
SlotProps & {
|
|
106
|
+
/** The children of the component. */
|
|
107
|
+
children?: JSX.Element;
|
|
108
|
+
/** The CSS className for the element. */
|
|
109
|
+
class?: ClassNameOrFunction<DatePickerRenderProps>;
|
|
110
|
+
/** The inline style for the element. */
|
|
111
|
+
style?: StyleOrFunction<DatePickerRenderProps>;
|
|
112
|
+
/** The locale to use for formatting. */
|
|
113
|
+
locale?: string;
|
|
114
|
+
/** Whether the calendar should close when a date is selected. */
|
|
115
|
+
shouldCloseOnSelect?: boolean;
|
|
116
|
+
/** Whether the overlay is open by default (uncontrolled). */
|
|
117
|
+
defaultOpen?: boolean;
|
|
118
|
+
/** Whether the overlay is open (controlled). */
|
|
119
|
+
isOpen?: boolean;
|
|
120
|
+
/** Callback when the overlay open state changes. */
|
|
121
|
+
onOpenChange?: (isOpen: boolean) => void;
|
|
122
|
+
/** The name for the hidden date input used in HTML form submission. */
|
|
123
|
+
name?: string;
|
|
124
|
+
/** The associated form id for the hidden date input. */
|
|
125
|
+
form?: string;
|
|
126
|
+
/** The number of months to display in the calendar popover. */
|
|
127
|
+
visibleMonths?: number;
|
|
128
|
+
/** Controls whether calendar paging advances by one month or by the visible month range. */
|
|
129
|
+
pageBehavior?: CalendarStateProps<T>["pageBehavior"];
|
|
130
|
+
/** Determines how visible months align around the initial focused date. */
|
|
131
|
+
selectionAlignment?: CalendarStateProps<T>["selectionAlignment"];
|
|
132
|
+
/** A function that determines whether a date is disabled. */
|
|
133
|
+
isDateDisabled?: (date: DateValue) => boolean;
|
|
98
134
|
};
|
|
99
|
-
triggerRef: () => HTMLElement | null;
|
|
100
|
-
setTriggerRef: (element: HTMLElement | null) => void;
|
|
101
|
-
pickerAria: ReturnType<typeof createDateRangePicker>;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export interface DatePickerProps<T extends DateValue = DateValue>
|
|
105
|
-
extends Omit<AriaDatePickerProps, 'id' | 'isDisabled' | 'isReadOnly' | 'isRequired'>,
|
|
106
|
-
Omit<DateFieldStateProps<T>, 'locale'>,
|
|
107
|
-
SlotProps {
|
|
108
|
-
/** The children of the component. */
|
|
109
|
-
children?: JSX.Element;
|
|
110
|
-
/** The CSS className for the element. */
|
|
111
|
-
class?: ClassNameOrFunction<DatePickerRenderProps>;
|
|
112
|
-
/** The inline style for the element. */
|
|
113
|
-
style?: StyleOrFunction<DatePickerRenderProps>;
|
|
114
|
-
/** The locale to use for formatting. */
|
|
115
|
-
locale?: string;
|
|
116
|
-
/** Whether the calendar should close when a date is selected. */
|
|
117
|
-
shouldCloseOnSelect?: boolean;
|
|
118
|
-
}
|
|
119
135
|
|
|
120
136
|
export interface DateRangePickerProps<T extends DateValue = DateValue>
|
|
121
|
-
extends
|
|
122
|
-
Omit<
|
|
137
|
+
extends
|
|
138
|
+
Omit<AriaDateRangePickerProps, "id" | "isDisabled" | "isReadOnly">,
|
|
139
|
+
Omit<RangeCalendarStateProps<T>, "locale">,
|
|
123
140
|
SlotProps {
|
|
124
141
|
children?: JSX.Element;
|
|
125
142
|
class?: ClassNameOrFunction<DateRangePickerRenderProps>;
|
|
126
143
|
style?: StyleOrFunction<DateRangePickerRenderProps>;
|
|
127
144
|
locale?: string;
|
|
128
145
|
shouldCloseOnSelect?: boolean;
|
|
146
|
+
/** Whether the overlay is open by default (uncontrolled). */
|
|
147
|
+
defaultOpen?: boolean;
|
|
148
|
+
/** Whether the overlay is open (controlled). */
|
|
149
|
+
isOpen?: boolean;
|
|
150
|
+
/** Callback when the overlay open state changes. */
|
|
151
|
+
onOpenChange?: (isOpen: boolean) => void;
|
|
152
|
+
/** The granularity of the date/time fields. */
|
|
153
|
+
granularity?: "day" | "hour" | "minute" | "second";
|
|
154
|
+
/** Whether to show the hour in 12 or 24 hour format. */
|
|
155
|
+
hourCycle?: 12 | 24;
|
|
156
|
+
/** Whether to hide the time zone in date/time fields. */
|
|
157
|
+
hideTimeZone?: boolean;
|
|
158
|
+
/** The placeholder date used to determine segment structure. */
|
|
159
|
+
placeholderValue?: DateValue;
|
|
160
|
+
/** The name for the start date input used in HTML form submission. */
|
|
161
|
+
startName?: string;
|
|
162
|
+
/** The name for the end date input used in HTML form submission. */
|
|
163
|
+
endName?: string;
|
|
164
|
+
/** The associated form id for the hidden start/end date inputs. */
|
|
165
|
+
form?: string;
|
|
166
|
+
/** Controls whether native or ARIA validation should be used. */
|
|
167
|
+
validationBehavior?: "native" | "aria";
|
|
129
168
|
}
|
|
130
169
|
|
|
131
170
|
export interface DatePickerButtonRenderProps {
|
|
@@ -148,35 +187,72 @@ export interface DatePickerButtonProps extends SlotProps {
|
|
|
148
187
|
|
|
149
188
|
export interface DateRangePickerButtonProps extends DatePickerButtonProps {}
|
|
150
189
|
|
|
151
|
-
// ============================================
|
|
152
|
-
// CONTEXT
|
|
153
|
-
// ============================================
|
|
154
|
-
|
|
155
190
|
export const DatePickerContext = createContext<DatePickerContextValue | null>(null);
|
|
156
|
-
export const DateRangePickerContext = createContext<DateRangePickerContextValue | null>(null);
|
|
157
191
|
export const DatePickerStateContext = createContext<DateFieldState<DateValue> | null>(null);
|
|
158
|
-
export const DateRangePickerStateContext = createContext<RangeCalendarState<DateValue> | null>(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
192
|
+
export const DateRangePickerStateContext = createContext<RangeCalendarState<DateValue> | null>(
|
|
193
|
+
null,
|
|
194
|
+
);
|
|
195
|
+
export { DateRangePickerContext, useDateRangePickerContext } from "./DateRangePickerContext";
|
|
196
|
+
export type {
|
|
197
|
+
DateRangePickerContextValue,
|
|
198
|
+
DateRangePickerFieldContextValue,
|
|
199
|
+
} from "./DateRangePickerContext";
|
|
200
|
+
|
|
201
|
+
function withFormValidationBehavior<P extends object>(props: P, formContext: FormProps | null): P {
|
|
202
|
+
if (!formContext?.validationBehavior) {
|
|
203
|
+
return props;
|
|
164
204
|
}
|
|
165
|
-
|
|
205
|
+
|
|
206
|
+
return new Proxy(props, {
|
|
207
|
+
get(target, property, receiver) {
|
|
208
|
+
const localValue = Reflect.get(target, property, receiver);
|
|
209
|
+
if (property === "validationBehavior" && localValue === undefined) {
|
|
210
|
+
return formContext.validationBehavior;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return localValue;
|
|
214
|
+
},
|
|
215
|
+
has(target, property) {
|
|
216
|
+
return (
|
|
217
|
+
Reflect.has(target, property) ||
|
|
218
|
+
(property === "validationBehavior" && formContext.validationBehavior !== undefined)
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
ownKeys(target) {
|
|
222
|
+
const keys = new Set(Reflect.ownKeys(target));
|
|
223
|
+
if (formContext.validationBehavior !== undefined) {
|
|
224
|
+
keys.add("validationBehavior");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return Array.from(keys);
|
|
228
|
+
},
|
|
229
|
+
getOwnPropertyDescriptor(target, property) {
|
|
230
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, property);
|
|
231
|
+
if (descriptor) {
|
|
232
|
+
return descriptor;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (property === "validationBehavior" && formContext.validationBehavior !== undefined) {
|
|
236
|
+
return {
|
|
237
|
+
enumerable: true,
|
|
238
|
+
configurable: true,
|
|
239
|
+
get: () => formContext.validationBehavior,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return undefined;
|
|
244
|
+
},
|
|
245
|
+
});
|
|
166
246
|
}
|
|
167
247
|
|
|
168
|
-
export function
|
|
169
|
-
const context = useContext(
|
|
248
|
+
export function useDatePickerContext(): DatePickerContextValue {
|
|
249
|
+
const context = useContext(DatePickerContext);
|
|
170
250
|
if (!context) {
|
|
171
|
-
throw new Error(
|
|
251
|
+
throw new Error("DatePicker components must be used within a DatePicker");
|
|
172
252
|
}
|
|
173
253
|
return context;
|
|
174
254
|
}
|
|
175
255
|
|
|
176
|
-
// ============================================
|
|
177
|
-
// DATE PICKER COMPONENT
|
|
178
|
-
// ============================================
|
|
179
|
-
|
|
180
256
|
/**
|
|
181
257
|
* A date picker combines a DateField and a Calendar popover.
|
|
182
258
|
*
|
|
@@ -203,86 +279,121 @@ export function useDateRangePickerContext(): DateRangePickerContextValue {
|
|
|
203
279
|
* ```
|
|
204
280
|
*/
|
|
205
281
|
export function DatePicker<T extends DateValue = CalendarDate>(
|
|
206
|
-
props: DatePickerProps<T
|
|
282
|
+
props: DatePickerProps<T>,
|
|
207
283
|
): JSX.Element {
|
|
208
284
|
// Use hydration-safe pattern for client-only rendering
|
|
209
285
|
const isHydrated = useIsHydrated();
|
|
286
|
+
const formContext = useContext(FormContext);
|
|
210
287
|
|
|
211
288
|
return (
|
|
212
289
|
<Show
|
|
213
290
|
when={isHydrated()}
|
|
214
|
-
fallback={
|
|
291
|
+
fallback={
|
|
292
|
+
<div class="solidaria-DatePicker solidaria-DatePicker--placeholder" aria-hidden="true" />
|
|
293
|
+
}
|
|
215
294
|
>
|
|
216
|
-
<DatePickerInner {...props} />
|
|
295
|
+
<DatePickerInner {...props} __formContext={formContext} />
|
|
217
296
|
</Show>
|
|
218
297
|
);
|
|
219
298
|
}
|
|
220
299
|
|
|
300
|
+
type DatePickerInnerProps<T extends DateValue = DateValue> = DatePickerProps<T> & {
|
|
301
|
+
__formContext?: FormProps | null;
|
|
302
|
+
};
|
|
303
|
+
|
|
221
304
|
/**
|
|
222
305
|
* Internal DatePicker component that renders after client mount.
|
|
223
306
|
*/
|
|
224
307
|
function DatePickerInner<T extends DateValue = CalendarDate>(
|
|
225
|
-
props:
|
|
308
|
+
props: DatePickerInnerProps<T>,
|
|
226
309
|
): JSX.Element {
|
|
310
|
+
const formContext = props.__formContext ?? useContext(FormContext);
|
|
311
|
+
const mergedProps = withFormValidationBehavior(props, formContext);
|
|
227
312
|
const [local, stateProps, rest] = splitProps(
|
|
228
|
-
|
|
229
|
-
[
|
|
313
|
+
mergedProps,
|
|
314
|
+
["children", "class", "style", "slot", "shouldCloseOnSelect", "__formContext"],
|
|
230
315
|
[
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
316
|
+
"value",
|
|
317
|
+
"defaultValue",
|
|
318
|
+
"onChange",
|
|
319
|
+
"isOpen",
|
|
320
|
+
"defaultOpen",
|
|
321
|
+
"onOpenChange",
|
|
322
|
+
"minValue",
|
|
323
|
+
"maxValue",
|
|
324
|
+
"isInvalid",
|
|
325
|
+
"isDisabled",
|
|
326
|
+
"isReadOnly",
|
|
327
|
+
"isRequired",
|
|
328
|
+
"locale",
|
|
329
|
+
"granularity",
|
|
330
|
+
"hourCycle",
|
|
331
|
+
"hideTimeZone",
|
|
332
|
+
"placeholderValue",
|
|
333
|
+
"shouldForceLeadingZeros",
|
|
334
|
+
"createCalendar",
|
|
335
|
+
"validationState",
|
|
336
|
+
"validationBehavior",
|
|
337
|
+
"validate",
|
|
338
|
+
"description",
|
|
339
|
+
"errorMessage",
|
|
340
|
+
"isDateUnavailable",
|
|
341
|
+
"firstDayOfWeek",
|
|
342
|
+
"visibleMonths",
|
|
343
|
+
"pageBehavior",
|
|
344
|
+
"selectionAlignment",
|
|
345
|
+
"isDateDisabled",
|
|
346
|
+
],
|
|
248
347
|
);
|
|
249
348
|
|
|
250
|
-
|
|
251
|
-
const [
|
|
252
|
-
|
|
349
|
+
const [triggerRef, setTriggerRef] = createSignal<HTMLElement | null>(null);
|
|
350
|
+
const [fieldRef, setFieldRef] = createSignal<HTMLDivElement | null>(null);
|
|
351
|
+
|
|
352
|
+
// Unified state using createDatePickerState as single source of truth
|
|
353
|
+
const datePickerState = createDatePickerState<T>({
|
|
354
|
+
...(stateProps as unknown as import("@proyecto-viviana/solid-stately").DatePickerStateOptions<T>),
|
|
355
|
+
shouldCloseOnSelect: local.shouldCloseOnSelect,
|
|
356
|
+
});
|
|
253
357
|
|
|
254
358
|
const overlayState = {
|
|
255
|
-
get isOpen() {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
359
|
+
get isOpen() {
|
|
360
|
+
return datePickerState.isOpen();
|
|
361
|
+
},
|
|
362
|
+
open: datePickerState.open,
|
|
363
|
+
close: datePickerState.close,
|
|
364
|
+
toggle: () => datePickerState.setOpen(!datePickerState.isOpen()),
|
|
259
365
|
};
|
|
260
366
|
|
|
261
|
-
// Create
|
|
262
|
-
const fieldState = createDateFieldState({
|
|
367
|
+
// Create field state synced through datePickerState
|
|
368
|
+
const fieldState = createDateFieldState<T>({
|
|
263
369
|
...stateProps,
|
|
370
|
+
value: () => datePickerState.value(),
|
|
264
371
|
onChange: (value) => {
|
|
265
|
-
|
|
266
|
-
if (local.shouldCloseOnSelect !== false && value) {
|
|
267
|
-
overlayState.close();
|
|
268
|
-
}
|
|
372
|
+
datePickerState.setValue(value);
|
|
269
373
|
},
|
|
270
374
|
});
|
|
271
375
|
|
|
272
|
-
// Create calendar state
|
|
273
|
-
const calendarState = createCalendarState({
|
|
274
|
-
value: () =>
|
|
376
|
+
// Create calendar state synced through datePickerState
|
|
377
|
+
const calendarState = createCalendarState<T>({
|
|
378
|
+
value: () => datePickerState.value(),
|
|
275
379
|
onChange: (value) => {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
overlayState.close();
|
|
380
|
+
if (!value) {
|
|
381
|
+
return;
|
|
279
382
|
}
|
|
383
|
+
datePickerState.setDateValue(value);
|
|
280
384
|
},
|
|
281
385
|
minValue: stateProps.minValue,
|
|
282
386
|
maxValue: stateProps.maxValue,
|
|
283
387
|
isDisabled: stateProps.isDisabled,
|
|
284
388
|
isReadOnly: stateProps.isReadOnly,
|
|
285
389
|
locale: stateProps.locale,
|
|
390
|
+
createCalendar: stateProps.createCalendar as CalendarStateProps<T>["createCalendar"],
|
|
391
|
+
isDateUnavailable: stateProps.isDateUnavailable,
|
|
392
|
+
firstDayOfWeek: stateProps.firstDayOfWeek as 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined,
|
|
393
|
+
visibleMonths: stateProps.visibleMonths,
|
|
394
|
+
pageBehavior: stateProps.pageBehavior,
|
|
395
|
+
selectionAlignment: stateProps.selectionAlignment,
|
|
396
|
+
isDateDisabled: stateProps.isDateDisabled,
|
|
286
397
|
});
|
|
287
398
|
|
|
288
399
|
// Create date picker ARIA props
|
|
@@ -294,27 +405,30 @@ function DatePickerInner<T extends DateValue = CalendarDate>(
|
|
|
294
405
|
}),
|
|
295
406
|
fieldState as unknown as DateFieldState<DateValue>,
|
|
296
407
|
overlayState as AriaDatePickerState,
|
|
297
|
-
calendarState as unknown as CalendarState<DateValue
|
|
408
|
+
calendarState as unknown as CalendarState<DateValue>,
|
|
298
409
|
);
|
|
299
410
|
|
|
300
|
-
// Context value
|
|
301
411
|
const contextValue: DatePickerContextValue = {
|
|
302
412
|
fieldState: fieldState as unknown as DateFieldState<DateValue>,
|
|
413
|
+
datePickerState: datePickerState as unknown as DatePickerState<DateValue>,
|
|
303
414
|
calendarState: calendarState as unknown as CalendarState<DateValue>,
|
|
304
415
|
overlayState,
|
|
305
|
-
triggerRef
|
|
416
|
+
triggerRef,
|
|
306
417
|
setTriggerRef: (element) => {
|
|
307
418
|
if (!element) return;
|
|
308
|
-
|
|
309
|
-
|
|
419
|
+
const current = triggerRef();
|
|
420
|
+
if (!current || !current.isConnected) {
|
|
421
|
+
setTriggerRef(() => element);
|
|
310
422
|
}
|
|
311
423
|
},
|
|
312
424
|
pickerAria,
|
|
313
425
|
};
|
|
314
426
|
|
|
315
|
-
// Render props values
|
|
316
427
|
const isInvalid = createMemo(
|
|
317
|
-
() =>
|
|
428
|
+
() =>
|
|
429
|
+
fieldState.isInvalid() ||
|
|
430
|
+
datePickerState.builtinValidation().isInvalid ||
|
|
431
|
+
Boolean(stateProps.isInvalid),
|
|
318
432
|
);
|
|
319
433
|
|
|
320
434
|
const renderValues = createMemo<DatePickerRenderProps>(() => ({
|
|
@@ -325,16 +439,20 @@ function DatePickerInner<T extends DateValue = CalendarDate>(
|
|
|
325
439
|
isOpen: overlayState.isOpen,
|
|
326
440
|
}));
|
|
327
441
|
|
|
328
|
-
// Resolve render props
|
|
329
442
|
const renderProps = useRenderProps(
|
|
330
443
|
{
|
|
331
444
|
class: local.class,
|
|
332
445
|
style: local.style,
|
|
333
|
-
defaultClassName:
|
|
446
|
+
defaultClassName: "solidaria-DatePicker",
|
|
334
447
|
},
|
|
335
|
-
renderValues
|
|
448
|
+
renderValues,
|
|
336
449
|
);
|
|
337
450
|
|
|
451
|
+
const validationBehavior = () =>
|
|
452
|
+
(stateProps as { validationBehavior?: "aria" | "native" }).validationBehavior ??
|
|
453
|
+
formContext?.validationBehavior ??
|
|
454
|
+
"native";
|
|
455
|
+
|
|
338
456
|
return (
|
|
339
457
|
<DatePickerStateContext.Provider value={fieldState as unknown as DateFieldState<DateValue>}>
|
|
340
458
|
<DatePickerContext.Provider value={contextValue}>
|
|
@@ -352,6 +470,7 @@ function DatePickerInner<T extends DateValue = CalendarDate>(
|
|
|
352
470
|
>
|
|
353
471
|
<CalendarContext.Provider value={calendarState as unknown as CalendarState<DateValue>}>
|
|
354
472
|
<div
|
|
473
|
+
ref={setFieldRef}
|
|
355
474
|
{...pickerAria.groupProps}
|
|
356
475
|
class={renderProps.class()}
|
|
357
476
|
style={renderProps.style()}
|
|
@@ -363,6 +482,24 @@ function DatePickerInner<T extends DateValue = CalendarDate>(
|
|
|
363
482
|
>
|
|
364
483
|
{props.children}
|
|
365
484
|
</div>
|
|
485
|
+
<Show when={(rest as Record<string, unknown>).name}>
|
|
486
|
+
<HiddenDateInput
|
|
487
|
+
name={(rest as Record<string, unknown>).name as string | undefined}
|
|
488
|
+
form={(rest as Record<string, unknown>).form as string | undefined}
|
|
489
|
+
value={() => datePickerState.value()}
|
|
490
|
+
autoComplete={(rest as Record<string, unknown>).autoComplete as string | undefined}
|
|
491
|
+
isDisabled={fieldState.isDisabled()}
|
|
492
|
+
isRequired={fieldState.isRequired()}
|
|
493
|
+
validationBehavior={validationBehavior()}
|
|
494
|
+
validationState={fieldState}
|
|
495
|
+
focus={() => {
|
|
496
|
+
fieldRef()?.querySelector<HTMLElement>('[role="spinbutton"]')?.focus();
|
|
497
|
+
}}
|
|
498
|
+
minValue={() => access(stateProps.minValue) as DateValue | undefined}
|
|
499
|
+
maxValue={() => access(stateProps.maxValue) as DateValue | undefined}
|
|
500
|
+
granularity={datePickerState.granularity}
|
|
501
|
+
/>
|
|
502
|
+
</Show>
|
|
366
503
|
</CalendarContext.Provider>
|
|
367
504
|
</DateFieldContext.Provider>
|
|
368
505
|
</DatePickerContext.Provider>
|
|
@@ -371,13 +508,18 @@ function DatePickerInner<T extends DateValue = CalendarDate>(
|
|
|
371
508
|
}
|
|
372
509
|
|
|
373
510
|
export function DateRangePicker<T extends DateValue = CalendarDate>(
|
|
374
|
-
props: DateRangePickerProps<T
|
|
511
|
+
props: DateRangePickerProps<T>,
|
|
375
512
|
): JSX.Element {
|
|
376
513
|
const isHydrated = useIsHydrated();
|
|
377
514
|
return (
|
|
378
515
|
<Show
|
|
379
516
|
when={isHydrated()}
|
|
380
|
-
fallback={
|
|
517
|
+
fallback={
|
|
518
|
+
<div
|
|
519
|
+
class="solidaria-DateRangePicker solidaria-DateRangePicker--placeholder"
|
|
520
|
+
aria-hidden="true"
|
|
521
|
+
/>
|
|
522
|
+
}
|
|
381
523
|
>
|
|
382
524
|
<DateRangePickerInner {...props} />
|
|
383
525
|
</Show>
|
|
@@ -385,50 +527,155 @@ export function DateRangePicker<T extends DateValue = CalendarDate>(
|
|
|
385
527
|
}
|
|
386
528
|
|
|
387
529
|
function DateRangePickerInner<T extends DateValue = CalendarDate>(
|
|
388
|
-
props: DateRangePickerProps<T
|
|
530
|
+
props: DateRangePickerProps<T>,
|
|
389
531
|
): JSX.Element {
|
|
390
|
-
const [local, stateProps, rest] = splitProps(
|
|
532
|
+
const [local, overlayProps, stateProps, rest] = splitProps(
|
|
391
533
|
props,
|
|
392
|
-
[
|
|
534
|
+
["children", "class", "style", "slot", "shouldCloseOnSelect"],
|
|
535
|
+
["defaultOpen", "isOpen", "onOpenChange"],
|
|
393
536
|
[
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
537
|
+
"value",
|
|
538
|
+
"defaultValue",
|
|
539
|
+
"onChange",
|
|
540
|
+
"minValue",
|
|
541
|
+
"maxValue",
|
|
542
|
+
"isDisabled",
|
|
543
|
+
"isReadOnly",
|
|
544
|
+
"focusedValue",
|
|
545
|
+
"defaultFocusedValue",
|
|
546
|
+
"onFocusChange",
|
|
547
|
+
"locale",
|
|
548
|
+
"granularity",
|
|
549
|
+
"hourCycle",
|
|
550
|
+
"hideTimeZone",
|
|
551
|
+
"placeholderValue",
|
|
552
|
+
"createCalendar",
|
|
553
|
+
"isDateUnavailable",
|
|
554
|
+
"visibleMonths",
|
|
555
|
+
"isDateDisabled",
|
|
556
|
+
"validationState",
|
|
557
|
+
"allowsNonContiguousRanges",
|
|
558
|
+
"firstDayOfWeek",
|
|
559
|
+
"pageBehavior",
|
|
560
|
+
"selectionAlignment",
|
|
561
|
+
],
|
|
412
562
|
);
|
|
413
563
|
|
|
414
|
-
const [
|
|
564
|
+
const [internalOpen, setInternalOpen] = createSignal(overlayProps.defaultOpen ?? false);
|
|
565
|
+
const isOpen = () => access(overlayProps.isOpen) ?? internalOpen();
|
|
566
|
+
const setOpen = (open: boolean) => {
|
|
567
|
+
if (access(overlayProps.isOpen) === undefined) {
|
|
568
|
+
setInternalOpen(open);
|
|
569
|
+
}
|
|
570
|
+
overlayProps.onOpenChange?.(open);
|
|
571
|
+
};
|
|
572
|
+
|
|
415
573
|
let triggerRef: HTMLElement | null = null;
|
|
416
574
|
const overlayState = {
|
|
417
|
-
get isOpen() {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
575
|
+
get isOpen() {
|
|
576
|
+
return isOpen();
|
|
577
|
+
},
|
|
578
|
+
open: () => setOpen(true),
|
|
579
|
+
close: () => setOpen(false),
|
|
580
|
+
toggle: () => setOpen(!isOpen()),
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
const [internalRangeValue, setInternalRangeValue] = createSignal<RangeValue<T> | null>(
|
|
584
|
+
stateProps.defaultValue ?? null,
|
|
585
|
+
);
|
|
586
|
+
const currentRangeValue = createMemo<RangeValue<T> | null>(() => {
|
|
587
|
+
const controlled = access(stateProps.value);
|
|
588
|
+
return controlled !== undefined ? controlled : internalRangeValue();
|
|
589
|
+
});
|
|
590
|
+
const setCommittedRangeValue = (value: RangeValue<T> | null) => {
|
|
591
|
+
if (access(stateProps.value) === undefined) {
|
|
592
|
+
setInternalRangeValue(() => value);
|
|
593
|
+
}
|
|
594
|
+
stateProps.onChange?.(value);
|
|
421
595
|
};
|
|
422
596
|
|
|
423
597
|
const calendarState = createRangeCalendarState({
|
|
424
598
|
...stateProps,
|
|
599
|
+
value: currentRangeValue,
|
|
425
600
|
onChange: (value) => {
|
|
426
|
-
|
|
601
|
+
setCommittedRangeValue(value);
|
|
427
602
|
if (local.shouldCloseOnSelect !== false && value?.start && value?.end) {
|
|
428
|
-
|
|
603
|
+
setOpen(false);
|
|
429
604
|
}
|
|
430
605
|
},
|
|
431
606
|
});
|
|
607
|
+
|
|
608
|
+
const isInvalid = createMemo(
|
|
609
|
+
() =>
|
|
610
|
+
Boolean((rest as { isInvalid?: boolean }).isInvalid) ||
|
|
611
|
+
calendarState.validationState() === "invalid",
|
|
612
|
+
);
|
|
613
|
+
const isRequired = createMemo(() => Boolean((rest as { isRequired?: boolean }).isRequired));
|
|
614
|
+
const [startFieldValue, setStartFieldValue] = createSignal<T | null>(
|
|
615
|
+
currentRangeValue()?.start ?? null,
|
|
616
|
+
);
|
|
617
|
+
const [endFieldValue, setEndFieldValue] = createSignal<T | null>(
|
|
618
|
+
currentRangeValue()?.end ?? null,
|
|
619
|
+
);
|
|
620
|
+
const rangeGranularity = createMemo<"day" | "hour" | "minute" | "second">(() => {
|
|
621
|
+
if (stateProps.granularity) {
|
|
622
|
+
return stateProps.granularity;
|
|
623
|
+
}
|
|
624
|
+
const value = currentRangeValue()?.start ?? currentRangeValue()?.end;
|
|
625
|
+
if (value && "hour" in value) {
|
|
626
|
+
return "second" in value ? "second" : "minute";
|
|
627
|
+
}
|
|
628
|
+
return "day";
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
createEffect(() => {
|
|
632
|
+
const value = currentRangeValue();
|
|
633
|
+
setStartFieldValue(() => value?.start ?? null);
|
|
634
|
+
setEndFieldValue(() => value?.end ?? null);
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
const setRangeFieldValue = (part: "start" | "end", nextValue: T | null) => {
|
|
638
|
+
if (part === "start") {
|
|
639
|
+
setStartFieldValue(() => nextValue);
|
|
640
|
+
} else {
|
|
641
|
+
setEndFieldValue(() => nextValue);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
const nextStart = part === "start" ? nextValue : startFieldValue();
|
|
645
|
+
const nextEnd = part === "end" ? nextValue : endFieldValue();
|
|
646
|
+
|
|
647
|
+
setCommittedRangeValue(
|
|
648
|
+
nextStart && nextEnd ? ({ start: nextStart, end: nextEnd } as RangeValue<T>) : null,
|
|
649
|
+
);
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
const rangeFieldStateProps = {
|
|
653
|
+
minValue: stateProps.minValue,
|
|
654
|
+
maxValue: stateProps.maxValue,
|
|
655
|
+
isDisabled: stateProps.isDisabled,
|
|
656
|
+
isReadOnly: stateProps.isReadOnly,
|
|
657
|
+
isRequired,
|
|
658
|
+
locale: access(stateProps.locale),
|
|
659
|
+
granularity: rangeGranularity(),
|
|
660
|
+
hourCycle: stateProps.hourCycle,
|
|
661
|
+
hideTimeZone: stateProps.hideTimeZone,
|
|
662
|
+
placeholderValue: stateProps.placeholderValue,
|
|
663
|
+
validationState: () => (isInvalid() ? "invalid" : access(stateProps.validationState)),
|
|
664
|
+
isDateUnavailable: stateProps.isDateUnavailable,
|
|
665
|
+
} satisfies Partial<DateFieldStateProps<T>>;
|
|
666
|
+
|
|
667
|
+
const startFieldState = createDateFieldState<T>({
|
|
668
|
+
...rangeFieldStateProps,
|
|
669
|
+
value: startFieldValue,
|
|
670
|
+
onChange: (value) => setRangeFieldValue("start", value),
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
const endFieldState = createDateFieldState<T>({
|
|
674
|
+
...rangeFieldStateProps,
|
|
675
|
+
value: endFieldValue,
|
|
676
|
+
onChange: (value) => setRangeFieldValue("end", value),
|
|
677
|
+
});
|
|
678
|
+
|
|
432
679
|
const pickerAria = createDateRangePicker(
|
|
433
680
|
() => ({
|
|
434
681
|
...(rest as Record<string, unknown>),
|
|
@@ -436,18 +683,47 @@ function DateRangePickerInner<T extends DateValue = CalendarDate>(
|
|
|
436
683
|
errorMessage: (props as { errorMessage?: string }).errorMessage,
|
|
437
684
|
}),
|
|
438
685
|
calendarState as unknown as RangeCalendarState<DateValue>,
|
|
439
|
-
overlayState as AriaDatePickerState
|
|
686
|
+
overlayState as AriaDatePickerState,
|
|
440
687
|
);
|
|
441
688
|
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
689
|
+
const startFieldContext: DateRangePickerFieldContextValue = {
|
|
690
|
+
state: startFieldState as unknown as DateFieldState<DateValue>,
|
|
691
|
+
aria: {
|
|
692
|
+
labelProps: {},
|
|
693
|
+
get inputProps() {
|
|
694
|
+
return pickerAria.startInputProps;
|
|
695
|
+
},
|
|
696
|
+
get descriptionProps() {
|
|
697
|
+
return pickerAria.descriptionProps;
|
|
698
|
+
},
|
|
699
|
+
get errorMessageProps() {
|
|
700
|
+
return pickerAria.errorMessageProps;
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
const endFieldContext: DateRangePickerFieldContextValue = {
|
|
706
|
+
state: endFieldState as unknown as DateFieldState<DateValue>,
|
|
707
|
+
aria: {
|
|
708
|
+
labelProps: {},
|
|
709
|
+
get inputProps() {
|
|
710
|
+
return pickerAria.endInputProps;
|
|
711
|
+
},
|
|
712
|
+
get descriptionProps() {
|
|
713
|
+
return pickerAria.descriptionProps;
|
|
714
|
+
},
|
|
715
|
+
get errorMessageProps() {
|
|
716
|
+
return pickerAria.errorMessageProps;
|
|
717
|
+
},
|
|
718
|
+
},
|
|
719
|
+
};
|
|
448
720
|
|
|
449
721
|
const contextValue: DateRangePickerContextValue = {
|
|
450
722
|
calendarState: calendarState as unknown as RangeCalendarState<DateValue>,
|
|
723
|
+
startFieldState: startFieldState as unknown as DateFieldState<DateValue>,
|
|
724
|
+
endFieldState: endFieldState as unknown as DateFieldState<DateValue>,
|
|
725
|
+
startFieldContext,
|
|
726
|
+
endFieldContext,
|
|
451
727
|
overlayState,
|
|
452
728
|
triggerRef: () => triggerRef,
|
|
453
729
|
setTriggerRef: (element) => {
|
|
@@ -469,15 +745,19 @@ function DateRangePickerInner<T extends DateValue = CalendarDate>(
|
|
|
469
745
|
{
|
|
470
746
|
class: local.class,
|
|
471
747
|
style: local.style,
|
|
472
|
-
defaultClassName:
|
|
748
|
+
defaultClassName: "solidaria-DateRangePicker",
|
|
473
749
|
},
|
|
474
|
-
renderValues
|
|
750
|
+
renderValues,
|
|
475
751
|
);
|
|
476
752
|
|
|
477
753
|
return (
|
|
478
|
-
<DateRangePickerStateContext.Provider
|
|
754
|
+
<DateRangePickerStateContext.Provider
|
|
755
|
+
value={calendarState as unknown as RangeCalendarState<DateValue>}
|
|
756
|
+
>
|
|
479
757
|
<DateRangePickerContext.Provider value={contextValue}>
|
|
480
|
-
<RangeCalendarContext.Provider
|
|
758
|
+
<RangeCalendarContext.Provider
|
|
759
|
+
value={calendarState as unknown as RangeCalendarState<DateValue>}
|
|
760
|
+
>
|
|
481
761
|
<div
|
|
482
762
|
{...pickerAria.groupProps}
|
|
483
763
|
class={renderProps.class()}
|
|
@@ -490,52 +770,66 @@ function DateRangePickerInner<T extends DateValue = CalendarDate>(
|
|
|
490
770
|
>
|
|
491
771
|
{props.children}
|
|
492
772
|
</div>
|
|
773
|
+
<Show when={(rest as Record<string, unknown>).startName}>
|
|
774
|
+
<HiddenDateInput
|
|
775
|
+
name={(rest as Record<string, unknown>).startName as string | undefined}
|
|
776
|
+
form={(rest as Record<string, unknown>).form as string | undefined}
|
|
777
|
+
value={() => currentRangeValue()?.start ?? null}
|
|
778
|
+
isDisabled={access(stateProps.isDisabled) ?? false}
|
|
779
|
+
minValue={() => access(stateProps.minValue) as DateValue | undefined}
|
|
780
|
+
maxValue={() => access(stateProps.maxValue) as DateValue | undefined}
|
|
781
|
+
granularity={rangeGranularity()}
|
|
782
|
+
/>
|
|
783
|
+
</Show>
|
|
784
|
+
<Show when={(rest as Record<string, unknown>).endName}>
|
|
785
|
+
<HiddenDateInput
|
|
786
|
+
name={(rest as Record<string, unknown>).endName as string | undefined}
|
|
787
|
+
form={(rest as Record<string, unknown>).form as string | undefined}
|
|
788
|
+
value={() => currentRangeValue()?.end ?? null}
|
|
789
|
+
isDisabled={access(stateProps.isDisabled) ?? false}
|
|
790
|
+
minValue={() => access(stateProps.minValue) as DateValue | undefined}
|
|
791
|
+
maxValue={() => access(stateProps.maxValue) as DateValue | undefined}
|
|
792
|
+
granularity={rangeGranularity()}
|
|
793
|
+
/>
|
|
794
|
+
</Show>
|
|
493
795
|
</RangeCalendarContext.Provider>
|
|
494
796
|
</DateRangePickerContext.Provider>
|
|
495
797
|
</DateRangePickerStateContext.Provider>
|
|
496
798
|
);
|
|
497
799
|
}
|
|
498
800
|
|
|
499
|
-
// ============================================
|
|
500
|
-
// DATE PICKER BUTTON COMPONENT
|
|
501
|
-
// ============================================
|
|
502
|
-
|
|
503
801
|
/**
|
|
504
802
|
* A button that opens the date picker calendar.
|
|
505
803
|
*/
|
|
506
804
|
export function DatePickerButton(props: DatePickerButtonProps): JSX.Element {
|
|
507
805
|
const context = useDatePickerContext();
|
|
508
|
-
let buttonRef: HTMLButtonElement | undefined;
|
|
509
806
|
|
|
510
|
-
// Render props values
|
|
511
807
|
const renderValues = createMemo<DatePickerButtonRenderProps>(() => ({
|
|
512
808
|
isDisabled: context.fieldState.isDisabled() || (props.isDisabled ?? false),
|
|
513
809
|
isOpen: context.overlayState.isOpen,
|
|
514
810
|
}));
|
|
515
811
|
|
|
516
|
-
// Resolve render props
|
|
517
812
|
const renderProps = useRenderProps(
|
|
518
813
|
{
|
|
519
814
|
children: props.children,
|
|
520
815
|
class: props.class,
|
|
521
816
|
style: props.style,
|
|
522
|
-
defaultClassName:
|
|
817
|
+
defaultClassName: "solidaria-DatePickerButton",
|
|
523
818
|
},
|
|
524
|
-
renderValues
|
|
819
|
+
renderValues,
|
|
525
820
|
);
|
|
526
821
|
|
|
527
822
|
// Determine children content - avoid Show for SSR hydration compatibility
|
|
528
823
|
const getChildren = () => {
|
|
529
|
-
if (typeof props.children ===
|
|
824
|
+
if (typeof props.children === "function") {
|
|
530
825
|
return renderProps.renderChildren();
|
|
531
826
|
}
|
|
532
|
-
return props.children ??
|
|
827
|
+
return props.children ?? "📅";
|
|
533
828
|
};
|
|
534
829
|
|
|
535
830
|
return (
|
|
536
831
|
<button
|
|
537
832
|
ref={(el) => {
|
|
538
|
-
buttonRef = el;
|
|
539
833
|
context.setTriggerRef(el);
|
|
540
834
|
}}
|
|
541
835
|
{...context.pickerAria.buttonProps}
|
|
@@ -563,16 +857,16 @@ export function DateRangePickerButton(props: DateRangePickerButtonProps): JSX.El
|
|
|
563
857
|
children: props.children,
|
|
564
858
|
class: props.class,
|
|
565
859
|
style: props.style,
|
|
566
|
-
defaultClassName:
|
|
860
|
+
defaultClassName: "solidaria-DateRangePickerButton",
|
|
567
861
|
},
|
|
568
|
-
renderValues
|
|
862
|
+
renderValues,
|
|
569
863
|
);
|
|
570
864
|
|
|
571
865
|
const getChildren = () => {
|
|
572
|
-
if (typeof props.children ===
|
|
866
|
+
if (typeof props.children === "function") {
|
|
573
867
|
return renderProps.renderChildren();
|
|
574
868
|
}
|
|
575
|
-
return props.children ??
|
|
869
|
+
return props.children ?? "📅";
|
|
576
870
|
};
|
|
577
871
|
|
|
578
872
|
return (
|
|
@@ -590,10 +884,6 @@ export function DateRangePickerButton(props: DateRangePickerButtonProps): JSX.El
|
|
|
590
884
|
);
|
|
591
885
|
}
|
|
592
886
|
|
|
593
|
-
// ============================================
|
|
594
|
-
// DATE PICKER CONTENT COMPONENT
|
|
595
|
-
// ============================================
|
|
596
|
-
|
|
597
887
|
export interface DatePickerContentProps extends SlotProps {
|
|
598
888
|
/** The children of the component. */
|
|
599
889
|
children?: JSX.Element;
|
|
@@ -689,6 +979,20 @@ export function DateRangePickerErrorMessage(props: DateRangePickerErrorMessagePr
|
|
|
689
979
|
);
|
|
690
980
|
}
|
|
691
981
|
|
|
982
|
+
function createEscapeDismissFallback(isOpen: () => boolean, close: () => void): void {
|
|
983
|
+
createEffect(() => {
|
|
984
|
+
if (!isOpen() || typeof document === "undefined") return;
|
|
985
|
+
|
|
986
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
987
|
+
if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
|
|
988
|
+
close();
|
|
989
|
+
};
|
|
990
|
+
|
|
991
|
+
document.addEventListener("keydown", onKeyDown);
|
|
992
|
+
onCleanup(() => document.removeEventListener("keydown", onKeyDown));
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
|
|
692
996
|
/**
|
|
693
997
|
* The content area of the date picker (typically contains a Calendar).
|
|
694
998
|
*/
|
|
@@ -700,9 +1004,9 @@ export function DatePickerContent(props: DatePickerContentProps): JSX.Element {
|
|
|
700
1004
|
|
|
701
1005
|
const popoverAria = createPopover(
|
|
702
1006
|
{
|
|
703
|
-
triggerRef: context.triggerRef,
|
|
1007
|
+
triggerRef: () => context.triggerRef()?.parentElement ?? context.triggerRef(),
|
|
704
1008
|
popoverRef: () => contentRef ?? null,
|
|
705
|
-
placement:
|
|
1009
|
+
placement: "bottom start",
|
|
706
1010
|
offset: 8,
|
|
707
1011
|
isNonModal: false,
|
|
708
1012
|
isKeyboardDismissDisabled: false,
|
|
@@ -712,48 +1016,50 @@ export function DatePickerContent(props: DatePickerContentProps): JSX.Element {
|
|
|
712
1016
|
open: context.overlayState.open,
|
|
713
1017
|
close: context.overlayState.close,
|
|
714
1018
|
toggle: context.overlayState.toggle,
|
|
715
|
-
}
|
|
1019
|
+
},
|
|
716
1020
|
);
|
|
717
1021
|
|
|
1022
|
+
createEscapeDismissFallback(() => context.overlayState.isOpen, context.overlayState.close);
|
|
1023
|
+
|
|
718
1024
|
const cleanPopoverProps = () => {
|
|
719
|
-
const {
|
|
1025
|
+
const {
|
|
1026
|
+
style: _style,
|
|
1027
|
+
ref: _ref,
|
|
1028
|
+
...rest
|
|
1029
|
+
} = popoverAria.popoverProps as Record<string, unknown>;
|
|
720
1030
|
return rest;
|
|
721
1031
|
};
|
|
722
1032
|
|
|
723
1033
|
const mergedStyle = (): JSX.CSSProperties => {
|
|
724
|
-
const popoverStyle = (popoverAria.popoverProps as Record<string, unknown>).style as
|
|
1034
|
+
const popoverStyle = (popoverAria.popoverProps as Record<string, unknown>).style as
|
|
1035
|
+
| JSX.CSSProperties
|
|
1036
|
+
| undefined;
|
|
725
1037
|
return {
|
|
726
|
-
...
|
|
727
|
-
...
|
|
1038
|
+
...popoverStyle,
|
|
1039
|
+
...props.style,
|
|
728
1040
|
};
|
|
729
1041
|
};
|
|
730
1042
|
|
|
1043
|
+
// Return focus to trigger when overlay closes
|
|
731
1044
|
createEffect(() => {
|
|
732
|
-
|
|
733
|
-
if (
|
|
734
|
-
|
|
1045
|
+
const open = context.overlayState.isOpen;
|
|
1046
|
+
if (!open) {
|
|
1047
|
+
requestAnimationFrame(() => context.triggerRef()?.focus());
|
|
735
1048
|
}
|
|
736
1049
|
});
|
|
737
1050
|
|
|
738
1051
|
return (
|
|
739
1052
|
<Show when={context.overlayState.isOpen}>
|
|
740
1053
|
<Portal mount={portalContainer()}>
|
|
741
|
-
<FocusScope contain restoreFocus
|
|
1054
|
+
<FocusScope contain restoreFocus>
|
|
742
1055
|
<div
|
|
743
1056
|
ref={contentRef}
|
|
744
1057
|
{...cleanPopoverProps()}
|
|
745
1058
|
{...context.pickerAria.dialogProps}
|
|
746
1059
|
tabIndex={-1}
|
|
747
|
-
class={props.class ??
|
|
1060
|
+
class={props.class ?? "solidaria-DatePickerContent"}
|
|
748
1061
|
style={mergedStyle()}
|
|
749
1062
|
data-placement={popoverAria.placement() ?? undefined}
|
|
750
|
-
onKeyDown={(event) => {
|
|
751
|
-
if (event.key === 'Escape') {
|
|
752
|
-
event.preventDefault();
|
|
753
|
-
event.stopPropagation();
|
|
754
|
-
context.overlayState.close();
|
|
755
|
-
}
|
|
756
|
-
}}
|
|
757
1063
|
>
|
|
758
1064
|
{props.children}
|
|
759
1065
|
</div>
|
|
@@ -771,9 +1077,9 @@ export function DateRangePickerContent(props: DateRangePickerContentProps): JSX.
|
|
|
771
1077
|
|
|
772
1078
|
const popoverAria = createPopover(
|
|
773
1079
|
{
|
|
774
|
-
triggerRef: context.triggerRef,
|
|
1080
|
+
triggerRef: () => context.triggerRef()?.parentElement ?? context.triggerRef(),
|
|
775
1081
|
popoverRef: () => contentRef ?? null,
|
|
776
|
-
placement:
|
|
1082
|
+
placement: "bottom start",
|
|
777
1083
|
offset: 8,
|
|
778
1084
|
isNonModal: false,
|
|
779
1085
|
isKeyboardDismissDisabled: false,
|
|
@@ -783,48 +1089,50 @@ export function DateRangePickerContent(props: DateRangePickerContentProps): JSX.
|
|
|
783
1089
|
open: context.overlayState.open,
|
|
784
1090
|
close: context.overlayState.close,
|
|
785
1091
|
toggle: context.overlayState.toggle,
|
|
786
|
-
}
|
|
1092
|
+
},
|
|
787
1093
|
);
|
|
788
1094
|
|
|
1095
|
+
createEscapeDismissFallback(() => context.overlayState.isOpen, context.overlayState.close);
|
|
1096
|
+
|
|
789
1097
|
const cleanPopoverProps = () => {
|
|
790
|
-
const {
|
|
1098
|
+
const {
|
|
1099
|
+
style: _style,
|
|
1100
|
+
ref: _ref,
|
|
1101
|
+
...rest
|
|
1102
|
+
} = popoverAria.popoverProps as Record<string, unknown>;
|
|
791
1103
|
return rest;
|
|
792
1104
|
};
|
|
793
1105
|
|
|
794
1106
|
const mergedStyle = (): JSX.CSSProperties => {
|
|
795
|
-
const popoverStyle = (popoverAria.popoverProps as Record<string, unknown>).style as
|
|
1107
|
+
const popoverStyle = (popoverAria.popoverProps as Record<string, unknown>).style as
|
|
1108
|
+
| JSX.CSSProperties
|
|
1109
|
+
| undefined;
|
|
796
1110
|
return {
|
|
797
|
-
...
|
|
798
|
-
...
|
|
1111
|
+
...popoverStyle,
|
|
1112
|
+
...props.style,
|
|
799
1113
|
};
|
|
800
1114
|
};
|
|
801
1115
|
|
|
1116
|
+
// Return focus to trigger when overlay closes
|
|
802
1117
|
createEffect(() => {
|
|
803
|
-
|
|
804
|
-
if (
|
|
805
|
-
|
|
1118
|
+
const open = context.overlayState.isOpen;
|
|
1119
|
+
if (!open) {
|
|
1120
|
+
requestAnimationFrame(() => context.triggerRef()?.focus());
|
|
806
1121
|
}
|
|
807
1122
|
});
|
|
808
1123
|
|
|
809
1124
|
return (
|
|
810
1125
|
<Show when={context.overlayState.isOpen}>
|
|
811
1126
|
<Portal mount={portalContainer()}>
|
|
812
|
-
<FocusScope contain restoreFocus
|
|
1127
|
+
<FocusScope contain restoreFocus>
|
|
813
1128
|
<div
|
|
814
1129
|
ref={contentRef}
|
|
815
1130
|
{...cleanPopoverProps()}
|
|
816
1131
|
{...context.pickerAria.dialogProps}
|
|
817
1132
|
tabIndex={-1}
|
|
818
|
-
class={props.class ??
|
|
1133
|
+
class={props.class ?? "solidaria-DateRangePickerContent"}
|
|
819
1134
|
style={mergedStyle()}
|
|
820
1135
|
data-placement={popoverAria.placement() ?? undefined}
|
|
821
|
-
onKeyDown={(event) => {
|
|
822
|
-
if (event.key === 'Escape') {
|
|
823
|
-
event.preventDefault();
|
|
824
|
-
event.stopPropagation();
|
|
825
|
-
context.overlayState.close();
|
|
826
|
-
}
|
|
827
|
-
}}
|
|
828
1136
|
>
|
|
829
1137
|
{props.children}
|
|
830
1138
|
</div>
|
|
@@ -834,4 +1142,7 @@ export function DateRangePickerContent(props: DateRangePickerContentProps): JSX.
|
|
|
834
1142
|
);
|
|
835
1143
|
}
|
|
836
1144
|
|
|
1145
|
+
export { HiddenDateInput } from "./HiddenDateInput";
|
|
1146
|
+
export type { HiddenDateInputProps } from "./HiddenDateInput";
|
|
1147
|
+
|
|
837
1148
|
// DatePickerContextValue is already exported at declaration
|