@bigbinary/neeto-atoms 1.0.144 → 1.1.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.
Files changed (48) hide show
  1. package/dist/{DatePicker-edLgTark.js → DatePicker-BC9AOZJ2.js} +713 -135
  2. package/dist/DatePicker-BC9AOZJ2.js.map +1 -0
  3. package/dist/{TimePicker-BA7JhrYd.js → TimePicker-CJ8K2zea.js} +192 -17
  4. package/dist/TimePicker-CJ8K2zea.js.map +1 -0
  5. package/dist/{TranslationProvider-Dd0ITHC0.js → TranslationProvider-BJjfFEgX.js} +12 -1
  6. package/dist/{TranslationProvider-Dd0ITHC0.js.map → TranslationProvider-BJjfFEgX.js.map} +1 -1
  7. package/dist/cjs/{DatePicker-D8GQGON2.js → DatePicker-aGLz-3Bz.js} +724 -145
  8. package/dist/cjs/DatePicker-aGLz-3Bz.js.map +1 -0
  9. package/dist/cjs/{TimePicker-CVGXEgk5.js → TimePicker-BhOW7vbV.js} +217 -41
  10. package/dist/cjs/TimePicker-BhOW7vbV.js.map +1 -0
  11. package/dist/cjs/{TranslationProvider-DOeyGtbV.js → TranslationProvider-C1JDwKEN.js} +12 -1
  12. package/dist/cjs/{TranslationProvider-DOeyGtbV.js.map → TranslationProvider-C1JDwKEN.js.map} +1 -1
  13. package/dist/cjs/components/DatePicker.js +7 -6
  14. package/dist/cjs/components/DatePicker.js.map +1 -1
  15. package/dist/cjs/components/TimePicker.js +7 -7
  16. package/dist/cjs/components/TranslationProvider.js +1 -1
  17. package/dist/cjs/components/index.js +7 -7
  18. package/dist/cjs/index.js +8 -8
  19. package/dist/cjs/primitives/AlertDialog.js +39 -7
  20. package/dist/cjs/primitives/AlertDialog.js.map +1 -1
  21. package/dist/cjs/primitives/index.js +1 -1
  22. package/dist/cjs/{TimePickerPanel-DvVRLqeM.js → utils-S4yTubWZ.js} +25 -197
  23. package/dist/cjs/utils-S4yTubWZ.js.map +1 -0
  24. package/dist/components/DatePicker/DatePickerFooter.d.ts +1 -0
  25. package/dist/components/DatePicker/RangeCalendar.d.ts +4 -3
  26. package/dist/components/DatePicker/SegmentedTimeInput.d.ts +17 -0
  27. package/dist/components/DatePicker/TimeSection.d.ts +22 -0
  28. package/dist/components/DatePicker/constants.d.ts +2 -1
  29. package/dist/components/DatePicker/segmentedTime.d.ts +58 -0
  30. package/dist/components/DatePicker/types.d.ts +33 -4
  31. package/dist/components/DatePicker/utils.d.ts +3 -0
  32. package/dist/components/DatePicker.js +7 -6
  33. package/dist/components/DatePicker.js.map +1 -1
  34. package/dist/components/TimePicker.js +6 -6
  35. package/dist/components/TranslationProvider.js +1 -1
  36. package/dist/components/index.js +6 -6
  37. package/dist/index.js +8 -8
  38. package/dist/translations/index.d.ts +11 -0
  39. package/dist/utils/inputMask.d.ts +2 -1
  40. package/dist/{TimePickerPanel-n-Dz1p5N.js → utils-Ca3DmOrC.js} +22 -197
  41. package/dist/utils-Ca3DmOrC.js.map +1 -0
  42. package/package.json +1 -1
  43. package/dist/DatePicker-edLgTark.js.map +0 -1
  44. package/dist/TimePicker-BA7JhrYd.js.map +0 -1
  45. package/dist/TimePickerPanel-n-Dz1p5N.js.map +0 -1
  46. package/dist/cjs/DatePicker-D8GQGON2.js.map +0 -1
  47. package/dist/cjs/TimePicker-CVGXEgk5.js.map +0 -1
  48. package/dist/cjs/TimePickerPanel-DvVRLqeM.js.map +0 -1
@@ -1,9 +1,9 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { forwardRef, useState, useCallback, useMemo, useId, useRef, useEffect } from 'react';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import React__default, { forwardRef, useRef, useState, useEffect, 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';
6
- import { u as useControlledOpen, l as isFixedWidthFormat, m as buildRangeMaskTemplate, d as buildMaskTemplate, b as useOutsideClickClose, e as useCursorRestore, T as TimePickerPanel, j as applyMask, n as dateToTimeValue } from './TimePickerPanel-n-Dz1p5N.js';
6
+ import { t as to12Hour, a as to24Hour, p as padNumber, d as timeValueEquals, C as Clock, u as useControlledOpen, q as isFixedWidthFormat, r as buildRangeMaskTemplate, h as buildMaskTemplate, e as useOutsideClickClose, j as useCursorRestore, m as applyMask, s as dateToTimeValue } from './utils-Ca3DmOrC.js';
7
7
  import pureDayjs from 'dayjs';
8
8
  import customParseFormat from 'dayjs/plugin/customParseFormat';
9
9
  import { dayjs } from '@bigbinary/neeto-commons-frontend/utils';
@@ -12,6 +12,9 @@ import { Button } from './primitives/Button.js';
12
12
  import { Field, FieldLabel, FieldContent, FieldError, FieldDescription } from './primitives/Field.js';
13
13
  import { c as createLucideIcon } from './createLucideIcon-C8ycilSN.js';
14
14
  import { X } from './x-_o2T3n6D.js';
15
+ import { useTranslation } from 'react-i18next';
16
+ import { Label } from './primitives/Label.js';
17
+ import { Switch } from './primitives/Switch.js';
15
18
  import { C as ChevronLeft } from './chevron-left-BDoT8E2-.js';
16
19
  import { C as ChevronRight } from './chevron-right-DQnrO-ek.js';
17
20
 
@@ -23,16 +26,32 @@ import { C as ChevronRight } from './chevron-right-DQnrO-ek.js';
23
26
  */
24
27
 
25
28
 
26
- const __iconNode = [
29
+ const __iconNode$1 = [
27
30
  ["path", { d: "M8 2v4", key: "1cmpym" }],
28
31
  ["path", { d: "M16 2v4", key: "4m81vk" }],
29
32
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
30
33
  ["path", { d: "M3 10h18", key: "8toen8" }]
31
34
  ];
32
- const Calendar = createLucideIcon("calendar", __iconNode);
35
+ const Calendar = createLucideIcon("calendar", __iconNode$1);
36
+
37
+ /**
38
+ * @license lucide-react v0.577.0 - ISC
39
+ *
40
+ * This source code is licensed under the ISC license.
41
+ * See the LICENSE file in the root directory of this source tree.
42
+ */
43
+
44
+
45
+ const __iconNode = [
46
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
47
+ ["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20", key: "13o1zl" }],
48
+ ["path", { d: "M2 12h20", key: "9i4pu4" }]
49
+ ];
50
+ const Globe = createLucideIcon("globe", __iconNode);
33
51
 
34
52
  const DEFAULT_DATE_FORMAT = "dd/MM/yyyy";
35
- const DEFAULT_TIME_FORMAT = "HH:mm:ss";
53
+ const DEFAULT_TIME_FORMAT = "hh:mm A";
54
+ const CALENDAR_NAVIGATION_YEAR_RANGE = 100;
36
55
  const INITIAL_TIME_VALUE = {
37
56
  hours: 0,
38
57
  minutes: 0,
@@ -102,6 +121,33 @@ const getInitialCalendarMonth = (value, defaultValue, type) => {
102
121
  };
103
122
  const normalizeToDayjsFormat = (fmt) => fmt.replace(/\byyyy\b/g, "YYYY").replace(/\byy\b/g, "YY").replace(/\bdd\b/g, "DD").replace(/\bd\b/g, "D");
104
123
  const normalizeToDateFnsFormat = (fmt) => fmt.replace(/YYYY/g, "yyyy").replace(/YY/g, "yy").replace(/DD/g, "dd").replace(/\bD\b/g, "d");
124
+ const roundToMinuteStep = (date, step) => {
125
+ const rounded = new Date(date);
126
+ const minutes = Math.min(
127
+ 60 - step,
128
+ Math.round(date.getMinutes() / step) * step
129
+ );
130
+ rounded.setMinutes(minutes, 0, 0);
131
+ return rounded;
132
+ };
133
+ const getTimezoneLabel = (timezone) => {
134
+ const zone = timezone === "utc" ? "UTC" : dayjs().$x?.$timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
135
+ try {
136
+ const zoneName = (timeZoneName) => new Intl.DateTimeFormat("en-US", { timeZone: zone, timeZoneName }).formatToParts(/* @__PURE__ */ new Date()).find((part) => part.type === "timeZoneName")?.value;
137
+ const name = zoneName("long") ?? zone;
138
+ const offset = (zoneName("longOffset") ?? "GMT").replace("GMT", "UTC").replace(/([+-])0?(\d+):00$/, "$1$2").replace(/([+-])0(\d)/, "$1$2");
139
+ return `${name} (${offset === "UTC" ? "UTC+0" : offset})`;
140
+ } catch {
141
+ return zone;
142
+ }
143
+ };
144
+ const roundUpToMinuteStep = (date, step) => {
145
+ const rounded = new Date(date);
146
+ const hasSeconds = date.getSeconds() > 0 || date.getMilliseconds() > 0;
147
+ const minutes = date.getMinutes() + (hasSeconds ? 1 : 0);
148
+ rounded.setMinutes(Math.ceil(minutes / step) * step, 0, 0);
149
+ return rounded;
150
+ };
105
151
  const formatDate = (date, formatStr) => {
106
152
  if (!date) return "";
107
153
  try {
@@ -260,6 +306,7 @@ const DatePickerFooter = ({
260
306
  timezone,
261
307
  onTimezoneChange,
262
308
  nowDisabled,
309
+ showNow = true,
263
310
  onNow,
264
311
  onOk,
265
312
  okLabel = "OK",
@@ -274,7 +321,7 @@ const DatePickerFooter = ({
274
321
  className
275
322
  ),
276
323
  children: [
277
- /* @__PURE__ */ jsx(
324
+ showNow && /* @__PURE__ */ jsx(
278
325
  Button,
279
326
  {
280
327
  variant: "ghost",
@@ -434,6 +481,443 @@ const DatePickerTrigger = forwardRef(
434
481
  );
435
482
  DatePickerTrigger.displayName = "DatePickerTrigger";
436
483
 
484
+ const SEGMENT_KEYS = ["hour", "minute", "period"];
485
+ const EMPTY_SEGMENT = { text: "", done: false, auto: false };
486
+ const segment = (text, done, auto = false) => ({
487
+ text,
488
+ done,
489
+ auto
490
+ });
491
+ const clampIndex = (index) => Math.max(0, Math.min(2, index));
492
+ const withSegment = (state, key, value) => ({ ...state, [key]: value });
493
+ const snapMinute = (minutes, step = 1) => padNumber(Math.min(60 - step, Math.round(Number(minutes) / step) * step));
494
+ const emptySegmentedTime = () => ({
495
+ hour: EMPTY_SEGMENT,
496
+ minute: EMPTY_SEGMENT,
497
+ period: EMPTY_SEGMENT,
498
+ active: 0
499
+ });
500
+ const segmentedTimeFromValue = (value, step = 1) => {
501
+ const { hour12, period } = to12Hour(value.hours);
502
+ return {
503
+ hour: segment(String(hour12), true),
504
+ minute: segment(snapMinute(value.minutes, step), true),
505
+ period: segment(period, true),
506
+ active: 0
507
+ };
508
+ };
509
+ const isSegmentedTimeEmpty = (state) => SEGMENT_KEYS.every((key) => state[key].text === "");
510
+ const getSegmentedTimeError = (state) => {
511
+ if (isSegmentedTimeEmpty(state)) return "timeRequired";
512
+ if (!state.hour.text) return "hourRequired";
513
+ if (!state.minute.text) return "minuteRequired";
514
+ if (!state.period.text) return "periodRequired";
515
+ return null;
516
+ };
517
+ const segmentedTimeToValue = (state) => {
518
+ if (getSegmentedTimeError(state)) return null;
519
+ return {
520
+ hours: to24Hour(Number(state.hour.text), state.period.text),
521
+ minutes: Number(state.minute.text),
522
+ seconds: 0
523
+ };
524
+ };
525
+ const finishSegment = (state, key, step) => {
526
+ const { text } = state[key];
527
+ if (!text) return state;
528
+ if (key === "hour" && text === "0") {
529
+ return withSegment(state, "hour", EMPTY_SEGMENT);
530
+ }
531
+ if (key === "minute" && text.length === 1) {
532
+ return withSegment(
533
+ state,
534
+ "minute",
535
+ segment(snapMinute(text, step), true, true)
536
+ );
537
+ }
538
+ return withSegment(state, key, { ...state[key], done: true });
539
+ };
540
+ const finishActiveSegment = (state, step = 1) => finishSegment(state, SEGMENT_KEYS[state.active], step);
541
+ const focusSegment = (state, index, step = 1) => {
542
+ const next = clampIndex(index);
543
+ const finished = next > state.active ? finishActiveSegment(state, step) : state;
544
+ return { ...finished, active: next };
545
+ };
546
+ const focusFirstEmptySegment = (state) => {
547
+ const index = SEGMENT_KEYS.findIndex((key) => !state[key].text);
548
+ return { ...state, active: index === -1 ? 2 : index };
549
+ };
550
+ const nextSegment = (state, step = 1) => state[SEGMENT_KEYS[state.active]].text ? focusSegment(state, state.active + 1, step) : state;
551
+ const previousSegment = (state) => focusSegment(state, state.active - 1);
552
+ const typeDigit = (state, digit, step = 1) => {
553
+ const advance = (next, index) => focusSegment(next, index, step);
554
+ const key = SEGMENT_KEYS[state.active];
555
+ if (key === "period") return state;
556
+ const current = state[key];
557
+ const text = current.done ? "" : current.text;
558
+ if (key === "hour") {
559
+ if (text === "") {
560
+ if (digit === "0" || digit === "1") {
561
+ return withSegment(state, "hour", segment(digit, false));
562
+ }
563
+ return advance(withSegment(state, "hour", segment(digit, true)), 1);
564
+ }
565
+ if (text === "1") {
566
+ if ("012".includes(digit)) {
567
+ return advance(
568
+ withSegment(state, "hour", segment(`1${digit}`, true)),
569
+ 1
570
+ );
571
+ }
572
+ const moved = advance(withSegment(state, "hour", segment("1", true)), 1);
573
+ return typeDigit(moved, digit, step);
574
+ }
575
+ if (digit === "0") return state;
576
+ return advance(withSegment(state, "hour", segment(digit, true)), 1);
577
+ }
578
+ if (text === "") {
579
+ if (digit >= "6") {
580
+ return advance(
581
+ withSegment(
582
+ state,
583
+ "minute",
584
+ segment(snapMinute(digit, step), true, true)
585
+ ),
586
+ 2
587
+ );
588
+ }
589
+ return withSegment(state, "minute", segment(digit, false));
590
+ }
591
+ return advance(
592
+ withSegment(state, "minute", segment(snapMinute(text + digit, step), true)),
593
+ 2
594
+ );
595
+ };
596
+ const typePeriod = (state, letter, step = 1) => withSegment(
597
+ focusSegment(state, 2, step),
598
+ "period",
599
+ segment(letter === "a" ? "AM" : "PM", true)
600
+ );
601
+ const togglePeriod = (state) => withSegment(
602
+ state,
603
+ "period",
604
+ segment(state.period.text === "AM" ? "PM" : "AM", true)
605
+ );
606
+ const stepSegment = (state, direction, step = 1) => {
607
+ const key = SEGMENT_KEYS[state.active];
608
+ if (key === "hour") {
609
+ const hour = Number(state.hour.text) || (direction > 0 ? 0 : 1);
610
+ const next = (hour - 1 + direction + 12) % 12 + 1;
611
+ return withSegment(state, "hour", segment(String(next), true));
612
+ }
613
+ if (key === "minute") {
614
+ const minute = state.minute.text === "" ? direction > 0 ? -step : 0 : Number(state.minute.text);
615
+ const stepped = direction > 0 ? Math.floor(minute / step) * step + step : Math.ceil(minute / step) * step - step;
616
+ return withSegment(
617
+ state,
618
+ "minute",
619
+ segment(padNumber((stepped + 60) % 60), true)
620
+ );
621
+ }
622
+ return togglePeriod(state);
623
+ };
624
+ const backspace = (state) => {
625
+ const moveBack = state[SEGMENT_KEYS[state.active]].text === "" && state.active > 0;
626
+ const active = moveBack ? clampIndex(state.active - 1) : state.active;
627
+ const key = SEGMENT_KEYS[active];
628
+ const current = state[key];
629
+ const text = key === "period" || current.auto ? "" : current.text.slice(0, -1);
630
+ return { ...withSegment(state, key, segment(text, false)), active };
631
+ };
632
+ const parsePastedTime = (text, step = 1) => {
633
+ const match = text.trim().toLowerCase().match(/^(\d{1,2}):?(\d{2})?\s*([ap])?\.?m?\.?$/);
634
+ if (!match) return null;
635
+ let hours = Number(match[1]);
636
+ const minutes = Number(match[2] ?? 0);
637
+ const period = match[3];
638
+ if (minutes > 59) return null;
639
+ if (period) {
640
+ if (hours < 1 || hours > 12) return null;
641
+ hours = hours % 12 + (period === "p" ? 12 : 0);
642
+ } else if (hours > 23) {
643
+ return null;
644
+ }
645
+ return { hours, minutes: Number(snapMinute(minutes, step)), seconds: 0 };
646
+ };
647
+
648
+ const PLACEHOLDERS = ["hh", "mm", "--"];
649
+ const SegmentedTimeInput = ({
650
+ value,
651
+ minuteStep,
652
+ onChange,
653
+ onErrorChange,
654
+ invalid = false,
655
+ disabled = false,
656
+ autoFocus = false,
657
+ "aria-describedby": ariaDescribedBy
658
+ }) => {
659
+ const { t } = useTranslation();
660
+ const fieldRef = useRef(null);
661
+ const step = minuteStep ?? 1;
662
+ const [time, setTime] = useState(
663
+ () => segmentedTimeFromValue(value, step)
664
+ );
665
+ const lastEmittedRef = useRef(value);
666
+ useEffect(() => {
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]"
737
+ );
738
+ if (segmentEl) {
739
+ event.preventDefault();
740
+ fieldRef.current?.focus();
741
+ update(focusSegment(time, Number(segmentEl.dataset.segment), step));
742
+ return;
743
+ }
744
+ update(focusFirstEmptySegment(time));
745
+ };
746
+ const segmentText = (index) => {
747
+ const { text, done } = time[SEGMENT_KEYS[index]];
748
+ if (!text) return PLACEHOLDERS[index];
749
+ return index < 2 && !done ? `${text}_` : text;
750
+ };
751
+ return /* @__PURE__ */ jsx(
752
+ "div",
753
+ {
754
+ ref: fieldRef,
755
+ role: "group",
756
+ tabIndex: disabled ? -1 : 0,
757
+ "aria-label": t("neetoatoms.datePicker.timeField", "Time"),
758
+ "aria-describedby": ariaDescribedBy,
759
+ "aria-invalid": invalid || void 0,
760
+ "aria-disabled": disabled || void 0,
761
+ "data-testid": "datepicker-time-input",
762
+ className: cn(
763
+ "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",
764
+ "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
765
+ invalid && "border-destructive",
766
+ disabled && "pointer-events-none cursor-not-allowed opacity-50"
767
+ ),
768
+ onBlur: () => update(finishActiveSegment(time, step)),
769
+ onKeyDown: handleKeyDown,
770
+ onMouseDown: handleMouseDown,
771
+ onPaste: handlePaste,
772
+ children: SEGMENT_KEYS.map((key, index) => /* @__PURE__ */ jsxs(React__default.Fragment, { children: [
773
+ index === 1 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "px-0.5 text-muted-foreground", children: ":" }),
774
+ index === 2 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "w-1" }),
775
+ /* @__PURE__ */ jsx(
776
+ "span",
777
+ {
778
+ "data-segment": index,
779
+ "data-testid": `datepicker-time-${key}`,
780
+ className: cn(
781
+ "min-w-[2ch] px-0.5 text-center whitespace-pre",
782
+ !time[key].text && "text-muted-foreground",
783
+ index === time.active && "group-focus/time:shadow-[inset_0_-1.5px_0_var(--color-muted-foreground)]"
784
+ ),
785
+ children: segmentText(index)
786
+ }
787
+ )
788
+ ] }, key))
789
+ }
790
+ );
791
+ };
792
+ SegmentedTimeInput.displayName = "SegmentedTimeInput";
793
+
794
+ const ERROR_DEFAULTS = {
795
+ timeRequired: "Enter a time, or turn off Add time.",
796
+ hourRequired: "Enter an hour.",
797
+ minuteRequired: "Enter minutes.",
798
+ periodRequired: "Type a or p for AM or PM."
799
+ };
800
+ const stepExamples = (step) => {
801
+ const pad = (minutes) => `1:${String(minutes).padStart(2, "0")}`;
802
+ if (step * 2 >= 60) return [pad(0), pad(step)];
803
+ return [pad(step), pad(30 % step === 0 && step < 30 ? 30 : step * 2)];
804
+ };
805
+ const TimeSection = ({
806
+ value,
807
+ minuteStep,
808
+ onChange,
809
+ onErrorChange,
810
+ showError,
811
+ optional,
812
+ hasTime,
813
+ onHasTimeChange,
814
+ timezoneLabel,
815
+ disabled = false,
816
+ className
817
+ }) => {
818
+ const { t } = useTranslation();
819
+ const id = useId();
820
+ const switchId = `datepicker-add-time-${id}`;
821
+ const hintId = `datepicker-time-hint-${id}`;
822
+ const errorId = `datepicker-time-error-${id}`;
823
+ const [error, setError] = useState(null);
824
+ const [focusOnMount, setFocusOnMount] = useState(false);
825
+ const handleErrorChange = useCallback(
826
+ (nextError) => {
827
+ setError(nextError);
828
+ onErrorChange(!!nextError);
829
+ },
830
+ [onErrorChange]
831
+ );
832
+ const handleHasTimeChange = (checked) => {
833
+ setFocusOnMount(checked);
834
+ if (!checked) {
835
+ setError(null);
836
+ onErrorChange(false);
837
+ }
838
+ onHasTimeChange(checked);
839
+ };
840
+ const isTimeOn = !optional || hasTime;
841
+ const showHint = (minuteStep ?? 1) > 1;
842
+ const errorMessage = isTimeOn && showError && error ? t(`neetoatoms.datePicker.errors.${error}`, ERROR_DEFAULTS[error]) : null;
843
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
844
+ optional && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
845
+ /* @__PURE__ */ jsxs(
846
+ Label,
847
+ {
848
+ htmlFor: switchId,
849
+ className: "flex items-center gap-2 font-medium",
850
+ children: [
851
+ /* @__PURE__ */ jsx(Clock, { "aria-hidden": true, className: "size-4 text-muted-foreground" }),
852
+ t("neetoatoms.datePicker.addTime", "Add time")
853
+ ]
854
+ }
855
+ ),
856
+ /* @__PURE__ */ jsx(
857
+ Switch,
858
+ {
859
+ id: switchId,
860
+ checked: hasTime,
861
+ "data-testid": "datepicker-add-time-switch",
862
+ disabled,
863
+ onCheckedChange: handleHasTimeChange
864
+ }
865
+ )
866
+ ] }),
867
+ isTimeOn && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
868
+ /* @__PURE__ */ jsx(
869
+ SegmentedTimeInput,
870
+ {
871
+ "aria-describedby": [showHint ? hintId : null, errorMessage ? errorId : null].filter(Boolean).join(" ") || void 0,
872
+ autoFocus: focusOnMount,
873
+ disabled,
874
+ invalid: !!errorMessage,
875
+ minuteStep,
876
+ value,
877
+ onChange,
878
+ onErrorChange: handleErrorChange
879
+ }
880
+ ),
881
+ showHint && /* @__PURE__ */ jsx(
882
+ "p",
883
+ {
884
+ id: hintId,
885
+ className: "text-xs text-muted-foreground",
886
+ "data-testid": "datepicker-time-hint",
887
+ children: t("neetoatoms.datePicker.timeHint", {
888
+ step: minuteStep,
889
+ first: stepExamples(minuteStep)[0],
890
+ second: stepExamples(minuteStep)[1],
891
+ defaultValue: "Only {{step}}-minute steps are allowed, like {{first}} or {{second}}."
892
+ })
893
+ }
894
+ ),
895
+ errorMessage && /* @__PURE__ */ jsx(
896
+ "p",
897
+ {
898
+ id: errorId,
899
+ className: "text-xs text-destructive",
900
+ "data-testid": "datepicker-time-error",
901
+ role: "alert",
902
+ children: errorMessage
903
+ }
904
+ ),
905
+ timezoneLabel && /* @__PURE__ */ jsxs(
906
+ "p",
907
+ {
908
+ className: "mt-1 flex items-center gap-2 text-xs text-muted-foreground",
909
+ "data-testid": "datepicker-timezone",
910
+ children: [
911
+ /* @__PURE__ */ jsx(Globe, { "aria-hidden": true, className: "size-3.5 shrink-0" }),
912
+ timezoneLabel
913
+ ]
914
+ }
915
+ )
916
+ ] })
917
+ ] });
918
+ };
919
+ TimeSection.displayName = "TimeSection";
920
+
437
921
  const MonthPicker = ({
438
922
  value,
439
923
  displayedYear,
@@ -502,11 +986,12 @@ const RangeCalendar = ({
502
986
  selected,
503
987
  onSelect,
504
988
  disabled,
505
- fromDate,
506
- toDate,
989
+ startMonth,
990
+ endMonth,
507
991
  onHoverIn,
508
992
  onHoverOut,
509
- numberOfMonths = 2
993
+ numberOfMonths = 2,
994
+ className
510
995
  }) => /* @__PURE__ */ jsx("div", { onMouseOver: onHoverIn, onMouseLeave: onHoverOut, children: /* @__PURE__ */ jsx(
511
996
  Calendar$1,
512
997
  {
@@ -515,14 +1000,17 @@ const RangeCalendar = ({
515
1000
  captionLayout: "dropdown",
516
1001
  today: todayDate,
517
1002
  weekStartsOn,
518
- className: "[&_[data-outside][data-selected=true]]:!bg-transparent [&_[data-outside][data-selected=true]]:after:!bg-transparent [&_[data-outside]_button]:!bg-transparent [&_[data-outside]_button]:!text-muted-foreground",
1003
+ className: cn(
1004
+ "[&_[data-outside][data-selected=true]]:!bg-transparent [&_[data-outside][data-selected=true]]:after:!bg-transparent [&_[data-outside]_button]:!bg-transparent [&_[data-outside]_button]:!text-muted-foreground",
1005
+ className
1006
+ ),
519
1007
  month,
520
1008
  onMonthChange,
521
1009
  selected,
522
1010
  onSelect,
523
1011
  disabled,
524
- ...fromDate && { fromDate },
525
- ...toDate && { toDate }
1012
+ startMonth,
1013
+ endMonth
526
1014
  }
527
1015
  ) });
528
1016
 
@@ -689,6 +1177,11 @@ const YearPicker = ({
689
1177
  ] });
690
1178
  };
691
1179
 
1180
+ const TIME_SECTION_CLASS_NAME = "w-0 min-w-full border-t border-border px-3 py-3";
1181
+ const SHOW_TIME_CALENDAR_CLASS_NAME = "[--cell-size:--spacing(8.125)]";
1182
+ const DEFAULT_ADDED_TIME = { hours: 12, minutes: 0, seconds: 0 };
1183
+ const noop = () => {
1184
+ };
692
1185
  const DatePicker = forwardRef(
693
1186
  ({
694
1187
  value,
@@ -699,8 +1192,10 @@ const DatePicker = forwardRef(
699
1192
  dateFormat = DEFAULT_DATE_FORMAT,
700
1193
  timeFormat = DEFAULT_TIME_FORMAT,
701
1194
  showTime = false,
702
- timePickerFormat,
703
- showSeconds = false,
1195
+ showNow = true,
1196
+ minuteStep,
1197
+ timeOptional = true,
1198
+ hasTime: hasTimeProp,
704
1199
  minDate,
705
1200
  maxDate,
706
1201
  disabledDate,
@@ -713,6 +1208,7 @@ const DatePicker = forwardRef(
713
1208
  allowClear = true,
714
1209
  required = false,
715
1210
  timezone,
1211
+ timezoneLabel: timezoneLabelProp,
716
1212
  onTimezoneChange,
717
1213
  onOk,
718
1214
  needConfirm = false,
@@ -747,6 +1243,15 @@ const DatePicker = forwardRef(
747
1243
  const [pendingDate, setPendingDate] = useState(null);
748
1244
  const [pendingTime, setPendingTime] = useState(INITIAL_TIME_VALUE);
749
1245
  const [pendingTimeTo, setPendingTimeTo] = useState(INITIAL_TIME_VALUE);
1246
+ const [hasTimeError, setHasTimeError] = useState(false);
1247
+ const [isTimeErrorRequested, setIsTimeErrorRequested] = useState(false);
1248
+ const isTimeOptional = showTime && timeOptional && type === "date";
1249
+ const [internalHasTime, setInternalHasTime] = useState(
1250
+ () => hasTimeProp ?? (value ?? defaultValue) != null
1251
+ );
1252
+ const committedHasTime = showTime && (!isTimeOptional || (hasTimeProp ?? internalHasTime));
1253
+ const [pendingHasTime, setPendingHasTime] = useState(committedHasTime);
1254
+ const isPendingTimeOn = showTime && (!isTimeOptional || pendingHasTime);
750
1255
  const currentValue = useMemo(
751
1256
  () => value !== void 0 ? coerceDateValue(value, type) : internalValue,
752
1257
  [value, type, internalValue]
@@ -759,10 +1264,13 @@ const DatePicker = forwardRef(
759
1264
  () => toNativeDate(maxDate) ?? void 0,
760
1265
  [maxDate]
761
1266
  );
762
- const displayFormat = getDisplayFormat(dateFormat, timeFormat, showTime);
1267
+ const displayFormat = getDisplayFormat(
1268
+ dateFormat,
1269
+ timeFormat,
1270
+ committedHasTime
1271
+ );
763
1272
  const sizeConfig = SIZE_CONFIG[size];
764
1273
  const maskEnabled = isFixedWidthFormat(displayFormat);
765
- const effectiveTimePickerFormat = timePickerFormat ?? (/\ba\b/i.test(timeFormat) ? "12" : "24");
766
1274
  const defaultPlaceholder = getDatePlaceholder(
767
1275
  dateFormat,
768
1276
  timeFormat,
@@ -799,38 +1307,46 @@ const DatePicker = forwardRef(
799
1307
  return `${from} - ${to}`;
800
1308
  }, [currentValue, displayFormat, type]);
801
1309
  const [inputText, setInputText] = useState(() => getDisplayText());
802
- const commitValue = (date) => {
1310
+ const emitChange = (changed, formatted, withTime) => {
1311
+ if (isTimeOptional) onChange?.(changed, formatted, { hasTime: withTime });
1312
+ else onChange?.(changed, formatted);
1313
+ };
1314
+ const commitValue = (date, withTime = committedHasTime) => {
803
1315
  if (date === null) {
804
1316
  setInternalValue(null);
1317
+ setInternalHasTime(false);
805
1318
  if (type === "range") {
806
- onChange?.([null, null], ["", ""]);
1319
+ emitChange([null, null], ["", ""], false);
807
1320
  } else {
808
- onChange?.(null, "");
1321
+ emitChange(null, "", false);
809
1322
  }
810
1323
  setInputText("");
811
1324
  return;
812
1325
  }
1326
+ const commitFormat = getDisplayFormat(dateFormat, timeFormat, withTime);
813
1327
  const toSerializableDayjs = (d) => {
814
1328
  const userTzDayjs = toUserTzDayjs(d);
815
- if (showTime) return userTzDayjs;
1329
+ if (withTime) return userTzDayjs;
816
1330
  return userTzDayjs.hour(12).minute(0).second(0).millisecond(0);
817
1331
  };
818
1332
  if (Array.isArray(date)) {
819
1333
  setInternalValue(date);
820
1334
  const formatted2 = [
821
- formatDate(date[0], displayFormat),
822
- formatDate(date[1], displayFormat)
1335
+ formatDate(date[0], commitFormat),
1336
+ formatDate(date[1], commitFormat)
823
1337
  ];
824
- onChange?.(
1338
+ emitChange(
825
1339
  [toSerializableDayjs(date[0]), toSerializableDayjs(date[1])],
826
- formatted2
1340
+ formatted2,
1341
+ withTime
827
1342
  );
828
1343
  setInputText(`${formatted2[0]} - ${formatted2[1]}`);
829
1344
  return;
830
1345
  }
831
1346
  setInternalValue(date);
832
- const formatted = formatDate(date, displayFormat);
833
- onChange?.(toSerializableDayjs(date), formatted);
1347
+ setInternalHasTime(withTime);
1348
+ const formatted = formatDate(date, commitFormat);
1349
+ emitChange(toSerializableDayjs(date), formatted, withTime);
834
1350
  setInputText(formatted);
835
1351
  };
836
1352
  const {
@@ -890,30 +1406,33 @@ const DatePicker = forwardRef(
890
1406
  };
891
1407
  const commitPendingOnClose = useCallback(() => {
892
1408
  const hasOkButton = showTime || needConfirm;
893
- if (!hasOkButton || !pendingDate) {
1409
+ if (!hasOkButton || !pendingDate || isPendingTimeOn && hasTimeError) {
894
1410
  setInputText(getDisplayText());
895
1411
  return;
896
1412
  }
897
- const finalDate = showTime ? applyTimeToDate(pendingDate, pendingTime) : pendingDate;
1413
+ const finalDate = isPendingTimeOn ? applyTimeToDate(pendingDate, pendingTime) : pendingDate;
898
1414
  const currentSingle = type === "date" ? currentValue : null;
899
- const isSame = currentSingle && finalDate.getTime() === currentSingle.getTime();
1415
+ const isSame = currentSingle && isPendingTimeOn === committedHasTime && finalDate.getTime() === currentSingle.getTime();
900
1416
  if (isSame) {
901
1417
  setInputText(getDisplayText());
902
1418
  return;
903
1419
  }
904
- commitValue(finalDate);
1420
+ commitValue(finalDate, isPendingTimeOn);
905
1421
  }, [
906
1422
  showTime,
907
1423
  needConfirm,
908
1424
  pendingDate,
909
1425
  pendingTime,
1426
+ isPendingTimeOn,
1427
+ committedHasTime,
910
1428
  type,
911
1429
  currentValue,
912
1430
  getDisplayText,
913
- onChange
1431
+ onChange,
1432
+ hasTimeError
914
1433
  ]);
915
1434
  const closePopover = useCallback(() => {
916
- if (type === "range" && pendingRange?.[0] && pendingRange?.[1]) {
1435
+ if (type === "range" && pendingRange?.[0] && pendingRange?.[1] && !(showTime && hasTimeError)) {
917
1436
  const [fromBase, toBase] = orderRange(
918
1437
  pendingRange[0],
919
1438
  pendingRange[1]
@@ -934,7 +1453,8 @@ const DatePicker = forwardRef(
934
1453
  pendingTime,
935
1454
  pendingTimeTo,
936
1455
  showTime,
937
- resetTransientState
1456
+ resetTransientState,
1457
+ hasTimeError
938
1458
  ]);
939
1459
  useOutsideClickClose({
940
1460
  enabled: open,
@@ -945,6 +1465,7 @@ const DatePicker = forwardRef(
945
1465
  const openPopover = () => {
946
1466
  setOpen(true);
947
1467
  resetTransientState();
1468
+ setIsTimeErrorRequested(false);
948
1469
  if (type === "range") {
949
1470
  const rangeVal = currentValue;
950
1471
  const fromDate = rangeVal?.[0] ?? null;
@@ -957,14 +1478,19 @@ const DatePicker = forwardRef(
957
1478
  return;
958
1479
  }
959
1480
  const dateVal = currentValue;
1481
+ setPendingHasTime(committedHasTime);
960
1482
  if (!dateVal) {
961
1483
  setPendingDate(null);
962
- setPendingTime(INITIAL_TIME_VALUE);
1484
+ setPendingTime(
1485
+ isTimeOptional ? DEFAULT_ADDED_TIME : INITIAL_TIME_VALUE
1486
+ );
963
1487
  return;
964
1488
  }
965
1489
  setCalendarMonth(dateVal);
966
1490
  setPendingDate(dateVal);
967
- setPendingTime(dateToTimeValue(dateVal));
1491
+ setPendingTime(
1492
+ committedHasTime || !isTimeOptional ? dateToTimeValue(dateVal) : DEFAULT_ADDED_TIME
1493
+ );
968
1494
  };
969
1495
  const handleDateSelect = (selected) => {
970
1496
  if (!selected) return;
@@ -977,7 +1503,9 @@ const DatePicker = forwardRef(
977
1503
  setOpen(false);
978
1504
  };
979
1505
  const handleNow = () => {
980
- const now = toBrowserLocalDate(/* @__PURE__ */ new Date());
1506
+ const now = toBrowserLocalDate(
1507
+ showTime && minuteStep ? roundUpToMinuteStep(/* @__PURE__ */ new Date(), minuteStep) : /* @__PURE__ */ new Date()
1508
+ );
981
1509
  if (calendarDisabled(now)) return;
982
1510
  setCalendarMonth(now);
983
1511
  if (type === "range") {
@@ -992,12 +1520,17 @@ const DatePicker = forwardRef(
992
1520
  if (showTime || needConfirm) {
993
1521
  setPendingDate(now);
994
1522
  setPendingTime(dateToTimeValue(now));
1523
+ if (isTimeOptional) setPendingHasTime(true);
995
1524
  return;
996
1525
  }
997
1526
  commitValue(now);
998
1527
  setOpen(false);
999
1528
  };
1000
1529
  const handleOk = () => {
1530
+ if (isPendingTimeOn && hasTimeError) {
1531
+ setIsTimeErrorRequested(true);
1532
+ return;
1533
+ }
1001
1534
  if (type === "range" && (showTime || needConfirm)) {
1002
1535
  const committedRange = currentValue;
1003
1536
  const fromValue = pendingRange?.[0] ?? committedRange?.[0] ?? null;
@@ -1016,7 +1549,7 @@ const DatePicker = forwardRef(
1016
1549
  const [fromBase, toBase] = orderRange(fromValue, toValue);
1017
1550
  const fromFinal = showTime ? applyTimeToDate(fromBase, pendingTime) : fromBase;
1018
1551
  const toFinal = showTime ? applyTimeToDate(toBase, pendingTimeTo) : toBase;
1019
- commitValue([fromFinal, toFinal]);
1552
+ commitValue([fromFinal, toFinal], showTime);
1020
1553
  onOk?.([fromFinal, toFinal]);
1021
1554
  resetTransientState();
1022
1555
  setOpen(false);
@@ -1025,8 +1558,8 @@ const DatePicker = forwardRef(
1025
1558
  return;
1026
1559
  }
1027
1560
  if (pendingDate) {
1028
- const finalDate = showTime ? applyTimeToDate(pendingDate, pendingTime) : pendingDate;
1029
- commitValue(finalDate);
1561
+ const finalDate = isPendingTimeOn ? applyTimeToDate(pendingDate, pendingTime) : pendingDate;
1562
+ commitValue(finalDate, isPendingTimeOn);
1030
1563
  onOk?.(finalDate);
1031
1564
  }
1032
1565
  setOpen(false);
@@ -1081,10 +1614,21 @@ const DatePicker = forwardRef(
1081
1614
  maskEnabled,
1082
1615
  singleDateLen
1083
1616
  );
1084
- if (range) commitValue(range);
1617
+ if (range) {
1618
+ commitValue(
1619
+ showTime && minuteStep ? [
1620
+ roundToMinuteStep(range[0], minuteStep),
1621
+ roundToMinuteStep(range[1], minuteStep)
1622
+ ] : range
1623
+ );
1624
+ }
1085
1625
  } else {
1086
1626
  const parsed = parseDate(inputText, displayFormat);
1087
- if (parsed) commitValue(parsed);
1627
+ if (parsed) {
1628
+ commitValue(
1629
+ committedHasTime && minuteStep ? roundToMinuteStep(parsed, minuteStep) : parsed
1630
+ );
1631
+ }
1088
1632
  }
1089
1633
  setOpen(false);
1090
1634
  };
@@ -1104,10 +1648,32 @@ const DatePicker = forwardRef(
1104
1648
  const dateVal = currentValue;
1105
1649
  if (dateVal instanceof Date) setCalendarMonth(dateVal);
1106
1650
  }, [open]);
1651
+ const timezoneLabel = showTime && !onTimezoneChange ? (timezoneLabelProp ?? getTimezoneLabel(timezone)) || null : null;
1107
1652
  const hasField = !!(label || error || helpText);
1108
1653
  const testIdPrefix = buildTestIdPrefix(dataTestId, label);
1109
1654
  const showFooter = showTime || needConfirm || !!onTimezoneChange;
1110
1655
  const todayDate = toBrowserLocalDate(/* @__PURE__ */ new Date());
1656
+ const handleHasTimeChange = (checked) => {
1657
+ setPendingHasTime(checked);
1658
+ setIsTimeErrorRequested(false);
1659
+ if (!checked) setHasTimeError(false);
1660
+ if (checked && !pendingDate && !calendarDisabled(todayDate)) {
1661
+ setPendingDate(todayDate);
1662
+ setCalendarMonth(todayDate);
1663
+ }
1664
+ };
1665
+ const defaultStartMonth = new Date(
1666
+ todayDate.getFullYear() - CALENDAR_NAVIGATION_YEAR_RANGE,
1667
+ 0,
1668
+ 1
1669
+ );
1670
+ const defaultEndMonth = new Date(
1671
+ todayDate.getFullYear() + CALENDAR_NAVIGATION_YEAR_RANGE,
1672
+ 11,
1673
+ 1
1674
+ );
1675
+ const calendarStartMonth = normalizedMinDate ?? (calendarMonth < defaultStartMonth ? calendarMonth : defaultStartMonth);
1676
+ const calendarEndMonth = normalizedMaxDate ?? (calendarMonth > defaultEndMonth ? calendarMonth : defaultEndMonth);
1111
1677
  const handleGridPickerSelect = (date) => {
1112
1678
  commitValue(date);
1113
1679
  setOpen(false);
@@ -1194,99 +1760,110 @@ const DatePicker = forwardRef(
1194
1760
  onPointerDownOutside: (e) => e.preventDefault(),
1195
1761
  onInteractOutside: (e) => e.preventDefault(),
1196
1762
  children: [
1197
- /* @__PURE__ */ jsxs("div", { className: cn("flex", showTime && "flex-row"), children: [
1198
- type === "date" && picker === "month" ? /* @__PURE__ */ jsx(
1199
- MonthPicker,
1200
- {
1201
- value: currentValue ?? null,
1202
- displayedYear: calendarMonth.getFullYear(),
1203
- onYearChange: (year) => setCalendarMonth(
1204
- new Date(year, calendarMonth.getMonth(), 1)
1205
- ),
1206
- onSelect: handleGridPickerSelect,
1207
- isDisabled: (date) => isMonthDisabled(date, normalizedMinDate, normalizedMaxDate)
1208
- }
1209
- ) : type === "date" && picker === "year" ? /* @__PURE__ */ jsx(
1210
- YearPicker,
1211
- {
1212
- value: currentValue ?? null,
1213
- displayedYear: calendarMonth.getFullYear(),
1214
- onYearChange: (year) => setCalendarMonth(new Date(year, 0, 1)),
1215
- onSelect: handleGridPickerSelect,
1216
- isDisabled: (date) => isYearDisabled(date, normalizedMinDate, normalizedMaxDate)
1217
- }
1218
- ) : type === "date" ? /* @__PURE__ */ jsx(
1219
- Calendar$1,
1220
- {
1221
- mode: "single",
1222
- captionLayout: "dropdown",
1223
- today: todayDate,
1224
- month: calendarMonth,
1225
- onMonthChange: setCalendarMonth,
1226
- selected: calendarSelected(),
1227
- onSelect: handleSingleDateSelectWithPicker,
1228
- disabled: calendarDisabled,
1229
- weekStartsOn,
1230
- classNames: weekRowHoverClassName ? { week: cn("mt-2 flex w-full", weekRowHoverClassName) } : void 0,
1231
- ...weekHighlightProps,
1232
- ...normalizedMinDate && { fromDate: normalizedMinDate },
1233
- ...normalizedMaxDate && { toDate: normalizedMaxDate }
1234
- }
1235
- ) : showTime ? /* @__PURE__ */ jsxs(Fragment, { children: [
1236
- /* @__PURE__ */ jsx(
1237
- RangeCalendar,
1238
- {
1239
- todayDate,
1240
- weekStartsOn,
1241
- month: calendarMonth,
1242
- onMonthChange: setCalendarMonth,
1243
- selected: memoizedRangeSelected,
1244
- onSelect: handleRangeSelect,
1245
- disabled: calendarDisabled,
1246
- fromDate: normalizedMinDate,
1247
- toDate: normalizedMaxDate,
1248
- onHoverIn: handleHoverIn,
1249
- onHoverOut: handleHoverOut,
1250
- numberOfMonths: 1
1251
- }
1763
+ /* @__PURE__ */ jsx("div", { className: "flex", children: type === "date" && picker === "month" ? /* @__PURE__ */ jsx(
1764
+ MonthPicker,
1765
+ {
1766
+ value: currentValue ?? null,
1767
+ displayedYear: calendarMonth.getFullYear(),
1768
+ onYearChange: (year) => setCalendarMonth(
1769
+ new Date(year, calendarMonth.getMonth(), 1)
1252
1770
  ),
1253
- /* @__PURE__ */ jsx("div", { className: "border-inline-start border-border pt-2", children: /* @__PURE__ */ jsx(
1254
- TimePickerPanel,
1255
- {
1256
- value: rangeSelectionStep === "from" ? pendingTime : pendingTimeTo,
1257
- onChange: rangeSelectionStep === "from" ? setPendingTime : setPendingTimeTo,
1258
- format: effectiveTimePickerFormat,
1259
- showSeconds,
1260
- disabled
1261
- }
1262
- ) })
1263
- ] }) : /* @__PURE__ */ jsx(
1264
- RangeCalendar,
1265
- {
1266
- todayDate,
1267
- weekStartsOn,
1268
- month: calendarMonth,
1269
- onMonthChange: setCalendarMonth,
1270
- selected: memoizedRangeSelected,
1271
- onSelect: handleRangeSelect,
1272
- disabled: calendarDisabled,
1273
- fromDate: normalizedMinDate,
1274
- toDate: normalizedMaxDate,
1275
- onHoverIn: handleHoverIn,
1276
- onHoverOut: handleHoverOut
1277
- }
1278
- ),
1279
- showTime && type !== "range" && /* @__PURE__ */ jsx("div", { className: "border-inline-start border-border", children: /* @__PURE__ */ jsx(
1280
- TimePickerPanel,
1281
- {
1282
- value: pendingTime,
1283
- onChange: setPendingTime,
1284
- format: effectiveTimePickerFormat,
1285
- showSeconds,
1286
- disabled
1287
- }
1288
- ) })
1289
- ] }),
1771
+ onSelect: handleGridPickerSelect,
1772
+ isDisabled: (date) => isMonthDisabled(date, normalizedMinDate, normalizedMaxDate)
1773
+ }
1774
+ ) : type === "date" && picker === "year" ? /* @__PURE__ */ jsx(
1775
+ YearPicker,
1776
+ {
1777
+ value: currentValue ?? null,
1778
+ displayedYear: calendarMonth.getFullYear(),
1779
+ onYearChange: (year) => setCalendarMonth(new Date(year, 0, 1)),
1780
+ onSelect: handleGridPickerSelect,
1781
+ isDisabled: (date) => isYearDisabled(date, normalizedMinDate, normalizedMaxDate)
1782
+ }
1783
+ ) : type === "date" ? /* @__PURE__ */ jsx(
1784
+ Calendar$1,
1785
+ {
1786
+ className: cn(showTime && SHOW_TIME_CALENDAR_CLASS_NAME),
1787
+ mode: "single",
1788
+ captionLayout: "dropdown",
1789
+ today: todayDate,
1790
+ month: calendarMonth,
1791
+ onMonthChange: setCalendarMonth,
1792
+ selected: calendarSelected(),
1793
+ onSelect: handleSingleDateSelectWithPicker,
1794
+ disabled: calendarDisabled,
1795
+ weekStartsOn,
1796
+ classNames: weekRowHoverClassName ? { week: cn("mt-2 flex w-full", weekRowHoverClassName) } : void 0,
1797
+ ...weekHighlightProps,
1798
+ startMonth: calendarStartMonth,
1799
+ endMonth: calendarEndMonth
1800
+ }
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
+ ) : /* @__PURE__ */ jsx(
1819
+ RangeCalendar,
1820
+ {
1821
+ todayDate,
1822
+ weekStartsOn,
1823
+ month: calendarMonth,
1824
+ onMonthChange: setCalendarMonth,
1825
+ selected: memoizedRangeSelected,
1826
+ onSelect: handleRangeSelect,
1827
+ disabled: calendarDisabled,
1828
+ startMonth: calendarStartMonth,
1829
+ endMonth: calendarEndMonth,
1830
+ onHoverIn: handleHoverIn,
1831
+ onHoverOut: handleHoverOut
1832
+ }
1833
+ ) }),
1834
+ showTime && type === "range" && /* @__PURE__ */ jsx(
1835
+ TimeSection,
1836
+ {
1837
+ className: TIME_SECTION_CLASS_NAME,
1838
+ disabled,
1839
+ hasTime: true,
1840
+ optional: false,
1841
+ showError: isTimeErrorRequested,
1842
+ timezoneLabel,
1843
+ value: rangeSelectionStep === "from" ? pendingTime : pendingTimeTo,
1844
+ onChange: rangeSelectionStep === "from" ? setPendingTime : setPendingTimeTo,
1845
+ minuteStep,
1846
+ onErrorChange: setHasTimeError,
1847
+ onHasTimeChange: noop
1848
+ },
1849
+ rangeSelectionStep
1850
+ ),
1851
+ showTime && type !== "range" && /* @__PURE__ */ jsx(
1852
+ TimeSection,
1853
+ {
1854
+ className: TIME_SECTION_CLASS_NAME,
1855
+ disabled,
1856
+ hasTime: pendingHasTime,
1857
+ optional: isTimeOptional,
1858
+ showError: isTimeErrorRequested,
1859
+ timezoneLabel,
1860
+ value: pendingTime,
1861
+ onChange: setPendingTime,
1862
+ minuteStep,
1863
+ onErrorChange: setHasTimeError,
1864
+ onHasTimeChange: handleHasTimeChange
1865
+ }
1866
+ ),
1290
1867
  showFooter && /* @__PURE__ */ jsx(
1291
1868
  DatePickerFooter,
1292
1869
  {
@@ -1295,6 +1872,7 @@ const DatePicker = forwardRef(
1295
1872
  timezone,
1296
1873
  onTimezoneChange,
1297
1874
  nowDisabled: calendarDisabled(todayDate),
1875
+ showNow,
1298
1876
  onNow: handleNow,
1299
1877
  onOk: handleOk,
1300
1878
  okLabel: type === "range" && (showTime || needConfirm) && rangeSelectionStep === "from" ? "Next" : "OK"
@@ -1331,4 +1909,4 @@ const DatePicker = forwardRef(
1331
1909
  DatePicker.displayName = "DatePicker";
1332
1910
 
1333
1911
  export { DatePicker as D };
1334
- //# sourceMappingURL=DatePicker-edLgTark.js.map
1912
+ //# sourceMappingURL=DatePicker-BC9AOZJ2.js.map