@bigbinary/neeto-atoms 1.1.1 → 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-BC9AOZJ2.js → DatePicker-CMlA-hNW.js} +478 -280
- 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-aGLz-3Bz.js → DatePicker-CBxWLALJ.js} +477 -279
- 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 +2 -1
- 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-BC9AOZJ2.js.map +0 -1
- package/dist/cjs/DatePicker-aGLz-3Bz.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';
|
|
@@ -186,8 +186,8 @@ const getDisplayFormat = (dateFormat, timeFormat, showTime) => {
|
|
|
186
186
|
const fmt = showTime ? `${dateFormat} ${timeFormat}` : dateFormat;
|
|
187
187
|
return normalizeToDateFnsFormat(fmt);
|
|
188
188
|
};
|
|
189
|
-
const getDatePlaceholder = (dateFormat,
|
|
190
|
-
const single =
|
|
189
|
+
const getDatePlaceholder = (dateFormat, type) => {
|
|
190
|
+
const single = dateFormat.toUpperCase();
|
|
191
191
|
return type === "range" ? `${single} - ${single}` : single;
|
|
192
192
|
};
|
|
193
193
|
const isDatePartComplete = (part, maskEnabled, singleDateLen) => maskEnabled ? part.length >= singleDateLen : part.length > 0;
|
|
@@ -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;
|
|
@@ -1271,12 +1467,7 @@ const DatePicker = forwardRef(
|
|
|
1271
1467
|
);
|
|
1272
1468
|
const sizeConfig = SIZE_CONFIG[size];
|
|
1273
1469
|
const maskEnabled = isFixedWidthFormat(displayFormat);
|
|
1274
|
-
const defaultPlaceholder = getDatePlaceholder(
|
|
1275
|
-
dateFormat,
|
|
1276
|
-
timeFormat,
|
|
1277
|
-
showTime,
|
|
1278
|
-
type
|
|
1279
|
-
);
|
|
1470
|
+
const defaultPlaceholder = getDatePlaceholder(dateFormat, type);
|
|
1280
1471
|
const maskTemplate = useMemo(
|
|
1281
1472
|
() => maskEnabled ? type === "range" ? buildRangeMaskTemplate(displayFormat) : buildMaskTemplate(displayFormat) : null,
|
|
1282
1473
|
[displayFormat, type, maskEnabled]
|
|
@@ -1351,8 +1542,9 @@ const DatePicker = forwardRef(
|
|
|
1351
1542
|
};
|
|
1352
1543
|
const {
|
|
1353
1544
|
pendingRange,
|
|
1354
|
-
|
|
1355
|
-
|
|
1545
|
+
setPendingRange,
|
|
1546
|
+
activeEndpoint,
|
|
1547
|
+
setActiveEndpoint,
|
|
1356
1548
|
handleRangeSelect,
|
|
1357
1549
|
handleHoverIn,
|
|
1358
1550
|
handleHoverOut,
|
|
@@ -1366,9 +1558,38 @@ const DatePicker = forwardRef(
|
|
|
1366
1558
|
commitValue,
|
|
1367
1559
|
setOpen
|
|
1368
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
|
+
};
|
|
1369
1589
|
useEffect(() => {
|
|
1370
1590
|
if (type !== "range" || !open) return;
|
|
1371
|
-
const { from, to } = getPreviewParts();
|
|
1591
|
+
const { from, to: previewTo } = getPreviewParts();
|
|
1592
|
+
const to = previewTo ?? (showTime ? from : null);
|
|
1372
1593
|
const fromWithTime = from && showTime ? applyTimeToDate(from, pendingTime) : from;
|
|
1373
1594
|
const toWithTime = to && showTime ? applyTimeToDate(to, pendingTimeTo) : to;
|
|
1374
1595
|
const fromText = fromWithTime ? formatDate(fromWithTime, displayFormat) : "";
|
|
@@ -1402,7 +1623,9 @@ const DatePicker = forwardRef(
|
|
|
1402
1623
|
maskEnabled,
|
|
1403
1624
|
singleDateLen
|
|
1404
1625
|
);
|
|
1405
|
-
if (range)
|
|
1626
|
+
if (!range) return;
|
|
1627
|
+
if (isRangeConfirm) applyTypedRange(range);
|
|
1628
|
+
else commitValue(range);
|
|
1406
1629
|
};
|
|
1407
1630
|
const commitPendingOnClose = useCallback(() => {
|
|
1408
1631
|
const hasOkButton = showTime || needConfirm;
|
|
@@ -1432,14 +1655,9 @@ const DatePicker = forwardRef(
|
|
|
1432
1655
|
hasTimeError
|
|
1433
1656
|
]);
|
|
1434
1657
|
const closePopover = useCallback(() => {
|
|
1435
|
-
if (type === "range"
|
|
1436
|
-
const
|
|
1437
|
-
|
|
1438
|
-
pendingRange[1]
|
|
1439
|
-
);
|
|
1440
|
-
const fromFinal = showTime ? applyTimeToDate(fromBase, pendingTime) : fromBase;
|
|
1441
|
-
const toFinal = showTime ? applyTimeToDate(toBase, pendingTimeTo) : toBase;
|
|
1442
|
-
commitValue([fromFinal, toFinal]);
|
|
1658
|
+
if (type === "range") {
|
|
1659
|
+
const canCommit = draftRange && !(showTime && (hasTimeError || isRangeOrderInvalid)) && !isSameRange(draftRange, committedRange);
|
|
1660
|
+
if (canCommit) commitValue(draftRange);
|
|
1443
1661
|
} else {
|
|
1444
1662
|
commitPendingOnClose();
|
|
1445
1663
|
}
|
|
@@ -1449,9 +1667,9 @@ const DatePicker = forwardRef(
|
|
|
1449
1667
|
commitPendingOnClose,
|
|
1450
1668
|
setOpen,
|
|
1451
1669
|
type,
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1670
|
+
draftRange,
|
|
1671
|
+
committedRange,
|
|
1672
|
+
isRangeOrderInvalid,
|
|
1455
1673
|
showTime,
|
|
1456
1674
|
resetTransientState,
|
|
1457
1675
|
hasTimeError
|
|
@@ -1474,7 +1692,10 @@ const DatePicker = forwardRef(
|
|
|
1474
1692
|
setPendingTime(
|
|
1475
1693
|
fromDate ? dateToTimeValue(fromDate) : INITIAL_TIME_VALUE
|
|
1476
1694
|
);
|
|
1477
|
-
setPendingTimeTo(
|
|
1695
|
+
setPendingTimeTo(
|
|
1696
|
+
toDate ? dateToTimeValue(toDate) : getDefaultEndTime(minuteStep)
|
|
1697
|
+
);
|
|
1698
|
+
if (fromDate) setCalendarMonth(fromDate);
|
|
1478
1699
|
return;
|
|
1479
1700
|
}
|
|
1480
1701
|
const dateVal = currentValue;
|
|
@@ -1510,11 +1731,6 @@ const DatePicker = forwardRef(
|
|
|
1510
1731
|
setCalendarMonth(now);
|
|
1511
1732
|
if (type === "range") {
|
|
1512
1733
|
handleRangeSelect(void 0, now);
|
|
1513
|
-
if (showTime) {
|
|
1514
|
-
const nowTime = dateToTimeValue(now);
|
|
1515
|
-
if (rangeSelectionStep === "from") setPendingTime(nowTime);
|
|
1516
|
-
else setPendingTimeTo(nowTime);
|
|
1517
|
-
}
|
|
1518
1734
|
return;
|
|
1519
1735
|
}
|
|
1520
1736
|
if (showTime || needConfirm) {
|
|
@@ -1531,30 +1747,12 @@ const DatePicker = forwardRef(
|
|
|
1531
1747
|
setIsTimeErrorRequested(true);
|
|
1532
1748
|
return;
|
|
1533
1749
|
}
|
|
1534
|
-
if (
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
setCalendarMonth(
|
|
1541
|
-
new Date(fromValue.getFullYear(), fromValue.getMonth(), 1)
|
|
1542
|
-
);
|
|
1543
|
-
if (showTime && pendingRange?.[0]) {
|
|
1544
|
-
setPendingTimeTo(INITIAL_TIME_VALUE);
|
|
1545
|
-
}
|
|
1546
|
-
return;
|
|
1547
|
-
}
|
|
1548
|
-
if (rangeSelectionStep === "to" && fromValue && toValue) {
|
|
1549
|
-
const [fromBase, toBase] = orderRange(fromValue, toValue);
|
|
1550
|
-
const fromFinal = showTime ? applyTimeToDate(fromBase, pendingTime) : fromBase;
|
|
1551
|
-
const toFinal = showTime ? applyTimeToDate(toBase, pendingTimeTo) : toBase;
|
|
1552
|
-
commitValue([fromFinal, toFinal], showTime);
|
|
1553
|
-
onOk?.([fromFinal, toFinal]);
|
|
1554
|
-
resetTransientState();
|
|
1555
|
-
setOpen(false);
|
|
1556
|
-
return;
|
|
1557
|
-
}
|
|
1750
|
+
if (isRangeConfirm) {
|
|
1751
|
+
if (!draftRange || isRangeOrderInvalid) return;
|
|
1752
|
+
commitValue(draftRange, showTime);
|
|
1753
|
+
onOk?.(draftRange);
|
|
1754
|
+
resetTransientState();
|
|
1755
|
+
setOpen(false);
|
|
1558
1756
|
return;
|
|
1559
1757
|
}
|
|
1560
1758
|
if (pendingDate) {
|
|
@@ -1615,12 +1813,8 @@ const DatePicker = forwardRef(
|
|
|
1615
1813
|
singleDateLen
|
|
1616
1814
|
);
|
|
1617
1815
|
if (range) {
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
roundToMinuteStep(range[0], minuteStep),
|
|
1621
|
-
roundToMinuteStep(range[1], minuteStep)
|
|
1622
|
-
] : range
|
|
1623
|
-
);
|
|
1816
|
+
const snapped = showTime && minuteStep ? range.map((date) => roundToMinuteStep(date, minuteStep)) : range;
|
|
1817
|
+
commitValue(orderRange(snapped[0], snapped[1]));
|
|
1624
1818
|
}
|
|
1625
1819
|
} else {
|
|
1626
1820
|
const parsed = parseDate(inputText, displayFormat);
|
|
@@ -1674,6 +1868,20 @@ const DatePicker = forwardRef(
|
|
|
1674
1868
|
);
|
|
1675
1869
|
const calendarStartMonth = normalizedMinDate ?? (calendarMonth < defaultStartMonth ? calendarMonth : defaultStartMonth);
|
|
1676
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
|
+
};
|
|
1677
1885
|
const handleGridPickerSelect = (date) => {
|
|
1678
1886
|
commitValue(date);
|
|
1679
1887
|
setOpen(false);
|
|
@@ -1798,26 +2006,10 @@ const DatePicker = forwardRef(
|
|
|
1798
2006
|
startMonth: calendarStartMonth,
|
|
1799
2007
|
endMonth: calendarEndMonth
|
|
1800
2008
|
}
|
|
1801
|
-
) : showTime ? /* @__PURE__ */ jsx(
|
|
1802
|
-
RangeCalendar,
|
|
1803
|
-
{
|
|
1804
|
-
className: SHOW_TIME_CALENDAR_CLASS_NAME,
|
|
1805
|
-
todayDate,
|
|
1806
|
-
weekStartsOn,
|
|
1807
|
-
month: calendarMonth,
|
|
1808
|
-
onMonthChange: setCalendarMonth,
|
|
1809
|
-
selected: memoizedRangeSelected,
|
|
1810
|
-
onSelect: handleRangeSelect,
|
|
1811
|
-
disabled: calendarDisabled,
|
|
1812
|
-
startMonth: calendarStartMonth,
|
|
1813
|
-
endMonth: calendarEndMonth,
|
|
1814
|
-
onHoverIn: handleHoverIn,
|
|
1815
|
-
onHoverOut: handleHoverOut,
|
|
1816
|
-
numberOfMonths: 1
|
|
1817
|
-
}
|
|
1818
2009
|
) : /* @__PURE__ */ jsx(
|
|
1819
2010
|
RangeCalendar,
|
|
1820
2011
|
{
|
|
2012
|
+
className: cn(showTime && SHOW_TIME_CALENDAR_CLASS_NAME),
|
|
1821
2013
|
todayDate,
|
|
1822
2014
|
weekStartsOn,
|
|
1823
2015
|
month: calendarMonth,
|
|
@@ -1828,25 +2020,31 @@ const DatePicker = forwardRef(
|
|
|
1828
2020
|
startMonth: calendarStartMonth,
|
|
1829
2021
|
endMonth: calendarEndMonth,
|
|
1830
2022
|
onHoverIn: handleHoverIn,
|
|
1831
|
-
onHoverOut: handleHoverOut
|
|
2023
|
+
onHoverOut: handleHoverOut,
|
|
2024
|
+
onKeyDown: showTime ? handleRangeCalendarKeyDown : void 0
|
|
1832
2025
|
}
|
|
1833
2026
|
) }),
|
|
1834
2027
|
showTime && type === "range" && /* @__PURE__ */ jsx(
|
|
1835
|
-
|
|
2028
|
+
RangeTimeSection,
|
|
1836
2029
|
{
|
|
2030
|
+
activeEndpoint,
|
|
1837
2031
|
className: TIME_SECTION_CLASS_NAME,
|
|
1838
2032
|
disabled,
|
|
1839
|
-
|
|
1840
|
-
|
|
2033
|
+
fromDateLabel: formatDate(draftFrom, dateFormat),
|
|
2034
|
+
fromTimeRef,
|
|
2035
|
+
fromValue: pendingTime,
|
|
2036
|
+
isOrderInvalid: isRangeOrderInvalid,
|
|
2037
|
+
minuteStep,
|
|
1841
2038
|
showError: isTimeErrorRequested,
|
|
1842
2039
|
timezoneLabel,
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
2040
|
+
isEndOnStartDay,
|
|
2041
|
+
toDateLabel: formatDate(draftTo, dateFormat),
|
|
2042
|
+
toValue: pendingTimeTo,
|
|
2043
|
+
onEndpointSelect: handleEndpointSelect,
|
|
1846
2044
|
onErrorChange: setHasTimeError,
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2045
|
+
onFromChange: setPendingTime,
|
|
2046
|
+
onToChange: setPendingTimeTo
|
|
2047
|
+
}
|
|
1850
2048
|
),
|
|
1851
2049
|
showTime && type !== "range" && /* @__PURE__ */ jsx(
|
|
1852
2050
|
TimeSection,
|
|
@@ -1872,10 +2070,10 @@ const DatePicker = forwardRef(
|
|
|
1872
2070
|
timezone,
|
|
1873
2071
|
onTimezoneChange,
|
|
1874
2072
|
nowDisabled: calendarDisabled(todayDate),
|
|
1875
|
-
showNow,
|
|
2073
|
+
showNow: showNow && !(type === "range" && showTime),
|
|
1876
2074
|
onNow: handleNow,
|
|
1877
|
-
|
|
1878
|
-
|
|
2075
|
+
okDisabled: isRangeConfirm && (!draftRange || isRangeOrderInvalid),
|
|
2076
|
+
onOk: handleOk
|
|
1879
2077
|
}
|
|
1880
2078
|
)
|
|
1881
2079
|
]
|
|
@@ -1909,4 +2107,4 @@ const DatePicker = forwardRef(
|
|
|
1909
2107
|
DatePicker.displayName = "DatePicker";
|
|
1910
2108
|
|
|
1911
2109
|
export { DatePicker as D };
|
|
1912
|
-
//# sourceMappingURL=DatePicker-
|
|
2110
|
+
//# sourceMappingURL=DatePicker-CMlA-hNW.js.map
|