@kopexa/date-picker 1.2.1 → 1.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/dist/{chunk-HPM5Y2V6.mjs → chunk-6IFLG64O.mjs} +5 -0
- package/dist/{chunk-VYQ6BFFN.mjs → chunk-BA6CJAOH.mjs} +431 -22
- package/dist/date-picker-field.d.mts +38 -1
- package/dist/date-picker-field.d.ts +38 -1
- package/dist/date-picker-field.js +423 -19
- package/dist/date-picker-field.mjs +2 -2
- package/dist/date-picker-messages.d.mts +5 -0
- package/dist/date-picker-messages.d.ts +5 -0
- package/dist/date-picker-messages.js +5 -0
- package/dist/date-picker-messages.mjs +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +423 -19
- package/dist/index.mjs +2 -2
- package/package.json +2 -2
|
@@ -27,6 +27,11 @@ var datePickerMessages = defineMessages({
|
|
|
27
27
|
id: "date-picker.select_date_and_time",
|
|
28
28
|
defaultMessage: "Select date and time",
|
|
29
29
|
description: "Placeholder for date+time input"
|
|
30
|
+
},
|
|
31
|
+
save: {
|
|
32
|
+
id: "date-picker.save",
|
|
33
|
+
defaultMessage: "Save",
|
|
34
|
+
description: "Button to commit the staged date selection (only shown when an onSave callback is provided)"
|
|
30
35
|
}
|
|
31
36
|
});
|
|
32
37
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
datePickerMessages
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6IFLG64O.mjs";
|
|
5
5
|
|
|
6
6
|
// src/date-picker-field.tsx
|
|
7
7
|
import {
|
|
@@ -24,14 +24,24 @@ import {
|
|
|
24
24
|
DatePickerTableHeader,
|
|
25
25
|
DatePickerTableRow,
|
|
26
26
|
DatePickerTrigger,
|
|
27
|
+
DatePickerValueText,
|
|
27
28
|
DatePickerView,
|
|
28
29
|
DatePickerViewControl,
|
|
29
30
|
DatePickerViewTrigger
|
|
30
31
|
} from "@ark-ui/react/date-picker";
|
|
31
32
|
import { Portal } from "@ark-ui/react/portal";
|
|
32
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
CalendarDate,
|
|
35
|
+
CalendarDateTime,
|
|
36
|
+
getLocalTimeZone
|
|
37
|
+
} from "@internationalized/date";
|
|
33
38
|
import { useSafeIntl } from "@kopexa/i18n";
|
|
34
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
useCallback,
|
|
41
|
+
useEffect,
|
|
42
|
+
useMemo,
|
|
43
|
+
useState
|
|
44
|
+
} from "react";
|
|
35
45
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
36
46
|
function CalendarIcon({ className }) {
|
|
37
47
|
return /* @__PURE__ */ jsxs(
|
|
@@ -109,6 +119,55 @@ function XIcon({ className }) {
|
|
|
109
119
|
}
|
|
110
120
|
);
|
|
111
121
|
}
|
|
122
|
+
function getDatePartOrder(locale) {
|
|
123
|
+
try {
|
|
124
|
+
const fmt = new Intl.DateTimeFormat(locale, {
|
|
125
|
+
day: "2-digit",
|
|
126
|
+
month: "2-digit",
|
|
127
|
+
year: "numeric"
|
|
128
|
+
});
|
|
129
|
+
return fmt.formatToParts(new Date(2024, 0, 1)).filter(
|
|
130
|
+
(p) => p.type === "day" || p.type === "month" || p.type === "year"
|
|
131
|
+
).map((p) => p.type);
|
|
132
|
+
} catch {
|
|
133
|
+
return ["day", "month", "year"];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function finalizeDateParts(parts) {
|
|
137
|
+
var _a, _b, _c;
|
|
138
|
+
const day = (_a = parts.day) != null ? _a : 1;
|
|
139
|
+
const month = (_b = parts.month) != null ? _b : 1;
|
|
140
|
+
let year = (_c = parts.year) != null ? _c : (/* @__PURE__ */ new Date()).getFullYear();
|
|
141
|
+
if (year < 100) year = year < 50 ? 2e3 + year : 1900 + year;
|
|
142
|
+
if (month < 1 || month > 12) return void 0;
|
|
143
|
+
if (day < 1 || day > 31) return void 0;
|
|
144
|
+
return { year, month, day };
|
|
145
|
+
}
|
|
146
|
+
function parseLocalizedDate(value, locale) {
|
|
147
|
+
const trimmed = value.trim();
|
|
148
|
+
if (!trimmed) return void 0;
|
|
149
|
+
const order = getDatePartOrder(locale);
|
|
150
|
+
const segments = trimmed.split(/[./\-\s]+/).filter(Boolean);
|
|
151
|
+
if (segments.length === 3 && segments.every((s) => /^\d+$/.test(s))) {
|
|
152
|
+
const map2 = {};
|
|
153
|
+
order.forEach((field, i) => {
|
|
154
|
+
map2[field] = Number.parseInt(segments[i], 10);
|
|
155
|
+
});
|
|
156
|
+
return finalizeDateParts(map2);
|
|
157
|
+
}
|
|
158
|
+
const digits = trimmed.replace(/\D/g, "");
|
|
159
|
+
const widths = digits.length === 8 ? { day: 2, month: 2, year: 4 } : digits.length === 6 ? { day: 2, month: 2, year: 2 } : digits.length === 4 ? { day: 2, month: 2, year: 0 } : null;
|
|
160
|
+
if (!widths) return void 0;
|
|
161
|
+
let pos = 0;
|
|
162
|
+
const map = {};
|
|
163
|
+
for (const field of order) {
|
|
164
|
+
const w = widths[field];
|
|
165
|
+
if (w === 0) continue;
|
|
166
|
+
map[field] = Number.parseInt(digits.slice(pos, pos + w), 10);
|
|
167
|
+
pos += w;
|
|
168
|
+
}
|
|
169
|
+
return finalizeDateParts(map);
|
|
170
|
+
}
|
|
112
171
|
var styles = {
|
|
113
172
|
control: "relative flex items-center",
|
|
114
173
|
input: "w-full h-9 rounded-md border bg-transparent pl-3 pr-9 text-sm outline-none focus:ring-2 focus:ring-ring",
|
|
@@ -132,9 +191,14 @@ var styles = {
|
|
|
132
191
|
yearCellTrigger: "inline-flex items-center justify-center w-full py-2 text-sm rounded-md transition-colors hover:bg-muted data-[selected]:bg-primary data-[selected]:text-primary-foreground data-[disabled]:text-muted-foreground/30 data-[disabled]:pointer-events-none",
|
|
133
192
|
footer: "flex items-center gap-1 pt-2 mt-2 border-t",
|
|
134
193
|
footerButton: "text-sm px-2 py-1 rounded-md hover:bg-muted transition-colors",
|
|
194
|
+
footerSaveButton: "ml-auto text-sm px-3 py-1 rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors",
|
|
135
195
|
timeInput: "h-9 rounded-md border bg-transparent px-3 text-sm outline-none focus:ring-2 focus:ring-ring",
|
|
136
196
|
label: "text-sm font-medium",
|
|
137
|
-
timeTrigger: "flex-1 h-9 rounded-md border bg-transparent px-3 text-sm text-left hover:bg-muted transition-colors flex items-center justify-between"
|
|
197
|
+
timeTrigger: "flex-1 h-9 rounded-md border bg-transparent px-3 text-sm text-left hover:bg-muted transition-colors flex items-center justify-between",
|
|
198
|
+
defaultGhostTrigger: "inline-flex items-center gap-2 h-9 rounded-md px-2.5 text-sm font-normal text-foreground transition-colors hover:bg-muted focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[placeholder]:text-muted-foreground",
|
|
199
|
+
defaultGhostPlaceholder: "text-muted-foreground",
|
|
200
|
+
timeRow: "mt-2 pt-2 border-t flex items-center gap-2",
|
|
201
|
+
timeRowLabel: "text-xs text-muted-foreground"
|
|
138
202
|
};
|
|
139
203
|
function DayView() {
|
|
140
204
|
return /* @__PURE__ */ jsx(DatePickerView, { view: "day", children: /* @__PURE__ */ jsx(DatePickerContext, { children: (api) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -239,9 +303,19 @@ function YearView() {
|
|
|
239
303
|
)) }) })
|
|
240
304
|
] }) }) });
|
|
241
305
|
}
|
|
306
|
+
function CalendarPanel() {
|
|
307
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
308
|
+
/* @__PURE__ */ jsx(DayView, {}),
|
|
309
|
+
/* @__PURE__ */ jsx(MonthView, {}),
|
|
310
|
+
/* @__PURE__ */ jsx(YearView, {})
|
|
311
|
+
] });
|
|
312
|
+
}
|
|
242
313
|
function CalendarFooter({
|
|
243
314
|
todayLabel,
|
|
244
|
-
clearLabel
|
|
315
|
+
clearLabel,
|
|
316
|
+
saveLabel,
|
|
317
|
+
clearable = true,
|
|
318
|
+
onSave
|
|
245
319
|
}) {
|
|
246
320
|
return /* @__PURE__ */ jsx(DatePickerContext, { children: (api) => /* @__PURE__ */ jsxs("div", { className: styles.footer, children: [
|
|
247
321
|
/* @__PURE__ */ jsx(
|
|
@@ -253,7 +327,7 @@ function CalendarFooter({
|
|
|
253
327
|
children: todayLabel
|
|
254
328
|
}
|
|
255
329
|
),
|
|
256
|
-
/* @__PURE__ */ jsx(
|
|
330
|
+
clearable && /* @__PURE__ */ jsx(
|
|
257
331
|
"button",
|
|
258
332
|
{
|
|
259
333
|
type: "button",
|
|
@@ -261,6 +335,64 @@ function CalendarFooter({
|
|
|
261
335
|
className: `${styles.footerButton} text-destructive`,
|
|
262
336
|
children: clearLabel
|
|
263
337
|
}
|
|
338
|
+
),
|
|
339
|
+
onSave && /* @__PURE__ */ jsx(
|
|
340
|
+
"button",
|
|
341
|
+
{
|
|
342
|
+
type: "button",
|
|
343
|
+
onClick: () => {
|
|
344
|
+
onSave({
|
|
345
|
+
value: api.value,
|
|
346
|
+
valueAsString: api.valueAsString,
|
|
347
|
+
view: api.view
|
|
348
|
+
});
|
|
349
|
+
api.setOpen(false);
|
|
350
|
+
},
|
|
351
|
+
className: styles.footerSaveButton,
|
|
352
|
+
children: saveLabel
|
|
353
|
+
}
|
|
354
|
+
)
|
|
355
|
+
] }) });
|
|
356
|
+
}
|
|
357
|
+
function DateTimeFooter({
|
|
358
|
+
todayLabel,
|
|
359
|
+
clearLabel,
|
|
360
|
+
saveLabel,
|
|
361
|
+
clearable = true,
|
|
362
|
+
onSelectNow,
|
|
363
|
+
onClear,
|
|
364
|
+
onSave
|
|
365
|
+
}) {
|
|
366
|
+
return /* @__PURE__ */ jsx(DatePickerContext, { children: (api) => /* @__PURE__ */ jsxs("div", { className: styles.footer, children: [
|
|
367
|
+
/* @__PURE__ */ jsx(
|
|
368
|
+
"button",
|
|
369
|
+
{
|
|
370
|
+
type: "button",
|
|
371
|
+
onClick: onSelectNow,
|
|
372
|
+
className: `${styles.footerButton} text-foreground`,
|
|
373
|
+
children: todayLabel
|
|
374
|
+
}
|
|
375
|
+
),
|
|
376
|
+
clearable && /* @__PURE__ */ jsx(
|
|
377
|
+
"button",
|
|
378
|
+
{
|
|
379
|
+
type: "button",
|
|
380
|
+
onClick: onClear,
|
|
381
|
+
className: `${styles.footerButton} text-destructive`,
|
|
382
|
+
children: clearLabel
|
|
383
|
+
}
|
|
384
|
+
),
|
|
385
|
+
onSave && /* @__PURE__ */ jsx(
|
|
386
|
+
"button",
|
|
387
|
+
{
|
|
388
|
+
type: "button",
|
|
389
|
+
onClick: () => {
|
|
390
|
+
onSave();
|
|
391
|
+
api.setOpen(false);
|
|
392
|
+
},
|
|
393
|
+
className: styles.footerSaveButton,
|
|
394
|
+
children: saveLabel
|
|
395
|
+
}
|
|
264
396
|
)
|
|
265
397
|
] }) });
|
|
266
398
|
}
|
|
@@ -280,16 +412,49 @@ function DatePickerField({
|
|
|
280
412
|
todayLabel: todayLabelProp,
|
|
281
413
|
clearLabel: clearLabelProp,
|
|
282
414
|
className,
|
|
283
|
-
rootProps
|
|
415
|
+
rootProps,
|
|
416
|
+
variant = "input",
|
|
417
|
+
trigger,
|
|
418
|
+
formatValue,
|
|
419
|
+
onSave,
|
|
420
|
+
saveLabel: saveLabelProp
|
|
284
421
|
}) {
|
|
285
422
|
var _a;
|
|
286
423
|
const intl = useSafeIntl();
|
|
287
424
|
const locale = (_a = localeProp != null ? localeProp : intl.locale) != null ? _a : "en-US";
|
|
288
425
|
const todayLabel = todayLabelProp != null ? todayLabelProp : intl.formatMessage(datePickerMessages.today);
|
|
289
426
|
const clearLabel = clearLabelProp != null ? clearLabelProp : intl.formatMessage(datePickerMessages.clear);
|
|
427
|
+
const saveLabel = saveLabelProp != null ? saveLabelProp : intl.formatMessage(datePickerMessages.save);
|
|
290
428
|
const placeholder = placeholderProp != null ? placeholderProp : intl.formatMessage(
|
|
291
429
|
showTime ? datePickerMessages.select_date_and_time : datePickerMessages.select_date
|
|
292
430
|
);
|
|
431
|
+
if (variant === "trigger") {
|
|
432
|
+
return /* @__PURE__ */ jsx(
|
|
433
|
+
DateTriggerPickerField,
|
|
434
|
+
{
|
|
435
|
+
label,
|
|
436
|
+
value,
|
|
437
|
+
defaultValue,
|
|
438
|
+
onValueChange,
|
|
439
|
+
showTime,
|
|
440
|
+
clearable,
|
|
441
|
+
locale,
|
|
442
|
+
min,
|
|
443
|
+
max,
|
|
444
|
+
disabled,
|
|
445
|
+
readOnly,
|
|
446
|
+
placeholder,
|
|
447
|
+
todayLabel,
|
|
448
|
+
clearLabel,
|
|
449
|
+
saveLabel,
|
|
450
|
+
className,
|
|
451
|
+
rootProps,
|
|
452
|
+
trigger,
|
|
453
|
+
formatValue,
|
|
454
|
+
onSave
|
|
455
|
+
}
|
|
456
|
+
);
|
|
457
|
+
}
|
|
293
458
|
if (showTime) {
|
|
294
459
|
return /* @__PURE__ */ jsx(
|
|
295
460
|
DateTimePickerField,
|
|
@@ -307,8 +472,10 @@ function DatePickerField({
|
|
|
307
472
|
placeholder,
|
|
308
473
|
todayLabel,
|
|
309
474
|
clearLabel,
|
|
475
|
+
saveLabel,
|
|
310
476
|
className,
|
|
311
|
-
rootProps
|
|
477
|
+
rootProps,
|
|
478
|
+
onSave
|
|
312
479
|
}
|
|
313
480
|
);
|
|
314
481
|
}
|
|
@@ -326,6 +493,10 @@ function DatePickerField({
|
|
|
326
493
|
selectionMode: "single",
|
|
327
494
|
outsideDaySelectable: true,
|
|
328
495
|
closeOnSelect: true,
|
|
496
|
+
parse: (input, details) => {
|
|
497
|
+
const parts = parseLocalizedDate(input, details.locale);
|
|
498
|
+
return parts ? new CalendarDate(parts.year, parts.month, parts.day) : void 0;
|
|
499
|
+
},
|
|
329
500
|
className,
|
|
330
501
|
...rootProps,
|
|
331
502
|
children: [
|
|
@@ -344,10 +515,17 @@ function DatePickerField({
|
|
|
344
515
|
] }) : /* @__PURE__ */ jsx(DatePickerTrigger, { className: styles.trigger, children: /* @__PURE__ */ jsx(CalendarIcon, { className: "size-4" }) })
|
|
345
516
|
] }),
|
|
346
517
|
/* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(DatePickerPositioner, { children: /* @__PURE__ */ jsxs(DatePickerContent, { className: styles.content, children: [
|
|
347
|
-
/* @__PURE__ */ jsx(
|
|
348
|
-
/* @__PURE__ */ jsx(
|
|
349
|
-
|
|
350
|
-
|
|
518
|
+
/* @__PURE__ */ jsx(CalendarPanel, {}),
|
|
519
|
+
/* @__PURE__ */ jsx(
|
|
520
|
+
CalendarFooter,
|
|
521
|
+
{
|
|
522
|
+
todayLabel,
|
|
523
|
+
clearLabel,
|
|
524
|
+
saveLabel,
|
|
525
|
+
clearable,
|
|
526
|
+
onSave
|
|
527
|
+
}
|
|
528
|
+
)
|
|
351
529
|
] }) }) })
|
|
352
530
|
]
|
|
353
531
|
}
|
|
@@ -367,14 +545,17 @@ function DateTimePickerField({
|
|
|
367
545
|
placeholder: placeholderProp,
|
|
368
546
|
todayLabel: todayLabelProp,
|
|
369
547
|
clearLabel: clearLabelProp,
|
|
548
|
+
saveLabel: saveLabelProp,
|
|
370
549
|
className,
|
|
371
|
-
rootProps
|
|
550
|
+
rootProps,
|
|
551
|
+
onSave
|
|
372
552
|
}) {
|
|
373
553
|
var _a;
|
|
374
554
|
const intl = useSafeIntl();
|
|
375
555
|
const locale = (_a = localeProp != null ? localeProp : intl.locale) != null ? _a : "en-US";
|
|
376
556
|
const todayLabel = todayLabelProp != null ? todayLabelProp : intl.formatMessage(datePickerMessages.today);
|
|
377
557
|
const clearLabel = clearLabelProp != null ? clearLabelProp : intl.formatMessage(datePickerMessages.clear);
|
|
558
|
+
const saveLabel = saveLabelProp != null ? saveLabelProp : intl.formatMessage(datePickerMessages.save);
|
|
378
559
|
const placeholder = placeholderProp != null ? placeholderProp : intl.formatMessage(datePickerMessages.select_date_and_time);
|
|
379
560
|
const [internalValue, setInternalValue] = useState(() => {
|
|
380
561
|
const initial = valueProp != null ? valueProp : defaultValue;
|
|
@@ -445,6 +626,22 @@ function DateTimePickerField({
|
|
|
445
626
|
view: "day"
|
|
446
627
|
});
|
|
447
628
|
}, [onValueChange]);
|
|
629
|
+
const handleSelectNow = useCallback(() => {
|
|
630
|
+
const now = /* @__PURE__ */ new Date();
|
|
631
|
+
const nowValue = new CalendarDateTime(
|
|
632
|
+
now.getFullYear(),
|
|
633
|
+
now.getMonth() + 1,
|
|
634
|
+
now.getDate(),
|
|
635
|
+
now.getHours(),
|
|
636
|
+
now.getMinutes()
|
|
637
|
+
);
|
|
638
|
+
setInternalValue([nowValue]);
|
|
639
|
+
onValueChange == null ? void 0 : onValueChange({
|
|
640
|
+
value: [nowValue],
|
|
641
|
+
valueAsString: [nowValue.toString()],
|
|
642
|
+
view: "day"
|
|
643
|
+
});
|
|
644
|
+
}, [onValueChange]);
|
|
448
645
|
return /* @__PURE__ */ jsxs(
|
|
449
646
|
DatePickerRoot,
|
|
450
647
|
{
|
|
@@ -458,13 +655,33 @@ function DateTimePickerField({
|
|
|
458
655
|
selectionMode: "single",
|
|
459
656
|
outsideDaySelectable: true,
|
|
460
657
|
closeOnSelect: false,
|
|
658
|
+
parse: (input, details) => {
|
|
659
|
+
const parts = parseLocalizedDate(input, details.locale);
|
|
660
|
+
if (!parts) return void 0;
|
|
661
|
+
const prev = currentValue[0];
|
|
662
|
+
const hour = prev && "hour" in prev ? prev.hour : 0;
|
|
663
|
+
const minute = prev && "minute" in prev ? prev.minute : 0;
|
|
664
|
+
return new CalendarDateTime(
|
|
665
|
+
parts.year,
|
|
666
|
+
parts.month,
|
|
667
|
+
parts.day,
|
|
668
|
+
hour,
|
|
669
|
+
minute
|
|
670
|
+
);
|
|
671
|
+
},
|
|
461
672
|
className,
|
|
462
673
|
...rootProps,
|
|
463
674
|
children: [
|
|
464
675
|
label && /* @__PURE__ */ jsx(DatePickerLabel, { className: styles.label, children: label }),
|
|
465
|
-
/* @__PURE__ */ jsxs(DatePickerControl, { className: "flex items-center
|
|
676
|
+
/* @__PURE__ */ jsxs(DatePickerControl, { className: "flex items-center", children: [
|
|
466
677
|
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 flex items-center", children: [
|
|
467
|
-
/* @__PURE__ */ jsx(
|
|
678
|
+
/* @__PURE__ */ jsx(
|
|
679
|
+
DatePickerInput,
|
|
680
|
+
{
|
|
681
|
+
className: "w-full h-9 rounded-l-md border border-r-0 bg-transparent pl-3 pr-9 text-sm outline-none focus:ring-2 focus:ring-ring",
|
|
682
|
+
placeholder
|
|
683
|
+
}
|
|
684
|
+
),
|
|
468
685
|
/* @__PURE__ */ jsx(DatePickerTrigger, { className: styles.trigger, children: /* @__PURE__ */ jsx(CalendarIcon, { className: "size-4" }) })
|
|
469
686
|
] }),
|
|
470
687
|
/* @__PURE__ */ jsx(
|
|
@@ -475,23 +692,215 @@ function DateTimePickerField({
|
|
|
475
692
|
onChange: handleTimeChange,
|
|
476
693
|
disabled,
|
|
477
694
|
readOnly,
|
|
478
|
-
className:
|
|
695
|
+
className: `h-9 border bg-transparent px-3 text-sm outline-none focus:ring-2 focus:ring-ring ${clearable && !disabled && !readOnly ? "border-r-0" : "rounded-r-md"}`
|
|
479
696
|
}
|
|
480
697
|
),
|
|
481
698
|
clearable && !disabled && !readOnly && /* @__PURE__ */ jsx(
|
|
482
|
-
|
|
699
|
+
"button",
|
|
483
700
|
{
|
|
484
|
-
|
|
701
|
+
type: "button",
|
|
702
|
+
className: "inline-flex items-center justify-center size-9 rounded-r-md border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
|
|
485
703
|
onClick: handleClear,
|
|
486
704
|
children: /* @__PURE__ */ jsx(XIcon, { className: "size-4" })
|
|
487
705
|
}
|
|
488
706
|
)
|
|
489
707
|
] }),
|
|
490
708
|
/* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(DatePickerPositioner, { children: /* @__PURE__ */ jsxs(DatePickerContent, { className: styles.content, children: [
|
|
491
|
-
/* @__PURE__ */ jsx(
|
|
492
|
-
/* @__PURE__ */ jsx(
|
|
493
|
-
|
|
494
|
-
|
|
709
|
+
/* @__PURE__ */ jsx(CalendarPanel, {}),
|
|
710
|
+
/* @__PURE__ */ jsx(
|
|
711
|
+
DateTimeFooter,
|
|
712
|
+
{
|
|
713
|
+
todayLabel,
|
|
714
|
+
clearLabel,
|
|
715
|
+
saveLabel,
|
|
716
|
+
clearable,
|
|
717
|
+
onSelectNow: handleSelectNow,
|
|
718
|
+
onClear: handleClear,
|
|
719
|
+
onSave: onSave ? () => onSave({
|
|
720
|
+
value: currentValue,
|
|
721
|
+
valueAsString: currentValue.map((v) => v.toString()),
|
|
722
|
+
view: "day"
|
|
723
|
+
}) : void 0
|
|
724
|
+
}
|
|
725
|
+
)
|
|
726
|
+
] }) }) })
|
|
727
|
+
]
|
|
728
|
+
}
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
function DateTriggerPickerField({
|
|
732
|
+
label,
|
|
733
|
+
value: valueProp,
|
|
734
|
+
defaultValue,
|
|
735
|
+
onValueChange,
|
|
736
|
+
showTime = false,
|
|
737
|
+
clearable = true,
|
|
738
|
+
locale: localeProp,
|
|
739
|
+
min,
|
|
740
|
+
max,
|
|
741
|
+
disabled,
|
|
742
|
+
readOnly,
|
|
743
|
+
placeholder: placeholderProp,
|
|
744
|
+
todayLabel: todayLabelProp,
|
|
745
|
+
clearLabel: clearLabelProp,
|
|
746
|
+
saveLabel: saveLabelProp,
|
|
747
|
+
className,
|
|
748
|
+
rootProps,
|
|
749
|
+
trigger,
|
|
750
|
+
formatValue,
|
|
751
|
+
onSave
|
|
752
|
+
}) {
|
|
753
|
+
var _a;
|
|
754
|
+
const intl = useSafeIntl();
|
|
755
|
+
const locale = (_a = localeProp != null ? localeProp : intl.locale) != null ? _a : "en-US";
|
|
756
|
+
const todayLabel = todayLabelProp != null ? todayLabelProp : intl.formatMessage(datePickerMessages.today);
|
|
757
|
+
const clearLabel = clearLabelProp != null ? clearLabelProp : intl.formatMessage(datePickerMessages.clear);
|
|
758
|
+
const saveLabel = saveLabelProp != null ? saveLabelProp : intl.formatMessage(datePickerMessages.save);
|
|
759
|
+
const placeholder = placeholderProp != null ? placeholderProp : intl.formatMessage(
|
|
760
|
+
showTime ? datePickerMessages.select_date_and_time : datePickerMessages.select_date
|
|
761
|
+
);
|
|
762
|
+
const [draft, setDraft] = useState(
|
|
763
|
+
() => {
|
|
764
|
+
var _a2;
|
|
765
|
+
return (_a2 = valueProp != null ? valueProp : defaultValue) != null ? _a2 : [];
|
|
766
|
+
}
|
|
767
|
+
);
|
|
768
|
+
const [committed, setCommitted] = useState(
|
|
769
|
+
() => {
|
|
770
|
+
var _a2;
|
|
771
|
+
return (_a2 = valueProp != null ? valueProp : defaultValue) != null ? _a2 : [];
|
|
772
|
+
}
|
|
773
|
+
);
|
|
774
|
+
useEffect(() => {
|
|
775
|
+
if (valueProp !== void 0) {
|
|
776
|
+
setCommitted(valueProp);
|
|
777
|
+
if (!onSave) setDraft(valueProp);
|
|
778
|
+
}
|
|
779
|
+
}, [valueProp, onSave]);
|
|
780
|
+
const currentValue = onSave ? draft : valueProp != null ? valueProp : draft;
|
|
781
|
+
const handleDateChange = useCallback(
|
|
782
|
+
(details) => {
|
|
783
|
+
const next = details.value[0];
|
|
784
|
+
if (!showTime || !next) {
|
|
785
|
+
setDraft(details.value);
|
|
786
|
+
onValueChange == null ? void 0 : onValueChange(details);
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const prev = currentValue[0];
|
|
790
|
+
const prevHour = prev && "hour" in prev ? prev.hour : 0;
|
|
791
|
+
const prevMinute = prev && "minute" in prev ? prev.minute : 0;
|
|
792
|
+
const merged = new CalendarDateTime(
|
|
793
|
+
next.year,
|
|
794
|
+
next.month,
|
|
795
|
+
next.day,
|
|
796
|
+
prevHour,
|
|
797
|
+
prevMinute
|
|
798
|
+
);
|
|
799
|
+
setDraft([merged]);
|
|
800
|
+
onValueChange == null ? void 0 : onValueChange({ ...details, value: [merged] });
|
|
801
|
+
},
|
|
802
|
+
[currentValue, onValueChange, showTime]
|
|
803
|
+
);
|
|
804
|
+
const handleTimeChange = useCallback(
|
|
805
|
+
(e) => {
|
|
806
|
+
const [hours, minutes] = e.currentTarget.value.split(":").map(Number);
|
|
807
|
+
const prev = currentValue[0];
|
|
808
|
+
const base = prev && "hour" in prev ? prev : prev ? new CalendarDateTime(prev.year, prev.month, prev.day, 0, 0) : (() => {
|
|
809
|
+
const now = /* @__PURE__ */ new Date();
|
|
810
|
+
return new CalendarDateTime(
|
|
811
|
+
now.getFullYear(),
|
|
812
|
+
now.getMonth() + 1,
|
|
813
|
+
now.getDate(),
|
|
814
|
+
0,
|
|
815
|
+
0
|
|
816
|
+
);
|
|
817
|
+
})();
|
|
818
|
+
const updated = base.set({ hour: hours, minute: minutes });
|
|
819
|
+
setDraft([updated]);
|
|
820
|
+
onValueChange == null ? void 0 : onValueChange({
|
|
821
|
+
value: [updated],
|
|
822
|
+
valueAsString: [updated.toString()],
|
|
823
|
+
view: "day"
|
|
824
|
+
});
|
|
825
|
+
},
|
|
826
|
+
[currentValue, onValueChange]
|
|
827
|
+
);
|
|
828
|
+
const userOnOpenChange = rootProps == null ? void 0 : rootProps.onOpenChange;
|
|
829
|
+
const handleOpenChange = useCallback(
|
|
830
|
+
(details) => {
|
|
831
|
+
if (onSave && details.open) {
|
|
832
|
+
setDraft(committed);
|
|
833
|
+
}
|
|
834
|
+
userOnOpenChange == null ? void 0 : userOnOpenChange(details);
|
|
835
|
+
},
|
|
836
|
+
[committed, onSave, userOnOpenChange]
|
|
837
|
+
);
|
|
838
|
+
const handleSaveCommit = useCallback(
|
|
839
|
+
(details) => {
|
|
840
|
+
setCommitted(details.value);
|
|
841
|
+
onSave == null ? void 0 : onSave(details);
|
|
842
|
+
},
|
|
843
|
+
[onSave]
|
|
844
|
+
);
|
|
845
|
+
const formatter = useMemo(() => {
|
|
846
|
+
if (formatValue) return formatValue;
|
|
847
|
+
const fmt = new Intl.DateTimeFormat(
|
|
848
|
+
locale,
|
|
849
|
+
showTime ? { dateStyle: "medium", timeStyle: "short" } : { dateStyle: "medium" }
|
|
850
|
+
);
|
|
851
|
+
return (v) => fmt.format(v.toDate(getLocalTimeZone()));
|
|
852
|
+
}, [formatValue, locale, showTime]);
|
|
853
|
+
const timeValue = currentValue[0] && "hour" in currentValue[0] ? `${String(currentValue[0].hour).padStart(2, "0")}:${String(currentValue[0].minute).padStart(2, "0")}` : "";
|
|
854
|
+
const triggerElement = trigger != null ? trigger : onSave ? /* @__PURE__ */ jsxs("button", { type: "button", className: styles.defaultGhostTrigger, children: [
|
|
855
|
+
/* @__PURE__ */ jsx(CalendarIcon, { className: "size-4 shrink-0 opacity-70" }),
|
|
856
|
+
/* @__PURE__ */ jsx("span", { children: committed[0] ? formatter(committed[0]) : placeholder })
|
|
857
|
+
] }) : /* @__PURE__ */ jsxs("button", { type: "button", className: styles.defaultGhostTrigger, children: [
|
|
858
|
+
/* @__PURE__ */ jsx(CalendarIcon, { className: "size-4 shrink-0 opacity-70" }),
|
|
859
|
+
/* @__PURE__ */ jsx(DatePickerValueText, { placeholder, children: ({ value }) => formatter(value) })
|
|
860
|
+
] });
|
|
861
|
+
return /* @__PURE__ */ jsxs(
|
|
862
|
+
DatePickerRoot,
|
|
863
|
+
{
|
|
864
|
+
value: currentValue,
|
|
865
|
+
defaultValue,
|
|
866
|
+
onValueChange: handleDateChange,
|
|
867
|
+
locale,
|
|
868
|
+
min,
|
|
869
|
+
max,
|
|
870
|
+
disabled,
|
|
871
|
+
readOnly,
|
|
872
|
+
selectionMode: "single",
|
|
873
|
+
outsideDaySelectable: true,
|
|
874
|
+
closeOnSelect: !showTime && !onSave,
|
|
875
|
+
className,
|
|
876
|
+
...rootProps,
|
|
877
|
+
onOpenChange: handleOpenChange,
|
|
878
|
+
children: [
|
|
879
|
+
label && /* @__PURE__ */ jsx(DatePickerLabel, { className: styles.label, children: label }),
|
|
880
|
+
/* @__PURE__ */ jsx(DatePickerControl, { children: /* @__PURE__ */ jsx(DatePickerTrigger, { asChild: true, children: triggerElement }) }),
|
|
881
|
+
/* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(DatePickerPositioner, { children: /* @__PURE__ */ jsxs(DatePickerContent, { className: styles.content, children: [
|
|
882
|
+
/* @__PURE__ */ jsx(CalendarPanel, {}),
|
|
883
|
+
showTime && /* @__PURE__ */ jsx("div", { className: styles.timeRow, children: /* @__PURE__ */ jsx(
|
|
884
|
+
"input",
|
|
885
|
+
{
|
|
886
|
+
type: "time",
|
|
887
|
+
value: timeValue,
|
|
888
|
+
onChange: handleTimeChange,
|
|
889
|
+
disabled,
|
|
890
|
+
readOnly,
|
|
891
|
+
className: styles.timeInput
|
|
892
|
+
}
|
|
893
|
+
) }),
|
|
894
|
+
/* @__PURE__ */ jsx(
|
|
895
|
+
CalendarFooter,
|
|
896
|
+
{
|
|
897
|
+
todayLabel,
|
|
898
|
+
clearLabel,
|
|
899
|
+
saveLabel,
|
|
900
|
+
clearable,
|
|
901
|
+
onSave: onSave ? handleSaveCommit : void 0
|
|
902
|
+
}
|
|
903
|
+
)
|
|
495
904
|
] }) }) })
|
|
496
905
|
]
|
|
497
906
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { DatePickerValueChangeDetails, DatePickerRootProps } from '@ark-ui/react/date-picker';
|
|
3
3
|
import { DateValue } from '@internationalized/date';
|
|
4
|
+
import { ReactElement } from 'react';
|
|
4
5
|
|
|
5
6
|
type DatePickerFieldProps = {
|
|
6
7
|
/** Label text */
|
|
@@ -35,7 +36,43 @@ type DatePickerFieldProps = {
|
|
|
35
36
|
className?: string;
|
|
36
37
|
/** Additional Ark UI Root props */
|
|
37
38
|
rootProps?: Partial<DatePickerRootProps>;
|
|
39
|
+
/**
|
|
40
|
+
* Visual variant.
|
|
41
|
+
* - `"input"` (default): bordered input + calendar button + optional inline time/clear
|
|
42
|
+
* - `"trigger"`: a single ghost-style button that opens the popover
|
|
43
|
+
* with the calendar (and time picker, if `showTime`). Use `trigger`
|
|
44
|
+
* to provide a custom trigger element.
|
|
45
|
+
*/
|
|
46
|
+
variant?: "input" | "trigger";
|
|
47
|
+
/**
|
|
48
|
+
* Custom trigger element rendered in `variant="trigger"` mode. Wrapped
|
|
49
|
+
* with `DatePickerTrigger asChild`, so any clickable element works
|
|
50
|
+
* (sight Button, Chip, etc.). The element should display the value —
|
|
51
|
+
* pass `<DatePickerValueText placeholder={…} />` as its children, or
|
|
52
|
+
* use the `formatValue` prop for default formatting.
|
|
53
|
+
*/
|
|
54
|
+
trigger?: ReactElement;
|
|
55
|
+
/**
|
|
56
|
+
* Custom formatter for the trigger label (only used by the default
|
|
57
|
+
* `variant="trigger"` button). Receives the selected `DateValue` and
|
|
58
|
+
* returns a display string. Defaults to `Intl.DateTimeFormat` with the
|
|
59
|
+
* picker's locale, including time when `showTime` is true.
|
|
60
|
+
*/
|
|
61
|
+
formatValue?: (value: DateValue) => string;
|
|
62
|
+
/**
|
|
63
|
+
* When provided, a "Save" button is rendered in the popover footer.
|
|
64
|
+
* `onValueChange` still fires per interaction so the picker stays
|
|
65
|
+
* controllable, but `onSave` is the explicit commit signal — callers
|
|
66
|
+
* that need draft-then-commit semantics (e.g. avoiding a save on every
|
|
67
|
+
* minute increment of the time picker) should listen here instead of
|
|
68
|
+
* `onValueChange`. Clicking Save also closes the popover.
|
|
69
|
+
*/
|
|
70
|
+
onSave?: (details: DatePickerValueChangeDetails) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Override the Save button label. Defaults to the i18n message.
|
|
73
|
+
*/
|
|
74
|
+
saveLabel?: string;
|
|
38
75
|
};
|
|
39
|
-
declare function DatePickerField({ label, value, defaultValue, onValueChange, showTime, clearable, locale: localeProp, min, max, disabled, readOnly, placeholder: placeholderProp, todayLabel: todayLabelProp, clearLabel: clearLabelProp, className, rootProps, }: DatePickerFieldProps): react_jsx_runtime.JSX.Element;
|
|
76
|
+
declare function DatePickerField({ label, value, defaultValue, onValueChange, showTime, clearable, locale: localeProp, min, max, disabled, readOnly, placeholder: placeholderProp, todayLabel: todayLabelProp, clearLabel: clearLabelProp, className, rootProps, variant, trigger, formatValue, onSave, saveLabel: saveLabelProp, }: DatePickerFieldProps): react_jsx_runtime.JSX.Element;
|
|
40
77
|
|
|
41
78
|
export { DatePickerField, type DatePickerFieldProps };
|