@underverse-ui/underverse 0.1.20 → 0.1.22

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.d.cts CHANGED
@@ -660,7 +660,7 @@ declare const ScrollArea: React$1.ForwardRefExoticComponent<ScrollAreaProps & Re
660
660
  interface DatePickerProps {
661
661
  id?: string;
662
662
  value?: Date;
663
- onChange: (date: Date) => void;
663
+ onChange: (date: Date | undefined) => void;
664
664
  placeholder?: string;
665
665
  className?: string;
666
666
  disabled?: boolean;
@@ -704,9 +704,13 @@ interface ComboboxProps {
704
704
  }
705
705
  declare const Combobox: React$1.FC<ComboboxProps>;
706
706
 
707
+ interface MultiComboboxOption {
708
+ value: string;
709
+ label: string;
710
+ }
707
711
  interface MultiComboboxProps {
708
712
  id?: string;
709
- options: string[];
713
+ options: Array<string | MultiComboboxOption>;
710
714
  value: string[];
711
715
  onChange: (value: string[]) => void;
712
716
  placeholder?: string;
@@ -718,7 +722,9 @@ interface MultiComboboxProps {
718
722
  disabled?: boolean;
719
723
  size?: 'sm' | 'md' | 'lg';
720
724
  label?: string;
725
+ title?: string;
721
726
  required?: boolean;
727
+ displayFormat?: (option: MultiComboboxOption) => string;
722
728
  }
723
729
  declare const MultiCombobox: React$1.FC<MultiComboboxProps>;
724
730
 
package/dist/index.d.ts CHANGED
@@ -660,7 +660,7 @@ declare const ScrollArea: React$1.ForwardRefExoticComponent<ScrollAreaProps & Re
660
660
  interface DatePickerProps {
661
661
  id?: string;
662
662
  value?: Date;
663
- onChange: (date: Date) => void;
663
+ onChange: (date: Date | undefined) => void;
664
664
  placeholder?: string;
665
665
  className?: string;
666
666
  disabled?: boolean;
@@ -704,9 +704,13 @@ interface ComboboxProps {
704
704
  }
705
705
  declare const Combobox: React$1.FC<ComboboxProps>;
706
706
 
707
+ interface MultiComboboxOption {
708
+ value: string;
709
+ label: string;
710
+ }
707
711
  interface MultiComboboxProps {
708
712
  id?: string;
709
- options: string[];
713
+ options: Array<string | MultiComboboxOption>;
710
714
  value: string[];
711
715
  onChange: (value: string[]) => void;
712
716
  placeholder?: string;
@@ -718,7 +722,9 @@ interface MultiComboboxProps {
718
722
  disabled?: boolean;
719
723
  size?: 'sm' | 'md' | 'lg';
720
724
  label?: string;
725
+ title?: string;
721
726
  required?: boolean;
727
+ displayFormat?: (option: MultiComboboxOption) => string;
722
728
  }
723
729
  declare const MultiCombobox: React$1.FC<MultiComboboxProps>;
724
730
 
package/dist/index.js CHANGED
@@ -3819,7 +3819,11 @@ var Combobox = ({
3819
3819
  const autoId = useId2();
3820
3820
  const resolvedId = id ? String(id) : `combobox-${autoId}`;
3821
3821
  const labelId = label ? `${resolvedId}-label` : void 0;
3822
- const filteredOptions = React18.useMemo(() => options.filter((o) => getOptionLabel(o).toLowerCase().includes(query.toLowerCase())), [options, query]);
3822
+ const enableSearch = options.length > 10;
3823
+ const filteredOptions = React18.useMemo(
3824
+ () => enableSearch ? options.filter((o) => getOptionLabel(o).toLowerCase().includes(query.toLowerCase())) : options,
3825
+ [options, query, enableSearch]
3826
+ );
3823
3827
  const [dropdownPosition, setDropdownPosition] = React18.useState(null);
3824
3828
  const triggerRef = React18.useRef(null);
3825
3829
  const calculatePosition = React18.useCallback(() => {
@@ -3886,12 +3890,12 @@ var Combobox = ({
3886
3890
  if (!open) {
3887
3891
  setQuery("");
3888
3892
  setActiveIndex(null);
3889
- } else {
3893
+ } else if (enableSearch) {
3890
3894
  setTimeout(() => {
3891
3895
  inputRef.current?.focus();
3892
3896
  }, 100);
3893
3897
  }
3894
- }, [open]);
3898
+ }, [open, enableSearch]);
3895
3899
  const selectedOption = findOptionByValue(options, value);
3896
3900
  const displayValue = selectedOption ? getOptionLabel(selectedOption) : "";
3897
3901
  const dropdownContent = /* @__PURE__ */ jsx23(
@@ -3914,7 +3918,7 @@ var Combobox = ({
3914
3918
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
3915
3919
  ),
3916
3920
  children: /* @__PURE__ */ jsxs21("div", { className: cn("rounded-md border bg-popover text-popover-foreground shadow-md", "backdrop-blur-sm bg-popover/95 border-border/60"), children: [
3917
- /* @__PURE__ */ jsxs21("div", { className: "relative p-3 border-b border-border/50 bg-muted/20", children: [
3921
+ enableSearch && /* @__PURE__ */ jsxs21("div", { className: "relative p-3 border-b border-border/50 bg-muted/20", children: [
3918
3922
  /* @__PURE__ */ jsx23(Search2, { className: "absolute left-6 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground transition-colors" }),
3919
3923
  /* @__PURE__ */ jsx23(
3920
3924
  "input",
@@ -4043,11 +4047,12 @@ var Combobox = ({
4043
4047
  setOpen(next);
4044
4048
  },
4045
4049
  className: cn(
4046
- "flex w-full items-center justify-between border border-input bg-background px-3 vanh",
4050
+ "flex w-full items-center justify-between border border-input bg-background px-3",
4047
4051
  radiusClass,
4048
4052
  sizeStyles8[size],
4049
- "ring-offset-background placeholder:text-muted-foreground outline-none focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 focus:ring-offset-0",
4053
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
4050
4054
  "disabled:cursor-not-allowed disabled:opacity-50",
4055
+ "hover:bg-accent/5 transition-colors hover:border-primary/40 focus:border-primary",
4051
4056
  className
4052
4057
  ),
4053
4058
  children: [
@@ -4412,7 +4417,7 @@ ScrollArea.displayName = "ScrollArea";
4412
4417
  import * as React21 from "react";
4413
4418
  import { useId as useId3 } from "react";
4414
4419
  import { createPortal as createPortal7 } from "react-dom";
4415
- import { Calendar, ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight3 } from "lucide-react";
4420
+ import { Calendar, ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight3, X as XIcon } from "lucide-react";
4416
4421
  import { useTranslations as useTranslations5, useLocale } from "next-intl";
4417
4422
 
4418
4423
  // ../../lib/utils/date.ts
@@ -4616,6 +4621,7 @@ var DatePicker = ({
4616
4621
  const [dropdownPosition, setDropdownPosition] = React21.useState(null);
4617
4622
  const [viewDate, setViewDate] = React21.useState(value || /* @__PURE__ */ new Date());
4618
4623
  const triggerRef = React21.useRef(null);
4624
+ const dropdownRef = React21.useRef(null);
4619
4625
  useShadCNAnimations();
4620
4626
  const calculatePosition = React21.useCallback(() => {
4621
4627
  if (!triggerRef.current) return null;
@@ -4641,15 +4647,24 @@ var DatePicker = ({
4641
4647
  window.removeEventListener("scroll", handler, true);
4642
4648
  };
4643
4649
  }, [isOpen, calculatePosition]);
4650
+ React21.useEffect(() => {
4651
+ if (value) {
4652
+ setViewDate(value);
4653
+ } else {
4654
+ setViewDate(/* @__PURE__ */ new Date());
4655
+ }
4656
+ }, [value]);
4644
4657
  React21.useEffect(() => {
4645
4658
  if (!isOpen) return;
4646
4659
  const handleClickOutside = (event) => {
4647
4660
  const target = event.target;
4648
- if (triggerRef.current && !triggerRef.current.contains(target)) {
4649
- const dropdown = document.querySelector("[data-datepicker]");
4650
- if (dropdown && !dropdown.contains(target)) {
4651
- setIsOpen(false);
4652
- }
4661
+ const trigger = triggerRef.current;
4662
+ const dropdown = dropdownRef.current;
4663
+ if (!trigger || !dropdown) return;
4664
+ const clickedOutsideTrigger = !trigger.contains(target);
4665
+ const clickedOutsideDropdown = !dropdown.contains(target);
4666
+ if (clickedOutsideTrigger && clickedOutsideDropdown) {
4667
+ setIsOpen(false);
4653
4668
  }
4654
4669
  };
4655
4670
  const handleEscape = (event) => {
@@ -4665,11 +4680,18 @@ var DatePicker = ({
4665
4680
  };
4666
4681
  }, [isOpen]);
4667
4682
  const handleDateSelect = (date) => {
4668
- onChange(date);
4683
+ let selectedDate;
4684
+ if (value && (value.getHours() !== 0 || value.getMinutes() !== 0 || value.getSeconds() !== 0)) {
4685
+ selectedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), value.getHours(), value.getMinutes(), value.getSeconds());
4686
+ } else {
4687
+ const now = /* @__PURE__ */ new Date();
4688
+ selectedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
4689
+ }
4690
+ onChange(selectedDate);
4669
4691
  setIsOpen(false);
4670
4692
  };
4671
4693
  const formatDateDisplay = (date) => {
4672
- return locale === "vi" /* VI */ ? formatDate(date) : formatDateShort(date);
4694
+ return formatDate(date);
4673
4695
  };
4674
4696
  const getDaysInMonth = (date) => {
4675
4697
  return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
@@ -4730,7 +4752,8 @@ var DatePicker = ({
4730
4752
  top: dropdownPosition?.top || 0,
4731
4753
  left: dropdownPosition?.left || 0,
4732
4754
  width: size === "sm" ? dropdownPosition?.width || 224 : dropdownPosition?.width || 256,
4733
- zIndex: 9999
4755
+ zIndex: 9999,
4756
+ pointerEvents: "none"
4734
4757
  },
4735
4758
  "data-state": isOpen ? "open" : "closed",
4736
4759
  className: cn(
@@ -4741,11 +4764,13 @@ var DatePicker = ({
4741
4764
  children: /* @__PURE__ */ jsxs23(
4742
4765
  "div",
4743
4766
  {
4767
+ ref: dropdownRef,
4744
4768
  className: cn(
4745
4769
  "rounded-md border bg-popover text-popover-foreground shadow-md",
4746
4770
  "backdrop-blur-sm bg-popover/95 border-border/60",
4747
4771
  size === "sm" ? "p-3 w-56" : "p-4 w-64"
4748
4772
  ),
4773
+ style: { pointerEvents: "auto" },
4749
4774
  children: [
4750
4775
  /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between mb-4", children: [
4751
4776
  /* @__PURE__ */ jsx27(Button_default, { variant: "ghost", size: "sm", onClick: () => navigateMonth("prev"), className: "p-1 h-auto", children: /* @__PURE__ */ jsx27(ChevronLeft2, { className: "h-4 w-4" }) }),
@@ -4753,7 +4778,20 @@ var DatePicker = ({
4753
4778
  /* @__PURE__ */ jsx27(Button_default, { variant: "ghost", size: "sm", onClick: () => navigateMonth("next"), className: "p-1 h-auto", children: /* @__PURE__ */ jsx27(ChevronRight3, { className: "h-4 w-4" }) })
4754
4779
  ] }),
4755
4780
  /* @__PURE__ */ jsx27("div", { className: cn("grid grid-cols-7 gap-1", size === "sm" ? "mb-1" : "mb-2"), children: (weekdayLabels || ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]).map((day) => /* @__PURE__ */ jsx27("div", { className: cn("text-muted-foreground text-center font-medium", size === "sm" ? "text-[10px] py-0.5" : "text-xs py-1"), children: day }, day)) }),
4756
- /* @__PURE__ */ jsx27("div", { className: "grid grid-cols-7 gap-1", children: renderCalendar() })
4781
+ /* @__PURE__ */ jsx27("div", { className: "grid grid-cols-7 gap-1", children: renderCalendar() }),
4782
+ /* @__PURE__ */ jsx27("div", { className: "flex items-center justify-end mt-2", children: /* @__PURE__ */ jsx27(
4783
+ Button_default,
4784
+ {
4785
+ variant: "outline",
4786
+ size: "sm",
4787
+ onClick: () => {
4788
+ onChange(void 0);
4789
+ setIsOpen(false);
4790
+ setViewDate(/* @__PURE__ */ new Date());
4791
+ },
4792
+ children: clearLabel || t("clear")
4793
+ }
4794
+ ) })
4757
4795
  ]
4758
4796
  }
4759
4797
  )
@@ -4811,6 +4849,31 @@ var DatePicker = ({
4811
4849
  ),
4812
4850
  children: [
4813
4851
  /* @__PURE__ */ jsx27("span", { className: cn("truncate", !value && "text-muted-foreground"), children: value ? formatDateDisplay(value) : placeholder || t("placeholder") }),
4852
+ value && /* @__PURE__ */ jsx27(
4853
+ "span",
4854
+ {
4855
+ role: "button",
4856
+ "aria-label": clearLabel || t("clear"),
4857
+ tabIndex: 0,
4858
+ onClick: (e) => {
4859
+ e.preventDefault();
4860
+ e.stopPropagation();
4861
+ onChange(void 0);
4862
+ setViewDate(/* @__PURE__ */ new Date());
4863
+ },
4864
+ onKeyDown: (e) => {
4865
+ if (e.key === "Enter" || e.key === " ") {
4866
+ e.preventDefault();
4867
+ e.stopPropagation();
4868
+ onChange(void 0);
4869
+ setViewDate(/* @__PURE__ */ new Date());
4870
+ }
4871
+ },
4872
+ className: "absolute right-8 inline-flex items-center justify-center rounded-sm text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors cursor-pointer",
4873
+ style: { width: 20, height: 20 },
4874
+ children: /* @__PURE__ */ jsx27(XIcon, { className: "h-3.5 w-3.5" })
4875
+ }
4876
+ ),
4814
4877
  /* @__PURE__ */ jsx27(Calendar, { className: "h-4 w-4 text-muted-foreground ml-2" })
4815
4878
  ]
4816
4879
  }
@@ -5048,7 +5111,9 @@ var MultiCombobox = ({
5048
5111
  disabled = false,
5049
5112
  size = "md",
5050
5113
  label,
5051
- required
5114
+ title,
5115
+ required,
5116
+ displayFormat = (option) => option.label
5052
5117
  }) => {
5053
5118
  const [query, setQuery] = React22.useState("");
5054
5119
  const [open, setOpen] = React22.useState(false);
@@ -5105,14 +5170,22 @@ var MultiCombobox = ({
5105
5170
  document.removeEventListener("keydown", handleEscape);
5106
5171
  };
5107
5172
  }, [open]);
5108
- const filtered = options.filter((o) => o.toLowerCase().includes(query.toLowerCase()));
5109
- const toggleSelect = (val) => {
5110
- if (disabledOptions.includes(val)) return;
5111
- if (value.includes(val)) {
5112
- onChange(value.filter((v) => v !== val));
5173
+ const normalizedOptions = React22.useMemo(
5174
+ () => options.map((o) => typeof o === "string" ? { value: o, label: o } : { value: o.value, label: o.label }),
5175
+ [options]
5176
+ );
5177
+ const enableSearch = normalizedOptions.length > 10;
5178
+ const filtered = React22.useMemo(
5179
+ () => enableSearch ? normalizedOptions.filter((opt) => opt.label.toLowerCase().includes(query.toLowerCase())) : normalizedOptions,
5180
+ [normalizedOptions, query, enableSearch]
5181
+ );
5182
+ const toggleSelect = (optionValue) => {
5183
+ if (disabledOptions.includes(optionValue)) return;
5184
+ if (value.includes(optionValue)) {
5185
+ onChange(value.filter((v) => v !== optionValue));
5113
5186
  } else {
5114
5187
  if (!maxSelected || value.length < maxSelected) {
5115
- onChange([...value, val]);
5188
+ onChange([...value, optionValue]);
5116
5189
  }
5117
5190
  }
5118
5191
  };
@@ -5124,7 +5197,7 @@ var MultiCombobox = ({
5124
5197
  if (e.key === "Enter") {
5125
5198
  e.preventDefault();
5126
5199
  if (activeIndex !== null && filtered[activeIndex]) {
5127
- toggleSelect(filtered[activeIndex]);
5200
+ toggleSelect(filtered[activeIndex].value);
5128
5201
  }
5129
5202
  }
5130
5203
  };
@@ -5132,12 +5205,12 @@ var MultiCombobox = ({
5132
5205
  onChange([]);
5133
5206
  };
5134
5207
  React22.useEffect(() => {
5135
- if (open) {
5208
+ if (open && enableSearch) {
5136
5209
  setTimeout(() => {
5137
5210
  inputRef.current?.focus();
5138
5211
  }, 100);
5139
5212
  }
5140
- }, [open]);
5213
+ }, [open, enableSearch]);
5141
5214
  const sizeStyles8 = {
5142
5215
  sm: {
5143
5216
  trigger: "h-8 px-3 py-1.5 text-sm md:h-7 md:text-xs",
@@ -5166,6 +5239,20 @@ var MultiCombobox = ({
5166
5239
  const labelId = label ? `${resolvedId}-label` : void 0;
5167
5240
  const labelSize = size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm";
5168
5241
  return /* @__PURE__ */ jsxs24("div", { className: cn("w-full space-y-2 group", className), children: [
5242
+ title && /* @__PURE__ */ jsx28("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs24(
5243
+ "label",
5244
+ {
5245
+ className: cn(
5246
+ size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm",
5247
+ "font-medium transition-colors duration-200",
5248
+ disabled ? "text-muted-foreground" : "text-foreground group-focus-within:text-primary"
5249
+ ),
5250
+ children: [
5251
+ title,
5252
+ required && /* @__PURE__ */ jsx28("span", { className: "text-destructive ml-1", children: "*" })
5253
+ ]
5254
+ }
5255
+ ) }),
5169
5256
  label && /* @__PURE__ */ jsxs24(
5170
5257
  "label",
5171
5258
  {
@@ -5182,148 +5269,152 @@ var MultiCombobox = ({
5182
5269
  ]
5183
5270
  }
5184
5271
  ),
5185
- /* @__PURE__ */ jsxs24("div", { className: "relative w-full", children: [
5186
- /* @__PURE__ */ jsxs24("div", { className: "flex flex-wrap gap-1", children: [
5187
- showTags && value.map((item) => /* @__PURE__ */ jsxs24("span", { className: cn("flex items-center gap-1 rounded bg-accent text-accent-foreground", sizeStyles8[size].tag), children: [
5188
- item,
5189
- /* @__PURE__ */ jsx28(
5190
- "button",
5191
- {
5192
- type: "button",
5193
- onClick: (e) => {
5194
- e.preventDefault();
5195
- e.stopPropagation();
5196
- handleRemove(item);
5197
- },
5198
- className: "text-xs hover:text-destructive",
5199
- children: "\xD7"
5200
- }
5201
- )
5202
- ] }, item)),
5203
- showClear && value.length > 0 && /* @__PURE__ */ jsx28(
5204
- "button",
5205
- {
5206
- type: "button",
5207
- onClick: (e) => {
5208
- e.preventDefault();
5209
- e.stopPropagation();
5210
- handleClearAll();
5211
- },
5212
- className: "ml-auto text-xs text-muted-foreground hover:underline",
5213
- children: "Clear all"
5272
+ /* @__PURE__ */ jsx28("div", { className: "relative w-full" }),
5273
+ /* @__PURE__ */ jsxs24(
5274
+ "button",
5275
+ {
5276
+ ref: triggerRef,
5277
+ type: "button",
5278
+ disabled,
5279
+ id: resolvedId,
5280
+ "aria-labelledby": labelId,
5281
+ onClick: () => {
5282
+ const next = !open;
5283
+ if (next) {
5284
+ const pos = calculatePosition();
5285
+ if (pos) setDropdownPosition(pos);
5214
5286
  }
5215
- )
5216
- ] }),
5217
- /* @__PURE__ */ jsxs24(
5218
- "button",
5287
+ setOpen(next);
5288
+ },
5289
+ className: cn(
5290
+ "flex w-full items-center gap-2 rounded-lg border border-input bg-background shadow-sm min-h-[2.5rem]",
5291
+ "px-3 py-2",
5292
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
5293
+ "disabled:cursor-not-allowed disabled:opacity-50"
5294
+ ),
5295
+ children: [
5296
+ /* @__PURE__ */ jsx28("div", { className: "flex items-center gap-1 flex-wrap min-h-[1.5rem] flex-1", children: value.length > 0 ? showTags ? value.map((itemValue) => {
5297
+ const option = normalizedOptions.find((o) => o.value === itemValue);
5298
+ return /* @__PURE__ */ jsxs24("span", { className: "inline-flex items-center gap-1 bg-accent text-accent-foreground rounded px-2 py-1 text-xs", children: [
5299
+ /* @__PURE__ */ jsx28("span", { className: "truncate max-w-[120px]", children: option ? displayFormat(option) : itemValue }),
5300
+ /* @__PURE__ */ jsx28(
5301
+ "button",
5302
+ {
5303
+ type: "button",
5304
+ onClick: (e) => {
5305
+ e.preventDefault();
5306
+ e.stopPropagation();
5307
+ handleRemove(itemValue);
5308
+ },
5309
+ className: "hover:text-destructive transition-colors cursor-pointer",
5310
+ children: "\xD7"
5311
+ }
5312
+ )
5313
+ ] }, itemValue);
5314
+ }) : /* @__PURE__ */ jsxs24("span", { className: "truncate text-sm", children: [
5315
+ value.length,
5316
+ " selected"
5317
+ ] }) : /* @__PURE__ */ jsx28("span", { className: "text-muted-foreground", children: placeholder || "Select..." }) }),
5318
+ /* @__PURE__ */ jsx28(ChevronDown2, { className: cn("opacity-50 transition-transform", sizeStyles8[size].icon, open && "rotate-180") })
5319
+ ]
5320
+ }
5321
+ ),
5322
+ open && dropdownPosition && typeof window !== "undefined" ? createPortal8(
5323
+ /* @__PURE__ */ jsx28(
5324
+ "div",
5219
5325
  {
5220
- ref: triggerRef,
5221
- type: "button",
5222
- disabled,
5223
- id: resolvedId,
5224
- "aria-labelledby": labelId,
5225
- onClick: () => {
5226
- const next = !open;
5227
- if (next) {
5228
- const pos = calculatePosition();
5229
- if (pos) setDropdownPosition(pos);
5230
- }
5231
- setOpen(next);
5326
+ "data-dropdown": "multicombobox",
5327
+ style: {
5328
+ position: "absolute",
5329
+ top: dropdownPosition?.top || 0,
5330
+ left: dropdownPosition?.left || 0,
5331
+ width: dropdownPosition?.width || 200,
5332
+ zIndex: 9999
5232
5333
  },
5334
+ "data-state": open ? "open" : "closed",
5233
5335
  className: cn(
5234
- "flex w-full items-center justify-between rounded-lg border border-input bg-background shadow-sm",
5235
- sizeStyles8[size].trigger,
5236
- "outline-none focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 focus:ring-offset-0",
5237
- "disabled:cursor-not-allowed disabled:opacity-50"
5336
+ "z-[9999]",
5337
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
5338
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
5238
5339
  ),
5239
- children: [
5240
- /* @__PURE__ */ jsx28("span", { className: "truncate", children: value.length ? `${value.length} selected` : placeholder || "Select..." }),
5241
- /* @__PURE__ */ jsx28(ChevronDown2, { className: cn("opacity-50 transition-transform", sizeStyles8[size].icon, open && "rotate-180") })
5242
- ]
5340
+ children: /* @__PURE__ */ jsxs24(
5341
+ "div",
5342
+ {
5343
+ className: cn(
5344
+ "rounded-md border bg-popover text-popover-foreground shadow-md",
5345
+ "backdrop-blur-sm bg-popover/95 border-border/60"
5346
+ ),
5347
+ children: [
5348
+ showClear && value.length > 0 && /* @__PURE__ */ jsx28("div", { className: "px-3 py-2 border-b border-border/60 flex justify-end", children: /* @__PURE__ */ jsx28(
5349
+ "button",
5350
+ {
5351
+ type: "button",
5352
+ onClick: (e) => {
5353
+ e.preventDefault();
5354
+ e.stopPropagation();
5355
+ handleClearAll();
5356
+ },
5357
+ className: "text-xs text-muted-foreground hover:underline cursor-pointer",
5358
+ children: "Clear all"
5359
+ }
5360
+ ) }),
5361
+ enableSearch && /* @__PURE__ */ jsxs24("div", { className: "relative border-b border-border/60", children: [
5362
+ /* @__PURE__ */ jsx28(Search3, { className: cn("absolute left-2 top-2.5 text-muted-foreground", sizeStyles8[size].icon) }),
5363
+ /* @__PURE__ */ jsx28(
5364
+ "input",
5365
+ {
5366
+ ref: inputRef,
5367
+ value: query,
5368
+ onChange: (e) => {
5369
+ setQuery(e.target.value);
5370
+ setActiveIndex(null);
5371
+ },
5372
+ onKeyDown: handleKeyDown,
5373
+ placeholder,
5374
+ className: cn("w-full rounded-t-md bg-transparent focus:outline-none cursor-text", sizeStyles8[size].search)
5375
+ }
5376
+ )
5377
+ ] }),
5378
+ /* @__PURE__ */ jsx28("ul", { className: cn("max-h-60 overflow-y-auto p-1", size === "lg" ? "text-base" : size === "sm" ? "text-xs" : "text-sm"), children: filtered.length ? filtered.map((item, index) => {
5379
+ const isSelected = value.includes(item.value);
5380
+ const isDisabled = disabledOptions.includes(item.value);
5381
+ return /* @__PURE__ */ jsxs24(
5382
+ "li",
5383
+ {
5384
+ ref: (node) => {
5385
+ listRef.current[index] = node;
5386
+ },
5387
+ onClick: (e) => {
5388
+ e.preventDefault();
5389
+ e.stopPropagation();
5390
+ toggleSelect(item.value);
5391
+ inputRef.current?.focus();
5392
+ },
5393
+ style: {
5394
+ animationDelay: open ? `${index * 25}ms` : "0ms"
5395
+ },
5396
+ className: cn(
5397
+ "dropdown-item flex cursor-pointer items-center justify-between rounded-sm transition-colors",
5398
+ sizeStyles8[size].item,
5399
+ "hover:bg-accent hover:text-accent-foreground",
5400
+ index === activeIndex && "bg-accent text-accent-foreground",
5401
+ isDisabled && "opacity-50 cursor-not-allowed pointer-events-none"
5402
+ ),
5403
+ children: [
5404
+ item.label,
5405
+ isSelected && /* @__PURE__ */ jsx28(Check4, { className: sizeStyles8[size].icon })
5406
+ ]
5407
+ },
5408
+ item.value
5409
+ );
5410
+ }) : /* @__PURE__ */ jsx28("li", { className: cn("px-3 py-2 text-muted-foreground", size === "lg" ? "text-base" : size === "sm" ? "text-xs" : "text-sm"), children: "No result." }) })
5411
+ ]
5412
+ }
5413
+ )
5243
5414
  }
5244
5415
  ),
5245
- open && dropdownPosition && typeof window !== "undefined" && createPortal8(
5246
- /* @__PURE__ */ jsx28(
5247
- "div",
5248
- {
5249
- "data-dropdown": "multicombobox",
5250
- style: {
5251
- position: "absolute",
5252
- top: dropdownPosition?.top || 0,
5253
- left: dropdownPosition?.left || 0,
5254
- width: dropdownPosition?.width || 200,
5255
- zIndex: 9999
5256
- },
5257
- "data-state": open ? "open" : "closed",
5258
- className: cn(
5259
- "z-[9999]",
5260
- "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
5261
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
5262
- ),
5263
- children: /* @__PURE__ */ jsxs24(
5264
- "div",
5265
- {
5266
- className: cn(
5267
- "rounded-md border bg-popover text-popover-foreground shadow-md",
5268
- "backdrop-blur-sm bg-popover/95 border-border/60"
5269
- ),
5270
- children: [
5271
- /* @__PURE__ */ jsxs24("div", { className: "relative border-b border-border/60", children: [
5272
- /* @__PURE__ */ jsx28(Search3, { className: cn("absolute left-2 top-2.5 text-muted-foreground", sizeStyles8[size].icon) }),
5273
- /* @__PURE__ */ jsx28(
5274
- "input",
5275
- {
5276
- ref: inputRef,
5277
- value: query,
5278
- onChange: (e) => {
5279
- setQuery(e.target.value);
5280
- setActiveIndex(null);
5281
- },
5282
- onKeyDown: handleKeyDown,
5283
- placeholder,
5284
- className: cn("w-full rounded-t-md bg-transparent focus:outline-none", sizeStyles8[size].search)
5285
- }
5286
- )
5287
- ] }),
5288
- /* @__PURE__ */ jsx28("ul", { className: cn("max-h-60 overflow-y-auto p-1", size === "lg" ? "text-base" : size === "sm" ? "text-xs" : "text-sm"), children: filtered.length ? filtered.map((item, index) => {
5289
- const isSelected = value.includes(item);
5290
- const isDisabled = disabledOptions.includes(item);
5291
- return /* @__PURE__ */ jsxs24(
5292
- "li",
5293
- {
5294
- ref: (node) => {
5295
- listRef.current[index] = node;
5296
- },
5297
- onClick: () => {
5298
- toggleSelect(item);
5299
- inputRef.current?.focus();
5300
- },
5301
- style: {
5302
- animationDelay: open ? `${index * 25}ms` : "0ms"
5303
- },
5304
- className: cn(
5305
- "dropdown-item flex cursor-pointer items-center justify-between rounded-sm transition-colors",
5306
- sizeStyles8[size].item,
5307
- "hover:bg-accent hover:text-accent-foreground",
5308
- index === activeIndex && "bg-accent text-accent-foreground",
5309
- isDisabled && "opacity-50 cursor-not-allowed pointer-events-none"
5310
- ),
5311
- children: [
5312
- item,
5313
- isSelected && /* @__PURE__ */ jsx28(Check4, { className: sizeStyles8[size].icon })
5314
- ]
5315
- },
5316
- item
5317
- );
5318
- }) : /* @__PURE__ */ jsx28("li", { className: cn("px-3 py-2 text-muted-foreground", size === "lg" ? "text-base" : size === "sm" ? "text-xs" : "text-sm"), children: "No result." }) })
5319
- ]
5320
- }
5321
- )
5322
- }
5323
- ),
5324
- document.body
5325
- )
5326
- ] })
5416
+ document.body
5417
+ ) : null
5327
5418
  ] });
5328
5419
  };
5329
5420