@underverse-ui/underverse 1.0.81 → 1.0.83

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.js CHANGED
@@ -6914,7 +6914,6 @@ var getOptionDisabled = (option) => {
6914
6914
  var findOptionByValue = (options, value) => {
6915
6915
  return options.find((opt) => getOptionValue(opt) === value);
6916
6916
  };
6917
- var REQUIRED_ERROR_MESSAGE = "This field is required";
6918
6917
  var Combobox = ({
6919
6918
  id,
6920
6919
  options,
@@ -6944,6 +6943,7 @@ var Combobox = ({
6944
6943
  helperText,
6945
6944
  useOverlayScrollbar = false
6946
6945
  }) => {
6946
+ const tv = useSmartTranslations("ValidationInput");
6947
6947
  const [open, setOpen] = React24.useState(false);
6948
6948
  const [query, setQuery] = React24.useState("");
6949
6949
  const [activeIndex, setActiveIndex] = React24.useState(null);
@@ -7293,13 +7293,14 @@ var Combobox = ({
7293
7293
  {
7294
7294
  tabIndex: -1,
7295
7295
  "aria-hidden": "true",
7296
- readOnly: true,
7297
7296
  value: hasValue ? "selected" : "",
7297
+ onChange: () => {
7298
+ },
7298
7299
  required,
7299
7300
  disabled,
7300
7301
  onInvalid: (e) => {
7301
7302
  e.preventDefault();
7302
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE);
7303
+ setLocalRequiredError(tv("required"));
7303
7304
  },
7304
7305
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
7305
7306
  }
@@ -8011,7 +8012,6 @@ import { Calendar, ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight3, S
8011
8012
  import * as React28 from "react";
8012
8013
  import { useId as useId6 } from "react";
8013
8014
  import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
8014
- var REQUIRED_ERROR_MESSAGE2 = "This field is required";
8015
8015
  var DatePicker = ({
8016
8016
  id,
8017
8017
  value,
@@ -8031,6 +8031,7 @@ var DatePicker = ({
8031
8031
  maxDate
8032
8032
  }) => {
8033
8033
  const t = useSmartTranslations("DatePicker");
8034
+ const tv = useSmartTranslations("ValidationInput");
8034
8035
  const locale = useSmartLocale();
8035
8036
  const [isOpen, setIsOpen] = React28.useState(false);
8036
8037
  const [viewDate, setViewDate] = React28.useState(value || /* @__PURE__ */ new Date());
@@ -8448,13 +8449,14 @@ var DatePicker = ({
8448
8449
  {
8449
8450
  tabIndex: -1,
8450
8451
  "aria-hidden": "true",
8451
- readOnly: true,
8452
8452
  value: value ? "selected" : "",
8453
+ onChange: () => {
8454
+ },
8453
8455
  required,
8454
8456
  disabled,
8455
8457
  onInvalid: (e) => {
8456
8458
  e.preventDefault();
8457
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE2);
8459
+ setLocalRequiredError(tv("required"));
8458
8460
  },
8459
8461
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
8460
8462
  }
@@ -8566,10 +8568,27 @@ var DatePicker = ({
8566
8568
  effectiveError && /* @__PURE__ */ jsx34("div", { className: "text-xs text-destructive", children: effectiveError })
8567
8569
  ] });
8568
8570
  };
8569
- var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select date range...", className, disablePastDates = false, minDate, maxDate, size = "md" }) => {
8571
+ var DateRangePicker = ({
8572
+ id,
8573
+ startDate,
8574
+ endDate,
8575
+ onChange,
8576
+ placeholder = "Select date range...",
8577
+ className,
8578
+ label,
8579
+ labelClassName,
8580
+ required = false,
8581
+ disablePastDates = false,
8582
+ minDate,
8583
+ maxDate,
8584
+ size = "md"
8585
+ }) => {
8570
8586
  const locale = useSmartLocale();
8571
8587
  const t = useSmartTranslations("DatePicker");
8588
+ const tv = useSmartTranslations("ValidationInput");
8572
8589
  const [isOpen, setIsOpen] = React28.useState(false);
8590
+ const [viewMode, setViewMode] = React28.useState("calendar");
8591
+ const [localRequiredError, setLocalRequiredError] = React28.useState();
8573
8592
  const wheelContainerRef = React28.useRef(null);
8574
8593
  const wheelDeltaRef = React28.useRef(0);
8575
8594
  const sizeStyles8 = {
@@ -8641,6 +8660,16 @@ var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select dat
8641
8660
  React28.useEffect(() => {
8642
8661
  setTempEnd(normalizeToLocal(endDate));
8643
8662
  }, [endDate]);
8663
+ React28.useEffect(() => {
8664
+ if (!isOpen) {
8665
+ setViewMode("calendar");
8666
+ }
8667
+ }, [isOpen]);
8668
+ React28.useEffect(() => {
8669
+ if (!required || startDate && endDate) {
8670
+ setLocalRequiredError(void 0);
8671
+ }
8672
+ }, [endDate, required, startDate]);
8644
8673
  const isSameDay2 = (a, b) => {
8645
8674
  if (!a || !b) return false;
8646
8675
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
@@ -8651,6 +8680,9 @@ var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select dat
8651
8680
  const navigateMonth = React28.useCallback((direction) => {
8652
8681
  setViewDate((prev) => new Date(prev.getFullYear(), prev.getMonth() + (direction === "next" ? 1 : -1), 1));
8653
8682
  }, []);
8683
+ const navigateYearRange = React28.useCallback((direction) => {
8684
+ setViewDate((prev) => new Date(prev.getFullYear() + (direction === "next" ? 12 : -12), prev.getMonth(), 1));
8685
+ }, []);
8654
8686
  const isElementVerticallyScrollable = (el) => {
8655
8687
  const style = window.getComputedStyle(el);
8656
8688
  const overflowY = style.overflowY;
@@ -8695,11 +8727,33 @@ var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select dat
8695
8727
  setTempStart(localDate);
8696
8728
  } else {
8697
8729
  setTempEnd(localDate);
8730
+ setLocalRequiredError(void 0);
8698
8731
  onChange(tempStart, localDate);
8699
8732
  setIsOpen(false);
8700
8733
  }
8701
8734
  }
8702
8735
  };
8736
+ const handleSelectToday = () => {
8737
+ const today = /* @__PURE__ */ new Date();
8738
+ today.setHours(0, 0, 0, 0);
8739
+ const localToday = new Date(today.getFullYear(), today.getMonth(), today.getDate());
8740
+ const isPastDate = disablePastDates && localToday < today;
8741
+ const isOutOfRange = !!minDay && localToday < minDay || !!maxDay && localToday > maxDay;
8742
+ if (isPastDate || isOutOfRange) return;
8743
+ setTempStart(localToday);
8744
+ setTempEnd(localToday);
8745
+ setHoveredDate(null);
8746
+ setLocalRequiredError(void 0);
8747
+ onChange(localToday, localToday);
8748
+ setIsOpen(false);
8749
+ };
8750
+ const handleClear = () => {
8751
+ setTempStart(null);
8752
+ setTempEnd(null);
8753
+ setHoveredDate(null);
8754
+ onChange(void 0, void 0);
8755
+ setIsOpen(false);
8756
+ };
8703
8757
  const renderGrid = () => {
8704
8758
  const nodes = [];
8705
8759
  const daysInMonth = getDaysInMonth(viewDate);
@@ -8768,13 +8822,63 @@ var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select dat
8768
8822
  }
8769
8823
  return nodes;
8770
8824
  };
8825
+ const renderMonthSelector = () => {
8826
+ const months = locale === "vi" ? ["Th1", "Th2", "Th3", "Th4", "Th5", "Th6", "Th7", "Th8", "Th9", "Th10", "Th11", "Th12"] : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
8827
+ return /* @__PURE__ */ jsx34("div", { className: "grid grid-cols-3 gap-2 p-2", children: months.map((month, idx) => {
8828
+ const isSelected = viewDate.getMonth() === idx;
8829
+ return /* @__PURE__ */ jsx34(
8830
+ "button",
8831
+ {
8832
+ type: "button",
8833
+ onClick: () => {
8834
+ setViewDate(new Date(viewDate.getFullYear(), idx, 1));
8835
+ setViewMode("calendar");
8836
+ },
8837
+ className: cn(
8838
+ "py-2 px-3 rounded-lg text-sm font-medium transition-all duration-200",
8839
+ isSelected ? "bg-primary text-primary-foreground shadow-md" : "hover:bg-accent/80 text-foreground hover:scale-105"
8840
+ ),
8841
+ children: month
8842
+ },
8843
+ month
8844
+ );
8845
+ }) });
8846
+ };
8847
+ const renderYearSelector = () => {
8848
+ const startYear = Math.floor(viewDate.getFullYear() / 12) * 12;
8849
+ const years = Array.from({ length: 12 }, (_, i) => startYear + i);
8850
+ return /* @__PURE__ */ jsx34("div", { className: "grid grid-cols-3 gap-2 p-2", children: years.map((year) => {
8851
+ const isSelected = viewDate.getFullYear() === year;
8852
+ return /* @__PURE__ */ jsx34(
8853
+ "button",
8854
+ {
8855
+ type: "button",
8856
+ onClick: () => {
8857
+ setViewDate(new Date(year, viewDate.getMonth(), 1));
8858
+ setViewMode("month");
8859
+ },
8860
+ className: cn(
8861
+ "py-2 px-3 rounded-lg text-sm font-medium transition-all duration-200",
8862
+ isSelected ? "bg-primary text-primary-foreground shadow-md" : "hover:bg-accent/80 text-foreground hover:scale-105"
8863
+ ),
8864
+ children: year
8865
+ },
8866
+ year
8867
+ );
8868
+ }) });
8869
+ };
8870
+ const todayDate = React28.useMemo(() => {
8871
+ const today = /* @__PURE__ */ new Date();
8872
+ return new Date(today.getFullYear(), today.getMonth(), today.getDate());
8873
+ }, []);
8874
+ const isTodayUnavailable = !!minDay && todayDate < minDay || !!maxDay && todayDate > maxDay;
8771
8875
  const panel = /* @__PURE__ */ jsxs24("div", { ref: wheelContainerRef, className: "w-full", children: [
8772
8876
  /* @__PURE__ */ jsxs24("div", { className: cn("flex items-center justify-between px-1", sizeStyles8[size].headerMargin), children: [
8773
8877
  /* @__PURE__ */ jsx34(
8774
8878
  "button",
8775
8879
  {
8776
8880
  type: "button",
8777
- onClick: () => navigateMonth("prev"),
8881
+ onClick: () => viewMode === "year" ? navigateYearRange("prev") : navigateMonth("prev"),
8778
8882
  className: cn(
8779
8883
  "rounded-xl transition-all duration-200",
8780
8884
  sizeStyles8[size].navButton,
@@ -8785,15 +8889,39 @@ var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select dat
8785
8889
  children: /* @__PURE__ */ jsx34(ChevronLeft2, { className: sizeStyles8[size].navIcon })
8786
8890
  }
8787
8891
  ),
8788
- /* @__PURE__ */ jsxs24("div", { className: "flex flex-col items-center", children: [
8789
- /* @__PURE__ */ jsx34("span", { className: cn("font-bold text-foreground", size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm"), children: viewDate.toLocaleDateString(locale === "vi" ? "vi-VN" : "en-US", { month: "long" }) }),
8790
- /* @__PURE__ */ jsx34("span", { className: cn("text-muted-foreground font-medium", size === "sm" ? "text-[10px]" : size === "lg" ? "text-sm" : "text-xs"), children: viewDate.getFullYear() })
8892
+ /* @__PURE__ */ jsxs24("div", { className: "flex items-center gap-1", children: [
8893
+ /* @__PURE__ */ jsx34(
8894
+ "button",
8895
+ {
8896
+ type: "button",
8897
+ onClick: () => setViewMode(viewMode === "month" ? "calendar" : "month"),
8898
+ className: cn(
8899
+ "rounded-lg px-2 py-0.5 font-bold transition-colors duration-200",
8900
+ size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm",
8901
+ viewMode === "month" ? "bg-primary/15 text-primary" : "text-foreground hover:bg-accent/50"
8902
+ ),
8903
+ children: viewDate.toLocaleDateString(locale === "vi" ? "vi-VN" : "en-US", { month: "long" })
8904
+ }
8905
+ ),
8906
+ /* @__PURE__ */ jsx34(
8907
+ "button",
8908
+ {
8909
+ type: "button",
8910
+ onClick: () => setViewMode(viewMode === "year" ? "calendar" : "year"),
8911
+ className: cn(
8912
+ "rounded-lg px-2 py-0.5 font-medium transition-colors duration-200",
8913
+ size === "sm" ? "text-[10px]" : size === "lg" ? "text-sm" : "text-xs",
8914
+ viewMode === "year" ? "bg-primary/15 text-primary" : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"
8915
+ ),
8916
+ children: viewDate.getFullYear()
8917
+ }
8918
+ )
8791
8919
  ] }),
8792
8920
  /* @__PURE__ */ jsx34(
8793
8921
  "button",
8794
8922
  {
8795
8923
  type: "button",
8796
- onClick: () => navigateMonth("next"),
8924
+ onClick: () => viewMode === "year" ? navigateYearRange("next") : navigateMonth("next"),
8797
8925
  className: cn(
8798
8926
  "rounded-xl transition-all duration-200",
8799
8927
  sizeStyles8[size].navButton,
@@ -8805,82 +8933,167 @@ var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select dat
8805
8933
  }
8806
8934
  )
8807
8935
  ] }),
8808
- /* @__PURE__ */ jsx34("div", { className: cn("grid grid-cols-7 gap-1 px-0.5", size === "sm" ? "mb-1" : size === "lg" ? "mb-3" : "mb-2"), children: (locale === "vi" ? ["CN", "T2", "T3", "T4", "T5", "T6", "T7"] : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]).map((d, idx) => /* @__PURE__ */ jsx34(
8809
- "div",
8810
- {
8811
- className: cn(
8812
- "text-center font-bold uppercase tracking-wide",
8813
- sizeStyles8[size].weekdayLabel,
8814
- idx === 0 || idx === 6 ? "text-primary/70" : "text-muted-foreground/60"
8815
- ),
8816
- children: d
8817
- },
8818
- d
8819
- )) }),
8820
- /* @__PURE__ */ jsx34("div", { className: "grid grid-cols-7 gap-0.5 p-1 rounded-xl bg-muted/20", children: renderGrid() })
8821
- ] });
8822
- const displayFormat = (date) => formatDateShort(date);
8823
- const label = tempStart && tempEnd ? `${displayFormat(tempStart)} - ${displayFormat(tempEnd)}` : tempStart ? `${displayFormat(tempStart)} - ...` : placeholder;
8824
- return /* @__PURE__ */ jsx34(
8825
- Popover,
8826
- {
8827
- open: isOpen,
8828
- onOpenChange: setIsOpen,
8829
- placement: "bottom-start",
8830
- contentWidth: size === "sm" ? 240 : 280,
8831
- contentClassName: cn(
8832
- "p-0",
8833
- "backdrop-blur-xl bg-popover/95 border-border/40 shadow-2xl",
8834
- "rounded-2xl md:rounded-3xl",
8835
- "max-w-[calc(100vw-1rem)] max-h-[calc(100vh-6rem)] overflow-auto overscroll-contain",
8836
- size === "sm" ? "p-3" : "p-5",
8837
- "animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-300"
8838
- ),
8839
- trigger: /* @__PURE__ */ jsxs24(
8936
+ viewMode === "calendar" && /* @__PURE__ */ jsxs24(Fragment6, { children: [
8937
+ /* @__PURE__ */ jsx34("div", { className: cn("grid grid-cols-7 gap-1 px-0.5", size === "sm" ? "mb-1" : size === "lg" ? "mb-3" : "mb-2"), children: (locale === "vi" ? ["CN", "T2", "T3", "T4", "T5", "T6", "T7"] : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]).map((d, idx) => /* @__PURE__ */ jsx34(
8938
+ "div",
8939
+ {
8940
+ className: cn(
8941
+ "text-center font-bold uppercase tracking-wide",
8942
+ sizeStyles8[size].weekdayLabel,
8943
+ idx === 0 || idx === 6 ? "text-primary/70" : "text-muted-foreground/60"
8944
+ ),
8945
+ children: d
8946
+ },
8947
+ d
8948
+ )) }),
8949
+ /* @__PURE__ */ jsx34("div", { className: "grid grid-cols-7 gap-0.5 p-1 rounded-xl bg-muted/20", children: renderGrid() })
8950
+ ] }),
8951
+ viewMode === "month" && renderMonthSelector(),
8952
+ viewMode === "year" && renderYearSelector(),
8953
+ /* @__PURE__ */ jsxs24("div", { className: cn("flex items-center border-t border-border/50", sizeStyles8[size].footerMargin), children: [
8954
+ /* @__PURE__ */ jsxs24(
8840
8955
  "button",
8841
8956
  {
8842
8957
  type: "button",
8958
+ onClick: handleSelectToday,
8959
+ disabled: isTodayUnavailable,
8843
8960
  className: cn(
8844
- "group flex w-full items-center justify-between rounded-full border bg-background/80 backdrop-blur-sm",
8845
- size === "sm" ? "px-2 py-1.5 text-xs" : "px-3 py-2.5 text-sm",
8846
- "border-border/60 hover:border-primary/40",
8847
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
8848
- "hover:bg-accent/10 hover:shadow-lg hover:shadow-primary/5 hover:-translate-y-0.5",
8849
- "transition-all duration-300 ease-out",
8850
- isOpen && "ring-2 ring-primary/30 border-primary/50 shadow-lg shadow-primary/10",
8851
- className
8961
+ "flex-1 font-semibold rounded-xl",
8962
+ "bg-linear-to-r from-primary/10 to-primary/5 border border-primary/30",
8963
+ "text-primary hover:from-primary/20 hover:to-primary/10 hover:border-primary/50",
8964
+ "transition-all duration-300 flex items-center justify-center",
8965
+ "hover:scale-[1.02] active:scale-[0.98] hover:shadow-md hover:shadow-primary/10",
8966
+ sizeStyles8[size].actionButton,
8967
+ isTodayUnavailable && "opacity-50 cursor-not-allowed hover:scale-100 active:scale-100"
8852
8968
  ),
8853
8969
  children: [
8854
- /* @__PURE__ */ jsxs24("div", { className: cn("flex items-center", size === "sm" ? "gap-1.5" : "gap-2.5"), children: [
8855
- /* @__PURE__ */ jsx34(
8856
- "div",
8857
- {
8858
- className: cn(
8859
- "flex items-center justify-center transition-colors duration-300",
8860
- isOpen ? "text-primary" : "text-muted-foreground group-hover:text-primary"
8861
- ),
8862
- children: /* @__PURE__ */ jsx34(Calendar, { className: cn("transition-transform duration-300", size === "sm" ? "h-3 w-3" : "h-4 w-4", isOpen && "scale-110") })
8863
- }
8864
- ),
8865
- /* @__PURE__ */ jsx34(
8866
- "span",
8867
- {
8868
- className: cn(
8869
- "truncate font-medium transition-colors duration-200",
8870
- !tempStart && !tempEnd && "text-muted-foreground",
8871
- (tempStart || tempEnd) && "text-foreground"
8872
- ),
8873
- children: label
8874
- }
8875
- )
8876
- ] }),
8877
- /* @__PURE__ */ jsx34("span", { className: cn("transition-all duration-300 text-muted-foreground group-hover:text-foreground", isOpen && "rotate-180 text-primary"), children: /* @__PURE__ */ jsx34("svg", { className: cn(size === "sm" ? "h-3 w-3" : "h-4 w-4"), fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, children: /* @__PURE__ */ jsx34("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
8970
+ /* @__PURE__ */ jsx34(Sparkles2, { className: sizeStyles8[size].actionIcon }),
8971
+ t("today")
8878
8972
  ]
8879
8973
  }
8880
8974
  ),
8881
- children: panel
8882
- }
8883
- );
8975
+ /* @__PURE__ */ jsxs24(
8976
+ "button",
8977
+ {
8978
+ type: "button",
8979
+ onClick: handleClear,
8980
+ className: cn(
8981
+ "flex-1 font-semibold rounded-xl",
8982
+ "bg-linear-to-r from-destructive/10 to-destructive/5 border border-destructive/30",
8983
+ "text-destructive hover:from-destructive/20 hover:to-destructive/10 hover:border-destructive/50",
8984
+ "transition-all duration-300 flex items-center justify-center",
8985
+ "hover:scale-[1.02] active:scale-[0.98] hover:shadow-md hover:shadow-destructive/10",
8986
+ sizeStyles8[size].actionButton
8987
+ ),
8988
+ children: [
8989
+ /* @__PURE__ */ jsx34(XIcon, { className: sizeStyles8[size].actionIcon }),
8990
+ t("clear")
8991
+ ]
8992
+ }
8993
+ )
8994
+ ] })
8995
+ ] });
8996
+ const displayFormat = (date) => formatDateShort(date);
8997
+ const displayLabel = tempStart && tempEnd ? `${displayFormat(tempStart)} - ${displayFormat(tempEnd)}` : tempStart ? `${displayFormat(tempStart)} - ...` : placeholder;
8998
+ const effectiveError = localRequiredError;
8999
+ const autoId = useId6();
9000
+ const resolvedId = id ? String(id) : `daterangepicker-${autoId}`;
9001
+ const labelId = label ? `${resolvedId}-label` : void 0;
9002
+ return /* @__PURE__ */ jsxs24("div", { className: cn("space-y-1.5", className), children: [
9003
+ label && /* @__PURE__ */ jsxs24(
9004
+ "label",
9005
+ {
9006
+ id: labelId,
9007
+ htmlFor: resolvedId,
9008
+ className: cn(size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm", "font-medium text-foreground", effectiveError && "text-destructive", labelClassName),
9009
+ children: [
9010
+ label,
9011
+ required && /* @__PURE__ */ jsx34("span", { className: "text-destructive ml-1", children: "*" })
9012
+ ]
9013
+ }
9014
+ ),
9015
+ /* @__PURE__ */ jsx34(
9016
+ "input",
9017
+ {
9018
+ tabIndex: -1,
9019
+ "aria-hidden": "true",
9020
+ value: startDate && endDate ? "selected" : "",
9021
+ onChange: () => {
9022
+ },
9023
+ required,
9024
+ onInvalid: (e) => {
9025
+ e.preventDefault();
9026
+ setLocalRequiredError(tv("required"));
9027
+ },
9028
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
9029
+ }
9030
+ ),
9031
+ /* @__PURE__ */ jsx34(
9032
+ Popover,
9033
+ {
9034
+ open: isOpen,
9035
+ onOpenChange: setIsOpen,
9036
+ placement: "bottom-start",
9037
+ contentWidth: sizeStyles8[size].contentWidth,
9038
+ contentClassName: cn(
9039
+ "p-0",
9040
+ "backdrop-blur-xl bg-popover/95 border-border/40 shadow-2xl",
9041
+ "rounded-2xl md:rounded-3xl",
9042
+ "max-w-[calc(100vw-1rem)] max-h-[calc(100vh-6rem)] overflow-auto overscroll-contain",
9043
+ sizeStyles8[size].contentPadding,
9044
+ "animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-300"
9045
+ ),
9046
+ trigger: /* @__PURE__ */ jsxs24(
9047
+ "button",
9048
+ {
9049
+ id: resolvedId,
9050
+ type: "button",
9051
+ "aria-labelledby": labelId,
9052
+ "aria-required": required,
9053
+ "aria-invalid": !!effectiveError,
9054
+ className: cn(
9055
+ "group flex w-full items-center justify-between rounded-full border bg-background/80 backdrop-blur-sm",
9056
+ sizeStyles8[size].trigger,
9057
+ "border-border/60 hover:border-primary/40",
9058
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
9059
+ "hover:bg-accent/10 hover:shadow-lg hover:shadow-primary/5 hover:-translate-y-0.5",
9060
+ "transition-all duration-300 ease-out",
9061
+ isOpen && "ring-2 ring-primary/30 border-primary/50 shadow-lg shadow-primary/10",
9062
+ effectiveError && "border-destructive/60 focus-visible:ring-destructive/50 bg-destructive/5"
9063
+ ),
9064
+ children: [
9065
+ /* @__PURE__ */ jsxs24("div", { className: cn("flex items-center", size === "sm" ? "gap-1.5" : "gap-2.5"), children: [
9066
+ /* @__PURE__ */ jsx34(
9067
+ "div",
9068
+ {
9069
+ className: cn(
9070
+ "flex items-center justify-center transition-colors duration-300",
9071
+ effectiveError ? "text-destructive" : isOpen ? "text-primary" : "text-muted-foreground group-hover:text-primary"
9072
+ ),
9073
+ children: /* @__PURE__ */ jsx34(Calendar, { className: cn("transition-transform duration-300", sizeStyles8[size].calendarIcon, isOpen && "scale-110") })
9074
+ }
9075
+ ),
9076
+ /* @__PURE__ */ jsx34(
9077
+ "span",
9078
+ {
9079
+ className: cn(
9080
+ "truncate font-medium transition-colors duration-200",
9081
+ !tempStart && !tempEnd && "text-muted-foreground",
9082
+ (tempStart || tempEnd) && "text-foreground"
9083
+ ),
9084
+ children: displayLabel
9085
+ }
9086
+ )
9087
+ ] }),
9088
+ /* @__PURE__ */ jsx34("span", { className: cn("transition-all duration-300 text-muted-foreground group-hover:text-foreground", isOpen && "rotate-180 text-primary"), children: /* @__PURE__ */ jsx34("svg", { className: cn(sizeStyles8[size].navIcon), fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2.5, children: /* @__PURE__ */ jsx34("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
9089
+ ]
9090
+ }
9091
+ ),
9092
+ children: panel
9093
+ }
9094
+ ),
9095
+ effectiveError && /* @__PURE__ */ jsx34("div", { className: "text-xs text-destructive", children: effectiveError })
9096
+ ] });
8884
9097
  };
8885
9098
  var CompactDatePicker = ({ value, onChange, className }) => {
8886
9099
  return /* @__PURE__ */ jsx34(
@@ -8907,7 +9120,6 @@ import * as React30 from "react";
8907
9120
  import * as React29 from "react";
8908
9121
  import { Calendar as Calendar2, X as X10, Check as Check4, ChevronDown as ChevronDown2 } from "lucide-react";
8909
9122
  import { jsx as jsx35, jsxs as jsxs25 } from "react/jsx-runtime";
8910
- var REQUIRED_ERROR_MESSAGE3 = "This field is required";
8911
9123
  var DEFAULT_MONTH_NAMES = [
8912
9124
  "January",
8913
9125
  "February",
@@ -9385,6 +9597,7 @@ function MonthYearPicker({
9385
9597
  className,
9386
9598
  ...rest
9387
9599
  }) {
9600
+ const tv = useSmartTranslations("ValidationInput");
9388
9601
  const now = /* @__PURE__ */ new Date();
9389
9602
  const currentYear = now.getFullYear();
9390
9603
  const resolvedMinYear = minYear ?? minDate?.getFullYear() ?? currentYear - 50;
@@ -9402,6 +9615,7 @@ function MonthYearPicker({
9402
9615
  const [parts, setParts] = React29.useState(initial);
9403
9616
  const [focusedColumn, setFocusedColumn] = React29.useState(null);
9404
9617
  const [localRequiredError, setLocalRequiredError] = React29.useState();
9618
+ const [hasCommittedValue, setHasCommittedValue] = React29.useState(Boolean(parseValue(isControlled ? value : defaultValue)));
9405
9619
  const monthScrollRef = React29.useRef(null);
9406
9620
  const yearScrollRef = React29.useRef(null);
9407
9621
  React29.useEffect(() => {
@@ -9410,7 +9624,12 @@ function MonthYearPicker({
9410
9624
  if (parsed) setParts(parsed);
9411
9625
  }
9412
9626
  }, [value, isControlled]);
9413
- const hasValue = isControlled ? !!value : !!defaultValue || parts !== initial;
9627
+ React29.useEffect(() => {
9628
+ if (isControlled) {
9629
+ setHasCommittedValue(Boolean(parseValue(value)));
9630
+ }
9631
+ }, [isControlled, value]);
9632
+ const hasValue = hasCommittedValue;
9414
9633
  const effectiveError = error ?? localRequiredError;
9415
9634
  React29.useEffect(() => {
9416
9635
  if (disabled || !required || hasValue) {
@@ -9441,15 +9660,17 @@ function MonthYearPicker({
9441
9660
  (next) => {
9442
9661
  if (!next) {
9443
9662
  setLocalRequiredError(void 0);
9663
+ if (!isControlled) setHasCommittedValue(false);
9444
9664
  onChange?.(void 0);
9445
9665
  return;
9446
9666
  }
9447
9667
  if (!isDateInRange(next.month, next.year)) return;
9448
9668
  const date = new Date(next.year, next.month, 1);
9449
9669
  setLocalRequiredError(void 0);
9670
+ if (!isControlled) setHasCommittedValue(true);
9450
9671
  onChange?.({ ...next, date });
9451
9672
  },
9452
- [isDateInRange, onChange]
9673
+ [isControlled, isDateInRange, onChange]
9453
9674
  );
9454
9675
  const tryUpdate = React29.useCallback(
9455
9676
  (next) => {
@@ -9697,13 +9918,14 @@ function MonthYearPicker({
9697
9918
  {
9698
9919
  tabIndex: -1,
9699
9920
  "aria-hidden": "true",
9700
- readOnly: true,
9701
9921
  value: hasValue ? "selected" : "",
9922
+ onChange: () => {
9923
+ },
9702
9924
  required,
9703
9925
  disabled,
9704
9926
  onInvalid: (e) => {
9705
9927
  e.preventDefault();
9706
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE3);
9928
+ setLocalRequiredError(tv("required"));
9707
9929
  },
9708
9930
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
9709
9931
  }
@@ -9732,13 +9954,14 @@ function MonthYearPicker({
9732
9954
  {
9733
9955
  tabIndex: -1,
9734
9956
  "aria-hidden": "true",
9735
- readOnly: true,
9736
9957
  value: hasValue ? "selected" : "",
9958
+ onChange: () => {
9959
+ },
9737
9960
  required,
9738
9961
  disabled,
9739
9962
  onInvalid: (e) => {
9740
9963
  e.preventDefault();
9741
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE3);
9964
+ setLocalRequiredError(tv("required"));
9742
9965
  },
9743
9966
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
9744
9967
  }
@@ -10414,7 +10637,6 @@ function Calendar3({
10414
10637
  import * as React31 from "react";
10415
10638
  import { Clock as Clock2, X as X11, Check as Check5, Sun, Moon, Sunset, Coffee } from "lucide-react";
10416
10639
  import { Fragment as Fragment9, jsx as jsx37, jsxs as jsxs27 } from "react/jsx-runtime";
10417
- var REQUIRED_ERROR_MESSAGE4 = "This field is required";
10418
10640
  var pad = (n) => n.toString().padStart(2, "0");
10419
10641
  var clamp4 = (n, min, max) => Math.min(max, Math.max(min, n));
10420
10642
  var WHEEL_ITEM_HEIGHT2 = {
@@ -10898,6 +11120,7 @@ function TimePicker({
10898
11120
  className,
10899
11121
  ...rest
10900
11122
  }) {
11123
+ const tv = useSmartTranslations("ValidationInput");
10901
11124
  const isControlled = value !== void 0;
10902
11125
  const now = /* @__PURE__ */ new Date();
10903
11126
  const initial = parseTime(isControlled ? value : defaultValue, format, includeSeconds) || (format === "12" ? { h: now.getHours() % 12 || 12, m: now.getMinutes(), s: now.getSeconds(), p: now.getHours() >= 12 ? "PM" : "AM" } : { h: now.getHours(), m: now.getMinutes(), s: now.getSeconds() });
@@ -11478,13 +11701,14 @@ function TimePicker({
11478
11701
  {
11479
11702
  tabIndex: -1,
11480
11703
  "aria-hidden": "true",
11481
- readOnly: true,
11482
11704
  value: hasCommittedValue ? "selected" : "",
11705
+ onChange: () => {
11706
+ },
11483
11707
  required,
11484
11708
  disabled,
11485
11709
  onInvalid: (e) => {
11486
11710
  e.preventDefault();
11487
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE4);
11711
+ setLocalRequiredError(tv("required"));
11488
11712
  },
11489
11713
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
11490
11714
  }
@@ -11527,13 +11751,14 @@ function TimePicker({
11527
11751
  {
11528
11752
  tabIndex: -1,
11529
11753
  "aria-hidden": "true",
11530
- readOnly: true,
11531
11754
  value: hasCommittedValue ? "selected" : "",
11755
+ onChange: () => {
11756
+ },
11532
11757
  required,
11533
11758
  disabled,
11534
11759
  onInvalid: (e) => {
11535
11760
  e.preventDefault();
11536
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE4);
11761
+ setLocalRequiredError(tv("required"));
11537
11762
  },
11538
11763
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
11539
11764
  }
@@ -11575,7 +11800,6 @@ function TimePicker({
11575
11800
 
11576
11801
  // src/components/DateTimePicker.tsx
11577
11802
  import { jsx as jsx38, jsxs as jsxs28 } from "react/jsx-runtime";
11578
- var REQUIRED_ERROR_MESSAGE5 = "This field is required";
11579
11803
  var DateTimePicker = ({
11580
11804
  value,
11581
11805
  onChange,
@@ -11594,6 +11818,7 @@ var DateTimePicker = ({
11594
11818
  size = "md"
11595
11819
  }) => {
11596
11820
  const t = useSmartTranslations("DateTimePicker");
11821
+ const tv = useSmartTranslations("ValidationInput");
11597
11822
  const locale = useSmartLocale();
11598
11823
  const [open, setOpen] = React32.useState(false);
11599
11824
  const [localRequiredError, setLocalRequiredError] = React32.useState();
@@ -11745,13 +11970,14 @@ var DateTimePicker = ({
11745
11970
  {
11746
11971
  tabIndex: -1,
11747
11972
  "aria-hidden": "true",
11748
- readOnly: true,
11749
11973
  value: value ? "selected" : "",
11974
+ onChange: () => {
11975
+ },
11750
11976
  required,
11751
11977
  disabled,
11752
11978
  onInvalid: (e) => {
11753
11979
  e.preventDefault();
11754
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE5);
11980
+ setLocalRequiredError(tv("required"));
11755
11981
  },
11756
11982
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
11757
11983
  }
@@ -14772,7 +14998,6 @@ import * as React39 from "react";
14772
14998
  import { useId as useId7 } from "react";
14773
14999
  import { ChevronDown as ChevronDown4, Search as Search5, Check as Check6, SearchX as SearchX2, Loader2 as Loader24, X as X13, Sparkles as Sparkles3 } from "lucide-react";
14774
15000
  import { Fragment as Fragment13, jsx as jsx45, jsxs as jsxs35 } from "react/jsx-runtime";
14775
- var REQUIRED_ERROR_MESSAGE6 = "This field is required";
14776
15001
  var MultiCombobox = ({
14777
15002
  id,
14778
15003
  options,
@@ -14806,6 +15031,7 @@ var MultiCombobox = ({
14806
15031
  maxTagsVisible = 3,
14807
15032
  useOverlayScrollbar = false
14808
15033
  }) => {
15034
+ const tv = useSmartTranslations("ValidationInput");
14809
15035
  const [query, setQuery] = React39.useState("");
14810
15036
  const [open, setOpen] = React39.useState(false);
14811
15037
  const [activeIndex, setActiveIndex] = React39.useState(null);
@@ -15219,13 +15445,14 @@ var MultiCombobox = ({
15219
15445
  {
15220
15446
  tabIndex: -1,
15221
15447
  "aria-hidden": "true",
15222
- readOnly: true,
15223
15448
  value: value.length > 0 ? "selected" : "",
15449
+ onChange: () => {
15450
+ },
15224
15451
  required,
15225
15452
  disabled,
15226
15453
  onInvalid: (e) => {
15227
15454
  e.preventDefault();
15228
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE6);
15455
+ setLocalRequiredError(tv("required"));
15229
15456
  },
15230
15457
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
15231
15458
  }
@@ -16400,7 +16627,6 @@ var defaultLabels = {
16400
16627
  searchPlaceholder: "Search...",
16401
16628
  noResultsText: "No results found"
16402
16629
  };
16403
- var REQUIRED_ERROR_MESSAGE7 = "This field is required";
16404
16630
  function getInitialExpandedNodes(categories, defaultExpanded, viewOnly, inline) {
16405
16631
  if (!(viewOnly || inline) || !defaultExpanded) return /* @__PURE__ */ new Set();
16406
16632
  const parentIds = /* @__PURE__ */ new Set();
@@ -16412,6 +16638,7 @@ function getInitialExpandedNodes(categories, defaultExpanded, viewOnly, inline)
16412
16638
  return parentIds;
16413
16639
  }
16414
16640
  function CategoryTreeSelect(props) {
16641
+ const tv = useSmartTranslations("ValidationInput");
16415
16642
  const {
16416
16643
  id,
16417
16644
  label,
@@ -16732,13 +16959,14 @@ function CategoryTreeSelect(props) {
16732
16959
  {
16733
16960
  tabIndex: -1,
16734
16961
  "aria-hidden": "true",
16735
- readOnly: true,
16736
16962
  value: valueArray.length > 0 ? "selected" : "",
16963
+ onChange: () => {
16964
+ },
16737
16965
  required,
16738
16966
  disabled,
16739
16967
  onInvalid: (e) => {
16740
16968
  e.preventDefault();
16741
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE7);
16969
+ setLocalRequiredError(tv("required"));
16742
16970
  },
16743
16971
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
16744
16972
  }
@@ -16767,13 +16995,14 @@ function CategoryTreeSelect(props) {
16767
16995
  {
16768
16996
  tabIndex: -1,
16769
16997
  "aria-hidden": "true",
16770
- readOnly: true,
16771
16998
  value: valueArray.length > 0 ? "selected" : "",
16999
+ onChange: () => {
17000
+ },
16772
17001
  required,
16773
17002
  disabled,
16774
17003
  onInvalid: (e) => {
16775
17004
  e.preventDefault();
16776
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE7);
17005
+ setLocalRequiredError(tv("required"));
16777
17006
  },
16778
17007
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
16779
17008
  }
@@ -16882,13 +17111,14 @@ function CategoryTreeSelect(props) {
16882
17111
  {
16883
17112
  tabIndex: -1,
16884
17113
  "aria-hidden": "true",
16885
- readOnly: true,
16886
17114
  value: valueArray.length > 0 ? "selected" : "",
17115
+ onChange: () => {
17116
+ },
16887
17117
  required,
16888
17118
  disabled,
16889
17119
  onInvalid: (e) => {
16890
17120
  e.preventDefault();
16891
- setLocalRequiredError(REQUIRED_ERROR_MESSAGE7);
17121
+ setLocalRequiredError(tv("required"));
16892
17122
  },
16893
17123
  className: "pointer-events-none absolute h-0 w-0 opacity-0"
16894
17124
  }