@underverse-ui/underverse 1.0.80 → 1.0.82

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
@@ -7128,11 +7128,12 @@ var Combobox = ({
7128
7128
  helperText,
7129
7129
  useOverlayScrollbar = false
7130
7130
  }) => {
7131
+ const tv = useSmartTranslations("ValidationInput");
7131
7132
  const [open, setOpen] = React24.useState(false);
7132
7133
  const [query, setQuery] = React24.useState("");
7133
7134
  const [activeIndex, setActiveIndex] = React24.useState(null);
7135
+ const [localRequiredError, setLocalRequiredError] = React24.useState();
7134
7136
  useShadCNAnimations();
7135
- const listRef = React24.useRef([]);
7136
7137
  const inputRef = React24.useRef(null);
7137
7138
  const optionsViewportRef = React24.useRef(null);
7138
7139
  useOverlayScrollbarTarget(optionsViewportRef, { enabled: useOverlayScrollbar });
@@ -7149,6 +7150,7 @@ var Combobox = ({
7149
7150
  if (getOptionDisabled(option)) return;
7150
7151
  const val = getOptionValue(option);
7151
7152
  if (val !== void 0 && val !== null) {
7153
+ setLocalRequiredError(void 0);
7152
7154
  onChange(val);
7153
7155
  setOpen(false);
7154
7156
  triggerRef.current?.focus();
@@ -7172,6 +7174,13 @@ var Combobox = ({
7172
7174
  const selectedOption = findOptionByValue(options, value);
7173
7175
  const displayValue = selectedOption ? getOptionLabel(selectedOption) : "";
7174
7176
  const selectedIcon = selectedOption ? getOptionIcon(selectedOption) : void 0;
7177
+ const hasValue = value !== void 0 && value !== null && value !== "";
7178
+ const effectiveError = error ?? localRequiredError;
7179
+ React24.useEffect(() => {
7180
+ if (disabled || !required || hasValue) {
7181
+ setLocalRequiredError(void 0);
7182
+ }
7183
+ }, [disabled, hasValue, required]);
7175
7184
  const groupedOptions = React24.useMemo(() => {
7176
7185
  if (!groupBy) return null;
7177
7186
  const groups = {};
@@ -7204,27 +7213,24 @@ var Combobox = ({
7204
7213
  const itemDescription = getOptionDescription(item);
7205
7214
  const itemDisabled = getOptionDisabled(item);
7206
7215
  const isSelected = itemValue === value;
7207
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
7208
- "li",
7216
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("li", { className: "list-none", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
7217
+ "button",
7209
7218
  {
7210
- ref: (node) => {
7211
- listRef.current[index] = node;
7212
- },
7213
7219
  id: `combobox-item-${index}`,
7214
- role: "option",
7220
+ type: "button",
7215
7221
  tabIndex: -1,
7216
- "aria-selected": isSelected,
7217
- "aria-disabled": itemDisabled,
7218
- onClick: () => !itemDisabled && handleSelect(item),
7222
+ disabled: itemDisabled,
7223
+ "aria-pressed": isSelected,
7224
+ onClick: () => handleSelect(item),
7219
7225
  style: {
7220
7226
  animationDelay: open ? `${Math.min(index * 15, 150)}ms` : "0ms"
7221
7227
  },
7222
7228
  className: cn(
7223
- "dropdown-item group flex cursor-pointer items-center rounded-full",
7229
+ "dropdown-item group flex w-full items-center rounded-full text-left",
7224
7230
  itemSizeStyles[size],
7225
7231
  "outline-none focus:outline-none focus-visible:outline-none",
7226
7232
  "transition-all duration-150",
7227
- !itemDisabled && "hover:bg-accent/70 hover:shadow-sm",
7233
+ !itemDisabled && "cursor-pointer hover:bg-accent/70 hover:shadow-sm",
7228
7234
  !itemDisabled && "focus:bg-accent/80 focus:text-accent-foreground",
7229
7235
  index === activeIndex && !itemDisabled && "bg-accent/60",
7230
7236
  isSelected && "bg-primary/10 text-primary font-medium",
@@ -7244,16 +7250,14 @@ var Combobox = ({
7244
7250
  ] }),
7245
7251
  isSelected && showSelectedIcon && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "shrink-0 ml-auto", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react13.Check, { className: cn(checkIconSizeStyles[size], "text-primary") }) })
7246
7252
  ]
7247
- },
7248
- `${itemValue}-${index}`
7249
- );
7253
+ }
7254
+ ) }, `${itemValue}-${index}`);
7250
7255
  };
7251
7256
  const dropdownBody = /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
7252
7257
  "div",
7253
7258
  {
7254
7259
  "data-combobox-dropdown": true,
7255
7260
  "data-state": open ? "open" : "closed",
7256
- role: "listbox",
7257
7261
  id: `${resolvedId}-listbox`,
7258
7262
  className: "w-full rounded-2xl md:rounded-3xl overflow-hidden",
7259
7263
  children: [
@@ -7308,8 +7312,7 @@ var Combobox = ({
7308
7312
  "transition-all duration-200",
7309
7313
  "placeholder:text-muted-foreground/50"
7310
7314
  ),
7311
- "aria-autocomplete": "list",
7312
- "aria-activedescendant": activeIndex != null ? `combobox-item-${activeIndex}` : void 0
7315
+ "aria-autocomplete": "list"
7313
7316
  }
7314
7317
  ),
7315
7318
  query && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
@@ -7381,7 +7384,8 @@ var Combobox = ({
7381
7384
  "aria-haspopup": "listbox",
7382
7385
  "aria-expanded": open,
7383
7386
  "aria-controls": `${resolvedId}-listbox`,
7384
- "aria-invalid": !!error,
7387
+ "aria-required": required,
7388
+ "aria-invalid": !!effectiveError,
7385
7389
  id: resolvedId,
7386
7390
  "aria-labelledby": labelId,
7387
7391
  onKeyDown: (e) => {
@@ -7402,7 +7406,7 @@ var Combobox = ({
7402
7406
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:border-primary",
7403
7407
  "disabled:cursor-not-allowed disabled:opacity-50",
7404
7408
  open && "ring-2 ring-primary/20 border-primary",
7405
- !!error && "border-destructive focus-visible:ring-destructive/30",
7409
+ !!effectiveError && "border-destructive focus-visible:ring-destructive/30",
7406
7410
  className
7407
7411
  )
7408
7412
  };
@@ -7460,6 +7464,7 @@ var Combobox = ({
7460
7464
  labelSize,
7461
7465
  "font-medium transition-colors duration-200",
7462
7466
  disabled ? "text-muted-foreground" : "text-foreground group-focus-within:text-primary",
7467
+ effectiveError && "text-destructive",
7463
7468
  labelClassName
7464
7469
  ),
7465
7470
  children: [
@@ -7468,6 +7473,23 @@ var Combobox = ({
7468
7473
  ]
7469
7474
  }
7470
7475
  ) }),
7476
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7477
+ "input",
7478
+ {
7479
+ tabIndex: -1,
7480
+ "aria-hidden": "true",
7481
+ value: hasValue ? "selected" : "",
7482
+ onChange: () => {
7483
+ },
7484
+ required,
7485
+ disabled,
7486
+ onInvalid: (e) => {
7487
+ e.preventDefault();
7488
+ setLocalRequiredError(tv("required"));
7489
+ },
7490
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
7491
+ }
7492
+ ),
7471
7493
  usePortal ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7472
7494
  Popover,
7473
7495
  {
@@ -7484,17 +7506,26 @@ var Combobox = ({
7484
7506
  triggerButtonInline,
7485
7507
  open && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "absolute left-0 top-full mt-1 z-50 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "rounded-2xl md:rounded-3xl overflow-hidden border text-popover-foreground shadow-md backdrop-blur-sm bg-popover/95 border-border/60", children: dropdownBody }) })
7486
7508
  ] }),
7487
- (helperText || error) && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("p", { className: cn("text-xs transition-colors duration-200 flex items-center gap-1.5", error ? "text-destructive" : "text-muted-foreground"), children: [
7488
- error && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: "w-3.5 h-3.5 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7489
- "path",
7490
- {
7491
- fillRule: "evenodd",
7492
- d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",
7493
- clipRule: "evenodd"
7494
- }
7495
- ) }),
7496
- error || helperText
7497
- ] })
7509
+ (helperText || effectiveError) && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
7510
+ "p",
7511
+ {
7512
+ className: cn(
7513
+ "text-xs transition-colors duration-200 flex items-center gap-1.5",
7514
+ effectiveError ? "text-destructive" : "text-muted-foreground"
7515
+ ),
7516
+ children: [
7517
+ effectiveError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: "w-3.5 h-3.5 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
7518
+ "path",
7519
+ {
7520
+ fillRule: "evenodd",
7521
+ d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",
7522
+ clipRule: "evenodd"
7523
+ }
7524
+ ) }),
7525
+ effectiveError || helperText
7526
+ ]
7527
+ }
7528
+ )
7498
7529
  ] });
7499
7530
  };
7500
7531
 
@@ -8185,10 +8216,12 @@ var DatePicker = ({
8185
8216
  maxDate
8186
8217
  }) => {
8187
8218
  const t = useSmartTranslations("DatePicker");
8219
+ const tv = useSmartTranslations("ValidationInput");
8188
8220
  const locale = useSmartLocale();
8189
8221
  const [isOpen, setIsOpen] = React28.useState(false);
8190
8222
  const [viewDate, setViewDate] = React28.useState(value || /* @__PURE__ */ new Date());
8191
8223
  const [viewMode, setViewMode] = React28.useState("calendar");
8224
+ const [localRequiredError, setLocalRequiredError] = React28.useState();
8192
8225
  const triggerRef = React28.useRef(null);
8193
8226
  const wheelContainerRef = React28.useRef(null);
8194
8227
  const wheelDeltaRef = React28.useRef(0);
@@ -8274,6 +8307,11 @@ var DatePicker = ({
8274
8307
  setViewDate(/* @__PURE__ */ new Date());
8275
8308
  }
8276
8309
  }, [value]);
8310
+ React28.useEffect(() => {
8311
+ if (disabled || !required || value) {
8312
+ setLocalRequiredError(void 0);
8313
+ }
8314
+ }, [disabled, required, value]);
8277
8315
  React28.useEffect(() => {
8278
8316
  if (!isOpen) {
8279
8317
  setViewMode("calendar");
@@ -8288,6 +8326,7 @@ var DatePicker = ({
8288
8326
  selectedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
8289
8327
  }
8290
8328
  onChange(selectedDate);
8329
+ setLocalRequiredError(void 0);
8291
8330
  setIsOpen(false);
8292
8331
  };
8293
8332
  const formatDateDisplay = (date) => {
@@ -8569,6 +8608,7 @@ var DatePicker = ({
8569
8608
  const labelSize = sizeStyles8[size].label;
8570
8609
  const radiusClass = size === "sm" ? "rounded-md" : "rounded-lg";
8571
8610
  const verticalGap = size === "sm" ? "space-y-1.5" : size === "lg" ? "space-y-2.5" : "space-y-2";
8611
+ const effectiveError = localRequiredError;
8572
8612
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: cn("w-full group", verticalGap), children: [
8573
8613
  label && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
8574
8614
  "label",
@@ -8580,6 +8620,7 @@ var DatePicker = ({
8580
8620
  labelSize,
8581
8621
  "font-semibold transition-colors duration-300 cursor-pointer",
8582
8622
  disabled ? "text-muted-foreground" : "text-foreground group-focus-within:text-primary hover:text-primary",
8623
+ effectiveError && "text-destructive",
8583
8624
  labelClassName
8584
8625
  ),
8585
8626
  children: [
@@ -8588,6 +8629,23 @@ var DatePicker = ({
8588
8629
  ]
8589
8630
  }
8590
8631
  ) }),
8632
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8633
+ "input",
8634
+ {
8635
+ tabIndex: -1,
8636
+ "aria-hidden": "true",
8637
+ value: value ? "selected" : "",
8638
+ onChange: () => {
8639
+ },
8640
+ required,
8641
+ disabled,
8642
+ onInvalid: (e) => {
8643
+ e.preventDefault();
8644
+ setLocalRequiredError(tv("required"));
8645
+ },
8646
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
8647
+ }
8648
+ ),
8591
8649
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
8592
8650
  Popover,
8593
8651
  {
@@ -8613,6 +8671,8 @@ var DatePicker = ({
8613
8671
  disabled,
8614
8672
  id: resolvedId,
8615
8673
  "aria-labelledby": labelId,
8674
+ "aria-required": required,
8675
+ "aria-invalid": !!effectiveError,
8616
8676
  className: cn(
8617
8677
  "group flex w-full items-center justify-between border bg-background/80 backdrop-blur-sm",
8618
8678
  "rounded-full",
@@ -8623,6 +8683,7 @@ var DatePicker = ({
8623
8683
  "hover:bg-accent/10 hover:shadow-lg hover:shadow-primary/5 hover:-translate-y-0.5",
8624
8684
  "transition-all duration-300 ease-out",
8625
8685
  isOpen && "ring-2 ring-primary/30 border-primary/50 shadow-lg shadow-primary/10",
8686
+ effectiveError && "border-destructive/60 focus-visible:ring-destructive/50 bg-destructive/5",
8626
8687
  className
8627
8688
  ),
8628
8689
  children: [
@@ -8663,6 +8724,7 @@ var DatePicker = ({
8663
8724
  e.preventDefault();
8664
8725
  e.stopPropagation();
8665
8726
  onChange(void 0);
8727
+ setLocalRequiredError(void 0);
8666
8728
  setViewDate(/* @__PURE__ */ new Date());
8667
8729
  }
8668
8730
  },
@@ -8687,7 +8749,8 @@ var DatePicker = ({
8687
8749
  ),
8688
8750
  children: datePickerContent
8689
8751
  }
8690
- )
8752
+ ),
8753
+ effectiveError && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "text-xs text-destructive", children: effectiveError })
8691
8754
  ] });
8692
8755
  };
8693
8756
  var DateRangePicker = ({ startDate, endDate, onChange, placeholder = "Select date range...", className, disablePastDates = false, minDate, maxDate, size = "md" }) => {
@@ -9508,6 +9571,7 @@ function MonthYearPicker({
9508
9571
  className,
9509
9572
  ...rest
9510
9573
  }) {
9574
+ const tv = useSmartTranslations("ValidationInput");
9511
9575
  const now = /* @__PURE__ */ new Date();
9512
9576
  const currentYear = now.getFullYear();
9513
9577
  const resolvedMinYear = minYear ?? minDate?.getFullYear() ?? currentYear - 50;
@@ -9524,6 +9588,8 @@ function MonthYearPicker({
9524
9588
  const [open, setOpen] = React29.useState(false);
9525
9589
  const [parts, setParts] = React29.useState(initial);
9526
9590
  const [focusedColumn, setFocusedColumn] = React29.useState(null);
9591
+ const [localRequiredError, setLocalRequiredError] = React29.useState();
9592
+ const [hasCommittedValue, setHasCommittedValue] = React29.useState(Boolean(parseValue(isControlled ? value : defaultValue)));
9527
9593
  const monthScrollRef = React29.useRef(null);
9528
9594
  const yearScrollRef = React29.useRef(null);
9529
9595
  React29.useEffect(() => {
@@ -9532,6 +9598,18 @@ function MonthYearPicker({
9532
9598
  if (parsed) setParts(parsed);
9533
9599
  }
9534
9600
  }, [value, isControlled]);
9601
+ React29.useEffect(() => {
9602
+ if (isControlled) {
9603
+ setHasCommittedValue(Boolean(parseValue(value)));
9604
+ }
9605
+ }, [isControlled, value]);
9606
+ const hasValue = hasCommittedValue;
9607
+ const effectiveError = error ?? localRequiredError;
9608
+ React29.useEffect(() => {
9609
+ if (disabled || !required || hasValue) {
9610
+ setLocalRequiredError(void 0);
9611
+ }
9612
+ }, [disabled, hasValue, required]);
9535
9613
  const years = React29.useMemo(() => {
9536
9614
  return Array.from({ length: resolvedMaxYear - resolvedMinYear + 1 }, (_, i) => resolvedMinYear + i);
9537
9615
  }, [resolvedMinYear, resolvedMaxYear]);
@@ -9555,14 +9633,18 @@ function MonthYearPicker({
9555
9633
  const emit = React29.useCallback(
9556
9634
  (next) => {
9557
9635
  if (!next) {
9636
+ setLocalRequiredError(void 0);
9637
+ if (!isControlled) setHasCommittedValue(false);
9558
9638
  onChange?.(void 0);
9559
9639
  return;
9560
9640
  }
9561
9641
  if (!isDateInRange(next.month, next.year)) return;
9562
9642
  const date = new Date(next.year, next.month, 1);
9643
+ setLocalRequiredError(void 0);
9644
+ if (!isControlled) setHasCommittedValue(true);
9563
9645
  onChange?.({ ...next, date });
9564
9646
  },
9565
- [isDateInRange, onChange]
9647
+ [isControlled, isDateInRange, onChange]
9566
9648
  );
9567
9649
  const tryUpdate = React29.useCallback(
9568
9650
  (next) => {
@@ -9634,7 +9716,6 @@ function MonthYearPicker({
9634
9716
  const monthIndex = parts.month;
9635
9717
  const yearIndex = years.indexOf(parts.year);
9636
9718
  const display = `${shortMonthNames[parts.month]} ${parts.year}`;
9637
- const hasValue = isControlled ? !!value : !!defaultValue || parts !== initial;
9638
9719
  const trigger = variant === "inline" ? null : /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
9639
9720
  "button",
9640
9721
  {
@@ -9643,6 +9724,8 @@ function MonthYearPicker({
9643
9724
  "aria-label": "Select month and year",
9644
9725
  "aria-haspopup": "dialog",
9645
9726
  "aria-expanded": open,
9727
+ "aria-required": required,
9728
+ "aria-invalid": !!effectiveError,
9646
9729
  className: cn(
9647
9730
  "group flex w-full items-center justify-between rounded-full border bg-background/80 backdrop-blur-sm",
9648
9731
  sz.height,
@@ -9651,9 +9734,9 @@ function MonthYearPicker({
9651
9734
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
9652
9735
  "disabled:opacity-50 disabled:cursor-not-allowed",
9653
9736
  "transition-all duration-300 ease-out",
9654
- error && "border-destructive/60 focus-visible:ring-destructive/50 bg-destructive/5",
9655
- success && "border-success/60 focus-visible:ring-success/50 bg-success/5",
9656
- !error && !success && "border-border/60 hover:border-primary/40 hover:bg-accent/10",
9737
+ effectiveError && "border-destructive/60 focus-visible:ring-destructive/50 bg-destructive/5",
9738
+ success && !effectiveError && "border-success/60 focus-visible:ring-success/50 bg-success/5",
9739
+ !effectiveError && !success && "border-border/60 hover:border-primary/40 hover:bg-accent/10",
9657
9740
  animate && !disabled && "hover:shadow-lg hover:shadow-primary/5 hover:-translate-y-0.5",
9658
9741
  open && "ring-2 ring-primary/30 border-primary/50 shadow-lg shadow-primary/10",
9659
9742
  className
@@ -9665,7 +9748,7 @@ function MonthYearPicker({
9665
9748
  {
9666
9749
  className: cn(
9667
9750
  "flex items-center justify-center transition-colors duration-300",
9668
- error ? "text-destructive" : success ? "text-success" : open ? "text-primary" : "text-muted-foreground group-hover:text-primary"
9751
+ effectiveError ? "text-destructive" : success ? "text-success" : open ? "text-primary" : "text-muted-foreground group-hover:text-primary"
9669
9752
  ),
9670
9753
  children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react16.Calendar, { className: cn(sz.icon, "transition-transform duration-300", open && "rotate-12") })
9671
9754
  }
@@ -9800,19 +9883,63 @@ function MonthYearPicker({
9800
9883
  ] });
9801
9884
  if (variant === "inline") {
9802
9885
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: cn("w-full", className), ...rest, children: [
9803
- label && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("label", { className: cn(sz.label, "block mb-1.5 font-medium text-foreground/80", labelClassName), children: [
9886
+ label && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("label", { className: cn(sz.label, "block mb-1.5 font-medium text-foreground/80", effectiveError && "text-destructive", labelClassName), children: [
9804
9887
  label,
9805
9888
  required && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "text-destructive ml-0.5", children: "*" })
9806
9889
  ] }),
9807
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: cn(panelSz.contentPadding, "rounded-2xl border border-border/50 bg-background/80 backdrop-blur-sm"), children: pickerContent }),
9808
- (helperText || error) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: cn("mt-1.5 text-xs", error ? "text-destructive" : "text-muted-foreground"), children: error || helperText })
9890
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
9891
+ "input",
9892
+ {
9893
+ tabIndex: -1,
9894
+ "aria-hidden": "true",
9895
+ value: hasValue ? "selected" : "",
9896
+ onChange: () => {
9897
+ },
9898
+ required,
9899
+ disabled,
9900
+ onInvalid: (e) => {
9901
+ e.preventDefault();
9902
+ setLocalRequiredError(tv("required"));
9903
+ },
9904
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
9905
+ }
9906
+ ),
9907
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
9908
+ "div",
9909
+ {
9910
+ className: cn(
9911
+ panelSz.contentPadding,
9912
+ "rounded-2xl border bg-background/80 backdrop-blur-sm",
9913
+ effectiveError ? "border-destructive/60 bg-destructive/5" : "border-border/50"
9914
+ ),
9915
+ children: pickerContent
9916
+ }
9917
+ ),
9918
+ (helperText || effectiveError) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: cn("mt-1.5 text-xs", effectiveError ? "text-destructive" : "text-muted-foreground"), children: effectiveError || helperText })
9809
9919
  ] });
9810
9920
  }
9811
9921
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: cn("w-full", className), ...rest, children: [
9812
- label && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("label", { className: cn(sz.label, "block mb-1.5 font-medium text-foreground/80", labelClassName), children: [
9922
+ label && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("label", { className: cn(sz.label, "block mb-1.5 font-medium text-foreground/80", effectiveError && "text-destructive", labelClassName), children: [
9813
9923
  label,
9814
9924
  required && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "text-destructive ml-0.5", children: "*" })
9815
9925
  ] }),
9926
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
9927
+ "input",
9928
+ {
9929
+ tabIndex: -1,
9930
+ "aria-hidden": "true",
9931
+ value: hasValue ? "selected" : "",
9932
+ onChange: () => {
9933
+ },
9934
+ required,
9935
+ disabled,
9936
+ onInvalid: (e) => {
9937
+ e.preventDefault();
9938
+ setLocalRequiredError(tv("required"));
9939
+ },
9940
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
9941
+ }
9942
+ ),
9816
9943
  /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
9817
9944
  Popover,
9818
9945
  {
@@ -9827,7 +9954,7 @@ function MonthYearPicker({
9827
9954
  children: pickerContent
9828
9955
  }
9829
9956
  ),
9830
- (helperText || error) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: cn("mt-1.5 text-xs", error ? "text-destructive" : "text-muted-foreground"), children: error || helperText })
9957
+ (helperText || effectiveError) && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: cn("mt-1.5 text-xs", effectiveError ? "text-destructive" : "text-muted-foreground"), children: effectiveError || helperText })
9831
9958
  ] });
9832
9959
  }
9833
9960
 
@@ -10967,6 +11094,7 @@ function TimePicker({
10967
11094
  className,
10968
11095
  ...rest
10969
11096
  }) {
11097
+ const tv = useSmartTranslations("ValidationInput");
10970
11098
  const isControlled = value !== void 0;
10971
11099
  const now = /* @__PURE__ */ new Date();
10972
11100
  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() });
@@ -10974,6 +11102,8 @@ function TimePicker({
10974
11102
  const [parts, setParts] = React31.useState(initial);
10975
11103
  const [manualInput, setManualInput] = React31.useState("");
10976
11104
  const [focusedColumn, setFocusedColumn] = React31.useState(null);
11105
+ const [localRequiredError, setLocalRequiredError] = React31.useState();
11106
+ const [hasCommittedValue, setHasCommittedValue] = React31.useState(Boolean(isControlled ? value : defaultValue));
10977
11107
  const hourScrollRef = React31.useRef(null);
10978
11108
  const minuteScrollRef = React31.useRef(null);
10979
11109
  const secondScrollRef = React31.useRef(null);
@@ -10983,6 +11113,11 @@ function TimePicker({
10983
11113
  if (parsed) setParts(parsed);
10984
11114
  }
10985
11115
  }, [value, isControlled, format, includeSeconds]);
11116
+ React31.useEffect(() => {
11117
+ if (isControlled) {
11118
+ setHasCommittedValue(Boolean(value));
11119
+ }
11120
+ }, [isControlled, value]);
10986
11121
  const isTimeDisabled = React31.useCallback(
10987
11122
  (timeStr) => {
10988
11123
  if (!disabledTimes) return false;
@@ -11037,9 +11172,13 @@ function TimePicker({
11037
11172
  (next) => {
11038
11173
  const timeStr = next ? formatTime2(next, format, includeSeconds) : void 0;
11039
11174
  if (!canEmit(next)) return;
11175
+ setLocalRequiredError(void 0);
11176
+ if (!isControlled) {
11177
+ setHasCommittedValue(Boolean(next));
11178
+ }
11040
11179
  onChange?.(timeStr);
11041
11180
  },
11042
- [canEmit, format, includeSeconds, onChange]
11181
+ [canEmit, format, includeSeconds, isControlled, onChange]
11043
11182
  );
11044
11183
  const tryUpdate = React31.useCallback(
11045
11184
  (next) => {
@@ -11059,6 +11198,11 @@ function TimePicker({
11059
11198
  setFocusedColumn(null);
11060
11199
  }
11061
11200
  };
11201
+ React31.useEffect(() => {
11202
+ if (disabled || !required || hasCommittedValue) {
11203
+ setLocalRequiredError(void 0);
11204
+ }
11205
+ }, [disabled, hasCommittedValue, required]);
11062
11206
  const handleKeyDown2 = (e, column) => {
11063
11207
  if (!["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End", "PageUp", "PageDown"].includes(e.key)) return;
11064
11208
  e.preventDefault();
@@ -11201,6 +11345,7 @@ function TimePicker({
11201
11345
  const panelSz = panelSizeClasses[effectivePanelSize];
11202
11346
  const shouldMatchTriggerWidth = matchTriggerWidth ?? variant !== "compact";
11203
11347
  const compactPanel = variant === "compact";
11348
+ const effectiveError = error ?? localRequiredError;
11204
11349
  const display = formatTime2(parts, format, includeSeconds);
11205
11350
  const trigger = variant === "inline" ? null : /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
11206
11351
  "button",
@@ -11210,6 +11355,8 @@ function TimePicker({
11210
11355
  "aria-label": "Select time",
11211
11356
  "aria-haspopup": "dialog",
11212
11357
  "aria-expanded": open,
11358
+ "aria-required": required,
11359
+ "aria-invalid": !!effectiveError,
11213
11360
  className: cn(
11214
11361
  "group flex w-full items-center justify-between rounded-full border bg-background/80 backdrop-blur-sm",
11215
11362
  sz.height,
@@ -11218,9 +11365,9 @@ function TimePicker({
11218
11365
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
11219
11366
  "disabled:opacity-50 disabled:cursor-not-allowed",
11220
11367
  "transition-all duration-300 ease-out",
11221
- error && "border-destructive/60 focus-visible:ring-destructive/50 bg-destructive/5",
11222
- success && "border-success/60 focus-visible:ring-success/50 bg-success/5",
11223
- !error && !success && "border-border/60 hover:border-primary/40 hover:bg-accent/10",
11368
+ effectiveError && "border-destructive/60 focus-visible:ring-destructive/50 bg-destructive/5",
11369
+ success && !effectiveError && "border-success/60 focus-visible:ring-success/50 bg-success/5",
11370
+ !effectiveError && !success && "border-border/60 hover:border-primary/40 hover:bg-accent/10",
11224
11371
  animate && !disabled && "hover:shadow-lg hover:shadow-primary/5 hover:-translate-y-0.5",
11225
11372
  open && "ring-2 ring-primary/30 border-primary/50 shadow-lg shadow-primary/10",
11226
11373
  className
@@ -11232,7 +11379,7 @@ function TimePicker({
11232
11379
  {
11233
11380
  className: cn(
11234
11381
  "flex items-center justify-center transition-colors duration-300",
11235
- error ? "text-destructive" : success ? "text-success" : open ? "text-primary" : "text-muted-foreground group-hover:text-primary"
11382
+ effectiveError ? "text-destructive" : success ? "text-success" : open ? "text-primary" : "text-muted-foreground group-hover:text-primary"
11236
11383
  ),
11237
11384
  children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react18.Clock, { className: cn(sz.icon, "transition-transform duration-300", open && "rotate-12") })
11238
11385
  }
@@ -11519,17 +11666,40 @@ function TimePicker({
11519
11666
  ] });
11520
11667
  if (variant === "inline") {
11521
11668
  return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "w-fit max-w-full", ...rest, children: [
11522
- label && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("label", { className: cn(sz.label, "font-semibold", disabled ? "text-muted-foreground" : "text-foreground"), children: [
11669
+ label && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("label", { className: cn(sz.label, "font-semibold", disabled ? "text-muted-foreground" : "text-foreground", effectiveError && "text-destructive"), children: [
11523
11670
  label,
11524
11671
  required && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-destructive ml-1", children: "*" })
11525
11672
  ] }) }),
11673
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11674
+ "input",
11675
+ {
11676
+ tabIndex: -1,
11677
+ "aria-hidden": "true",
11678
+ value: hasCommittedValue ? "selected" : "",
11679
+ onChange: () => {
11680
+ },
11681
+ required,
11682
+ disabled,
11683
+ onInvalid: (e) => {
11684
+ e.preventDefault();
11685
+ setLocalRequiredError(tv("required"));
11686
+ },
11687
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
11688
+ }
11689
+ ),
11526
11690
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11527
11691
  "div",
11528
11692
  {
11529
- className: cn(panelSz.contentPadding, "rounded-2xl md:rounded-3xl border border-border/60 bg-card/95 backdrop-blur-sm shadow-xl", className),
11693
+ className: cn(
11694
+ panelSz.contentPadding,
11695
+ "rounded-2xl md:rounded-3xl border bg-card/95 backdrop-blur-sm shadow-xl",
11696
+ effectiveError ? "border-destructive/60 bg-destructive/5" : "border-border/60",
11697
+ className
11698
+ ),
11530
11699
  children: timePickerContent
11531
11700
  }
11532
- )
11701
+ ),
11702
+ effectiveError && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: cn("mt-2", sz.label, "text-destructive"), children: effectiveError })
11533
11703
  ] });
11534
11704
  }
11535
11705
  return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "w-full", ...rest, children: [
@@ -11540,6 +11710,7 @@ function TimePicker({
11540
11710
  sz.label,
11541
11711
  "font-semibold",
11542
11712
  disabled ? "text-muted-foreground" : "text-foreground",
11713
+ effectiveError && "text-destructive",
11543
11714
  "cursor-pointer transition-colors hover:text-primary"
11544
11715
  ),
11545
11716
  onClick: () => !disabled && handleOpenChange(true),
@@ -11549,6 +11720,23 @@ function TimePicker({
11549
11720
  ]
11550
11721
  }
11551
11722
  ) }),
11723
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11724
+ "input",
11725
+ {
11726
+ tabIndex: -1,
11727
+ "aria-hidden": "true",
11728
+ value: hasCommittedValue ? "selected" : "",
11729
+ onChange: () => {
11730
+ },
11731
+ required,
11732
+ disabled,
11733
+ onInvalid: (e) => {
11734
+ e.preventDefault();
11735
+ setLocalRequiredError(tv("required"));
11736
+ },
11737
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
11738
+ }
11739
+ ),
11552
11740
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
11553
11741
  Popover,
11554
11742
  {
@@ -11562,24 +11750,24 @@ function TimePicker({
11562
11750
  panelSz.contentPadding,
11563
11751
  compactPanel && "max-w-[calc(100vw-2rem)] p-4 rounded-2xl",
11564
11752
  "rounded-2xl md:rounded-3xl border bg-popover/98 backdrop-blur-md shadow-2xl",
11565
- error && "border-destructive/40",
11566
- success && "border-success/40",
11567
- !error && !success && "border-border/60",
11753
+ effectiveError && "border-destructive/40",
11754
+ success && !effectiveError && "border-success/40",
11755
+ !effectiveError && !success && "border-border/60",
11568
11756
  animate && "animate-in fade-in-0 zoom-in-95 slide-in-from-top-2 duration-300"
11569
11757
  ),
11570
11758
  children: timePickerContent
11571
11759
  }
11572
11760
  ),
11573
- (error || success || helperText) && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: cn("mt-2 flex items-start gap-2", sz.label), children: [
11574
- error && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-2 text-destructive bg-destructive/10 px-3 py-1.5 rounded-lg", children: [
11761
+ (effectiveError || success || helperText) && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: cn("mt-2 flex items-start gap-2", sz.label), children: [
11762
+ effectiveError && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-2 text-destructive bg-destructive/10 px-3 py-1.5 rounded-lg", children: [
11575
11763
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react18.X, { className: "w-3.5 h-3.5 shrink-0" }),
11576
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: error })
11764
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: effectiveError })
11577
11765
  ] }),
11578
- success && !error && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-2 text-success bg-success/10 px-3 py-1.5 rounded-lg", children: [
11766
+ success && !effectiveError && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-2 text-success bg-success/10 px-3 py-1.5 rounded-lg", children: [
11579
11767
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react18.Check, { className: "w-3.5 h-3.5 shrink-0" }),
11580
11768
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "font-medium", children: "Valid time selected" })
11581
11769
  ] }),
11582
- helperText && !error && !success && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-muted-foreground/80 italic", children: helperText })
11770
+ helperText && !effectiveError && !success && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-muted-foreground/80 italic", children: helperText })
11583
11771
  ] })
11584
11772
  ] });
11585
11773
  }
@@ -11604,8 +11792,10 @@ var DateTimePicker = ({
11604
11792
  size = "md"
11605
11793
  }) => {
11606
11794
  const t = useSmartTranslations("DateTimePicker");
11795
+ const tv = useSmartTranslations("ValidationInput");
11607
11796
  const locale = useSmartLocale();
11608
11797
  const [open, setOpen] = React32.useState(false);
11798
+ const [localRequiredError, setLocalRequiredError] = React32.useState();
11609
11799
  const sizeStyles8 = {
11610
11800
  sm: {
11611
11801
  trigger: "h-8 px-2.5 py-1.5 text-sm md:h-7 md:text-xs",
@@ -11644,6 +11834,11 @@ var DateTimePicker = ({
11644
11834
  setTempDate(value);
11645
11835
  setCalendarMonth(value ?? /* @__PURE__ */ new Date());
11646
11836
  }, [value, open]);
11837
+ React32.useEffect(() => {
11838
+ if (disabled || !required || value) {
11839
+ setLocalRequiredError(void 0);
11840
+ }
11841
+ }, [disabled, required, value]);
11647
11842
  const getTimeString = (date) => {
11648
11843
  if (!date) return "";
11649
11844
  const h = date.getHours();
@@ -11700,11 +11895,13 @@ var DateTimePicker = ({
11700
11895
  };
11701
11896
  const handleApply = () => {
11702
11897
  onChange(tempDate);
11898
+ setLocalRequiredError(void 0);
11703
11899
  setOpen(false);
11704
11900
  };
11705
11901
  const handleClear = () => {
11706
11902
  onChange(void 0);
11707
11903
  setTempDate(void 0);
11904
+ setLocalRequiredError(void 0);
11708
11905
  setOpen(false);
11709
11906
  };
11710
11907
  const displayValue = value ? value.toLocaleString(locale === "vi" ? "vi-VN" : "en-US", {
@@ -11735,12 +11932,30 @@ var DateTimePicker = ({
11735
11932
  }
11736
11933
  };
11737
11934
  const weekdays = getWeekdays(locale);
11935
+ const effectiveError = localRequiredError;
11738
11936
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: cn("space-y-1.5", className), children: [
11739
- label && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { className: cn(sizeStyles8[size].label, "font-medium text-foreground flex items-center gap-1", labelClassName), children: [
11937
+ label && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { className: cn(sizeStyles8[size].label, "font-medium text-foreground flex items-center gap-1", effectiveError && "text-destructive", labelClassName), children: [
11740
11938
  label,
11741
11939
  " ",
11742
11940
  required && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-destructive", children: "*" })
11743
11941
  ] }),
11942
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
11943
+ "input",
11944
+ {
11945
+ tabIndex: -1,
11946
+ "aria-hidden": "true",
11947
+ value: value ? "selected" : "",
11948
+ onChange: () => {
11949
+ },
11950
+ required,
11951
+ disabled,
11952
+ onInvalid: (e) => {
11953
+ e.preventDefault();
11954
+ setLocalRequiredError(tv("required"));
11955
+ },
11956
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
11957
+ }
11958
+ ),
11744
11959
  /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
11745
11960
  Popover,
11746
11961
  {
@@ -11751,12 +11966,15 @@ var DateTimePicker = ({
11751
11966
  {
11752
11967
  type: "button",
11753
11968
  disabled,
11969
+ "aria-required": required,
11970
+ "aria-invalid": !!effectiveError,
11754
11971
  className: cn(
11755
11972
  "flex w-full items-center justify-between rounded-full border border-input bg-background",
11756
11973
  sizeStyles8[size].trigger,
11757
11974
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
11758
11975
  disabled && "opacity-50 cursor-not-allowed",
11759
- !displayValue && "text-muted-foreground"
11976
+ !displayValue && "text-muted-foreground",
11977
+ effectiveError && "border-destructive/60 bg-destructive/5"
11760
11978
  ),
11761
11979
  children: [
11762
11980
  /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "truncate", children: displayValue || placeholder || "Select date & time" }),
@@ -11769,6 +11987,7 @@ var DateTimePicker = ({
11769
11987
  onClick: (e) => {
11770
11988
  e.stopPropagation();
11771
11989
  onChange(void 0);
11990
+ setLocalRequiredError(void 0);
11772
11991
  },
11773
11992
  className: "hover:text-foreground p-0.5 rounded-md hover:bg-accent",
11774
11993
  children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react19.X, { className: sizeStyles8[size].icon })
@@ -11828,7 +12047,8 @@ var DateTimePicker = ({
11828
12047
  ] })
11829
12048
  ]
11830
12049
  }
11831
- )
12050
+ ),
12051
+ effectiveError && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "text-xs text-destructive", children: effectiveError })
11832
12052
  ] });
11833
12053
  };
11834
12054
 
@@ -14785,9 +15005,11 @@ var MultiCombobox = ({
14785
15005
  maxTagsVisible = 3,
14786
15006
  useOverlayScrollbar = false
14787
15007
  }) => {
15008
+ const tv = useSmartTranslations("ValidationInput");
14788
15009
  const [query, setQuery] = React39.useState("");
14789
15010
  const [open, setOpen] = React39.useState(false);
14790
15011
  const [activeIndex, setActiveIndex] = React39.useState(null);
15012
+ const [localRequiredError, setLocalRequiredError] = React39.useState();
14791
15013
  const inputRef = React39.useRef(null);
14792
15014
  const listRef = React39.useRef([]);
14793
15015
  const optionsListRef = React39.useRef(null);
@@ -14824,6 +15046,7 @@ var MultiCombobox = ({
14824
15046
  onChange(value.filter((v) => v !== optionValue));
14825
15047
  } else {
14826
15048
  if (!maxSelected || value.length < maxSelected) {
15049
+ setLocalRequiredError(void 0);
14827
15050
  onChange([...value, optionValue]);
14828
15051
  }
14829
15052
  }
@@ -14843,6 +15066,12 @@ var MultiCombobox = ({
14843
15066
  const handleClearAll = () => {
14844
15067
  onChange([]);
14845
15068
  };
15069
+ const effectiveError = error ?? localRequiredError;
15070
+ React39.useEffect(() => {
15071
+ if (disabled || !required || value.length > 0) {
15072
+ setLocalRequiredError(void 0);
15073
+ }
15074
+ }, [disabled, required, value.length]);
14846
15075
  React39.useEffect(() => {
14847
15076
  if (open && enableSearch) {
14848
15077
  setTimeout(() => {
@@ -15053,7 +15282,8 @@ var MultiCombobox = ({
15053
15282
  "aria-haspopup": "listbox",
15054
15283
  "aria-expanded": open,
15055
15284
  "aria-controls": listboxId,
15056
- "aria-invalid": !!error,
15285
+ "aria-required": required,
15286
+ "aria-invalid": !!effectiveError,
15057
15287
  className: cn(
15058
15288
  "group flex w-full items-center gap-2 rounded-full transition-all duration-200",
15059
15289
  sizeStyles8[size].trigger,
@@ -15061,7 +15291,7 @@ var MultiCombobox = ({
15061
15291
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:border-primary",
15062
15292
  "disabled:cursor-not-allowed disabled:opacity-50",
15063
15293
  open && "ring-2 ring-primary/20 border-primary",
15064
- !!error && "border-destructive focus-visible:ring-destructive/30"
15294
+ !!effectiveError && "border-destructive focus-visible:ring-destructive/30"
15065
15295
  ),
15066
15296
  children: [
15067
15297
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: cn("flex items-center gap-1.5 flex-1 overflow-hidden", size === "sm" ? "min-h-4" : size === "lg" ? "min-h-8" : "min-h-6"), children: value.length > 0 ? showTags ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
@@ -15157,6 +15387,7 @@ var MultiCombobox = ({
15157
15387
  size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm",
15158
15388
  "font-medium transition-colors duration-200",
15159
15389
  disabled ? "text-muted-foreground" : "text-foreground group-focus-within:text-primary",
15390
+ effectiveError && "text-destructive",
15160
15391
  labelClassName
15161
15392
  ),
15162
15393
  children: [
@@ -15174,6 +15405,7 @@ var MultiCombobox = ({
15174
15405
  labelSize,
15175
15406
  "font-medium transition-colors duration-200",
15176
15407
  disabled ? "text-muted-foreground" : "text-foreground group-focus-within:text-primary",
15408
+ effectiveError && "text-destructive",
15177
15409
  labelClassName
15178
15410
  ),
15179
15411
  children: [
@@ -15182,6 +15414,23 @@ var MultiCombobox = ({
15182
15414
  ]
15183
15415
  }
15184
15416
  ),
15417
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
15418
+ "input",
15419
+ {
15420
+ tabIndex: -1,
15421
+ "aria-hidden": "true",
15422
+ value: value.length > 0 ? "selected" : "",
15423
+ onChange: () => {
15424
+ },
15425
+ required,
15426
+ disabled,
15427
+ onInvalid: (e) => {
15428
+ e.preventDefault();
15429
+ setLocalRequiredError(tv("required"));
15430
+ },
15431
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
15432
+ }
15433
+ ),
15185
15434
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
15186
15435
  Popover,
15187
15436
  {
@@ -15195,17 +15444,26 @@ var MultiCombobox = ({
15195
15444
  children: dropdownBody
15196
15445
  }
15197
15446
  ),
15198
- (helperText || error) && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: cn("text-xs transition-colors duration-200 flex items-center gap-1.5", error ? "text-destructive" : "text-muted-foreground"), children: [
15199
- error && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: "w-3.5 h-3.5 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
15200
- "path",
15201
- {
15202
- fillRule: "evenodd",
15203
- d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",
15204
- clipRule: "evenodd"
15205
- }
15206
- ) }),
15207
- error || helperText
15208
- ] })
15447
+ (helperText || effectiveError) && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
15448
+ "p",
15449
+ {
15450
+ className: cn(
15451
+ "text-xs transition-colors duration-200 flex items-center gap-1.5",
15452
+ effectiveError ? "text-destructive" : "text-muted-foreground"
15453
+ ),
15454
+ children: [
15455
+ effectiveError && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", className: "w-3.5 h-3.5 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
15456
+ "path",
15457
+ {
15458
+ fillRule: "evenodd",
15459
+ d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z",
15460
+ clipRule: "evenodd"
15461
+ }
15462
+ ) }),
15463
+ effectiveError || helperText
15464
+ ]
15465
+ }
15466
+ )
15209
15467
  ] });
15210
15468
  };
15211
15469
 
@@ -16354,6 +16612,7 @@ function getInitialExpandedNodes(categories, defaultExpanded, viewOnly, inline)
16354
16612
  return parentIds;
16355
16613
  }
16356
16614
  function CategoryTreeSelect(props) {
16615
+ const tv = useSmartTranslations("ValidationInput");
16357
16616
  const {
16358
16617
  id,
16359
16618
  label,
@@ -16381,14 +16640,16 @@ function CategoryTreeSelect(props) {
16381
16640
  const [isOpen, setIsOpen] = (0, import_react22.useState)(false);
16382
16641
  const [expandedNodes, setExpandedNodes] = (0, import_react22.useState)(() => getInitialExpandedNodes(categories, defaultExpanded, viewOnly, inline));
16383
16642
  const [query, setQuery] = (0, import_react22.useState)("");
16643
+ const [localRequiredError, setLocalRequiredError] = (0, import_react22.useState)();
16384
16644
  const searchInputRef = (0, import_react22.useRef)(null);
16385
16645
  const dropdownViewportRef = (0, import_react22.useRef)(null);
16386
16646
  useOverlayScrollbarTarget(dropdownViewportRef, { enabled: useOverlayScrollbar });
16387
16647
  const autoId = (0, import_react22.useId)();
16388
16648
  const resolvedId = id ? String(id) : `category-tree-select-${autoId}`;
16389
16649
  const labelId = label ? `${resolvedId}-label` : void 0;
16390
- const helperId = helperText && !error ? `${resolvedId}-helper` : void 0;
16391
- const errorId = error ? `${resolvedId}-error` : void 0;
16650
+ const effectiveError = error ?? localRequiredError;
16651
+ const helperId = helperText && !effectiveError ? `${resolvedId}-helper` : void 0;
16652
+ const errorId = effectiveError ? `${resolvedId}-error` : void 0;
16392
16653
  const describedBy = errorId || helperId;
16393
16654
  const mergedLabels = { ...defaultLabels, ...labels };
16394
16655
  const valueArray = (0, import_react22.useMemo)(
@@ -16459,6 +16720,11 @@ function CategoryTreeSelect(props) {
16459
16720
  const t = setTimeout(() => searchInputRef.current?.focus(), 50);
16460
16721
  return () => clearTimeout(t);
16461
16722
  }, [isOpen, isSearchEnabled]);
16723
+ (0, import_react22.useEffect)(() => {
16724
+ if (disabled || !required || valueArray.length > 0) {
16725
+ setLocalRequiredError(void 0);
16726
+ }
16727
+ }, [disabled, required, valueArray.length]);
16462
16728
  const toggleExpand = (id2) => {
16463
16729
  if (isSearchMode) return;
16464
16730
  const newExpanded = new Set(expandedNodes);
@@ -16477,6 +16743,7 @@ function CategoryTreeSelect(props) {
16477
16743
  toggleExpand(categoryId);
16478
16744
  return;
16479
16745
  }
16746
+ setLocalRequiredError(void 0);
16480
16747
  if (!props.onChange) return;
16481
16748
  if (singleSelect) {
16482
16749
  const onChange = props.onChange;
@@ -16648,7 +16915,7 @@ function CategoryTreeSelect(props) {
16648
16915
  className: cn(
16649
16916
  size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm",
16650
16917
  disabled ? "text-muted-foreground" : "text-foreground",
16651
- error && "text-destructive",
16918
+ effectiveError && "text-destructive",
16652
16919
  labelClassName
16653
16920
  ),
16654
16921
  children: [
@@ -16657,10 +16924,27 @@ function CategoryTreeSelect(props) {
16657
16924
  ]
16658
16925
  }
16659
16926
  ) }) : null;
16660
- const renderAssistiveText = () => error ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { id: errorId, className: "text-sm text-destructive", children: error }) : helperText ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { id: helperId, className: "text-sm text-muted-foreground", children: helperText }) : null;
16927
+ const renderAssistiveText = () => effectiveError ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { id: errorId, className: "text-sm text-destructive", children: effectiveError }) : helperText ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { id: helperId, className: "text-sm text-muted-foreground", children: helperText }) : null;
16661
16928
  if (viewOnly) {
16662
16929
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: cn("w-full space-y-2", className), children: [
16663
16930
  renderLabel(),
16931
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
16932
+ "input",
16933
+ {
16934
+ tabIndex: -1,
16935
+ "aria-hidden": "true",
16936
+ value: valueArray.length > 0 ? "selected" : "",
16937
+ onChange: () => {
16938
+ },
16939
+ required,
16940
+ disabled,
16941
+ onInvalid: (e) => {
16942
+ e.preventDefault();
16943
+ setLocalRequiredError(tv("required"));
16944
+ },
16945
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
16946
+ }
16947
+ ),
16664
16948
  /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
16665
16949
  "div",
16666
16950
  {
@@ -16680,6 +16964,23 @@ function CategoryTreeSelect(props) {
16680
16964
  if (inline) {
16681
16965
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: cn("w-full space-y-2", className), children: [
16682
16966
  renderLabel(),
16967
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
16968
+ "input",
16969
+ {
16970
+ tabIndex: -1,
16971
+ "aria-hidden": "true",
16972
+ value: valueArray.length > 0 ? "selected" : "",
16973
+ onChange: () => {
16974
+ },
16975
+ required,
16976
+ disabled,
16977
+ onInvalid: (e) => {
16978
+ e.preventDefault();
16979
+ setLocalRequiredError(tv("required"));
16980
+ },
16981
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
16982
+ }
16983
+ ),
16683
16984
  /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
16684
16985
  "div",
16685
16986
  {
@@ -16779,6 +17080,23 @@ function CategoryTreeSelect(props) {
16779
17080
  ] });
16780
17081
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: cn("w-full space-y-2", className), children: [
16781
17082
  renderLabel(),
17083
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
17084
+ "input",
17085
+ {
17086
+ tabIndex: -1,
17087
+ "aria-hidden": "true",
17088
+ value: valueArray.length > 0 ? "selected" : "",
17089
+ onChange: () => {
17090
+ },
17091
+ required,
17092
+ disabled,
17093
+ onInvalid: (e) => {
17094
+ e.preventDefault();
17095
+ setLocalRequiredError(tv("required"));
17096
+ },
17097
+ className: "pointer-events-none absolute h-0 w-0 opacity-0"
17098
+ }
17099
+ ),
16782
17100
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
16783
17101
  Popover,
16784
17102
  {
@@ -16805,7 +17123,8 @@ function CategoryTreeSelect(props) {
16805
17123
  "aria-controls": `${resolvedId}-tree`,
16806
17124
  "aria-labelledby": labelId,
16807
17125
  "aria-describedby": describedBy,
16808
- "aria-invalid": !!error,
17126
+ "aria-required": required,
17127
+ "aria-invalid": !!effectiveError,
16809
17128
  className: cn(
16810
17129
  "group flex w-full items-center justify-between rounded-full transition-all duration-200",
16811
17130
  "backdrop-blur-sm",
@@ -16814,7 +17133,7 @@ function CategoryTreeSelect(props) {
16814
17133
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
16815
17134
  disabled && "opacity-50 cursor-not-allowed hover:transform-none hover:shadow-none",
16816
17135
  isOpen && "ring-2 ring-primary/30 border-primary/50 shadow-lg shadow-primary/10",
16817
- error && "border-destructive focus-visible:ring-destructive/30"
17136
+ effectiveError && "border-destructive focus-visible:ring-destructive/30"
16818
17137
  ),
16819
17138
  children: [
16820
17139
  /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2.5 text-left", children: [
@@ -20793,7 +21112,7 @@ function DataTableHeader({
20793
21112
  className: cn(
20794
21113
  "absolute inset-y-0 right-0 z-10 w-3 -mr-1",
20795
21114
  "cursor-col-resize select-none bg-transparent",
20796
- "after:absolute after:inset-y-2 after:right-[3px] after:w-px after:bg-border/0 after:transition-colors",
21115
+ "after:absolute after:inset-y-2 after:right-0.8 after:w-px after:bg-border/0 after:transition-colors",
20797
21116
  "hover:after:bg-primary/50 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary"
20798
21117
  )
20799
21118
  }
@@ -24023,7 +24342,7 @@ var TableInsertGrid = ({
24023
24342
  onFocus: () => setSelection({ rows, cols }),
24024
24343
  onClick: () => onInsert(rows, cols),
24025
24344
  className: cn(
24026
- "h-5 w-5 rounded-[4px] border transition-colors",
24345
+ "h-5 w-5 rounded-sm border transition-colors",
24027
24346
  active ? "border-primary bg-primary/20" : "border-border/70 bg-background hover:border-primary/60 hover:bg-primary/10"
24028
24347
  )
24029
24348
  },