@page-speed/forms 0.4.4 → 0.4.6

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/inputs.js CHANGED
@@ -1,4 +1,4 @@
1
- import * as React8 from 'react';
1
+ import * as React9 from 'react';
2
2
  import { clsx } from 'clsx';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import { useOnClickOutside } from '@opensite/hooks/useOnClickOutside';
@@ -40,7 +40,7 @@ function TextInput({
40
40
  error && "border-destructive ring-1 ring-destructive",
41
41
  className
42
42
  );
43
- return /* @__PURE__ */ React8.createElement(
43
+ return /* @__PURE__ */ React9.createElement(
44
44
  "input",
45
45
  {
46
46
  type,
@@ -94,7 +94,7 @@ function TextArea({
94
94
  error && "border-destructive ring-1 ring-destructive",
95
95
  className
96
96
  );
97
- return /* @__PURE__ */ React8.createElement(
97
+ return /* @__PURE__ */ React9.createElement(
98
98
  "textarea",
99
99
  {
100
100
  name,
@@ -133,11 +133,11 @@ var LabelGroup = ({
133
133
  variant === "legend" ? "mb-1.5" : "mb-1 block",
134
134
  primaryClassName
135
135
  );
136
- const requiredIndicator = required ? /* @__PURE__ */ React8.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
136
+ const requiredIndicator = required ? /* @__PURE__ */ React9.createElement("span", { className: "text-destructive pl-0.5", "aria-label": "required" }, "*") : null;
137
137
  let primaryElement = null;
138
138
  if (primary) {
139
139
  if (variant === "label") {
140
- primaryElement = /* @__PURE__ */ React8.createElement(
140
+ primaryElement = /* @__PURE__ */ React9.createElement(
141
141
  "label",
142
142
  {
143
143
  htmlFor: labelHtmlFor,
@@ -148,12 +148,12 @@ var LabelGroup = ({
148
148
  requiredIndicator
149
149
  );
150
150
  } else if (variant === "legend") {
151
- primaryElement = /* @__PURE__ */ React8.createElement("legend", { "data-slot": "field-legend", className: primaryClasses }, primary, requiredIndicator);
151
+ primaryElement = /* @__PURE__ */ React9.createElement("legend", { "data-slot": "field-legend", className: primaryClasses }, primary, requiredIndicator);
152
152
  } else {
153
- primaryElement = /* @__PURE__ */ React8.createElement("div", { "data-slot": "field-label", className: primaryClasses }, primary, requiredIndicator);
153
+ primaryElement = /* @__PURE__ */ React9.createElement("div", { "data-slot": "field-label", className: primaryClasses }, primary, requiredIndicator);
154
154
  }
155
155
  }
156
- const secondaryElement = secondary ? /* @__PURE__ */ React8.createElement(
156
+ const secondaryElement = secondary ? /* @__PURE__ */ React9.createElement(
157
157
  "p",
158
158
  {
159
159
  "data-slot": "field-description",
@@ -163,7 +163,10 @@ var LabelGroup = ({
163
163
  secondary
164
164
  ) : null;
165
165
  if (!primaryElement && !secondaryElement) return null;
166
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, primaryElement, secondaryElement);
166
+ if (variant === "legend") {
167
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, primaryElement, secondaryElement);
168
+ }
169
+ return /* @__PURE__ */ React9.createElement("div", { className: "flex flex-1 flex-col gap-0.5" }, primaryElement, secondaryElement);
167
170
  };
168
171
 
169
172
  // src/inputs/Checkbox.tsx
@@ -182,9 +185,9 @@ function Checkbox({
182
185
  useChoiceCard = false,
183
186
  ...props
184
187
  }) {
185
- const inputRef = React8.useRef(null);
188
+ const inputRef = React9.useRef(null);
186
189
  const checkboxId = props.id || `checkbox-${name}`;
187
- React8.useEffect(() => {
190
+ React9.useEffect(() => {
188
191
  if (inputRef.current) {
189
192
  inputRef.current.indeterminate = indeterminate;
190
193
  }
@@ -196,7 +199,7 @@ function Checkbox({
196
199
  onBlur?.();
197
200
  };
198
201
  const isActive = value || indeterminate && !value;
199
- const checkbox = /* @__PURE__ */ React8.createElement(
202
+ const checkbox = /* @__PURE__ */ React9.createElement(
200
203
  "div",
201
204
  {
202
205
  className: cn(
@@ -204,7 +207,7 @@ function Checkbox({
204
207
  !label && className
205
208
  )
206
209
  },
207
- /* @__PURE__ */ React8.createElement(
210
+ /* @__PURE__ */ React9.createElement(
208
211
  "input",
209
212
  {
210
213
  ref: inputRef,
@@ -223,7 +226,7 @@ function Checkbox({
223
226
  ...props
224
227
  }
225
228
  ),
226
- /* @__PURE__ */ React8.createElement(
229
+ /* @__PURE__ */ React9.createElement(
227
230
  "div",
228
231
  {
229
232
  className: cn(
@@ -236,7 +239,7 @@ function Checkbox({
236
239
  "peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-1"
237
240
  )
238
241
  },
239
- value && /* @__PURE__ */ React8.createElement(
242
+ value && /* @__PURE__ */ React9.createElement(
240
243
  "svg",
241
244
  {
242
245
  className: "size-3.5",
@@ -247,9 +250,9 @@ function Checkbox({
247
250
  strokeLinecap: "round",
248
251
  strokeLinejoin: "round"
249
252
  },
250
- /* @__PURE__ */ React8.createElement("polyline", { points: "20 6 9 17 4 12" })
253
+ /* @__PURE__ */ React9.createElement("polyline", { points: "20 6 9 17 4 12" })
251
254
  ),
252
- indeterminate && !value && /* @__PURE__ */ React8.createElement(
255
+ indeterminate && !value && /* @__PURE__ */ React9.createElement(
253
256
  "svg",
254
257
  {
255
258
  className: "size-3.5",
@@ -260,12 +263,12 @@ function Checkbox({
260
263
  strokeLinecap: "round",
261
264
  strokeLinejoin: "round"
262
265
  },
263
- /* @__PURE__ */ React8.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
266
+ /* @__PURE__ */ React9.createElement("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
264
267
  )
265
268
  )
266
269
  );
267
270
  if (label) {
268
- return /* @__PURE__ */ React8.createElement(
271
+ return /* @__PURE__ */ React9.createElement(
269
272
  "label",
270
273
  {
271
274
  className: cn(
@@ -277,7 +280,7 @@ function Checkbox({
277
280
  ),
278
281
  htmlFor: checkboxId
279
282
  },
280
- /* @__PURE__ */ React8.createElement(
283
+ /* @__PURE__ */ React9.createElement(
281
284
  "div",
282
285
  {
283
286
  className: cn(
@@ -286,7 +289,7 @@ function Checkbox({
286
289
  )
287
290
  },
288
291
  checkbox,
289
- /* @__PURE__ */ React8.createElement(
292
+ /* @__PURE__ */ React9.createElement(
290
293
  LabelGroup,
291
294
  {
292
295
  variant: "text",
@@ -331,11 +334,11 @@ function CheckboxGroup({
331
334
  ).length;
332
335
  const allSelected = selectedEnabledCount === enabledOptions.length;
333
336
  const someSelected = selectedEnabledCount > 0 && !allSelected;
334
- const useChoiceCard = React8.useMemo(() => {
337
+ const useChoiceCard = React9.useMemo(() => {
335
338
  if (!options) return false;
336
339
  return options?.some((opt) => opt.description);
337
340
  }, [options]);
338
- const countableValue = React8.useMemo(() => {
341
+ const countableValue = React9.useMemo(() => {
339
342
  if (value?.length > 0) {
340
343
  return value.length;
341
344
  }
@@ -360,7 +363,7 @@ function CheckboxGroup({
360
363
  onBlur?.();
361
364
  };
362
365
  const maxReached = Boolean(maxSelections && countableValue >= maxSelections);
363
- const containerClass = React8.useMemo(() => {
366
+ const containerClass = React9.useMemo(() => {
364
367
  return cn(
365
368
  "w-full gap-3 grid grid-cols-1 border-0 m-0 p-0 min-w-0",
366
369
  (layout === "grid" || layout === "inline") && "md:grid-cols-2",
@@ -369,7 +372,7 @@ function CheckboxGroup({
369
372
  }, [layout, className]);
370
373
  const groupDescriptionId = description ? `${name}-description` : void 0;
371
374
  const groupAriaDescribedBy = [props["aria-describedby"], groupDescriptionId].filter(Boolean).join(" ") || void 0;
372
- return /* @__PURE__ */ React8.createElement(
375
+ return /* @__PURE__ */ React9.createElement(
373
376
  "fieldset",
374
377
  {
375
378
  className: containerClass,
@@ -379,7 +382,7 @@ function CheckboxGroup({
379
382
  "aria-required": required || props["aria-required"],
380
383
  "aria-label": typeof label === "string" ? label : props["aria-label"]
381
384
  },
382
- /* @__PURE__ */ React8.createElement(
385
+ /* @__PURE__ */ React9.createElement(
383
386
  LabelGroup,
384
387
  {
385
388
  labelHtmlFor: name,
@@ -390,7 +393,7 @@ function CheckboxGroup({
390
393
  primary: label
391
394
  }
392
395
  ),
393
- showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */ React8.createElement(
396
+ showSelectAll && enabledOptions.length > 0 && /* @__PURE__ */ React9.createElement(
394
397
  Checkbox,
395
398
  {
396
399
  name: `${name}-select-all`,
@@ -408,7 +411,7 @@ function CheckboxGroup({
408
411
  options.map((option) => {
409
412
  const isChecked = value.includes(option.value);
410
413
  const isDisabled = disabled || option.disabled || maxReached && !isChecked;
411
- return /* @__PURE__ */ React8.createElement(
414
+ return /* @__PURE__ */ React9.createElement(
412
415
  Checkbox,
413
416
  {
414
417
  key: option.value,
@@ -426,7 +429,7 @@ function CheckboxGroup({
426
429
  }
427
430
  );
428
431
  }),
429
- (minSelections || maxSelections) && /* @__PURE__ */ React8.createElement(
432
+ (minSelections || maxSelections) && /* @__PURE__ */ React9.createElement(
430
433
  "div",
431
434
  {
432
435
  className: cn(
@@ -435,8 +438,8 @@ function CheckboxGroup({
435
438
  ),
436
439
  "aria-live": "polite"
437
440
  },
438
- minSelections && countableValue < minSelections && /* @__PURE__ */ React8.createElement("span", null, "Select at least ", minSelections, " option", minSelections !== 1 ? "s" : ""),
439
- maxSelections && /* @__PURE__ */ React8.createElement("span", null, countableValue, "/", maxSelections, " selected")
441
+ minSelections && countableValue < minSelections && /* @__PURE__ */ React9.createElement("span", null, "Select at least ", minSelections, " option", minSelections !== 1 ? "s" : ""),
442
+ maxSelections && /* @__PURE__ */ React9.createElement("span", null, countableValue, "/", maxSelections, " selected")
440
443
  )
441
444
  );
442
445
  }
@@ -487,10 +490,10 @@ function Radio({
487
490
  const handleBlur = () => {
488
491
  onBlur?.();
489
492
  };
490
- const useChoiceCard = React8.useMemo(() => {
493
+ const useChoiceCard = React9.useMemo(() => {
491
494
  return options.some((option) => option.description);
492
495
  }, [options]);
493
- const containerClass = React8.useMemo(() => {
496
+ const containerClass = React9.useMemo(() => {
494
497
  return cn(
495
498
  "w-full gap-3 grid grid-cols-1 border-0 m-0 p-0 min-w-0",
496
499
  (layout === "grid" || layout === "inline") && "md:grid-cols-2",
@@ -499,7 +502,7 @@ function Radio({
499
502
  }, [layout, className]);
500
503
  const groupDescriptionId = description ? `${name}-description` : void 0;
501
504
  const groupAriaDescribedBy = [props["aria-describedby"], groupDescriptionId].filter(Boolean).join(" ") || void 0;
502
- return /* @__PURE__ */ React8.createElement(
505
+ return /* @__PURE__ */ React9.createElement(
503
506
  "fieldset",
504
507
  {
505
508
  className: containerClass,
@@ -509,7 +512,7 @@ function Radio({
509
512
  "aria-required": required || props["aria-required"],
510
513
  "aria-label": typeof label === "string" ? label : props["aria-label"]
511
514
  },
512
- /* @__PURE__ */ React8.createElement(
515
+ /* @__PURE__ */ React9.createElement(
513
516
  LabelGroup,
514
517
  {
515
518
  variant: "legend",
@@ -523,7 +526,7 @@ function Radio({
523
526
  const isDisabled = disabled || option.disabled;
524
527
  const radioId = `${name}-${option.value}`;
525
528
  const hasDescription = option.description != null && option.description !== "";
526
- const radioIndicator = /* @__PURE__ */ React8.createElement("div", { className: "relative inline-flex items-center justify-center" }, /* @__PURE__ */ React8.createElement(
529
+ const radioIndicator = /* @__PURE__ */ React9.createElement("div", { className: "relative inline-flex items-center justify-center" }, /* @__PURE__ */ React9.createElement(
527
530
  "input",
528
531
  {
529
532
  type: "radio",
@@ -538,7 +541,7 @@ function Radio({
538
541
  className: "peer sr-only",
539
542
  "aria-describedby": hasDescription ? `${radioId}-description` : props["aria-describedby"]
540
543
  }
541
- ), /* @__PURE__ */ React8.createElement(
544
+ ), /* @__PURE__ */ React9.createElement(
542
545
  "div",
543
546
  {
544
547
  className: cn(
@@ -551,9 +554,9 @@ function Radio({
551
554
  "peer-focus-visible:ring-2 peer-focus-visible:ring-ring/50 peer-focus-visible:ring-offset-1"
552
555
  )
553
556
  },
554
- isChecked && /* @__PURE__ */ React8.createElement("div", { className: "size-3 rounded-full bg-primary" })
557
+ isChecked && /* @__PURE__ */ React9.createElement("div", { className: "size-3 rounded-full bg-primary" })
555
558
  ));
556
- const labelContent = /* @__PURE__ */ React8.createElement(
559
+ const labelContent = /* @__PURE__ */ React9.createElement(
557
560
  LabelGroup,
558
561
  {
559
562
  variant: "text",
@@ -564,7 +567,7 @@ function Radio({
564
567
  secondaryClassName: "text-xs opacity-75"
565
568
  }
566
569
  );
567
- return /* @__PURE__ */ React8.createElement(
570
+ return /* @__PURE__ */ React9.createElement(
568
571
  "label",
569
572
  {
570
573
  key: option.value,
@@ -578,7 +581,7 @@ function Radio({
578
581
  onKeyDown: (e) => handleKeyDown(e, index),
579
582
  tabIndex: isDisabled ? -1 : 0
580
583
  },
581
- /* @__PURE__ */ React8.createElement(
584
+ /* @__PURE__ */ React9.createElement(
582
585
  "div",
583
586
  {
584
587
  className: cn(
@@ -587,7 +590,7 @@ function Radio({
587
590
  )
588
591
  },
589
592
  !useChoiceCard && radioIndicator,
590
- /* @__PURE__ */ React8.createElement("div", { className: "flex flex-1 flex-col gap-0.5" }, labelContent),
593
+ labelContent,
591
594
  useChoiceCard && radioIndicator
592
595
  )
593
596
  );
@@ -614,19 +617,20 @@ function Select({
614
617
  renderOption,
615
618
  ...props
616
619
  }) {
617
- const [isOpen, setIsOpen] = React8.useState(false);
618
- const [searchQuery, setSearchQuery] = React8.useState("");
619
- const [focusedIndex, setFocusedIndex] = React8.useState(-1);
620
- const selectRef = React8.useRef(null);
621
- const searchInputRef = React8.useRef(null);
620
+ const [isOpen, setIsOpen] = React9.useState(false);
621
+ const [searchQuery, setSearchQuery] = React9.useState("");
622
+ const [focusedIndex, setFocusedIndex] = React9.useState(-1);
623
+ const triggerRef = React9.useRef(null);
624
+ const dropdownRef = React9.useRef(null);
625
+ const searchInputRef = React9.useRef(null);
622
626
  const dropdownId = `${name}-dropdown`;
623
- const allOptions = React8.useMemo(() => {
627
+ const allOptions = React9.useMemo(() => {
624
628
  if (optionGroups.length > 0) {
625
629
  return optionGroups.flatMap((group) => group.options);
626
630
  }
627
631
  return options;
628
632
  }, [options, optionGroups]);
629
- const filteredOptions = React8.useMemo(() => {
633
+ const filteredOptions = React9.useMemo(() => {
630
634
  if (!searchQuery.trim()) {
631
635
  return allOptions;
632
636
  }
@@ -636,7 +640,7 @@ function Select({
636
640
  return label.toLowerCase().includes(query);
637
641
  });
638
642
  }, [allOptions, searchQuery]);
639
- const selectedOption = React8.useMemo(() => {
643
+ const selectedOption = React9.useMemo(() => {
640
644
  return allOptions.find((opt) => opt.value === value);
641
645
  }, [allOptions, value]);
642
646
  const hasValue = Boolean(value);
@@ -736,28 +740,29 @@ function Select({
736
740
  };
737
741
  const handleBlur = (event) => {
738
742
  const nextTarget = event?.relatedTarget;
739
- if (!nextTarget || !selectRef.current?.contains(nextTarget)) {
743
+ const focusStayedInside = !!triggerRef.current && triggerRef.current.contains(nextTarget) || !!dropdownRef.current && dropdownRef.current.contains(nextTarget);
744
+ if (!nextTarget || !focusStayedInside) {
740
745
  onBlur?.();
741
746
  }
742
747
  };
743
- const closeDropdown = React8.useCallback(() => {
744
- if (!isOpen) return;
748
+ const closeDropdown = React9.useCallback(() => {
745
749
  setIsOpen(false);
746
750
  setSearchQuery("");
747
751
  setFocusedIndex(-1);
748
752
  onBlur?.();
749
- }, [isOpen, onBlur]);
750
- useOnClickOutside(selectRef, closeDropdown, "pointerdown", true);
753
+ }, [onBlur]);
754
+ useOnClickOutside([triggerRef, dropdownRef], closeDropdown, void 0, {
755
+ capture: true
756
+ });
751
757
  const combinedClassName = cn("relative w-full", className);
752
- return /* @__PURE__ */ React8.createElement(
758
+ return /* @__PURE__ */ React9.createElement(
753
759
  "div",
754
760
  {
755
- ref: selectRef,
756
761
  className: combinedClassName,
757
762
  onKeyDown: handleKeyDown,
758
763
  onBlur: handleBlur
759
764
  },
760
- /* @__PURE__ */ React8.createElement(
765
+ /* @__PURE__ */ React9.createElement(
761
766
  "select",
762
767
  {
763
768
  name,
@@ -770,12 +775,13 @@ function Select({
770
775
  tabIndex: -1,
771
776
  style: { display: "none" }
772
777
  },
773
- /* @__PURE__ */ React8.createElement("option", { value: "" }, "Select..."),
774
- allOptions.map((option) => /* @__PURE__ */ React8.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
778
+ /* @__PURE__ */ React9.createElement("option", { value: "" }, "Select..."),
779
+ allOptions.map((option) => /* @__PURE__ */ React9.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
775
780
  ),
776
- /* @__PURE__ */ React8.createElement(
781
+ /* @__PURE__ */ React9.createElement(
777
782
  "div",
778
783
  {
784
+ ref: triggerRef,
779
785
  className: cn(
780
786
  "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm",
781
787
  "cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
@@ -793,8 +799,8 @@ function Select({
793
799
  "aria-disabled": disabled,
794
800
  tabIndex: disabled ? -1 : 0
795
801
  },
796
- /* @__PURE__ */ React8.createElement("span", { className: "flex items-center flex-1 overflow-hidden text-ellipsis" }, selectedOption ? renderOption ? renderOption(selectedOption) : selectedOption.label : /* @__PURE__ */ React8.createElement("span", { className: "relative" }, placeholder)),
797
- /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-1 ml-2" }, loading && /* @__PURE__ */ React8.createElement("span", { className: "text-xs" }, "\u23F3"), clearable && value && !disabled && !loading && /* @__PURE__ */ React8.createElement(
802
+ /* @__PURE__ */ React9.createElement("span", { className: "flex items-center flex-1 overflow-hidden text-ellipsis" }, selectedOption ? renderOption ? renderOption(selectedOption) : selectedOption.label : /* @__PURE__ */ React9.createElement("span", { className: "relative" }, placeholder)),
803
+ /* @__PURE__ */ React9.createElement("div", { className: "flex items-center gap-1 ml-2" }, loading && /* @__PURE__ */ React9.createElement("span", { className: "text-xs" }, "\u23F3"), clearable && value && !disabled && !loading && /* @__PURE__ */ React9.createElement(
798
804
  "button",
799
805
  {
800
806
  type: "button",
@@ -804,16 +810,17 @@ function Select({
804
810
  tabIndex: -1
805
811
  },
806
812
  "\u2715"
807
- ), /* @__PURE__ */ React8.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
813
+ ), /* @__PURE__ */ React9.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
808
814
  ),
809
- isOpen && /* @__PURE__ */ React8.createElement(
815
+ isOpen && /* @__PURE__ */ React9.createElement(
810
816
  "div",
811
817
  {
818
+ ref: dropdownRef,
812
819
  id: dropdownId,
813
820
  className: "absolute z-50 top-full mt-1 min-w-full overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md",
814
821
  role: "listbox"
815
822
  },
816
- searchable && /* @__PURE__ */ React8.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React8.createElement(
823
+ searchable && /* @__PURE__ */ React9.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React9.createElement(
817
824
  "input",
818
825
  {
819
826
  ref: searchInputRef,
@@ -829,19 +836,19 @@ function Select({
829
836
  "aria-label": "Search options"
830
837
  }
831
838
  )),
832
- /* @__PURE__ */ React8.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React8.createElement("div", { className: "py-2 px-3 text-center text-sm " }, "No options found") : optionGroups.length > 0 ? (
839
+ /* @__PURE__ */ React9.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React9.createElement("div", { className: "py-2 px-3 text-center text-sm " }, "No options found") : optionGroups.length > 0 ? (
833
840
  // Render grouped options
834
841
  optionGroups.map((group, groupIndex) => {
835
842
  const groupOptions = group.options.filter(
836
843
  (opt) => filteredOptions.includes(opt)
837
844
  );
838
845
  if (groupOptions.length === 0) return null;
839
- return /* @__PURE__ */ React8.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React8.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold " }, group.label), groupOptions.map((option) => {
846
+ return /* @__PURE__ */ React9.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React9.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold " }, group.label), groupOptions.map((option) => {
840
847
  const globalIndex = filteredOptions.indexOf(option);
841
848
  const isSelected = value === option.value;
842
849
  const isFocused = globalIndex === focusedIndex;
843
850
  const isDisabled = option.disabled;
844
- return /* @__PURE__ */ React8.createElement(
851
+ return /* @__PURE__ */ React9.createElement(
845
852
  "div",
846
853
  {
847
854
  key: option.value,
@@ -861,7 +868,7 @@ function Select({
861
868
  const isSelected = value === option.value;
862
869
  const isFocused = index === focusedIndex;
863
870
  const isDisabled = option.disabled;
864
- return /* @__PURE__ */ React8.createElement(
871
+ return /* @__PURE__ */ React9.createElement(
865
872
  "div",
866
873
  {
867
874
  key: option.value,
@@ -879,6 +886,360 @@ function Select({
879
886
  );
880
887
  }
881
888
  Select.displayName = "Select";
889
+ function MultiSelect({
890
+ name,
891
+ value = [],
892
+ onChange,
893
+ onBlur,
894
+ onFocus,
895
+ disabled = false,
896
+ required = false,
897
+ error = false,
898
+ className = "",
899
+ placeholder = "Select...",
900
+ searchable = true,
901
+ clearable = true,
902
+ loading = false,
903
+ maxSelections,
904
+ showSelectAll = false,
905
+ options = [],
906
+ optionGroups = [],
907
+ renderOption,
908
+ renderValue,
909
+ ...props
910
+ }) {
911
+ const [isOpen, setIsOpen] = React9.useState(false);
912
+ const [searchQuery, setSearchQuery] = React9.useState("");
913
+ const [focusedIndex, setFocusedIndex] = React9.useState(-1);
914
+ const triggerRef = React9.useRef(null);
915
+ const dropdownRef = React9.useRef(null);
916
+ const searchInputRef = React9.useRef(null);
917
+ const dropdownId = `${name}-dropdown`;
918
+ const allOptions = React9.useMemo(() => {
919
+ if (optionGroups.length > 0) {
920
+ return optionGroups.flatMap((group) => group.options);
921
+ }
922
+ return options;
923
+ }, [options, optionGroups]);
924
+ const filteredOptions = React9.useMemo(() => {
925
+ if (!searchQuery.trim()) {
926
+ return allOptions;
927
+ }
928
+ const query = searchQuery.toLowerCase();
929
+ return allOptions.filter((option) => {
930
+ const label = typeof option.label === "string" ? option.label : String(option.label);
931
+ return label.toLowerCase().includes(query);
932
+ });
933
+ }, [allOptions, searchQuery]);
934
+ const selectedOptions = React9.useMemo(() => {
935
+ return allOptions.filter((opt) => value.includes(opt.value));
936
+ }, [allOptions, value]);
937
+ const hasValue = value.length > 0;
938
+ const isMaxReached = React9.useMemo(() => {
939
+ return maxSelections !== void 0 && value.length >= maxSelections;
940
+ }, [maxSelections, value.length]);
941
+ const handleToggleOption = (optionValue) => {
942
+ const isSelected = value.includes(optionValue);
943
+ if (isSelected) {
944
+ onChange(value.filter((v) => v !== optionValue));
945
+ } else {
946
+ if (!isMaxReached) {
947
+ onChange([...value, optionValue]);
948
+ }
949
+ }
950
+ setSearchQuery("");
951
+ };
952
+ const handleSelectAll = () => {
953
+ const enabledOptions = filteredOptions.filter((opt) => !opt.disabled);
954
+ const allValues = enabledOptions.map((opt) => opt.value);
955
+ onChange(allValues);
956
+ setSearchQuery("");
957
+ };
958
+ const handleClearAll = (e) => {
959
+ e.stopPropagation();
960
+ onChange([]);
961
+ setSearchQuery("");
962
+ setFocusedIndex(-1);
963
+ };
964
+ const handleRemoveValue = (optionValue, e) => {
965
+ e.stopPropagation();
966
+ onChange(value.filter((v) => v !== optionValue));
967
+ };
968
+ const handleToggle = () => {
969
+ if (disabled) return;
970
+ const newIsOpen = !isOpen;
971
+ setIsOpen(newIsOpen);
972
+ if (newIsOpen && searchable && searchInputRef.current) {
973
+ setTimeout(() => searchInputRef.current?.focus(), 0);
974
+ }
975
+ if (newIsOpen) {
976
+ onFocus?.();
977
+ }
978
+ };
979
+ const handleSearchChange = (e) => {
980
+ setSearchQuery(e.target.value);
981
+ setFocusedIndex(0);
982
+ };
983
+ const handleKeyDown = (e) => {
984
+ if (disabled) return;
985
+ switch (e.key) {
986
+ case "ArrowDown":
987
+ e.preventDefault();
988
+ if (!isOpen) {
989
+ setIsOpen(true);
990
+ setFocusedIndex(0);
991
+ } else {
992
+ const enabledOptions = filteredOptions.filter((opt) => !opt.disabled);
993
+ if (enabledOptions.length > 0) {
994
+ const currentIndexInFiltered = focusedIndex;
995
+ const nextIndex = (currentIndexInFiltered + 1) % enabledOptions.length;
996
+ setFocusedIndex(filteredOptions.indexOf(enabledOptions[nextIndex]));
997
+ }
998
+ }
999
+ break;
1000
+ case "ArrowUp":
1001
+ e.preventDefault();
1002
+ if (isOpen) {
1003
+ const enabledOptions = filteredOptions.filter((opt) => !opt.disabled);
1004
+ if (enabledOptions.length > 0) {
1005
+ const currentIndexInFiltered = focusedIndex;
1006
+ const prevIndex = (currentIndexInFiltered - 1 + enabledOptions.length) % enabledOptions.length;
1007
+ setFocusedIndex(filteredOptions.indexOf(enabledOptions[prevIndex]));
1008
+ }
1009
+ }
1010
+ break;
1011
+ case "Enter":
1012
+ e.preventDefault();
1013
+ if (isOpen && focusedIndex >= 0 && focusedIndex < filteredOptions.length) {
1014
+ const focusedOption = filteredOptions[focusedIndex];
1015
+ if (!focusedOption.disabled) {
1016
+ handleToggleOption(focusedOption.value);
1017
+ }
1018
+ } else if (!isOpen) {
1019
+ setIsOpen(true);
1020
+ }
1021
+ break;
1022
+ case "Escape":
1023
+ e.preventDefault();
1024
+ if (isOpen) {
1025
+ setIsOpen(false);
1026
+ setSearchQuery("");
1027
+ setFocusedIndex(-1);
1028
+ }
1029
+ break;
1030
+ case " ":
1031
+ if (isOpen && focusedIndex >= 0 && focusedIndex < filteredOptions.length) {
1032
+ e.preventDefault();
1033
+ const focusedOption = filteredOptions[focusedIndex];
1034
+ if (!focusedOption.disabled) {
1035
+ handleToggleOption(focusedOption.value);
1036
+ }
1037
+ } else if (!isOpen && !searchable) {
1038
+ e.preventDefault();
1039
+ setIsOpen(true);
1040
+ }
1041
+ break;
1042
+ }
1043
+ };
1044
+ const handleBlur = (event) => {
1045
+ const nextTarget = event?.relatedTarget;
1046
+ const focusStayedInside = !!triggerRef.current && triggerRef.current.contains(nextTarget) || !!dropdownRef.current && dropdownRef.current.contains(nextTarget);
1047
+ if (!nextTarget || !focusStayedInside) {
1048
+ onBlur?.();
1049
+ }
1050
+ };
1051
+ const closeDropdown = React9.useCallback(() => {
1052
+ setIsOpen(false);
1053
+ setSearchQuery("");
1054
+ setFocusedIndex(-1);
1055
+ onBlur?.();
1056
+ }, [onBlur]);
1057
+ useOnClickOutside([triggerRef, dropdownRef], closeDropdown, void 0, {
1058
+ capture: true
1059
+ });
1060
+ const combinedClassName = cn("relative w-full", className);
1061
+ return /* @__PURE__ */ React9.createElement(
1062
+ "div",
1063
+ {
1064
+ className: combinedClassName,
1065
+ onKeyDown: handleKeyDown,
1066
+ onBlur: handleBlur
1067
+ },
1068
+ /* @__PURE__ */ React9.createElement(
1069
+ "select",
1070
+ {
1071
+ name,
1072
+ value,
1073
+ onChange: () => {
1074
+ },
1075
+ disabled,
1076
+ required,
1077
+ "aria-hidden": "true",
1078
+ tabIndex: -1,
1079
+ style: { display: "none" },
1080
+ multiple: true
1081
+ },
1082
+ /* @__PURE__ */ React9.createElement("option", { value: "" }, "Select..."),
1083
+ allOptions.map((option) => /* @__PURE__ */ React9.createElement("option", { key: option.value, value: option.value }, typeof option.label === "string" ? option.label : option.value))
1084
+ ),
1085
+ /* @__PURE__ */ React9.createElement(
1086
+ "div",
1087
+ {
1088
+ ref: triggerRef,
1089
+ className: cn(
1090
+ "flex min-h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm",
1091
+ "cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
1092
+ !error && hasValue && "ring-2 ring-ring",
1093
+ disabled && "cursor-not-allowed opacity-50 pointer-events-none",
1094
+ error && "border-destructive ring-1 ring-destructive"
1095
+ ),
1096
+ onClick: handleToggle,
1097
+ role: "combobox",
1098
+ "aria-expanded": isOpen,
1099
+ "aria-controls": dropdownId,
1100
+ "aria-invalid": error || props["aria-invalid"],
1101
+ "aria-describedby": props["aria-describedby"],
1102
+ "aria-required": required || props["aria-required"],
1103
+ "aria-disabled": disabled,
1104
+ tabIndex: disabled ? -1 : 0
1105
+ },
1106
+ /* @__PURE__ */ React9.createElement("div", { className: "flex items-center flex-1 overflow-hidden" }, selectedOptions.length > 0 ? /* @__PURE__ */ React9.createElement("div", { className: "flex flex-wrap gap-1" }, selectedOptions.map((option) => /* @__PURE__ */ React9.createElement(
1107
+ "span",
1108
+ {
1109
+ key: option.value,
1110
+ className: "inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium"
1111
+ },
1112
+ renderValue ? renderValue(option) : /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement("span", { className: "max-w-40 overflow-hidden text-ellipsis whitespace-nowrap" }, option.label), !disabled && /* @__PURE__ */ React9.createElement(
1113
+ "button",
1114
+ {
1115
+ type: "button",
1116
+ className: "flex items-center justify-center h-3.5 w-3.5 rounded-sm border-none bg-transparent cursor-pointer text-[0.625rem] p-0 transition-opacity hover:opacity-70",
1117
+ onClick: (e) => handleRemoveValue(option.value, e),
1118
+ "aria-label": `Remove ${option.label}`,
1119
+ tabIndex: -1
1120
+ },
1121
+ "\u2715"
1122
+ ))
1123
+ ))) : /* @__PURE__ */ React9.createElement("span", { className: "relative" }, placeholder)),
1124
+ /* @__PURE__ */ React9.createElement("div", { className: "flex items-center gap-1 ml-2" }, loading && /* @__PURE__ */ React9.createElement("span", { className: "text-xs" }, "\u23F3"), clearable && value.length > 0 && !disabled && !loading && /* @__PURE__ */ React9.createElement(
1125
+ "button",
1126
+ {
1127
+ type: "button",
1128
+ className: "flex items-center justify-center h-4 w-4 rounded-sm border-none bg-transparent cursor-pointer text-xs p-0 transition-opacity hover:opacity-70",
1129
+ onClick: handleClearAll,
1130
+ "aria-label": "Clear all selections",
1131
+ tabIndex: -1
1132
+ },
1133
+ "\u2715"
1134
+ ), /* @__PURE__ */ React9.createElement("span", { className: "text-xs leading-none", "aria-hidden": "true" }, isOpen ? "\u25B2" : "\u25BC"))
1135
+ ),
1136
+ isOpen && /* @__PURE__ */ React9.createElement(
1137
+ "div",
1138
+ {
1139
+ ref: dropdownRef,
1140
+ id: dropdownId,
1141
+ className: "absolute z-50 top-full mt-1 w-full overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md",
1142
+ role: "listbox",
1143
+ "aria-multiselectable": "true"
1144
+ },
1145
+ searchable && /* @__PURE__ */ React9.createElement("div", { className: "p-2 border-b border-border" }, /* @__PURE__ */ React9.createElement(
1146
+ "input",
1147
+ {
1148
+ ref: searchInputRef,
1149
+ type: "text",
1150
+ className: cn(
1151
+ "w-full border border-input rounded px-2 py-1 text-sm bg-transparent outline-none focus:ring-1 focus:ring-ring",
1152
+ INPUT_AUTOFILL_RESET_CLASSES
1153
+ ),
1154
+ placeholder: "Search...",
1155
+ value: searchQuery,
1156
+ onChange: handleSearchChange,
1157
+ onClick: (e) => e.stopPropagation(),
1158
+ "aria-label": "Search options"
1159
+ }
1160
+ )),
1161
+ showSelectAll && filteredOptions.length > 0 && /* @__PURE__ */ React9.createElement("div", { className: "flex gap-2 p-2 border-b border-border" }, /* @__PURE__ */ React9.createElement(
1162
+ "button",
1163
+ {
1164
+ type: "button",
1165
+ className: "flex-1 px-3 py-1.5 text-xs font-medium rounded border border-input bg-transparent hover:bg-muted transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
1166
+ onClick: handleSelectAll,
1167
+ disabled
1168
+ },
1169
+ "Select All"
1170
+ ), value.length > 0 && /* @__PURE__ */ React9.createElement(
1171
+ "button",
1172
+ {
1173
+ type: "button",
1174
+ className: "flex-1 px-3 py-1.5 text-xs font-medium rounded border border-input bg-transparent hover:bg-muted transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
1175
+ onClick: handleClearAll,
1176
+ disabled
1177
+ },
1178
+ "Clear All"
1179
+ )),
1180
+ isMaxReached && /* @__PURE__ */ React9.createElement("div", { className: "px-2 py-1 text-xs font-medium text-amber-600 bg-destructive/80 text-destructive-foreground border-b border-destructive" }, "Maximum ", maxSelections, " selection", maxSelections !== 1 ? "s" : "", " ", "reached"),
1181
+ /* @__PURE__ */ React9.createElement("div", { className: "max-h-64 overflow-y-auto p-1" }, filteredOptions.length === 0 ? /* @__PURE__ */ React9.createElement("div", { className: "px-2 py-1 text-center text-sm" }, "No options found") : optionGroups.length > 0 ? (
1182
+ // Render grouped options
1183
+ optionGroups.map((group, groupIndex) => {
1184
+ const groupOptions = group.options.filter(
1185
+ (opt) => filteredOptions.includes(opt)
1186
+ );
1187
+ if (groupOptions.length === 0) return null;
1188
+ return /* @__PURE__ */ React9.createElement("div", { key: groupIndex, className: "py-1" }, /* @__PURE__ */ React9.createElement("div", { className: "py-1.5 px-2 text-xs font-semibold " }, group.label), groupOptions.map((option) => {
1189
+ const globalIndex = filteredOptions.indexOf(option);
1190
+ const isSelected = value.includes(option.value);
1191
+ const isFocused = globalIndex === focusedIndex;
1192
+ const isDisabled = option.disabled || isMaxReached && !isSelected;
1193
+ return /* @__PURE__ */ React9.createElement(
1194
+ "div",
1195
+ {
1196
+ key: option.value,
1197
+ className: cn(
1198
+ "relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 px-2 text-sm outline-none transition-colors hover:bg-muted",
1199
+ isFocused && "bg-muted",
1200
+ isSelected && "font-medium",
1201
+ isDisabled && "pointer-events-none opacity-50"
1202
+ ),
1203
+ onClick: () => !isDisabled && handleToggleOption(option.value),
1204
+ role: "option",
1205
+ "aria-selected": isSelected,
1206
+ "aria-disabled": isDisabled
1207
+ },
1208
+ /* @__PURE__ */ React9.createElement("span", { className: "text-base leading-none" }, isSelected ? "\u2611" : "\u2610"),
1209
+ /* @__PURE__ */ React9.createElement("span", { className: "flex-1" }, renderOption ? renderOption(option) : option.label)
1210
+ );
1211
+ }));
1212
+ })
1213
+ ) : (
1214
+ // Render flat options
1215
+ filteredOptions.map((option, index) => {
1216
+ const isSelected = value.includes(option.value);
1217
+ const isFocused = index === focusedIndex;
1218
+ const isDisabled = option.disabled || isMaxReached && !isSelected;
1219
+ return /* @__PURE__ */ React9.createElement(
1220
+ "div",
1221
+ {
1222
+ key: option.value,
1223
+ className: cn(
1224
+ "relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 px-2 text-sm outline-none transition-colors hover:bg-muted",
1225
+ isFocused && "bg-muted",
1226
+ isSelected && "font-medium bg-muted",
1227
+ isDisabled && "pointer-events-none opacity-50"
1228
+ ),
1229
+ onClick: () => !isDisabled && handleToggleOption(option.value),
1230
+ role: "option",
1231
+ "aria-selected": isSelected,
1232
+ "aria-disabled": isDisabled
1233
+ },
1234
+ /* @__PURE__ */ React9.createElement("span", { className: "text-base leading-none" }, isSelected ? "\u2611" : "\u2610"),
1235
+ /* @__PURE__ */ React9.createElement("span", { className: "flex-1" }, renderOption ? renderOption(option) : option.label)
1236
+ );
1237
+ })
1238
+ ))
1239
+ )
1240
+ );
1241
+ }
1242
+ MultiSelect.displayName = "MultiSelect";
882
1243
  function FileInput({
883
1244
  name,
884
1245
  value = [],
@@ -904,14 +1265,14 @@ function FileInput({
904
1265
  onFileRemove,
905
1266
  ...props
906
1267
  }) {
907
- const inputRef = React8.useRef(null);
908
- const [dragActive, setDragActive] = React8.useState(false);
909
- const [cropperOpen, setCropperOpen] = React8.useState(false);
910
- const [imageToCrop, setImageToCrop] = React8.useState(null);
911
- const [crop, setCrop] = React8.useState({ x: 0, y: 0 });
912
- const [zoom, setZoom] = React8.useState(1);
913
- const [croppedAreaPixels, setCroppedAreaPixels] = React8.useState(null);
914
- const validateFile = React8.useCallback(
1268
+ const inputRef = React9.useRef(null);
1269
+ const [dragActive, setDragActive] = React9.useState(false);
1270
+ const [cropperOpen, setCropperOpen] = React9.useState(false);
1271
+ const [imageToCrop, setImageToCrop] = React9.useState(null);
1272
+ const [crop, setCrop] = React9.useState({ x: 0, y: 0 });
1273
+ const [zoom, setZoom] = React9.useState(1);
1274
+ const [croppedAreaPixels, setCroppedAreaPixels] = React9.useState(null);
1275
+ const validateFile = React9.useCallback(
915
1276
  (file) => {
916
1277
  if (accept) {
917
1278
  const acceptedTypes = accept.split(",").map((t) => t.trim());
@@ -946,7 +1307,7 @@ function FileInput({
946
1307
  },
947
1308
  [accept, maxSize]
948
1309
  );
949
- const handleFiles = React8.useCallback(
1310
+ const handleFiles = React9.useCallback(
950
1311
  (fileList) => {
951
1312
  if (!fileList || fileList.length === 0) return;
952
1313
  const newFiles = Array.from(fileList);
@@ -997,7 +1358,7 @@ function FileInput({
997
1358
  onValidationError
998
1359
  ]
999
1360
  );
1000
- const createCroppedImage = React8.useCallback(
1361
+ const createCroppedImage = React9.useCallback(
1001
1362
  async (imageUrl, cropArea) => {
1002
1363
  return new Promise((resolve, reject) => {
1003
1364
  const image = new Image();
@@ -1041,7 +1402,7 @@ function FileInput({
1041
1402
  },
1042
1403
  []
1043
1404
  );
1044
- const handleCropSave = React8.useCallback(async () => {
1405
+ const handleCropSave = React9.useCallback(async () => {
1045
1406
  if (!imageToCrop || !croppedAreaPixels) return;
1046
1407
  try {
1047
1408
  const croppedBlob = await createCroppedImage(
@@ -1074,7 +1435,7 @@ function FileInput({
1074
1435
  onChange,
1075
1436
  multiple
1076
1437
  ]);
1077
- const handleCropCancel = React8.useCallback(() => {
1438
+ const handleCropCancel = React9.useCallback(() => {
1078
1439
  if (imageToCrop) {
1079
1440
  URL.revokeObjectURL(imageToCrop.url);
1080
1441
  }
@@ -1084,13 +1445,13 @@ function FileInput({
1084
1445
  setZoom(1);
1085
1446
  setCroppedAreaPixels(null);
1086
1447
  }, [imageToCrop]);
1087
- const onCropChange = React8.useCallback((crop2) => {
1448
+ const onCropChange = React9.useCallback((crop2) => {
1088
1449
  setCrop(crop2);
1089
1450
  }, []);
1090
- const onZoomChange = React8.useCallback((zoom2) => {
1451
+ const onZoomChange = React9.useCallback((zoom2) => {
1091
1452
  setZoom(zoom2);
1092
1453
  }, []);
1093
- const onCropCompleteInternal = React8.useCallback(
1454
+ const onCropCompleteInternal = React9.useCallback(
1094
1455
  (_, croppedAreaPixels2) => {
1095
1456
  setCroppedAreaPixels(croppedAreaPixels2);
1096
1457
  },
@@ -1151,7 +1512,7 @@ function FileInput({
1151
1512
  }
1152
1513
  return null;
1153
1514
  };
1154
- React8.useEffect(() => {
1515
+ React9.useEffect(() => {
1155
1516
  return () => {
1156
1517
  value.forEach((file) => {
1157
1518
  const previewUrl = getPreviewUrl(file);
@@ -1165,7 +1526,7 @@ function FileInput({
1165
1526
  };
1166
1527
  }, [value, imageToCrop]);
1167
1528
  const combinedClassName = `${className}`.trim();
1168
- return /* @__PURE__ */ React8.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React8.createElement(
1529
+ return /* @__PURE__ */ React9.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React9.createElement(
1169
1530
  "input",
1170
1531
  {
1171
1532
  ref: inputRef,
@@ -1182,7 +1543,7 @@ function FileInput({
1182
1543
  "aria-required": required || props["aria-required"],
1183
1544
  style: { display: "none" }
1184
1545
  }
1185
- ), /* @__PURE__ */ React8.createElement(
1546
+ ), /* @__PURE__ */ React9.createElement(
1186
1547
  "div",
1187
1548
  {
1188
1549
  className: `flex min-h-32 w-full cursor-pointer items-center justify-center rounded-md border-2 border-dashed border-input bg-transparent p-6 transition-colors hover:bg-primary/50 hover:border-ring ${dragActive ? "bg-primary text-primary-foreground border-ring" : ""} ${disabled ? "cursor-not-allowed opacity-50" : ""} ${error ? "border-destructive" : ""}`,
@@ -1197,7 +1558,7 @@ function FileInput({
1197
1558
  "aria-label": placeholder,
1198
1559
  "aria-disabled": disabled
1199
1560
  },
1200
- /* @__PURE__ */ React8.createElement("div", { className: "flex flex-col items-center gap-2 text-center" }, /* @__PURE__ */ React8.createElement(
1561
+ /* @__PURE__ */ React9.createElement("div", { className: "flex flex-col items-center gap-2 text-center" }, /* @__PURE__ */ React9.createElement(
1201
1562
  "svg",
1202
1563
  {
1203
1564
  width: "48",
@@ -1210,19 +1571,19 @@ function FileInput({
1210
1571
  strokeLinejoin: "round",
1211
1572
  "aria-hidden": "true"
1212
1573
  },
1213
- /* @__PURE__ */ React8.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1214
- /* @__PURE__ */ React8.createElement("polyline", { points: "17 8 12 3 7 8" }),
1215
- /* @__PURE__ */ React8.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
1216
- ), /* @__PURE__ */ React8.createElement("p", { className: "text-sm font-medium" }, value.length > 0 ? `${value.length} file(s) selected` : placeholder), accept && /* @__PURE__ */ React8.createElement("p", { className: "text-xs" }, "Accepted: ", accept), maxSize && /* @__PURE__ */ React8.createElement("p", { className: "text-xs " }, "Max size: ", formatFileSize(maxSize)))
1217
- ), value.length > 0 && /* @__PURE__ */ React8.createElement("ul", { className: "flex flex-col gap-2 mt-4", role: "list" }, value.map((file, index) => {
1574
+ /* @__PURE__ */ React9.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1575
+ /* @__PURE__ */ React9.createElement("polyline", { points: "17 8 12 3 7 8" }),
1576
+ /* @__PURE__ */ React9.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
1577
+ ), /* @__PURE__ */ React9.createElement("p", { className: "text-sm font-medium" }, value.length > 0 ? `${value.length} file(s) selected` : placeholder), accept && /* @__PURE__ */ React9.createElement("p", { className: "text-xs" }, "Accepted: ", accept), maxSize && /* @__PURE__ */ React9.createElement("p", { className: "text-xs " }, "Max size: ", formatFileSize(maxSize)))
1578
+ ), value.length > 0 && /* @__PURE__ */ React9.createElement("ul", { className: "flex flex-col gap-2 mt-4", role: "list" }, value.map((file, index) => {
1218
1579
  const previewUrl = showPreview ? getPreviewUrl(file) : null;
1219
- return /* @__PURE__ */ React8.createElement(
1580
+ return /* @__PURE__ */ React9.createElement(
1220
1581
  "li",
1221
1582
  {
1222
1583
  key: `${file.name}-${index}`,
1223
1584
  className: "flex items-center gap-3 p-3 rounded-md border border-border bg-card text-card-foreground hover:bg-primary/50 transition-colors"
1224
1585
  },
1225
- previewUrl && /* @__PURE__ */ React8.createElement(
1586
+ previewUrl && /* @__PURE__ */ React9.createElement(
1226
1587
  "img",
1227
1588
  {
1228
1589
  src: previewUrl,
@@ -1232,7 +1593,7 @@ function FileInput({
1232
1593
  height: "48"
1233
1594
  }
1234
1595
  ),
1235
- /* @__PURE__ */ React8.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React8.createElement("span", { className: "text-sm font-medium truncate" }, file.name), /* @__PURE__ */ React8.createElement("span", { className: "text-xs" }, formatFileSize(file.size)), showProgress && uploadProgress[file.name] !== void 0 && /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-2 mt-1" }, /* @__PURE__ */ React8.createElement(
1596
+ /* @__PURE__ */ React9.createElement("div", { className: "flex flex-col flex-1 min-w-0" }, /* @__PURE__ */ React9.createElement("span", { className: "text-sm font-medium truncate" }, file.name), /* @__PURE__ */ React9.createElement("span", { className: "text-xs" }, formatFileSize(file.size)), showProgress && uploadProgress[file.name] !== void 0 && /* @__PURE__ */ React9.createElement("div", { className: "flex items-center gap-2 mt-1" }, /* @__PURE__ */ React9.createElement(
1236
1597
  "div",
1237
1598
  {
1238
1599
  className: "h-1.5 bg-muted rounded-full overflow-hidden flex-1",
@@ -1242,15 +1603,15 @@ function FileInput({
1242
1603
  "aria-valuemax": 100,
1243
1604
  "aria-label": `Upload progress: ${uploadProgress[file.name]}%`
1244
1605
  },
1245
- /* @__PURE__ */ React8.createElement(
1606
+ /* @__PURE__ */ React9.createElement(
1246
1607
  "div",
1247
1608
  {
1248
1609
  className: "h-full bg-primary transition-all",
1249
1610
  style: { width: `${uploadProgress[file.name]}%` }
1250
1611
  }
1251
1612
  )
1252
- ), /* @__PURE__ */ React8.createElement("span", { className: "text-xs " }, uploadProgress[file.name], "%"))),
1253
- enableCropping && file.type.startsWith("image/") && /* @__PURE__ */ React8.createElement(
1613
+ ), /* @__PURE__ */ React9.createElement("span", { className: "text-xs " }, uploadProgress[file.name], "%"))),
1614
+ enableCropping && file.type.startsWith("image/") && /* @__PURE__ */ React9.createElement(
1254
1615
  "button",
1255
1616
  {
1256
1617
  type: "button",
@@ -1262,7 +1623,7 @@ function FileInput({
1262
1623
  className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
1263
1624
  "aria-label": `Crop ${file.name}`
1264
1625
  },
1265
- /* @__PURE__ */ React8.createElement(
1626
+ /* @__PURE__ */ React9.createElement(
1266
1627
  "svg",
1267
1628
  {
1268
1629
  width: "20",
@@ -1275,11 +1636,11 @@ function FileInput({
1275
1636
  strokeLinejoin: "round",
1276
1637
  "aria-hidden": "true"
1277
1638
  },
1278
- /* @__PURE__ */ React8.createElement("path", { d: "M6.13 1L6 16a2 2 0 0 0 2 2h15" }),
1279
- /* @__PURE__ */ React8.createElement("path", { d: "M1 6.13L16 6a2 2 0 0 1 2 2v15" })
1639
+ /* @__PURE__ */ React9.createElement("path", { d: "M6.13 1L6 16a2 2 0 0 0 2 2h15" }),
1640
+ /* @__PURE__ */ React9.createElement("path", { d: "M1 6.13L16 6a2 2 0 0 1 2 2v15" })
1280
1641
  )
1281
1642
  ),
1282
- /* @__PURE__ */ React8.createElement(
1643
+ /* @__PURE__ */ React9.createElement(
1283
1644
  "button",
1284
1645
  {
1285
1646
  type: "button",
@@ -1291,7 +1652,7 @@ function FileInput({
1291
1652
  className: "flex items-center justify-center h-8 w-8 rounded border-none bg-transparent hover:bg-primary hover:text-primary-foreground transition-colors",
1292
1653
  "aria-label": `Remove ${file.name}`
1293
1654
  },
1294
- /* @__PURE__ */ React8.createElement(
1655
+ /* @__PURE__ */ React9.createElement(
1295
1656
  "svg",
1296
1657
  {
1297
1658
  width: "20",
@@ -1304,19 +1665,19 @@ function FileInput({
1304
1665
  strokeLinejoin: "round",
1305
1666
  "aria-hidden": "true"
1306
1667
  },
1307
- /* @__PURE__ */ React8.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1308
- /* @__PURE__ */ React8.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1668
+ /* @__PURE__ */ React9.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1669
+ /* @__PURE__ */ React9.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1309
1670
  )
1310
1671
  )
1311
1672
  );
1312
- })), cropperOpen && imageToCrop && /* @__PURE__ */ React8.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center" }, /* @__PURE__ */ React8.createElement(
1673
+ })), cropperOpen && imageToCrop && /* @__PURE__ */ React9.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center" }, /* @__PURE__ */ React9.createElement(
1313
1674
  "div",
1314
1675
  {
1315
1676
  className: "absolute inset-0 bg-black/50",
1316
1677
  onClick: handleCropCancel,
1317
1678
  "aria-label": "Close cropper"
1318
1679
  }
1319
- ), /* @__PURE__ */ React8.createElement("div", { className: "relative bg-popover border border-border rounded-lg shadow-lg max-w-3xl w-full mx-4" }, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-between p-4 border-b border-border" }, /* @__PURE__ */ React8.createElement("h3", { className: "text-lg font-semibold" }, "Crop Image"), /* @__PURE__ */ React8.createElement(
1680
+ ), /* @__PURE__ */ React9.createElement("div", { className: "relative bg-popover border border-border rounded-lg shadow-lg max-w-3xl w-full mx-4" }, /* @__PURE__ */ React9.createElement("div", { className: "flex items-center justify-between p-4 border-b border-border" }, /* @__PURE__ */ React9.createElement("h3", { className: "text-lg font-semibold" }, "Crop Image"), /* @__PURE__ */ React9.createElement(
1320
1681
  "button",
1321
1682
  {
1322
1683
  type: "button",
@@ -1325,7 +1686,7 @@ function FileInput({
1325
1686
  "aria-label": "Close"
1326
1687
  },
1327
1688
  "\u2715"
1328
- )), /* @__PURE__ */ React8.createElement("div", { className: "p-4" }, /* @__PURE__ */ React8.createElement(
1689
+ )), /* @__PURE__ */ React9.createElement("div", { className: "p-4" }, /* @__PURE__ */ React9.createElement(
1329
1690
  "div",
1330
1691
  {
1331
1692
  className: "relative w-full h-96 bg-muted rounded-md overflow-hidden",
@@ -1347,7 +1708,7 @@ function FileInput({
1347
1708
  document.addEventListener("mouseup", handleMouseUp);
1348
1709
  }
1349
1710
  },
1350
- /* @__PURE__ */ React8.createElement(
1711
+ /* @__PURE__ */ React9.createElement(
1351
1712
  "img",
1352
1713
  {
1353
1714
  src: imageToCrop.url,
@@ -1382,7 +1743,7 @@ function FileInput({
1382
1743
  }
1383
1744
  }
1384
1745
  ),
1385
- /* @__PURE__ */ React8.createElement(
1746
+ /* @__PURE__ */ React9.createElement(
1386
1747
  "div",
1387
1748
  {
1388
1749
  className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 border-2 border-primary rounded pointer-events-none",
@@ -1391,9 +1752,9 @@ function FileInput({
1391
1752
  aspectRatio: cropAspectRatio ? String(cropAspectRatio) : void 0
1392
1753
  }
1393
1754
  },
1394
- /* @__PURE__ */ React8.createElement("div", { className: "absolute inset-0 grid grid-cols-3 grid-rows-3" }, /* @__PURE__ */ React8.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React8.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React8.createElement("div", null))
1755
+ /* @__PURE__ */ React9.createElement("div", { className: "absolute inset-0 grid grid-cols-3 grid-rows-3" }, /* @__PURE__ */ React9.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React9.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React9.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React9.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React9.createElement("div", { className: "border-r border-b border-primary/30" }), /* @__PURE__ */ React9.createElement("div", { className: "border-b border-primary/30" }), /* @__PURE__ */ React9.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React9.createElement("div", { className: "border-r border-primary/30" }), /* @__PURE__ */ React9.createElement("div", null))
1395
1756
  )
1396
- ), /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-3 mt-4" }, /* @__PURE__ */ React8.createElement(
1757
+ ), /* @__PURE__ */ React9.createElement("div", { className: "flex items-center gap-3 mt-4" }, /* @__PURE__ */ React9.createElement(
1397
1758
  "label",
1398
1759
  {
1399
1760
  htmlFor: "zoom-slider",
@@ -1402,7 +1763,7 @@ function FileInput({
1402
1763
  "Zoom: ",
1403
1764
  zoom.toFixed(1),
1404
1765
  "x"
1405
- ), /* @__PURE__ */ React8.createElement(
1766
+ ), /* @__PURE__ */ React9.createElement(
1406
1767
  "input",
1407
1768
  {
1408
1769
  id: "zoom-slider",
@@ -1415,7 +1776,7 @@ function FileInput({
1415
1776
  className: "flex-1 h-2 bg-muted rounded-lg appearance-none cursor-pointer",
1416
1777
  "aria-label": "Zoom level"
1417
1778
  }
1418
- ))), /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-end gap-2 p-4 border-t border-border" }, /* @__PURE__ */ React8.createElement(
1779
+ ))), /* @__PURE__ */ React9.createElement("div", { className: "flex items-center justify-end gap-2 p-4 border-t border-border" }, /* @__PURE__ */ React9.createElement(
1419
1780
  "button",
1420
1781
  {
1421
1782
  type: "button",
@@ -1423,7 +1784,7 @@ function FileInput({
1423
1784
  onClick: handleCropCancel
1424
1785
  },
1425
1786
  "Cancel"
1426
- ), /* @__PURE__ */ React8.createElement(
1787
+ ), /* @__PURE__ */ React9.createElement(
1427
1788
  "button",
1428
1789
  {
1429
1790
  type: "button",
@@ -1465,13 +1826,13 @@ function DatePicker({
1465
1826
  showIcon = true,
1466
1827
  ...props
1467
1828
  }) {
1468
- const [isOpen, setIsOpen] = React8.useState(false);
1469
- const [selectedMonth, setSelectedMonth] = React8.useState(
1829
+ const [isOpen, setIsOpen] = React9.useState(false);
1830
+ const [selectedMonth, setSelectedMonth] = React9.useState(
1470
1831
  value || /* @__PURE__ */ new Date()
1471
1832
  );
1472
- const containerRef = React8.useRef(null);
1473
- const inputRef = React8.useRef(null);
1474
- React8.useEffect(() => {
1833
+ const inputRef = React9.useRef(null);
1834
+ const dropdownRef = React9.useRef(null);
1835
+ React9.useEffect(() => {
1475
1836
  if (value) {
1476
1837
  setSelectedMonth(value);
1477
1838
  }
@@ -1497,12 +1858,20 @@ function DatePicker({
1497
1858
  if (isDateDisabled && isDateDisabled(date)) return true;
1498
1859
  return false;
1499
1860
  };
1500
- const closeCalendar = React8.useCallback(() => {
1501
- if (!isOpen) return;
1861
+ const closeCalendar = React9.useCallback(() => {
1502
1862
  setIsOpen(false);
1503
1863
  onBlur?.();
1504
- }, [isOpen, onBlur]);
1505
- useOnClickOutside(containerRef, closeCalendar, "pointerdown", true);
1864
+ }, [onBlur]);
1865
+ useOnClickOutside([inputRef, dropdownRef], closeCalendar, void 0, {
1866
+ capture: true
1867
+ });
1868
+ const handleBlur = (event) => {
1869
+ const nextTarget = event?.relatedTarget;
1870
+ const focusStayedInside = !!inputRef.current && inputRef.current.contains(nextTarget) || !!dropdownRef.current && dropdownRef.current.contains(nextTarget);
1871
+ if (!nextTarget || !focusStayedInside) {
1872
+ onBlur?.();
1873
+ }
1874
+ };
1506
1875
  const dayGridStyle = {
1507
1876
  gridTemplateColumns: "repeat(7, minmax(0, 1fr))"
1508
1877
  };
@@ -1540,7 +1909,7 @@ function DatePicker({
1540
1909
  const handleNextMonth = () => {
1541
1910
  setSelectedMonth(new Date(year, month + 1, 1));
1542
1911
  };
1543
- return /* @__PURE__ */ React8.createElement("div", { role: "grid", "aria-label": "Calendar", className: "w-[248px] max-w-full" }, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-between pb-3" }, /* @__PURE__ */ React8.createElement(
1912
+ return /* @__PURE__ */ React9.createElement("div", { role: "grid", "aria-label": "Calendar", className: "w-[248px] max-w-full" }, /* @__PURE__ */ React9.createElement("div", { className: "flex items-center justify-between pb-3" }, /* @__PURE__ */ React9.createElement(
1544
1913
  "button",
1545
1914
  {
1546
1915
  type: "button",
@@ -1549,7 +1918,7 @@ function DatePicker({
1549
1918
  "aria-label": "Previous month"
1550
1919
  },
1551
1920
  "\u2039"
1552
- ), /* @__PURE__ */ React8.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React8.createElement(
1921
+ ), /* @__PURE__ */ React9.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), /* @__PURE__ */ React9.createElement(
1553
1922
  "button",
1554
1923
  {
1555
1924
  type: "button",
@@ -1558,13 +1927,13 @@ function DatePicker({
1558
1927
  "aria-label": "Next month"
1559
1928
  },
1560
1929
  "\u203A"
1561
- )), /* @__PURE__ */ React8.createElement(
1930
+ )), /* @__PURE__ */ React9.createElement(
1562
1931
  "div",
1563
1932
  {
1564
1933
  className: "grid gap-1 text-xs text-muted-foreground",
1565
1934
  style: dayGridStyle
1566
1935
  },
1567
- ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React8.createElement(
1936
+ ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React9.createElement(
1568
1937
  "div",
1569
1938
  {
1570
1939
  key: day,
@@ -1572,14 +1941,14 @@ function DatePicker({
1572
1941
  },
1573
1942
  day
1574
1943
  ))
1575
- ), /* @__PURE__ */ React8.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
1944
+ ), /* @__PURE__ */ React9.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
1576
1945
  if (!date) {
1577
- return /* @__PURE__ */ React8.createElement("div", { key: `empty-${index}`, className: "h-8 w-8" });
1946
+ return /* @__PURE__ */ React9.createElement("div", { key: `empty-${index}`, className: "h-8 w-8" });
1578
1947
  }
1579
1948
  const isSelected = value && date.toDateString() === value.toDateString();
1580
1949
  const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
1581
1950
  const disabled2 = isDisabled(date);
1582
- return /* @__PURE__ */ React8.createElement(
1951
+ return /* @__PURE__ */ React9.createElement(
1583
1952
  "button",
1584
1953
  {
1585
1954
  key: date.toISOString(),
@@ -1600,20 +1969,20 @@ function DatePicker({
1600
1969
  })));
1601
1970
  };
1602
1971
  const combinedClassName = cn("relative", className);
1603
- return /* @__PURE__ */ React8.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React8.createElement(
1972
+ return /* @__PURE__ */ React9.createElement("div", { className: combinedClassName, onBlur: handleBlur }, /* @__PURE__ */ React9.createElement(
1604
1973
  "input",
1605
1974
  {
1606
1975
  type: "hidden",
1607
1976
  name,
1608
1977
  value: value ? value.toISOString() : ""
1609
1978
  }
1610
- ), /* @__PURE__ */ React8.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8.createElement(
1979
+ ), /* @__PURE__ */ React9.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React9.createElement(
1611
1980
  "span",
1612
1981
  {
1613
1982
  className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
1614
1983
  "aria-hidden": "true"
1615
1984
  },
1616
- /* @__PURE__ */ React8.createElement(
1985
+ /* @__PURE__ */ React9.createElement(
1617
1986
  "svg",
1618
1987
  {
1619
1988
  xmlns: "http://www.w3.org/2000/svg",
@@ -1626,9 +1995,9 @@ function DatePicker({
1626
1995
  strokeLinejoin: "round",
1627
1996
  strokeWidth: "2"
1628
1997
  },
1629
- /* @__PURE__ */ React8.createElement("path", { d: "M8 2v4m8-4v4m5 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8M3 10h18m-5 10l2 2l4-4" })
1998
+ /* @__PURE__ */ React9.createElement("path", { d: "M8 2v4m8-4v4m5 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8M3 10h18m-5 10l2 2l4-4" })
1630
1999
  )
1631
- ), /* @__PURE__ */ React8.createElement(
2000
+ ), /* @__PURE__ */ React9.createElement(
1632
2001
  "input",
1633
2002
  {
1634
2003
  ref: inputRef,
@@ -1645,7 +2014,6 @@ function DatePicker({
1645
2014
  ),
1646
2015
  value: displayValue,
1647
2016
  onClick: handleToggle,
1648
- onBlur,
1649
2017
  disabled,
1650
2018
  required,
1651
2019
  placeholder,
@@ -1654,7 +2022,7 @@ function DatePicker({
1654
2022
  "aria-required": required || props["aria-required"],
1655
2023
  readOnly: true
1656
2024
  }
1657
- ), clearable && value && !disabled && /* @__PURE__ */ React8.createElement(
2025
+ ), clearable && value && !disabled && /* @__PURE__ */ React9.createElement(
1658
2026
  "button",
1659
2027
  {
1660
2028
  type: "button",
@@ -1664,7 +2032,14 @@ function DatePicker({
1664
2032
  tabIndex: -1
1665
2033
  },
1666
2034
  "\u2715"
1667
- )), isOpen && !disabled && /* @__PURE__ */ React8.createElement("div", { className: "absolute z-50 top-full mt-1 w-fit rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3" }, renderCalendar()));
2035
+ )), isOpen && !disabled && /* @__PURE__ */ React9.createElement(
2036
+ "div",
2037
+ {
2038
+ ref: dropdownRef,
2039
+ className: "absolute z-50 top-full mt-1 w-fit rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3"
2040
+ },
2041
+ renderCalendar()
2042
+ ));
1668
2043
  }
1669
2044
  DatePicker.displayName = "DatePicker";
1670
2045
  function normalizeToNativeTime(value) {
@@ -1724,11 +2099,11 @@ function TimePicker({
1724
2099
  showIcon = true,
1725
2100
  ...props
1726
2101
  }) {
1727
- const inputRef = React8.useRef(null);
1728
- const [nativeValue, setNativeValue] = React8.useState(
2102
+ const inputRef = React9.useRef(null);
2103
+ const [nativeValue, setNativeValue] = React9.useState(
1729
2104
  normalizeToNativeTime(value)
1730
2105
  );
1731
- React8.useEffect(() => {
2106
+ React9.useEffect(() => {
1732
2107
  setNativeValue(normalizeToNativeTime(value));
1733
2108
  }, [value]);
1734
2109
  const handleChange = (e) => {
@@ -1744,13 +2119,13 @@ function TimePicker({
1744
2119
  };
1745
2120
  const hasValue = Boolean(value);
1746
2121
  const stepInSeconds = Math.max(1, minuteStep * 60);
1747
- return /* @__PURE__ */ React8.createElement("div", { className: cn("relative", className) }, /* @__PURE__ */ React8.createElement("input", { type: "hidden", name, value }), /* @__PURE__ */ React8.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8.createElement(
2122
+ return /* @__PURE__ */ React9.createElement("div", { className: cn("relative", className) }, /* @__PURE__ */ React9.createElement("input", { type: "hidden", name, value }), /* @__PURE__ */ React9.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React9.createElement(
1748
2123
  "span",
1749
2124
  {
1750
2125
  className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
1751
2126
  "aria-hidden": "true"
1752
2127
  },
1753
- /* @__PURE__ */ React8.createElement(
2128
+ /* @__PURE__ */ React9.createElement(
1754
2129
  "svg",
1755
2130
  {
1756
2131
  xmlns: "http://www.w3.org/2000/svg",
@@ -1763,10 +2138,10 @@ function TimePicker({
1763
2138
  strokeLinejoin: "round",
1764
2139
  strokeWidth: "2"
1765
2140
  },
1766
- /* @__PURE__ */ React8.createElement("circle", { cx: "12", cy: "12", r: "10" }),
1767
- /* @__PURE__ */ React8.createElement("path", { d: "M12 6v6l4 2" })
2141
+ /* @__PURE__ */ React9.createElement("circle", { cx: "12", cy: "12", r: "10" }),
2142
+ /* @__PURE__ */ React9.createElement("path", { d: "M12 6v6l4 2" })
1768
2143
  )
1769
- ), /* @__PURE__ */ React8.createElement(
2144
+ ), /* @__PURE__ */ React9.createElement(
1770
2145
  "input",
1771
2146
  {
1772
2147
  ref: inputRef,
@@ -1794,7 +2169,7 @@ function TimePicker({
1794
2169
  "aria-required": required || props["aria-required"],
1795
2170
  ...props
1796
2171
  }
1797
- ), clearable && value && !disabled && /* @__PURE__ */ React8.createElement(
2172
+ ), clearable && value && !disabled && /* @__PURE__ */ React9.createElement(
1798
2173
  "button",
1799
2174
  {
1800
2175
  type: "button",
@@ -1847,15 +2222,16 @@ function DateRangePicker({
1847
2222
  separator = " - ",
1848
2223
  ...props
1849
2224
  }) {
1850
- const [isOpen, setIsOpen] = React8.useState(false);
1851
- const [selectedMonth, setSelectedMonth] = React8.useState(
2225
+ const [isOpen, setIsOpen] = React9.useState(false);
2226
+ const [selectedMonth, setSelectedMonth] = React9.useState(
1852
2227
  value.start || /* @__PURE__ */ new Date()
1853
2228
  );
1854
- const [rangeStart, setRangeStart] = React8.useState(value.start);
1855
- const [rangeEnd, setRangeEnd] = React8.useState(value.end);
1856
- const [hoverDate, setHoverDate] = React8.useState(null);
1857
- const containerRef = React8.useRef(null);
1858
- React8.useEffect(() => {
2229
+ const [rangeStart, setRangeStart] = React9.useState(value.start);
2230
+ const [rangeEnd, setRangeEnd] = React9.useState(value.end);
2231
+ const [hoverDate, setHoverDate] = React9.useState(null);
2232
+ const triggerRef = React9.useRef(null);
2233
+ const dropdownRef = React9.useRef(null);
2234
+ React9.useEffect(() => {
1859
2235
  setRangeStart(value.start);
1860
2236
  setRangeEnd(value.end);
1861
2237
  if (value.start) {
@@ -1898,12 +2274,20 @@ function DateRangePicker({
1898
2274
  if (isDateDisabled && isDateDisabled(date)) return true;
1899
2275
  return false;
1900
2276
  };
1901
- const closeCalendar = React8.useCallback(() => {
1902
- if (!isOpen) return;
2277
+ const closeCalendar = React9.useCallback(() => {
1903
2278
  setIsOpen(false);
1904
2279
  onBlur?.();
1905
- }, [isOpen, onBlur]);
1906
- useOnClickOutside(containerRef, closeCalendar, "pointerdown", true);
2280
+ }, [onBlur]);
2281
+ useOnClickOutside([triggerRef, dropdownRef], closeCalendar, void 0, {
2282
+ capture: true
2283
+ });
2284
+ const handleBlur = (event) => {
2285
+ const nextTarget = event?.relatedTarget;
2286
+ const focusStayedInside = !!triggerRef.current && triggerRef.current.contains(nextTarget) || !!dropdownRef.current && dropdownRef.current.contains(nextTarget);
2287
+ if (!nextTarget || !focusStayedInside) {
2288
+ onBlur?.();
2289
+ }
2290
+ };
1907
2291
  const dayGridStyle = {
1908
2292
  gridTemplateColumns: "repeat(7, minmax(0, 1fr))"
1909
2293
  };
@@ -1937,7 +2321,7 @@ function DateRangePicker({
1937
2321
  for (let day = 1; day <= daysInMonth; day++) {
1938
2322
  days.push(new Date(year, month, day));
1939
2323
  }
1940
- return /* @__PURE__ */ React8.createElement("div", { className: "w-[240px] max-w-full" }, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-between pb-3" }, controls?.prev ? /* @__PURE__ */ React8.createElement(
2324
+ return /* @__PURE__ */ React9.createElement("div", { className: "w-[240px] max-w-full" }, /* @__PURE__ */ React9.createElement("div", { className: "flex items-center justify-between pb-3" }, controls?.prev ? /* @__PURE__ */ React9.createElement(
1941
2325
  "button",
1942
2326
  {
1943
2327
  type: "button",
@@ -1946,7 +2330,7 @@ function DateRangePicker({
1946
2330
  "aria-label": "Previous month"
1947
2331
  },
1948
2332
  "\u2039"
1949
- ) : /* @__PURE__ */ React8.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" }), /* @__PURE__ */ React8.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), controls?.next ? /* @__PURE__ */ React8.createElement(
2333
+ ) : /* @__PURE__ */ React9.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" }), /* @__PURE__ */ React9.createElement("div", { className: "font-medium text-sm" }, `${monthNames[month]} ${year}`), controls?.next ? /* @__PURE__ */ React9.createElement(
1950
2334
  "button",
1951
2335
  {
1952
2336
  type: "button",
@@ -1955,13 +2339,13 @@ function DateRangePicker({
1955
2339
  "aria-label": "Next month"
1956
2340
  },
1957
2341
  "\u203A"
1958
- ) : /* @__PURE__ */ React8.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" })), /* @__PURE__ */ React8.createElement(
2342
+ ) : /* @__PURE__ */ React9.createElement("div", { className: "h-8 w-8", "aria-hidden": "true" })), /* @__PURE__ */ React9.createElement(
1959
2343
  "div",
1960
2344
  {
1961
2345
  className: "grid gap-1 text-xs text-muted-foreground",
1962
2346
  style: dayGridStyle
1963
2347
  },
1964
- ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React8.createElement(
2348
+ ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map((day) => /* @__PURE__ */ React9.createElement(
1965
2349
  "div",
1966
2350
  {
1967
2351
  key: `${month}-${day}`,
@@ -1969,9 +2353,9 @@ function DateRangePicker({
1969
2353
  },
1970
2354
  day
1971
2355
  ))
1972
- ), /* @__PURE__ */ React8.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
2356
+ ), /* @__PURE__ */ React9.createElement("div", { className: "grid gap-1", style: dayGridStyle }, days.map((date, index) => {
1973
2357
  if (!date) {
1974
- return /* @__PURE__ */ React8.createElement("div", { key: `empty-${month}-${index}`, className: "h-8 w-8" });
2358
+ return /* @__PURE__ */ React9.createElement("div", { key: `empty-${month}-${index}`, className: "h-8 w-8" });
1975
2359
  }
1976
2360
  const isStart = rangeStart && date.toDateString() === rangeStart.toDateString();
1977
2361
  const isEnd = rangeEnd && date.toDateString() === rangeEnd.toDateString();
@@ -1983,7 +2367,7 @@ function DateRangePicker({
1983
2367
  );
1984
2368
  const isToday = date.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
1985
2369
  const disabled2 = isDisabled(date);
1986
- return /* @__PURE__ */ React8.createElement(
2370
+ return /* @__PURE__ */ React9.createElement(
1987
2371
  "button",
1988
2372
  {
1989
2373
  key: date.toISOString(),
@@ -2008,27 +2392,27 @@ function DateRangePicker({
2008
2392
  };
2009
2393
  const combinedClassName = cn("relative", className);
2010
2394
  const displayValue = rangeStart && rangeEnd ? `${formatDate2(rangeStart, format)}${separator}${formatDate2(rangeEnd, format)}` : rangeStart ? formatDate2(rangeStart, format) : "";
2011
- return /* @__PURE__ */ React8.createElement("div", { ref: containerRef, className: combinedClassName }, /* @__PURE__ */ React8.createElement(
2395
+ return /* @__PURE__ */ React9.createElement("div", { className: combinedClassName, onBlur: handleBlur }, /* @__PURE__ */ React9.createElement(
2012
2396
  "input",
2013
2397
  {
2014
2398
  type: "hidden",
2015
2399
  name: `${name}[start]`,
2016
2400
  value: rangeStart ? rangeStart.toISOString() : ""
2017
2401
  }
2018
- ), /* @__PURE__ */ React8.createElement(
2402
+ ), /* @__PURE__ */ React9.createElement(
2019
2403
  "input",
2020
2404
  {
2021
2405
  type: "hidden",
2022
2406
  name: `${name}[end]`,
2023
2407
  value: rangeEnd ? rangeEnd.toISOString() : ""
2024
2408
  }
2025
- ), /* @__PURE__ */ React8.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React8.createElement(
2409
+ ), /* @__PURE__ */ React9.createElement("div", { className: "relative" }, showIcon && /* @__PURE__ */ React9.createElement(
2026
2410
  "span",
2027
2411
  {
2028
2412
  className: "absolute left-3 top-1/2 -translate-y-1/2 pointer-events-none",
2029
2413
  "aria-hidden": "true"
2030
2414
  },
2031
- /* @__PURE__ */ React8.createElement(
2415
+ /* @__PURE__ */ React9.createElement(
2032
2416
  "svg",
2033
2417
  {
2034
2418
  xmlns: "http://www.w3.org/2000/svg",
@@ -2041,11 +2425,12 @@ function DateRangePicker({
2041
2425
  strokeLinejoin: "round",
2042
2426
  strokeWidth: "2"
2043
2427
  },
2044
- /* @__PURE__ */ React8.createElement("path", { d: "M8 2v4m8-4v4m5 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8M3 10h18m-5 10l2 2l4-4" })
2428
+ /* @__PURE__ */ React9.createElement("path", { d: "M8 2v4m8-4v4m5 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8M3 10h18m-5 10l2 2l4-4" })
2045
2429
  )
2046
- ), /* @__PURE__ */ React8.createElement(
2430
+ ), /* @__PURE__ */ React9.createElement(
2047
2431
  "input",
2048
2432
  {
2433
+ ref: triggerRef,
2049
2434
  type: "text",
2050
2435
  className: cn(
2051
2436
  "flex h-9 w-full rounded-md border border-input bg-transparent py-1 text-base shadow-sm transition-colors",
@@ -2059,7 +2444,6 @@ function DateRangePicker({
2059
2444
  ),
2060
2445
  value: displayValue,
2061
2446
  onClick: handleToggle,
2062
- onBlur,
2063
2447
  disabled,
2064
2448
  required,
2065
2449
  placeholder,
@@ -2068,7 +2452,7 @@ function DateRangePicker({
2068
2452
  "aria-required": required || props["aria-required"],
2069
2453
  readOnly: true
2070
2454
  }
2071
- ), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */ React8.createElement(
2455
+ ), clearable && (rangeStart || rangeEnd) && !disabled && /* @__PURE__ */ React9.createElement(
2072
2456
  "button",
2073
2457
  {
2074
2458
  type: "button",
@@ -2078,7 +2462,15 @@ function DateRangePicker({
2078
2462
  tabIndex: -1
2079
2463
  },
2080
2464
  "\u2715"
2081
- )), isOpen && !disabled && /* @__PURE__ */ React8.createElement("div", { className: "absolute z-50 top-full mt-1 w-fit rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3" }, /* @__PURE__ */ React8.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React8.createElement("div", { className: "grid gap-4", style: monthsGridStyle }, renderMonth(selectedMonth, { prev: true }), renderMonth(addMonths(selectedMonth, 1), { next: true }))), rangeStart && !rangeEnd && /* @__PURE__ */ React8.createElement("div", { className: "text-xs text-center pt-2 border-t border-border mt-2" }, "Select end date")));
2465
+ )), isOpen && !disabled && /* @__PURE__ */ React9.createElement(
2466
+ "div",
2467
+ {
2468
+ ref: dropdownRef,
2469
+ className: "absolute z-50 top-full mt-1 w-fit rounded-md border border-border bg-popover text-popover-foreground shadow-md p-3"
2470
+ },
2471
+ /* @__PURE__ */ React9.createElement("div", { role: "grid", "aria-label": "Calendar" }, /* @__PURE__ */ React9.createElement("div", { className: "grid gap-4", style: monthsGridStyle }, renderMonth(selectedMonth, { prev: true }), renderMonth(addMonths(selectedMonth, 1), { next: true }))),
2472
+ rangeStart && !rangeEnd && /* @__PURE__ */ React9.createElement("div", { className: "text-xs text-center pt-2 border-t border-border mt-2" }, "Select end date")
2473
+ ));
2082
2474
  }
2083
2475
  DateRangePicker.displayName = "DateRangePicker";
2084
2476
  function htmlToMarkdown(html) {
@@ -2149,11 +2541,11 @@ function RichTextEditor({
2149
2541
  ],
2150
2542
  ...props
2151
2543
  }) {
2152
- const [currentMode, setCurrentMode] = React8.useState(mode);
2153
- const [content, setContent] = React8.useState(value);
2154
- const editorRef = React8.useRef(null);
2155
- const textareaRef = React8.useRef(null);
2156
- React8.useEffect(() => {
2544
+ const [currentMode, setCurrentMode] = React9.useState(mode);
2545
+ const [content, setContent] = React9.useState(value);
2546
+ const editorRef = React9.useRef(null);
2547
+ const textareaRef = React9.useRef(null);
2548
+ React9.useEffect(() => {
2157
2549
  setContent(value);
2158
2550
  if (currentMode === "wysiwyg" && editorRef.current) {
2159
2551
  editorRef.current.innerHTML = value;
@@ -2241,7 +2633,7 @@ function RichTextEditor({
2241
2633
  }
2242
2634
  }
2243
2635
  };
2244
- const hasValue = React8.useMemo(() => {
2636
+ const hasValue = React9.useMemo(() => {
2245
2637
  if (!content) return false;
2246
2638
  const stripped = content.replace(/<[^>]+>/g, "").trim();
2247
2639
  return stripped.length > 0;
@@ -2258,10 +2650,10 @@ function RichTextEditor({
2258
2650
  maxHeight,
2259
2651
  overflowY: maxHeight ? "auto" : void 0
2260
2652
  };
2261
- return /* @__PURE__ */ React8.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React8.createElement("input", { type: "hidden", name, value: content }), showToolbar && /* @__PURE__ */ React8.createElement("div", { className: "flex items-center justify-between p-2 border-b border-border bg-muted/50" }, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-1" }, toolbarButtons.map((buttonName) => {
2653
+ return /* @__PURE__ */ React9.createElement("div", { className: combinedClassName }, /* @__PURE__ */ React9.createElement("input", { type: "hidden", name, value: content }), showToolbar && /* @__PURE__ */ React9.createElement("div", { className: "flex items-center justify-between p-2 border-b border-border bg-muted/50" }, /* @__PURE__ */ React9.createElement("div", { className: "flex items-center gap-1" }, toolbarButtons.map((buttonName) => {
2262
2654
  const button = toolbarConfig[buttonName];
2263
2655
  if (!button) return null;
2264
- return /* @__PURE__ */ React8.createElement(
2656
+ return /* @__PURE__ */ React9.createElement(
2265
2657
  "button",
2266
2658
  {
2267
2659
  key: buttonName,
@@ -2274,7 +2666,7 @@ function RichTextEditor({
2274
2666
  },
2275
2667
  button.icon
2276
2668
  );
2277
- })), allowModeSwitch && /* @__PURE__ */ React8.createElement(
2669
+ })), allowModeSwitch && /* @__PURE__ */ React9.createElement(
2278
2670
  "button",
2279
2671
  {
2280
2672
  type: "button",
@@ -2285,7 +2677,7 @@ function RichTextEditor({
2285
2677
  "aria-label": `Switch to ${currentMode === "wysiwyg" ? "Markdown" : "WYSIWYG"}`
2286
2678
  },
2287
2679
  currentMode === "wysiwyg" ? "MD" : "WYSIWYG"
2288
- )), /* @__PURE__ */ React8.createElement("div", { style: editorStyle }, currentMode === "wysiwyg" ? /* @__PURE__ */ React8.createElement(
2680
+ )), /* @__PURE__ */ React9.createElement("div", { style: editorStyle }, currentMode === "wysiwyg" ? /* @__PURE__ */ React9.createElement(
2289
2681
  "div",
2290
2682
  {
2291
2683
  ref: editorRef,
@@ -2300,7 +2692,7 @@ function RichTextEditor({
2300
2692
  "aria-required": required || props["aria-required"],
2301
2693
  suppressContentEditableWarning: true
2302
2694
  }
2303
- ) : /* @__PURE__ */ React8.createElement(
2695
+ ) : /* @__PURE__ */ React9.createElement(
2304
2696
  "textarea",
2305
2697
  {
2306
2698
  ref: textareaRef,
@@ -2323,6 +2715,6 @@ function RichTextEditor({
2323
2715
  }
2324
2716
  RichTextEditor.displayName = "RichTextEditor";
2325
2717
 
2326
- export { Checkbox, CheckboxGroup, DatePicker, DateRangePicker, FileInput, Radio, RichTextEditor, Select, TextArea, TextInput, TimePicker };
2718
+ export { Checkbox, CheckboxGroup, DatePicker, DateRangePicker, FileInput, MultiSelect, Radio, RichTextEditor, Select, TextArea, TextInput, TimePicker };
2327
2719
  //# sourceMappingURL=inputs.js.map
2328
2720
  //# sourceMappingURL=inputs.js.map