@fluixi-ui/date-picker 0.3.0-alpha.18 → 0.3.0-alpha.20
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/dist/date-picker.js +325 -220
- package/dist/date-range-picker.js +369 -256
- package/dist/index.js +3 -18
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +6 -6
package/dist/date-picker.js
CHANGED
|
@@ -1,236 +1,341 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createComponent, createNativeElement, delegateEvents, handleRef, insert, mergeProps, splitProps, spread } from "@fluixi/dom";
|
|
2
|
+
import { createEffect, createMemo, createRenderEffect, createSignal } from "@fluixi/reactive/signal";
|
|
3
3
|
import { fxProps } from "@fluixi-ui/fx";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { Portal,
|
|
4
|
+
import { Show, useRef } from "@fluixi/core";
|
|
5
|
+
import { composeEventHandlers, composeId, createControllableBooleanSignal, createControllableSignal, createId, createSafeContext } from "@fluixi-ui/kit";
|
|
6
|
+
import { Portal, createDismissableLayer, createFloatingPosition, createFocusScope } from "@fluixi-ui/primitives";
|
|
7
7
|
import { DateField, DateInput } from "@fluixi-ui/date-field";
|
|
8
|
-
import { Calendar,
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { Calendar, CalendarGrid, CalendarHeader, CalendarHeading, CalendarNextButton, CalendarPrevButton } from "@fluixi-ui/calendar";
|
|
9
|
+
//#region src/date-picker.tsx
|
|
10
|
+
delegateEvents([
|
|
11
|
+
"change",
|
|
12
|
+
"keydown",
|
|
13
|
+
"click"
|
|
14
|
+
]);
|
|
15
|
+
var [DatePickerProvider, useDatePickerContext] = createSafeContext("DatePicker");
|
|
16
|
+
/**
|
|
17
|
+
* A date picker: a segmented field paired with a popover calendar over one
|
|
18
|
+
* shared value. Typing in the field and picking in the calendar stay in sync;
|
|
19
|
+
* selecting a day closes the popover.
|
|
20
|
+
*/
|
|
11
21
|
function DatePicker(props) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
22
|
+
const [value, setValue] = createControllableSignal({
|
|
23
|
+
value: () => props.value ?? void 0,
|
|
24
|
+
defaultValue: () => props.defaultValue ?? null,
|
|
25
|
+
onChange: (v) => props.onChange?.(v)
|
|
26
|
+
});
|
|
27
|
+
const [isOpen, setOpen] = createControllableBooleanSignal({
|
|
28
|
+
value: () => props.open,
|
|
29
|
+
defaultValue: () => props.defaultOpen ?? false,
|
|
30
|
+
onChange: (o) => props.onOpenChange?.(o)
|
|
31
|
+
});
|
|
32
|
+
const baseId = createId("date-picker");
|
|
33
|
+
const [triggerRef, setTriggerRef] = createSignal(void 0);
|
|
34
|
+
const ctx = {
|
|
35
|
+
value: () => value() ?? null,
|
|
36
|
+
setValue,
|
|
37
|
+
isOpen,
|
|
38
|
+
setOpen: (o) => setOpen(o),
|
|
39
|
+
ids: {
|
|
40
|
+
label: composeId(baseId, "label"),
|
|
41
|
+
content: composeId(baseId, "content")
|
|
42
|
+
},
|
|
43
|
+
triggerRef,
|
|
44
|
+
setTriggerRef,
|
|
45
|
+
placement: props.placement ?? "bottom-start",
|
|
46
|
+
offset: props.offset ?? 6,
|
|
47
|
+
locale: () => props.locale,
|
|
48
|
+
granularity: props.granularity,
|
|
49
|
+
hourCycle: props.hourCycle,
|
|
50
|
+
minValue: () => props.minValue,
|
|
51
|
+
maxValue: () => props.maxValue,
|
|
52
|
+
isDisabled: () => props.isDisabled ?? false,
|
|
53
|
+
isReadOnly: () => props.isReadOnly ?? false,
|
|
54
|
+
isDateUnavailable: props.isDateUnavailable,
|
|
55
|
+
name: props.name
|
|
56
|
+
};
|
|
57
|
+
return createMemo(() => createComponent(DatePickerProvider, {
|
|
58
|
+
get value() {
|
|
59
|
+
return ctx;
|
|
60
|
+
},
|
|
61
|
+
get children() {
|
|
62
|
+
return props.children;
|
|
63
|
+
}
|
|
64
|
+
}));
|
|
49
65
|
}
|
|
66
|
+
/** Field label; linked to the segmented input. */
|
|
50
67
|
function DatePickerLabel(props) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
const ctx = useDatePickerContext();
|
|
69
|
+
const [local, others] = splitProps(props, [
|
|
70
|
+
"children",
|
|
71
|
+
"fx",
|
|
72
|
+
"style"
|
|
73
|
+
]);
|
|
74
|
+
return (() => {
|
|
75
|
+
const _el$ = createNativeElement("span");
|
|
76
|
+
spread({
|
|
77
|
+
element: _el$,
|
|
78
|
+
props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
|
|
79
|
+
id: () => ctx.ids.label,
|
|
80
|
+
"data-date-picker-label": ""
|
|
81
|
+
})
|
|
82
|
+
});
|
|
83
|
+
insert(_el$, local.children, null);
|
|
84
|
+
return _el$;
|
|
85
|
+
})();
|
|
62
86
|
}
|
|
87
|
+
/** The bordered control: the segmented date field plus the calendar trigger. */
|
|
63
88
|
function DatePickerField(props) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
89
|
+
const ctx = useDatePickerContext();
|
|
90
|
+
const [local, others] = splitProps(props, [
|
|
91
|
+
"ref",
|
|
92
|
+
"children",
|
|
93
|
+
"fx",
|
|
94
|
+
"style"
|
|
95
|
+
]);
|
|
96
|
+
const setRef = (node) => {
|
|
97
|
+
ctx.setTriggerRef(node);
|
|
98
|
+
handleRef(local.ref, node);
|
|
99
|
+
};
|
|
100
|
+
return createMemo(() => createComponent(DateField, {
|
|
101
|
+
get value() {
|
|
102
|
+
return ctx.value;
|
|
103
|
+
},
|
|
104
|
+
get onChange() {
|
|
105
|
+
return ctx.setValue;
|
|
106
|
+
},
|
|
107
|
+
get locale() {
|
|
108
|
+
return ctx.locale;
|
|
109
|
+
},
|
|
110
|
+
get granularity() {
|
|
111
|
+
return ctx.granularity;
|
|
112
|
+
},
|
|
113
|
+
get hourCycle() {
|
|
114
|
+
return ctx.hourCycle;
|
|
115
|
+
},
|
|
116
|
+
get minValue() {
|
|
117
|
+
return ctx.minValue;
|
|
118
|
+
},
|
|
119
|
+
get maxValue() {
|
|
120
|
+
return ctx.maxValue;
|
|
121
|
+
},
|
|
122
|
+
get isDisabled() {
|
|
123
|
+
return ctx.isDisabled;
|
|
124
|
+
},
|
|
125
|
+
get isReadOnly() {
|
|
126
|
+
return ctx.isReadOnly;
|
|
127
|
+
},
|
|
128
|
+
get name() {
|
|
129
|
+
return ctx.name;
|
|
130
|
+
},
|
|
131
|
+
get "data-date-picker"() {
|
|
132
|
+
return "";
|
|
133
|
+
},
|
|
134
|
+
get children() {
|
|
135
|
+
return (() => {
|
|
136
|
+
const _el$ = createNativeElement("div");
|
|
137
|
+
spread({
|
|
138
|
+
element: _el$,
|
|
139
|
+
props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
|
|
140
|
+
ref: setRef,
|
|
141
|
+
"data-date-picker-control": ""
|
|
142
|
+
})
|
|
143
|
+
});
|
|
144
|
+
insert(_el$, createMemo(() => createComponent(DateInput, {
|
|
145
|
+
get "aria-labelledby"() {
|
|
146
|
+
return ctx.ids.label;
|
|
147
|
+
},
|
|
148
|
+
get "data-date-picker-input"() {
|
|
149
|
+
return "";
|
|
150
|
+
}
|
|
151
|
+
})), null);
|
|
152
|
+
insert(_el$, local.children ?? createMemo(() => createComponent(DatePickerTrigger, {})), null);
|
|
153
|
+
return _el$;
|
|
154
|
+
})();
|
|
155
|
+
}
|
|
156
|
+
}));
|
|
108
157
|
}
|
|
158
|
+
/** Toggles the calendar popover. */
|
|
109
159
|
function DatePickerTrigger(props) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
160
|
+
const ctx = useDatePickerContext();
|
|
161
|
+
const [local, others] = splitProps(props, [
|
|
162
|
+
"onClick",
|
|
163
|
+
"children",
|
|
164
|
+
"fx",
|
|
165
|
+
"style"
|
|
166
|
+
]);
|
|
167
|
+
return (() => {
|
|
168
|
+
const _el$ = createNativeElement("button");
|
|
169
|
+
spread({
|
|
170
|
+
element: _el$,
|
|
171
|
+
props: mergeProps(fxProps(() => local.fx, () => local.style), others, {
|
|
172
|
+
type: "button",
|
|
173
|
+
"aria-haspopup": "dialog",
|
|
174
|
+
"aria-expanded": () => ctx.isOpen() ? "true" : "false",
|
|
175
|
+
"aria-controls": () => ctx.ids.content,
|
|
176
|
+
"aria-label": "Open calendar",
|
|
177
|
+
disabled: () => ctx.isDisabled(),
|
|
178
|
+
"data-date-picker-trigger": "",
|
|
179
|
+
onClick: composeEventHandlers([local.onClick, () => {
|
|
180
|
+
if (ctx.isDisabled() || ctx.isReadOnly()) return;
|
|
181
|
+
ctx.setOpen(!ctx.isOpen());
|
|
182
|
+
}])
|
|
183
|
+
})
|
|
184
|
+
});
|
|
185
|
+
insert(_el$, local.children ?? "📅", null);
|
|
186
|
+
return _el$;
|
|
187
|
+
})();
|
|
127
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* The floating calendar panel. Renders a default calendar bound to the shared
|
|
191
|
+
* value (override by passing children); selecting a day closes the popover.
|
|
192
|
+
*/
|
|
128
193
|
function DatePickerContent(props) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
194
|
+
const ctx = useDatePickerContext();
|
|
195
|
+
const [local, others] = splitProps(props, [
|
|
196
|
+
"ref",
|
|
197
|
+
"children",
|
|
198
|
+
"style",
|
|
199
|
+
"fx",
|
|
200
|
+
"style"
|
|
201
|
+
]);
|
|
202
|
+
const [element, setElement] = createSignal(void 0);
|
|
203
|
+
const portalRef = useRef(null);
|
|
204
|
+
createEffect(() => {
|
|
205
|
+
if (!ctx.isOpen() && portalRef.current) portalRef.current.remove();
|
|
206
|
+
});
|
|
207
|
+
return createMemo(() => createComponent(Show, {
|
|
208
|
+
get when() {
|
|
209
|
+
return ctx.isOpen();
|
|
210
|
+
},
|
|
211
|
+
get children() {
|
|
212
|
+
return createMemo(() => createComponent(Portal, {
|
|
213
|
+
get ref() {
|
|
214
|
+
return portalRef;
|
|
215
|
+
},
|
|
216
|
+
get children() {
|
|
217
|
+
return createMemo(() => createComponent(FloatingPanel, mergeProps(others, {
|
|
218
|
+
get setElement() {
|
|
219
|
+
return setElement;
|
|
220
|
+
},
|
|
221
|
+
get element() {
|
|
222
|
+
return element;
|
|
223
|
+
},
|
|
224
|
+
get forwardRef() {
|
|
225
|
+
return local.ref;
|
|
226
|
+
},
|
|
227
|
+
get fx() {
|
|
228
|
+
return local.fx;
|
|
229
|
+
},
|
|
230
|
+
get style() {
|
|
231
|
+
return local.style;
|
|
232
|
+
},
|
|
233
|
+
get children() {
|
|
234
|
+
return local.children ?? createMemo(() => createComponent(DatePickerCalendar, {}));
|
|
235
|
+
}
|
|
236
|
+
})));
|
|
237
|
+
}
|
|
238
|
+
}));
|
|
239
|
+
}
|
|
240
|
+
}));
|
|
157
241
|
}
|
|
242
|
+
/** Inner panel — split out so the floating hooks run inside the portal. */
|
|
158
243
|
function FloatingPanel(props) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
244
|
+
const ctx = useDatePickerContext();
|
|
245
|
+
const position = createFloatingPosition(ctx.triggerRef, props.element, {
|
|
246
|
+
placement: ctx.placement,
|
|
247
|
+
offset: ctx.offset
|
|
248
|
+
});
|
|
249
|
+
createDismissableLayer(props.element, {
|
|
250
|
+
shouldExcludeTarget: (target) => {
|
|
251
|
+
const trigger = ctx.triggerRef();
|
|
252
|
+
return !!trigger && (trigger === target || trigger.contains(target));
|
|
253
|
+
},
|
|
254
|
+
onDismiss: () => ctx.setOpen(false)
|
|
255
|
+
});
|
|
256
|
+
createFocusScope(props.element, {
|
|
257
|
+
trap: false,
|
|
258
|
+
autoFocus: true,
|
|
259
|
+
restoreFocus: true
|
|
260
|
+
});
|
|
261
|
+
createRenderEffect(() => {
|
|
262
|
+
const el = props.element();
|
|
263
|
+
if (!el) return;
|
|
264
|
+
el.style.position = "absolute";
|
|
265
|
+
el.style.left = `${Math.round(position.x())}px`;
|
|
266
|
+
el.style.top = `${Math.round(position.y())}px`;
|
|
267
|
+
});
|
|
268
|
+
const setRef = (node) => {
|
|
269
|
+
props.setElement(node);
|
|
270
|
+
handleRef(props.forwardRef, node);
|
|
271
|
+
};
|
|
272
|
+
return (() => {
|
|
273
|
+
const _el$ = createNativeElement("div");
|
|
274
|
+
spread({
|
|
275
|
+
element: _el$,
|
|
276
|
+
props: mergeProps(fxProps(() => props.fx, () => props.style), {
|
|
277
|
+
ref: setRef,
|
|
278
|
+
role: "dialog",
|
|
279
|
+
id: () => ctx.ids.content,
|
|
280
|
+
"aria-label": "Calendar",
|
|
281
|
+
"data-date-picker-content": "",
|
|
282
|
+
"data-placement": () => position.placement(),
|
|
283
|
+
tabindex: -1,
|
|
284
|
+
onKeyDown: (e) => {
|
|
285
|
+
if (e.key === "Escape") {
|
|
286
|
+
e.stopPropagation();
|
|
287
|
+
ctx.setOpen(false);
|
|
288
|
+
ctx.triggerRef()?.querySelector("[data-date-picker-trigger]")?.focus();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
});
|
|
293
|
+
insert(_el$, props.children, null);
|
|
294
|
+
return _el$;
|
|
295
|
+
})();
|
|
198
296
|
}
|
|
297
|
+
/** Default calendar inside the popover; closes on selection. */
|
|
199
298
|
function DatePickerCalendar() {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
299
|
+
const ctx = useDatePickerContext();
|
|
300
|
+
return createMemo(() => createComponent(Calendar, {
|
|
301
|
+
get value() {
|
|
302
|
+
return ctx.value;
|
|
303
|
+
},
|
|
304
|
+
get onChange() {
|
|
305
|
+
return (v) => {
|
|
306
|
+
ctx.setValue(v);
|
|
307
|
+
ctx.setOpen(false);
|
|
308
|
+
};
|
|
309
|
+
},
|
|
310
|
+
get locale() {
|
|
311
|
+
return ctx.locale;
|
|
312
|
+
},
|
|
313
|
+
get minValue() {
|
|
314
|
+
return ctx.minValue;
|
|
315
|
+
},
|
|
316
|
+
get maxValue() {
|
|
317
|
+
return ctx.maxValue;
|
|
318
|
+
},
|
|
319
|
+
get isDateUnavailable() {
|
|
320
|
+
return ctx.isDateUnavailable;
|
|
321
|
+
},
|
|
322
|
+
get "data-date-picker-calendar"() {
|
|
323
|
+
return "";
|
|
324
|
+
},
|
|
325
|
+
get children() {
|
|
326
|
+
return [createMemo(() => createComponent(CalendarHeader, { get children() {
|
|
327
|
+
return [
|
|
328
|
+
createMemo(() => createComponent(CalendarPrevButton, { get children() {
|
|
329
|
+
return "‹";
|
|
330
|
+
} })),
|
|
331
|
+
createMemo(() => createComponent(CalendarHeading, {})),
|
|
332
|
+
createMemo(() => createComponent(CalendarNextButton, { get children() {
|
|
333
|
+
return "›";
|
|
334
|
+
} }))
|
|
335
|
+
];
|
|
336
|
+
} })), createMemo(() => createComponent(CalendarGrid, {}))];
|
|
337
|
+
}
|
|
338
|
+
}));
|
|
227
339
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
DatePickerCalendar,
|
|
231
|
-
DatePickerContent,
|
|
232
|
-
DatePickerField,
|
|
233
|
-
DatePickerLabel,
|
|
234
|
-
DatePickerTrigger,
|
|
235
|
-
useDatePickerContext
|
|
236
|
-
};
|
|
340
|
+
//#endregion
|
|
341
|
+
export { DatePicker, DatePickerCalendar, DatePickerContent, DatePickerField, DatePickerLabel, DatePickerTrigger, useDatePickerContext };
|