@bigbinary/neeto-atoms 1.0.59 → 1.0.61

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 (85) hide show
  1. package/dist/{DataTable-BTdSpJfs.js → DataTable-DP06B8C7.js} +140 -124
  2. package/dist/{DataTable-BTdSpJfs.js.map → DataTable-DP06B8C7.js.map} +1 -1
  3. package/dist/{DatePicker-kulToqfM.js → DatePicker-mdjh5u40.js} +422 -157
  4. package/dist/DatePicker-mdjh5u40.js.map +1 -0
  5. package/dist/{Input-Bxs8n6xp.js → Input-B7twzkUr.js} +5 -3
  6. package/dist/Input-B7twzkUr.js.map +1 -0
  7. package/dist/{Pagination-C_X9kgc8.js → Pagination-BRd3WPJ_.js} +15 -4
  8. package/dist/Pagination-BRd3WPJ_.js.map +1 -0
  9. package/dist/{Select-BiyQTuiQ.js → Select-Zr8sFnAC.js} +46 -14
  10. package/dist/Select-Zr8sFnAC.js.map +1 -0
  11. package/dist/cjs/{DataTable-CCIIXb4B.js → DataTable-CXjAvPHV.js} +140 -124
  12. package/dist/cjs/{DataTable-CCIIXb4B.js.map → DataTable-CXjAvPHV.js.map} +1 -1
  13. package/dist/cjs/{DatePicker-BZd4rM2R.js → DatePicker-DpyYPJfR.js} +420 -155
  14. package/dist/cjs/DatePicker-DpyYPJfR.js.map +1 -0
  15. package/dist/cjs/{Input-BQh-GS_w.js → Input-Dwl5OhCq.js} +5 -3
  16. package/dist/cjs/Input-Dwl5OhCq.js.map +1 -0
  17. package/dist/cjs/{Pagination-DeWfLAq5.js → Pagination-8yFg8xR2.js} +15 -4
  18. package/dist/cjs/Pagination-8yFg8xR2.js.map +1 -0
  19. package/dist/cjs/{Select-DC23xcMU.js → Select-BJs-J8fs.js} +45 -13
  20. package/dist/cjs/Select-BJs-J8fs.js.map +1 -0
  21. package/dist/cjs/components/DataTable.js +1 -1
  22. package/dist/cjs/components/DatePicker.js +9 -9
  23. package/dist/cjs/components/Input.js +1 -1
  24. package/dist/cjs/components/Pagination.js +2 -1
  25. package/dist/cjs/components/Pagination.js.map +1 -1
  26. package/dist/cjs/components/Select.js +2 -2
  27. package/dist/cjs/components/index.js +15 -15
  28. package/dist/cjs/formik/ActionBlock.js +10 -4
  29. package/dist/cjs/formik/ActionBlock.js.map +1 -1
  30. package/dist/cjs/formik/Input.js +1 -1
  31. package/dist/cjs/formik/Select.js +2 -2
  32. package/dist/cjs/formik/index.js +3 -3
  33. package/dist/cjs/index.js +15 -15
  34. package/dist/cjs/primitives/Checkbox.js +1 -1
  35. package/dist/cjs/primitives/Checkbox.js.map +1 -1
  36. package/dist/cjs/primitives/Combobox.js +14 -2
  37. package/dist/cjs/primitives/Combobox.js.map +1 -1
  38. package/dist/cjs/primitives/RadioGroup.js +1 -1
  39. package/dist/cjs/primitives/RadioGroup.js.map +1 -1
  40. package/dist/components/DataTable/DataTable.d.ts +1 -1
  41. package/dist/components/DataTable/types.d.ts +1 -0
  42. package/dist/components/DataTable.js +1 -1
  43. package/dist/components/DatePicker/DatePickerField.d.ts +15 -0
  44. package/dist/components/DatePicker/DatePickerTrigger.d.ts +25 -0
  45. package/dist/components/DatePicker/RangeCalendar.d.ts +17 -0
  46. package/dist/components/DatePicker/types.d.ts +3 -3
  47. package/dist/components/DatePicker/useRangePicker.d.ts +28 -0
  48. package/dist/components/DatePicker/utils.d.ts +15 -0
  49. package/dist/components/DatePicker.js +9 -9
  50. package/dist/components/Input.js +1 -1
  51. package/dist/components/Pagination/Pagination.d.ts +5 -1
  52. package/dist/components/Pagination/hooks/usePaginationQueryParams.d.ts +11 -0
  53. package/dist/components/Pagination.js +2 -1
  54. package/dist/components/Pagination.js.map +1 -1
  55. package/dist/components/Select/MultiSelectCombobox.types.d.ts +1 -0
  56. package/dist/components/Select/MultiSelectDropdown.d.ts +2 -2
  57. package/dist/components/Select/OptionItem.d.ts +3 -2
  58. package/dist/components/Select/SelectCombobox.types.d.ts +2 -0
  59. package/dist/components/Select/hooks/useMultiSelectState.d.ts +3 -1
  60. package/dist/components/Select/hooks/useSelectState.d.ts +3 -1
  61. package/dist/components/Select/types.d.ts +7 -0
  62. package/dist/components/Select.js +2 -2
  63. package/dist/components/index.js +5 -5
  64. package/dist/formik/ActionBlock.js +10 -4
  65. package/dist/formik/ActionBlock.js.map +1 -1
  66. package/dist/formik/Input.js +1 -1
  67. package/dist/formik/Select.js +2 -2
  68. package/dist/formik/index.js +3 -3
  69. package/dist/index.js +5 -5
  70. package/dist/primitives/Checkbox.js +1 -1
  71. package/dist/primitives/Checkbox.js.map +1 -1
  72. package/dist/primitives/Combobox.d.ts +1 -1
  73. package/dist/primitives/Combobox.js +14 -2
  74. package/dist/primitives/Combobox.js.map +1 -1
  75. package/dist/primitives/RadioGroup.js +1 -1
  76. package/dist/primitives/RadioGroup.js.map +1 -1
  77. package/package.json +1 -1
  78. package/dist/DatePicker-kulToqfM.js.map +0 -1
  79. package/dist/Input-Bxs8n6xp.js.map +0 -1
  80. package/dist/Pagination-C_X9kgc8.js.map +0 -1
  81. package/dist/Select-BiyQTuiQ.js.map +0 -1
  82. package/dist/cjs/DatePicker-BZd4rM2R.js.map +0 -1
  83. package/dist/cjs/Input-BQh-GS_w.js.map +0 -1
  84. package/dist/cjs/Pagination-DeWfLAq5.js.map +0 -1
  85. package/dist/cjs/Select-DC23xcMU.js.map +0 -1
@@ -4,17 +4,17 @@ var jsxRuntime = require('react/jsx-runtime');
4
4
  var React = require('react');
5
5
  var primitives_Calendar = require('./primitives/Calendar.js');
6
6
  var primitives_Popover = require('./primitives/Popover.js');
7
- var primitives_Field = require('./primitives/Field.js');
8
7
  var utils$1 = require('./utils-BhM0B89p.js');
9
8
  var TimePickerPanel = require('./TimePickerPanel-DX6cjrSN.js');
10
9
  var pureDayjs = require('dayjs');
11
10
  var customParseFormat = require('dayjs/plugin/customParseFormat');
12
11
  var utils = require('@bigbinary/neeto-commons-frontend/utils');
13
12
  var primitives_Button = require('./primitives/Button.js');
14
- var chevronLeft = require('./chevron-left-BldoOh5p.js');
15
- var chevronRight = require('./chevron-right-0jNdwX2Q.js');
13
+ var primitives_Field = require('./primitives/Field.js');
16
14
  var createLucideIcon = require('./createLucideIcon-D0tRgV6l.js');
17
15
  var x = require('./x-Brw3FJst.js');
16
+ var chevronLeft = require('./chevron-left-BldoOh5p.js');
17
+ var chevronRight = require('./chevron-right-0jNdwX2Q.js');
18
18
 
19
19
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
20
20
 
@@ -93,6 +93,12 @@ const coerceDateValue = (value, type) => {
93
93
  }
94
94
  return toNativeDate(value);
95
95
  };
96
+ const getInitialCalendarMonth = (value, defaultValue, type) => {
97
+ const initial = coerceDateValue(value ?? defaultValue, type);
98
+ if (initial instanceof Date) return initial;
99
+ if (Array.isArray(initial) && initial[0] instanceof Date) return initial[0];
100
+ return /* @__PURE__ */ new Date();
101
+ };
96
102
  const normalizeToDayjsFormat = (fmt) => fmt.replace(/\byyyy\b/g, "YYYY").replace(/\byy\b/g, "YY").replace(/\bdd\b/g, "DD").replace(/\bd\b/g, "D");
97
103
  const normalizeToDateFnsFormat = (fmt) => fmt.replace(/YYYY/g, "yyyy").replace(/YY/g, "yy").replace(/DD/g, "dd").replace(/\bD\b/g, "d");
98
104
  const formatDate = (date, formatStr) => {
@@ -128,11 +134,7 @@ const applyTimeToDate = (date, time) => {
128
134
  result.setHours(time.hours, time.minutes, time.seconds ?? 0, 0);
129
135
  return result;
130
136
  };
131
- const applyTimezone = (date) => {
132
- const dateStr = pureDayjs__default.default(date).format("YYYY-MM-DD HH:mm:ss");
133
- return utils.dayjs(dateStr).toDate();
134
- };
135
- const toDayjs = (date) => utils.dayjs(date);
137
+ const toUserTzDayjs = (date) => utils.dayjs(pureDayjs__default.default(date).format("YYYY-MM-DD HH:mm:ss"));
136
138
  const getDisplayFormat = (dateFormat, timeFormat, showTime) => {
137
139
  const fmt = showTime ? `${dateFormat} ${timeFormat}` : dateFormat;
138
140
  return normalizeToDateFnsFormat(fmt);
@@ -187,6 +189,34 @@ const isYearDisabled = (yearDate, minDate, maxDate) => {
187
189
  };
188
190
  const buildMonth = (year, month) => new Date(year, month, 1);
189
191
  const isSameMonth = (a, b) => !!a && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
192
+ const isSameDay = (a, b) => !!a && !!b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
193
+ const orderRange = (from, to) => {
194
+ if (from && to && from.getTime() > to.getTime()) return [to, from];
195
+ return [from, to];
196
+ };
197
+ const parseGridcellDay = (target) => {
198
+ const el = target;
199
+ const cell = el?.closest('[role="gridcell"][data-day]');
200
+ const dayAttr = cell?.getAttribute("data-day");
201
+ if (!dayAttr) return null;
202
+ const parsed = new Date(dayAttr);
203
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
204
+ };
205
+ const computeRangePreview = ({
206
+ pendingRange,
207
+ committed,
208
+ hoveredDate,
209
+ rangeStep
210
+ }) => {
211
+ let from = pendingRange ? pendingRange[0] : committed?.[0] ?? null;
212
+ let to = pendingRange ? pendingRange[1] : committed?.[1] ?? null;
213
+ if (hoveredDate) {
214
+ if (rangeStep === "from") from = hoveredDate;
215
+ else if (!isSameDay(from, hoveredDate)) to = hoveredDate;
216
+ }
217
+ [from, to] = orderRange(from, to);
218
+ return { from, to };
219
+ };
190
220
  const decadeStartFor = (year) => Math.floor(year / 10) * 10;
191
221
 
192
222
  const TIMEZONE_OPTIONS = [
@@ -250,6 +280,136 @@ const DatePickerFooter = ({
250
280
  };
251
281
  DatePickerFooter.displayName = "DatePickerFooter";
252
282
 
283
+ const DatePickerField = React.forwardRef(
284
+ ({
285
+ disabled,
286
+ error,
287
+ className,
288
+ label,
289
+ required,
290
+ helpText,
291
+ labelProps,
292
+ errorId,
293
+ helpTextId,
294
+ children
295
+ }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
296
+ primitives_Field.Field,
297
+ {
298
+ ref,
299
+ "data-disabled": disabled || void 0,
300
+ "data-invalid": !!error || void 0,
301
+ className,
302
+ children: [
303
+ label && /* @__PURE__ */ jsxRuntime.jsxs(
304
+ primitives_Field.FieldLabel,
305
+ {
306
+ ...labelProps,
307
+ children: [
308
+ label,
309
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "text-destructive", children: "*" })
310
+ ]
311
+ }
312
+ ),
313
+ /* @__PURE__ */ jsxRuntime.jsxs(primitives_Field.FieldContent, { children: [
314
+ children,
315
+ !!error && /* @__PURE__ */ jsxRuntime.jsx(primitives_Field.FieldError, { id: errorId, children: error }),
316
+ helpText && /* @__PURE__ */ jsxRuntime.jsx(primitives_Field.FieldDescription, { id: helpTextId, children: helpText })
317
+ ] })
318
+ ]
319
+ }
320
+ )
321
+ );
322
+ DatePickerField.displayName = "DatePickerField";
323
+
324
+ const DatePickerTrigger = React.forwardRef(
325
+ ({
326
+ containerRef,
327
+ inputRef,
328
+ disabled,
329
+ error,
330
+ hasField,
331
+ className,
332
+ triggerSizeClass,
333
+ inputSizeClass,
334
+ iconSizeClass,
335
+ label,
336
+ ariaDescribedBy,
337
+ placeholder,
338
+ inputText,
339
+ allowClear,
340
+ timezone,
341
+ onInputChange,
342
+ onInputKeyDown,
343
+ onInputFocus,
344
+ onInputBlur,
345
+ onClear
346
+ }, _ref) => /* @__PURE__ */ jsxRuntime.jsx(primitives_Popover.PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
347
+ "div",
348
+ {
349
+ ref: containerRef,
350
+ className: utils$1.cn(
351
+ "relative flex w-full cursor-text items-center gap-2 rounded-md border border-input bg-background pe-8 ps-3",
352
+ "focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
353
+ disabled && "cursor-not-allowed opacity-50",
354
+ !!error && "border-destructive ring-destructive/20 ring-3",
355
+ triggerSizeClass,
356
+ !hasField && className
357
+ ),
358
+ onClick: () => {
359
+ if (disabled) return;
360
+ inputRef.current?.focus();
361
+ },
362
+ children: [
363
+ /* @__PURE__ */ jsxRuntime.jsx(
364
+ Calendar,
365
+ {
366
+ className: utils$1.cn("shrink-0 text-muted-foreground", iconSizeClass)
367
+ }
368
+ ),
369
+ /* @__PURE__ */ jsxRuntime.jsx(
370
+ "input",
371
+ {
372
+ ref: inputRef,
373
+ type: "text",
374
+ disabled,
375
+ "aria-label": label || "Pick a date",
376
+ "aria-describedby": ariaDescribedBy,
377
+ "aria-invalid": !!error || void 0,
378
+ placeholder,
379
+ value: inputText,
380
+ onChange: onInputChange,
381
+ onKeyDown: onInputKeyDown,
382
+ onFocus: onInputFocus,
383
+ onBlur: onInputBlur,
384
+ className: utils$1.cn(
385
+ "min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground",
386
+ "disabled:cursor-not-allowed",
387
+ inputSizeClass
388
+ )
389
+ }
390
+ ),
391
+ timezone && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground", children: timezone.toUpperCase() }),
392
+ allowClear && /* @__PURE__ */ jsxRuntime.jsx(
393
+ "button",
394
+ {
395
+ type: "button",
396
+ onPointerDown: (e) => e.preventDefault(),
397
+ onClick: onClear,
398
+ className: utils$1.cn(
399
+ "absolute inset-y-0 end-2 flex items-center text-muted-foreground hover:text-foreground focus:outline-none",
400
+ !(inputText && !disabled) && "invisible"
401
+ ),
402
+ "aria-label": "Clear date",
403
+ tabIndex: -1,
404
+ children: /* @__PURE__ */ jsxRuntime.jsx(x.X, { className: iconSizeClass })
405
+ }
406
+ )
407
+ ]
408
+ }
409
+ ) })
410
+ );
411
+ DatePickerTrigger.displayName = "DatePickerTrigger";
412
+
253
413
  const MonthPicker = ({
254
414
  value,
255
415
  displayedYear,
@@ -310,6 +470,129 @@ const MonthPicker = ({
310
470
  ] });
311
471
  };
312
472
 
473
+ const RangeCalendar = ({
474
+ todayDate,
475
+ weekStartsOn,
476
+ month,
477
+ onMonthChange,
478
+ selected,
479
+ onSelect,
480
+ disabled,
481
+ fromDate,
482
+ toDate,
483
+ onHoverIn,
484
+ onHoverOut
485
+ }) => /* @__PURE__ */ jsxRuntime.jsx("div", { onMouseOver: onHoverIn, onMouseLeave: onHoverOut, children: /* @__PURE__ */ jsxRuntime.jsx(
486
+ primitives_Calendar.Calendar,
487
+ {
488
+ mode: "range",
489
+ numberOfMonths: 2,
490
+ captionLayout: "dropdown",
491
+ today: todayDate,
492
+ weekStartsOn,
493
+ 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",
494
+ month,
495
+ onMonthChange,
496
+ selected,
497
+ onSelect,
498
+ disabled,
499
+ ...fromDate && { fromDate },
500
+ ...toDate && { toDate }
501
+ }
502
+ ) });
503
+
504
+ const useRangePicker = ({
505
+ currentValue,
506
+ showTime,
507
+ needConfirm,
508
+ commitValue,
509
+ setPendingDate,
510
+ setOpen
511
+ }) => {
512
+ const [pendingRange, setPendingRange] = React.useState(null);
513
+ const [rangeSelectionStep, setRangeSelectionStep] = React.useState(
514
+ "from"
515
+ );
516
+ const [hoveredDate, setHoveredDate] = React.useState(null);
517
+ const committed = currentValue ?? null;
518
+ const resetTransientState = React.useCallback(() => {
519
+ setPendingRange(null);
520
+ setRangeSelectionStep("from");
521
+ setHoveredDate(null);
522
+ }, []);
523
+ const handleRangeSelect = React.useCallback(
524
+ (_range, triggerDate) => {
525
+ if (!triggerDate) return;
526
+ if (rangeSelectionStep === "from" || !pendingRange?.[0]) {
527
+ const existingTo = pendingRange?.[1] ?? committed?.[1] ?? null;
528
+ const nextTo = existingTo && triggerDate <= existingTo ? existingTo : null;
529
+ setPendingRange([triggerDate, nextTo]);
530
+ setRangeSelectionStep("to");
531
+ return;
532
+ }
533
+ const [from, to] = orderRange(pendingRange[0], triggerDate);
534
+ setRangeSelectionStep("from");
535
+ setPendingRange(null);
536
+ if (showTime || needConfirm) {
537
+ setPendingDate(from);
538
+ return;
539
+ }
540
+ commitValue([from, to]);
541
+ setOpen(false);
542
+ },
543
+ [
544
+ rangeSelectionStep,
545
+ pendingRange,
546
+ committed,
547
+ showTime,
548
+ needConfirm,
549
+ commitValue,
550
+ setPendingDate,
551
+ setOpen
552
+ ]
553
+ );
554
+ const handleHoverIn = React.useCallback(
555
+ (e) => {
556
+ const parsed = parseGridcellDay(e.target);
557
+ if (!parsed) return;
558
+ if (hoveredDate && hoveredDate.getTime() === parsed.getTime()) return;
559
+ setHoveredDate(parsed);
560
+ },
561
+ [hoveredDate]
562
+ );
563
+ const handleHoverOut = React.useCallback(() => setHoveredDate(null), []);
564
+ const memoizedRangeSelected = React.useMemo(() => {
565
+ const { from, to } = computeRangePreview({
566
+ pendingRange,
567
+ committed,
568
+ hoveredDate,
569
+ rangeStep: rangeSelectionStep
570
+ });
571
+ if (!from && !to) return void 0;
572
+ return { from: from ?? void 0, to: to ?? void 0 };
573
+ }, [pendingRange, committed, hoveredDate, rangeSelectionStep]);
574
+ const getPreviewParts = React.useCallback(
575
+ () => computeRangePreview({
576
+ pendingRange,
577
+ committed,
578
+ hoveredDate,
579
+ rangeStep: rangeSelectionStep
580
+ }),
581
+ [pendingRange, committed, hoveredDate, rangeSelectionStep]
582
+ );
583
+ return {
584
+ pendingRange,
585
+ rangeSelectionStep,
586
+ hoveredDate,
587
+ handleRangeSelect,
588
+ handleHoverIn,
589
+ handleHoverOut,
590
+ memoizedRangeSelected,
591
+ getPreviewParts,
592
+ resetTransientState
593
+ };
594
+ };
595
+
313
596
  const YearPicker = ({
314
597
  value,
315
598
  displayedYear,
@@ -425,14 +708,22 @@ const DatePicker = React.forwardRef(
425
708
  coerceDateValue(defaultValue, type) ?? null
426
709
  );
427
710
  const [calendarMonth, setCalendarMonth] = React.useState(
428
- (type === "date" ? value ?? defaultValue : null) ?? /* @__PURE__ */ new Date()
429
- );
430
- const [rangeSelectionStep, setRangeSelectionStep] = React.useState(
431
- "from"
711
+ () => getInitialCalendarMonth(value, defaultValue, type)
432
712
  );
433
713
  const [pendingDate, setPendingDate] = React.useState(null);
434
714
  const [pendingTime, setPendingTime] = React.useState(INITIAL_TIME_VALUE);
435
- const currentValue = value !== void 0 ? coerceDateValue(value, type) : internalValue;
715
+ const currentValue = React.useMemo(
716
+ () => value !== void 0 ? coerceDateValue(value, type) : internalValue,
717
+ [value, type, internalValue]
718
+ );
719
+ const normalizedMinDate = React.useMemo(
720
+ () => toNativeDate(minDate) ?? void 0,
721
+ [minDate]
722
+ );
723
+ const normalizedMaxDate = React.useMemo(
724
+ () => toNativeDate(maxDate) ?? void 0,
725
+ [maxDate]
726
+ );
436
727
  const displayFormat = getDisplayFormat(dateFormat, timeFormat, showTime);
437
728
  const sizeConfig = SIZE_CONFIG[size];
438
729
  const maskEnabled = TimePickerPanel.isFixedWidthFormat(displayFormat);
@@ -453,13 +744,13 @@ const DatePicker = React.forwardRef(
453
744
  const calendarDisabled = React.useCallback(
454
745
  (date) => {
455
746
  if (disabledDate?.(date)) return true;
456
- if (minDate && date < new Date(new Date(minDate).setHours(0, 0, 0, 0)))
747
+ if (normalizedMinDate && date < new Date(new Date(normalizedMinDate).setHours(0, 0, 0, 0)))
457
748
  return true;
458
- if (maxDate && date > new Date(new Date(maxDate).setHours(23, 59, 59, 999)))
749
+ if (normalizedMaxDate && date > new Date(new Date(normalizedMaxDate).setHours(23, 59, 59, 999)))
459
750
  return true;
460
751
  return false;
461
752
  },
462
- [minDate, maxDate, disabledDate]
753
+ [normalizedMinDate, normalizedMaxDate, disabledDate]
463
754
  );
464
755
  const getDisplayText = React.useCallback(() => {
465
756
  if (type !== "range") {
@@ -475,36 +766,73 @@ const DatePicker = React.forwardRef(
475
766
  const commitValue = (date) => {
476
767
  if (date === null) {
477
768
  setInternalValue(null);
478
- onChange?.(null, "");
769
+ if (type === "range") {
770
+ onChange?.([null, null], ["", ""]);
771
+ } else {
772
+ onChange?.(null, "");
773
+ }
479
774
  setInputText("");
480
775
  return;
481
776
  }
777
+ const toSerializableDayjs = (d) => {
778
+ const userTzDayjs = toUserTzDayjs(d);
779
+ if (showTime) return userTzDayjs;
780
+ return userTzDayjs.hour(12).minute(0).second(0).millisecond(0);
781
+ };
482
782
  if (Array.isArray(date)) {
483
783
  setInternalValue(date);
484
- const converted2 = [
485
- applyTimezone(date[0]),
486
- applyTimezone(date[1])
487
- ];
488
784
  const formatted2 = [
489
785
  formatDate(date[0], displayFormat),
490
786
  formatDate(date[1], displayFormat)
491
787
  ];
492
- onChange?.([toDayjs(converted2[0]), toDayjs(converted2[1])], formatted2);
788
+ onChange?.(
789
+ [toSerializableDayjs(date[0]), toSerializableDayjs(date[1])],
790
+ formatted2
791
+ );
493
792
  setInputText(`${formatted2[0]} - ${formatted2[1]}`);
494
793
  return;
495
794
  }
496
795
  setInternalValue(date);
497
- const converted = applyTimezone(date);
498
796
  const formatted = formatDate(date, displayFormat);
499
- onChange?.(toDayjs(converted), formatted);
797
+ onChange?.(toSerializableDayjs(date), formatted);
500
798
  setInputText(formatted);
501
799
  };
502
- const parseAndApplyRange = (text) => {
800
+ const {
801
+ pendingRange,
802
+ handleRangeSelect,
803
+ handleHoverIn,
804
+ handleHoverOut,
805
+ memoizedRangeSelected,
806
+ getPreviewParts,
807
+ resetTransientState
808
+ } = useRangePicker({
809
+ currentValue,
810
+ showTime,
811
+ needConfirm,
812
+ commitValue,
813
+ setPendingDate,
814
+ setOpen
815
+ });
816
+ React.useEffect(() => {
817
+ if (type !== "range" || !open) return;
818
+ const { from, to } = getPreviewParts();
819
+ const fromText = from ? formatDate(from, displayFormat) : "";
820
+ const toText = to ? formatDate(to, displayFormat) : "";
821
+ setInputText(fromText || toText ? `${fromText} - ${toText}` : "");
822
+ }, [type, open, getPreviewParts, displayFormat]);
823
+ const parseAndApplyRange = (text, cursorPos) => {
503
824
  const parts = text.split(" - ");
504
- if (!isDatePartComplete(parts[0] ?? "", maskEnabled, singleDateLen))
505
- return;
506
- const from = parseDate(parts[0], displayFormat);
507
- if (from) setCalendarMonth(from);
825
+ const separatorIdx = text.indexOf(" - ");
826
+ const editingTo = separatorIdx >= 0 && cursorPos !== null && cursorPos > separatorIdx + 2;
827
+ if (editingTo) {
828
+ const to = parseDate(parts[1] ?? "", displayFormat);
829
+ if (to) setCalendarMonth(to);
830
+ } else {
831
+ if (!isDatePartComplete(parts[0] ?? "", maskEnabled, singleDateLen))
832
+ return;
833
+ const from = parseDate(parts[0] ?? "", displayFormat);
834
+ if (from) setCalendarMonth(from);
835
+ }
508
836
  const range = parseRangeText(
509
837
  text,
510
838
  displayFormat,
@@ -538,9 +866,20 @@ const DatePicker = React.forwardRef(
538
866
  onChange
539
867
  ]);
540
868
  const closePopover = React.useCallback(() => {
541
- commitPendingOnClose();
869
+ if (type === "range" && pendingRange?.[0] && pendingRange?.[1]) {
870
+ commitValue([pendingRange[0], pendingRange[1]]);
871
+ } else {
872
+ commitPendingOnClose();
873
+ }
874
+ resetTransientState();
542
875
  setOpen(false);
543
- }, [commitPendingOnClose, setOpen]);
876
+ }, [
877
+ commitPendingOnClose,
878
+ setOpen,
879
+ type,
880
+ pendingRange,
881
+ resetTransientState
882
+ ]);
544
883
  TimePickerPanel.useOutsideClickClose({
545
884
  enabled: open,
546
885
  containerRef,
@@ -549,7 +888,7 @@ const DatePicker = React.forwardRef(
549
888
  });
550
889
  const openPopover = () => {
551
890
  setOpen(true);
552
- setRangeSelectionStep("from");
891
+ resetTransientState();
553
892
  const dateVal = type === "date" ? currentValue : null;
554
893
  if (!dateVal) {
555
894
  setPendingDate(null);
@@ -570,27 +909,6 @@ const DatePicker = React.forwardRef(
570
909
  commitValue(selected);
571
910
  setOpen(false);
572
911
  };
573
- const handleRangeSelect = (range) => {
574
- if (!range) return;
575
- const from = range.from ?? null;
576
- const to = range.to ?? null;
577
- if (rangeSelectionStep === "from") {
578
- setInternalValue([from, null]);
579
- setRangeSelectionStep("to");
580
- return;
581
- }
582
- setRangeSelectionStep("from");
583
- if (from && to) {
584
- if (showTime || needConfirm) {
585
- setPendingDate(from);
586
- return;
587
- }
588
- commitValue([from, to]);
589
- setOpen(false);
590
- return;
591
- }
592
- if (from) setInternalValue([from, null]);
593
- };
594
912
  const handleNow = () => {
595
913
  const now = toBrowserLocalDate(/* @__PURE__ */ new Date());
596
914
  if (showTime || needConfirm) {
@@ -628,7 +946,7 @@ const DatePicker = React.forwardRef(
628
946
  }
629
947
  setInputText(text);
630
948
  if (type === "range") {
631
- parseAndApplyRange(text);
949
+ parseAndApplyRange(text, e.target.selectionStart);
632
950
  return;
633
951
  }
634
952
  const isComplete = maskTemplate ? text.length >= maskTemplate.pattern.length : true;
@@ -719,71 +1037,33 @@ const DatePicker = React.forwardRef(
719
1037
  return currentValue ?? void 0;
720
1038
  };
721
1039
  const triggerContent = /* @__PURE__ */ jsxRuntime.jsxs(primitives_Popover.Popover, { open, onOpenChange: trigger ? setOpen : void 0, children: [
722
- trigger ? /* @__PURE__ */ jsxRuntime.jsx(primitives_Popover.PopoverTrigger, { asChild: true, children: trigger }) : /* @__PURE__ */ jsxRuntime.jsx(primitives_Popover.PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
723
- "div",
1040
+ trigger ? /* @__PURE__ */ jsxRuntime.jsx(primitives_Popover.PopoverTrigger, { asChild: true, children: trigger }) : /* @__PURE__ */ jsxRuntime.jsx(
1041
+ DatePickerTrigger,
724
1042
  {
725
- ref: containerRef,
726
- className: utils$1.cn(
727
- "relative flex w-full items-center gap-2 rounded-md border border-input bg-background pe-8 ps-3",
728
- "focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
729
- disabled && "cursor-not-allowed opacity-50",
730
- !!error && "border-destructive ring-destructive/20 ring-3",
731
- sizeConfig.trigger,
732
- !hasField && className
733
- ),
734
- children: [
735
- /* @__PURE__ */ jsxRuntime.jsx(
736
- Calendar,
737
- {
738
- className: utils$1.cn(
739
- "shrink-0 text-muted-foreground",
740
- sizeConfig.icon
741
- )
742
- }
743
- ),
744
- /* @__PURE__ */ jsxRuntime.jsx(
745
- "input",
746
- {
747
- ref: inputRef,
748
- type: "text",
749
- disabled,
750
- "aria-label": label || "Pick a date",
751
- "aria-describedby": ariaDescribedBy,
752
- "aria-invalid": !!error || void 0,
753
- placeholder: placeholder ?? defaultPlaceholder,
754
- value: inputText,
755
- onChange: handleInputChange,
756
- onKeyDown: handleInputKeyDown,
757
- onFocus: () => {
758
- if (!open) openPopover();
759
- },
760
- onBlur: handleInputBlur,
761
- className: utils$1.cn(
762
- "min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground",
763
- "disabled:cursor-not-allowed",
764
- sizeConfig.input
765
- )
766
- }
767
- ),
768
- timezone && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground", children: timezone.toUpperCase() }),
769
- allowClear && /* @__PURE__ */ jsxRuntime.jsx(
770
- "button",
771
- {
772
- type: "button",
773
- onPointerDown: (e) => e.preventDefault(),
774
- onClick: handleClear,
775
- className: utils$1.cn(
776
- "absolute inset-y-0 end-2 flex items-center text-muted-foreground hover:text-foreground focus:outline-none",
777
- !(inputText && !disabled) && "invisible"
778
- ),
779
- "aria-label": "Clear date",
780
- tabIndex: -1,
781
- children: /* @__PURE__ */ jsxRuntime.jsx(x.X, { className: sizeConfig.icon })
782
- }
783
- )
784
- ]
1043
+ containerRef,
1044
+ inputRef,
1045
+ disabled,
1046
+ error,
1047
+ hasField,
1048
+ className,
1049
+ triggerSizeClass: sizeConfig.trigger,
1050
+ inputSizeClass: sizeConfig.input,
1051
+ iconSizeClass: sizeConfig.icon,
1052
+ label,
1053
+ ariaDescribedBy,
1054
+ placeholder: placeholder ?? defaultPlaceholder,
1055
+ inputText,
1056
+ allowClear,
1057
+ timezone,
1058
+ onInputChange: handleInputChange,
1059
+ onInputKeyDown: handleInputKeyDown,
1060
+ onInputFocus: () => {
1061
+ if (!open) openPopover();
1062
+ },
1063
+ onInputBlur: handleInputBlur,
1064
+ onClear: handleClear
785
1065
  }
786
- ) }),
1066
+ ),
787
1067
  open && /* @__PURE__ */ jsxRuntime.jsxs(
788
1068
  primitives_Popover.PopoverContent,
789
1069
  {
@@ -806,7 +1086,7 @@ const DatePicker = React.forwardRef(
806
1086
  new Date(year, calendarMonth.getMonth(), 1)
807
1087
  ),
808
1088
  onSelect: handleGridPickerSelect,
809
- isDisabled: (date) => isMonthDisabled(date, minDate, maxDate)
1089
+ isDisabled: (date) => isMonthDisabled(date, normalizedMinDate, normalizedMaxDate)
810
1090
  }
811
1091
  ) : type === "date" && picker === "year" ? /* @__PURE__ */ jsxRuntime.jsx(
812
1092
  YearPicker,
@@ -815,7 +1095,7 @@ const DatePicker = React.forwardRef(
815
1095
  displayedYear: calendarMonth.getFullYear(),
816
1096
  onYearChange: (year) => setCalendarMonth(new Date(year, 0, 1)),
817
1097
  onSelect: handleGridPickerSelect,
818
- isDisabled: (date) => isYearDisabled(date, minDate, maxDate)
1098
+ isDisabled: (date) => isYearDisabled(date, normalizedMinDate, normalizedMaxDate)
819
1099
  }
820
1100
  ) : type === "date" ? /* @__PURE__ */ jsxRuntime.jsx(
821
1101
  primitives_Calendar.Calendar,
@@ -831,28 +1111,23 @@ const DatePicker = React.forwardRef(
831
1111
  weekStartsOn,
832
1112
  classNames: weekRowHoverClassName ? { week: utils$1.cn("mt-2 flex w-full", weekRowHoverClassName) } : void 0,
833
1113
  ...weekHighlightProps,
834
- ...minDate && { fromDate: minDate },
835
- ...maxDate && { toDate: maxDate }
1114
+ ...normalizedMinDate && { fromDate: normalizedMinDate },
1115
+ ...normalizedMaxDate && { toDate: normalizedMaxDate }
836
1116
  }
837
1117
  ) : /* @__PURE__ */ jsxRuntime.jsx(
838
- primitives_Calendar.Calendar,
1118
+ RangeCalendar,
839
1119
  {
840
- mode: "range",
841
- numberOfMonths: 2,
842
- captionLayout: "dropdown",
843
- today: todayDate,
1120
+ todayDate,
844
1121
  weekStartsOn,
845
- 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",
846
1122
  month: calendarMonth,
847
1123
  onMonthChange: setCalendarMonth,
848
- selected: currentValue ? {
849
- from: currentValue[0] ?? void 0,
850
- to: currentValue[1] ?? void 0
851
- } : void 0,
1124
+ selected: memoizedRangeSelected,
852
1125
  onSelect: handleRangeSelect,
853
1126
  disabled: calendarDisabled,
854
- ...minDate && { fromDate: minDate },
855
- ...maxDate && { toDate: maxDate }
1127
+ fromDate: normalizedMinDate,
1128
+ toDate: normalizedMaxDate,
1129
+ onHoverIn: handleHoverIn,
1130
+ onHoverOut: handleHoverOut
856
1131
  }
857
1132
  ),
858
1133
  showTime && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-inline-start border-border", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -884,30 +1159,20 @@ const DatePicker = React.forwardRef(
884
1159
  if (!hasField) {
885
1160
  return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className, children: triggerContent });
886
1161
  }
887
- return /* @__PURE__ */ jsxRuntime.jsxs(
888
- primitives_Field.Field,
1162
+ return /* @__PURE__ */ jsxRuntime.jsx(
1163
+ DatePickerField,
889
1164
  {
890
1165
  ref,
891
- "data-disabled": disabled || void 0,
892
- "data-invalid": !!error || void 0,
1166
+ disabled,
1167
+ error,
893
1168
  className,
894
- children: [
895
- label && /* @__PURE__ */ jsxRuntime.jsxs(
896
- primitives_Field.FieldLabel,
897
- {
898
- ...labelProps,
899
- children: [
900
- label,
901
- required && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "text-destructive", children: "*" })
902
- ]
903
- }
904
- ),
905
- /* @__PURE__ */ jsxRuntime.jsxs(primitives_Field.FieldContent, { children: [
906
- triggerContent,
907
- !!error && /* @__PURE__ */ jsxRuntime.jsx(primitives_Field.FieldError, { id: errorId, children: error }),
908
- helpText && /* @__PURE__ */ jsxRuntime.jsx(primitives_Field.FieldDescription, { id: helpTextId, children: helpText })
909
- ] })
910
- ]
1169
+ label,
1170
+ required,
1171
+ helpText,
1172
+ labelProps,
1173
+ errorId,
1174
+ helpTextId,
1175
+ children: triggerContent
911
1176
  }
912
1177
  );
913
1178
  }
@@ -915,4 +1180,4 @@ const DatePicker = React.forwardRef(
915
1180
  DatePicker.displayName = "DatePicker";
916
1181
 
917
1182
  exports.DatePicker = DatePicker;
918
- //# sourceMappingURL=DatePicker-BZd4rM2R.js.map
1183
+ //# sourceMappingURL=DatePicker-DpyYPJfR.js.map