@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.mjs CHANGED
@@ -39537,12 +39537,11 @@ function clampVisible(total, minVisible, maxVisible) {
39537
39537
  function sizeClasses(size4) {
39538
39538
  switch (size4) {
39539
39539
  case "sm":
39540
- return "text-xs min-h-[2rem]";
39540
+ return "h-8 text-xs";
39541
39541
  case "lg":
39542
- return "text-sm min-h-[2.75rem]";
39543
- case "md":
39542
+ return "h-11 text-base";
39544
39543
  default:
39545
- return "text-sm min-h-[2.5rem]";
39544
+ return "h-9 text-sm";
39546
39545
  }
39547
39546
  }
39548
39547
  function densityPadding(density) {
@@ -39553,7 +39552,7 @@ function densityPadding(density) {
39553
39552
  return "py-3 px-3 gap-3";
39554
39553
  case "comfortable":
39555
39554
  default:
39556
- return "py-2 px-3 gap-2";
39555
+ return "py-1 px-3 gap-2";
39557
39556
  }
39558
39557
  }
39559
39558
  function defaultMoreLabel(count3) {
@@ -41388,15 +41387,34 @@ function formatSizeDefault(size4) {
41388
41387
  const mb = kb / 1024;
41389
41388
  return `${mb.toFixed(1)} MB`;
41390
41389
  }
41391
- function sliderHeight2(size4) {
41390
+ function triggerHeight4(size4) {
41392
41391
  switch (size4) {
41393
41392
  case "sm":
41394
- return "min-h-8 text-xs";
41393
+ return "h-8 text-xs";
41395
41394
  case "lg":
41396
- return "min-h-12 text-base";
41397
- 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";
41398
41406
  default:
41399
- return "min-h-10 text-sm";
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";
41416
+ default:
41417
+ return "h-7 w-7";
41400
41418
  }
41401
41419
  }
41402
41420
  function toArray(v) {
@@ -41473,481 +41491,657 @@ var FileThumbnail = ({ item }) => {
41473
41491
  setPreview(item.url || item.path || null);
41474
41492
  }
41475
41493
  }, [item]);
41476
- 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" }) });
41477
41502
  };
41478
- var ShadcnFileVariant = React54.forwardRef(
41479
- function ShadcnFileVariant2(props, ref) {
41480
- const {
41481
- value,
41482
- onValue,
41483
- disabled,
41484
- readOnly,
41485
- error,
41486
- size: size4 = "md",
41487
- density = "comfortable",
41488
- multiple = false,
41489
- accept,
41490
- maxFiles,
41491
- maxTotalSize,
41492
- showDropArea = false,
41493
- dropIcon,
41494
- dropTitle,
41495
- dropDescription,
41496
- renderDropArea,
41497
- renderFileItem,
41498
- showCheckboxes,
41499
- onFilesAdded,
41500
- customLoader,
41501
- mergeMode = "append",
41502
- formatFileName,
41503
- formatFileSize = formatSizeDefault,
41504
- placeholder = "Select file...",
41505
- className,
41506
- dropAreaClassName,
41507
- listClassName,
41508
- leadingIcons,
41509
- trailingIcons,
41510
- icon,
41511
- leadingControl,
41512
- trailingControl,
41513
- leadingControlClassName,
41514
- trailingControlClassName,
41515
- joinControls = true,
41516
- extendBoxToControls = true
41517
- } = props;
41518
- const items = value != null ? value : [];
41519
- const isDisabled = !!disabled || !!readOnly;
41520
- const [dragOver, setDragOver] = React54.useState(false);
41521
- const [selectedIds, setSelectedIds] = React54.useState(() => /* @__PURE__ */ new Set());
41522
- const [popoverOpen, setPopoverOpen] = React54.useState(false);
41523
- const fileInputRef = React54.useRef(null);
41524
- const heightCls = sliderHeight2(size4);
41525
- const resolvedLeadingIcons = leadingIcons || (icon ? [icon] : []);
41526
- const resolvedTrailingIcons = trailingIcons || [];
41527
- const hasExternalControls = !!leadingControl || !!trailingControl;
41528
- const COLLAPSE_LIMIT = 2;
41529
- const emitChange = React54.useCallback(
41530
- (next, meta) => {
41531
- onValue == null ? void 0 : onValue(next, { source: "variant", raw: next, nativeEvent: void 0, meta });
41532
- },
41533
- [onValue]
41534
- );
41535
- const handleAddItems = (incoming, from) => {
41536
- if (isDisabled) return;
41537
- let next = multiple ? [...items] : [];
41538
- const added = [];
41539
- for (const item of incoming) {
41540
- if (multiple && maxFiles && next.length >= maxFiles) break;
41541
- const currentTotalSize = next.reduce((acc, i) => acc + (i.size || 0), 0);
41542
- if (maxTotalSize && currentTotalSize + (item.size || 0) > maxTotalSize) break;
41543
- next.push(item);
41544
- added.push(item);
41545
- }
41546
- if (added.length > 0) {
41547
- onFilesAdded == null ? void 0 : onFilesAdded(added, { source: "variant", raw: added, nativeEvent: void 0, meta: { from } });
41548
- emitChange(next, { action: "add", from, added });
41549
- }
41550
- };
41551
- const handleRemove = (id) => {
41552
- const next = items.filter((i) => i.id !== id);
41553
- emitChange(next, { action: "remove", id });
41554
- if (selectedIds.has(id)) {
41555
- const nextSel = new Set(selectedIds);
41556
- nextSel.delete(id);
41557
- 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);
41558
41628
  }
41559
- };
41560
- const handleBulkRemove = () => {
41561
- const next = items.filter((i) => !selectedIds.has(i.id));
41562
- emitChange(next, { action: "bulk-remove", ids: Array.from(selectedIds) });
41563
- setSelectedIds(/* @__PURE__ */ new Set());
41564
- };
41565
- 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(() => {
41566
41660
  var _a;
41567
- if (isDisabled) return;
41568
- if (customLoader) {
41569
- try {
41570
- const result = await customLoader({ multiple, current: items });
41571
- if (!result) return;
41572
- const normalized = toArray(result).map(normaliseFileLike);
41573
- if (mergeMode === "replace" || !multiple) {
41574
- emitChange(normalized, { action: "set", from: "custom-loader" });
41575
- } else {
41576
- handleAddItems(normalized, "custom-loader");
41577
- }
41578
- } catch (err) {
41579
- console.error("Custom loader failed", err);
41580
- }
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);
41581
41664
  return;
41582
41665
  }
41583
- (_a = fileInputRef.current) == null ? void 0 : _a.click();
41584
- };
41585
- const onDragOver = (e) => {
41586
- e.preventDefault();
41587
- if (!isDisabled) setDragOver(true);
41588
- };
41589
- const onDrop = (e) => {
41590
- var _a;
41591
- e.preventDefault();
41592
- setDragOver(false);
41593
- if (isDisabled || !((_a = e.dataTransfer.files) == null ? void 0 : _a.length)) return;
41594
- const files = normaliseFromFiles(e.dataTransfer.files);
41595
- handleAddItems(files, "drop");
41596
- };
41597
- const onNativeChange = (e) => {
41598
- var _a;
41599
- if ((_a = e.target.files) == null ? void 0 : _a.length) {
41600
- 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);
41601
41670
  }
41602
- e.target.value = "";
41603
- };
41604
- const FileChip = ({ item, condensed = false }) => {
41605
- const name = formatFileName ? formatFileName(item) : item.name;
41606
- const [preview, setPreview] = React54.useState(null);
41607
- const [isOpen, setIsOpen] = React54.useState(false);
41608
- React54.useEffect(() => {
41609
- var _a;
41610
- const isImage2 = ((_a = item.type) == null ? void 0 : _a.startsWith("image/")) || item.name.match(/\.(jpg|jpeg|png|gif|webp)$/i);
41611
- if (!isImage2) {
41612
- setPreview(null);
41613
- 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
+ ]
41614
41715
  }
41615
- if (item.file) {
41616
- const url = URL.createObjectURL(item.file);
41617
- setPreview(url);
41618
- 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
+ ]
41619
41750
  }
41620
- if (item.url || item.path) {
41621
- 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
+ ]
41622
41779
  }
41623
- }, [item]);
41624
- return /* @__PURE__ */ jsxs(Popover2, { open: isOpen, onOpenChange: setIsOpen, children: [
41625
- /* @__PURE__ */ jsx(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
41626
- "div",
41627
- {
41628
- role: "button",
41629
- tabIndex: 0,
41630
- className: cn(
41631
- "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",
41632
- 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
+ }
41633
41851
  ),
41634
- onClick: (e) => {
41635
- e.stopPropagation();
41636
- setIsOpen(true);
41637
- },
41638
- onKeyDown: (e) => {
41639
- if (e.key === "Enter" || e.key === " ") {
41640
- e.stopPropagation();
41641
- 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
+ )
41642
41859
  }
41643
- },
41644
- children: [
41645
- /* @__PURE__ */ jsx(File2, { className: "h-3 w-3 text-muted-foreground shrink-0" }),
41646
- /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: name }),
41647
- /* @__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(
41648
41873
  "button",
41649
41874
  {
41650
41875
  type: "button",
41651
- onClick: (e) => {
41652
- e.stopPropagation();
41653
- handleRemove(item.id);
41654
- },
41655
- 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",
41656
- "aria-label": "Remove file",
41657
- children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
41876
+ className: "text-destructive hover:underline",
41877
+ onClick: handleBulkRemove,
41878
+ children: "Remove selected"
41658
41879
  }
41659
- )
41660
- ]
41661
- }
41662
- ) }),
41663
- /* @__PURE__ */ jsxs(PopoverContent2, { className: "w-64 p-0", align: "start", side: "bottom", children: [
41664
- /* @__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: [
41665
- /* @__PURE__ */ jsx(File2, { className: "h-10 w-10" }),
41666
- /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase", children: "No Preview" })
41667
- ] }) }),
41668
- /* @__PURE__ */ jsxs("div", { className: "p-3", children: [
41669
- /* @__PURE__ */ jsx("div", { className: "font-medium text-sm truncate", title: item.name, children: name }),
41670
- /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center justify-between text-xs text-muted-foreground", children: [
41671
- /* @__PURE__ */ jsx("span", { children: formatFileSize(item.size) }),
41672
- item.type && /* @__PURE__ */ jsx("span", { className: "uppercase opacity-70", children: item.type.split("/").pop() })
41673
- ] })
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
+ ) })
41674
41960
  ] })
41675
- ] })
41676
- ] });
41677
- };
41678
- const TriggerRegion = React54.useMemo(() => {
41679
- if (showDropArea) {
41680
- if (renderDropArea) return renderDropArea({ openPicker, isDragging: dragOver });
41681
- return /* @__PURE__ */ jsxs(
41682
- "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",
41683
42009
  {
41684
- onClick: openPicker,
41685
- onDragOver,
41686
- onDragLeave: () => setDragOver(false),
41687
- onDrop,
41688
- className: cn(
41689
- "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",
41690
- dragOver ? "border-primary bg-primary/5 ring-4 ring-primary/10" : "border-muted-foreground/25 hover:bg-muted/30 hover:border-muted-foreground/50",
41691
- isDisabled && "cursor-not-allowed opacity-50",
41692
- error && "border-destructive/50 bg-destructive/5",
41693
- dropAreaClassName
41694
- ),
41695
- children: [
41696
- /* @__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" }) }),
41697
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
41698
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: dropTitle != null ? dropTitle : "Click or drag to select" }),
41699
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: dropDescription != null ? dropDescription : multiple ? "Select files" : "Select a file" })
41700
- ] })
41701
- ]
42010
+ type: "button",
42011
+ onClick: handleBulkRemove,
42012
+ className: "text-destructive hover:underline",
42013
+ children: "Remove selected"
41702
42014
  }
41703
- );
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
+ });
41704
42044
  }
41705
- const hasItems = items.length > 0;
41706
- const visibleItems = items.slice(0, COLLAPSE_LIMIT);
41707
- const hiddenCount = items.length - COLLAPSE_LIMIT;
41708
- const isOverflowing = hiddenCount > 0;
41709
- const anySelected = selectedIds.size > 0 && showCheckboxes && multiple;
41710
- return /* @__PURE__ */ jsxs(Popover2, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [
41711
- /* @__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(
41712
42093
  "div",
41713
42094
  {
41714
42095
  className: cn(
41715
- "relative flex w-full cursor-pointer items-center gap-2 px-3 transition-all",
41716
- heightCls,
41717
- (!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",
41718
- dragOver && "border-primary ring-2 ring-primary/20",
41719
- isDisabled && "cursor-not-allowed opacity-50",
41720
- error && "border-destructive text-destructive",
41721
- 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"
41722
42101
  ),
41723
- onDragOver,
41724
- onDragLeave: () => setDragOver(false),
41725
- onDrop,
41726
42102
  children: [
41727
- resolvedLeadingIcons.map((ico, i) => /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center justify-center text-muted-foreground", children: ico }, i)),
41728
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center gap-2 overflow-hidden", children: hasItems ? /* @__PURE__ */ jsxs(Fragment, { children: [
41729
- visibleItems.map((item) => /* @__PURE__ */ jsx(FileChip, { item, condensed: multiple }, item.id)),
41730
- 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: [
41731
- "+",
41732
- hiddenCount
41733
- ] })
41734
- ] }) : /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: placeholder }) }),
41735
- resolvedTrailingIcons.map((ico, i) => /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center justify-center text-muted-foreground", children: ico }, i)),
41736
- /* @__PURE__ */ jsx(
41737
- Button2,
42103
+ leadingControl && /* @__PURE__ */ jsx(
42104
+ "div",
41738
42105
  {
41739
- type: "button",
41740
- variant: "ghost",
41741
- size: "icon",
41742
- className: "h-6 w-6 shrink-0 text-muted-foreground hover:text-foreground",
41743
- onClick: (e) => {
41744
- e.stopPropagation();
41745
- openPicker();
41746
- },
41747
- 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
41748
42112
  }
41749
42113
  ),
41750
- /* @__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
+ )
41751
42126
  ]
41752
42127
  }
41753
- ) }),
42128
+ ),
42129
+ ExternalFileList,
41754
42130
  /* @__PURE__ */ jsx(
41755
- PopoverContent2,
42131
+ "input",
41756
42132
  {
41757
- className: "w-(--radix-popover-trigger-width) p-0",
41758
- align: "start",
41759
- children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
41760
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-3 py-2 text-xs font-medium text-muted-foreground", children: [
41761
- /* @__PURE__ */ jsx("span", { children: anySelected ? `${selectedIds.size} selected` : `${items.length} files total` }),
41762
- anySelected ? /* @__PURE__ */ jsx(
41763
- "button",
41764
- {
41765
- type: "button",
41766
- className: "text-destructive hover:underline",
41767
- onClick: handleBulkRemove,
41768
- children: "Remove selected"
41769
- }
41770
- ) : items.length > 0 && /* @__PURE__ */ jsx(
41771
- "button",
41772
- {
41773
- type: "button",
41774
- className: "text-muted-foreground hover:text-foreground",
41775
- onClick: () => emitChange([], { action: "clear" }),
41776
- children: "Clear all"
41777
- }
41778
- )
41779
- ] }),
41780
- /* @__PURE__ */ jsx(ScrollArea2, { className: "h-auto max-h-[300px] w-full p-1", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
41781
- items.map((item) => {
41782
- var _a;
41783
- const selected = selectedIds.has(item.id);
41784
- const toggle = () => {
41785
- const next = new Set(selectedIds);
41786
- if (next.has(item.id)) next.delete(item.id);
41787
- else next.add(item.id);
41788
- setSelectedIds(next);
41789
- };
41790
- 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: [
41791
- showCheckboxes && multiple && /* @__PURE__ */ jsx(Checkbox2, { checked: selected, onCheckedChange: toggle, className: "h-4 w-4 shrink-0" }),
41792
- /* @__PURE__ */ jsx(FileThumbnail, { item }),
41793
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
41794
- /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: (_a = formatFileName == null ? void 0 : formatFileName(item)) != null ? _a : item.name }),
41795
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
41796
- /* @__PURE__ */ jsx("span", { children: formatFileSize(item.size) }),
41797
- item.status === "failed" && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "Failed" })
41798
- ] })
41799
- ] }),
41800
- /* @__PURE__ */ jsx(
41801
- Button2,
41802
- {
41803
- variant: "ghost",
41804
- size: "icon",
41805
- className: "h-7 w-7 opacity-0 group-hover:opacity-100",
41806
- onClick: (e) => {
41807
- e.stopPropagation();
41808
- handleRemove(item.id);
41809
- },
41810
- children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5 text-muted-foreground" })
41811
- }
41812
- )
41813
- ] }, item.id);
41814
- }),
41815
- items.length === 0 && /* @__PURE__ */ jsx("div", { className: "py-4 text-center text-xs text-muted-foreground", children: "No files selected" })
41816
- ] }) }),
41817
- /* @__PURE__ */ jsx("div", { className: "border-t p-1", children: /* @__PURE__ */ jsxs(
41818
- Button2,
41819
- {
41820
- variant: "secondary",
41821
- size: "sm",
41822
- className: "w-full justify-start text-xs",
41823
- onClick: () => {
41824
- setPopoverOpen(false);
41825
- openPicker();
41826
- },
41827
- children: [
41828
- /* @__PURE__ */ jsx(Plus, { className: "mr-2 h-3 w-3" }),
41829
- multiple ? "Add files..." : items.length ? "Replace file" : "Add file"
41830
- ]
41831
- }
41832
- ) })
41833
- ] })
42133
+ ref: fileInputRef,
42134
+ type: "file",
42135
+ className: "hidden",
42136
+ multiple,
42137
+ accept: Array.isArray(accept) ? accept.join(",") : accept,
42138
+ onChange: onNativeChange
41834
42139
  }
41835
42140
  )
41836
- ] });
41837
- }, [
41838
- showDropArea,
41839
- items,
41840
- multiple,
41841
- dragOver,
41842
- isDisabled,
41843
- placeholder,
41844
- joinControls,
41845
- hasExternalControls,
41846
- resolvedLeadingIcons,
41847
- resolvedTrailingIcons,
41848
- popoverOpen,
41849
- COLLAPSE_LIMIT,
41850
- heightCls,
41851
- openPicker,
41852
- onDragOver,
41853
- onDrop,
41854
- renderDropArea,
41855
- className,
41856
- error,
41857
- dropAreaClassName,
41858
- dropIcon,
41859
- dropTitle,
41860
- dropDescription,
41861
- selectedIds,
41862
- showCheckboxes,
41863
- handleBulkRemove,
41864
- emitChange,
41865
- formatFileName,
41866
- formatFileSize,
41867
- handleRemove
41868
- ]);
41869
- const showExternalList = multiple && showDropArea && items.length > 0;
41870
- const anySelectedExternal = selectedIds.size > 0 && showCheckboxes && multiple;
41871
- const ExternalFileList = showExternalList ? /* @__PURE__ */ jsxs(Fragment, { children: [
41872
- (anySelectedExternal || items.length > 0) && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-between px-1 text-xs text-muted-foreground", children: [
41873
- /* @__PURE__ */ jsxs("span", { children: [
41874
- items.length,
41875
- " files"
41876
- ] }),
41877
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
41878
- anySelectedExternal && /* @__PURE__ */ jsx("button", { type: "button", onClick: handleBulkRemove, className: "text-destructive hover:underline", children: "Remove selected" }),
41879
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => emitChange([], { action: "clear" }), className: "hover:text-foreground", children: "Clear all" })
41880
- ] })
41881
- ] }),
41882
- /* @__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) => {
41883
- var _a;
41884
- const selected = selectedIds.has(item.id);
41885
- const toggle = () => {
41886
- const next = new Set(selectedIds);
41887
- if (next.has(item.id)) next.delete(item.id);
41888
- else next.add(item.id);
41889
- setSelectedIds(next);
41890
- };
41891
- if (renderFileItem) {
41892
- return renderFileItem({ item, index: index2, selected, toggleSelected: toggle, remove: () => handleRemove(item.id) });
41893
- }
41894
- 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: [
41895
- showCheckboxes && /* @__PURE__ */ jsx(Checkbox2, { checked: selected, onCheckedChange: toggle, className: "ml-1" }),
41896
- /* @__PURE__ */ jsx(FileThumbnail, { item }),
41897
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
41898
- /* @__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 }) }),
41899
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
41900
- /* @__PURE__ */ jsx("span", { children: formatFileSize(item.size) }),
41901
- 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" }) }),
41902
- item.status === "failed" && /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 text-destructive", children: /* @__PURE__ */ jsx(CircleAlert, { className: "h-3 w-3" }) }),
41903
- item.status === "done" && /* @__PURE__ */ jsx(CircleCheck, { className: "h-3 w-3 text-emerald-500" })
41904
- ] })
41905
- ] }),
41906
- /* @__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" }) })
41907
- ] }, item.id);
41908
- }) }) })
41909
- ] }) : null;
41910
- return /* @__PURE__ */ jsxs(
41911
- "div",
41912
- {
41913
- ref,
41914
- className: cn("w-full", className),
41915
- "aria-disabled": isDisabled,
41916
- "aria-invalid": !!error,
41917
- children: [
41918
- /* @__PURE__ */ jsxs("div", { className: cn(
41919
- "flex w-full",
41920
- 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"
41921
- ), children: [
41922
- leadingControl && /* @__PURE__ */ jsx("div", { className: cn(
41923
- "flex items-center",
41924
- joinControls && !showDropArea && "border-r bg-muted/50 px-3",
41925
- leadingControlClassName
41926
- ), children: leadingControl }),
41927
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: TriggerRegion }),
41928
- trailingControl && /* @__PURE__ */ jsx("div", { className: cn(
41929
- "flex items-center",
41930
- joinControls && !showDropArea && "border-l bg-muted/50 px-3",
41931
- trailingControlClassName
41932
- ), children: trailingControl })
41933
- ] }),
41934
- ExternalFileList,
41935
- /* @__PURE__ */ jsx(
41936
- "input",
41937
- {
41938
- ref: fileInputRef,
41939
- type: "file",
41940
- className: "hidden",
41941
- multiple,
41942
- accept: Array.isArray(accept) ? accept.join(",") : accept,
41943
- onChange: onNativeChange
41944
- }
41945
- )
41946
- ]
41947
- }
41948
- );
41949
- }
41950
- );
42141
+ ]
42142
+ }
42143
+ );
42144
+ });
41951
42145
  ShadcnFileVariant.displayName = "ShadcnFileVariant";
41952
42146
  var file_default = ShadcnFileVariant;
41953
42147