@underverse-ui/underverse 0.2.109 → 0.2.110

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/index.cjs CHANGED
@@ -6196,8 +6196,8 @@ var DatePicker = ({
6196
6196
  "div",
6197
6197
  {
6198
6198
  className: cn(
6199
- "flex items-center justify-center rounded-lg p-1.5 transition-all duration-300",
6200
- isOpen ? "bg-primary/15 text-primary" : "bg-muted/50 text-muted-foreground group-hover:bg-primary/10 group-hover:text-primary"
6199
+ "flex items-center justify-center transition-colors duration-300",
6200
+ isOpen ? "text-primary" : "text-muted-foreground group-hover:text-primary"
6201
6201
  ),
6202
6202
  children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react14.Calendar, { className: cn(size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4", "transition-transform duration-300", isOpen && "scale-110") })
6203
6203
  }
@@ -6492,9 +6492,8 @@ var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select dat
6492
6492
  "div",
6493
6493
  {
6494
6494
  className: cn(
6495
- "flex items-center justify-center rounded-lg transition-all duration-300",
6496
- size === "sm" ? "p-1" : "p-1.5",
6497
- isOpen ? "bg-primary/15 text-primary" : "bg-muted/50 text-muted-foreground group-hover:bg-primary/10 group-hover:text-primary"
6495
+ "flex items-center justify-center transition-colors duration-300",
6496
+ isOpen ? "text-primary" : "text-muted-foreground group-hover:text-primary"
6498
6497
  ),
6499
6498
  children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react14.Calendar, { className: cn("transition-transform duration-300", size === "sm" ? "h-3 w-3" : "h-4 w-4", isOpen && "scale-110") })
6500
6499
  }
@@ -7568,6 +7567,8 @@ function TimePicker({
7568
7567
  showPresets = false,
7569
7568
  allowManualInput = false,
7570
7569
  customPresets = [],
7570
+ min,
7571
+ max,
7571
7572
  minTime,
7572
7573
  maxTime,
7573
7574
  disabledTimes,
@@ -7604,37 +7605,65 @@ function TimePicker({
7604
7605
  },
7605
7606
  [disabledTimes]
7606
7607
  );
7608
+ const resolvedMinTime = minTime ?? min;
7609
+ const resolvedMaxTime = maxTime ?? max;
7610
+ const toSeconds = React25.useCallback(
7611
+ (p) => {
7612
+ let h = p.h;
7613
+ if (format === "12") {
7614
+ const period = p.p ?? (h >= 12 ? "PM" : "AM");
7615
+ const base = h % 12;
7616
+ h = period === "PM" ? base + 12 : base;
7617
+ }
7618
+ return h * 3600 + p.m * 60 + (includeSeconds ? p.s : 0);
7619
+ },
7620
+ [format, includeSeconds]
7621
+ );
7607
7622
  const isTimeInRange = React25.useCallback(
7608
7623
  (timeStr) => {
7609
- if (!minTime && !maxTime) return true;
7624
+ if (!resolvedMinTime && !resolvedMaxTime) return true;
7610
7625
  const parsed = parseTime(timeStr, format, includeSeconds);
7611
7626
  if (!parsed) return true;
7612
- if (minTime) {
7613
- const min = parseTime(minTime, format, includeSeconds);
7614
- if (min) {
7615
- const currentMinutes = parsed.h * 60 + parsed.m;
7616
- const minMinutes = min.h * 60 + min.m;
7617
- if (currentMinutes < minMinutes) return false;
7618
- }
7627
+ const current = toSeconds(parsed);
7628
+ if (resolvedMinTime) {
7629
+ const minParsed = parseTime(resolvedMinTime, format, includeSeconds);
7630
+ if (minParsed && current < toSeconds(minParsed)) return false;
7619
7631
  }
7620
- if (maxTime) {
7621
- const max = parseTime(maxTime, format, includeSeconds);
7622
- if (max) {
7623
- const currentMinutes = parsed.h * 60 + parsed.m;
7624
- const maxMinutes = max.h * 60 + max.m;
7625
- if (currentMinutes > maxMinutes) return false;
7626
- }
7632
+ if (resolvedMaxTime) {
7633
+ const maxParsed = parseTime(resolvedMaxTime, format, includeSeconds);
7634
+ if (maxParsed && current > toSeconds(maxParsed)) return false;
7627
7635
  }
7628
7636
  return true;
7629
7637
  },
7630
- [minTime, maxTime, format, includeSeconds]
7638
+ [format, includeSeconds, resolvedMaxTime, resolvedMinTime, toSeconds]
7639
+ );
7640
+ const canEmit = React25.useCallback(
7641
+ (next) => {
7642
+ const timeStr = next ? formatTime(next, format, includeSeconds) : void 0;
7643
+ if (!timeStr) return true;
7644
+ if (!isTimeInRange(timeStr)) return false;
7645
+ if (isTimeDisabled(timeStr)) return false;
7646
+ return true;
7647
+ },
7648
+ [format, includeSeconds, isTimeDisabled, isTimeInRange]
7649
+ );
7650
+ const emit = React25.useCallback(
7651
+ (next) => {
7652
+ const timeStr = next ? formatTime(next, format, includeSeconds) : void 0;
7653
+ if (!canEmit(next)) return;
7654
+ onChange?.(timeStr);
7655
+ },
7656
+ [canEmit, format, includeSeconds, onChange]
7657
+ );
7658
+ const tryUpdate = React25.useCallback(
7659
+ (next) => {
7660
+ if (!canEmit(next)) return false;
7661
+ setParts(next);
7662
+ emit(next);
7663
+ return true;
7664
+ },
7665
+ [canEmit, emit]
7631
7666
  );
7632
- const emit = (next) => {
7633
- const timeStr = next ? formatTime(next, format, includeSeconds) : void 0;
7634
- if (timeStr && !isTimeInRange(timeStr)) return;
7635
- if (timeStr && isTimeDisabled(timeStr)) return;
7636
- onChange?.(timeStr);
7637
- };
7638
7667
  const handleOpenChange = (newOpen) => {
7639
7668
  setOpen(newOpen);
7640
7669
  if (newOpen) {
@@ -7685,8 +7714,7 @@ function TimePicker({
7685
7714
  if (e.key === "ArrowLeft") setFocusedColumn(includeSeconds ? "second" : "minute");
7686
7715
  break;
7687
7716
  }
7688
- setParts(newParts);
7689
- emit(newParts);
7717
+ tryUpdate(newParts);
7690
7718
  };
7691
7719
  const setNow = () => {
7692
7720
  const now2 = /* @__PURE__ */ new Date();
@@ -7699,8 +7727,7 @@ function TimePicker({
7699
7727
  } else {
7700
7728
  next = { h, m, s };
7701
7729
  }
7702
- setParts(next);
7703
- emit(next);
7730
+ tryUpdate(next);
7704
7731
  };
7705
7732
  const setPreset = (preset) => {
7706
7733
  const { h, m, s } = PRESETS[preset];
@@ -7710,8 +7737,7 @@ function TimePicker({
7710
7737
  } else {
7711
7738
  next = { h, m, s };
7712
7739
  }
7713
- setParts(next);
7714
- emit(next);
7740
+ tryUpdate(next);
7715
7741
  };
7716
7742
  const handleManualInput = (input) => {
7717
7743
  setManualInput(input);
@@ -7719,16 +7745,14 @@ function TimePicker({
7719
7745
  if (parsed) {
7720
7746
  const timeStr = formatTime(parsed, format, includeSeconds);
7721
7747
  if (isTimeInRange(timeStr) && !isTimeDisabled(timeStr)) {
7722
- setParts(parsed);
7723
- emit(parsed);
7748
+ tryUpdate(parsed);
7724
7749
  }
7725
7750
  }
7726
7751
  };
7727
7752
  const handleCustomPreset = (time) => {
7728
7753
  const parsed = parseTime(time, format, includeSeconds);
7729
7754
  if (parsed) {
7730
- setParts(parsed);
7731
- emit(parsed);
7755
+ tryUpdate(parsed);
7732
7756
  }
7733
7757
  };
7734
7758
  const hours = format === "24" ? Array.from({ length: 24 }, (_, i) => i) : Array.from({ length: 12 }, (_, i) => i + 1);
@@ -7849,8 +7873,7 @@ function TimePicker({
7849
7873
  return period === "PM" ? base + 12 : base;
7850
7874
  })();
7851
7875
  const next = { ...parts, h: nextH, p: format === "12" ? period : parts.p };
7852
- setParts(next);
7853
- emit(next);
7876
+ tryUpdate(next);
7854
7877
  };
7855
7878
  const timePickerContent = /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: panelSz.stackGap, children: [
7856
7879
  /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex items-center justify-center py-1", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: cn(panelSz.timeText, "font-bold tabular-nums tracking-wide text-foreground underline underline-offset-8 decoration-primary/60"), children: display }) }),
@@ -7956,8 +7979,7 @@ function TimePicker({
7956
7979
  valueIndex: minuteIndex,
7957
7980
  onSelect: (m) => {
7958
7981
  const next = { ...parts, m };
7959
- setParts(next);
7960
- emit(next);
7982
+ tryUpdate(next);
7961
7983
  },
7962
7984
  scrollRef: minuteScrollRef,
7963
7985
  itemHeight,
@@ -7985,8 +8007,7 @@ function TimePicker({
7985
8007
  valueIndex: secondIndex,
7986
8008
  onSelect: (s) => {
7987
8009
  const next = { ...parts, s };
7988
- setParts(next);
7989
- emit(next);
8010
+ tryUpdate(next);
7990
8011
  },
7991
8012
  scrollRef: secondScrollRef,
7992
8013
  itemHeight,
@@ -8039,8 +8060,7 @@ function TimePicker({
8039
8060
  if (pVal === "AM" && hour >= 12) hour -= 12;
8040
8061
  if (pVal === "PM" && hour < 12) hour += 12;
8041
8062
  const next = { ...parts, p: pVal, h: hour };
8042
- setParts(next);
8043
- emit(next);
8063
+ tryUpdate(next);
8044
8064
  },
8045
8065
  children: [
8046
8066
  isSelected && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "absolute inset-0 bg-linear-to-tr from-white/20 to-transparent" }),