@timeax/form-palette 0.0.19 → 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.js CHANGED
@@ -39558,12 +39558,11 @@ function clampVisible(total, minVisible, maxVisible) {
39558
39558
  function sizeClasses(size4) {
39559
39559
  switch (size4) {
39560
39560
  case "sm":
39561
- return "text-xs min-h-[2rem]";
39561
+ return "h-8 text-xs";
39562
39562
  case "lg":
39563
- return "text-sm min-h-[2.75rem]";
39564
- case "md":
39563
+ return "h-11 text-base";
39565
39564
  default:
39566
- return "text-sm min-h-[2.5rem]";
39565
+ return "h-9 text-sm";
39567
39566
  }
39568
39567
  }
39569
39568
  function densityPadding(density) {
@@ -39574,7 +39573,7 @@ function densityPadding(density) {
39574
39573
  return "py-3 px-3 gap-3";
39575
39574
  case "comfortable":
39576
39575
  default:
39577
- return "py-2 px-3 gap-2";
39576
+ return "py-1 px-3 gap-2";
39578
39577
  }
39579
39578
  }
39580
39579
  function defaultMoreLabel(count3) {
@@ -41409,15 +41408,34 @@ function formatSizeDefault(size4) {
41409
41408
  const mb = kb / 1024;
41410
41409
  return `${mb.toFixed(1)} MB`;
41411
41410
  }
41412
- function sliderHeight2(size4) {
41411
+ function triggerHeight4(size4) {
41413
41412
  switch (size4) {
41414
41413
  case "sm":
41415
- return "min-h-8 text-xs";
41414
+ return "h-8 text-xs";
41416
41415
  case "lg":
41417
- return "min-h-12 text-base";
41418
- case "md":
41416
+ return "h-11 text-base";
41417
+ default:
41418
+ return "h-9 text-sm";
41419
+ }
41420
+ }
41421
+ function chipHeight(size4) {
41422
+ switch (size4) {
41423
+ case "sm":
41424
+ return "h-5";
41425
+ case "lg":
41426
+ return "h-7";
41419
41427
  default:
41420
- return "min-h-10 text-sm";
41428
+ return "h-6";
41429
+ }
41430
+ }
41431
+ function pickerBtnSize(size4) {
41432
+ switch (size4) {
41433
+ case "sm":
41434
+ return "h-6 w-6";
41435
+ case "lg":
41436
+ return "h-8 w-8";
41437
+ default:
41438
+ return "h-7 w-7";
41421
41439
  }
41422
41440
  }
41423
41441
  function toArray(v) {
@@ -41494,481 +41512,657 @@ var FileThumbnail = ({ item }) => {
41494
41512
  setPreview(item.url || item.path || null);
41495
41513
  }
41496
41514
  }, [item]);
41497
- return /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("img", { src: preview, alt: "", className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx(File2, { className: "h-4 w-4 text-muted-foreground/50" }) });
41515
+ return /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(
41516
+ "img",
41517
+ {
41518
+ src: preview,
41519
+ alt: "",
41520
+ className: "h-full w-full object-cover"
41521
+ }
41522
+ ) : /* @__PURE__ */ jsxRuntime.jsx(File2, { className: "h-4 w-4 text-muted-foreground/50" }) });
41498
41523
  };
41499
- var ShadcnFileVariant = React54__namespace.forwardRef(
41500
- function ShadcnFileVariant2(props, ref) {
41501
- const {
41502
- value,
41503
- onValue,
41504
- disabled,
41505
- readOnly,
41506
- error,
41507
- size: size4 = "md",
41508
- density = "comfortable",
41509
- multiple = false,
41510
- accept,
41511
- maxFiles,
41512
- maxTotalSize,
41513
- showDropArea = false,
41514
- dropIcon,
41515
- dropTitle,
41516
- dropDescription,
41517
- renderDropArea,
41518
- renderFileItem,
41519
- showCheckboxes,
41520
- onFilesAdded,
41521
- customLoader,
41522
- mergeMode = "append",
41523
- formatFileName,
41524
- formatFileSize = formatSizeDefault,
41525
- placeholder = "Select file...",
41526
- className,
41527
- dropAreaClassName,
41528
- listClassName,
41529
- leadingIcons,
41530
- trailingIcons,
41531
- icon,
41532
- leadingControl,
41533
- trailingControl,
41534
- leadingControlClassName,
41535
- trailingControlClassName,
41536
- joinControls = true,
41537
- extendBoxToControls = true
41538
- } = props;
41539
- const items = value != null ? value : [];
41540
- const isDisabled = !!disabled || !!readOnly;
41541
- const [dragOver, setDragOver] = React54__namespace.useState(false);
41542
- const [selectedIds, setSelectedIds] = React54__namespace.useState(() => /* @__PURE__ */ new Set());
41543
- const [popoverOpen, setPopoverOpen] = React54__namespace.useState(false);
41544
- const fileInputRef = React54__namespace.useRef(null);
41545
- const heightCls = sliderHeight2(size4);
41546
- const resolvedLeadingIcons = leadingIcons || (icon ? [icon] : []);
41547
- const resolvedTrailingIcons = trailingIcons || [];
41548
- const hasExternalControls = !!leadingControl || !!trailingControl;
41549
- const COLLAPSE_LIMIT = 2;
41550
- const emitChange = React54__namespace.useCallback(
41551
- (next, meta) => {
41552
- onValue == null ? void 0 : onValue(next, { source: "variant", raw: next, nativeEvent: void 0, meta });
41553
- },
41554
- [onValue]
41555
- );
41556
- const handleAddItems = (incoming, from) => {
41557
- if (isDisabled) return;
41558
- let next = multiple ? [...items] : [];
41559
- const added = [];
41560
- for (const item of incoming) {
41561
- if (multiple && maxFiles && next.length >= maxFiles) break;
41562
- const currentTotalSize = next.reduce((acc, i) => acc + (i.size || 0), 0);
41563
- if (maxTotalSize && currentTotalSize + (item.size || 0) > maxTotalSize) break;
41564
- next.push(item);
41565
- added.push(item);
41566
- }
41567
- if (added.length > 0) {
41568
- onFilesAdded == null ? void 0 : onFilesAdded(added, { source: "variant", raw: added, nativeEvent: void 0, meta: { from } });
41569
- emitChange(next, { action: "add", from, added });
41570
- }
41571
- };
41572
- const handleRemove = (id) => {
41573
- const next = items.filter((i) => i.id !== id);
41574
- emitChange(next, { action: "remove", id });
41575
- if (selectedIds.has(id)) {
41576
- const nextSel = new Set(selectedIds);
41577
- nextSel.delete(id);
41578
- setSelectedIds(nextSel);
41524
+ var ShadcnFileVariant = React54__namespace.forwardRef(function ShadcnFileVariant2(props, ref) {
41525
+ const {
41526
+ value,
41527
+ onValue,
41528
+ disabled,
41529
+ readOnly,
41530
+ error,
41531
+ size: size4 = "md",
41532
+ density = "comfortable",
41533
+ multiple = false,
41534
+ accept,
41535
+ maxFiles,
41536
+ maxTotalSize,
41537
+ showDropArea = false,
41538
+ dropIcon,
41539
+ dropTitle,
41540
+ dropDescription,
41541
+ renderDropArea,
41542
+ renderFileItem,
41543
+ showCheckboxes,
41544
+ onFilesAdded,
41545
+ customLoader,
41546
+ mergeMode = "append",
41547
+ formatFileName,
41548
+ formatFileSize = formatSizeDefault,
41549
+ placeholder = "Select file...",
41550
+ className,
41551
+ dropAreaClassName,
41552
+ listClassName,
41553
+ leadingIcons,
41554
+ trailingIcons,
41555
+ icon,
41556
+ leadingControl,
41557
+ trailingControl,
41558
+ leadingControlClassName,
41559
+ trailingControlClassName,
41560
+ joinControls = true,
41561
+ extendBoxToControls = true
41562
+ } = props;
41563
+ const items = value != null ? value : [];
41564
+ const isDisabled = Boolean(disabled || readOnly);
41565
+ const [dragOver, setDragOver] = React54__namespace.useState(false);
41566
+ const [selectedIds, setSelectedIds] = React54__namespace.useState(
41567
+ () => /* @__PURE__ */ new Set()
41568
+ );
41569
+ const [popoverOpen, setPopoverOpen] = React54__namespace.useState(false);
41570
+ const fileInputRef = React54__namespace.useRef(null);
41571
+ const heightCls = triggerHeight4(size4);
41572
+ const chipHeightCls = chipHeight(size4);
41573
+ const pickerBtnCls = pickerBtnSize(size4);
41574
+ const resolvedLeadingIcons = leadingIcons || (icon ? [icon] : []);
41575
+ const resolvedTrailingIcons = trailingIcons || [];
41576
+ const hasExternalControls = !!leadingControl || !!trailingControl;
41577
+ const COLLAPSE_LIMIT = 2;
41578
+ const emitChange = React54__namespace.useCallback(
41579
+ (next, meta) => {
41580
+ onValue == null ? void 0 : onValue(next, {
41581
+ source: "variant",
41582
+ raw: next,
41583
+ nativeEvent: void 0,
41584
+ meta
41585
+ });
41586
+ },
41587
+ [onValue]
41588
+ );
41589
+ const handleAddItems = (incoming, from) => {
41590
+ if (isDisabled) return;
41591
+ let next = multiple ? [...items] : [];
41592
+ const added = [];
41593
+ for (const item of incoming) {
41594
+ if (multiple && maxFiles && next.length >= maxFiles) break;
41595
+ const currentTotalSize = next.reduce(
41596
+ (acc, i) => acc + (i.size || 0),
41597
+ 0
41598
+ );
41599
+ if (maxTotalSize && currentTotalSize + (item.size || 0) > maxTotalSize)
41600
+ break;
41601
+ next.push(item);
41602
+ added.push(item);
41603
+ }
41604
+ if (added.length > 0) {
41605
+ onFilesAdded == null ? void 0 : onFilesAdded(added, {
41606
+ source: "variant",
41607
+ raw: added,
41608
+ nativeEvent: void 0,
41609
+ meta: { from }
41610
+ });
41611
+ emitChange(next, { action: "add", from, added });
41612
+ }
41613
+ };
41614
+ const handleRemove = (id) => {
41615
+ const next = items.filter((i) => i.id !== id);
41616
+ emitChange(next, { action: "remove", id });
41617
+ if (selectedIds.has(id)) {
41618
+ const nextSel = new Set(selectedIds);
41619
+ nextSel.delete(id);
41620
+ setSelectedIds(nextSel);
41621
+ }
41622
+ };
41623
+ const handleBulkRemove = () => {
41624
+ const next = items.filter((i) => !selectedIds.has(i.id));
41625
+ emitChange(next, {
41626
+ action: "bulk-remove",
41627
+ ids: Array.from(selectedIds)
41628
+ });
41629
+ setSelectedIds(/* @__PURE__ */ new Set());
41630
+ };
41631
+ const openPicker = async () => {
41632
+ var _a;
41633
+ if (isDisabled) return;
41634
+ if (customLoader) {
41635
+ try {
41636
+ const result = await customLoader({ multiple, current: items });
41637
+ if (!result) return;
41638
+ const normalized = toArray(result).map(normaliseFileLike);
41639
+ if (mergeMode === "replace" || !multiple) {
41640
+ emitChange(normalized, {
41641
+ action: "set",
41642
+ from: "custom-loader"
41643
+ });
41644
+ } else {
41645
+ handleAddItems(normalized, "custom-loader");
41646
+ }
41647
+ } catch (err) {
41648
+ console.error("Custom loader failed", err);
41579
41649
  }
41580
- };
41581
- const handleBulkRemove = () => {
41582
- const next = items.filter((i) => !selectedIds.has(i.id));
41583
- emitChange(next, { action: "bulk-remove", ids: Array.from(selectedIds) });
41584
- setSelectedIds(/* @__PURE__ */ new Set());
41585
- };
41586
- const openPicker = async () => {
41650
+ return;
41651
+ }
41652
+ (_a = fileInputRef.current) == null ? void 0 : _a.click();
41653
+ };
41654
+ const onDragOver = (e) => {
41655
+ e.preventDefault();
41656
+ if (!isDisabled) setDragOver(true);
41657
+ };
41658
+ const onDrop = (e) => {
41659
+ var _a;
41660
+ e.preventDefault();
41661
+ setDragOver(false);
41662
+ if (isDisabled || !((_a = e.dataTransfer.files) == null ? void 0 : _a.length)) return;
41663
+ const files = normaliseFromFiles(e.dataTransfer.files);
41664
+ handleAddItems(files, "drop");
41665
+ };
41666
+ const onNativeChange = (e) => {
41667
+ var _a;
41668
+ if ((_a = e.target.files) == null ? void 0 : _a.length) {
41669
+ handleAddItems(normaliseFromFiles(e.target.files), "input");
41670
+ }
41671
+ e.target.value = "";
41672
+ };
41673
+ const FileChip = ({
41674
+ item,
41675
+ condensed = false
41676
+ }) => {
41677
+ const name = formatFileName ? formatFileName(item) : item.name;
41678
+ const [preview, setPreview] = React54__namespace.useState(null);
41679
+ const [isOpen, setIsOpen] = React54__namespace.useState(false);
41680
+ React54__namespace.useEffect(() => {
41587
41681
  var _a;
41588
- if (isDisabled) return;
41589
- if (customLoader) {
41590
- try {
41591
- const result = await customLoader({ multiple, current: items });
41592
- if (!result) return;
41593
- const normalized = toArray(result).map(normaliseFileLike);
41594
- if (mergeMode === "replace" || !multiple) {
41595
- emitChange(normalized, { action: "set", from: "custom-loader" });
41596
- } else {
41597
- handleAddItems(normalized, "custom-loader");
41598
- }
41599
- } catch (err) {
41600
- console.error("Custom loader failed", err);
41601
- }
41682
+ const isImage2 = ((_a = item.type) == null ? void 0 : _a.startsWith("image/")) || item.name.match(/\.(jpg|jpeg|png|gif|webp)$/i);
41683
+ if (!isImage2) {
41684
+ setPreview(null);
41602
41685
  return;
41603
41686
  }
41604
- (_a = fileInputRef.current) == null ? void 0 : _a.click();
41605
- };
41606
- const onDragOver = (e) => {
41607
- e.preventDefault();
41608
- if (!isDisabled) setDragOver(true);
41609
- };
41610
- const onDrop = (e) => {
41611
- var _a;
41612
- e.preventDefault();
41613
- setDragOver(false);
41614
- if (isDisabled || !((_a = e.dataTransfer.files) == null ? void 0 : _a.length)) return;
41615
- const files = normaliseFromFiles(e.dataTransfer.files);
41616
- handleAddItems(files, "drop");
41617
- };
41618
- const onNativeChange = (e) => {
41619
- var _a;
41620
- if ((_a = e.target.files) == null ? void 0 : _a.length) {
41621
- handleAddItems(normaliseFromFiles(e.target.files), "input");
41687
+ if (item.file) {
41688
+ const url = URL.createObjectURL(item.file);
41689
+ setPreview(url);
41690
+ return () => URL.revokeObjectURL(url);
41622
41691
  }
41623
- e.target.value = "";
41624
- };
41625
- const FileChip = ({ item, condensed = false }) => {
41626
- const name = formatFileName ? formatFileName(item) : item.name;
41627
- const [preview, setPreview] = React54__namespace.useState(null);
41628
- const [isOpen, setIsOpen] = React54__namespace.useState(false);
41629
- React54__namespace.useEffect(() => {
41630
- var _a;
41631
- const isImage2 = ((_a = item.type) == null ? void 0 : _a.startsWith("image/")) || item.name.match(/\.(jpg|jpeg|png|gif|webp)$/i);
41632
- if (!isImage2) {
41633
- setPreview(null);
41634
- return;
41692
+ if (item.url || item.path) {
41693
+ setPreview(item.url || item.path || null);
41694
+ }
41695
+ }, [item]);
41696
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover2, { open: isOpen, onOpenChange: setIsOpen, children: [
41697
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
41698
+ "div",
41699
+ {
41700
+ role: "button",
41701
+ tabIndex: 0,
41702
+ className: cn(
41703
+ "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",
41704
+ chipHeightCls,
41705
+ condensed ? "max-w-[120px]" : "max-w-[200px]"
41706
+ ),
41707
+ onPointerDown: (e) => e.stopPropagation(),
41708
+ onClick: (e) => {
41709
+ e.stopPropagation();
41710
+ setIsOpen(true);
41711
+ },
41712
+ onKeyDown: (e) => {
41713
+ if (e.key === "Enter" || e.key === " ") {
41714
+ e.stopPropagation();
41715
+ setIsOpen(true);
41716
+ }
41717
+ },
41718
+ children: [
41719
+ /* @__PURE__ */ jsxRuntime.jsx(File2, { className: "h-3 w-3 text-muted-foreground shrink-0" }),
41720
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: name }),
41721
+ /* @__PURE__ */ jsxRuntime.jsx(
41722
+ "button",
41723
+ {
41724
+ type: "button",
41725
+ onPointerDown: (e) => e.stopPropagation(),
41726
+ onClick: (e) => {
41727
+ e.stopPropagation();
41728
+ handleRemove(item.id);
41729
+ },
41730
+ 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",
41731
+ "aria-label": "Remove file",
41732
+ children: /* @__PURE__ */ jsxRuntime.jsx(X, { className: "h-3 w-3" })
41733
+ }
41734
+ )
41735
+ ]
41635
41736
  }
41636
- if (item.file) {
41637
- const url = URL.createObjectURL(item.file);
41638
- setPreview(url);
41639
- return () => URL.revokeObjectURL(url);
41737
+ ) }),
41738
+ /* @__PURE__ */ jsxRuntime.jsxs(
41739
+ PopoverContent2,
41740
+ {
41741
+ className: "w-64 p-0",
41742
+ align: "start",
41743
+ side: "bottom",
41744
+ children: [
41745
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative aspect-video w-full flex items-center justify-center bg-muted/30 border-b", children: preview ? /* @__PURE__ */ jsxRuntime.jsx(
41746
+ "img",
41747
+ {
41748
+ src: preview,
41749
+ alt: item.name,
41750
+ className: "h-full w-full object-contain"
41751
+ }
41752
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2 text-muted-foreground/50", children: [
41753
+ /* @__PURE__ */ jsxRuntime.jsx(File2, { className: "h-10 w-10" }),
41754
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase", children: "No Preview" })
41755
+ ] }) }),
41756
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3", children: [
41757
+ /* @__PURE__ */ jsxRuntime.jsx(
41758
+ "div",
41759
+ {
41760
+ className: "font-medium text-sm truncate",
41761
+ title: item.name,
41762
+ children: name
41763
+ }
41764
+ ),
41765
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center justify-between text-xs text-muted-foreground", children: [
41766
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFileSize(item.size) }),
41767
+ item.type && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "uppercase opacity-70", children: item.type.split("/").pop() })
41768
+ ] })
41769
+ ] })
41770
+ ]
41640
41771
  }
41641
- if (item.url || item.path) {
41642
- setPreview(item.url || item.path || null);
41772
+ )
41773
+ ] });
41774
+ };
41775
+ const TriggerRegion = React54__namespace.useMemo(() => {
41776
+ if (showDropArea) {
41777
+ if (renderDropArea)
41778
+ return renderDropArea({ openPicker, isDragging: dragOver });
41779
+ return /* @__PURE__ */ jsxRuntime.jsxs(
41780
+ "div",
41781
+ {
41782
+ onClick: openPicker,
41783
+ onDragOver,
41784
+ onDragLeave: () => setDragOver(false),
41785
+ onDrop,
41786
+ className: cn(
41787
+ "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",
41788
+ dragOver ? "border-primary bg-primary/5 ring-4 ring-primary/10" : "border-muted-foreground/25 hover:bg-muted/30 hover:border-muted-foreground/50",
41789
+ isDisabled && "cursor-not-allowed opacity-50",
41790
+ error && "border-destructive/50 bg-destructive/5",
41791
+ dropAreaClassName
41792
+ ),
41793
+ children: [
41794
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-full bg-surfaces-input p-3 shadow-sm", children: dropIcon != null ? dropIcon : /* @__PURE__ */ jsxRuntime.jsx(CloudUpload, { className: "h-5 w-5 text-muted-foreground" }) }),
41795
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
41796
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: dropTitle != null ? dropTitle : "Click or drag to select" }),
41797
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: dropDescription != null ? dropDescription : multiple ? "Select files" : "Select a file" })
41798
+ ] })
41799
+ ]
41643
41800
  }
41644
- }, [item]);
41645
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover2, { open: isOpen, onOpenChange: setIsOpen, children: [
41646
- /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
41647
- "div",
41648
- {
41649
- role: "button",
41650
- tabIndex: 0,
41651
- className: cn(
41652
- "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",
41653
- condensed ? "max-w-[120px]" : "max-w-[200px]"
41801
+ );
41802
+ }
41803
+ const hasItems = items.length > 0;
41804
+ const visibleItems = items.slice(0, COLLAPSE_LIMIT);
41805
+ const hiddenCount = items.length - COLLAPSE_LIMIT;
41806
+ const isOverflowing = hiddenCount > 0;
41807
+ const anySelected = selectedIds.size > 0 && showCheckboxes && multiple;
41808
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover2, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [
41809
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
41810
+ "div",
41811
+ {
41812
+ className: cn(
41813
+ "relative flex w-full cursor-pointer items-center gap-2 px-3 py-0 transition-all",
41814
+ heightCls,
41815
+ (!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",
41816
+ dragOver && (!joinControls || !hasExternalControls) && "border-primary ring-2 ring-primary/20",
41817
+ isDisabled && "cursor-not-allowed opacity-50",
41818
+ error && (!joinControls || !hasExternalControls) && "border-destructive text-destructive",
41819
+ className
41820
+ ),
41821
+ onDragOver,
41822
+ onDragLeave: () => setDragOver(false),
41823
+ onDrop,
41824
+ children: [
41825
+ resolvedLeadingIcons.map((ico, i) => /* @__PURE__ */ jsxRuntime.jsx(
41826
+ "span",
41827
+ {
41828
+ className: "flex shrink-0 items-center justify-center text-muted-foreground",
41829
+ children: ico
41830
+ },
41831
+ i
41832
+ )),
41833
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center gap-2 overflow-hidden", children: hasItems ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
41834
+ visibleItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
41835
+ FileChip,
41836
+ {
41837
+ item,
41838
+ condensed: multiple
41839
+ },
41840
+ item.id
41841
+ )),
41842
+ isOverflowing && /* @__PURE__ */ jsxRuntime.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: [
41843
+ "+",
41844
+ hiddenCount
41845
+ ] })
41846
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-muted-foreground", children: placeholder }) }),
41847
+ resolvedTrailingIcons.map((ico, i) => /* @__PURE__ */ jsxRuntime.jsx(
41848
+ "span",
41849
+ {
41850
+ className: "flex shrink-0 items-center justify-center text-muted-foreground",
41851
+ children: ico
41852
+ },
41853
+ i
41854
+ )),
41855
+ /* @__PURE__ */ jsxRuntime.jsx(
41856
+ Button2,
41857
+ {
41858
+ type: "button",
41859
+ variant: "ghost",
41860
+ size: "icon",
41861
+ className: cn(
41862
+ "shrink-0 text-muted-foreground hover:text-foreground",
41863
+ pickerBtnCls
41864
+ ),
41865
+ onPointerDown: (e) => e.stopPropagation(),
41866
+ onClick: (e) => {
41867
+ e.stopPropagation();
41868
+ openPicker();
41869
+ },
41870
+ children: /* @__PURE__ */ jsxRuntime.jsx(FolderUp, { className: "h-4 w-4" })
41871
+ }
41654
41872
  ),
41655
- onClick: (e) => {
41656
- e.stopPropagation();
41657
- setIsOpen(true);
41658
- },
41659
- onKeyDown: (e) => {
41660
- if (e.key === "Enter" || e.key === " ") {
41661
- e.stopPropagation();
41662
- setIsOpen(true);
41873
+ /* @__PURE__ */ jsxRuntime.jsx(
41874
+ ChevronDown,
41875
+ {
41876
+ className: cn(
41877
+ "h-4 w-4 shrink-0 text-muted-foreground opacity-50 transition-transform duration-200",
41878
+ popoverOpen && "rotate-180"
41879
+ )
41663
41880
  }
41664
- },
41665
- children: [
41666
- /* @__PURE__ */ jsxRuntime.jsx(File2, { className: "h-3 w-3 text-muted-foreground shrink-0" }),
41667
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: name }),
41668
- /* @__PURE__ */ jsxRuntime.jsx(
41881
+ )
41882
+ ]
41883
+ }
41884
+ ) }),
41885
+ /* @__PURE__ */ jsxRuntime.jsx(
41886
+ PopoverContent2,
41887
+ {
41888
+ className: "w-(--radix-popover-trigger-width) p-0",
41889
+ align: "start",
41890
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
41891
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b px-3 py-2 text-xs font-medium text-muted-foreground", children: [
41892
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: anySelected ? `${selectedIds.size} selected` : `${items.length} files total` }),
41893
+ anySelected ? /* @__PURE__ */ jsxRuntime.jsx(
41669
41894
  "button",
41670
41895
  {
41671
41896
  type: "button",
41672
- onClick: (e) => {
41673
- e.stopPropagation();
41674
- handleRemove(item.id);
41675
- },
41676
- 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",
41677
- "aria-label": "Remove file",
41678
- children: /* @__PURE__ */ jsxRuntime.jsx(X, { className: "h-3 w-3" })
41897
+ className: "text-destructive hover:underline",
41898
+ onClick: handleBulkRemove,
41899
+ children: "Remove selected"
41679
41900
  }
41680
- )
41681
- ]
41682
- }
41683
- ) }),
41684
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent2, { className: "w-64 p-0", align: "start", side: "bottom", children: [
41685
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative aspect-video w-full flex items-center justify-center bg-muted/30 border-b", children: preview ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: preview, alt: item.name, className: "h-full w-full object-contain" }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2 text-muted-foreground/50", children: [
41686
- /* @__PURE__ */ jsxRuntime.jsx(File2, { className: "h-10 w-10" }),
41687
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase", children: "No Preview" })
41688
- ] }) }),
41689
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3", children: [
41690
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-sm truncate", title: item.name, children: name }),
41691
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex items-center justify-between text-xs text-muted-foreground", children: [
41692
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFileSize(item.size) }),
41693
- item.type && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "uppercase opacity-70", children: item.type.split("/").pop() })
41694
- ] })
41901
+ ) : items.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
41902
+ "button",
41903
+ {
41904
+ type: "button",
41905
+ className: "text-muted-foreground hover:text-foreground",
41906
+ onClick: () => emitChange([], { action: "clear" }),
41907
+ children: "Clear all"
41908
+ }
41909
+ ) : null
41910
+ ] }),
41911
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollArea2, { className: "h-auto max-h-[300px] w-full p-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
41912
+ items.map((item) => {
41913
+ var _a;
41914
+ const selected = selectedIds.has(item.id);
41915
+ const toggle = () => {
41916
+ const next = new Set(selectedIds);
41917
+ if (next.has(item.id))
41918
+ next.delete(item.id);
41919
+ else next.add(item.id);
41920
+ setSelectedIds(next);
41921
+ };
41922
+ return /* @__PURE__ */ jsxRuntime.jsxs(
41923
+ "div",
41924
+ {
41925
+ className: "group flex items-center gap-3 rounded-md px-2 py-2 text-sm transition-colors hover:bg-muted/50",
41926
+ children: [
41927
+ showCheckboxes && multiple && /* @__PURE__ */ jsxRuntime.jsx(
41928
+ Checkbox2,
41929
+ {
41930
+ checked: selected,
41931
+ onCheckedChange: toggle,
41932
+ className: "h-4 w-4 shrink-0"
41933
+ }
41934
+ ),
41935
+ /* @__PURE__ */ jsxRuntime.jsx(FileThumbnail, { item }),
41936
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
41937
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate font-medium", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }),
41938
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
41939
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFileSize(
41940
+ item.size
41941
+ ) }),
41942
+ item.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive", children: "Failed" })
41943
+ ] })
41944
+ ] }),
41945
+ /* @__PURE__ */ jsxRuntime.jsx(
41946
+ Button2,
41947
+ {
41948
+ variant: "ghost",
41949
+ size: "icon",
41950
+ className: "h-7 w-7 opacity-0 group-hover:opacity-100",
41951
+ onClick: (e) => {
41952
+ e.stopPropagation();
41953
+ handleRemove(item.id);
41954
+ },
41955
+ children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, { className: "h-3.5 w-3.5 text-muted-foreground" })
41956
+ }
41957
+ )
41958
+ ]
41959
+ },
41960
+ item.id
41961
+ );
41962
+ }),
41963
+ items.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-4 text-center text-xs text-muted-foreground", children: "No files selected" })
41964
+ ] }) }),
41965
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t p-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
41966
+ Button2,
41967
+ {
41968
+ variant: "secondary",
41969
+ size: "sm",
41970
+ className: "w-full justify-start text-xs",
41971
+ onClick: () => {
41972
+ setPopoverOpen(false);
41973
+ openPicker();
41974
+ },
41975
+ children: [
41976
+ /* @__PURE__ */ jsxRuntime.jsx(Plus, { className: "mr-2 h-3 w-3" }),
41977
+ multiple ? "Add files..." : items.length ? "Replace file" : "Add file"
41978
+ ]
41979
+ }
41980
+ ) })
41695
41981
  ] })
41696
- ] })
41697
- ] });
41698
- };
41699
- const TriggerRegion = React54__namespace.useMemo(() => {
41700
- if (showDropArea) {
41701
- if (renderDropArea) return renderDropArea({ openPicker, isDragging: dragOver });
41702
- return /* @__PURE__ */ jsxRuntime.jsxs(
41703
- "div",
41982
+ }
41983
+ )
41984
+ ] });
41985
+ }, [
41986
+ showDropArea,
41987
+ items,
41988
+ multiple,
41989
+ dragOver,
41990
+ isDisabled,
41991
+ placeholder,
41992
+ joinControls,
41993
+ hasExternalControls,
41994
+ resolvedLeadingIcons,
41995
+ resolvedTrailingIcons,
41996
+ popoverOpen,
41997
+ COLLAPSE_LIMIT,
41998
+ heightCls,
41999
+ chipHeightCls,
42000
+ pickerBtnCls,
42001
+ openPicker,
42002
+ onDragOver,
42003
+ onDrop,
42004
+ renderDropArea,
42005
+ className,
42006
+ error,
42007
+ dropAreaClassName,
42008
+ dropIcon,
42009
+ dropTitle,
42010
+ dropDescription,
42011
+ selectedIds,
42012
+ showCheckboxes,
42013
+ handleBulkRemove,
42014
+ emitChange,
42015
+ formatFileName,
42016
+ formatFileSize,
42017
+ handleRemove
42018
+ ]);
42019
+ const showExternalList = multiple && showDropArea && items.length > 0;
42020
+ const anySelectedExternal = selectedIds.size > 0 && showCheckboxes && multiple;
42021
+ const ExternalFileList = showExternalList ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
42022
+ (anySelectedExternal || items.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between px-1 text-xs text-muted-foreground", children: [
42023
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
42024
+ items.length,
42025
+ " files"
42026
+ ] }),
42027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
42028
+ anySelectedExternal && /* @__PURE__ */ jsxRuntime.jsx(
42029
+ "button",
41704
42030
  {
41705
- onClick: openPicker,
41706
- onDragOver,
41707
- onDragLeave: () => setDragOver(false),
41708
- onDrop,
41709
- className: cn(
41710
- "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",
41711
- dragOver ? "border-primary bg-primary/5 ring-4 ring-primary/10" : "border-muted-foreground/25 hover:bg-muted/30 hover:border-muted-foreground/50",
41712
- isDisabled && "cursor-not-allowed opacity-50",
41713
- error && "border-destructive/50 bg-destructive/5",
41714
- dropAreaClassName
41715
- ),
41716
- children: [
41717
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-full bg-surfaces-input p-3 shadow-sm", children: dropIcon != null ? dropIcon : /* @__PURE__ */ jsxRuntime.jsx(CloudUpload, { className: "h-5 w-5 text-muted-foreground" }) }),
41718
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
41719
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: dropTitle != null ? dropTitle : "Click or drag to select" }),
41720
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: dropDescription != null ? dropDescription : multiple ? "Select files" : "Select a file" })
41721
- ] })
41722
- ]
42031
+ type: "button",
42032
+ onClick: handleBulkRemove,
42033
+ className: "text-destructive hover:underline",
42034
+ children: "Remove selected"
41723
42035
  }
41724
- );
42036
+ ),
42037
+ /* @__PURE__ */ jsxRuntime.jsx(
42038
+ "button",
42039
+ {
42040
+ type: "button",
42041
+ onClick: () => emitChange([], { action: "clear" }),
42042
+ className: "hover:text-foreground",
42043
+ children: "Clear all"
42044
+ }
42045
+ )
42046
+ ] })
42047
+ ] }),
42048
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollArea2, { className: cn("mt-1 w-full", listClassName), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: items.map((item, index2) => {
42049
+ var _a;
42050
+ const selected = selectedIds.has(item.id);
42051
+ const toggle = () => {
42052
+ const next = new Set(selectedIds);
42053
+ if (next.has(item.id)) next.delete(item.id);
42054
+ else next.add(item.id);
42055
+ setSelectedIds(next);
42056
+ };
42057
+ if (renderFileItem) {
42058
+ return renderFileItem({
42059
+ item,
42060
+ index: index2,
42061
+ selected,
42062
+ toggleSelected: toggle,
42063
+ remove: () => handleRemove(item.id)
42064
+ });
41725
42065
  }
41726
- const hasItems = items.length > 0;
41727
- const visibleItems = items.slice(0, COLLAPSE_LIMIT);
41728
- const hiddenCount = items.length - COLLAPSE_LIMIT;
41729
- const isOverflowing = hiddenCount > 0;
41730
- const anySelected = selectedIds.size > 0 && showCheckboxes && multiple;
41731
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover2, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [
41732
- /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
42066
+ return /* @__PURE__ */ jsxRuntime.jsxs(
42067
+ "div",
42068
+ {
42069
+ className: "group relative flex items-center gap-3 rounded-lg border bg-card p-2 pr-3 transition-all hover:bg-muted/30",
42070
+ children: [
42071
+ showCheckboxes && /* @__PURE__ */ jsxRuntime.jsx(
42072
+ Checkbox2,
42073
+ {
42074
+ checked: selected,
42075
+ onCheckedChange: toggle,
42076
+ className: "ml-1"
42077
+ }
42078
+ ),
42079
+ /* @__PURE__ */ jsxRuntime.jsx(FileThumbnail, { item }),
42080
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
42081
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-medium text-foreground", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }) }),
42082
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
42083
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFileSize(item.size) }),
42084
+ item.status === "loading" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center gap-1 text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }) }),
42085
+ item.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center gap-1 text-destructive", children: /* @__PURE__ */ jsxRuntime.jsx(CircleAlert, { className: "h-3 w-3" }) }),
42086
+ item.status === "done" && /* @__PURE__ */ jsxRuntime.jsx(CircleCheck, { className: "h-3 w-3 text-emerald-500" })
42087
+ ] })
42088
+ ] }),
42089
+ /* @__PURE__ */ jsxRuntime.jsx(
42090
+ "button",
42091
+ {
42092
+ type: "button",
42093
+ onClick: () => handleRemove(item.id),
42094
+ 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",
42095
+ children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, { className: "h-4 w-4" })
42096
+ }
42097
+ )
42098
+ ]
42099
+ },
42100
+ item.id
42101
+ );
42102
+ }) }) })
42103
+ ] }) : null;
42104
+ const joinedBox = joinControls && extendBoxToControls && !showDropArea;
42105
+ return /* @__PURE__ */ jsxRuntime.jsxs(
42106
+ "div",
42107
+ {
42108
+ ref,
42109
+ className: cn("w-full", className),
42110
+ "aria-disabled": isDisabled,
42111
+ "aria-invalid": !!error,
42112
+ children: [
42113
+ /* @__PURE__ */ jsxRuntime.jsxs(
41733
42114
  "div",
41734
42115
  {
41735
42116
  className: cn(
41736
- "relative flex w-full cursor-pointer items-center gap-2 px-3 transition-all",
41737
- heightCls,
41738
- (!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",
41739
- dragOver && "border-primary ring-2 ring-primary/20",
41740
- isDisabled && "cursor-not-allowed opacity-50",
41741
- error && "border-destructive text-destructive",
41742
- className
42117
+ "flex w-full",
42118
+ 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",
42119
+ // if the wrapper owns the border, apply border-state feedback here too
42120
+ joinedBox && dragOver && "border-primary ring-2 ring-primary/20",
42121
+ joinedBox && error && "border-destructive"
41743
42122
  ),
41744
- onDragOver,
41745
- onDragLeave: () => setDragOver(false),
41746
- onDrop,
41747
42123
  children: [
41748
- resolvedLeadingIcons.map((ico, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center justify-center text-muted-foreground", children: ico }, i)),
41749
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center gap-2 overflow-hidden", children: hasItems ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
41750
- visibleItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(FileChip, { item, condensed: multiple }, item.id)),
41751
- isOverflowing && /* @__PURE__ */ jsxRuntime.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: [
41752
- "+",
41753
- hiddenCount
41754
- ] })
41755
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-muted-foreground", children: placeholder }) }),
41756
- resolvedTrailingIcons.map((ico, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center justify-center text-muted-foreground", children: ico }, i)),
41757
- /* @__PURE__ */ jsxRuntime.jsx(
41758
- Button2,
42124
+ leadingControl && /* @__PURE__ */ jsxRuntime.jsx(
42125
+ "div",
41759
42126
  {
41760
- type: "button",
41761
- variant: "ghost",
41762
- size: "icon",
41763
- className: "h-6 w-6 shrink-0 text-muted-foreground hover:text-foreground",
41764
- onClick: (e) => {
41765
- e.stopPropagation();
41766
- openPicker();
41767
- },
41768
- children: /* @__PURE__ */ jsxRuntime.jsx(FolderUp, { className: "h-4 w-4" })
42127
+ className: cn(
42128
+ "flex items-center",
42129
+ joinControls && !showDropArea && "border-r bg-muted/50 px-3",
42130
+ leadingControlClassName
42131
+ ),
42132
+ children: leadingControl
41769
42133
  }
41770
42134
  ),
41771
- /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { className: cn("h-4 w-4 shrink-0 text-muted-foreground opacity-50 transition-transform duration-200", popoverOpen && "rotate-180") })
42135
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: TriggerRegion }),
42136
+ trailingControl && /* @__PURE__ */ jsxRuntime.jsx(
42137
+ "div",
42138
+ {
42139
+ className: cn(
42140
+ "flex items-center",
42141
+ joinControls && !showDropArea && "border-l bg-muted/50 px-3",
42142
+ trailingControlClassName
42143
+ ),
42144
+ children: trailingControl
42145
+ }
42146
+ )
41772
42147
  ]
41773
42148
  }
41774
- ) }),
42149
+ ),
42150
+ ExternalFileList,
41775
42151
  /* @__PURE__ */ jsxRuntime.jsx(
41776
- PopoverContent2,
42152
+ "input",
41777
42153
  {
41778
- className: "w-(--radix-popover-trigger-width) p-0",
41779
- align: "start",
41780
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
41781
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b px-3 py-2 text-xs font-medium text-muted-foreground", children: [
41782
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: anySelected ? `${selectedIds.size} selected` : `${items.length} files total` }),
41783
- anySelected ? /* @__PURE__ */ jsxRuntime.jsx(
41784
- "button",
41785
- {
41786
- type: "button",
41787
- className: "text-destructive hover:underline",
41788
- onClick: handleBulkRemove,
41789
- children: "Remove selected"
41790
- }
41791
- ) : items.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
41792
- "button",
41793
- {
41794
- type: "button",
41795
- className: "text-muted-foreground hover:text-foreground",
41796
- onClick: () => emitChange([], { action: "clear" }),
41797
- children: "Clear all"
41798
- }
41799
- )
41800
- ] }),
41801
- /* @__PURE__ */ jsxRuntime.jsx(ScrollArea2, { className: "h-auto max-h-[300px] w-full p-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
41802
- items.map((item) => {
41803
- var _a;
41804
- const selected = selectedIds.has(item.id);
41805
- const toggle = () => {
41806
- const next = new Set(selectedIds);
41807
- if (next.has(item.id)) next.delete(item.id);
41808
- else next.add(item.id);
41809
- setSelectedIds(next);
41810
- };
41811
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group flex items-center gap-3 rounded-md px-2 py-2 text-sm transition-colors hover:bg-muted/50", children: [
41812
- showCheckboxes && multiple && /* @__PURE__ */ jsxRuntime.jsx(Checkbox2, { checked: selected, onCheckedChange: toggle, className: "h-4 w-4 shrink-0" }),
41813
- /* @__PURE__ */ jsxRuntime.jsx(FileThumbnail, { item }),
41814
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
41815
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate font-medium", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }),
41816
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
41817
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFileSize(item.size) }),
41818
- item.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-destructive", children: "Failed" })
41819
- ] })
41820
- ] }),
41821
- /* @__PURE__ */ jsxRuntime.jsx(
41822
- Button2,
41823
- {
41824
- variant: "ghost",
41825
- size: "icon",
41826
- className: "h-7 w-7 opacity-0 group-hover:opacity-100",
41827
- onClick: (e) => {
41828
- e.stopPropagation();
41829
- handleRemove(item.id);
41830
- },
41831
- children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, { className: "h-3.5 w-3.5 text-muted-foreground" })
41832
- }
41833
- )
41834
- ] }, item.id);
41835
- }),
41836
- items.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-4 text-center text-xs text-muted-foreground", children: "No files selected" })
41837
- ] }) }),
41838
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t p-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
41839
- Button2,
41840
- {
41841
- variant: "secondary",
41842
- size: "sm",
41843
- className: "w-full justify-start text-xs",
41844
- onClick: () => {
41845
- setPopoverOpen(false);
41846
- openPicker();
41847
- },
41848
- children: [
41849
- /* @__PURE__ */ jsxRuntime.jsx(Plus, { className: "mr-2 h-3 w-3" }),
41850
- multiple ? "Add files..." : items.length ? "Replace file" : "Add file"
41851
- ]
41852
- }
41853
- ) })
41854
- ] })
42154
+ ref: fileInputRef,
42155
+ type: "file",
42156
+ className: "hidden",
42157
+ multiple,
42158
+ accept: Array.isArray(accept) ? accept.join(",") : accept,
42159
+ onChange: onNativeChange
41855
42160
  }
41856
42161
  )
41857
- ] });
41858
- }, [
41859
- showDropArea,
41860
- items,
41861
- multiple,
41862
- dragOver,
41863
- isDisabled,
41864
- placeholder,
41865
- joinControls,
41866
- hasExternalControls,
41867
- resolvedLeadingIcons,
41868
- resolvedTrailingIcons,
41869
- popoverOpen,
41870
- COLLAPSE_LIMIT,
41871
- heightCls,
41872
- openPicker,
41873
- onDragOver,
41874
- onDrop,
41875
- renderDropArea,
41876
- className,
41877
- error,
41878
- dropAreaClassName,
41879
- dropIcon,
41880
- dropTitle,
41881
- dropDescription,
41882
- selectedIds,
41883
- showCheckboxes,
41884
- handleBulkRemove,
41885
- emitChange,
41886
- formatFileName,
41887
- formatFileSize,
41888
- handleRemove
41889
- ]);
41890
- const showExternalList = multiple && showDropArea && items.length > 0;
41891
- const anySelectedExternal = selectedIds.size > 0 && showCheckboxes && multiple;
41892
- const ExternalFileList = showExternalList ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
41893
- (anySelectedExternal || items.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between px-1 text-xs text-muted-foreground", children: [
41894
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
41895
- items.length,
41896
- " files"
41897
- ] }),
41898
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
41899
- anySelectedExternal && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: handleBulkRemove, className: "text-destructive hover:underline", children: "Remove selected" }),
41900
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => emitChange([], { action: "clear" }), className: "hover:text-foreground", children: "Clear all" })
41901
- ] })
41902
- ] }),
41903
- /* @__PURE__ */ jsxRuntime.jsx(ScrollArea2, { className: cn("mt-1 w-full", listClassName), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: items.map((item, index2) => {
41904
- var _a;
41905
- const selected = selectedIds.has(item.id);
41906
- const toggle = () => {
41907
- const next = new Set(selectedIds);
41908
- if (next.has(item.id)) next.delete(item.id);
41909
- else next.add(item.id);
41910
- setSelectedIds(next);
41911
- };
41912
- if (renderFileItem) {
41913
- return renderFileItem({ item, index: index2, selected, toggleSelected: toggle, remove: () => handleRemove(item.id) });
41914
- }
41915
- return /* @__PURE__ */ jsxRuntime.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: [
41916
- showCheckboxes && /* @__PURE__ */ jsxRuntime.jsx(Checkbox2, { checked: selected, onCheckedChange: toggle, className: "ml-1" }),
41917
- /* @__PURE__ */ jsxRuntime.jsx(FileThumbnail, { item }),
41918
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
41919
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-medium text-foreground", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }) }),
41920
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
41921
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatFileSize(item.size) }),
41922
- item.status === "loading" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center gap-1 text-primary", children: /* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }) }),
41923
- item.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center gap-1 text-destructive", children: /* @__PURE__ */ jsxRuntime.jsx(CircleAlert, { className: "h-3 w-3" }) }),
41924
- item.status === "done" && /* @__PURE__ */ jsxRuntime.jsx(CircleCheck, { className: "h-3 w-3 text-emerald-500" })
41925
- ] })
41926
- ] }),
41927
- /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(Trash2, { className: "h-4 w-4" }) })
41928
- ] }, item.id);
41929
- }) }) })
41930
- ] }) : null;
41931
- return /* @__PURE__ */ jsxRuntime.jsxs(
41932
- "div",
41933
- {
41934
- ref,
41935
- className: cn("w-full", className),
41936
- "aria-disabled": isDisabled,
41937
- "aria-invalid": !!error,
41938
- children: [
41939
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(
41940
- "flex w-full",
41941
- 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"
41942
- ), children: [
41943
- leadingControl && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
41944
- "flex items-center",
41945
- joinControls && !showDropArea && "border-r bg-muted/50 px-3",
41946
- leadingControlClassName
41947
- ), children: leadingControl }),
41948
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: TriggerRegion }),
41949
- trailingControl && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
41950
- "flex items-center",
41951
- joinControls && !showDropArea && "border-l bg-muted/50 px-3",
41952
- trailingControlClassName
41953
- ), children: trailingControl })
41954
- ] }),
41955
- ExternalFileList,
41956
- /* @__PURE__ */ jsxRuntime.jsx(
41957
- "input",
41958
- {
41959
- ref: fileInputRef,
41960
- type: "file",
41961
- className: "hidden",
41962
- multiple,
41963
- accept: Array.isArray(accept) ? accept.join(",") : accept,
41964
- onChange: onNativeChange
41965
- }
41966
- )
41967
- ]
41968
- }
41969
- );
41970
- }
41971
- );
42162
+ ]
42163
+ }
42164
+ );
42165
+ });
41972
42166
  ShadcnFileVariant.displayName = "ShadcnFileVariant";
41973
42167
  var file_default = ShadcnFileVariant;
41974
42168