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