@timeax/form-palette 0.0.18 → 0.0.20

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.mjs CHANGED
@@ -36647,11 +36647,9 @@ var checkboxModule = {
36647
36647
  tags: ["checkbox", "group", "boolean", "tri-state"]
36648
36648
  }
36649
36649
  };
36650
- function capitalizeFirst3(label) {
36651
- if (!label) return label;
36652
- return label.charAt(0).toUpperCase() + label.slice(1);
36653
- }
36654
- function normalizeOptions(opts, config3) {
36650
+
36651
+ // src/lib/normalise-selects.ts
36652
+ function globalNormalizeOptions(opts, config3) {
36655
36653
  if (!opts || !opts.length) return [];
36656
36654
  return opts.map((raw, index2) => {
36657
36655
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
@@ -36678,6 +36676,13 @@ function normalizeOptions(opts, config3) {
36678
36676
  };
36679
36677
  });
36680
36678
  }
36679
+ function capitalizeFirst3(label) {
36680
+ if (!label) return label;
36681
+ return label.charAt(0).toUpperCase() + label.slice(1);
36682
+ }
36683
+ function normalizeOptions(opts, config3) {
36684
+ return globalNormalizeOptions(opts, config3);
36685
+ }
36681
36686
  function triggerHeight(size4) {
36682
36687
  switch (size4) {
36683
36688
  case "sm":
@@ -37299,36 +37304,8 @@ function removeSelectValue(current, valueToRemove) {
37299
37304
  const target = String(valueToRemove);
37300
37305
  return current.filter((v) => String(v) !== target);
37301
37306
  }
37302
- function capitalizeFirst4(label) {
37303
- if (!label) return label;
37304
- return label.charAt(0).toUpperCase() + label.slice(1);
37305
- }
37306
37307
  function normalizeOptions2(opts, config3) {
37307
- if (!opts || !opts.length) return [];
37308
- return opts.map((raw, index2) => {
37309
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
37310
- const asObj = typeof raw === "string" || typeof raw === "number" ? { label: String(raw), value: raw } : raw;
37311
- const value = typeof config3.optionValue === "function" ? config3.optionValue(raw) : typeof config3.optionValue === "string" ? asObj[config3.optionValue] : (_c = (_b = (_a = asObj.value) != null ? _a : asObj.id) != null ? _b : asObj.key) != null ? _c : String(index2);
37312
- let labelNode = typeof config3.optionLabel === "function" ? config3.optionLabel(raw) : typeof config3.optionLabel === "string" ? (_e = (_d = asObj[config3.optionLabel]) != null ? _d : asObj.label) != null ? _e : String(value) : (_f = asObj.label) != null ? _f : String(value);
37313
- if (config3.autoCap && typeof labelNode === "string") {
37314
- labelNode = capitalizeFirst4(labelNode);
37315
- }
37316
- const labelText = typeof labelNode === "string" ? labelNode : typeof labelNode === "number" ? String(labelNode) : (_g = asObj.labelText) != null ? _g : String(value);
37317
- const description = typeof config3.optionDescription === "function" ? config3.optionDescription(raw) : typeof config3.optionDescription === "string" ? asObj[config3.optionDescription] : asObj.description;
37318
- const disabled = typeof config3.optionDisabled === "function" ? config3.optionDisabled(raw) : typeof config3.optionDisabled === "string" ? !!asObj[config3.optionDisabled] : !!asObj.disabled;
37319
- const icon = typeof config3.optionIcon === "function" ? config3.optionIcon(raw) : typeof config3.optionIcon === "string" ? asObj[config3.optionIcon] : asObj.icon;
37320
- const key = typeof config3.optionKey === "function" ? config3.optionKey(raw, index2) : typeof config3.optionKey === "string" ? (_i = (_h = asObj[config3.optionKey]) != null ? _h : value) != null ? _i : index2 : (_k = (_j = asObj.key) != null ? _j : value) != null ? _k : index2;
37321
- return {
37322
- key: String(key),
37323
- value,
37324
- labelNode,
37325
- labelText,
37326
- description,
37327
- disabled,
37328
- icon,
37329
- raw
37330
- };
37331
- });
37308
+ return globalNormalizeOptions(opts, config3);
37332
37309
  }
37333
37310
  function triggerHeight2(size4) {
37334
37311
  switch (size4) {
@@ -37432,9 +37409,7 @@ var ShadcnMultiSelectVariant = React54.forwardRef(function ShadcnMultiSelectVari
37432
37409
  const filteredItems = React54.useMemo(() => {
37433
37410
  if (!query) return items;
37434
37411
  const q = query.toLowerCase();
37435
- return items.filter(
37436
- (it) => it.labelText.toLowerCase().includes(q)
37437
- );
37412
+ return items.filter((it) => it.labelText.toLowerCase().includes(q));
37438
37413
  }, [items, query]);
37439
37414
  const selectableItems = React54.useMemo(
37440
37415
  () => items.filter((it) => !it.disabled),
@@ -37587,7 +37562,7 @@ var ShadcnMultiSelectVariant = React54.forwardRef(function ShadcnMultiSelectVari
37587
37562
  type: "button",
37588
37563
  disabled: disabledTrigger,
37589
37564
  className: cn(
37590
- "flex w-full items-center justify-between rounded-md border border-input bg-background px-3 text-left shadow-xs",
37565
+ "flex w-full items-center justify-between rounded-md border border-input bg-surfaces-input px-3 text-left shadow-xs",
37591
37566
  "focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:border-ring",
37592
37567
  "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
37593
37568
  heightCls,
@@ -37712,9 +37687,7 @@ var ShadcnMultiSelectVariant = React54.forwardRef(function ShadcnMultiSelectVari
37712
37687
  }
37713
37688
  ),
37714
37689
  filteredItems.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs text-muted-foreground", children: emptySearchText != null ? emptySearchText : "No results found" }) : filteredItems.map((item, index2) => {
37715
- const selected = selectedValues.has(
37716
- item.value
37717
- );
37690
+ const selected = selectedValues.has(item.value);
37718
37691
  const row = /* @__PURE__ */ jsxs(
37719
37692
  "button",
37720
37693
  {
@@ -37845,9 +37818,7 @@ var ShadcnMultiSelectVariant = React54.forwardRef(function ShadcnMultiSelectVari
37845
37818
  /* @__PURE__ */ jsx(
37846
37819
  "div",
37847
37820
  {
37848
- className: cn(
37849
- "flex-1 min-w-0 flex items-stretch"
37850
- ),
37821
+ className: cn("flex-1 min-w-0 flex items-stretch"),
37851
37822
  "data-slot": "select-region",
37852
37823
  children: MultiSelectCore
37853
37824
  }
@@ -39566,12 +39537,11 @@ function clampVisible(total, minVisible, maxVisible) {
39566
39537
  function sizeClasses(size4) {
39567
39538
  switch (size4) {
39568
39539
  case "sm":
39569
- return "text-xs min-h-[2rem]";
39540
+ return "h-8 text-xs";
39570
39541
  case "lg":
39571
- return "text-sm min-h-[2.75rem]";
39572
- case "md":
39542
+ return "h-11 text-base";
39573
39543
  default:
39574
- return "text-sm min-h-[2.5rem]";
39544
+ return "h-9 text-sm";
39575
39545
  }
39576
39546
  }
39577
39547
  function densityPadding(density) {
@@ -39582,7 +39552,7 @@ function densityPadding(density) {
39582
39552
  return "py-3 px-3 gap-3";
39583
39553
  case "comfortable":
39584
39554
  default:
39585
- return "py-2 px-3 gap-2";
39555
+ return "py-1 px-3 gap-2";
39586
39556
  }
39587
39557
  }
39588
39558
  function defaultMoreLabel(count3) {
@@ -40076,7 +40046,7 @@ function Badge({
40076
40046
  }
40077
40047
  );
40078
40048
  }
40079
- function capitalizeFirst5(label) {
40049
+ function capitalizeFirst4(label) {
40080
40050
  if (!label) return label;
40081
40051
  return label.charAt(0).toUpperCase() + label.slice(1);
40082
40052
  }
@@ -40088,7 +40058,7 @@ function normalizeTree(opts, config3, level = 0, parentValue, path = []) {
40088
40058
  const value = typeof config3.optionValue === "function" ? config3.optionValue(raw) : typeof config3.optionValue === "string" ? asObj[config3.optionValue] : (_c = (_b = (_a = asObj.value) != null ? _a : asObj.id) != null ? _b : asObj.key) != null ? _c : String(index2);
40089
40059
  let labelNode = typeof config3.optionLabel === "function" ? config3.optionLabel(raw) : typeof config3.optionLabel === "string" ? (_e = (_d = asObj[config3.optionLabel]) != null ? _d : asObj.label) != null ? _e : String(value) : (_f = asObj.label) != null ? _f : String(value);
40090
40060
  if (config3.autoCap && typeof labelNode === "string") {
40091
- labelNode = capitalizeFirst5(labelNode);
40061
+ labelNode = capitalizeFirst4(labelNode);
40092
40062
  }
40093
40063
  const labelText = typeof labelNode === "string" ? labelNode : typeof labelNode === "number" ? String(labelNode) : (_g = asObj.labelText) != null ? _g : String(value);
40094
40064
  const description = typeof config3.optionDescription === "function" ? config3.optionDescription(raw) : typeof config3.optionDescription === "string" ? asObj[config3.optionDescription] : asObj.description;
@@ -41417,15 +41387,34 @@ function formatSizeDefault(size4) {
41417
41387
  const mb = kb / 1024;
41418
41388
  return `${mb.toFixed(1)} MB`;
41419
41389
  }
41420
- function sliderHeight2(size4) {
41390
+ function triggerHeight4(size4) {
41421
41391
  switch (size4) {
41422
41392
  case "sm":
41423
- return "min-h-8 text-xs";
41393
+ return "h-8 text-xs";
41424
41394
  case "lg":
41425
- return "min-h-12 text-base";
41426
- case "md":
41395
+ return "h-11 text-base";
41396
+ default:
41397
+ return "h-9 text-sm";
41398
+ }
41399
+ }
41400
+ function chipHeight(size4) {
41401
+ switch (size4) {
41402
+ case "sm":
41403
+ return "h-5";
41404
+ case "lg":
41405
+ return "h-7";
41406
+ default:
41407
+ return "h-6";
41408
+ }
41409
+ }
41410
+ function pickerBtnSize(size4) {
41411
+ switch (size4) {
41412
+ case "sm":
41413
+ return "h-6 w-6";
41414
+ case "lg":
41415
+ return "h-8 w-8";
41427
41416
  default:
41428
- return "min-h-10 text-sm";
41417
+ return "h-7 w-7";
41429
41418
  }
41430
41419
  }
41431
41420
  function toArray(v) {
@@ -41502,481 +41491,657 @@ var FileThumbnail = ({ item }) => {
41502
41491
  setPreview(item.url || item.path || null);
41503
41492
  }
41504
41493
  }, [item]);
41505
- return /* @__PURE__ */ jsx("div", { className: "relative flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-sm border bg-muted/50", children: preview ? /* @__PURE__ */ jsx("img", { src: preview, alt: "", className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsx(File2, { className: "h-4 w-4 text-muted-foreground/50" }) });
41494
+ return /* @__PURE__ */ jsx("div", { className: "relative flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-sm border bg-muted/50", children: preview ? /* @__PURE__ */ jsx(
41495
+ "img",
41496
+ {
41497
+ src: preview,
41498
+ alt: "",
41499
+ className: "h-full w-full object-cover"
41500
+ }
41501
+ ) : /* @__PURE__ */ jsx(File2, { className: "h-4 w-4 text-muted-foreground/50" }) });
41506
41502
  };
41507
- var ShadcnFileVariant = React54.forwardRef(
41508
- function ShadcnFileVariant2(props, ref) {
41509
- const {
41510
- value,
41511
- onValue,
41512
- disabled,
41513
- readOnly,
41514
- error,
41515
- size: size4 = "md",
41516
- density = "comfortable",
41517
- multiple = false,
41518
- accept,
41519
- maxFiles,
41520
- maxTotalSize,
41521
- showDropArea = false,
41522
- dropIcon,
41523
- dropTitle,
41524
- dropDescription,
41525
- renderDropArea,
41526
- renderFileItem,
41527
- showCheckboxes,
41528
- onFilesAdded,
41529
- customLoader,
41530
- mergeMode = "append",
41531
- formatFileName,
41532
- formatFileSize = formatSizeDefault,
41533
- placeholder = "Select file...",
41534
- className,
41535
- dropAreaClassName,
41536
- listClassName,
41537
- leadingIcons,
41538
- trailingIcons,
41539
- icon,
41540
- leadingControl,
41541
- trailingControl,
41542
- leadingControlClassName,
41543
- trailingControlClassName,
41544
- joinControls = true,
41545
- extendBoxToControls = true
41546
- } = props;
41547
- const items = value != null ? value : [];
41548
- const isDisabled = !!disabled || !!readOnly;
41549
- const [dragOver, setDragOver] = React54.useState(false);
41550
- const [selectedIds, setSelectedIds] = React54.useState(() => /* @__PURE__ */ new Set());
41551
- const [popoverOpen, setPopoverOpen] = React54.useState(false);
41552
- const fileInputRef = React54.useRef(null);
41553
- const heightCls = sliderHeight2(size4);
41554
- const resolvedLeadingIcons = leadingIcons || (icon ? [icon] : []);
41555
- const resolvedTrailingIcons = trailingIcons || [];
41556
- const hasExternalControls = !!leadingControl || !!trailingControl;
41557
- const COLLAPSE_LIMIT = 2;
41558
- const emitChange = React54.useCallback(
41559
- (next, meta) => {
41560
- onValue == null ? void 0 : onValue(next, { source: "variant", raw: next, nativeEvent: void 0, meta });
41561
- },
41562
- [onValue]
41563
- );
41564
- const handleAddItems = (incoming, from) => {
41565
- if (isDisabled) return;
41566
- let next = multiple ? [...items] : [];
41567
- const added = [];
41568
- for (const item of incoming) {
41569
- if (multiple && maxFiles && next.length >= maxFiles) break;
41570
- const currentTotalSize = next.reduce((acc, i) => acc + (i.size || 0), 0);
41571
- if (maxTotalSize && currentTotalSize + (item.size || 0) > maxTotalSize) break;
41572
- next.push(item);
41573
- added.push(item);
41574
- }
41575
- if (added.length > 0) {
41576
- onFilesAdded == null ? void 0 : onFilesAdded(added, { source: "variant", raw: added, nativeEvent: void 0, meta: { from } });
41577
- emitChange(next, { action: "add", from, added });
41578
- }
41579
- };
41580
- const handleRemove = (id) => {
41581
- const next = items.filter((i) => i.id !== id);
41582
- emitChange(next, { action: "remove", id });
41583
- if (selectedIds.has(id)) {
41584
- const nextSel = new Set(selectedIds);
41585
- nextSel.delete(id);
41586
- setSelectedIds(nextSel);
41503
+ var ShadcnFileVariant = React54.forwardRef(function ShadcnFileVariant2(props, ref) {
41504
+ const {
41505
+ value,
41506
+ onValue,
41507
+ disabled,
41508
+ readOnly,
41509
+ error,
41510
+ size: size4 = "md",
41511
+ density = "comfortable",
41512
+ multiple = false,
41513
+ accept,
41514
+ maxFiles,
41515
+ maxTotalSize,
41516
+ showDropArea = false,
41517
+ dropIcon,
41518
+ dropTitle,
41519
+ dropDescription,
41520
+ renderDropArea,
41521
+ renderFileItem,
41522
+ showCheckboxes,
41523
+ onFilesAdded,
41524
+ customLoader,
41525
+ mergeMode = "append",
41526
+ formatFileName,
41527
+ formatFileSize = formatSizeDefault,
41528
+ placeholder = "Select file...",
41529
+ className,
41530
+ dropAreaClassName,
41531
+ listClassName,
41532
+ leadingIcons,
41533
+ trailingIcons,
41534
+ icon,
41535
+ leadingControl,
41536
+ trailingControl,
41537
+ leadingControlClassName,
41538
+ trailingControlClassName,
41539
+ joinControls = true,
41540
+ extendBoxToControls = true
41541
+ } = props;
41542
+ const items = value != null ? value : [];
41543
+ const isDisabled = Boolean(disabled || readOnly);
41544
+ const [dragOver, setDragOver] = React54.useState(false);
41545
+ const [selectedIds, setSelectedIds] = React54.useState(
41546
+ () => /* @__PURE__ */ new Set()
41547
+ );
41548
+ const [popoverOpen, setPopoverOpen] = React54.useState(false);
41549
+ const fileInputRef = React54.useRef(null);
41550
+ const heightCls = triggerHeight4(size4);
41551
+ const chipHeightCls = chipHeight(size4);
41552
+ const pickerBtnCls = pickerBtnSize(size4);
41553
+ const resolvedLeadingIcons = leadingIcons || (icon ? [icon] : []);
41554
+ const resolvedTrailingIcons = trailingIcons || [];
41555
+ const hasExternalControls = !!leadingControl || !!trailingControl;
41556
+ const COLLAPSE_LIMIT = 2;
41557
+ const emitChange = React54.useCallback(
41558
+ (next, meta) => {
41559
+ onValue == null ? void 0 : onValue(next, {
41560
+ source: "variant",
41561
+ raw: next,
41562
+ nativeEvent: void 0,
41563
+ meta
41564
+ });
41565
+ },
41566
+ [onValue]
41567
+ );
41568
+ const handleAddItems = (incoming, from) => {
41569
+ if (isDisabled) return;
41570
+ let next = multiple ? [...items] : [];
41571
+ const added = [];
41572
+ for (const item of incoming) {
41573
+ if (multiple && maxFiles && next.length >= maxFiles) break;
41574
+ const currentTotalSize = next.reduce(
41575
+ (acc, i) => acc + (i.size || 0),
41576
+ 0
41577
+ );
41578
+ if (maxTotalSize && currentTotalSize + (item.size || 0) > maxTotalSize)
41579
+ break;
41580
+ next.push(item);
41581
+ added.push(item);
41582
+ }
41583
+ if (added.length > 0) {
41584
+ onFilesAdded == null ? void 0 : onFilesAdded(added, {
41585
+ source: "variant",
41586
+ raw: added,
41587
+ nativeEvent: void 0,
41588
+ meta: { from }
41589
+ });
41590
+ emitChange(next, { action: "add", from, added });
41591
+ }
41592
+ };
41593
+ const handleRemove = (id) => {
41594
+ const next = items.filter((i) => i.id !== id);
41595
+ emitChange(next, { action: "remove", id });
41596
+ if (selectedIds.has(id)) {
41597
+ const nextSel = new Set(selectedIds);
41598
+ nextSel.delete(id);
41599
+ setSelectedIds(nextSel);
41600
+ }
41601
+ };
41602
+ const handleBulkRemove = () => {
41603
+ const next = items.filter((i) => !selectedIds.has(i.id));
41604
+ emitChange(next, {
41605
+ action: "bulk-remove",
41606
+ ids: Array.from(selectedIds)
41607
+ });
41608
+ setSelectedIds(/* @__PURE__ */ new Set());
41609
+ };
41610
+ const openPicker = async () => {
41611
+ var _a;
41612
+ if (isDisabled) return;
41613
+ if (customLoader) {
41614
+ try {
41615
+ const result = await customLoader({ multiple, current: items });
41616
+ if (!result) return;
41617
+ const normalized = toArray(result).map(normaliseFileLike);
41618
+ if (mergeMode === "replace" || !multiple) {
41619
+ emitChange(normalized, {
41620
+ action: "set",
41621
+ from: "custom-loader"
41622
+ });
41623
+ } else {
41624
+ handleAddItems(normalized, "custom-loader");
41625
+ }
41626
+ } catch (err) {
41627
+ console.error("Custom loader failed", err);
41587
41628
  }
41588
- };
41589
- const handleBulkRemove = () => {
41590
- const next = items.filter((i) => !selectedIds.has(i.id));
41591
- emitChange(next, { action: "bulk-remove", ids: Array.from(selectedIds) });
41592
- setSelectedIds(/* @__PURE__ */ new Set());
41593
- };
41594
- const openPicker = async () => {
41629
+ return;
41630
+ }
41631
+ (_a = fileInputRef.current) == null ? void 0 : _a.click();
41632
+ };
41633
+ const onDragOver = (e) => {
41634
+ e.preventDefault();
41635
+ if (!isDisabled) setDragOver(true);
41636
+ };
41637
+ const onDrop = (e) => {
41638
+ var _a;
41639
+ e.preventDefault();
41640
+ setDragOver(false);
41641
+ if (isDisabled || !((_a = e.dataTransfer.files) == null ? void 0 : _a.length)) return;
41642
+ const files = normaliseFromFiles(e.dataTransfer.files);
41643
+ handleAddItems(files, "drop");
41644
+ };
41645
+ const onNativeChange = (e) => {
41646
+ var _a;
41647
+ if ((_a = e.target.files) == null ? void 0 : _a.length) {
41648
+ handleAddItems(normaliseFromFiles(e.target.files), "input");
41649
+ }
41650
+ e.target.value = "";
41651
+ };
41652
+ const FileChip = ({
41653
+ item,
41654
+ condensed = false
41655
+ }) => {
41656
+ const name = formatFileName ? formatFileName(item) : item.name;
41657
+ const [preview, setPreview] = React54.useState(null);
41658
+ const [isOpen, setIsOpen] = React54.useState(false);
41659
+ React54.useEffect(() => {
41595
41660
  var _a;
41596
- if (isDisabled) return;
41597
- if (customLoader) {
41598
- try {
41599
- const result = await customLoader({ multiple, current: items });
41600
- if (!result) return;
41601
- const normalized = toArray(result).map(normaliseFileLike);
41602
- if (mergeMode === "replace" || !multiple) {
41603
- emitChange(normalized, { action: "set", from: "custom-loader" });
41604
- } else {
41605
- handleAddItems(normalized, "custom-loader");
41606
- }
41607
- } catch (err) {
41608
- console.error("Custom loader failed", err);
41609
- }
41661
+ const isImage2 = ((_a = item.type) == null ? void 0 : _a.startsWith("image/")) || item.name.match(/\.(jpg|jpeg|png|gif|webp)$/i);
41662
+ if (!isImage2) {
41663
+ setPreview(null);
41610
41664
  return;
41611
41665
  }
41612
- (_a = fileInputRef.current) == null ? void 0 : _a.click();
41613
- };
41614
- const onDragOver = (e) => {
41615
- e.preventDefault();
41616
- if (!isDisabled) setDragOver(true);
41617
- };
41618
- const onDrop = (e) => {
41619
- var _a;
41620
- e.preventDefault();
41621
- setDragOver(false);
41622
- if (isDisabled || !((_a = e.dataTransfer.files) == null ? void 0 : _a.length)) return;
41623
- const files = normaliseFromFiles(e.dataTransfer.files);
41624
- handleAddItems(files, "drop");
41625
- };
41626
- const onNativeChange = (e) => {
41627
- var _a;
41628
- if ((_a = e.target.files) == null ? void 0 : _a.length) {
41629
- handleAddItems(normaliseFromFiles(e.target.files), "input");
41666
+ if (item.file) {
41667
+ const url = URL.createObjectURL(item.file);
41668
+ setPreview(url);
41669
+ return () => URL.revokeObjectURL(url);
41630
41670
  }
41631
- e.target.value = "";
41632
- };
41633
- const FileChip = ({ item, condensed = false }) => {
41634
- const name = formatFileName ? formatFileName(item) : item.name;
41635
- const [preview, setPreview] = React54.useState(null);
41636
- const [isOpen, setIsOpen] = React54.useState(false);
41637
- React54.useEffect(() => {
41638
- var _a;
41639
- const isImage2 = ((_a = item.type) == null ? void 0 : _a.startsWith("image/")) || item.name.match(/\.(jpg|jpeg|png|gif|webp)$/i);
41640
- if (!isImage2) {
41641
- setPreview(null);
41642
- return;
41671
+ if (item.url || item.path) {
41672
+ setPreview(item.url || item.path || null);
41673
+ }
41674
+ }, [item]);
41675
+ return /* @__PURE__ */ jsxs(Popover2, { open: isOpen, onOpenChange: setIsOpen, children: [
41676
+ /* @__PURE__ */ jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
41677
+ "div",
41678
+ {
41679
+ role: "button",
41680
+ tabIndex: 0,
41681
+ className: cn(
41682
+ "flex items-center gap-1.5 overflow-hidden rounded-sm border bg-muted/60 px-1.5 text-xs transition-colors hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none cursor-pointer",
41683
+ chipHeightCls,
41684
+ condensed ? "max-w-[120px]" : "max-w-[200px]"
41685
+ ),
41686
+ onPointerDown: (e) => e.stopPropagation(),
41687
+ onClick: (e) => {
41688
+ e.stopPropagation();
41689
+ setIsOpen(true);
41690
+ },
41691
+ onKeyDown: (e) => {
41692
+ if (e.key === "Enter" || e.key === " ") {
41693
+ e.stopPropagation();
41694
+ setIsOpen(true);
41695
+ }
41696
+ },
41697
+ children: [
41698
+ /* @__PURE__ */ jsx(File2, { className: "h-3 w-3 text-muted-foreground shrink-0" }),
41699
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: name }),
41700
+ /* @__PURE__ */ jsx(
41701
+ "button",
41702
+ {
41703
+ type: "button",
41704
+ onPointerDown: (e) => e.stopPropagation(),
41705
+ onClick: (e) => {
41706
+ e.stopPropagation();
41707
+ handleRemove(item.id);
41708
+ },
41709
+ className: "ml-auto flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-muted-foreground/70 hover:bg-destructive/20 hover:text-destructive focus:outline-none",
41710
+ "aria-label": "Remove file",
41711
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
41712
+ }
41713
+ )
41714
+ ]
41643
41715
  }
41644
- if (item.file) {
41645
- const url = URL.createObjectURL(item.file);
41646
- setPreview(url);
41647
- return () => URL.revokeObjectURL(url);
41716
+ ) }),
41717
+ /* @__PURE__ */ jsxs(
41718
+ PopoverContent2,
41719
+ {
41720
+ className: "w-64 p-0",
41721
+ align: "start",
41722
+ side: "bottom",
41723
+ children: [
41724
+ /* @__PURE__ */ jsx("div", { className: "relative aspect-video w-full flex items-center justify-center bg-muted/30 border-b", children: preview ? /* @__PURE__ */ jsx(
41725
+ "img",
41726
+ {
41727
+ src: preview,
41728
+ alt: item.name,
41729
+ className: "h-full w-full object-contain"
41730
+ }
41731
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 text-muted-foreground/50", children: [
41732
+ /* @__PURE__ */ jsx(File2, { className: "h-10 w-10" }),
41733
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase", children: "No Preview" })
41734
+ ] }) }),
41735
+ /* @__PURE__ */ jsxs("div", { className: "p-3", children: [
41736
+ /* @__PURE__ */ jsx(
41737
+ "div",
41738
+ {
41739
+ className: "font-medium text-sm truncate",
41740
+ title: item.name,
41741
+ children: name
41742
+ }
41743
+ ),
41744
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center justify-between text-xs text-muted-foreground", children: [
41745
+ /* @__PURE__ */ jsx("span", { children: formatFileSize(item.size) }),
41746
+ item.type && /* @__PURE__ */ jsx("span", { className: "uppercase opacity-70", children: item.type.split("/").pop() })
41747
+ ] })
41748
+ ] })
41749
+ ]
41648
41750
  }
41649
- if (item.url || item.path) {
41650
- setPreview(item.url || item.path || null);
41751
+ )
41752
+ ] });
41753
+ };
41754
+ const TriggerRegion = React54.useMemo(() => {
41755
+ if (showDropArea) {
41756
+ if (renderDropArea)
41757
+ return renderDropArea({ openPicker, isDragging: dragOver });
41758
+ return /* @__PURE__ */ jsxs(
41759
+ "div",
41760
+ {
41761
+ onClick: openPicker,
41762
+ onDragOver,
41763
+ onDragLeave: () => setDragOver(false),
41764
+ onDrop,
41765
+ className: cn(
41766
+ "group relative flex cursor-pointer flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed px-6 py-8 text-center transition-all duration-200",
41767
+ dragOver ? "border-primary bg-primary/5 ring-4 ring-primary/10" : "border-muted-foreground/25 hover:bg-muted/30 hover:border-muted-foreground/50",
41768
+ isDisabled && "cursor-not-allowed opacity-50",
41769
+ error && "border-destructive/50 bg-destructive/5",
41770
+ dropAreaClassName
41771
+ ),
41772
+ children: [
41773
+ /* @__PURE__ */ jsx("div", { className: "rounded-full bg-surfaces-input p-3 shadow-sm", children: dropIcon != null ? dropIcon : /* @__PURE__ */ jsx(CloudUpload, { className: "h-5 w-5 text-muted-foreground" }) }),
41774
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
41775
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: dropTitle != null ? dropTitle : "Click or drag to select" }),
41776
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: dropDescription != null ? dropDescription : multiple ? "Select files" : "Select a file" })
41777
+ ] })
41778
+ ]
41651
41779
  }
41652
- }, [item]);
41653
- return /* @__PURE__ */ jsxs(Popover2, { open: isOpen, onOpenChange: setIsOpen, children: [
41654
- /* @__PURE__ */ jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
41655
- "div",
41656
- {
41657
- role: "button",
41658
- tabIndex: 0,
41659
- className: cn(
41660
- "flex items-center gap-1.5 overflow-hidden rounded-sm border bg-muted/60 px-1.5 py-0.5 text-xs transition-colors hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none cursor-pointer",
41661
- condensed ? "max-w-[120px]" : "max-w-[200px]"
41780
+ );
41781
+ }
41782
+ const hasItems = items.length > 0;
41783
+ const visibleItems = items.slice(0, COLLAPSE_LIMIT);
41784
+ const hiddenCount = items.length - COLLAPSE_LIMIT;
41785
+ const isOverflowing = hiddenCount > 0;
41786
+ const anySelected = selectedIds.size > 0 && showCheckboxes && multiple;
41787
+ return /* @__PURE__ */ jsxs(Popover2, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [
41788
+ /* @__PURE__ */ jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
41789
+ "div",
41790
+ {
41791
+ className: cn(
41792
+ "relative flex w-full cursor-pointer items-center gap-2 px-3 py-0 transition-all",
41793
+ heightCls,
41794
+ (!joinControls || !hasExternalControls) && "rounded-md border border-input bg-surfaces-input ring-offset-background hover:bg-accent/5 focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
41795
+ dragOver && (!joinControls || !hasExternalControls) && "border-primary ring-2 ring-primary/20",
41796
+ isDisabled && "cursor-not-allowed opacity-50",
41797
+ error && (!joinControls || !hasExternalControls) && "border-destructive text-destructive",
41798
+ className
41799
+ ),
41800
+ onDragOver,
41801
+ onDragLeave: () => setDragOver(false),
41802
+ onDrop,
41803
+ children: [
41804
+ resolvedLeadingIcons.map((ico, i) => /* @__PURE__ */ jsx(
41805
+ "span",
41806
+ {
41807
+ className: "flex shrink-0 items-center justify-center text-muted-foreground",
41808
+ children: ico
41809
+ },
41810
+ i
41811
+ )),
41812
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center gap-2 overflow-hidden", children: hasItems ? /* @__PURE__ */ jsxs(Fragment, { children: [
41813
+ visibleItems.map((item) => /* @__PURE__ */ jsx(
41814
+ FileChip,
41815
+ {
41816
+ item,
41817
+ condensed: multiple
41818
+ },
41819
+ item.id
41820
+ )),
41821
+ isOverflowing && /* @__PURE__ */ jsxs("span", { className: "flex h-5 items-center justify-center rounded-sm bg-muted px-1.5 text-xs font-medium text-muted-foreground", children: [
41822
+ "+",
41823
+ hiddenCount
41824
+ ] })
41825
+ ] }) : /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: placeholder }) }),
41826
+ resolvedTrailingIcons.map((ico, i) => /* @__PURE__ */ jsx(
41827
+ "span",
41828
+ {
41829
+ className: "flex shrink-0 items-center justify-center text-muted-foreground",
41830
+ children: ico
41831
+ },
41832
+ i
41833
+ )),
41834
+ /* @__PURE__ */ jsx(
41835
+ Button2,
41836
+ {
41837
+ type: "button",
41838
+ variant: "ghost",
41839
+ size: "icon",
41840
+ className: cn(
41841
+ "shrink-0 text-muted-foreground hover:text-foreground",
41842
+ pickerBtnCls
41843
+ ),
41844
+ onPointerDown: (e) => e.stopPropagation(),
41845
+ onClick: (e) => {
41846
+ e.stopPropagation();
41847
+ openPicker();
41848
+ },
41849
+ children: /* @__PURE__ */ jsx(FolderUp, { className: "h-4 w-4" })
41850
+ }
41662
41851
  ),
41663
- onClick: (e) => {
41664
- e.stopPropagation();
41665
- setIsOpen(true);
41666
- },
41667
- onKeyDown: (e) => {
41668
- if (e.key === "Enter" || e.key === " ") {
41669
- e.stopPropagation();
41670
- setIsOpen(true);
41852
+ /* @__PURE__ */ jsx(
41853
+ ChevronDown,
41854
+ {
41855
+ className: cn(
41856
+ "h-4 w-4 shrink-0 text-muted-foreground opacity-50 transition-transform duration-200",
41857
+ popoverOpen && "rotate-180"
41858
+ )
41671
41859
  }
41672
- },
41673
- children: [
41674
- /* @__PURE__ */ jsx(File2, { className: "h-3 w-3 text-muted-foreground shrink-0" }),
41675
- /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: name }),
41676
- /* @__PURE__ */ jsx(
41860
+ )
41861
+ ]
41862
+ }
41863
+ ) }),
41864
+ /* @__PURE__ */ jsx(
41865
+ PopoverContent2,
41866
+ {
41867
+ className: "w-(--radix-popover-trigger-width) p-0",
41868
+ align: "start",
41869
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
41870
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-3 py-2 text-xs font-medium text-muted-foreground", children: [
41871
+ /* @__PURE__ */ jsx("span", { children: anySelected ? `${selectedIds.size} selected` : `${items.length} files total` }),
41872
+ anySelected ? /* @__PURE__ */ jsx(
41677
41873
  "button",
41678
41874
  {
41679
41875
  type: "button",
41680
- onClick: (e) => {
41681
- e.stopPropagation();
41682
- handleRemove(item.id);
41683
- },
41684
- className: "ml-auto flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-muted-foreground/70 hover:bg-destructive/20 hover:text-destructive focus:outline-none",
41685
- "aria-label": "Remove file",
41686
- children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
41876
+ className: "text-destructive hover:underline",
41877
+ onClick: handleBulkRemove,
41878
+ children: "Remove selected"
41687
41879
  }
41688
- )
41689
- ]
41690
- }
41691
- ) }),
41692
- /* @__PURE__ */ jsxs(PopoverContent2, { className: "w-64 p-0", align: "start", side: "bottom", children: [
41693
- /* @__PURE__ */ jsx("div", { className: "relative aspect-video w-full flex items-center justify-center bg-muted/30 border-b", children: preview ? /* @__PURE__ */ jsx("img", { src: preview, alt: item.name, className: "h-full w-full object-contain" }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 text-muted-foreground/50", children: [
41694
- /* @__PURE__ */ jsx(File2, { className: "h-10 w-10" }),
41695
- /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase", children: "No Preview" })
41696
- ] }) }),
41697
- /* @__PURE__ */ jsxs("div", { className: "p-3", children: [
41698
- /* @__PURE__ */ jsx("div", { className: "font-medium text-sm truncate", title: item.name, children: name }),
41699
- /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center justify-between text-xs text-muted-foreground", children: [
41700
- /* @__PURE__ */ jsx("span", { children: formatFileSize(item.size) }),
41701
- item.type && /* @__PURE__ */ jsx("span", { className: "uppercase opacity-70", children: item.type.split("/").pop() })
41702
- ] })
41880
+ ) : items.length > 0 ? /* @__PURE__ */ jsx(
41881
+ "button",
41882
+ {
41883
+ type: "button",
41884
+ className: "text-muted-foreground hover:text-foreground",
41885
+ onClick: () => emitChange([], { action: "clear" }),
41886
+ children: "Clear all"
41887
+ }
41888
+ ) : null
41889
+ ] }),
41890
+ /* @__PURE__ */ jsx(ScrollArea2, { className: "h-auto max-h-[300px] w-full p-1", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
41891
+ items.map((item) => {
41892
+ var _a;
41893
+ const selected = selectedIds.has(item.id);
41894
+ const toggle = () => {
41895
+ const next = new Set(selectedIds);
41896
+ if (next.has(item.id))
41897
+ next.delete(item.id);
41898
+ else next.add(item.id);
41899
+ setSelectedIds(next);
41900
+ };
41901
+ return /* @__PURE__ */ jsxs(
41902
+ "div",
41903
+ {
41904
+ className: "group flex items-center gap-3 rounded-md px-2 py-2 text-sm transition-colors hover:bg-muted/50",
41905
+ children: [
41906
+ showCheckboxes && multiple && /* @__PURE__ */ jsx(
41907
+ Checkbox2,
41908
+ {
41909
+ checked: selected,
41910
+ onCheckedChange: toggle,
41911
+ className: "h-4 w-4 shrink-0"
41912
+ }
41913
+ ),
41914
+ /* @__PURE__ */ jsx(FileThumbnail, { item }),
41915
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
41916
+ /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }),
41917
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
41918
+ /* @__PURE__ */ jsx("span", { children: formatFileSize(
41919
+ item.size
41920
+ ) }),
41921
+ item.status === "failed" && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "Failed" })
41922
+ ] })
41923
+ ] }),
41924
+ /* @__PURE__ */ jsx(
41925
+ Button2,
41926
+ {
41927
+ variant: "ghost",
41928
+ size: "icon",
41929
+ className: "h-7 w-7 opacity-0 group-hover:opacity-100",
41930
+ onClick: (e) => {
41931
+ e.stopPropagation();
41932
+ handleRemove(item.id);
41933
+ },
41934
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5 text-muted-foreground" })
41935
+ }
41936
+ )
41937
+ ]
41938
+ },
41939
+ item.id
41940
+ );
41941
+ }),
41942
+ items.length === 0 && /* @__PURE__ */ jsx("div", { className: "py-4 text-center text-xs text-muted-foreground", children: "No files selected" })
41943
+ ] }) }),
41944
+ /* @__PURE__ */ jsx("div", { className: "border-t p-1", children: /* @__PURE__ */ jsxs(
41945
+ Button2,
41946
+ {
41947
+ variant: "secondary",
41948
+ size: "sm",
41949
+ className: "w-full justify-start text-xs",
41950
+ onClick: () => {
41951
+ setPopoverOpen(false);
41952
+ openPicker();
41953
+ },
41954
+ children: [
41955
+ /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-3 w-3" }),
41956
+ multiple ? "Add files..." : items.length ? "Replace file" : "Add file"
41957
+ ]
41958
+ }
41959
+ ) })
41703
41960
  ] })
41704
- ] })
41705
- ] });
41706
- };
41707
- const TriggerRegion = React54.useMemo(() => {
41708
- if (showDropArea) {
41709
- if (renderDropArea) return renderDropArea({ openPicker, isDragging: dragOver });
41710
- return /* @__PURE__ */ jsxs(
41711
- "div",
41961
+ }
41962
+ )
41963
+ ] });
41964
+ }, [
41965
+ showDropArea,
41966
+ items,
41967
+ multiple,
41968
+ dragOver,
41969
+ isDisabled,
41970
+ placeholder,
41971
+ joinControls,
41972
+ hasExternalControls,
41973
+ resolvedLeadingIcons,
41974
+ resolvedTrailingIcons,
41975
+ popoverOpen,
41976
+ COLLAPSE_LIMIT,
41977
+ heightCls,
41978
+ chipHeightCls,
41979
+ pickerBtnCls,
41980
+ openPicker,
41981
+ onDragOver,
41982
+ onDrop,
41983
+ renderDropArea,
41984
+ className,
41985
+ error,
41986
+ dropAreaClassName,
41987
+ dropIcon,
41988
+ dropTitle,
41989
+ dropDescription,
41990
+ selectedIds,
41991
+ showCheckboxes,
41992
+ handleBulkRemove,
41993
+ emitChange,
41994
+ formatFileName,
41995
+ formatFileSize,
41996
+ handleRemove
41997
+ ]);
41998
+ const showExternalList = multiple && showDropArea && items.length > 0;
41999
+ const anySelectedExternal = selectedIds.size > 0 && showCheckboxes && multiple;
42000
+ const ExternalFileList = showExternalList ? /* @__PURE__ */ jsxs(Fragment, { children: [
42001
+ (anySelectedExternal || items.length > 0) && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-between px-1 text-xs text-muted-foreground", children: [
42002
+ /* @__PURE__ */ jsxs("span", { children: [
42003
+ items.length,
42004
+ " files"
42005
+ ] }),
42006
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
42007
+ anySelectedExternal && /* @__PURE__ */ jsx(
42008
+ "button",
41712
42009
  {
41713
- onClick: openPicker,
41714
- onDragOver,
41715
- onDragLeave: () => setDragOver(false),
41716
- onDrop,
41717
- className: cn(
41718
- "group relative flex cursor-pointer flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed px-6 py-8 text-center transition-all duration-200",
41719
- dragOver ? "border-primary bg-primary/5 ring-4 ring-primary/10" : "border-muted-foreground/25 hover:bg-muted/30 hover:border-muted-foreground/50",
41720
- isDisabled && "cursor-not-allowed opacity-50",
41721
- error && "border-destructive/50 bg-destructive/5",
41722
- dropAreaClassName
41723
- ),
41724
- children: [
41725
- /* @__PURE__ */ jsx("div", { className: "rounded-full bg-surfaces-input p-3 shadow-sm", children: dropIcon != null ? dropIcon : /* @__PURE__ */ jsx(CloudUpload, { className: "h-5 w-5 text-muted-foreground" }) }),
41726
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
41727
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: dropTitle != null ? dropTitle : "Click or drag to select" }),
41728
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: dropDescription != null ? dropDescription : multiple ? "Select files" : "Select a file" })
41729
- ] })
41730
- ]
42010
+ type: "button",
42011
+ onClick: handleBulkRemove,
42012
+ className: "text-destructive hover:underline",
42013
+ children: "Remove selected"
41731
42014
  }
41732
- );
42015
+ ),
42016
+ /* @__PURE__ */ jsx(
42017
+ "button",
42018
+ {
42019
+ type: "button",
42020
+ onClick: () => emitChange([], { action: "clear" }),
42021
+ className: "hover:text-foreground",
42022
+ children: "Clear all"
42023
+ }
42024
+ )
42025
+ ] })
42026
+ ] }),
42027
+ /* @__PURE__ */ jsx(ScrollArea2, { className: cn("mt-1 w-full", listClassName), children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: items.map((item, index2) => {
42028
+ var _a;
42029
+ const selected = selectedIds.has(item.id);
42030
+ const toggle = () => {
42031
+ const next = new Set(selectedIds);
42032
+ if (next.has(item.id)) next.delete(item.id);
42033
+ else next.add(item.id);
42034
+ setSelectedIds(next);
42035
+ };
42036
+ if (renderFileItem) {
42037
+ return renderFileItem({
42038
+ item,
42039
+ index: index2,
42040
+ selected,
42041
+ toggleSelected: toggle,
42042
+ remove: () => handleRemove(item.id)
42043
+ });
41733
42044
  }
41734
- const hasItems = items.length > 0;
41735
- const visibleItems = items.slice(0, COLLAPSE_LIMIT);
41736
- const hiddenCount = items.length - COLLAPSE_LIMIT;
41737
- const isOverflowing = hiddenCount > 0;
41738
- const anySelected = selectedIds.size > 0 && showCheckboxes && multiple;
41739
- return /* @__PURE__ */ jsxs(Popover2, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [
41740
- /* @__PURE__ */ jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
42045
+ return /* @__PURE__ */ jsxs(
42046
+ "div",
42047
+ {
42048
+ className: "group relative flex items-center gap-3 rounded-lg border bg-card p-2 pr-3 transition-all hover:bg-muted/30",
42049
+ children: [
42050
+ showCheckboxes && /* @__PURE__ */ jsx(
42051
+ Checkbox2,
42052
+ {
42053
+ checked: selected,
42054
+ onCheckedChange: toggle,
42055
+ className: "ml-1"
42056
+ }
42057
+ ),
42058
+ /* @__PURE__ */ jsx(FileThumbnail, { item }),
42059
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
42060
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between gap-2", children: /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-foreground", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }) }),
42061
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
42062
+ /* @__PURE__ */ jsx("span", { children: formatFileSize(item.size) }),
42063
+ item.status === "loading" && /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 text-primary", children: /* @__PURE__ */ jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }) }),
42064
+ item.status === "failed" && /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 text-destructive", children: /* @__PURE__ */ jsx(CircleAlert, { className: "h-3 w-3" }) }),
42065
+ item.status === "done" && /* @__PURE__ */ jsx(CircleCheck, { className: "h-3 w-3 text-emerald-500" })
42066
+ ] })
42067
+ ] }),
42068
+ /* @__PURE__ */ jsx(
42069
+ "button",
42070
+ {
42071
+ type: "button",
42072
+ onClick: () => handleRemove(item.id),
42073
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground/70 opacity-0 transition-all hover:bg-destructive/10 hover:text-destructive group-hover:opacity-100",
42074
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
42075
+ }
42076
+ )
42077
+ ]
42078
+ },
42079
+ item.id
42080
+ );
42081
+ }) }) })
42082
+ ] }) : null;
42083
+ const joinedBox = joinControls && extendBoxToControls && !showDropArea;
42084
+ return /* @__PURE__ */ jsxs(
42085
+ "div",
42086
+ {
42087
+ ref,
42088
+ className: cn("w-full", className),
42089
+ "aria-disabled": isDisabled,
42090
+ "aria-invalid": !!error,
42091
+ children: [
42092
+ /* @__PURE__ */ jsxs(
41741
42093
  "div",
41742
42094
  {
41743
42095
  className: cn(
41744
- "relative flex w-full cursor-pointer items-center gap-2 px-3 transition-all",
41745
- heightCls,
41746
- (!joinControls || !hasExternalControls) && "rounded-md border border-input bg-surfaces-input ring-offset-background hover:bg-accent/5 focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
41747
- dragOver && "border-primary ring-2 ring-primary/20",
41748
- isDisabled && "cursor-not-allowed opacity-50",
41749
- error && "border-destructive text-destructive",
41750
- className
42096
+ "flex w-full",
42097
+ joinedBox ? "items-stretch rounded-md border border-input bg-surfaces-input shadow-xs ring-offset-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2" : "items-start gap-2",
42098
+ // if the wrapper owns the border, apply border-state feedback here too
42099
+ joinedBox && dragOver && "border-primary ring-2 ring-primary/20",
42100
+ joinedBox && error && "border-destructive"
41751
42101
  ),
41752
- onDragOver,
41753
- onDragLeave: () => setDragOver(false),
41754
- onDrop,
41755
42102
  children: [
41756
- resolvedLeadingIcons.map((ico, i) => /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center justify-center text-muted-foreground", children: ico }, i)),
41757
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center gap-2 overflow-hidden", children: hasItems ? /* @__PURE__ */ jsxs(Fragment, { children: [
41758
- visibleItems.map((item) => /* @__PURE__ */ jsx(FileChip, { item, condensed: multiple }, item.id)),
41759
- isOverflowing && /* @__PURE__ */ jsxs("span", { className: "flex h-5 items-center justify-center rounded-sm bg-muted px-1.5 text-xs font-medium text-muted-foreground", children: [
41760
- "+",
41761
- hiddenCount
41762
- ] })
41763
- ] }) : /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: placeholder }) }),
41764
- resolvedTrailingIcons.map((ico, i) => /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center justify-center text-muted-foreground", children: ico }, i)),
41765
- /* @__PURE__ */ jsx(
41766
- Button2,
42103
+ leadingControl && /* @__PURE__ */ jsx(
42104
+ "div",
41767
42105
  {
41768
- type: "button",
41769
- variant: "ghost",
41770
- size: "icon",
41771
- className: "h-6 w-6 shrink-0 text-muted-foreground hover:text-foreground",
41772
- onClick: (e) => {
41773
- e.stopPropagation();
41774
- openPicker();
41775
- },
41776
- children: /* @__PURE__ */ jsx(FolderUp, { className: "h-4 w-4" })
42106
+ className: cn(
42107
+ "flex items-center",
42108
+ joinControls && !showDropArea && "border-r bg-muted/50 px-3",
42109
+ leadingControlClassName
42110
+ ),
42111
+ children: leadingControl
41777
42112
  }
41778
42113
  ),
41779
- /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 text-muted-foreground opacity-50 transition-transform duration-200", popoverOpen && "rotate-180") })
42114
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: TriggerRegion }),
42115
+ trailingControl && /* @__PURE__ */ jsx(
42116
+ "div",
42117
+ {
42118
+ className: cn(
42119
+ "flex items-center",
42120
+ joinControls && !showDropArea && "border-l bg-muted/50 px-3",
42121
+ trailingControlClassName
42122
+ ),
42123
+ children: trailingControl
42124
+ }
42125
+ )
41780
42126
  ]
41781
42127
  }
41782
- ) }),
42128
+ ),
42129
+ ExternalFileList,
41783
42130
  /* @__PURE__ */ jsx(
41784
- PopoverContent2,
42131
+ "input",
41785
42132
  {
41786
- className: "w-(--radix-popover-trigger-width) p-0",
41787
- align: "start",
41788
- children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
41789
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-3 py-2 text-xs font-medium text-muted-foreground", children: [
41790
- /* @__PURE__ */ jsx("span", { children: anySelected ? `${selectedIds.size} selected` : `${items.length} files total` }),
41791
- anySelected ? /* @__PURE__ */ jsx(
41792
- "button",
41793
- {
41794
- type: "button",
41795
- className: "text-destructive hover:underline",
41796
- onClick: handleBulkRemove,
41797
- children: "Remove selected"
41798
- }
41799
- ) : items.length > 0 && /* @__PURE__ */ jsx(
41800
- "button",
41801
- {
41802
- type: "button",
41803
- className: "text-muted-foreground hover:text-foreground",
41804
- onClick: () => emitChange([], { action: "clear" }),
41805
- children: "Clear all"
41806
- }
41807
- )
41808
- ] }),
41809
- /* @__PURE__ */ jsx(ScrollArea2, { className: "h-auto max-h-[300px] w-full p-1", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
41810
- items.map((item) => {
41811
- var _a;
41812
- const selected = selectedIds.has(item.id);
41813
- const toggle = () => {
41814
- const next = new Set(selectedIds);
41815
- if (next.has(item.id)) next.delete(item.id);
41816
- else next.add(item.id);
41817
- setSelectedIds(next);
41818
- };
41819
- return /* @__PURE__ */ jsxs("div", { className: "group flex items-center gap-3 rounded-md px-2 py-2 text-sm transition-colors hover:bg-muted/50", children: [
41820
- showCheckboxes && multiple && /* @__PURE__ */ jsx(Checkbox2, { checked: selected, onCheckedChange: toggle, className: "h-4 w-4 shrink-0" }),
41821
- /* @__PURE__ */ jsx(FileThumbnail, { item }),
41822
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
41823
- /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }),
41824
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
41825
- /* @__PURE__ */ jsx("span", { children: formatFileSize(item.size) }),
41826
- item.status === "failed" && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "Failed" })
41827
- ] })
41828
- ] }),
41829
- /* @__PURE__ */ jsx(
41830
- Button2,
41831
- {
41832
- variant: "ghost",
41833
- size: "icon",
41834
- className: "h-7 w-7 opacity-0 group-hover:opacity-100",
41835
- onClick: (e) => {
41836
- e.stopPropagation();
41837
- handleRemove(item.id);
41838
- },
41839
- children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5 text-muted-foreground" })
41840
- }
41841
- )
41842
- ] }, item.id);
41843
- }),
41844
- items.length === 0 && /* @__PURE__ */ jsx("div", { className: "py-4 text-center text-xs text-muted-foreground", children: "No files selected" })
41845
- ] }) }),
41846
- /* @__PURE__ */ jsx("div", { className: "border-t p-1", children: /* @__PURE__ */ jsxs(
41847
- Button2,
41848
- {
41849
- variant: "secondary",
41850
- size: "sm",
41851
- className: "w-full justify-start text-xs",
41852
- onClick: () => {
41853
- setPopoverOpen(false);
41854
- openPicker();
41855
- },
41856
- children: [
41857
- /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-3 w-3" }),
41858
- multiple ? "Add files..." : items.length ? "Replace file" : "Add file"
41859
- ]
41860
- }
41861
- ) })
41862
- ] })
42133
+ ref: fileInputRef,
42134
+ type: "file",
42135
+ className: "hidden",
42136
+ multiple,
42137
+ accept: Array.isArray(accept) ? accept.join(",") : accept,
42138
+ onChange: onNativeChange
41863
42139
  }
41864
42140
  )
41865
- ] });
41866
- }, [
41867
- showDropArea,
41868
- items,
41869
- multiple,
41870
- dragOver,
41871
- isDisabled,
41872
- placeholder,
41873
- joinControls,
41874
- hasExternalControls,
41875
- resolvedLeadingIcons,
41876
- resolvedTrailingIcons,
41877
- popoverOpen,
41878
- COLLAPSE_LIMIT,
41879
- heightCls,
41880
- openPicker,
41881
- onDragOver,
41882
- onDrop,
41883
- renderDropArea,
41884
- className,
41885
- error,
41886
- dropAreaClassName,
41887
- dropIcon,
41888
- dropTitle,
41889
- dropDescription,
41890
- selectedIds,
41891
- showCheckboxes,
41892
- handleBulkRemove,
41893
- emitChange,
41894
- formatFileName,
41895
- formatFileSize,
41896
- handleRemove
41897
- ]);
41898
- const showExternalList = multiple && showDropArea && items.length > 0;
41899
- const anySelectedExternal = selectedIds.size > 0 && showCheckboxes && multiple;
41900
- const ExternalFileList = showExternalList ? /* @__PURE__ */ jsxs(Fragment, { children: [
41901
- (anySelectedExternal || items.length > 0) && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-between px-1 text-xs text-muted-foreground", children: [
41902
- /* @__PURE__ */ jsxs("span", { children: [
41903
- items.length,
41904
- " files"
41905
- ] }),
41906
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
41907
- anySelectedExternal && /* @__PURE__ */ jsx("button", { type: "button", onClick: handleBulkRemove, className: "text-destructive hover:underline", children: "Remove selected" }),
41908
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => emitChange([], { action: "clear" }), className: "hover:text-foreground", children: "Clear all" })
41909
- ] })
41910
- ] }),
41911
- /* @__PURE__ */ jsx(ScrollArea2, { className: cn("mt-1 w-full", listClassName), children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: items.map((item, index2) => {
41912
- var _a;
41913
- const selected = selectedIds.has(item.id);
41914
- const toggle = () => {
41915
- const next = new Set(selectedIds);
41916
- if (next.has(item.id)) next.delete(item.id);
41917
- else next.add(item.id);
41918
- setSelectedIds(next);
41919
- };
41920
- if (renderFileItem) {
41921
- return renderFileItem({ item, index: index2, selected, toggleSelected: toggle, remove: () => handleRemove(item.id) });
41922
- }
41923
- return /* @__PURE__ */ jsxs("div", { className: "group relative flex items-center gap-3 rounded-lg border bg-card p-2 pr-3 transition-all hover:bg-muted/30", children: [
41924
- showCheckboxes && /* @__PURE__ */ jsx(Checkbox2, { checked: selected, onCheckedChange: toggle, className: "ml-1" }),
41925
- /* @__PURE__ */ jsx(FileThumbnail, { item }),
41926
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
41927
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between gap-2", children: /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-foreground", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }) }),
41928
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
41929
- /* @__PURE__ */ jsx("span", { children: formatFileSize(item.size) }),
41930
- item.status === "loading" && /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 text-primary", children: /* @__PURE__ */ jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }) }),
41931
- item.status === "failed" && /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 text-destructive", children: /* @__PURE__ */ jsx(CircleAlert, { className: "h-3 w-3" }) }),
41932
- item.status === "done" && /* @__PURE__ */ jsx(CircleCheck, { className: "h-3 w-3 text-emerald-500" })
41933
- ] })
41934
- ] }),
41935
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => handleRemove(item.id), className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-muted-foreground/70 opacity-0 transition-all hover:bg-destructive/10 hover:text-destructive group-hover:opacity-100", children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" }) })
41936
- ] }, item.id);
41937
- }) }) })
41938
- ] }) : null;
41939
- return /* @__PURE__ */ jsxs(
41940
- "div",
41941
- {
41942
- ref,
41943
- className: cn("w-full", className),
41944
- "aria-disabled": isDisabled,
41945
- "aria-invalid": !!error,
41946
- children: [
41947
- /* @__PURE__ */ jsxs("div", { className: cn(
41948
- "flex w-full",
41949
- joinControls && extendBoxToControls && !showDropArea ? "items-stretch rounded-md border border-input bg-surfaces-input shadow-xs ring-offset-background focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2" : "items-start gap-2"
41950
- ), children: [
41951
- leadingControl && /* @__PURE__ */ jsx("div", { className: cn(
41952
- "flex items-center",
41953
- joinControls && !showDropArea && "border-r bg-muted/50 px-3",
41954
- leadingControlClassName
41955
- ), children: leadingControl }),
41956
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: TriggerRegion }),
41957
- trailingControl && /* @__PURE__ */ jsx("div", { className: cn(
41958
- "flex items-center",
41959
- joinControls && !showDropArea && "border-l bg-muted/50 px-3",
41960
- trailingControlClassName
41961
- ), children: trailingControl })
41962
- ] }),
41963
- ExternalFileList,
41964
- /* @__PURE__ */ jsx(
41965
- "input",
41966
- {
41967
- ref: fileInputRef,
41968
- type: "file",
41969
- className: "hidden",
41970
- multiple,
41971
- accept: Array.isArray(accept) ? accept.join(",") : accept,
41972
- onChange: onNativeChange
41973
- }
41974
- )
41975
- ]
41976
- }
41977
- );
41978
- }
41979
- );
42141
+ ]
42142
+ }
42143
+ );
42144
+ });
41980
42145
  ShadcnFileVariant.displayName = "ShadcnFileVariant";
41981
42146
  var file_default = ShadcnFileVariant;
41982
42147
 
@@ -43142,7 +43307,7 @@ function normalizeValue(val, multiple) {
43142
43307
  if (Array.isArray(val)) return val[0] || "";
43143
43308
  return val || "";
43144
43309
  }
43145
- function capitalizeFirst6(label) {
43310
+ function capitalizeFirst5(label) {
43146
43311
  if (!label) return label;
43147
43312
  return label.charAt(0).toUpperCase() + label.slice(1);
43148
43313
  }
@@ -43168,7 +43333,7 @@ function normalizeOption(input, {
43168
43333
  label2 = String(rawValue != null ? rawValue : value2);
43169
43334
  }
43170
43335
  if (autoCap && typeof label2 === "string") {
43171
- label2 = capitalizeFirst6(label2);
43336
+ label2 = capitalizeFirst5(label2);
43172
43337
  }
43173
43338
  const icon = optionIcon != null ? anyInput[optionIcon] : (_b = anyInput.icon) != null ? _b : void 0;
43174
43339
  const disabled = optionDisabled != null ? !!anyInput[optionDisabled] : !!anyInput.disabled;
@@ -43190,7 +43355,7 @@ function normalizeOption(input, {
43190
43355
  const value2 = String(input);
43191
43356
  let label2 = value2;
43192
43357
  if (autoCap && typeof label2 === "string") {
43193
- label2 = capitalizeFirst6(label2);
43358
+ label2 = capitalizeFirst5(label2);
43194
43359
  }
43195
43360
  return {
43196
43361
  ui: {
@@ -43204,7 +43369,7 @@ function normalizeOption(input, {
43204
43369
  const value = String(baseValue);
43205
43370
  let label = anyInput.label != null ? anyInput.label : String(value);
43206
43371
  if (autoCap && typeof label === "string") {
43207
- label = capitalizeFirst6(label);
43372
+ label = capitalizeFirst5(label);
43208
43373
  }
43209
43374
  return {
43210
43375
  ui: {