@better-s3/ui 3.1050.0 → 3.1051.0

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.
@@ -1,9 +1,12 @@
1
+ import type { ReactNode } from "react";
1
2
  import { type UseUploadControlsOptions, type UseMultiUploadControlsOptions } from "@better-s3/react";
2
3
  /** Props for {@link UploadButton}. Extends {@link UseUploadControlsOptions} or {@link UseMultiUploadControlsOptions}. */
3
4
  export type UploadButtonProps = (UseUploadControlsOptions | UseMultiUploadControlsOptions) & {
4
5
  className?: string;
5
6
  /** Button label. */
6
7
  label?: string;
8
+ /** Custom button content. Replaces default icon + label. */
9
+ children?: ReactNode;
7
10
  disabled?: boolean;
8
11
  tooltipText?: string;
9
12
  /** Show sonner toasts during upload. @default true */
@@ -11,4 +14,4 @@ export type UploadButtonProps = (UseUploadControlsOptions | UseMultiUploadContro
11
14
  /** Show inline status below the button. @default true */
12
15
  showStatus?: boolean;
13
16
  };
14
- export declare function UploadButton({ className, label, disabled, tooltipText, toast: enableToast, showStatus, ...options }: UploadButtonProps): import("react").JSX.Element;
17
+ export declare function UploadButton({ className, label, children, disabled, tooltipText, toast: enableToast, showStatus, ...options }: UploadButtonProps): import("react").JSX.Element;
@@ -1,13 +1,16 @@
1
+ import { type ReactNode } from "react";
1
2
  import { type UseUploadControlsOptions, type UseMultiUploadControlsOptions } from "@better-s3/react";
2
3
  /** Props for {@link UploadDropzone}. Extends {@link UseUploadControlsOptions} or {@link UseMultiUploadControlsOptions}. */
3
4
  export type UploadDropzoneProps = (UseUploadControlsOptions | UseMultiUploadControlsOptions) & {
4
5
  className?: string;
5
6
  /** Dropzone label. */
6
7
  label?: string;
8
+ /** Custom dropzone content. Replaces built-in icon/text/status block. */
9
+ children?: ReactNode;
7
10
  disabled?: boolean;
8
11
  /** Show sonner toasts during upload. @default true */
9
12
  toast?: boolean;
10
13
  /** Show inline status inside the dropzone. @default true */
11
14
  showStatus?: boolean;
12
15
  };
13
- export declare function UploadDropzone({ className, label, disabled, toast: enableToast, showStatus, ...options }: UploadDropzoneProps): import("react").JSX.Element;
16
+ export declare function UploadDropzone({ className, label, children, disabled, toast: enableToast, showStatus, ...options }: UploadDropzoneProps): import("react").JSX.Element;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { XIcon, CheckCircleIcon, AlertCircleIcon, UploadIcon, LoaderIcon, DownloadIcon, Trash2Icon, CheckCircle2Icon } from 'lucide-react';
2
- import { formatEta, useUploadControls, useMultiUploadControls, useDownload, useFetchDownload, formatSpeed, useDelete } from '@better-s3/react';
1
+ import { XIcon, CheckCircleIcon, AlertCircleIcon, CloudUpload, LoaderIcon, DownloadIcon, Trash2Icon, CheckCircle2Icon } from 'lucide-react';
2
+ import { formatEta, useUploadControls, useMultiUploadControls, formatAcceptLabels, useDownload, useFetchDownload, formatSpeed, useDelete } from '@better-s3/react';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import { Button as Button$1 } from '@base-ui/react/button';
@@ -8,7 +8,7 @@ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
8
  import { Tooltip as Tooltip$1 } from '@base-ui/react/tooltip';
9
9
  import { truncateFilename, formatFileSize } from '@better-s3/core';
10
10
  import { Progress as Progress$1 } from '@base-ui/react/progress';
11
- import { useRef, useEffect } from 'react';
11
+ import { useState, useRef, useEffect } from 'react';
12
12
  import { toast } from 'sonner';
13
13
  import { AlertDialog as AlertDialog$1 } from '@base-ui/react/alert-dialog';
14
14
 
@@ -152,7 +152,7 @@ function UploadStatus({
152
152
  return /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-2 text-xs", children: [
153
153
  /* @__PURE__ */ jsx(CircleProgress, { percent: progress.percent, size: 14, strokeWidth: 2 }),
154
154
  /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate max-w-[30ch]", children: truncateFilename(fileInfo.name) }),
155
- /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 whitespace-nowrap tabular-nums text-muted-foreground", children: progressMeta }),
155
+ /* @__PURE__ */ jsx("span", { className: "ms-auto shrink-0 whitespace-nowrap tabular-nums text-muted-foreground", children: progressMeta }),
156
156
  /* @__PURE__ */ jsx(
157
157
  Button,
158
158
  {
@@ -172,7 +172,7 @@ function UploadStatus({
172
172
  return /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-1.5 text-xs", children: [
173
173
  /* @__PURE__ */ jsx(CheckCircleIcon, { className: "size-3.5 shrink-0 text-green-600" }),
174
174
  /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate max-w-[30ch]", children: truncateFilename(fileInfo.name) }),
175
- /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 text-muted-foreground", children: formatFileSize(fileInfo.size) })
175
+ /* @__PURE__ */ jsx("span", { className: "ms-auto shrink-0 text-muted-foreground", children: formatFileSize(fileInfo.size) })
176
176
  ] });
177
177
  }
178
178
  if (phase === "error") {
@@ -346,10 +346,23 @@ function FileList({ files }) {
346
346
  "%)"
347
347
  ] }) : /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: formatFileSize(f.fileSize) })
348
348
  ] }),
349
- f.status === "error" && f.error && /* @__PURE__ */ jsx("span", { className: "truncate [overflow-wrap:anywhere] pl-5 text-destructive", children: f.error })
349
+ f.status === "error" && f.error && /* @__PURE__ */ jsx("span", { className: "truncate [overflow-wrap:anywhere] ps-5 text-destructive", children: f.error })
350
350
  ] }, f.id)) });
351
351
  }
352
352
  function UploadStatusBlock(props) {
353
+ if (props.mode === "multi" && props.files.length === 1) {
354
+ const f = props.files[0];
355
+ return /* @__PURE__ */ jsx(
356
+ UploadStatus,
357
+ {
358
+ phase: props.phase,
359
+ progress: f.progress,
360
+ error: f.error ?? props.error,
361
+ fileInfo: { name: f.fileName, size: f.fileSize },
362
+ onCancel: props.onCancel
363
+ }
364
+ );
365
+ }
353
366
  if (props.mode === "multi") {
354
367
  return /* @__PURE__ */ jsx(
355
368
  MultiUploadStatus,
@@ -375,14 +388,19 @@ function UploadStatusBlock(props) {
375
388
  }
376
389
  function useUploadToast(ctrl, enabled) {
377
390
  const toastIdRef = useRef(null);
378
- const isMulti = ctrl.mode === "multi";
391
+ const sizeNode = (size) => /* @__PURE__ */ jsx("span", { dir: "ltr", className: "inline-block whitespace-nowrap tabular-nums", children: formatFileSize(size) });
392
+ const progressNode = (loaded, total) => /* @__PURE__ */ jsxs("span", { dir: "ltr", className: "inline-block whitespace-nowrap tabular-nums", children: [
393
+ formatFileSize(loaded),
394
+ " / ",
395
+ formatFileSize(total)
396
+ ] });
379
397
  const files = ctrl.files ?? [];
398
+ const isMulti = ctrl.mode === "multi" && files.length > 1;
399
+ const file = ctrl.fileInfo ?? (files.length === 1 ? { name: files[0].fileName, size: files[0].fileSize } : null);
380
400
  const totalProgress = ctrl.totalProgress ?? {
381
401
  loaded: 0,
382
- total: 0,
383
- percent: 0
384
- };
385
- const progress = ctrl.progress ?? { loaded: 0, percent: 0 };
402
+ total: 0};
403
+ const progress = ctrl.progress ?? (files.length === 1 ? files[0].progress : { loaded: 0});
386
404
  const prevPhaseRef = useRef(ctrl.phase);
387
405
  if (prevPhaseRef.current !== ctrl.phase) {
388
406
  prevPhaseRef.current = ctrl.phase;
@@ -395,11 +413,11 @@ function useUploadToast(ctrl, enabled) {
395
413
  if (toastIdRef.current) toast.dismiss(toastIdRef.current);
396
414
  if (isMulti) {
397
415
  toast.success(`${files.length} file(s) uploaded`, {
398
- description: formatFileSize(totalProgress.total)
416
+ description: sizeNode(totalProgress.total)
399
417
  });
400
- } else if (ctrl.fileInfo) {
418
+ } else if (file) {
401
419
  toast.success("Upload complete", {
402
- description: formatFileSize(ctrl.fileInfo.size)
420
+ description: sizeNode(file.size)
403
421
  });
404
422
  }
405
423
  toastIdRef.current = null;
@@ -410,11 +428,23 @@ function useUploadToast(ctrl, enabled) {
410
428
  const succeeded = files.filter((f) => f.status === "success").length;
411
429
  const failed = files.filter((f) => f.status === "error").length;
412
430
  toast.error("Upload finished with errors", {
413
- description: `${succeeded} succeeded, ${failed} failed`
431
+ description: /* @__PURE__ */ jsxs(
432
+ "span",
433
+ {
434
+ dir: "ltr",
435
+ className: "inline-block whitespace-nowrap tabular-nums",
436
+ children: [
437
+ succeeded,
438
+ " succeeded, ",
439
+ failed,
440
+ " failed"
441
+ ]
442
+ }
443
+ )
414
444
  });
415
445
  } else {
416
446
  toast.error("Upload failed", {
417
- description: /* @__PURE__ */ jsx("span", { className: "block [overflow-wrap:anywhere]", children: ctrl.error ?? "Unknown error" })
447
+ description: /* @__PURE__ */ jsx("span", { dir: "auto", className: "block [overflow-wrap:anywhere]", children: ctrl.error ?? files[0]?.error ?? "Unknown error" })
418
448
  });
419
449
  }
420
450
  toastIdRef.current = null;
@@ -427,15 +457,15 @@ function useUploadToast(ctrl, enabled) {
427
457
  toastIdRef.current = id;
428
458
  if (isMulti) {
429
459
  const done = files.filter((f) => f.status === "success").length;
430
- toast.loading(`Uploading... ${done}/${files.length}`, {
460
+ toast.loading(`Uploading ${done}/${files.length}`, {
431
461
  id,
432
- description: `${formatFileSize(totalProgress.loaded)} / ${formatFileSize(totalProgress.total)} (${totalProgress.percent}%)`,
462
+ description: progressNode(totalProgress.loaded, totalProgress.total),
433
463
  cancel: { label: "Cancel", onClick: () => ctrl.cancel() }
434
464
  });
435
- } else if (ctrl.fileInfo) {
436
- toast.loading("Uploading...", {
465
+ } else if (file) {
466
+ toast.loading("Uploading", {
437
467
  id,
438
- description: `${formatFileSize(progress.loaded)} / ${formatFileSize(ctrl.fileInfo.size)} (${progress.percent}%)`,
468
+ description: progressNode(progress.loaded, file.size),
439
469
  cancel: { label: "Cancel", onClick: () => ctrl.cancel() }
440
470
  });
441
471
  }
@@ -444,11 +474,9 @@ function useUploadToast(ctrl, enabled) {
444
474
  ctrl.phase,
445
475
  isMulti,
446
476
  progress.loaded,
447
- progress.percent,
448
477
  totalProgress.loaded,
449
478
  totalProgress.total,
450
- totalProgress.percent,
451
- ctrl.fileInfo,
479
+ file,
452
480
  files,
453
481
  ctrl.cancel
454
482
  ]);
@@ -458,6 +486,7 @@ var EMPTY_FILES = [];
458
486
  function UploadButton({
459
487
  className,
460
488
  label,
489
+ children,
461
490
  disabled,
462
491
  tooltipText,
463
492
  toast: enableToast = true,
@@ -510,10 +539,11 @@ function UploadButton({
510
539
  const openFilePicker = isMulti ? multi.openFilePicker : single.openFilePicker;
511
540
  const inputProps = isMulti ? multi.inputProps : single.inputProps;
512
541
  const buttonLabel = label ?? (isMulti ? "Upload files" : "Upload file");
513
- const button = /* @__PURE__ */ jsxs(Button, { size: "default", disabled: isDisabled, onClick: openFilePicker, children: [
514
- /* @__PURE__ */ jsx(UploadIcon, { "data-icon": "inline-start" }),
542
+ const buttonContent = children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
543
+ /* @__PURE__ */ jsx(CloudUpload, { "data-icon": "inline-start" }),
515
544
  buttonLabel
516
545
  ] });
546
+ const button = /* @__PURE__ */ jsx(Button, { size: "default", disabled: isDisabled, onClick: openFilePicker, children: buttonContent });
517
547
  return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col gap-2", className), children: [
518
548
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-2", children: [
519
549
  /* @__PURE__ */ jsx("input", { ...inputProps }),
@@ -525,11 +555,30 @@ function UploadButton({
525
555
  status
526
556
  ] });
527
557
  }
558
+ function formatDropzoneLimits(options) {
559
+ const parts = [];
560
+ if (options.maxFiles != null && options.maxFiles > 0) {
561
+ parts.push(
562
+ options.maxFiles === 1 ? "You can upload a file" : `You can upload ${options.maxFiles} files`
563
+ );
564
+ }
565
+ if (options.maxFileSize != null) {
566
+ const size = formatFileSize(options.maxFileSize);
567
+ parts.push(
568
+ options.maxFiles != null && options.maxFiles > 1 ? `Each up to ${size}` : `Up to ${size}`
569
+ );
570
+ }
571
+ return parts.length > 0 ? `${parts.join(". ")}.` : null;
572
+ }
573
+ function formatDropzoneAcceptLine(labels) {
574
+ return labels.length > 0 ? `Accepted ${labels.join(", ")}.` : null;
575
+ }
528
576
  var EMPTY_PROGRESS2 = { loaded: 0, total: 0, percent: 0 };
529
577
  var EMPTY_FILES2 = [];
530
578
  function UploadDropzone({
531
579
  className,
532
580
  label,
581
+ children,
533
582
  disabled,
534
583
  toast: enableToast = true,
535
584
  showStatus = true,
@@ -555,11 +604,19 @@ function UploadDropzone({
555
604
  error: single.error,
556
605
  cancel: single.cancel
557
606
  };
607
+ const [isDragOver, setIsDragOver] = useState(false);
558
608
  const isDisabled = disabled || (isMulti ? multi.isUploading : single.isUploading);
559
609
  const openFilePicker = isMulti ? multi.openFilePicker : single.openFilePicker;
560
610
  const dropHandlers = isMulti ? multi.dropHandlers : single.dropHandlers;
561
611
  const inputProps = isMulti ? multi.inputProps : single.inputProps;
562
612
  useUploadToast(ctrl, enableToast);
613
+ const acceptLabels = formatAcceptLabels(options.accept);
614
+ const limitsLine = formatDropzoneLimits({
615
+ maxFileSize: options.maxFileSize,
616
+ maxFiles: options.maxFiles
617
+ });
618
+ const acceptLine = formatDropzoneAcceptLine(acceptLabels);
619
+ const hasCustomContent = children != null;
563
620
  const status = showStatus ? isMulti ? /* @__PURE__ */ jsx(
564
621
  UploadStatusBlock,
565
622
  {
@@ -585,34 +642,51 @@ function UploadDropzone({
585
642
  "div",
586
643
  {
587
644
  className: cn(
588
- "flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed p-6 text-center transition-colors",
645
+ "rounded-lg border-2 border-dashed transition-colors",
646
+ hasCustomContent ? "flex items-stretch justify-stretch p-0" : "flex flex-col items-center justify-center gap-3 p-6 text-center",
589
647
  isDisabled ? "cursor-not-allowed border-muted-foreground/25" : "cursor-pointer border-muted-foreground/25 hover:border-primary/50",
648
+ !isDisabled && isDragOver && "border-primary/50",
590
649
  className
591
650
  ),
592
651
  onClick: isDisabled ? void 0 : openFilePicker,
593
- ...isDisabled ? {} : dropHandlers,
652
+ ...isDisabled ? {} : {
653
+ ...dropHandlers,
654
+ onDragEnter: (e) => {
655
+ if (e.dataTransfer.types.includes("Files")) setIsDragOver(true);
656
+ },
657
+ onDragLeave: (e) => {
658
+ if (!e.currentTarget.contains(e.relatedTarget)) {
659
+ setIsDragOver(false);
660
+ }
661
+ },
662
+ onDrop: (e) => {
663
+ setIsDragOver(false);
664
+ dropHandlers.onDrop(e);
665
+ }
666
+ },
594
667
  children: [
595
668
  /* @__PURE__ */ jsx("input", { ...inputProps }),
596
- /* @__PURE__ */ jsx(
597
- UploadIcon,
598
- {
599
- className: cn(
600
- "size-6 text-muted-foreground",
601
- isDisabled && "opacity-50"
602
- )
603
- }
604
- ),
605
- /* @__PURE__ */ jsx(
606
- "p",
607
- {
608
- className: cn(
609
- "text-sm text-muted-foreground",
610
- isDisabled && "opacity-50"
611
- ),
612
- children: label ?? (isMulti ? "Click or drag & drop files to upload" : "Click or drag & drop to upload")
613
- }
614
- ),
615
- status && /* @__PURE__ */ jsx("div", { className: "w-full text-left", children: status })
669
+ hasCustomContent ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
670
+ /* @__PURE__ */ jsx(
671
+ CloudUpload,
672
+ {
673
+ className: cn("size-6", isDisabled && "opacity-50"),
674
+ strokeWidth: 1.5
675
+ }
676
+ ),
677
+ /* @__PURE__ */ jsxs(
678
+ "div",
679
+ {
680
+ className: cn("flex flex-col gap-1", isDisabled && "opacity-50"),
681
+ children: [
682
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: label ?? "Drag and drop files here" }),
683
+ limitsLine && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: limitsLine }),
684
+ acceptLine && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: acceptLine })
685
+ ]
686
+ }
687
+ ),
688
+ status && /* @__PURE__ */ jsx("div", { className: "w-full text-start", children: status })
689
+ ] })
616
690
  ]
617
691
  }
618
692
  );
@@ -624,7 +698,7 @@ function useDownloadToast({
624
698
  fileSize
625
699
  }) {
626
700
  const displayName = fileName ?? objectKey.split("/").pop() ?? objectKey;
627
- const errorNode = (error) => /* @__PURE__ */ jsx("span", { className: "block [overflow-wrap:anywhere]", children: error instanceof Error ? error.message : "Unknown error" });
701
+ const errorNode = (error) => /* @__PURE__ */ jsx("span", { dir: "auto", className: "block [overflow-wrap:anywhere]", children: error instanceof Error ? error.message : "Unknown error" });
628
702
  const onInitiated = () => {
629
703
  if (enabled) toast.success("Download started");
630
704
  };
@@ -633,8 +707,20 @@ function useDownloadToast({
633
707
  toast.dismiss(`dl-${objectKey}`);
634
708
  toast.success("Download complete", {
635
709
  description: /* @__PURE__ */ jsxs("span", { className: "block", children: [
636
- truncateFilename(actualFileName),
637
- fileSize != null ? ` \xB7 ${formatFileSize(fileSize)}` : ""
710
+ /* @__PURE__ */ jsx("bdi", { children: truncateFilename(actualFileName) }),
711
+ fileSize != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
712
+ " ",
713
+ "\xB7",
714
+ " ",
715
+ /* @__PURE__ */ jsx(
716
+ "span",
717
+ {
718
+ dir: "ltr",
719
+ className: "inline-block whitespace-nowrap tabular-nums",
720
+ children: formatFileSize(fileSize)
721
+ }
722
+ )
723
+ ] }) : null
638
724
  ] })
639
725
  });
640
726
  };
@@ -652,7 +738,7 @@ function useDownloadToast({
652
738
  if (!enabled) return;
653
739
  toast.dismiss(`dl-${objectKey}`);
654
740
  toast.info("Download cancelled", {
655
- description: /* @__PURE__ */ jsx("span", { children: truncateFilename(displayName) })
741
+ description: /* @__PURE__ */ jsx("span", { dir: "auto", children: truncateFilename(displayName) })
656
742
  });
657
743
  };
658
744
  return { onInitiated, onSuccess, onError, onErrorWithPhase, onCancel };
@@ -756,6 +842,9 @@ function ProgressDownloadButton({
756
842
  }
757
843
  dl.download(objectKey, fileName);
758
844
  };
845
+ const computedPercentFromFileSize = fileSize && fileSize > 0 ? Math.min(100, Math.round(dl.progress.loaded / fileSize * 100)) : null;
846
+ const fillPercent = dl.phase === "presigning" ? 12 : dl.progress.total > 0 ? dl.progress.percent : computedPercentFromFileSize;
847
+ const isIndeterminateFill = isDownloading && fillPercent == null && dl.phase === "downloading";
759
848
  return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col gap-1.5", className), children: [
760
849
  /* @__PURE__ */ jsxs(Tooltip, { children: [
761
850
  /* @__PURE__ */ jsxs(
@@ -776,10 +865,12 @@ function ProgressDownloadButton({
776
865
  "span",
777
866
  {
778
867
  className: cn(
779
- "absolute inset-0 bg-primary/15 transition-[width] duration-200",
868
+ "absolute inset-y-0 start-0 bg-primary/15",
869
+ fillPercent != null ? "transition-[width] duration-200" : "w-full animate-pulse",
780
870
  fillClassName
781
871
  ),
782
- style: { width: `${dl.progress.percent}%` }
872
+ style: fillPercent != null ? { width: `${fillPercent}%` } : void 0,
873
+ "aria-hidden": isIndeterminateFill
783
874
  }
784
875
  ),
785
876
  /* @__PURE__ */ jsxs("span", { className: "relative z-10 inline-flex items-center gap-1", children: [
@@ -975,13 +1066,13 @@ function useDeleteToast({
975
1066
  const onSuccess = (_key) => {
976
1067
  if (!enabled) return;
977
1068
  toast.success("File deleted", {
978
- description: /* @__PURE__ */ jsx("span", { children: truncateFilename(displayName) })
1069
+ description: /* @__PURE__ */ jsx("span", { dir: "auto", children: truncateFilename(displayName) })
979
1070
  });
980
1071
  };
981
1072
  const onError = (_key, error) => {
982
1073
  if (!enabled) return;
983
1074
  toast.error("Delete failed", {
984
- description: /* @__PURE__ */ jsx("span", { className: "block [overflow-wrap:anywhere]", children: error instanceof Error ? error.message : "Unknown error" })
1075
+ description: /* @__PURE__ */ jsx("span", { dir: "auto", className: "block [overflow-wrap:anywhere]", children: error instanceof Error ? error.message : "Unknown error" })
985
1076
  });
986
1077
  };
987
1078
  return { onSuccess, onError };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/button.tsx","../src/components/ui/tooltip.tsx","../src/components/ui/circle-progress.tsx","../src/components/upload/upload-status.tsx","../src/components/ui/progress.tsx","../src/components/upload/multi-upload-status.tsx","../src/components/upload/upload-status-block.tsx","../src/hooks/use-upload-toast.tsx","../src/components/upload/upload-button.tsx","../src/components/upload/upload-dropzone.tsx","../src/hooks/use-download-toast.tsx","../src/components/download/download-button.tsx","../src/components/download/progress-download-button.tsx","../src/components/ui/alert-dialog.tsx","../src/hooks/use-delete-toast.tsx","../src/components/delete/delete-button.tsx"],"names":["ButtonPrimitive","jsx","TooltipPrimitive","jsxs","ProgressPrimitive","formatEta","XIcon","CheckCircleIcon","AlertCircleIcon","truncateFilename","formatFileSize","EMPTY_PROGRESS","EMPTY_FILES","useUploadControls","useMultiUploadControls","UploadIcon","toast","DownloadIcon","AlertDialogPrimitive","LoaderIcon"],"mappings":"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","file":"index.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import { Button as ButtonPrimitive } from \"@base-ui/react/button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n xs: \"h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-2.5\",\n sm: \"h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3\",\n lg: \"h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2 [&_svg:not([class*='size-'])]:size-4\",\n icon: \"size-7 [&_svg:not([class*='size-'])]:size-3.5\",\n \"icon-xs\": \"size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5\",\n \"icon-sm\": \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n \"icon-lg\": \"size-8 [&_svg:not([class*='size-'])]:size-4\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Button, buttonVariants };\n","\"use client\";\n\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\n\nimport { cn } from \"@/lib/utils\";\n\nfunction TooltipProvider({\n delay = 0,\n ...props\n}: TooltipPrimitive.Provider.Props) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delay={delay}\n {...props}\n />\n );\n}\n\nfunction Tooltip({ ...props }: TooltipPrimitive.Root.Props) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />;\n}\n\nfunction TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />;\n}\n\nfunction TooltipContent({\n className,\n side = \"top\",\n sideOffset = 4,\n align = \"center\",\n alignOffset = 0,\n children,\n ...props\n}: TooltipPrimitive.Popup.Props &\n Pick<\n TooltipPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\">\n <TooltipPrimitive.Popup\n data-slot=\"tooltip-content\"\n className={cn(\n \"z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pe-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-start-2 data-[side=inline-start]:slide-in-from-end-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n className,\n )}\n {...props}>\n {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-start-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-end-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5\" />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n );\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","\"use client\"\n\nexport function CircleProgress({\n percent,\n size = 20,\n strokeWidth = 2.5,\n}: {\n percent: number\n size?: number\n strokeWidth?: number\n}) {\n const r = (size - strokeWidth) / 2\n const c = 2 * Math.PI * r\n const offset = c - (percent / 100) * c\n return (\n <svg width={size} height={size} className=\"shrink-0 -rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n className=\"text-muted-foreground/20\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n strokeDasharray={c}\n strokeDashoffset={offset}\n strokeLinecap=\"round\"\n className=\"text-primary transition-[stroke-dashoffset] duration-200\"\n />\n </svg>\n )\n}\n","\"use client\";\n\nimport { XIcon, CheckCircleIcon, AlertCircleIcon } from \"lucide-react\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/core\";\nimport { formatEta } from \"@better-s3/react\";\nimport type { UploadPhase, UploadProgress } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport { CircleProgress } from \"@/components/ui/circle-progress\";\n\nexport function UploadStatus({\n phase,\n progress,\n error,\n fileInfo,\n onCancel,\n}: {\n phase: UploadPhase;\n progress: UploadProgress;\n error: string | null;\n fileInfo: { name: string; size: number } | null;\n onCancel?: () => void;\n}) {\n if (phase === \"idle\") return null;\n\n if (phase === \"uploading\" && fileInfo) {\n const eta =\n progress.speed && progress.total\n ? formatEta(progress.total - progress.loaded, progress.speed)\n : null;\n\n const progressMeta = eta ?? `${Math.round(progress.percent)}%`;\n\n return (\n <div className=\"flex w-full items-center gap-2 text-xs\">\n <CircleProgress percent={progress.percent} size={14} strokeWidth={2} />\n <span className=\"min-w-0 flex-1 truncate max-w-[30ch]\">\n {truncateFilename(fileInfo.name)}\n </span>\n <span className=\"ml-auto shrink-0 whitespace-nowrap tabular-nums text-muted-foreground\">\n {progressMeta}\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-6 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\n }}\n >\n <XIcon className=\"size-3.5\" />\n </Button>\n </div>\n );\n }\n\n if (phase === \"success\" && fileInfo) {\n return (\n <div className=\"flex w-full items-center gap-1.5 text-xs\">\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n <span className=\"min-w-0 flex-1 truncate max-w-[30ch]\">\n {truncateFilename(fileInfo.name)}\n </span>\n <span className=\"ml-auto shrink-0 text-muted-foreground\">\n {formatFileSize(fileInfo.size)}\n </span>\n </div>\n );\n }\n\n if (phase === \"error\") {\n return (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {error ?? \"Upload failed\"}\n </p>\n </div>\n );\n }\n\n if (phase === \"validating\" || phase === \"presigning\") {\n return <span className=\"text-xs text-muted-foreground\">Preparing…</span>;\n }\n\n return null;\n}\n","\"use client\";\n\nimport { Progress as ProgressPrimitive } from \"@base-ui/react/progress\";\n\nimport { cn } from \"@/lib/utils\";\n\nfunction Progress({\n className,\n children,\n value,\n ...props\n}: ProgressPrimitive.Root.Props) {\n return (\n <ProgressPrimitive.Root\n value={value}\n data-slot=\"progress\"\n className={cn(\"flex flex-wrap gap-3\", className)}\n {...props}>\n {children}\n <ProgressTrack>\n <ProgressIndicator />\n </ProgressTrack>\n </ProgressPrimitive.Root>\n );\n}\n\nfunction ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {\n return (\n <ProgressPrimitive.Track\n className={cn(\n \"relative flex h-1 w-full items-center overflow-x-hidden rounded-md bg-muted\",\n className,\n )}\n data-slot=\"progress-track\"\n {...props}\n />\n );\n}\n\nfunction ProgressIndicator({\n className,\n ...props\n}: ProgressPrimitive.Indicator.Props) {\n return (\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className={cn(\"h-full bg-primary transition-all\", className)}\n {...props}\n />\n );\n}\n\nfunction ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {\n return (\n <ProgressPrimitive.Label\n className={cn(\"text-xs/relaxed font-medium\", className)}\n data-slot=\"progress-label\"\n {...props}\n />\n );\n}\n\nfunction ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {\n return (\n <ProgressPrimitive.Value\n className={cn(\n \"ms-auto text-xs/relaxed text-muted-foreground tabular-nums\",\n className,\n )}\n data-slot=\"progress-value\"\n {...props}\n />\n );\n}\n\nexport {\n Progress,\n ProgressTrack,\n ProgressIndicator,\n ProgressLabel,\n ProgressValue,\n};\n","\"use client\";\n\nimport { XIcon, CheckCircleIcon, AlertCircleIcon } from \"lucide-react\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/core\";\nimport { formatEta } from \"@better-s3/react\";\nimport type { UploadProgress, MultiUploadFileState } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Progress,\n ProgressLabel,\n ProgressValue,\n} from \"@/components/ui/progress\";\nimport { CircleProgress } from \"@/components/ui/circle-progress\";\n\nexport function MultiUploadStatus({\n phase,\n files,\n totalProgress,\n error,\n onCancel,\n}: {\n phase: string;\n files: MultiUploadFileState[];\n totalProgress: UploadProgress;\n error: string | null;\n onCancel?: () => void;\n}) {\n if (phase === \"idle\") return null;\n\n if (phase === \"uploading\") {\n const eta =\n totalProgress.speed && totalProgress.total\n ? formatEta(\n totalProgress.total - totalProgress.loaded,\n totalProgress.speed,\n )\n : null;\n\n return (\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"flex w-full items-center gap-1.5\">\n <Progress value={totalProgress.percent} className=\"flex-1\">\n <ProgressLabel>\n {files.filter((f) => f.status === \"success\").length}/\n {files.length} files\n {eta ? (\n <span className=\"font-normal text-muted-foreground\">\n {\" \"}\n · {eta}\n </span>\n ) : null}\n </ProgressLabel>\n <ProgressValue />\n </Progress>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\n }}\n >\n <XIcon className=\"size-4\" />\n </Button>\n </div>\n <FileList files={files} />\n </div>\n );\n }\n\n if (phase === \"success\") {\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <span className=\"text-xs text-green-600\">\n All {files.length} file(s) uploaded\n </span>\n <FileList files={files} />\n </div>\n );\n }\n\n if (phase === \"error\") {\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <span className=\"text-xs text-destructive\">\n {error ?? \"Upload failed\"}\n </span>\n {files.length > 0 && <FileList files={files} />}\n </div>\n );\n }\n\n if (phase === \"validating\") {\n return <span className=\"text-xs text-muted-foreground\">Validating…</span>;\n }\n\n return null;\n}\n\n// ─── File List ──────────────────────────────────────────────────────────\n\nfunction FileList({ files }: { files: MultiUploadFileState[] }) {\n return (\n <ul className=\"flex flex-col gap-1\">\n {files.map((f) => (\n <li key={f.id} className=\"flex flex-col gap-0.5 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n {f.status === \"success\" && (\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n )}\n {f.status === \"error\" && (\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n )}\n {(f.status === \"pending\" || f.status === \"uploading\") && (\n <CircleProgress\n percent={f.status === \"uploading\" ? f.progress.percent : 0}\n size={14}\n strokeWidth={2}\n />\n )}\n <span className=\"min-w-0 shrink\">\n {truncateFilename(f.fileName)}\n </span>\n {f.status === \"uploading\" ? (\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(f.progress.loaded)} /{\" \"}\n {formatFileSize(f.fileSize)} ({f.progress.percent}%)\n </span>\n ) : (\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(f.fileSize)}\n </span>\n )}\n </div>\n {f.status === \"error\" && f.error && (\n <span className=\"truncate [overflow-wrap:anywhere] pl-5 text-destructive\">\n {f.error}\n </span>\n )}\n </li>\n ))}\n </ul>\n );\n}\n","\"use client\";\n\nimport type {\n UploadPhase,\n UploadProgress,\n MultiUploadFileState,\n MultiUploadPhase,\n} from \"@better-s3/react\";\nimport { UploadStatus } from \"@/components/upload/upload-status\";\nimport { MultiUploadStatus } from \"@/components/upload/multi-upload-status\";\n\nexport type UploadStatusBlockProps =\n | {\n mode: \"single\";\n phase: UploadPhase;\n progress: UploadProgress;\n error: string | null;\n fileInfo: { name: string; size: number } | null;\n onCancel?: () => void;\n }\n | {\n mode: \"multi\";\n phase: MultiUploadPhase;\n files: MultiUploadFileState[];\n totalProgress: UploadProgress;\n error: string | null;\n onCancel?: () => void;\n };\n\nexport function UploadStatusBlock(props: UploadStatusBlockProps) {\n if (props.mode === \"multi\") {\n return (\n <MultiUploadStatus\n phase={props.phase}\n files={props.files}\n totalProgress={props.totalProgress}\n error={props.error}\n onCancel={props.onCancel}\n />\n );\n }\n return (\n <UploadStatus\n phase={props.phase}\n progress={props.progress}\n error={props.error}\n fileInfo={props.fileInfo}\n onCancel={props.onCancel}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { formatFileSize } from \"@better-s3/core\";\nimport type { UploadProgress, MultiUploadFileState } from \"@better-s3/react\";\n\nexport type UploadToastCtrl = {\n mode: \"single\" | \"multi\";\n phase: string;\n fileInfo?: { name: string; size: number } | null;\n progress?: UploadProgress;\n files?: MultiUploadFileState[];\n totalProgress?: UploadProgress;\n error: string | null;\n cancel: () => void;\n};\n\n/**\n * Drives sonner toasts for upload progress/success/error.\n * Shared between UploadButton and UploadDropzone.\n */\nexport function useUploadToast(ctrl: UploadToastCtrl, enabled: boolean) {\n const toastIdRef = useRef<string | null>(null);\n const isMulti = ctrl.mode === \"multi\";\n const files = ctrl.files ?? [];\n const totalProgress = ctrl.totalProgress ?? {\n loaded: 0,\n total: 0,\n percent: 0,\n };\n const progress = ctrl.progress ?? { loaded: 0, total: 0, percent: 0 };\n\n // Phase-transition toasts (runs synchronously during render to fire exactly once)\n const prevPhaseRef = useRef(ctrl.phase);\n if (prevPhaseRef.current !== ctrl.phase) {\n prevPhaseRef.current = ctrl.phase;\n if (enabled) {\n if (ctrl.phase === \"idle\" && toastIdRef.current) {\n toast.dismiss(toastIdRef.current);\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"success\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n if (isMulti) {\n toast.success(`${files.length} file(s) uploaded`, {\n description: formatFileSize(totalProgress.total),\n });\n } else if (ctrl.fileInfo) {\n toast.success(\"Upload complete\", {\n description: formatFileSize(ctrl.fileInfo.size),\n });\n }\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"error\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n if (isMulti && files.length > 0) {\n const succeeded = files.filter((f) => f.status === \"success\").length;\n const failed = files.filter((f) => f.status === \"error\").length;\n toast.error(\"Upload finished with errors\", {\n description: `${succeeded} succeeded, ${failed} failed`,\n });\n } else {\n toast.error(\"Upload failed\", {\n description: (\n <span className=\"block [overflow-wrap:anywhere]\">\n {ctrl.error ?? \"Unknown error\"}\n </span>\n ),\n });\n }\n toastIdRef.current = null;\n }\n }\n }\n\n // Progress toast (updated on each progress tick)\n useEffect(() => {\n if (!enabled || ctrl.phase !== \"uploading\") return;\n const id = toastIdRef.current ?? `upload-${Date.now()}`;\n toastIdRef.current = id;\n if (isMulti) {\n const done = files.filter((f) => f.status === \"success\").length;\n toast.loading(`Uploading... ${done}/${files.length}`, {\n id,\n description: `${formatFileSize(totalProgress.loaded)} / ${formatFileSize(totalProgress.total)} (${totalProgress.percent}%)`,\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n } else if (ctrl.fileInfo) {\n toast.loading(\"Uploading...\", {\n id,\n description: `${formatFileSize(progress.loaded)} / ${formatFileSize(ctrl.fileInfo.size)} (${progress.percent}%)`,\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n }\n }, [\n enabled,\n ctrl.phase,\n isMulti,\n progress.loaded,\n progress.percent,\n totalProgress.loaded,\n totalProgress.total,\n totalProgress.percent,\n ctrl.fileInfo,\n files,\n ctrl.cancel,\n ]);\n}\n","\"use client\";\n\nimport { UploadIcon } from \"lucide-react\";\nimport {\n useUploadControls,\n useMultiUploadControls,\n type UseUploadControlsOptions,\n type UseMultiUploadControlsOptions,\n type UploadProgress,\n type MultiUploadFileState,\n} from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { UploadStatusBlock } from \"@/components/upload/upload-status-block\";\nimport { useUploadToast, type UploadToastCtrl } from \"@/hooks/use-upload-toast\";\n\nconst EMPTY_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\nconst EMPTY_FILES: MultiUploadFileState[] = [];\n\n/** Props for {@link UploadButton}. Extends {@link UseUploadControlsOptions} or {@link UseMultiUploadControlsOptions}. */\nexport type UploadButtonProps = (\n | UseUploadControlsOptions\n | UseMultiUploadControlsOptions\n) & {\n className?: string;\n /** Button label. */\n label?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Show sonner toasts during upload. @default true */\n toast?: boolean;\n /** Show inline status below the button. @default true */\n showStatus?: boolean;\n};\n\nexport function UploadButton({\n className,\n label,\n disabled,\n tooltipText,\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadButtonProps) {\n const isMulti =\n ((options as UseMultiUploadControlsOptions).maxFiles ?? 1) > 1;\n\n // Both hooks must be called unconditionally (React rules of hooks).\n // Only the active mode's output is used.\n const single = useUploadControls(options as UseUploadControlsOptions);\n const multi = useMultiUploadControls(\n options as UseMultiUploadControlsOptions,\n );\n\n const ctrl: UploadToastCtrl = isMulti\n ? {\n mode: \"multi\",\n phase: multi.phase,\n files: multi.files,\n totalProgress: multi.totalProgress,\n error: multi.error,\n cancel: multi.cancel,\n }\n : {\n mode: \"single\",\n phase: single.phase,\n fileInfo: single.fileInfo,\n progress: single.progress,\n error: single.error,\n cancel: single.cancel,\n };\n\n const isDisabled =\n disabled || (isMulti ? multi.isUploading : single.isUploading);\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <UploadStatusBlock\n mode=\"multi\"\n phase={multi.phase}\n files={multi.files ?? EMPTY_FILES}\n totalProgress={multi.totalProgress ?? EMPTY_PROGRESS}\n error={multi.error}\n onCancel={multi.cancel}\n />\n ) : (\n <UploadStatusBlock\n mode=\"single\"\n phase={single.phase}\n progress={single.progress}\n error={single.error}\n fileInfo={single.fileInfo}\n onCancel={single.cancel}\n />\n )\n ) : null;\n\n const openFilePicker = isMulti ? multi.openFilePicker : single.openFilePicker;\n const inputProps = isMulti ? multi.inputProps : single.inputProps;\n\n const buttonLabel = label ?? (isMulti ? \"Upload files\" : \"Upload file\");\n\n const button = (\n <Button size=\"default\" disabled={isDisabled} onClick={openFilePicker}>\n <UploadIcon data-icon=\"inline-start\" />\n {buttonLabel}\n </Button>\n );\n\n return (\n <div className={cn(\"inline-flex flex-col gap-2\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <input {...inputProps} />\n {tooltipText ? (\n <Tooltip>\n <TooltipTrigger render={button} />\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n ) : (\n button\n )}\n </div>\n {status}\n </div>\n );\n}\n","\"use client\";\n\nimport { UploadIcon } from \"lucide-react\";\nimport {\n useUploadControls,\n useMultiUploadControls,\n type UseUploadControlsOptions,\n type UseMultiUploadControlsOptions,\n type UploadProgress,\n type MultiUploadFileState,\n} from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { UploadStatusBlock } from \"@/components/upload/upload-status-block\";\nimport { useUploadToast, type UploadToastCtrl } from \"@/hooks/use-upload-toast\";\n\nconst EMPTY_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\nconst EMPTY_FILES: MultiUploadFileState[] = [];\n\n/** Props for {@link UploadDropzone}. Extends {@link UseUploadControlsOptions} or {@link UseMultiUploadControlsOptions}. */\nexport type UploadDropzoneProps = (\n | UseUploadControlsOptions\n | UseMultiUploadControlsOptions\n) & {\n className?: string;\n /** Dropzone label. */\n label?: string;\n disabled?: boolean;\n /** Show sonner toasts during upload. @default true */\n toast?: boolean;\n /** Show inline status inside the dropzone. @default true */\n showStatus?: boolean;\n};\n\nexport function UploadDropzone({\n className,\n label,\n disabled,\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadDropzoneProps) {\n const isMulti =\n ((options as UseMultiUploadControlsOptions).maxFiles ?? 1) > 1;\n\n // Both hooks must be called unconditionally (React rules of hooks).\n const single = useUploadControls(options as UseUploadControlsOptions);\n const multi = useMultiUploadControls(\n options as UseMultiUploadControlsOptions,\n );\n\n const ctrl: UploadToastCtrl = isMulti\n ? {\n mode: \"multi\",\n phase: multi.phase,\n files: multi.files,\n totalProgress: multi.totalProgress,\n error: multi.error,\n cancel: multi.cancel,\n }\n : {\n mode: \"single\",\n phase: single.phase,\n fileInfo: single.fileInfo,\n progress: single.progress,\n error: single.error,\n cancel: single.cancel,\n };\n\n const isDisabled =\n disabled || (isMulti ? multi.isUploading : single.isUploading);\n const openFilePicker = isMulti ? multi.openFilePicker : single.openFilePicker;\n const dropHandlers = isMulti ? multi.dropHandlers : single.dropHandlers;\n const inputProps = isMulti ? multi.inputProps : single.inputProps;\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <UploadStatusBlock\n mode=\"multi\"\n phase={multi.phase}\n files={multi.files ?? EMPTY_FILES}\n totalProgress={multi.totalProgress ?? EMPTY_PROGRESS}\n error={multi.error}\n onCancel={multi.cancel}\n />\n ) : (\n <UploadStatusBlock\n mode=\"single\"\n phase={single.phase}\n progress={single.progress}\n error={single.error}\n fileInfo={single.fileInfo}\n onCancel={single.cancel}\n />\n )\n ) : null;\n\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed p-6 text-center transition-colors\",\n isDisabled\n ? \"cursor-not-allowed border-muted-foreground/25\"\n : \"cursor-pointer border-muted-foreground/25 hover:border-primary/50\",\n className,\n )}\n onClick={isDisabled ? undefined : openFilePicker}\n {...(isDisabled ? {} : dropHandlers)}\n >\n <input {...inputProps} />\n <UploadIcon\n className={cn(\n \"size-6 text-muted-foreground\",\n isDisabled && \"opacity-50\",\n )}\n />\n <p\n className={cn(\n \"text-sm text-muted-foreground\",\n isDisabled && \"opacity-50\",\n )}\n >\n {label ??\n (isMulti\n ? \"Click or drag & drop files to upload\"\n : \"Click or drag & drop to upload\")}\n </p>\n {status && <div className=\"w-full text-left\">{status}</div>}\n </div>\n );\n}\n","\"use client\";\n\nimport { toast } from \"sonner\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/core\";\n\nexport type DownloadToastOptions = {\n enabled?: boolean;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n};\n\nexport function useDownloadToast({\n enabled = true,\n objectKey,\n fileName,\n fileSize,\n}: DownloadToastOptions) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const errorNode = (error: unknown) => (\n <span className=\"block [overflow-wrap:anywhere]\">\n {error instanceof Error ? error.message : \"Unknown error\"}\n </span>\n );\n\n const onInitiated = () => {\n if (enabled) toast.success(\"Download started\");\n };\n\n const onSuccess = (_key: string, actualFileName: string) => {\n if (!enabled) return;\n toast.dismiss(`dl-${objectKey}`);\n toast.success(\"Download complete\", {\n description: (\n <span className=\"block\">\n {truncateFilename(actualFileName)}\n {fileSize != null ? ` · ${formatFileSize(fileSize)}` : \"\"}\n </span>\n ),\n });\n };\n\n const onError = (_key: string, error: unknown) => {\n if (!enabled) return;\n toast.dismiss(`dl-${objectKey}`);\n toast.error(\"Download failed\", { description: errorNode(error) });\n };\n\n const onErrorWithPhase = (_key: string, error: unknown, _phase: string) => {\n if (!enabled) return;\n toast.dismiss(`dl-${objectKey}`);\n toast.error(\"Download failed\", { description: errorNode(error) });\n };\n\n const onCancel = (_key: string) => {\n if (!enabled) return;\n toast.dismiss(`dl-${objectKey}`);\n toast.info(\"Download cancelled\", {\n description: <span>{truncateFilename(displayName)}</span>,\n });\n };\n\n return { onInitiated, onSuccess, onError, onErrorWithPhase, onCancel };\n}\n","\"use client\";\n\nimport { AlertCircleIcon, DownloadIcon, LoaderIcon } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { useDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport { useDownloadToast } from \"@/hooks/use-download-toast\";\n\n/** Props for {@link DownloadButton}. */\nexport type DownloadButtonProps = {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** S3 object key to download. */\n objectKey: string;\n /** Download filename for Content-Disposition. */\n fileName?: string;\n /** Button label. @default \"Download\" */\n label?: string;\n className?: string;\n disabled?: boolean;\n /** Show a sonner toast when download starts. @default true */\n toast?: boolean;\n /** Show inline error below the button. @default true */\n showStatus?: boolean;\n};\n\nexport function DownloadButton({\n api,\n objectKey,\n fileName,\n label,\n className,\n disabled,\n toast: enableToast = true,\n showStatus = true,\n}: DownloadButtonProps) {\n const toastHandlers = useDownloadToast({\n enabled: enableToast,\n objectKey,\n fileName,\n });\n\n const dl = useDownload({\n api,\n onInitiated: () => {\n toastHandlers.onInitiated();\n },\n onError: (key, error) => {\n toastHandlers.onError(key, error);\n },\n });\n\n const isPending = dl.phase === \"presigning\";\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <Button\n size=\"default\"\n variant=\"outline\"\n disabled={disabled || isPending}\n onClick={() => dl.download(objectKey, fileName)}\n >\n <span className=\"inline-flex items-center gap-1\">\n {isPending ? (\n <LoaderIcon className=\"animate-spin\" data-icon=\"inline-start\" />\n ) : (\n <DownloadIcon data-icon=\"inline-start\" />\n )}\n {label ?? \"Download\"}\n </span>\n </Button>\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {dl.error ?? \"Download failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { DownloadIcon, AlertCircleIcon } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/core\";\nimport { formatSpeed, formatEta } from \"@better-s3/react\";\nimport type { FetchDownloadHooks } from \"@better-s3/react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { useFetchDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useDownloadToast } from \"@/hooks/use-download-toast\";\n\n/** Props for {@link ProgressDownloadButton}. */\nexport type ProgressDownloadButtonProps = FetchDownloadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** S3 object key to download. */\n objectKey: string;\n /** Download filename for Content-Disposition. */\n fileName?: string;\n /** Total file size in bytes (used for progress display). */\n fileSize?: number;\n /** Target bucket (overrides server default). */\n bucket?: string;\n /** Button label. @default \"Download\" */\n label?: string;\n className?: string;\n fillClassName?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Show sonner toasts during download. @default true */\n toast?: boolean;\n /** Show inline error below the button. @default true */\n showStatus?: boolean;\n};\n\nexport function ProgressDownloadButton({\n api,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n fillClassName,\n disabled,\n tooltipText = \"Download file\",\n toast: enableToast = true,\n showStatus = true,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess,\n onError,\n onCancel,\n}: ProgressDownloadButtonProps) {\n const toastHandlers = useDownloadToast({\n enabled: enableToast,\n objectKey,\n fileName,\n fileSize,\n });\n\n const dl = useFetchDownload({\n api,\n bucket,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess: (key, actualFileName) => {\n toastHandlers.onSuccess(key, actualFileName);\n onSuccess?.(key, actualFileName);\n },\n onError: (key, error, phase) => {\n toastHandlers.onErrorWithPhase(key, error, phase);\n onError?.(key, error, phase);\n },\n onCancel: (key) => {\n toastHandlers.onCancel(key);\n onCancel?.(key);\n },\n });\n\n const isDownloading = dl.phase === \"downloading\" || dl.phase === \"presigning\";\n\n const eta =\n dl.phase === \"downloading\" && dl.progress.speed && dl.progress.total\n ? formatEta(dl.progress.total - dl.progress.loaded, dl.progress.speed)\n : null;\n\n const handleClick = () => {\n if (isDownloading) {\n dl.cancel();\n return;\n }\n dl.download(objectKey, fileName);\n };\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n size=\"default\"\n variant=\"outline\"\n disabled={disabled}\n className={cn(\"relative min-w-24 overflow-hidden\")}\n onClick={handleClick}\n />\n }\n >\n {isDownloading && (\n <span\n className={cn(\n \"absolute inset-0 bg-primary/15 transition-[width] duration-200\",\n fillClassName,\n )}\n style={{ width: `${dl.progress.percent}%` }}\n />\n )}\n <span className=\"relative z-10 inline-flex items-center gap-1\">\n <DownloadIcon data-icon=\"inline-start\" />\n {isDownloading\n ? formatFileSize(dl.progress.loaded)\n : (label ?? \"Download\")}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {isDownloading ? \"Cancel download\" : tooltipText}\n </TooltipContent>\n </Tooltip>\n\n {showStatus && dl.phase === \"downloading\" && dl.progress.loaded > 0 && (\n <p className=\"text-xs tabular-nums text-muted-foreground\">\n {formatFileSize(dl.progress.loaded)}\n {dl.progress.total > 0 && (\n <span className=\"text-muted-foreground/50\">\n {\" \"}\n / {formatFileSize(dl.progress.total)}\n </span>\n )}\n {dl.progress.speed ? (\n <span> · {formatSpeed(dl.progress.speed)}</span>\n ) : null}\n {eta ? (\n <span className=\"text-muted-foreground/50\"> · in {eta}</span>\n ) : null}\n </p>\n )}\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {dl.error ?? \"Download failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { AlertDialog as AlertDialogPrimitive } from \"@base-ui/react/alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\n\nfunction AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {\n return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />;\n}\n\nfunction AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {\n return (\n <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n );\n}\n\nfunction AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {\n return (\n <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n );\n}\n\nfunction AlertDialogOverlay({\n className,\n ...props\n}: AlertDialogPrimitive.Backdrop.Props) {\n return (\n <AlertDialogPrimitive.Backdrop\n data-slot=\"alert-dialog-overlay\"\n className={cn(\n \"fixed inset-0 isolate z-50 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogContent({\n className,\n size = \"default\",\n ...props\n}: AlertDialogPrimitive.Popup.Props & {\n size?: \"default\" | \"sm\";\n}) {\n return (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Popup\n data-slot=\"alert-dialog-content\"\n data-size={size}\n className={cn(\n \"group/alert-dialog-content fixed top-1/2 start-1/2 z-50 grid w-full -translate-x-1/2 rtl:translate-x-1/2 -translate-y-1/2 gap-3 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-64 data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n );\n}\n\nfunction AlertDialogHeader({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-header\"\n className={cn(\n \"grid grid-rows-[auto_1fr] place-items-center gap-1 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-start sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogFooter({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogMedia({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-media\"\n className={cn(\n \"mb-2 inline-flex size-8 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n return (\n <AlertDialogPrimitive.Title\n data-slot=\"alert-dialog-title\"\n className={cn(\n \"font-heading text-sm font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n return (\n <AlertDialogPrimitive.Description\n data-slot=\"alert-dialog-description\"\n className={cn(\n \"text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogAction({\n className,\n ...props\n}: React.ComponentProps<typeof Button>) {\n return (\n <Button\n data-slot=\"alert-dialog-action\"\n className={cn(className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogCancel({\n className,\n variant = \"outline\",\n size = \"default\",\n ...props\n}: AlertDialogPrimitive.Close.Props &\n Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n return (\n <AlertDialogPrimitive.Close\n data-slot=\"alert-dialog-cancel\"\n className={cn(className)}\n render={<Button variant={variant} size={size} />}\n {...props}\n />\n );\n}\n\nexport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogTitle,\n AlertDialogTrigger,\n};\n","\"use client\";\n\nimport { toast } from \"sonner\";\nimport { truncateFilename } from \"@better-s3/core\";\n\nexport type DeleteToastOptions = {\n enabled?: boolean;\n displayName: string;\n};\n\nexport function useDeleteToast({\n enabled = true,\n displayName,\n}: DeleteToastOptions) {\n const onSuccess = (_key: string) => {\n if (!enabled) return;\n toast.success(\"File deleted\", {\n description: <span>{truncateFilename(displayName)}</span>,\n });\n };\n\n const onError = (_key: string, error: unknown) => {\n if (!enabled) return;\n toast.error(\"Delete failed\", {\n description: (\n <span className=\"block [overflow-wrap:anywhere]\">\n {error instanceof Error ? error.message : \"Unknown error\"}\n </span>\n ),\n });\n };\n\n return { onSuccess, onError };\n}\n","\"use client\";\n\nimport {\n Trash2Icon,\n LoaderIcon,\n AlertCircleIcon,\n CheckCircle2Icon,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/core\";\nimport type { DeleteHooks } from \"@better-s3/react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { useDelete } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@/components/ui/alert-dialog\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useDeleteToast } from \"@/hooks/use-delete-toast\";\n\n/** Props for {@link DeleteButton}. */\nexport type DeleteButtonProps = DeleteHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** S3 object key to delete. */\n objectKey: string;\n /** Display file name in the confirmation dialog. */\n fileName?: string;\n /** Display file size in the confirmation dialog. */\n fileSize?: number;\n /** Target bucket (overrides server default). */\n bucket?: string;\n /** Button label. */\n label?: string;\n className?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Show a sonner toast during delete. @default true */\n toast?: boolean;\n /** Show inline error below the button. @default true */\n showStatus?: boolean;\n confirmTitle?: string;\n confirmDescription?: string;\n};\n\nexport function DeleteButton({\n api,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n disabled,\n tooltipText = \"Delete file\",\n toast: enableToast = true,\n showStatus = true,\n confirmTitle = \"Delete file?\",\n confirmDescription,\n beforeDelete,\n onDeleteStart,\n onSuccess,\n onError,\n}: DeleteButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n const toastHandlers = useDeleteToast({\n enabled: enableToast,\n displayName,\n });\n\n const del = useDelete({\n api,\n bucket,\n beforeDelete,\n onDeleteStart,\n onSuccess: (key) => {\n toastHandlers.onSuccess(key);\n onSuccess?.(key);\n },\n onError: (key, error, phase) => {\n toastHandlers.onError(key, error);\n onError?.(key, error, phase);\n },\n });\n\n const isDeleting = del.phase === \"deleting\";\n const isDisabled = disabled || isDeleting;\n\n const description = confirmDescription ?? (\n <>\n {\"Are you sure you want to delete \"}\n <span className=\"font-medium inline-block align-bottom\">\n &ldquo;{truncateFilename(displayName)}&rdquo;\n </span>\n {fileSize != null ? ` (${formatFileSize(fileSize)})` : \"\"}\n {\"? This action cannot be undone.\"}\n </>\n );\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <AlertDialog\n open={del.phase === \"confirming\"}\n onOpenChange={(open) => {\n if (!open) del.cancelDelete();\n }}\n >\n <Tooltip>\n <TooltipTrigger\n render={\n <AlertDialogTrigger\n disabled={isDisabled}\n onClick={() => del.requestDelete(objectKey)}\n render={\n <Button\n size=\"default\"\n variant=\"destructive\"\n disabled={isDisabled}\n />\n }\n />\n }\n >\n {isDeleting ? (\n <LoaderIcon className=\"animate-spin\" data-icon=\"inline-start\" />\n ) : (\n <Trash2Icon data-icon=\"inline-start\" />\n )}\n {label ?? \"Delete\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogMedia>\n <Trash2Icon />\n </AlertDialogMedia>\n <AlertDialogTitle>{confirmTitle}</AlertDialogTitle>\n <AlertDialogDescription className=\"[overflow-wrap:anywhere]\">\n {description}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => del.confirmDelete()}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n\n {showStatus && del.phase === \"success\" && (\n <div className=\"flex min-w-0 items-center gap-1.5 text-xs\">\n <CheckCircle2Icon className=\"size-3.5 shrink-0 text-green-600\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-green-600\">\n &ldquo;{truncateFilename(displayName)}&rdquo; deleted\n </p>\n </div>\n )}\n\n {showStatus && del.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {del.error ?? \"Delete failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/button.tsx","../src/components/ui/tooltip.tsx","../src/components/ui/circle-progress.tsx","../src/components/upload/upload-status.tsx","../src/components/ui/progress.tsx","../src/components/upload/multi-upload-status.tsx","../src/components/upload/upload-status-block.tsx","../src/hooks/use-upload-toast.tsx","../src/components/upload/upload-button.tsx","../src/components/upload/upload-dropzone.tsx","../src/hooks/use-download-toast.tsx","../src/components/download/download-button.tsx","../src/components/download/progress-download-button.tsx","../src/components/ui/alert-dialog.tsx","../src/hooks/use-delete-toast.tsx","../src/components/delete/delete-button.tsx"],"names":["ButtonPrimitive","jsx","TooltipPrimitive","jsxs","ProgressPrimitive","formatEta","XIcon","CheckCircleIcon","AlertCircleIcon","truncateFilename","formatFileSize","EMPTY_PROGRESS","EMPTY_FILES","useUploadControls","useMultiUploadControls","Fragment","CloudUpload","toast","DownloadIcon","AlertDialogPrimitive","LoaderIcon"],"mappings":"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","file":"index.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","import { Button as ButtonPrimitive } from \"@base-ui/react/button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n xs: \"h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-2.5\",\n sm: \"h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3\",\n lg: \"h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2 [&_svg:not([class*='size-'])]:size-4\",\n icon: \"size-7 [&_svg:not([class*='size-'])]:size-3.5\",\n \"icon-xs\": \"size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5\",\n \"icon-sm\": \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n \"icon-lg\": \"size-8 [&_svg:not([class*='size-'])]:size-4\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Button, buttonVariants };\n","\"use client\";\n\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\n\nimport { cn } from \"@/lib/utils\";\n\nfunction TooltipProvider({\n delay = 0,\n ...props\n}: TooltipPrimitive.Provider.Props) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delay={delay}\n {...props}\n />\n );\n}\n\nfunction Tooltip({ ...props }: TooltipPrimitive.Root.Props) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />;\n}\n\nfunction TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />;\n}\n\nfunction TooltipContent({\n className,\n side = \"top\",\n sideOffset = 4,\n align = \"center\",\n alignOffset = 0,\n children,\n ...props\n}: TooltipPrimitive.Popup.Props &\n Pick<\n TooltipPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\">\n <TooltipPrimitive.Popup\n data-slot=\"tooltip-content\"\n className={cn(\n \"z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pe-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-start-2 data-[side=inline-start]:slide-in-from-end-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n className,\n )}\n {...props}>\n {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-start-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-end-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5\" />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n );\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n","\"use client\"\n\nexport function CircleProgress({\n percent,\n size = 20,\n strokeWidth = 2.5,\n}: {\n percent: number\n size?: number\n strokeWidth?: number\n}) {\n const r = (size - strokeWidth) / 2\n const c = 2 * Math.PI * r\n const offset = c - (percent / 100) * c\n return (\n <svg width={size} height={size} className=\"shrink-0 -rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n className=\"text-muted-foreground/20\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n strokeDasharray={c}\n strokeDashoffset={offset}\n strokeLinecap=\"round\"\n className=\"text-primary transition-[stroke-dashoffset] duration-200\"\n />\n </svg>\n )\n}\n","\"use client\";\n\nimport { XIcon, CheckCircleIcon, AlertCircleIcon } from \"lucide-react\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/core\";\nimport { formatEta } from \"@better-s3/react\";\nimport type { UploadPhase, UploadProgress } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport { CircleProgress } from \"@/components/ui/circle-progress\";\n\nexport function UploadStatus({\n phase,\n progress,\n error,\n fileInfo,\n onCancel,\n}: {\n phase: UploadPhase;\n progress: UploadProgress;\n error: string | null;\n fileInfo: { name: string; size: number } | null;\n onCancel?: () => void;\n}) {\n if (phase === \"idle\") return null;\n\n if (phase === \"uploading\" && fileInfo) {\n const eta =\n progress.speed && progress.total\n ? formatEta(progress.total - progress.loaded, progress.speed)\n : null;\n\n const progressMeta = eta ?? `${Math.round(progress.percent)}%`;\n\n return (\n <div className=\"flex w-full items-center gap-2 text-xs\">\n <CircleProgress percent={progress.percent} size={14} strokeWidth={2} />\n <span className=\"min-w-0 flex-1 truncate max-w-[30ch]\">\n {truncateFilename(fileInfo.name)}\n </span>\n <span className=\"ms-auto shrink-0 whitespace-nowrap tabular-nums text-muted-foreground\">\n {progressMeta}\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-6 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\n }}\n >\n <XIcon className=\"size-3.5\" />\n </Button>\n </div>\n );\n }\n\n if (phase === \"success\" && fileInfo) {\n return (\n <div className=\"flex w-full items-center gap-1.5 text-xs\">\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n <span className=\"min-w-0 flex-1 truncate max-w-[30ch]\">\n {truncateFilename(fileInfo.name)}\n </span>\n <span className=\"ms-auto shrink-0 text-muted-foreground\">\n {formatFileSize(fileInfo.size)}\n </span>\n </div>\n );\n }\n\n if (phase === \"error\") {\n return (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {error ?? \"Upload failed\"}\n </p>\n </div>\n );\n }\n\n if (phase === \"validating\" || phase === \"presigning\") {\n return <span className=\"text-xs text-muted-foreground\">Preparing…</span>;\n }\n\n return null;\n}\n","\"use client\";\n\nimport { Progress as ProgressPrimitive } from \"@base-ui/react/progress\";\n\nimport { cn } from \"@/lib/utils\";\n\nfunction Progress({\n className,\n children,\n value,\n ...props\n}: ProgressPrimitive.Root.Props) {\n return (\n <ProgressPrimitive.Root\n value={value}\n data-slot=\"progress\"\n className={cn(\"flex flex-wrap gap-3\", className)}\n {...props}>\n {children}\n <ProgressTrack>\n <ProgressIndicator />\n </ProgressTrack>\n </ProgressPrimitive.Root>\n );\n}\n\nfunction ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {\n return (\n <ProgressPrimitive.Track\n className={cn(\n \"relative flex h-1 w-full items-center overflow-x-hidden rounded-md bg-muted\",\n className,\n )}\n data-slot=\"progress-track\"\n {...props}\n />\n );\n}\n\nfunction ProgressIndicator({\n className,\n ...props\n}: ProgressPrimitive.Indicator.Props) {\n return (\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className={cn(\"h-full bg-primary transition-all\", className)}\n {...props}\n />\n );\n}\n\nfunction ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {\n return (\n <ProgressPrimitive.Label\n className={cn(\"text-xs/relaxed font-medium\", className)}\n data-slot=\"progress-label\"\n {...props}\n />\n );\n}\n\nfunction ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {\n return (\n <ProgressPrimitive.Value\n className={cn(\n \"ms-auto text-xs/relaxed text-muted-foreground tabular-nums\",\n className,\n )}\n data-slot=\"progress-value\"\n {...props}\n />\n );\n}\n\nexport {\n Progress,\n ProgressTrack,\n ProgressIndicator,\n ProgressLabel,\n ProgressValue,\n};\n","\"use client\";\n\nimport { XIcon, CheckCircleIcon, AlertCircleIcon } from \"lucide-react\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/core\";\nimport { formatEta } from \"@better-s3/react\";\nimport type { UploadProgress, MultiUploadFileState } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Progress,\n ProgressLabel,\n ProgressValue,\n} from \"@/components/ui/progress\";\nimport { CircleProgress } from \"@/components/ui/circle-progress\";\n\nexport function MultiUploadStatus({\n phase,\n files,\n totalProgress,\n error,\n onCancel,\n}: {\n phase: string;\n files: MultiUploadFileState[];\n totalProgress: UploadProgress;\n error: string | null;\n onCancel?: () => void;\n}) {\n if (phase === \"idle\") return null;\n\n if (phase === \"uploading\") {\n const eta =\n totalProgress.speed && totalProgress.total\n ? formatEta(\n totalProgress.total - totalProgress.loaded,\n totalProgress.speed,\n )\n : null;\n\n return (\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"flex w-full items-center gap-1.5\">\n <Progress value={totalProgress.percent} className=\"flex-1\">\n <ProgressLabel>\n {files.filter((f) => f.status === \"success\").length}/\n {files.length} files\n {eta ? (\n <span className=\"font-normal text-muted-foreground\">\n {\" \"}\n · {eta}\n </span>\n ) : null}\n </ProgressLabel>\n <ProgressValue />\n </Progress>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\n }}\n >\n <XIcon className=\"size-4\" />\n </Button>\n </div>\n <FileList files={files} />\n </div>\n );\n }\n\n if (phase === \"success\") {\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <span className=\"text-xs text-green-600\">\n All {files.length} file(s) uploaded\n </span>\n <FileList files={files} />\n </div>\n );\n }\n\n if (phase === \"error\") {\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <span className=\"text-xs text-destructive\">\n {error ?? \"Upload failed\"}\n </span>\n {files.length > 0 && <FileList files={files} />}\n </div>\n );\n }\n\n if (phase === \"validating\") {\n return <span className=\"text-xs text-muted-foreground\">Validating…</span>;\n }\n\n return null;\n}\n\n// ─── File List ──────────────────────────────────────────────────────────\n\nfunction FileList({ files }: { files: MultiUploadFileState[] }) {\n return (\n <ul className=\"flex flex-col gap-1\">\n {files.map((f) => (\n <li key={f.id} className=\"flex flex-col gap-0.5 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n {f.status === \"success\" && (\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n )}\n {f.status === \"error\" && (\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n )}\n {(f.status === \"pending\" || f.status === \"uploading\") && (\n <CircleProgress\n percent={f.status === \"uploading\" ? f.progress.percent : 0}\n size={14}\n strokeWidth={2}\n />\n )}\n <span className=\"min-w-0 shrink\">\n {truncateFilename(f.fileName)}\n </span>\n {f.status === \"uploading\" ? (\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(f.progress.loaded)} /{\" \"}\n {formatFileSize(f.fileSize)} ({f.progress.percent}%)\n </span>\n ) : (\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(f.fileSize)}\n </span>\n )}\n </div>\n {f.status === \"error\" && f.error && (\n <span className=\"truncate [overflow-wrap:anywhere] ps-5 text-destructive\">\n {f.error}\n </span>\n )}\n </li>\n ))}\n </ul>\n );\n}\n","\"use client\";\n\nimport type {\n UploadPhase,\n UploadProgress,\n MultiUploadFileState,\n MultiUploadPhase,\n} from \"@better-s3/react\";\nimport { UploadStatus } from \"@/components/upload/upload-status\";\nimport { MultiUploadStatus } from \"@/components/upload/multi-upload-status\";\n\nexport type UploadStatusBlockProps =\n | {\n mode: \"single\";\n phase: UploadPhase;\n progress: UploadProgress;\n error: string | null;\n fileInfo: { name: string; size: number } | null;\n onCancel?: () => void;\n }\n | {\n mode: \"multi\";\n phase: MultiUploadPhase;\n files: MultiUploadFileState[];\n totalProgress: UploadProgress;\n error: string | null;\n onCancel?: () => void;\n };\n\nexport function UploadStatusBlock(props: UploadStatusBlockProps) {\n if (props.mode === \"multi\" && props.files.length === 1) {\n const f = props.files[0];\n return (\n <UploadStatus\n phase={props.phase}\n progress={f.progress}\n error={f.error ?? props.error}\n fileInfo={{ name: f.fileName, size: f.fileSize }}\n onCancel={props.onCancel}\n />\n );\n }\n\n if (props.mode === \"multi\") {\n return (\n <MultiUploadStatus\n phase={props.phase}\n files={props.files}\n totalProgress={props.totalProgress}\n error={props.error}\n onCancel={props.onCancel}\n />\n );\n }\n return (\n <UploadStatus\n phase={props.phase}\n progress={props.progress}\n error={props.error}\n fileInfo={props.fileInfo}\n onCancel={props.onCancel}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { formatFileSize } from \"@better-s3/core\";\nimport type { UploadProgress, MultiUploadFileState } from \"@better-s3/react\";\n\nexport type UploadToastCtrl = {\n mode: \"single\" | \"multi\";\n phase: string;\n fileInfo?: { name: string; size: number } | null;\n progress?: UploadProgress;\n files?: MultiUploadFileState[];\n totalProgress?: UploadProgress;\n error: string | null;\n cancel: () => void;\n};\n\n/**\n * Drives sonner toasts for upload progress/success/error.\n * Shared between UploadButton and UploadDropzone.\n */\nexport function useUploadToast(ctrl: UploadToastCtrl, enabled: boolean) {\n const toastIdRef = useRef<string | null>(null);\n const sizeNode = (size: number) => (\n <span dir=\"ltr\" className=\"inline-block whitespace-nowrap tabular-nums\">\n {formatFileSize(size)}\n </span>\n );\n const progressNode = (loaded: number, total: number) => (\n <span dir=\"ltr\" className=\"inline-block whitespace-nowrap tabular-nums\">\n {formatFileSize(loaded)} / {formatFileSize(total)}\n </span>\n );\n const files = ctrl.files ?? [];\n const isMulti = ctrl.mode === \"multi\" && files.length > 1;\n const file =\n ctrl.fileInfo ??\n (files.length === 1\n ? { name: files[0].fileName, size: files[0].fileSize }\n : null);\n const totalProgress = ctrl.totalProgress ?? {\n loaded: 0,\n total: 0,\n percent: 0,\n };\n const progress =\n ctrl.progress ??\n (files.length === 1\n ? files[0].progress\n : { loaded: 0, total: 0, percent: 0 });\n\n // Phase-transition toasts (runs synchronously during render to fire exactly once)\n const prevPhaseRef = useRef(ctrl.phase);\n if (prevPhaseRef.current !== ctrl.phase) {\n prevPhaseRef.current = ctrl.phase;\n if (enabled) {\n if (ctrl.phase === \"idle\" && toastIdRef.current) {\n toast.dismiss(toastIdRef.current);\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"success\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n if (isMulti) {\n toast.success(`${files.length} file(s) uploaded`, {\n description: sizeNode(totalProgress.total),\n });\n } else if (file) {\n toast.success(\"Upload complete\", {\n description: sizeNode(file.size),\n });\n }\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"error\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n if (isMulti && files.length > 0) {\n const succeeded = files.filter((f) => f.status === \"success\").length;\n const failed = files.filter((f) => f.status === \"error\").length;\n toast.error(\"Upload finished with errors\", {\n description: (\n <span\n dir=\"ltr\"\n className=\"inline-block whitespace-nowrap tabular-nums\"\n >\n {succeeded} succeeded, {failed} failed\n </span>\n ),\n });\n } else {\n toast.error(\"Upload failed\", {\n description: (\n <span dir=\"auto\" className=\"block [overflow-wrap:anywhere]\">\n {ctrl.error ?? files[0]?.error ?? \"Unknown error\"}\n </span>\n ),\n });\n }\n toastIdRef.current = null;\n }\n }\n }\n\n // Progress toast (updated on each progress tick)\n useEffect(() => {\n if (!enabled || ctrl.phase !== \"uploading\") return;\n const id = toastIdRef.current ?? `upload-${Date.now()}`;\n toastIdRef.current = id;\n if (isMulti) {\n const done = files.filter((f) => f.status === \"success\").length;\n toast.loading(`Uploading ${done}/${files.length}`, {\n id,\n description: progressNode(totalProgress.loaded, totalProgress.total),\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n } else if (file) {\n toast.loading(\"Uploading\", {\n id,\n description: progressNode(progress.loaded, file.size),\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n }\n }, [\n enabled,\n ctrl.phase,\n isMulti,\n progress.loaded,\n totalProgress.loaded,\n totalProgress.total,\n file,\n files,\n ctrl.cancel,\n ]);\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { CloudUpload } from \"lucide-react\";\nimport {\n useUploadControls,\n useMultiUploadControls,\n type UseUploadControlsOptions,\n type UseMultiUploadControlsOptions,\n type UploadProgress,\n type MultiUploadFileState,\n} from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { UploadStatusBlock } from \"@/components/upload/upload-status-block\";\nimport { useUploadToast, type UploadToastCtrl } from \"@/hooks/use-upload-toast\";\n\nconst EMPTY_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\nconst EMPTY_FILES: MultiUploadFileState[] = [];\n\n/** Props for {@link UploadButton}. Extends {@link UseUploadControlsOptions} or {@link UseMultiUploadControlsOptions}. */\nexport type UploadButtonProps = (\n | UseUploadControlsOptions\n | UseMultiUploadControlsOptions\n) & {\n className?: string;\n /** Button label. */\n label?: string;\n /** Custom button content. Replaces default icon + label. */\n children?: ReactNode;\n disabled?: boolean;\n tooltipText?: string;\n /** Show sonner toasts during upload. @default true */\n toast?: boolean;\n /** Show inline status below the button. @default true */\n showStatus?: boolean;\n};\n\nexport function UploadButton({\n className,\n label,\n children,\n disabled,\n tooltipText,\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadButtonProps) {\n const isMulti =\n ((options as UseMultiUploadControlsOptions).maxFiles ?? 1) > 1;\n\n // Both hooks must be called unconditionally (React rules of hooks).\n // Only the active mode's output is used.\n const single = useUploadControls(options as UseUploadControlsOptions);\n const multi = useMultiUploadControls(\n options as UseMultiUploadControlsOptions,\n );\n\n const ctrl: UploadToastCtrl = isMulti\n ? {\n mode: \"multi\",\n phase: multi.phase,\n files: multi.files,\n totalProgress: multi.totalProgress,\n error: multi.error,\n cancel: multi.cancel,\n }\n : {\n mode: \"single\",\n phase: single.phase,\n fileInfo: single.fileInfo,\n progress: single.progress,\n error: single.error,\n cancel: single.cancel,\n };\n\n const isDisabled =\n disabled || (isMulti ? multi.isUploading : single.isUploading);\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <UploadStatusBlock\n mode=\"multi\"\n phase={multi.phase}\n files={multi.files ?? EMPTY_FILES}\n totalProgress={multi.totalProgress ?? EMPTY_PROGRESS}\n error={multi.error}\n onCancel={multi.cancel}\n />\n ) : (\n <UploadStatusBlock\n mode=\"single\"\n phase={single.phase}\n progress={single.progress}\n error={single.error}\n fileInfo={single.fileInfo}\n onCancel={single.cancel}\n />\n )\n ) : null;\n\n const openFilePicker = isMulti ? multi.openFilePicker : single.openFilePicker;\n const inputProps = isMulti ? multi.inputProps : single.inputProps;\n\n const buttonLabel = label ?? (isMulti ? \"Upload files\" : \"Upload file\");\n const buttonContent = children ?? (\n <>\n <CloudUpload data-icon=\"inline-start\" />\n {buttonLabel}\n </>\n );\n\n const button = (\n <Button size=\"default\" disabled={isDisabled} onClick={openFilePicker}>\n {buttonContent}\n </Button>\n );\n\n return (\n <div className={cn(\"inline-flex flex-col gap-2\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <input {...inputProps} />\n {tooltipText ? (\n <Tooltip>\n <TooltipTrigger render={button} />\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n ) : (\n button\n )}\n </div>\n {status}\n </div>\n );\n}\n","\"use client\";\n\nimport { useState, type ReactNode } from \"react\";\nimport { CloudUpload } from \"lucide-react\";\nimport {\n useUploadControls,\n useMultiUploadControls,\n formatAcceptLabels,\n type UseUploadControlsOptions,\n type UseMultiUploadControlsOptions,\n type UploadProgress,\n type MultiUploadFileState,\n} from \"@better-s3/react\";\nimport { formatFileSize } from \"@better-s3/core\";\nimport { cn } from \"@/lib/utils\";\nimport { UploadStatusBlock } from \"@/components/upload/upload-status-block\";\nimport { useUploadToast, type UploadToastCtrl } from \"@/hooks/use-upload-toast\";\n\nfunction formatDropzoneLimits(options: {\n maxFiles?: number;\n maxFileSize?: number;\n}): string | null {\n const parts: string[] = [];\n\n if (options.maxFiles != null && options.maxFiles > 0) {\n parts.push(\n options.maxFiles === 1\n ? \"You can upload a file\"\n : `You can upload ${options.maxFiles} files`,\n );\n }\n\n if (options.maxFileSize != null) {\n const size = formatFileSize(options.maxFileSize);\n parts.push(\n options.maxFiles != null && options.maxFiles > 1\n ? `Each up to ${size}`\n : `Up to ${size}`,\n );\n }\n\n return parts.length > 0 ? `${parts.join(\". \")}.` : null;\n}\n\nfunction formatDropzoneAcceptLine(labels: string[]): string | null {\n return labels.length > 0 ? `Accepted ${labels.join(\", \")}.` : null;\n}\n\nconst EMPTY_PROGRESS: UploadProgress = { loaded: 0, total: 0, percent: 0 };\nconst EMPTY_FILES: MultiUploadFileState[] = [];\n\n/** Props for {@link UploadDropzone}. Extends {@link UseUploadControlsOptions} or {@link UseMultiUploadControlsOptions}. */\nexport type UploadDropzoneProps = (\n | UseUploadControlsOptions\n | UseMultiUploadControlsOptions\n) & {\n className?: string;\n /** Dropzone label. */\n label?: string;\n /** Custom dropzone content. Replaces built-in icon/text/status block. */\n children?: ReactNode;\n disabled?: boolean;\n /** Show sonner toasts during upload. @default true */\n toast?: boolean;\n /** Show inline status inside the dropzone. @default true */\n showStatus?: boolean;\n};\n\nexport function UploadDropzone({\n className,\n label,\n children,\n disabled,\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadDropzoneProps) {\n const isMulti =\n ((options as UseMultiUploadControlsOptions).maxFiles ?? 1) > 1;\n\n // Both hooks must be called unconditionally (React rules of hooks).\n const single = useUploadControls(options as UseUploadControlsOptions);\n const multi = useMultiUploadControls(\n options as UseMultiUploadControlsOptions,\n );\n\n const ctrl: UploadToastCtrl = isMulti\n ? {\n mode: \"multi\",\n phase: multi.phase,\n files: multi.files,\n totalProgress: multi.totalProgress,\n error: multi.error,\n cancel: multi.cancel,\n }\n : {\n mode: \"single\",\n phase: single.phase,\n fileInfo: single.fileInfo,\n progress: single.progress,\n error: single.error,\n cancel: single.cancel,\n };\n\n const [isDragOver, setIsDragOver] = useState(false);\n\n const isDisabled =\n disabled || (isMulti ? multi.isUploading : single.isUploading);\n const openFilePicker = isMulti ? multi.openFilePicker : single.openFilePicker;\n const dropHandlers = isMulti ? multi.dropHandlers : single.dropHandlers;\n const inputProps = isMulti ? multi.inputProps : single.inputProps;\n\n useUploadToast(ctrl, enableToast);\n\n const acceptLabels = formatAcceptLabels(options.accept);\n const limitsLine = formatDropzoneLimits({\n maxFileSize: options.maxFileSize,\n maxFiles: (options as UseMultiUploadControlsOptions).maxFiles,\n });\n const acceptLine = formatDropzoneAcceptLine(acceptLabels);\n const hasCustomContent = children != null;\n\n const status = showStatus ? (\n isMulti ? (\n <UploadStatusBlock\n mode=\"multi\"\n phase={multi.phase}\n files={multi.files ?? EMPTY_FILES}\n totalProgress={multi.totalProgress ?? EMPTY_PROGRESS}\n error={multi.error}\n onCancel={multi.cancel}\n />\n ) : (\n <UploadStatusBlock\n mode=\"single\"\n phase={single.phase}\n progress={single.progress}\n error={single.error}\n fileInfo={single.fileInfo}\n onCancel={single.cancel}\n />\n )\n ) : null;\n\n return (\n <div\n className={cn(\n \"rounded-lg border-2 border-dashed transition-colors\",\n hasCustomContent\n ? \"flex items-stretch justify-stretch p-0\"\n : \"flex flex-col items-center justify-center gap-3 p-6 text-center\",\n isDisabled\n ? \"cursor-not-allowed border-muted-foreground/25\"\n : \"cursor-pointer border-muted-foreground/25 hover:border-primary/50\",\n !isDisabled && isDragOver && \"border-primary/50\",\n className,\n )}\n onClick={isDisabled ? undefined : openFilePicker}\n {...(isDisabled\n ? {}\n : {\n ...dropHandlers,\n onDragEnter: (e) => {\n if (e.dataTransfer.types.includes(\"Files\")) setIsDragOver(true);\n },\n onDragLeave: (e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node)) {\n setIsDragOver(false);\n }\n },\n onDrop: (e) => {\n setIsDragOver(false);\n dropHandlers.onDrop(e);\n },\n })}\n >\n <input {...inputProps} />\n {hasCustomContent ? (\n children\n ) : (\n <>\n <CloudUpload\n className={cn(\"size-6\", isDisabled && \"opacity-50\")}\n strokeWidth={1.5}\n />\n <div\n className={cn(\"flex flex-col gap-1\", isDisabled && \"opacity-50\")}\n >\n <p className=\"text-sm font-medium\">\n {label ?? \"Drag and drop files here\"}\n </p>\n {limitsLine && (\n <p className=\"text-xs text-muted-foreground\">{limitsLine}</p>\n )}\n {acceptLine && (\n <p className=\"text-xs text-muted-foreground\">{acceptLine}</p>\n )}\n </div>\n {status && <div className=\"w-full text-start\">{status}</div>}\n </>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { toast } from \"sonner\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/core\";\n\nexport type DownloadToastOptions = {\n enabled?: boolean;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n};\n\nexport function useDownloadToast({\n enabled = true,\n objectKey,\n fileName,\n fileSize,\n}: DownloadToastOptions) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const errorNode = (error: unknown) => (\n <span dir=\"auto\" className=\"block [overflow-wrap:anywhere]\">\n {error instanceof Error ? error.message : \"Unknown error\"}\n </span>\n );\n\n const onInitiated = () => {\n if (enabled) toast.success(\"Download started\");\n };\n\n const onSuccess = (_key: string, actualFileName: string) => {\n if (!enabled) return;\n toast.dismiss(`dl-${objectKey}`);\n toast.success(\"Download complete\", {\n description: (\n <span className=\"block\">\n <bdi>{truncateFilename(actualFileName)}</bdi>\n {fileSize != null ? (\n <>\n {\" \"}\n ·{\" \"}\n <span\n dir=\"ltr\"\n className=\"inline-block whitespace-nowrap tabular-nums\"\n >\n {formatFileSize(fileSize)}\n </span>\n </>\n ) : null}\n </span>\n ),\n });\n };\n\n const onError = (_key: string, error: unknown) => {\n if (!enabled) return;\n toast.dismiss(`dl-${objectKey}`);\n toast.error(\"Download failed\", { description: errorNode(error) });\n };\n\n const onErrorWithPhase = (_key: string, error: unknown, _phase: string) => {\n if (!enabled) return;\n toast.dismiss(`dl-${objectKey}`);\n toast.error(\"Download failed\", { description: errorNode(error) });\n };\n\n const onCancel = (_key: string) => {\n if (!enabled) return;\n toast.dismiss(`dl-${objectKey}`);\n toast.info(\"Download cancelled\", {\n description: <span dir=\"auto\">{truncateFilename(displayName)}</span>,\n });\n };\n\n return { onInitiated, onSuccess, onError, onErrorWithPhase, onCancel };\n}\n","\"use client\";\n\nimport { AlertCircleIcon, DownloadIcon, LoaderIcon } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { useDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport { useDownloadToast } from \"@/hooks/use-download-toast\";\n\n/** Props for {@link DownloadButton}. */\nexport type DownloadButtonProps = {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** S3 object key to download. */\n objectKey: string;\n /** Download filename for Content-Disposition. */\n fileName?: string;\n /** Button label. @default \"Download\" */\n label?: string;\n className?: string;\n disabled?: boolean;\n /** Show a sonner toast when download starts. @default true */\n toast?: boolean;\n /** Show inline error below the button. @default true */\n showStatus?: boolean;\n};\n\nexport function DownloadButton({\n api,\n objectKey,\n fileName,\n label,\n className,\n disabled,\n toast: enableToast = true,\n showStatus = true,\n}: DownloadButtonProps) {\n const toastHandlers = useDownloadToast({\n enabled: enableToast,\n objectKey,\n fileName,\n });\n\n const dl = useDownload({\n api,\n onInitiated: () => {\n toastHandlers.onInitiated();\n },\n onError: (key, error) => {\n toastHandlers.onError(key, error);\n },\n });\n\n const isPending = dl.phase === \"presigning\";\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <Button\n size=\"default\"\n variant=\"outline\"\n disabled={disabled || isPending}\n onClick={() => dl.download(objectKey, fileName)}\n >\n <span className=\"inline-flex items-center gap-1\">\n {isPending ? (\n <LoaderIcon className=\"animate-spin\" data-icon=\"inline-start\" />\n ) : (\n <DownloadIcon data-icon=\"inline-start\" />\n )}\n {label ?? \"Download\"}\n </span>\n </Button>\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {dl.error ?? \"Download failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { DownloadIcon, AlertCircleIcon } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/core\";\nimport { formatSpeed, formatEta } from \"@better-s3/react\";\nimport type { FetchDownloadHooks } from \"@better-s3/react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { useFetchDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useDownloadToast } from \"@/hooks/use-download-toast\";\n\n/** Props for {@link ProgressDownloadButton}. */\nexport type ProgressDownloadButtonProps = FetchDownloadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** S3 object key to download. */\n objectKey: string;\n /** Download filename for Content-Disposition. */\n fileName?: string;\n /** Total file size in bytes (used for progress display). */\n fileSize?: number;\n /** Target bucket (overrides server default). */\n bucket?: string;\n /** Button label. @default \"Download\" */\n label?: string;\n className?: string;\n fillClassName?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Show sonner toasts during download. @default true */\n toast?: boolean;\n /** Show inline error below the button. @default true */\n showStatus?: boolean;\n};\n\nexport function ProgressDownloadButton({\n api,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n fillClassName,\n disabled,\n tooltipText = \"Download file\",\n toast: enableToast = true,\n showStatus = true,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess,\n onError,\n onCancel,\n}: ProgressDownloadButtonProps) {\n const toastHandlers = useDownloadToast({\n enabled: enableToast,\n objectKey,\n fileName,\n fileSize,\n });\n\n const dl = useFetchDownload({\n api,\n bucket,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess: (key, actualFileName) => {\n toastHandlers.onSuccess(key, actualFileName);\n onSuccess?.(key, actualFileName);\n },\n onError: (key, error, phase) => {\n toastHandlers.onErrorWithPhase(key, error, phase);\n onError?.(key, error, phase);\n },\n onCancel: (key) => {\n toastHandlers.onCancel(key);\n onCancel?.(key);\n },\n });\n\n const isDownloading = dl.phase === \"downloading\" || dl.phase === \"presigning\";\n\n const eta =\n dl.phase === \"downloading\" && dl.progress.speed && dl.progress.total\n ? formatEta(dl.progress.total - dl.progress.loaded, dl.progress.speed)\n : null;\n\n const handleClick = () => {\n if (isDownloading) {\n dl.cancel();\n return;\n }\n dl.download(objectKey, fileName);\n };\n\n const computedPercentFromFileSize =\n fileSize && fileSize > 0\n ? Math.min(100, Math.round((dl.progress.loaded / fileSize) * 100))\n : null;\n\n const fillPercent =\n dl.phase === \"presigning\"\n ? 12\n : dl.progress.total > 0\n ? dl.progress.percent\n : computedPercentFromFileSize;\n\n const isIndeterminateFill =\n isDownloading && fillPercent == null && dl.phase === \"downloading\";\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n size=\"default\"\n variant=\"outline\"\n disabled={disabled}\n className={cn(\"relative min-w-24 overflow-hidden\")}\n onClick={handleClick}\n />\n }\n >\n {isDownloading && (\n <span\n className={cn(\n \"absolute inset-y-0 start-0 bg-primary/15\",\n fillPercent != null\n ? \"transition-[width] duration-200\"\n : \"w-full animate-pulse\",\n fillClassName,\n )}\n style={\n fillPercent != null ? { width: `${fillPercent}%` } : undefined\n }\n aria-hidden={isIndeterminateFill}\n />\n )}\n <span className=\"relative z-10 inline-flex items-center gap-1\">\n <DownloadIcon data-icon=\"inline-start\" />\n {isDownloading\n ? formatFileSize(dl.progress.loaded)\n : (label ?? \"Download\")}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {isDownloading ? \"Cancel download\" : tooltipText}\n </TooltipContent>\n </Tooltip>\n\n {showStatus && dl.phase === \"downloading\" && dl.progress.loaded > 0 && (\n <p className=\"text-xs tabular-nums text-muted-foreground\">\n {formatFileSize(dl.progress.loaded)}\n {dl.progress.total > 0 && (\n <span className=\"text-muted-foreground/50\">\n {\" \"}\n / {formatFileSize(dl.progress.total)}\n </span>\n )}\n {dl.progress.speed ? (\n <span> · {formatSpeed(dl.progress.speed)}</span>\n ) : null}\n {eta ? (\n <span className=\"text-muted-foreground/50\"> · in {eta}</span>\n ) : null}\n </p>\n )}\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {dl.error ?? \"Download failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { AlertDialog as AlertDialogPrimitive } from \"@base-ui/react/alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\n\nfunction AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {\n return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />;\n}\n\nfunction AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {\n return (\n <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n );\n}\n\nfunction AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {\n return (\n <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n );\n}\n\nfunction AlertDialogOverlay({\n className,\n ...props\n}: AlertDialogPrimitive.Backdrop.Props) {\n return (\n <AlertDialogPrimitive.Backdrop\n data-slot=\"alert-dialog-overlay\"\n className={cn(\n \"fixed inset-0 isolate z-50 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogContent({\n className,\n size = \"default\",\n ...props\n}: AlertDialogPrimitive.Popup.Props & {\n size?: \"default\" | \"sm\";\n}) {\n return (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Popup\n data-slot=\"alert-dialog-content\"\n data-size={size}\n className={cn(\n \"group/alert-dialog-content fixed top-1/2 start-1/2 z-50 grid w-full -translate-x-1/2 rtl:translate-x-1/2 -translate-y-1/2 gap-3 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-64 data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n );\n}\n\nfunction AlertDialogHeader({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-header\"\n className={cn(\n \"grid grid-rows-[auto_1fr] place-items-center gap-1 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-start sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogFooter({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogMedia({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-media\"\n className={cn(\n \"mb-2 inline-flex size-8 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n return (\n <AlertDialogPrimitive.Title\n data-slot=\"alert-dialog-title\"\n className={cn(\n \"font-heading text-sm font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n return (\n <AlertDialogPrimitive.Description\n data-slot=\"alert-dialog-description\"\n className={cn(\n \"text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogAction({\n className,\n ...props\n}: React.ComponentProps<typeof Button>) {\n return (\n <Button\n data-slot=\"alert-dialog-action\"\n className={cn(className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogCancel({\n className,\n variant = \"outline\",\n size = \"default\",\n ...props\n}: AlertDialogPrimitive.Close.Props &\n Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n return (\n <AlertDialogPrimitive.Close\n data-slot=\"alert-dialog-cancel\"\n className={cn(className)}\n render={<Button variant={variant} size={size} />}\n {...props}\n />\n );\n}\n\nexport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogTitle,\n AlertDialogTrigger,\n};\n","\"use client\";\n\nimport { toast } from \"sonner\";\nimport { truncateFilename } from \"@better-s3/core\";\n\nexport type DeleteToastOptions = {\n enabled?: boolean;\n displayName: string;\n};\n\nexport function useDeleteToast({\n enabled = true,\n displayName,\n}: DeleteToastOptions) {\n const onSuccess = (_key: string) => {\n if (!enabled) return;\n toast.success(\"File deleted\", {\n description: <span dir=\"auto\">{truncateFilename(displayName)}</span>,\n });\n };\n\n const onError = (_key: string, error: unknown) => {\n if (!enabled) return;\n toast.error(\"Delete failed\", {\n description: (\n <span dir=\"auto\" className=\"block [overflow-wrap:anywhere]\">\n {error instanceof Error ? error.message : \"Unknown error\"}\n </span>\n ),\n });\n };\n\n return { onSuccess, onError };\n}\n","\"use client\";\n\nimport {\n Trash2Icon,\n LoaderIcon,\n AlertCircleIcon,\n CheckCircle2Icon,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/core\";\nimport type { DeleteHooks } from \"@better-s3/react\";\nimport type { S3Api } from \"@better-s3/core\";\nimport { useDelete } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@/components/ui/alert-dialog\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useDeleteToast } from \"@/hooks/use-delete-toast\";\n\n/** Props for {@link DeleteButton}. */\nexport type DeleteButtonProps = DeleteHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n /** S3 object key to delete. */\n objectKey: string;\n /** Display file name in the confirmation dialog. */\n fileName?: string;\n /** Display file size in the confirmation dialog. */\n fileSize?: number;\n /** Target bucket (overrides server default). */\n bucket?: string;\n /** Button label. */\n label?: string;\n className?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Show a sonner toast during delete. @default true */\n toast?: boolean;\n /** Show inline error below the button. @default true */\n showStatus?: boolean;\n confirmTitle?: string;\n confirmDescription?: string;\n};\n\nexport function DeleteButton({\n api,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n disabled,\n tooltipText = \"Delete file\",\n toast: enableToast = true,\n showStatus = true,\n confirmTitle = \"Delete file?\",\n confirmDescription,\n beforeDelete,\n onDeleteStart,\n onSuccess,\n onError,\n}: DeleteButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n const toastHandlers = useDeleteToast({\n enabled: enableToast,\n displayName,\n });\n\n const del = useDelete({\n api,\n bucket,\n beforeDelete,\n onDeleteStart,\n onSuccess: (key) => {\n toastHandlers.onSuccess(key);\n onSuccess?.(key);\n },\n onError: (key, error, phase) => {\n toastHandlers.onError(key, error);\n onError?.(key, error, phase);\n },\n });\n\n const isDeleting = del.phase === \"deleting\";\n const isDisabled = disabled || isDeleting;\n\n const description = confirmDescription ?? (\n <>\n {\"Are you sure you want to delete \"}\n <span className=\"font-medium inline-block align-bottom\">\n &ldquo;{truncateFilename(displayName)}&rdquo;\n </span>\n {fileSize != null ? ` (${formatFileSize(fileSize)})` : \"\"}\n {\"? This action cannot be undone.\"}\n </>\n );\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <AlertDialog\n open={del.phase === \"confirming\"}\n onOpenChange={(open) => {\n if (!open) del.cancelDelete();\n }}\n >\n <Tooltip>\n <TooltipTrigger\n render={\n <AlertDialogTrigger\n disabled={isDisabled}\n onClick={() => del.requestDelete(objectKey)}\n render={\n <Button\n size=\"default\"\n variant=\"destructive\"\n disabled={isDisabled}\n />\n }\n />\n }\n >\n {isDeleting ? (\n <LoaderIcon className=\"animate-spin\" data-icon=\"inline-start\" />\n ) : (\n <Trash2Icon data-icon=\"inline-start\" />\n )}\n {label ?? \"Delete\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogMedia>\n <Trash2Icon />\n </AlertDialogMedia>\n <AlertDialogTitle>{confirmTitle}</AlertDialogTitle>\n <AlertDialogDescription className=\"[overflow-wrap:anywhere]\">\n {description}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => del.confirmDelete()}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n\n {showStatus && del.phase === \"success\" && (\n <div className=\"flex min-w-0 items-center gap-1.5 text-xs\">\n <CheckCircle2Icon className=\"size-3.5 shrink-0 text-green-600\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-green-600\">\n &ldquo;{truncateFilename(displayName)}&rdquo; deleted\n </p>\n </div>\n )}\n\n {showStatus && del.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {del.error ?? \"Delete failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-s3/ui",
3
- "version": "3.1050.0",
3
+ "version": "3.1051.0",
4
4
  "description": "Pre-built React UI components for S3 file upload, download, and delete",
5
5
  "keywords": [
6
6
  "s3",
@@ -36,8 +36,8 @@
36
36
  "styles.css"
37
37
  ],
38
38
  "dependencies": {
39
- "@better-s3/core": "3.1050.0",
40
- "@better-s3/react": "3.1050.0"
39
+ "@better-s3/react": "3.1051.0",
40
+ "@better-s3/core": "3.1051.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@base-ui/react": ">=1.0.0",
@@ -50,11 +50,11 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@base-ui/react": "^1.5.0",
53
- "@types/node": "^25.9.2",
53
+ "@types/node": "^25.9.3",
54
54
  "@types/react": "^19.2.17",
55
55
  "class-variance-authority": "^0.7.1",
56
56
  "clsx": "^2.1.1",
57
- "lucide-react": "^1.17.0",
57
+ "lucide-react": "^1.18.0",
58
58
  "react": "^19.2.7",
59
59
  "sonner": "^2.0.7",
60
60
  "tailwind-merge": "^3.6.0",