@better-s3/ui 3.1045.2 → 3.1046.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,6 +1,7 @@
1
1
  import type { S3Api, DeleteHooks } from "@better-s3/react";
2
2
  type DeleteButtonProps = DeleteHooks & {
3
- api: S3Api;
3
+ /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */
4
+ api?: S3Api;
4
5
  objectKey: string;
5
6
  fileName?: string;
6
7
  fileSize?: number;
@@ -1,6 +1,7 @@
1
1
  import type { S3Api } from "@better-s3/react";
2
2
  type DownloadButtonProps = {
3
- api: S3Api;
3
+ /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */
4
+ api?: S3Api;
4
5
  objectKey: string;
5
6
  fileName?: string;
6
7
  label?: string;
@@ -1,6 +1,7 @@
1
1
  import type { S3Api, FetchDownloadHooks } from "@better-s3/react";
2
2
  type ProgressDownloadButtonProps = FetchDownloadHooks & {
3
- api: S3Api;
3
+ /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */
4
+ api?: S3Api;
4
5
  objectKey: string;
5
6
  fileName?: string;
6
7
  fileSize?: number;
@@ -1,5 +1,5 @@
1
- import type { UseUploadControlsOptions } from "@better-s3/react";
2
- export type UploadButtonProps = UseUploadControlsOptions & {
1
+ import { type UseUploadControlsOptions, type UseMultiUploadControlsOptions } from "@better-s3/react";
2
+ export type UploadButtonProps = (UseUploadControlsOptions | UseMultiUploadControlsOptions) & {
3
3
  className?: string;
4
4
  label?: string;
5
5
  disabled?: boolean;
@@ -1,5 +1,5 @@
1
- import type { UseUploadControlsOptions } from "@better-s3/react";
2
- export type UploadDropzoneProps = UseUploadControlsOptions & {
1
+ import { type UseUploadControlsOptions, type UseMultiUploadControlsOptions } from "@better-s3/react";
2
+ export type UploadDropzoneProps = (UseUploadControlsOptions | UseMultiUploadControlsOptions) & {
3
3
  className?: string;
4
4
  label?: string;
5
5
  disabled?: boolean;
@@ -0,0 +1,20 @@
1
+ import type { UploadPhase, UploadProgress, MultiUploadFileState, MultiUploadPhase } from "@better-s3/react";
2
+ export type UploadStatusBlockProps = {
3
+ mode: "single";
4
+ phase: UploadPhase;
5
+ progress: UploadProgress;
6
+ error: string | null;
7
+ fileInfo: {
8
+ name: string;
9
+ size: number;
10
+ } | null;
11
+ onCancel?: () => void;
12
+ } | {
13
+ mode: "multi";
14
+ phase: MultiUploadPhase;
15
+ files: MultiUploadFileState[];
16
+ totalProgress: UploadProgress;
17
+ error: string | null;
18
+ onCancel?: () => void;
19
+ };
20
+ export declare function UploadStatusBlock(props: UploadStatusBlockProps): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,19 @@
1
- import type { UseUploadControlsReturn } from "@better-s3/react";
1
+ import type { UploadProgress, MultiUploadFileState } from "@better-s3/react";
2
+ export type UploadToastCtrl = {
3
+ mode: "single" | "multi";
4
+ phase: string;
5
+ fileInfo?: {
6
+ name: string;
7
+ size: number;
8
+ } | null;
9
+ progress?: UploadProgress;
10
+ files?: MultiUploadFileState[];
11
+ totalProgress?: UploadProgress;
12
+ error: string | null;
13
+ cancel: () => void;
14
+ };
2
15
  /**
3
16
  * Drives sonner toasts for upload progress/success/error.
4
17
  * Shared between UploadButton and UploadDropzone.
5
18
  */
6
- export declare function useUploadToast(ctrl: Pick<UseUploadControlsReturn, "mode" | "phase" | "fileInfo" | "progress" | "files" | "totalProgress" | "error" | "cancel">, enabled: boolean): void;
19
+ export declare function useUploadToast(ctrl: UploadToastCtrl, enabled: boolean): void;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { XIcon, CheckCircleIcon, AlertCircleIcon, UploadIcon, LoaderIcon, DownloadIcon, Trash2Icon, CheckCircle2Icon } from 'lucide-react';
2
- import { formatFileSize, useUploadControls, useDownload, useFetchDownload, useDelete } from '@better-s3/react';
2
+ import { formatEta, formatFileSize, formatSpeed, truncateFilename, useUploadControls, useMultiUploadControls, useDownload, useFetchDownload, 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';
@@ -159,23 +159,24 @@ function UploadStatus({
159
159
  }) {
160
160
  if (phase === "idle") return null;
161
161
  if (phase === "uploading" && fileInfo) {
162
- return /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-1.5 text-xs", children: [
162
+ const eta = progress.speed && progress.total ? formatEta(progress.total - progress.loaded, progress.speed) : null;
163
+ const meta = [
164
+ `${formatFileSize(progress.loaded)} / ${formatFileSize(fileInfo.size)}`,
165
+ progress.speed ? formatSpeed(progress.speed) : null,
166
+ eta ? `${eta} left` : null
167
+ ].filter(Boolean).join(" \xB7 ");
168
+ const compactMeta = `${Math.round(progress.percent)}%`;
169
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-2 text-xs", children: [
163
170
  /* @__PURE__ */ jsx(CircleProgress, { percent: progress.percent, size: 14, strokeWidth: 2 }),
164
- /* @__PURE__ */ jsx("span", { className: "max-w-32 min-w-16 truncate sm:max-w-48", children: fileInfo.name }),
165
- /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
166
- formatFileSize(progress.loaded),
167
- " / ",
168
- formatFileSize(fileInfo.size),
169
- " (",
170
- progress.percent,
171
- "%)"
172
- ] }),
171
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate max-w-[30ch]", children: truncateFilename(fileInfo.name) }),
172
+ /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 whitespace-nowrap tabular-nums text-muted-foreground sm:hidden", children: compactMeta }),
173
+ /* @__PURE__ */ jsx("span", { className: "ml-auto hidden shrink-0 whitespace-nowrap tabular-nums text-muted-foreground sm:inline", children: meta }),
173
174
  /* @__PURE__ */ jsx(
174
175
  Button,
175
176
  {
176
177
  variant: "ghost",
177
178
  size: "icon",
178
- className: "ml-auto size-6 shrink-0",
179
+ className: "size-6 shrink-0",
179
180
  onClick: (e) => {
180
181
  e.stopPropagation();
181
182
  onCancel?.();
@@ -186,10 +187,10 @@ function UploadStatus({
186
187
  ] });
187
188
  }
188
189
  if (phase === "success" && fileInfo) {
189
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
190
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-1.5 text-xs", children: [
190
191
  /* @__PURE__ */ jsx(CheckCircleIcon, { className: "size-3.5 shrink-0 text-green-600" }),
191
- /* @__PURE__ */ jsx("span", { className: "[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48", children: fileInfo.name }),
192
- /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: formatFileSize(fileInfo.size) })
192
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate max-w-[30ch]", children: truncateFilename(fileInfo.name) }),
193
+ /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 text-muted-foreground", children: formatFileSize(fileInfo.size) })
193
194
  ] });
194
195
  }
195
196
  if (phase === "error") {
@@ -343,7 +344,7 @@ function FileList({ files }) {
343
344
  strokeWidth: 2
344
345
  }
345
346
  ),
346
- /* @__PURE__ */ jsx("span", { className: "[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48", children: f.fileName }),
347
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 shrink", children: truncateFilename(f.fileName) }),
347
348
  f.status === "uploading" ? /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
348
349
  formatFileSize(f.progress.loaded),
349
350
  " /",
@@ -357,9 +358,40 @@ function FileList({ files }) {
357
358
  f.status === "error" && f.error && /* @__PURE__ */ jsx("span", { className: "truncate [overflow-wrap:anywhere] pl-5 text-destructive", children: f.error })
358
359
  ] }, f.id)) });
359
360
  }
361
+ function UploadStatusBlock(props) {
362
+ if (props.mode === "multi") {
363
+ return /* @__PURE__ */ jsx(
364
+ MultiUploadStatus,
365
+ {
366
+ phase: props.phase,
367
+ files: props.files,
368
+ totalProgress: props.totalProgress,
369
+ error: props.error,
370
+ onCancel: props.onCancel
371
+ }
372
+ );
373
+ }
374
+ return /* @__PURE__ */ jsx(
375
+ UploadStatus,
376
+ {
377
+ phase: props.phase,
378
+ progress: props.progress,
379
+ error: props.error,
380
+ fileInfo: props.fileInfo,
381
+ onCancel: props.onCancel
382
+ }
383
+ );
384
+ }
360
385
  function useUploadToast(ctrl, enabled) {
361
386
  const toastIdRef = useRef(null);
362
387
  const isMulti = ctrl.mode === "multi";
388
+ const files = ctrl.files ?? [];
389
+ const totalProgress = ctrl.totalProgress ?? {
390
+ loaded: 0,
391
+ total: 0,
392
+ percent: 0
393
+ };
394
+ const progress = ctrl.progress ?? { loaded: 0, percent: 0 };
363
395
  const prevPhaseRef = useRef(ctrl.phase);
364
396
  if (prevPhaseRef.current !== ctrl.phase) {
365
397
  prevPhaseRef.current = ctrl.phase;
@@ -371,8 +403,8 @@ function useUploadToast(ctrl, enabled) {
371
403
  if (ctrl.phase === "success") {
372
404
  if (toastIdRef.current) toast.dismiss(toastIdRef.current);
373
405
  if (isMulti) {
374
- toast.success(`${ctrl.files.length} file(s) uploaded`, {
375
- description: formatFileSize(ctrl.totalProgress.total)
406
+ toast.success(`${files.length} file(s) uploaded`, {
407
+ description: formatFileSize(totalProgress.total)
376
408
  });
377
409
  } else if (ctrl.fileInfo) {
378
410
  toast.success("Upload complete", {
@@ -383,11 +415,9 @@ function useUploadToast(ctrl, enabled) {
383
415
  }
384
416
  if (ctrl.phase === "error") {
385
417
  if (toastIdRef.current) toast.dismiss(toastIdRef.current);
386
- if (isMulti && ctrl.files.length > 0) {
387
- const succeeded = ctrl.files.filter(
388
- (f) => f.status === "success"
389
- ).length;
390
- const failed = ctrl.files.filter((f) => f.status === "error").length;
418
+ if (isMulti && files.length > 0) {
419
+ const succeeded = files.filter((f) => f.status === "success").length;
420
+ const failed = files.filter((f) => f.status === "error").length;
391
421
  toast.error("Upload finished with errors", {
392
422
  description: `${succeeded} succeeded, ${failed} failed`
393
423
  });
@@ -405,16 +435,16 @@ function useUploadToast(ctrl, enabled) {
405
435
  const id = toastIdRef.current ?? `upload-${Date.now()}`;
406
436
  toastIdRef.current = id;
407
437
  if (isMulti) {
408
- const done = ctrl.files.filter((f) => f.status === "success").length;
409
- toast.loading(`Uploading... ${done}/${ctrl.files.length}`, {
438
+ const done = files.filter((f) => f.status === "success").length;
439
+ toast.loading(`Uploading... ${done}/${files.length}`, {
410
440
  id,
411
- description: `${formatFileSize(ctrl.totalProgress.loaded)} / ${formatFileSize(ctrl.totalProgress.total)} (${ctrl.totalProgress.percent}%)`,
441
+ description: `${formatFileSize(totalProgress.loaded)} / ${formatFileSize(totalProgress.total)} (${totalProgress.percent}%)`,
412
442
  cancel: { label: "Cancel", onClick: () => ctrl.cancel() }
413
443
  });
414
444
  } else if (ctrl.fileInfo) {
415
445
  toast.loading("Uploading...", {
416
446
  id,
417
- description: `${formatFileSize(ctrl.progress.loaded)} / ${formatFileSize(ctrl.fileInfo.size)} (${ctrl.progress.percent}%)`,
447
+ description: `${formatFileSize(progress.loaded)} / ${formatFileSize(ctrl.fileInfo.size)} (${progress.percent}%)`,
418
448
  cancel: { label: "Cancel", onClick: () => ctrl.cancel() }
419
449
  });
420
450
  }
@@ -422,16 +452,18 @@ function useUploadToast(ctrl, enabled) {
422
452
  enabled,
423
453
  ctrl.phase,
424
454
  isMulti,
425
- ctrl.progress.loaded,
426
- ctrl.progress.percent,
427
- ctrl.totalProgress.loaded,
428
- ctrl.totalProgress.total,
429
- ctrl.totalProgress.percent,
455
+ progress.loaded,
456
+ progress.percent,
457
+ totalProgress.loaded,
458
+ totalProgress.total,
459
+ totalProgress.percent,
430
460
  ctrl.fileInfo,
431
- ctrl.files,
461
+ files,
432
462
  ctrl.cancel
433
463
  ]);
434
464
  }
465
+ var EMPTY_PROGRESS = { loaded: 0, total: 0, percent: 0 };
466
+ var EMPTY_FILES = [];
435
467
  function UploadButton({
436
468
  className,
437
469
  label,
@@ -441,56 +473,69 @@ function UploadButton({
441
473
  showStatus = true,
442
474
  ...options
443
475
  }) {
444
- const ctrl = useUploadControls(options);
445
- const isMulti = ctrl.mode === "multi";
446
- const isDisabled = disabled || ctrl.isUploading;
476
+ const isMulti = (options.maxFiles ?? 1) > 1;
477
+ const single = useUploadControls(options);
478
+ const multi = useMultiUploadControls(
479
+ options
480
+ );
481
+ const ctrl = isMulti ? {
482
+ mode: "multi",
483
+ phase: multi.phase,
484
+ files: multi.files,
485
+ totalProgress: multi.totalProgress,
486
+ error: multi.error,
487
+ cancel: multi.cancel
488
+ } : {
489
+ mode: "single",
490
+ phase: single.phase,
491
+ fileInfo: single.fileInfo,
492
+ progress: single.progress,
493
+ error: single.error,
494
+ cancel: single.cancel
495
+ };
496
+ const isDisabled = disabled || (isMulti ? multi.isUploading : single.isUploading);
447
497
  useUploadToast(ctrl, enableToast);
448
498
  const status = showStatus ? isMulti ? /* @__PURE__ */ jsx(
449
- MultiUploadStatus,
499
+ UploadStatusBlock,
450
500
  {
451
- phase: ctrl.phase,
452
- files: ctrl.files,
453
- totalProgress: ctrl.totalProgress,
454
- error: ctrl.error,
455
- onCancel: ctrl.cancel
501
+ mode: "multi",
502
+ phase: multi.phase,
503
+ files: multi.files ?? EMPTY_FILES,
504
+ totalProgress: multi.totalProgress ?? EMPTY_PROGRESS,
505
+ error: multi.error,
506
+ onCancel: multi.cancel
456
507
  }
457
508
  ) : /* @__PURE__ */ jsx(
458
- UploadStatus,
509
+ UploadStatusBlock,
459
510
  {
460
- phase: ctrl.phase,
461
- progress: ctrl.progress,
462
- error: ctrl.error,
463
- fileInfo: ctrl.fileInfo,
464
- onCancel: ctrl.cancel
511
+ mode: "single",
512
+ phase: single.phase,
513
+ progress: single.progress,
514
+ error: single.error,
515
+ fileInfo: single.fileInfo,
516
+ onCancel: single.cancel
465
517
  }
466
518
  ) : null;
519
+ const openFilePicker = isMulti ? multi.openFilePicker : single.openFilePicker;
520
+ const inputProps = isMulti ? multi.inputProps : single.inputProps;
521
+ const buttonLabel = label ?? (isMulti ? "Upload files" : "Upload file");
522
+ const button = /* @__PURE__ */ jsxs(Button, { size: "default", disabled: isDisabled, onClick: openFilePicker, children: [
523
+ /* @__PURE__ */ jsx(UploadIcon, { "data-icon": "inline-start" }),
524
+ buttonLabel
525
+ ] });
467
526
  return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col gap-2", className), children: [
468
527
  /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-2", children: [
469
- /* @__PURE__ */ jsx("input", { ...ctrl.inputProps }),
470
- /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
471
- /* @__PURE__ */ jsxs(
472
- TooltipTrigger,
473
- {
474
- render: /* @__PURE__ */ jsx(
475
- Button,
476
- {
477
- size: "default",
478
- disabled: isDisabled,
479
- onClick: ctrl.openFilePicker
480
- }
481
- ),
482
- children: [
483
- /* @__PURE__ */ jsx(UploadIcon, { "data-icon": "inline-start" }),
484
- label ?? (isMulti ? "Upload files" : "Upload file")
485
- ]
486
- }
487
- ),
488
- /* @__PURE__ */ jsx(TooltipContent, { children: tooltipText ?? (isMulti ? "Upload files" : "Upload file") })
489
- ] }) })
528
+ /* @__PURE__ */ jsx("input", { ...inputProps }),
529
+ tooltipText ? /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
530
+ /* @__PURE__ */ jsx(TooltipTrigger, { render: button }),
531
+ /* @__PURE__ */ jsx(TooltipContent, { children: tooltipText })
532
+ ] }) }) : button
490
533
  ] }),
491
534
  status
492
535
  ] });
493
536
  }
537
+ var EMPTY_PROGRESS2 = { loaded: 0, total: 0, percent: 0 };
538
+ var EMPTY_FILES2 = [];
494
539
  function UploadDropzone({
495
540
  className,
496
541
  label,
@@ -499,27 +544,50 @@ function UploadDropzone({
499
544
  showStatus = true,
500
545
  ...options
501
546
  }) {
502
- const ctrl = useUploadControls(options);
503
- const isMulti = ctrl.mode === "multi";
504
- const isDisabled = disabled || ctrl.isUploading;
547
+ const isMulti = (options.maxFiles ?? 1) > 1;
548
+ const single = useUploadControls(options);
549
+ const multi = useMultiUploadControls(
550
+ options
551
+ );
552
+ const ctrl = isMulti ? {
553
+ mode: "multi",
554
+ phase: multi.phase,
555
+ files: multi.files,
556
+ totalProgress: multi.totalProgress,
557
+ error: multi.error,
558
+ cancel: multi.cancel
559
+ } : {
560
+ mode: "single",
561
+ phase: single.phase,
562
+ fileInfo: single.fileInfo,
563
+ progress: single.progress,
564
+ error: single.error,
565
+ cancel: single.cancel
566
+ };
567
+ const isDisabled = disabled || (isMulti ? multi.isUploading : single.isUploading);
568
+ const openFilePicker = isMulti ? multi.openFilePicker : single.openFilePicker;
569
+ const dropHandlers = isMulti ? multi.dropHandlers : single.dropHandlers;
570
+ const inputProps = isMulti ? multi.inputProps : single.inputProps;
505
571
  useUploadToast(ctrl, enableToast);
506
572
  const status = showStatus ? isMulti ? /* @__PURE__ */ jsx(
507
- MultiUploadStatus,
573
+ UploadStatusBlock,
508
574
  {
509
- phase: ctrl.phase,
510
- files: ctrl.files,
511
- totalProgress: ctrl.totalProgress,
512
- error: ctrl.error,
513
- onCancel: ctrl.cancel
575
+ mode: "multi",
576
+ phase: multi.phase,
577
+ files: multi.files ?? EMPTY_FILES2,
578
+ totalProgress: multi.totalProgress ?? EMPTY_PROGRESS2,
579
+ error: multi.error,
580
+ onCancel: multi.cancel
514
581
  }
515
582
  ) : /* @__PURE__ */ jsx(
516
- UploadStatus,
583
+ UploadStatusBlock,
517
584
  {
518
- phase: ctrl.phase,
519
- progress: ctrl.progress,
520
- error: ctrl.error,
521
- fileInfo: ctrl.fileInfo,
522
- onCancel: ctrl.cancel
585
+ mode: "single",
586
+ phase: single.phase,
587
+ progress: single.progress,
588
+ error: single.error,
589
+ fileInfo: single.fileInfo,
590
+ onCancel: single.cancel
523
591
  }
524
592
  ) : null;
525
593
  return /* @__PURE__ */ jsxs(
@@ -530,10 +598,10 @@ function UploadDropzone({
530
598
  isDisabled ? "cursor-not-allowed border-muted-foreground/25" : "cursor-pointer border-muted-foreground/25 hover:border-primary/50",
531
599
  className
532
600
  ),
533
- onClick: isDisabled ? void 0 : ctrl.openFilePicker,
534
- ...isDisabled ? {} : ctrl.dropHandlers,
601
+ onClick: isDisabled ? void 0 : openFilePicker,
602
+ ...isDisabled ? {} : dropHandlers,
535
603
  children: [
536
- /* @__PURE__ */ jsx("input", { ...ctrl.inputProps }),
604
+ /* @__PURE__ */ jsx("input", { ...inputProps }),
537
605
  /* @__PURE__ */ jsx(
538
606
  UploadIcon,
539
607
  {
@@ -573,8 +641,8 @@ function useDownloadToast({
573
641
  if (!enabled) return;
574
642
  toast.dismiss(`dl-${objectKey}`);
575
643
  toast.success("Download complete", {
576
- description: /* @__PURE__ */ jsxs("span", { className: "block max-w-[50ch] truncate", children: [
577
- actualFileName,
644
+ description: /* @__PURE__ */ jsxs("span", { className: "block", children: [
645
+ truncateFilename(actualFileName),
578
646
  fileSize != null ? ` \xB7 ${formatFileSize(fileSize)}` : ""
579
647
  ] })
580
648
  });
@@ -593,7 +661,7 @@ function useDownloadToast({
593
661
  if (!enabled) return;
594
662
  toast.dismiss(`dl-${objectKey}`);
595
663
  toast.info("Download cancelled", {
596
- description: /* @__PURE__ */ jsx("span", { className: "block max-w-[50ch] truncate", children: displayName })
664
+ description: /* @__PURE__ */ jsx("span", { children: truncateFilename(displayName) })
597
665
  });
598
666
  };
599
667
  return { onInitiated, onSuccess, onError, onErrorWithPhase, onCancel };
@@ -689,6 +757,7 @@ function ProgressDownloadButton({
689
757
  }
690
758
  });
691
759
  const isDownloading = dl.phase === "downloading" || dl.phase === "presigning";
760
+ const eta = dl.phase === "downloading" && dl.progress.speed && dl.progress.total ? formatEta(dl.progress.total - dl.progress.loaded, dl.progress.speed) : null;
692
761
  const handleClick = () => {
693
762
  if (isDownloading) {
694
763
  dl.cancel();
@@ -731,6 +800,22 @@ function ProgressDownloadButton({
731
800
  ),
732
801
  /* @__PURE__ */ jsx(TooltipContent, { children: isDownloading ? "Cancel download" : tooltipText })
733
802
  ] }) }),
803
+ showStatus && dl.phase === "downloading" && dl.progress.loaded > 0 && /* @__PURE__ */ jsxs("p", { className: "text-xs tabular-nums text-muted-foreground", children: [
804
+ formatFileSize(dl.progress.loaded),
805
+ dl.progress.total > 0 && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground/50", children: [
806
+ " ",
807
+ "/ ",
808
+ formatFileSize(dl.progress.total)
809
+ ] }),
810
+ dl.progress.speed ? /* @__PURE__ */ jsxs("span", { children: [
811
+ " \xB7 ",
812
+ formatSpeed(dl.progress.speed)
813
+ ] }) : null,
814
+ eta ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground/50", children: [
815
+ " \xB7 in ",
816
+ eta
817
+ ] }) : null
818
+ ] }),
734
819
  showStatus && dl.phase === "error" && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-1.5 text-xs", children: [
735
820
  /* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0 text-destructive" }),
736
821
  /* @__PURE__ */ jsx("p", { className: "min-w-0 [overflow-wrap:anywhere] text-destructive", children: dl.error ?? "Download failed" })
@@ -899,7 +984,7 @@ function useDeleteToast({
899
984
  const onSuccess = (_key) => {
900
985
  if (!enabled) return;
901
986
  toast.success("File deleted", {
902
- description: /* @__PURE__ */ jsx("span", { className: "block max-w-[50ch] truncate", children: displayName })
987
+ description: /* @__PURE__ */ jsx("span", { children: truncateFilename(displayName) })
903
988
  });
904
989
  };
905
990
  const onError = (_key, error) => {
@@ -952,9 +1037,9 @@ function DeleteButton({
952
1037
  const isDisabled = disabled || isDeleting;
953
1038
  const description = confirmDescription ?? /* @__PURE__ */ jsxs(Fragment, { children: [
954
1039
  "Are you sure you want to delete ",
955
- /* @__PURE__ */ jsxs("span", { className: "inline-block max-w-[30ch] truncate align-bottom", children: [
1040
+ /* @__PURE__ */ jsxs("span", { className: "font-medium inline-block align-bottom", children: [
956
1041
  "\u201C",
957
- displayName,
1042
+ truncateFilename(displayName),
958
1043
  "\u201D"
959
1044
  ] }),
960
1045
  fileSize != null ? ` (${formatFileSize(fileSize)})` : "",
@@ -1027,7 +1112,7 @@ function DeleteButton({
1027
1112
  /* @__PURE__ */ jsx(CheckCircle2Icon, { className: "size-3.5 shrink-0 text-green-600" }),
1028
1113
  /* @__PURE__ */ jsxs("p", { className: "min-w-0 [overflow-wrap:anywhere] text-green-600", children: [
1029
1114
  "\u201C",
1030
- /* @__PURE__ */ jsx("span", { className: "inline-block max-w-[30ch] truncate align-bottom", children: displayName }),
1115
+ truncateFilename(displayName),
1031
1116
  "\u201D deleted"
1032
1117
  ] })
1033
1118
  ] }),
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/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","XIcon","CheckCircleIcon","AlertCircleIcon","formatFileSize","useUploadControls","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","\"use client\";\n\nimport { 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 cursor-pointer 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 } 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 return (\n <div className=\"flex w-full items-center gap-1.5 text-xs\">\n <CircleProgress percent={progress.percent} size={14} strokeWidth={2} />\n <span className=\"max-w-32 min-w-16 truncate sm:max-w-48\">\n {fileInfo.name}\n </span>\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(progress.loaded)} / {formatFileSize(fileInfo.size)} (\n {progress.percent}%)\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"ml-auto size-6 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\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 items-center gap-1.5 text-xs\">\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n <span className=\"[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48\">\n {fileInfo.name}\n </span>\n <span className=\"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 } 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 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 </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 <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=\"[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48\">\n {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 { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { UseUploadControlsReturn } from \"@better-s3/react\";\n\n/**\n * Drives sonner toasts for upload progress/success/error.\n * Shared between UploadButton and UploadDropzone.\n */\nexport function useUploadToast(\n ctrl: Pick<\n UseUploadControlsReturn,\n | \"mode\"\n | \"phase\"\n | \"fileInfo\"\n | \"progress\"\n | \"files\"\n | \"totalProgress\"\n | \"error\"\n | \"cancel\"\n >,\n enabled: boolean,\n) {\n const toastIdRef = useRef<string | null>(null);\n const isMulti = ctrl.mode === \"multi\";\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(`${ctrl.files.length} file(s) uploaded`, {\n description: formatFileSize(ctrl.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 && ctrl.files.length > 0) {\n const succeeded = ctrl.files.filter(\n (f) => f.status === \"success\",\n ).length;\n const failed = ctrl.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 = ctrl.files.filter((f) => f.status === \"success\").length;\n toast.loading(`Uploading... ${done}/${ctrl.files.length}`, {\n id,\n description: `${formatFileSize(ctrl.totalProgress.loaded)} / ${formatFileSize(ctrl.totalProgress.total)} (${ctrl.totalProgress.percent}%)`,\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n } else if (ctrl.fileInfo) {\n toast.loading(\"Uploading...\", {\n id,\n description: `${formatFileSize(ctrl.progress.loaded)} / ${formatFileSize(ctrl.fileInfo.size)} (${ctrl.progress.percent}%)`,\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n }\n }, [\n enabled,\n ctrl.phase,\n isMulti,\n ctrl.progress.loaded,\n ctrl.progress.percent,\n ctrl.totalProgress.loaded,\n ctrl.totalProgress.total,\n ctrl.totalProgress.percent,\n ctrl.fileInfo,\n ctrl.files,\n ctrl.cancel,\n ]);\n}\n","\"use client\";\n\nimport { UploadIcon } from \"lucide-react\";\nimport type { UseUploadControlsOptions } from \"@better-s3/react\";\nimport { useUploadControls } from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { UploadStatus } from \"@/components/upload/upload-status\";\nimport { MultiUploadStatus } from \"@/components/upload/multi-upload-status\";\nimport { useUploadToast } from \"@/hooks/use-upload-toast\";\n\nexport type UploadButtonProps = UseUploadControlsOptions & {\n className?: string;\n label?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (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 ctrl = useUploadControls(options);\n const isMulti = ctrl.mode === \"multi\";\n const isDisabled = disabled || ctrl.isUploading;\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <MultiUploadStatus\n phase={ctrl.phase}\n files={ctrl.files}\n totalProgress={ctrl.totalProgress}\n error={ctrl.error}\n onCancel={ctrl.cancel}\n />\n ) : (\n <UploadStatus\n phase={ctrl.phase}\n progress={ctrl.progress}\n error={ctrl.error}\n fileInfo={ctrl.fileInfo}\n onCancel={ctrl.cancel}\n />\n )\n ) : null;\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 {...ctrl.inputProps} />\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n size=\"default\"\n disabled={isDisabled}\n onClick={ctrl.openFilePicker}\n />\n }>\n <UploadIcon data-icon=\"inline-start\" />\n {label ?? (isMulti ? \"Upload files\" : \"Upload file\")}\n </TooltipTrigger>\n <TooltipContent>\n {tooltipText ?? (isMulti ? \"Upload files\" : \"Upload file\")}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n {status}\n </div>\n );\n}\n","\"use client\";\n\nimport { UploadIcon } from \"lucide-react\";\nimport type { UseUploadControlsOptions } from \"@better-s3/react\";\nimport { useUploadControls } from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { UploadStatus } from \"@/components/upload/upload-status\";\nimport { MultiUploadStatus } from \"@/components/upload/multi-upload-status\";\nimport { useUploadToast } from \"@/hooks/use-upload-toast\";\n\nexport type UploadDropzoneProps = UseUploadControlsOptions & {\n className?: string;\n label?: string;\n disabled?: boolean;\n /** Enable sonner toasts (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 ctrl = useUploadControls(options);\n const isMulti = ctrl.mode === \"multi\";\n const isDisabled = disabled || ctrl.isUploading;\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <MultiUploadStatus\n phase={ctrl.phase}\n files={ctrl.files}\n totalProgress={ctrl.totalProgress}\n error={ctrl.error}\n onCancel={ctrl.cancel}\n />\n ) : (\n <UploadStatus\n phase={ctrl.phase}\n progress={ctrl.progress}\n error={ctrl.error}\n fileInfo={ctrl.fileInfo}\n onCancel={ctrl.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 : ctrl.openFilePicker}\n {...(isDisabled ? {} : ctrl.dropHandlers)}>\n <input {...ctrl.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 {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 } from \"@better-s3/react\";\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 max-w-[50ch] truncate\">\n {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: (\n <span className=\"block max-w-[50ch] truncate\">{displayName}</span>\n ),\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/react\";\nimport { useDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport { useDownloadToast } from \"@/hooks/use-download-toast\";\n\ntype DownloadButtonProps = {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n label?: string;\n className?: string;\n disabled?: boolean;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status 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 <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/react\";\nimport type { S3Api, FetchDownloadHooks } from \"@better-s3/react\";\nimport { useFetchDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useDownloadToast } from \"@/hooks/use-download-toast\";\n\ntype ProgressDownloadButtonProps = FetchDownloadHooks & {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n /** Target bucket (overrides server default) */\n bucket?: string;\n label?: string;\n className?: string;\n fillClassName?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status 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 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 <TooltipProvider>\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 {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 </TooltipProvider>\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\";\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: (\n <span className=\"block max-w-[50ch] truncate\">{displayName}</span>\n ),\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 } from \"@better-s3/react\";\nimport type { S3Api, DeleteHooks } from \"@better-s3/react\";\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 TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useDeleteToast } from \"@/hooks/use-delete-toast\";\n\ntype DeleteButtonProps = DeleteHooks & {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n /** Target bucket (overrides server default) */\n bucket?: string;\n label?: string;\n className?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status 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=\"inline-block max-w-[30ch] truncate align-bottom\">\n &ldquo;{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 <TooltipProvider>\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 {isDeleting ? (\n <LoaderIcon\n className=\"animate-spin\"\n data-icon=\"inline-start\"\n />\n ) : (\n <Trash2Icon data-icon=\"inline-start\" />\n )}\n {label ?? \"Delete\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\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 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;\n <span className=\"inline-block max-w-[30ch] truncate align-bottom\">\n {displayName}\n </span>\n &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","XIcon","CheckCircleIcon","AlertCircleIcon","truncateFilename","formatFileSize","EMPTY_PROGRESS","EMPTY_FILES","useUploadControls","useMultiUploadControls","UploadIcon","toast","formatEta","DownloadIcon","formatSpeed","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 cursor-pointer 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 {\n formatFileSize,\n formatSpeed,\n formatEta,\n truncateFilename,\n} 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 meta = [\n `${formatFileSize(progress.loaded)} / ${formatFileSize(fileInfo.size)}`,\n progress.speed ? formatSpeed(progress.speed) : null,\n eta ? `${eta} left` : null,\n ]\n .filter(Boolean)\n .join(\" · \");\n\n const compactMeta = `${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 sm:hidden\">\n {compactMeta}\n </span>\n <span className=\"ml-auto hidden shrink-0 whitespace-nowrap tabular-nums text-muted-foreground sm:inline\">\n {meta}\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 <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/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 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 </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 <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/react\";\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 { useRef, useState } from \"react\";\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 TooltipProvider,\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\nexport type UploadButtonProps = (\n | UseUploadControlsOptions\n | UseMultiUploadControlsOptions\n) & {\n className?: string;\n label?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (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 <TooltipProvider>\n <Tooltip>\n <TooltipTrigger render={button} />\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\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\nexport type UploadDropzoneProps = (\n | UseUploadControlsOptions\n | UseMultiUploadControlsOptions\n) & {\n className?: string;\n label?: string;\n disabled?: boolean;\n /** Enable sonner toasts (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 <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 {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\n\n","\"use client\";\n\nimport { toast } from \"sonner\";\nimport { formatFileSize, truncateFilename } from \"@better-s3/react\";\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/react\";\nimport { useDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport { useDownloadToast } from \"@/hooks/use-download-toast\";\n\ntype DownloadButtonProps = {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n objectKey: string;\n fileName?: string;\n label?: string;\n className?: string;\n disabled?: boolean;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status 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 <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, formatSpeed, formatEta } from \"@better-s3/react\";\nimport type { S3Api, FetchDownloadHooks } from \"@better-s3/react\";\nimport { useFetchDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useDownloadToast } from \"@/hooks/use-download-toast\";\n\ntype ProgressDownloadButtonProps = FetchDownloadHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n /** Target bucket (overrides server default) */\n bucket?: string;\n label?: string;\n className?: string;\n fillClassName?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status 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 <TooltipProvider>\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 {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 </TooltipProvider>\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/react\";\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/react\";\nimport type { S3Api, DeleteHooks } from \"@better-s3/react\";\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 TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { useDeleteToast } from \"@/hooks/use-delete-toast\";\n\ntype DeleteButtonProps = DeleteHooks & {\n /** S3Api client. Optional when an `<S3Provider>` is present in the tree. */\n api?: S3Api;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n /** Target bucket (overrides server default) */\n bucket?: string;\n label?: string;\n className?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status 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 <TooltipProvider>\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 {isDeleting ? (\n <LoaderIcon\n className=\"animate-spin\"\n data-icon=\"inline-start\"\n />\n ) : (\n <Trash2Icon data-icon=\"inline-start\" />\n )}\n {label ?? \"Delete\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\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 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.1045.2",
3
+ "version": "3.1046.0",
4
4
  "description": "Pre-built React UI components for S3 file upload, download, and delete",
5
5
  "keywords": [
6
6
  "s3",
@@ -36,7 +36,7 @@
36
36
  "styles.css"
37
37
  ],
38
38
  "dependencies": {
39
- "@better-s3/react": "3.1045.2"
39
+ "@better-s3/react": "3.1046.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@base-ui/react": ">=1.0.0",
@@ -56,7 +56,7 @@
56
56
  "lucide-react": "^1.14.0",
57
57
  "react": "^19.2.6",
58
58
  "sonner": "^2.0.7",
59
- "tailwind-merge": "^3.5.0",
59
+ "tailwind-merge": "^3.6.0",
60
60
  "tsc-alias": "^1.8.17",
61
61
  "tsup": "^8.5.1",
62
62
  "typescript": "^6.0.3"