@bigbinary/neeto-atoms 1.1.2 → 1.1.3
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/{DatePicker-BiUWzq-V.js → DatePicker-CMlA-hNW.js} +475 -272
- package/dist/DatePicker-CMlA-hNW.js.map +1 -0
- package/dist/{TranslationProvider-BJjfFEgX.js → TranslationProvider-DKdbPweu.js} +9 -2
- package/dist/{TranslationProvider-BJjfFEgX.js.map → TranslationProvider-DKdbPweu.js.map} +1 -1
- package/dist/cjs/{DatePicker-C_nezxpH.js → DatePicker-CBxWLALJ.js} +474 -271
- package/dist/cjs/DatePicker-CBxWLALJ.js.map +1 -0
- package/dist/cjs/{TranslationProvider-C1JDwKEN.js → TranslationProvider-Cao2ugzJ.js} +9 -2
- package/dist/cjs/{TranslationProvider-C1JDwKEN.js.map → TranslationProvider-Cao2ugzJ.js.map} +1 -1
- package/dist/cjs/components/DatePicker.js +1 -1
- package/dist/cjs/components/TranslationProvider.js +1 -1
- package/dist/cjs/components/index.js +2 -2
- package/dist/cjs/formik/Form.js +1 -0
- package/dist/cjs/formik/Form.js.map +1 -1
- package/dist/cjs/index.js +5 -5
- package/dist/components/DatePicker/DatePickerFooter.d.ts +1 -1
- package/dist/components/DatePicker/RangeCalendar.d.ts +2 -1
- package/dist/components/DatePicker/RangeTimeSection.d.ts +37 -0
- package/dist/components/DatePicker/SegmentedTimeInput.d.ts +7 -1
- package/dist/components/DatePicker/TimeSection.d.ts +3 -0
- package/dist/components/DatePicker/types.d.ts +5 -2
- package/dist/components/DatePicker/useRangePicker.d.ts +4 -2
- package/dist/components/DatePicker/utils.d.ts +1 -0
- package/dist/components/DatePicker.js +1 -1
- package/dist/components/TranslationProvider.js +1 -1
- package/dist/components/index.js +2 -2
- package/dist/formik/Form.js +1 -0
- package/dist/formik/Form.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/translations/index.d.ts +7 -0
- package/package.json +1 -1
- package/dist/DatePicker-BiUWzq-V.js.map +0 -1
- package/dist/cjs/DatePicker-C_nezxpH.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import React__default, { forwardRef, useRef, useState, useEffect, useId, useCallback, useMemo } from 'react';
|
|
2
|
+
import React__default, { forwardRef, useRef, useState, useEffect, useImperativeHandle, useId, useCallback, useMemo } from 'react';
|
|
3
3
|
import { Calendar as Calendar$1 } from './primitives/Calendar.js';
|
|
4
4
|
import { PopoverAnchor, Popover, PopoverTrigger, PopoverContent } from './primitives/Popover.js';
|
|
5
5
|
import { c as cn } from './utils-BJnb9o5c.js';
|
|
@@ -200,6 +200,7 @@ const parseRangeText = (text, displayFormat, maskEnabled, singleDateLen) => {
|
|
|
200
200
|
const to = parseDate(parts[1], displayFormat);
|
|
201
201
|
return from && to ? [from, to] : null;
|
|
202
202
|
};
|
|
203
|
+
const startOfDay = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
203
204
|
const startOfWeek = (date, weekStartsOn = 0) => {
|
|
204
205
|
const d = new Date(date);
|
|
205
206
|
const diff = (d.getDay() - weekStartsOn + 7) % 7;
|
|
@@ -260,10 +261,12 @@ const computeRangePreview = ({
|
|
|
260
261
|
let from = pendingRange ? pendingRange[0] : committed?.[0] ?? null;
|
|
261
262
|
let to = pendingRange ? pendingRange[1] : committed?.[1] ?? null;
|
|
262
263
|
if (hoveredDate) {
|
|
263
|
-
if (rangeStep === "from"
|
|
264
|
-
from
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
if (rangeStep === "from") {
|
|
265
|
+
if (!(from && to)) {
|
|
266
|
+
from = hoveredDate;
|
|
267
|
+
if (to && hoveredDate.getTime() > to.getTime()) to = null;
|
|
268
|
+
}
|
|
269
|
+
} else if (!isSameDay(from, hoveredDate)) {
|
|
267
270
|
to = hoveredDate;
|
|
268
271
|
if (from && hoveredDate.getTime() < from.getTime()) from = null;
|
|
269
272
|
}
|
|
@@ -309,7 +312,7 @@ const DatePickerFooter = ({
|
|
|
309
312
|
showNow = true,
|
|
310
313
|
onNow,
|
|
311
314
|
onOk,
|
|
312
|
-
|
|
315
|
+
okDisabled = false,
|
|
313
316
|
className
|
|
314
317
|
}) => {
|
|
315
318
|
const showOkButton = showTime || needConfirm;
|
|
@@ -341,7 +344,16 @@ const DatePickerFooter = ({
|
|
|
341
344
|
className: "me-2"
|
|
342
345
|
}
|
|
343
346
|
),
|
|
344
|
-
showOkButton && /* @__PURE__ */ jsx(
|
|
347
|
+
showOkButton && /* @__PURE__ */ jsx(
|
|
348
|
+
Button,
|
|
349
|
+
{
|
|
350
|
+
size: "sm",
|
|
351
|
+
disabled: okDisabled,
|
|
352
|
+
onClick: onOk,
|
|
353
|
+
className: "text-xs",
|
|
354
|
+
children: "OK"
|
|
355
|
+
}
|
|
356
|
+
)
|
|
345
357
|
]
|
|
346
358
|
}
|
|
347
359
|
);
|
|
@@ -646,149 +658,160 @@ const parsePastedTime = (text, step = 1) => {
|
|
|
646
658
|
};
|
|
647
659
|
|
|
648
660
|
const PLACEHOLDERS = ["hh", "mm", "--"];
|
|
649
|
-
const SegmentedTimeInput = (
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
if (timeValueEquals(value, lastEmittedRef.current)) return;
|
|
668
|
-
lastEmittedRef.current = value;
|
|
669
|
-
setTime(segmentedTimeFromValue(value, step));
|
|
670
|
-
}, [value]);
|
|
671
|
-
const error = getSegmentedTimeError(time);
|
|
672
|
-
useEffect(() => {
|
|
673
|
-
onErrorChange(error);
|
|
674
|
-
}, [error, onErrorChange]);
|
|
675
|
-
useEffect(() => {
|
|
676
|
-
const snapped = segmentedTimeToValue(time);
|
|
677
|
-
if (snapped && !timeValueEquals(snapped, value)) {
|
|
678
|
-
lastEmittedRef.current = snapped;
|
|
679
|
-
onChange(snapped);
|
|
680
|
-
}
|
|
681
|
-
}, []);
|
|
682
|
-
useEffect(() => {
|
|
683
|
-
if (autoFocus) fieldRef.current?.focus();
|
|
684
|
-
}, [autoFocus]);
|
|
685
|
-
const update = (next) => {
|
|
686
|
-
setTime(next);
|
|
687
|
-
const nextValue = segmentedTimeToValue(next);
|
|
688
|
-
if (!nextValue || timeValueEquals(nextValue, lastEmittedRef.current)) {
|
|
689
|
-
return;
|
|
690
|
-
}
|
|
691
|
-
lastEmittedRef.current = nextValue;
|
|
692
|
-
onChange(nextValue);
|
|
693
|
-
};
|
|
694
|
-
const consume = (event) => {
|
|
695
|
-
event.preventDefault();
|
|
696
|
-
event.stopPropagation();
|
|
697
|
-
};
|
|
698
|
-
const handleKeyDown = (event) => {
|
|
699
|
-
const { key } = event;
|
|
700
|
-
if (key === "Tab") {
|
|
701
|
-
if (!event.shiftKey || time.active !== 2) return;
|
|
702
|
-
consume(event);
|
|
703
|
-
update(togglePeriod(time));
|
|
704
|
-
return;
|
|
705
|
-
}
|
|
706
|
-
if ((event.metaKey || event.ctrlKey) && key === "Backspace") {
|
|
707
|
-
consume(event);
|
|
708
|
-
update(emptySegmentedTime());
|
|
709
|
-
return;
|
|
710
|
-
}
|
|
711
|
-
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
712
|
-
let next = null;
|
|
713
|
-
if (/^[0-9]$/.test(key)) next = typeDigit(time, key, step);
|
|
714
|
-
else if (/^[ap]$/i.test(key)) {
|
|
715
|
-
next = typePeriod(time, key.toLowerCase(), step);
|
|
716
|
-
} else if (/^m$/i.test(key))
|
|
717
|
-
next = time;
|
|
718
|
-
else if (key === ":" || key === " " || key === "ArrowRight") {
|
|
719
|
-
next = nextSegment(time, step);
|
|
720
|
-
} else if (key === "ArrowLeft") next = previousSegment(time);
|
|
721
|
-
else if (key === "ArrowUp") next = stepSegment(time, 1, step);
|
|
722
|
-
else if (key === "ArrowDown") next = stepSegment(time, -1, step);
|
|
723
|
-
else if (key === "Backspace" || key === "Delete") next = backspace(time);
|
|
724
|
-
if (!next) return;
|
|
725
|
-
consume(event);
|
|
726
|
-
update(next);
|
|
727
|
-
};
|
|
728
|
-
const handlePaste = (event) => {
|
|
729
|
-
event.preventDefault();
|
|
730
|
-
const pasted = parsePastedTime(event.clipboardData.getData("text"), step);
|
|
731
|
-
if (pasted) update({ ...segmentedTimeFromValue(pasted, step), active: 2 });
|
|
732
|
-
};
|
|
733
|
-
const handleMouseDown = (event) => {
|
|
734
|
-
if (disabled) return;
|
|
735
|
-
const segmentEl = event.target.closest(
|
|
736
|
-
"[data-segment]"
|
|
661
|
+
const SegmentedTimeInput = forwardRef(
|
|
662
|
+
({
|
|
663
|
+
value,
|
|
664
|
+
minuteStep,
|
|
665
|
+
onChange,
|
|
666
|
+
onErrorChange,
|
|
667
|
+
invalid = false,
|
|
668
|
+
disabled = false,
|
|
669
|
+
autoFocus = false,
|
|
670
|
+
"aria-label": ariaLabel,
|
|
671
|
+
"aria-describedby": ariaDescribedBy,
|
|
672
|
+
"data-testid": dataTestId = "datepicker-time-input"
|
|
673
|
+
}, ref) => {
|
|
674
|
+
const { t } = useTranslation();
|
|
675
|
+
const fieldRef = useRef(null);
|
|
676
|
+
const step = minuteStep ?? 1;
|
|
677
|
+
const [time, setTime] = useState(
|
|
678
|
+
() => segmentedTimeFromValue(value, step)
|
|
737
679
|
);
|
|
738
|
-
|
|
680
|
+
const lastEmittedRef = useRef(value);
|
|
681
|
+
useEffect(() => {
|
|
682
|
+
if (timeValueEquals(value, lastEmittedRef.current)) return;
|
|
683
|
+
lastEmittedRef.current = value;
|
|
684
|
+
setTime(segmentedTimeFromValue(value, step));
|
|
685
|
+
}, [value]);
|
|
686
|
+
const error = getSegmentedTimeError(time);
|
|
687
|
+
useEffect(() => {
|
|
688
|
+
onErrorChange(error);
|
|
689
|
+
}, [error, onErrorChange]);
|
|
690
|
+
useEffect(() => {
|
|
691
|
+
const snapped = segmentedTimeToValue(time);
|
|
692
|
+
if (snapped && !timeValueEquals(snapped, value)) {
|
|
693
|
+
lastEmittedRef.current = snapped;
|
|
694
|
+
onChange(snapped);
|
|
695
|
+
}
|
|
696
|
+
}, []);
|
|
697
|
+
useEffect(() => {
|
|
698
|
+
if (autoFocus) fieldRef.current?.focus();
|
|
699
|
+
}, [autoFocus]);
|
|
700
|
+
useImperativeHandle(ref, () => ({
|
|
701
|
+
focusHour: () => {
|
|
702
|
+
fieldRef.current?.focus();
|
|
703
|
+
setTime((current) => ({ ...current, active: 0 }));
|
|
704
|
+
}
|
|
705
|
+
}));
|
|
706
|
+
const update = (next) => {
|
|
707
|
+
setTime(next);
|
|
708
|
+
const nextValue = segmentedTimeToValue(next);
|
|
709
|
+
if (!nextValue || timeValueEquals(nextValue, lastEmittedRef.current)) {
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
lastEmittedRef.current = nextValue;
|
|
713
|
+
onChange(nextValue);
|
|
714
|
+
};
|
|
715
|
+
const consume = (event) => {
|
|
739
716
|
event.preventDefault();
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
)
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
717
|
+
event.stopPropagation();
|
|
718
|
+
};
|
|
719
|
+
const handleKeyDown = (event) => {
|
|
720
|
+
const { key } = event;
|
|
721
|
+
if (key === "Tab") {
|
|
722
|
+
if (!event.shiftKey || time.active !== 2) return;
|
|
723
|
+
consume(event);
|
|
724
|
+
update(togglePeriod(time));
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if ((event.metaKey || event.ctrlKey) && key === "Backspace") {
|
|
728
|
+
consume(event);
|
|
729
|
+
update(emptySegmentedTime());
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
733
|
+
let next = null;
|
|
734
|
+
if (/^[0-9]$/.test(key)) next = typeDigit(time, key, step);
|
|
735
|
+
else if (/^[ap]$/i.test(key)) {
|
|
736
|
+
next = typePeriod(time, key.toLowerCase(), step);
|
|
737
|
+
} else if (/^m$/i.test(key))
|
|
738
|
+
next = time;
|
|
739
|
+
else if (key === ":" || key === " " || key === "ArrowRight") {
|
|
740
|
+
next = nextSegment(time, step);
|
|
741
|
+
} else if (key === "ArrowLeft") next = previousSegment(time);
|
|
742
|
+
else if (key === "ArrowUp") next = stepSegment(time, 1, step);
|
|
743
|
+
else if (key === "ArrowDown") next = stepSegment(time, -1, step);
|
|
744
|
+
else if (key === "Backspace" || key === "Delete") next = backspace(time);
|
|
745
|
+
if (!next) return;
|
|
746
|
+
consume(event);
|
|
747
|
+
update(next);
|
|
748
|
+
};
|
|
749
|
+
const handlePaste = (event) => {
|
|
750
|
+
event.preventDefault();
|
|
751
|
+
const pasted = parsePastedTime(event.clipboardData.getData("text"), step);
|
|
752
|
+
if (pasted)
|
|
753
|
+
update({ ...segmentedTimeFromValue(pasted, step), active: 2 });
|
|
754
|
+
};
|
|
755
|
+
const handleMouseDown = (event) => {
|
|
756
|
+
if (disabled) return;
|
|
757
|
+
const segmentEl = event.target.closest(
|
|
758
|
+
"[data-segment]"
|
|
759
|
+
);
|
|
760
|
+
if (segmentEl) {
|
|
761
|
+
event.preventDefault();
|
|
762
|
+
fieldRef.current?.focus();
|
|
763
|
+
update(focusSegment(time, Number(segmentEl.dataset.segment), step));
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
update(focusFirstEmptySegment(time));
|
|
767
|
+
};
|
|
768
|
+
const segmentText = (index) => {
|
|
769
|
+
const { text, done } = time[SEGMENT_KEYS[index]];
|
|
770
|
+
if (!text) return PLACEHOLDERS[index];
|
|
771
|
+
return index < 2 && !done ? `${text}_` : text;
|
|
772
|
+
};
|
|
773
|
+
return /* @__PURE__ */ jsx(
|
|
774
|
+
"div",
|
|
775
|
+
{
|
|
776
|
+
ref: fieldRef,
|
|
777
|
+
role: "group",
|
|
778
|
+
tabIndex: disabled ? -1 : 0,
|
|
779
|
+
"aria-label": ariaLabel ?? t("neetoatoms.datePicker.timeField", "Time"),
|
|
780
|
+
"aria-describedby": ariaDescribedBy,
|
|
781
|
+
"aria-invalid": invalid || void 0,
|
|
782
|
+
"aria-disabled": disabled || void 0,
|
|
783
|
+
"data-testid": dataTestId,
|
|
784
|
+
className: cn(
|
|
785
|
+
"group/time flex h-9 w-full cursor-text items-center rounded-md border border-input bg-transparent px-3 text-sm tabular-nums outline-none select-none",
|
|
786
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
787
|
+
invalid && "border-destructive",
|
|
788
|
+
disabled && "pointer-events-none cursor-not-allowed opacity-50"
|
|
789
|
+
),
|
|
790
|
+
onBlur: () => update(finishActiveSegment(time, step)),
|
|
791
|
+
onKeyDown: handleKeyDown,
|
|
792
|
+
onMouseDown: handleMouseDown,
|
|
793
|
+
onPaste: handlePaste,
|
|
794
|
+
children: SEGMENT_KEYS.map((key, index) => /* @__PURE__ */ jsxs(React__default.Fragment, { children: [
|
|
795
|
+
index === 1 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "px-0.5 text-muted-foreground", children: ":" }),
|
|
796
|
+
index === 2 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "w-1" }),
|
|
797
|
+
/* @__PURE__ */ jsx(
|
|
798
|
+
"span",
|
|
799
|
+
{
|
|
800
|
+
"data-segment": index,
|
|
801
|
+
"data-testid": `datepicker-time-${key}`,
|
|
802
|
+
className: cn(
|
|
803
|
+
"min-w-[2ch] px-0.5 text-center whitespace-pre",
|
|
804
|
+
!time[key].text && "text-muted-foreground",
|
|
805
|
+
index === time.active && "group-focus/time:shadow-[inset_0_-1.5px_0_var(--color-muted-foreground)]"
|
|
806
|
+
),
|
|
807
|
+
children: segmentText(index)
|
|
808
|
+
}
|
|
809
|
+
)
|
|
810
|
+
] }, key))
|
|
811
|
+
}
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
);
|
|
792
815
|
SegmentedTimeInput.displayName = "SegmentedTimeInput";
|
|
793
816
|
|
|
794
817
|
const ERROR_DEFAULTS = {
|
|
@@ -990,9 +1013,10 @@ const RangeCalendar = ({
|
|
|
990
1013
|
endMonth,
|
|
991
1014
|
onHoverIn,
|
|
992
1015
|
onHoverOut,
|
|
1016
|
+
onKeyDown,
|
|
993
1017
|
numberOfMonths = 2,
|
|
994
1018
|
className
|
|
995
|
-
}) => /* @__PURE__ */ jsx("div", {
|
|
1019
|
+
}) => /* @__PURE__ */ jsx("div", { onKeyDown, onMouseLeave: onHoverOut, onMouseOver: onHoverIn, children: /* @__PURE__ */ jsx(
|
|
996
1020
|
Calendar$1,
|
|
997
1021
|
{
|
|
998
1022
|
mode: "range",
|
|
@@ -1014,6 +1038,180 @@ const RangeCalendar = ({
|
|
|
1014
1038
|
}
|
|
1015
1039
|
) });
|
|
1016
1040
|
|
|
1041
|
+
const ENDPOINT_LABELS = {
|
|
1042
|
+
from: "Start",
|
|
1043
|
+
to: "End"
|
|
1044
|
+
};
|
|
1045
|
+
const RangeTimeSection = ({
|
|
1046
|
+
fromDateLabel,
|
|
1047
|
+
toDateLabel,
|
|
1048
|
+
isEndOnStartDay,
|
|
1049
|
+
fromValue,
|
|
1050
|
+
toValue,
|
|
1051
|
+
onFromChange,
|
|
1052
|
+
onToChange,
|
|
1053
|
+
activeEndpoint,
|
|
1054
|
+
onEndpointSelect,
|
|
1055
|
+
minuteStep,
|
|
1056
|
+
onErrorChange,
|
|
1057
|
+
showError,
|
|
1058
|
+
isOrderInvalid,
|
|
1059
|
+
timezoneLabel,
|
|
1060
|
+
fromTimeRef,
|
|
1061
|
+
disabled = false,
|
|
1062
|
+
className
|
|
1063
|
+
}) => {
|
|
1064
|
+
const { t } = useTranslation();
|
|
1065
|
+
const id = useId();
|
|
1066
|
+
const hintId = `datepicker-time-hint-${id}`;
|
|
1067
|
+
const orderErrorId = `datepicker-time-order-error-${id}`;
|
|
1068
|
+
const [errors, setErrors] = useState({ from: null, to: null });
|
|
1069
|
+
const hasError = !!(errors.from || errors.to);
|
|
1070
|
+
useEffect(() => {
|
|
1071
|
+
onErrorChange(hasError);
|
|
1072
|
+
}, [hasError, onErrorChange]);
|
|
1073
|
+
const handleErrorChange = useCallback(
|
|
1074
|
+
(endpoint, error) => setErrors((previous) => ({ ...previous, [endpoint]: error })),
|
|
1075
|
+
[]
|
|
1076
|
+
);
|
|
1077
|
+
const handleFromErrorChange = useCallback(
|
|
1078
|
+
(error) => handleErrorChange("from", error),
|
|
1079
|
+
[handleErrorChange]
|
|
1080
|
+
);
|
|
1081
|
+
const handleToErrorChange = useCallback(
|
|
1082
|
+
(error) => handleErrorChange("to", error),
|
|
1083
|
+
[handleErrorChange]
|
|
1084
|
+
);
|
|
1085
|
+
const showHint = (minuteStep ?? 1) > 1;
|
|
1086
|
+
const endpoints = [
|
|
1087
|
+
{
|
|
1088
|
+
endpoint: "from",
|
|
1089
|
+
dateLabel: fromDateLabel,
|
|
1090
|
+
value: fromValue,
|
|
1091
|
+
onChange: onFromChange,
|
|
1092
|
+
onFieldErrorChange: handleFromErrorChange
|
|
1093
|
+
},
|
|
1094
|
+
{
|
|
1095
|
+
endpoint: "to",
|
|
1096
|
+
dateLabel: isEndOnStartDay ? t("neetoatoms.datePicker.sameDay", "Same day") : toDateLabel,
|
|
1097
|
+
value: toValue,
|
|
1098
|
+
onChange: onToChange,
|
|
1099
|
+
onFieldErrorChange: handleToErrorChange
|
|
1100
|
+
}
|
|
1101
|
+
];
|
|
1102
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
|
|
1103
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: endpoints.map(
|
|
1104
|
+
({ endpoint, dateLabel, value, onChange, onFieldErrorChange }) => {
|
|
1105
|
+
const isActive = endpoint === activeEndpoint;
|
|
1106
|
+
const endpointLabel = t(
|
|
1107
|
+
`neetoatoms.datePicker.${endpoint === "from" ? "start" : "end"}`,
|
|
1108
|
+
ENDPOINT_LABELS[endpoint]
|
|
1109
|
+
);
|
|
1110
|
+
const error = errors[endpoint];
|
|
1111
|
+
const errorId = `datepicker-${endpoint}-time-error-${id}`;
|
|
1112
|
+
const errorMessage = showError && error ? t(
|
|
1113
|
+
`neetoatoms.datePicker.errors.${error}`,
|
|
1114
|
+
ERROR_DEFAULTS[error]
|
|
1115
|
+
) : null;
|
|
1116
|
+
const isInvalid = !!errorMessage || endpoint === "to" && isOrderInvalid;
|
|
1117
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
|
|
1118
|
+
/* @__PURE__ */ jsxs(
|
|
1119
|
+
"button",
|
|
1120
|
+
{
|
|
1121
|
+
type: "button",
|
|
1122
|
+
"aria-pressed": isActive,
|
|
1123
|
+
tabIndex: -1,
|
|
1124
|
+
"data-testid": `datepicker-${endpoint}-endpoint`,
|
|
1125
|
+
disabled,
|
|
1126
|
+
className: cn(
|
|
1127
|
+
"flex min-w-0 items-baseline gap-1.5 rounded-sm text-start text-sm outline-none",
|
|
1128
|
+
"focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
1129
|
+
isActive ? "font-medium text-foreground" : "text-muted-foreground hover:text-foreground"
|
|
1130
|
+
),
|
|
1131
|
+
onClick: () => onEndpointSelect(endpoint),
|
|
1132
|
+
children: [
|
|
1133
|
+
/* @__PURE__ */ jsx("span", { children: endpointLabel }),
|
|
1134
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-xs font-normal text-muted-foreground", children: dateLabel || t("neetoatoms.datePicker.pickADay", "Pick a day") })
|
|
1135
|
+
]
|
|
1136
|
+
}
|
|
1137
|
+
),
|
|
1138
|
+
/* @__PURE__ */ jsx(
|
|
1139
|
+
SegmentedTimeInput,
|
|
1140
|
+
{
|
|
1141
|
+
"aria-describedby": [
|
|
1142
|
+
showHint ? hintId : null,
|
|
1143
|
+
errorMessage ? errorId : null,
|
|
1144
|
+
endpoint === "to" && isOrderInvalid ? orderErrorId : null
|
|
1145
|
+
].filter(Boolean).join(" ") || void 0,
|
|
1146
|
+
"aria-label": t(
|
|
1147
|
+
`neetoatoms.datePicker.${endpoint === "from" ? "startTime" : "endTime"}`,
|
|
1148
|
+
`${ENDPOINT_LABELS[endpoint]} time`
|
|
1149
|
+
),
|
|
1150
|
+
"data-testid": `datepicker-${endpoint}-time-input`,
|
|
1151
|
+
disabled,
|
|
1152
|
+
invalid: isInvalid,
|
|
1153
|
+
minuteStep,
|
|
1154
|
+
ref: endpoint === "from" ? fromTimeRef : void 0,
|
|
1155
|
+
value,
|
|
1156
|
+
onChange,
|
|
1157
|
+
onErrorChange: onFieldErrorChange
|
|
1158
|
+
}
|
|
1159
|
+
),
|
|
1160
|
+
errorMessage && /* @__PURE__ */ jsx(
|
|
1161
|
+
"p",
|
|
1162
|
+
{
|
|
1163
|
+
id: errorId,
|
|
1164
|
+
className: "text-xs text-destructive",
|
|
1165
|
+
"data-testid": `datepicker-${endpoint}-time-error`,
|
|
1166
|
+
role: "alert",
|
|
1167
|
+
children: errorMessage
|
|
1168
|
+
}
|
|
1169
|
+
)
|
|
1170
|
+
] }, endpoint);
|
|
1171
|
+
}
|
|
1172
|
+
) }),
|
|
1173
|
+
showHint && /* @__PURE__ */ jsx(
|
|
1174
|
+
"p",
|
|
1175
|
+
{
|
|
1176
|
+
id: hintId,
|
|
1177
|
+
className: "text-xs text-muted-foreground",
|
|
1178
|
+
"data-testid": "datepicker-time-hint",
|
|
1179
|
+
children: t("neetoatoms.datePicker.timeHint", {
|
|
1180
|
+
step: minuteStep,
|
|
1181
|
+
first: stepExamples(minuteStep)[0],
|
|
1182
|
+
second: stepExamples(minuteStep)[1],
|
|
1183
|
+
defaultValue: "Only {{step}}-minute steps are allowed, like {{first}} or {{second}}."
|
|
1184
|
+
})
|
|
1185
|
+
}
|
|
1186
|
+
),
|
|
1187
|
+
isOrderInvalid && /* @__PURE__ */ jsx(
|
|
1188
|
+
"p",
|
|
1189
|
+
{
|
|
1190
|
+
id: orderErrorId,
|
|
1191
|
+
className: "text-xs text-destructive",
|
|
1192
|
+
"data-testid": "datepicker-time-order-error",
|
|
1193
|
+
role: "alert",
|
|
1194
|
+
children: t(
|
|
1195
|
+
"neetoatoms.datePicker.errors.endBeforeStart",
|
|
1196
|
+
"End time must be after the start time."
|
|
1197
|
+
)
|
|
1198
|
+
}
|
|
1199
|
+
),
|
|
1200
|
+
timezoneLabel && /* @__PURE__ */ jsxs(
|
|
1201
|
+
"p",
|
|
1202
|
+
{
|
|
1203
|
+
className: "mt-1 flex items-center gap-2 text-xs text-muted-foreground",
|
|
1204
|
+
"data-testid": "datepicker-timezone",
|
|
1205
|
+
children: [
|
|
1206
|
+
/* @__PURE__ */ jsx(Globe, { "aria-hidden": true, className: "size-3.5 shrink-0" }),
|
|
1207
|
+
timezoneLabel
|
|
1208
|
+
]
|
|
1209
|
+
}
|
|
1210
|
+
)
|
|
1211
|
+
] });
|
|
1212
|
+
};
|
|
1213
|
+
RangeTimeSection.displayName = "RangeTimeSection";
|
|
1214
|
+
|
|
1017
1215
|
const useRangePicker = ({
|
|
1018
1216
|
currentValue,
|
|
1019
1217
|
showTime,
|
|
@@ -1022,52 +1220,49 @@ const useRangePicker = ({
|
|
|
1022
1220
|
setOpen
|
|
1023
1221
|
}) => {
|
|
1024
1222
|
const [pendingRange, setPendingRange] = useState(null);
|
|
1025
|
-
const [
|
|
1026
|
-
"from"
|
|
1027
|
-
);
|
|
1223
|
+
const [activeEndpoint, setActiveEndpoint] = useState("from");
|
|
1028
1224
|
const [hoveredDate, setHoveredDate] = useState(null);
|
|
1029
1225
|
const committed = currentValue ?? null;
|
|
1030
1226
|
const resetTransientState = useCallback(() => {
|
|
1031
1227
|
setPendingRange(null);
|
|
1032
|
-
|
|
1228
|
+
setActiveEndpoint("from");
|
|
1033
1229
|
setHoveredDate(null);
|
|
1034
1230
|
}, []);
|
|
1035
1231
|
const handleRangeSelect = useCallback(
|
|
1036
1232
|
(_range, triggerDate) => {
|
|
1037
1233
|
if (!triggerDate) return;
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
const nextFrom = existingFrom && triggerDate >= existingFrom ? existingFrom : null;
|
|
1046
|
-
setPendingRange([nextFrom, triggerDate]);
|
|
1047
|
-
}
|
|
1234
|
+
const from = pendingRange ? pendingRange[0] : committed?.[0] ?? null;
|
|
1235
|
+
const to = pendingRange ? pendingRange[1] : committed?.[1] ?? null;
|
|
1236
|
+
const isBeforeFrom = !!from && triggerDate < startOfDay(from);
|
|
1237
|
+
if (activeEndpoint === "from" || !from) {
|
|
1238
|
+
const nextTo = to && triggerDate <= to ? to : null;
|
|
1239
|
+
setPendingRange([triggerDate, nextTo]);
|
|
1240
|
+
setActiveEndpoint("to");
|
|
1048
1241
|
return;
|
|
1049
1242
|
}
|
|
1050
|
-
if (
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1243
|
+
if (showTime || needConfirm) {
|
|
1244
|
+
if (isBeforeFrom) {
|
|
1245
|
+
setPendingRange([triggerDate, null]);
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
setPendingRange([from, triggerDate]);
|
|
1249
|
+
setActiveEndpoint("from");
|
|
1055
1250
|
return;
|
|
1056
1251
|
}
|
|
1057
|
-
const [
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
commitValue([from, to]);
|
|
1252
|
+
const [orderedFrom, orderedTo] = orderRange(from, triggerDate);
|
|
1253
|
+
resetTransientState();
|
|
1254
|
+
commitValue([orderedFrom, orderedTo]);
|
|
1061
1255
|
setOpen(false);
|
|
1062
1256
|
},
|
|
1063
1257
|
[
|
|
1064
|
-
|
|
1258
|
+
activeEndpoint,
|
|
1065
1259
|
pendingRange,
|
|
1066
1260
|
committed,
|
|
1067
1261
|
showTime,
|
|
1068
1262
|
needConfirm,
|
|
1069
1263
|
commitValue,
|
|
1070
|
-
setOpen
|
|
1264
|
+
setOpen,
|
|
1265
|
+
resetTransientState
|
|
1071
1266
|
]
|
|
1072
1267
|
);
|
|
1073
1268
|
const handleHoverIn = useCallback(
|
|
@@ -1080,29 +1275,25 @@ const useRangePicker = ({
|
|
|
1080
1275
|
[hoveredDate]
|
|
1081
1276
|
);
|
|
1082
1277
|
const handleHoverOut = useCallback(() => setHoveredDate(null), []);
|
|
1083
|
-
const memoizedRangeSelected = useMemo(() => {
|
|
1084
|
-
const { from, to } = computeRangePreview({
|
|
1085
|
-
pendingRange,
|
|
1086
|
-
committed,
|
|
1087
|
-
hoveredDate,
|
|
1088
|
-
rangeStep: rangeSelectionStep
|
|
1089
|
-
});
|
|
1090
|
-
if (!from && !to) return void 0;
|
|
1091
|
-
return { from: from ?? void 0, to: to ?? void 0 };
|
|
1092
|
-
}, [pendingRange, committed, hoveredDate, rangeSelectionStep]);
|
|
1093
1278
|
const getPreviewParts = useCallback(
|
|
1094
1279
|
() => computeRangePreview({
|
|
1095
1280
|
pendingRange,
|
|
1096
1281
|
committed,
|
|
1097
1282
|
hoveredDate,
|
|
1098
|
-
rangeStep:
|
|
1283
|
+
rangeStep: activeEndpoint
|
|
1099
1284
|
}),
|
|
1100
|
-
[pendingRange, committed, hoveredDate,
|
|
1285
|
+
[pendingRange, committed, hoveredDate, activeEndpoint]
|
|
1101
1286
|
);
|
|
1287
|
+
const memoizedRangeSelected = useMemo(() => {
|
|
1288
|
+
const { from, to } = getPreviewParts();
|
|
1289
|
+
if (!from && !to) return void 0;
|
|
1290
|
+
return { from: from ?? void 0, to: to ?? void 0 };
|
|
1291
|
+
}, [getPreviewParts]);
|
|
1102
1292
|
return {
|
|
1103
1293
|
pendingRange,
|
|
1104
|
-
|
|
1105
|
-
|
|
1294
|
+
setPendingRange,
|
|
1295
|
+
activeEndpoint,
|
|
1296
|
+
setActiveEndpoint,
|
|
1106
1297
|
hoveredDate,
|
|
1107
1298
|
handleRangeSelect,
|
|
1108
1299
|
handleHoverIn,
|
|
@@ -1180,8 +1371,12 @@ const YearPicker = ({
|
|
|
1180
1371
|
const TIME_SECTION_CLASS_NAME = "w-0 min-w-full border-t border-border px-3 py-3";
|
|
1181
1372
|
const SHOW_TIME_CALENDAR_CLASS_NAME = "[--cell-size:--spacing(8.125)]";
|
|
1182
1373
|
const DEFAULT_ADDED_TIME = { hours: 12, minutes: 0, seconds: 0 };
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1374
|
+
const getDefaultEndTime = (minuteStep = 1) => ({
|
|
1375
|
+
hours: 23,
|
|
1376
|
+
minutes: Math.floor(59 / minuteStep) * minuteStep,
|
|
1377
|
+
seconds: 0
|
|
1378
|
+
});
|
|
1379
|
+
const isSameRange = (a, b) => a?.[0]?.getTime() === b?.[0]?.getTime() && a?.[1]?.getTime() === b?.[1]?.getTime();
|
|
1185
1380
|
const DatePicker = forwardRef(
|
|
1186
1381
|
({
|
|
1187
1382
|
value,
|
|
@@ -1230,6 +1425,7 @@ const DatePicker = forwardRef(
|
|
|
1230
1425
|
const containerRef = useRef(null);
|
|
1231
1426
|
const inputRef = useRef(null);
|
|
1232
1427
|
const cursorPosRef = useRef(null);
|
|
1428
|
+
const fromTimeRef = useRef(null);
|
|
1233
1429
|
const popoverContentId = useRef(
|
|
1234
1430
|
`datepicker-popover-${generatedId}`
|
|
1235
1431
|
).current;
|
|
@@ -1346,8 +1542,9 @@ const DatePicker = forwardRef(
|
|
|
1346
1542
|
};
|
|
1347
1543
|
const {
|
|
1348
1544
|
pendingRange,
|
|
1349
|
-
|
|
1350
|
-
|
|
1545
|
+
setPendingRange,
|
|
1546
|
+
activeEndpoint,
|
|
1547
|
+
setActiveEndpoint,
|
|
1351
1548
|
handleRangeSelect,
|
|
1352
1549
|
handleHoverIn,
|
|
1353
1550
|
handleHoverOut,
|
|
@@ -1361,9 +1558,38 @@ const DatePicker = forwardRef(
|
|
|
1361
1558
|
commitValue,
|
|
1362
1559
|
setOpen
|
|
1363
1560
|
});
|
|
1561
|
+
const isRangeConfirm = type === "range" && (showTime || needConfirm);
|
|
1562
|
+
const committedRange = type === "range" ? currentValue : null;
|
|
1563
|
+
const [draftFrom, draftTo] = orderRange(
|
|
1564
|
+
pendingRange ? pendingRange[0] : committedRange?.[0] ?? null,
|
|
1565
|
+
pendingRange ? pendingRange[1] : committedRange?.[1] ?? null
|
|
1566
|
+
);
|
|
1567
|
+
const draftEnd = draftTo ?? (showTime ? draftFrom : null);
|
|
1568
|
+
const isEndOnStartDay = showTime && !!draftFrom && isSameDay(draftFrom, draftEnd);
|
|
1569
|
+
const draftRange = useMemo(() => {
|
|
1570
|
+
if (!draftFrom || !draftEnd) return null;
|
|
1571
|
+
return showTime ? [
|
|
1572
|
+
applyTimeToDate(draftFrom, pendingTime),
|
|
1573
|
+
applyTimeToDate(draftEnd, pendingTimeTo)
|
|
1574
|
+
] : [draftFrom, draftEnd];
|
|
1575
|
+
}, [draftFrom, draftEnd, showTime, pendingTime, pendingTimeTo]);
|
|
1576
|
+
const isRangeOrderInvalid = showTime && !!draftRange && draftRange[1].getTime() <= draftRange[0].getTime();
|
|
1577
|
+
const applyTypedRange = (range) => {
|
|
1578
|
+
const snapped = range.map(
|
|
1579
|
+
(date) => showTime && minuteStep ? roundToMinuteStep(date, minuteStep) : date
|
|
1580
|
+
);
|
|
1581
|
+
const [from, to] = orderRange(snapped[0], snapped[1]);
|
|
1582
|
+
setPendingRange([startOfDay(from), startOfDay(to)]);
|
|
1583
|
+
setActiveEndpoint("from");
|
|
1584
|
+
if (showTime) {
|
|
1585
|
+
setPendingTime(dateToTimeValue(from));
|
|
1586
|
+
setPendingTimeTo(dateToTimeValue(to));
|
|
1587
|
+
}
|
|
1588
|
+
};
|
|
1364
1589
|
useEffect(() => {
|
|
1365
1590
|
if (type !== "range" || !open) return;
|
|
1366
|
-
const { from, to } = getPreviewParts();
|
|
1591
|
+
const { from, to: previewTo } = getPreviewParts();
|
|
1592
|
+
const to = previewTo ?? (showTime ? from : null);
|
|
1367
1593
|
const fromWithTime = from && showTime ? applyTimeToDate(from, pendingTime) : from;
|
|
1368
1594
|
const toWithTime = to && showTime ? applyTimeToDate(to, pendingTimeTo) : to;
|
|
1369
1595
|
const fromText = fromWithTime ? formatDate(fromWithTime, displayFormat) : "";
|
|
@@ -1397,7 +1623,9 @@ const DatePicker = forwardRef(
|
|
|
1397
1623
|
maskEnabled,
|
|
1398
1624
|
singleDateLen
|
|
1399
1625
|
);
|
|
1400
|
-
if (range)
|
|
1626
|
+
if (!range) return;
|
|
1627
|
+
if (isRangeConfirm) applyTypedRange(range);
|
|
1628
|
+
else commitValue(range);
|
|
1401
1629
|
};
|
|
1402
1630
|
const commitPendingOnClose = useCallback(() => {
|
|
1403
1631
|
const hasOkButton = showTime || needConfirm;
|
|
@@ -1427,14 +1655,9 @@ const DatePicker = forwardRef(
|
|
|
1427
1655
|
hasTimeError
|
|
1428
1656
|
]);
|
|
1429
1657
|
const closePopover = useCallback(() => {
|
|
1430
|
-
if (type === "range"
|
|
1431
|
-
const
|
|
1432
|
-
|
|
1433
|
-
pendingRange[1]
|
|
1434
|
-
);
|
|
1435
|
-
const fromFinal = showTime ? applyTimeToDate(fromBase, pendingTime) : fromBase;
|
|
1436
|
-
const toFinal = showTime ? applyTimeToDate(toBase, pendingTimeTo) : toBase;
|
|
1437
|
-
commitValue([fromFinal, toFinal]);
|
|
1658
|
+
if (type === "range") {
|
|
1659
|
+
const canCommit = draftRange && !(showTime && (hasTimeError || isRangeOrderInvalid)) && !isSameRange(draftRange, committedRange);
|
|
1660
|
+
if (canCommit) commitValue(draftRange);
|
|
1438
1661
|
} else {
|
|
1439
1662
|
commitPendingOnClose();
|
|
1440
1663
|
}
|
|
@@ -1444,9 +1667,9 @@ const DatePicker = forwardRef(
|
|
|
1444
1667
|
commitPendingOnClose,
|
|
1445
1668
|
setOpen,
|
|
1446
1669
|
type,
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1670
|
+
draftRange,
|
|
1671
|
+
committedRange,
|
|
1672
|
+
isRangeOrderInvalid,
|
|
1450
1673
|
showTime,
|
|
1451
1674
|
resetTransientState,
|
|
1452
1675
|
hasTimeError
|
|
@@ -1469,7 +1692,10 @@ const DatePicker = forwardRef(
|
|
|
1469
1692
|
setPendingTime(
|
|
1470
1693
|
fromDate ? dateToTimeValue(fromDate) : INITIAL_TIME_VALUE
|
|
1471
1694
|
);
|
|
1472
|
-
setPendingTimeTo(
|
|
1695
|
+
setPendingTimeTo(
|
|
1696
|
+
toDate ? dateToTimeValue(toDate) : getDefaultEndTime(minuteStep)
|
|
1697
|
+
);
|
|
1698
|
+
if (fromDate) setCalendarMonth(fromDate);
|
|
1473
1699
|
return;
|
|
1474
1700
|
}
|
|
1475
1701
|
const dateVal = currentValue;
|
|
@@ -1505,11 +1731,6 @@ const DatePicker = forwardRef(
|
|
|
1505
1731
|
setCalendarMonth(now);
|
|
1506
1732
|
if (type === "range") {
|
|
1507
1733
|
handleRangeSelect(void 0, now);
|
|
1508
|
-
if (showTime) {
|
|
1509
|
-
const nowTime = dateToTimeValue(now);
|
|
1510
|
-
if (rangeSelectionStep === "from") setPendingTime(nowTime);
|
|
1511
|
-
else setPendingTimeTo(nowTime);
|
|
1512
|
-
}
|
|
1513
1734
|
return;
|
|
1514
1735
|
}
|
|
1515
1736
|
if (showTime || needConfirm) {
|
|
@@ -1526,30 +1747,12 @@ const DatePicker = forwardRef(
|
|
|
1526
1747
|
setIsTimeErrorRequested(true);
|
|
1527
1748
|
return;
|
|
1528
1749
|
}
|
|
1529
|
-
if (
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
setCalendarMonth(
|
|
1536
|
-
new Date(fromValue.getFullYear(), fromValue.getMonth(), 1)
|
|
1537
|
-
);
|
|
1538
|
-
if (showTime && pendingRange?.[0]) {
|
|
1539
|
-
setPendingTimeTo(INITIAL_TIME_VALUE);
|
|
1540
|
-
}
|
|
1541
|
-
return;
|
|
1542
|
-
}
|
|
1543
|
-
if (rangeSelectionStep === "to" && fromValue && toValue) {
|
|
1544
|
-
const [fromBase, toBase] = orderRange(fromValue, toValue);
|
|
1545
|
-
const fromFinal = showTime ? applyTimeToDate(fromBase, pendingTime) : fromBase;
|
|
1546
|
-
const toFinal = showTime ? applyTimeToDate(toBase, pendingTimeTo) : toBase;
|
|
1547
|
-
commitValue([fromFinal, toFinal], showTime);
|
|
1548
|
-
onOk?.([fromFinal, toFinal]);
|
|
1549
|
-
resetTransientState();
|
|
1550
|
-
setOpen(false);
|
|
1551
|
-
return;
|
|
1552
|
-
}
|
|
1750
|
+
if (isRangeConfirm) {
|
|
1751
|
+
if (!draftRange || isRangeOrderInvalid) return;
|
|
1752
|
+
commitValue(draftRange, showTime);
|
|
1753
|
+
onOk?.(draftRange);
|
|
1754
|
+
resetTransientState();
|
|
1755
|
+
setOpen(false);
|
|
1553
1756
|
return;
|
|
1554
1757
|
}
|
|
1555
1758
|
if (pendingDate) {
|
|
@@ -1610,12 +1813,8 @@ const DatePicker = forwardRef(
|
|
|
1610
1813
|
singleDateLen
|
|
1611
1814
|
);
|
|
1612
1815
|
if (range) {
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
roundToMinuteStep(range[0], minuteStep),
|
|
1616
|
-
roundToMinuteStep(range[1], minuteStep)
|
|
1617
|
-
] : range
|
|
1618
|
-
);
|
|
1816
|
+
const snapped = showTime && minuteStep ? range.map((date) => roundToMinuteStep(date, minuteStep)) : range;
|
|
1817
|
+
commitValue(orderRange(snapped[0], snapped[1]));
|
|
1619
1818
|
}
|
|
1620
1819
|
} else {
|
|
1621
1820
|
const parsed = parseDate(inputText, displayFormat);
|
|
@@ -1669,6 +1868,20 @@ const DatePicker = forwardRef(
|
|
|
1669
1868
|
);
|
|
1670
1869
|
const calendarStartMonth = normalizedMinDate ?? (calendarMonth < defaultStartMonth ? calendarMonth : defaultStartMonth);
|
|
1671
1870
|
const calendarEndMonth = normalizedMaxDate ?? (calendarMonth > defaultEndMonth ? calendarMonth : defaultEndMonth);
|
|
1871
|
+
const handleEndpointSelect = (endpoint) => {
|
|
1872
|
+
setActiveEndpoint(endpoint);
|
|
1873
|
+
const date = endpoint === "from" ? draftFrom : draftEnd;
|
|
1874
|
+
if (!date) return;
|
|
1875
|
+
const monthsAhead = (date.getFullYear() - calendarMonth.getFullYear()) * 12 + date.getMonth() - calendarMonth.getMonth();
|
|
1876
|
+
if (monthsAhead < 0 || monthsAhead > 1) {
|
|
1877
|
+
setCalendarMonth(new Date(date.getFullYear(), date.getMonth(), 1));
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
const handleRangeCalendarKeyDown = (e) => {
|
|
1881
|
+
if (e.key !== "Tab" || e.shiftKey || !draftRange) return;
|
|
1882
|
+
e.preventDefault();
|
|
1883
|
+
fromTimeRef.current?.focusHour();
|
|
1884
|
+
};
|
|
1672
1885
|
const handleGridPickerSelect = (date) => {
|
|
1673
1886
|
commitValue(date);
|
|
1674
1887
|
setOpen(false);
|
|
@@ -1793,26 +2006,10 @@ const DatePicker = forwardRef(
|
|
|
1793
2006
|
startMonth: calendarStartMonth,
|
|
1794
2007
|
endMonth: calendarEndMonth
|
|
1795
2008
|
}
|
|
1796
|
-
) : showTime ? /* @__PURE__ */ jsx(
|
|
1797
|
-
RangeCalendar,
|
|
1798
|
-
{
|
|
1799
|
-
className: SHOW_TIME_CALENDAR_CLASS_NAME,
|
|
1800
|
-
todayDate,
|
|
1801
|
-
weekStartsOn,
|
|
1802
|
-
month: calendarMonth,
|
|
1803
|
-
onMonthChange: setCalendarMonth,
|
|
1804
|
-
selected: memoizedRangeSelected,
|
|
1805
|
-
onSelect: handleRangeSelect,
|
|
1806
|
-
disabled: calendarDisabled,
|
|
1807
|
-
startMonth: calendarStartMonth,
|
|
1808
|
-
endMonth: calendarEndMonth,
|
|
1809
|
-
onHoverIn: handleHoverIn,
|
|
1810
|
-
onHoverOut: handleHoverOut,
|
|
1811
|
-
numberOfMonths: 1
|
|
1812
|
-
}
|
|
1813
2009
|
) : /* @__PURE__ */ jsx(
|
|
1814
2010
|
RangeCalendar,
|
|
1815
2011
|
{
|
|
2012
|
+
className: cn(showTime && SHOW_TIME_CALENDAR_CLASS_NAME),
|
|
1816
2013
|
todayDate,
|
|
1817
2014
|
weekStartsOn,
|
|
1818
2015
|
month: calendarMonth,
|
|
@@ -1823,25 +2020,31 @@ const DatePicker = forwardRef(
|
|
|
1823
2020
|
startMonth: calendarStartMonth,
|
|
1824
2021
|
endMonth: calendarEndMonth,
|
|
1825
2022
|
onHoverIn: handleHoverIn,
|
|
1826
|
-
onHoverOut: handleHoverOut
|
|
2023
|
+
onHoverOut: handleHoverOut,
|
|
2024
|
+
onKeyDown: showTime ? handleRangeCalendarKeyDown : void 0
|
|
1827
2025
|
}
|
|
1828
2026
|
) }),
|
|
1829
2027
|
showTime && type === "range" && /* @__PURE__ */ jsx(
|
|
1830
|
-
|
|
2028
|
+
RangeTimeSection,
|
|
1831
2029
|
{
|
|
2030
|
+
activeEndpoint,
|
|
1832
2031
|
className: TIME_SECTION_CLASS_NAME,
|
|
1833
2032
|
disabled,
|
|
1834
|
-
|
|
1835
|
-
|
|
2033
|
+
fromDateLabel: formatDate(draftFrom, dateFormat),
|
|
2034
|
+
fromTimeRef,
|
|
2035
|
+
fromValue: pendingTime,
|
|
2036
|
+
isOrderInvalid: isRangeOrderInvalid,
|
|
2037
|
+
minuteStep,
|
|
1836
2038
|
showError: isTimeErrorRequested,
|
|
1837
2039
|
timezoneLabel,
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
2040
|
+
isEndOnStartDay,
|
|
2041
|
+
toDateLabel: formatDate(draftTo, dateFormat),
|
|
2042
|
+
toValue: pendingTimeTo,
|
|
2043
|
+
onEndpointSelect: handleEndpointSelect,
|
|
1841
2044
|
onErrorChange: setHasTimeError,
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
2045
|
+
onFromChange: setPendingTime,
|
|
2046
|
+
onToChange: setPendingTimeTo
|
|
2047
|
+
}
|
|
1845
2048
|
),
|
|
1846
2049
|
showTime && type !== "range" && /* @__PURE__ */ jsx(
|
|
1847
2050
|
TimeSection,
|
|
@@ -1867,10 +2070,10 @@ const DatePicker = forwardRef(
|
|
|
1867
2070
|
timezone,
|
|
1868
2071
|
onTimezoneChange,
|
|
1869
2072
|
nowDisabled: calendarDisabled(todayDate),
|
|
1870
|
-
showNow,
|
|
2073
|
+
showNow: showNow && !(type === "range" && showTime),
|
|
1871
2074
|
onNow: handleNow,
|
|
1872
|
-
|
|
1873
|
-
|
|
2075
|
+
okDisabled: isRangeConfirm && (!draftRange || isRangeOrderInvalid),
|
|
2076
|
+
onOk: handleOk
|
|
1874
2077
|
}
|
|
1875
2078
|
)
|
|
1876
2079
|
]
|
|
@@ -1904,4 +2107,4 @@ const DatePicker = forwardRef(
|
|
|
1904
2107
|
DatePicker.displayName = "DatePicker";
|
|
1905
2108
|
|
|
1906
2109
|
export { DatePicker as D };
|
|
1907
|
-
//# sourceMappingURL=DatePicker-
|
|
2110
|
+
//# sourceMappingURL=DatePicker-CMlA-hNW.js.map
|