@better-s3/ui 3.1045.0 → 3.1045.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -7
- package/dist/index.js +1041 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/delete/delete-button.d.ts +0 -21
- package/dist/download/download-button.d.ts +0 -15
- package/dist/download/progress-download-button.d.ts +0 -20
- package/dist/lib/utils.d.ts +0 -2
- package/dist/ui/alert-dialog.d.ts +0 -18
- package/dist/ui/button.d.ts +0 -8
- package/dist/ui/circle-progress.d.ts +0 -5
- package/dist/ui/progress.d.ts +0 -7
- package/dist/ui/tooltip.d.ts +0 -6
- package/dist/upload/multi-upload-status.d.ts +0 -8
- package/dist/upload/upload-button.d.ts +0 -12
- package/dist/upload/upload-dropzone.d.ts +0 -11
- package/dist/upload/upload-status.d.ts +0 -11
- package/dist/upload/use-upload-toast.d.ts +0 -6
package/dist/index.js
CHANGED
|
@@ -1,2 +1,1042 @@
|
|
|
1
|
-
import {XIcon,CheckCircleIcon,AlertCircleIcon,UploadIcon,LoaderIcon,DownloadIcon,Trash2Icon,CheckCircle2Icon}from'lucide-react';import {formatFileSize,useUploadControls,useDownload,useFetchDownload,useDelete}from'@better-s3/react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {Button}from'@base-ui/react/button';import {cva}from'class-variance-authority';import {jsxs,jsx}from'react/jsx-runtime';import {Tooltip}from'@base-ui/react/tooltip';import {Progress}from'@base-ui/react/progress';import {useRef,useEffect}from'react';import {toast}from'sonner';import {AlertDialog}from'@base-ui/react/alert-dialog';function a(...e){return twMerge(clsx(e))}var Ue=cva("group/button cursor-pointer inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/80",outline:"border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",ghost:"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",destructive:"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",link:"text-primary underline-offset-4 hover:underline"},size:{default:"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",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",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",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",icon:"size-7 [&_svg:not([class*='size-'])]:size-3.5","icon-xs":"size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5","icon-sm":"size-6 [&_svg:not([class*='size-'])]:size-3","icon-lg":"size-8 [&_svg:not([class*='size-'])]:size-4"}},defaultVariants:{variant:"default",size:"default"}});function c({className:e,variant:t="default",size:o="default",...r}){return jsx(Button,{"data-slot":"button",className:a(Ue({variant:t,size:o,className:e})),...r})}function B({delay:e=0,...t}){return jsx(Tooltip.Provider,{"data-slot":"tooltip-provider",delay:e,...t})}function S({...e}){return jsx(Tooltip.Root,{"data-slot":"tooltip",...e})}function I({...e}){return jsx(Tooltip.Trigger,{"data-slot":"tooltip-trigger",...e})}function $({className:e,side:t="top",sideOffset:o=4,align:r="center",alignOffset:l=0,children:n,...i}){return jsx(Tooltip.Portal,{children:jsx(Tooltip.Positioner,{align:r,alignOffset:l,side:t,sideOffset:o,className:"isolate z-50",children:jsxs(Tooltip.Popup,{"data-slot":"tooltip-content",className:a("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",e),...i,children:[n,jsx(Tooltip.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"})]})})})}function W({percent:e,size:t=20,strokeWidth:o=2.5}){let r=(t-o)/2,l=2*Math.PI*r,n=l-e/100*l;return jsxs("svg",{width:t,height:t,className:"shrink-0 -rotate-90",children:[jsx("circle",{cx:t/2,cy:t/2,r,fill:"none",stroke:"currentColor",strokeWidth:o,className:"text-muted-foreground/20"}),jsx("circle",{cx:t/2,cy:t/2,r,fill:"none",stroke:"currentColor",strokeWidth:o,strokeDasharray:l,strokeDashoffset:n,strokeLinecap:"round",className:"text-primary transition-[stroke-dashoffset] duration-200"})]})}function O({phase:e,progress:t,error:o,fileInfo:r,onCancel:l}){return e==="idle"?null:e==="uploading"&&r?jsxs("div",{className:"flex w-full items-center gap-1.5 text-xs",children:[jsx(W,{percent:t.percent,size:14,strokeWidth:2}),jsx("span",{className:"max-w-32 min-w-16 truncate sm:max-w-48",children:r.name}),jsxs("span",{className:"shrink-0 text-muted-foreground",children:[formatFileSize(t.loaded)," / ",formatFileSize(r.size)," (",t.percent,"%)"]}),jsx(c,{variant:"ghost",size:"icon",className:"ml-auto size-6 shrink-0",onClick:n=>{n.stopPropagation(),l?.();},children:jsx(XIcon,{className:"size-3.5"})})]}):e==="success"&&r?jsxs("div",{className:"flex items-center gap-1.5 text-xs",children:[jsx(CheckCircleIcon,{className:"size-3.5 shrink-0 text-green-600"}),jsx("span",{className:"[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48",children:r.name}),jsx("span",{className:"shrink-0 text-muted-foreground",children:formatFileSize(r.size)})]}):e==="error"?jsxs("div",{className:"flex min-w-0 items-start gap-1.5 text-xs",children:[jsx(AlertCircleIcon,{className:"mt-0.5 size-3.5 shrink-0 text-destructive"}),jsx("p",{className:"min-w-0 [overflow-wrap:anywhere] text-destructive",children:o??"Upload failed"})]}):e==="validating"||e==="presigning"?jsx("span",{className:"text-xs text-muted-foreground",children:"Preparing\u2026"}):null}function ne({className:e,children:t,value:o,...r}){return jsxs(Progress.Root,{value:o,"data-slot":"progress",className:a("flex flex-wrap gap-3",e),...r,children:[t,jsx(Me,{children:jsx(Fe,{})})]})}function Me({className:e,...t}){return jsx(Progress.Track,{className:a("relative flex h-1 w-full items-center overflow-x-hidden rounded-md bg-muted",e),"data-slot":"progress-track",...t})}function Fe({className:e,...t}){return jsx(Progress.Indicator,{"data-slot":"progress-indicator",className:a("h-full bg-primary transition-all",e),...t})}function le({className:e,...t}){return jsx(Progress.Label,{className:a("text-xs/relaxed font-medium",e),"data-slot":"progress-label",...t})}function de({className:e,...t}){return jsx(Progress.Value,{className:a("ms-auto text-xs/relaxed text-muted-foreground tabular-nums",e),"data-slot":"progress-value",...t})}function H({phase:e,files:t,totalProgress:o,error:r,onCancel:l}){return e==="idle"?null:e==="uploading"?jsxs("div",{className:"flex w-full flex-col gap-2",children:[jsxs("div",{className:"flex w-full items-center gap-1.5",children:[jsxs(ne,{value:o.percent,className:"flex-1",children:[jsxs(le,{children:[t.filter(n=>n.status==="success").length,"/",t.length," files"]}),jsx(de,{})]}),jsx(c,{variant:"ghost",size:"icon",className:"size-7 shrink-0",onClick:n=>{n.stopPropagation(),l?.();},children:jsx(XIcon,{className:"size-4"})})]}),jsx(ae,{files:t})]}):e==="success"?jsxs("div",{className:"flex w-full flex-col gap-1",children:[jsxs("span",{className:"text-xs text-green-600",children:["All ",t.length," file(s) uploaded"]}),jsx(ae,{files:t})]}):e==="error"?jsxs("div",{className:"flex w-full flex-col gap-1",children:[jsx("span",{className:"text-xs text-destructive",children:r??"Upload failed"}),t.length>0&&jsx(ae,{files:t})]}):e==="validating"?jsx("span",{className:"text-xs text-muted-foreground",children:"Validating\u2026"}):null}function ae({files:e}){return jsx("ul",{className:"flex flex-col gap-1",children:e.map(t=>jsxs("li",{className:"flex flex-col gap-0.5 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[t.status==="success"&&jsx(CheckCircleIcon,{className:"size-3.5 shrink-0 text-green-600"}),t.status==="error"&&jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),(t.status==="pending"||t.status==="uploading")&&jsx(W,{percent:t.status==="uploading"?t.progress.percent:0,size:14,strokeWidth:2}),jsx("span",{className:"[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48",children:t.fileName}),t.status==="uploading"?jsxs("span",{className:"shrink-0 text-muted-foreground",children:[formatFileSize(t.progress.loaded)," /"," ",formatFileSize(t.fileSize)," (",t.progress.percent,"%)"]}):jsx("span",{className:"shrink-0 text-muted-foreground",children:formatFileSize(t.fileSize)})]}),t.status==="error"&&t.error&&jsx("span",{className:"truncate [overflow-wrap:anywhere] pl-5 text-destructive",children:t.error})]},t.id))})}var Ee=(e,t=100)=>e.length>t?e.slice(0,t)+"\u2026":e;function G(e,t){let o=useRef(null),r=e.mode==="multi",l=useRef(e.phase);if(l.current!==e.phase&&(l.current=e.phase,t&&(e.phase==="idle"&&o.current&&(toast.dismiss(o.current),o.current=null),e.phase==="success"&&(o.current&&toast.dismiss(o.current),r?toast.success(`${e.files.length} file(s) uploaded`,{description:formatFileSize(e.totalProgress.total)}):e.fileInfo&&toast.success("Upload complete",{description:formatFileSize(e.fileInfo.size)}),o.current=null),e.phase==="error"))){if(o.current&&toast.dismiss(o.current),r&&e.files.length>0){let n=e.files.filter(s=>s.status==="success").length,i=e.files.filter(s=>s.status==="error").length;toast.error("Upload finished with errors",{description:`${n} succeeded, ${i} failed`});}else toast.error("Upload failed",{description:Ee(e.error??"Unknown error")});o.current=null;}useEffect(()=>{if(!t||e.phase!=="uploading")return;let n=o.current??`upload-${Date.now()}`;if(o.current=n,r){let i=e.files.filter(s=>s.status==="success").length;toast.loading(`Uploading\u2026 ${i}/${e.files.length}`,{id:n,description:`${formatFileSize(e.totalProgress.loaded)} / ${formatFileSize(e.totalProgress.total)} (${e.totalProgress.percent}%)`,cancel:{label:"Cancel",onClick:()=>e.cancel()}});}else e.fileInfo&&toast.loading("Uploading\u2026",{id:n,description:`${formatFileSize(e.progress.loaded)} / ${formatFileSize(e.fileInfo.size)} (${e.progress.percent}%)`,cancel:{label:"Cancel",onClick:()=>e.cancel()}});},[t,e.phase,r,e.progress.loaded,e.progress.percent,e.totalProgress.loaded,e.totalProgress.total,e.totalProgress.percent,e.fileInfo,e.files,e.cancel]);}function Xe({className:e,label:t,disabled:o,tooltipText:r,toast:l=true,showStatus:n=true,...i}){let s=useUploadControls(i),d=s.mode==="multi",g=o||s.isUploading;G(s,l);let D=n?d?jsx(H,{phase:s.phase,files:s.files,totalProgress:s.totalProgress,error:s.error,onCancel:s.cancel}):jsx(O,{phase:s.phase,progress:s.progress,error:s.error,fileInfo:s.fileInfo,onCancel:s.cancel}):null;return jsxs("div",{className:a("inline-flex flex-col gap-2",e),children:[jsxs("div",{className:"inline-flex items-center gap-2",children:[jsx("input",{...s.inputProps}),jsx(B,{children:jsxs(S,{children:[jsxs(I,{render:jsx(c,{size:"default",disabled:g,onClick:s.openFilePicker}),children:[jsx(UploadIcon,{"data-icon":"inline-start"}),t??(d?"Upload files":"Upload file")]}),jsx($,{children:r??(d?"Upload files":"Upload file")})]})})]}),D]})}function Qe({className:e,label:t,disabled:o,toast:r=true,showStatus:l=true,...n}){let i=useUploadControls(n),s=i.mode==="multi",d=o||i.isUploading;G(i,r);let g=l?s?jsx(H,{phase:i.phase,files:i.files,totalProgress:i.totalProgress,error:i.error,onCancel:i.cancel}):jsx(O,{phase:i.phase,progress:i.progress,error:i.error,fileInfo:i.fileInfo,onCancel:i.cancel}):null;return jsxs("div",{className:a("flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed p-6 text-center transition-colors",d?"cursor-not-allowed border-muted-foreground/25":"cursor-pointer border-muted-foreground/25 hover:border-primary/50",e),onClick:d?void 0:i.openFilePicker,...d?{}:i.dropHandlers,children:[jsx("input",{...i.inputProps}),jsx(UploadIcon,{className:a("size-6 text-muted-foreground",d&&"opacity-50")}),jsx("p",{className:a("text-sm text-muted-foreground",d&&"opacity-50"),children:t??(s?"Click or drag & drop files to upload":"Click or drag & drop to upload")}),g&&jsx("div",{className:"w-full text-left",children:g})]})}var tt=(e,t=100)=>e.length>t?e.slice(0,t)+"\u2026":e;function ot({api:e,objectKey:t,fileName:o,label:r,className:l,disabled:n,toast:i=true,showStatus:s=true}){let d=useDownload({api:e,onInitiated:()=>{i&&toast.success("Download started");},onError:(D,U)=>{i&&toast.error("Download failed",{description:tt(U instanceof Error?U.message:"Unknown error")});}}),g=d.phase==="presigning";return jsxs("div",{className:a("inline-flex flex-col gap-1.5",l),children:[jsx(c,{size:"default",variant:"outline",disabled:n||g,onClick:()=>d.download(t,o),children:jsxs("span",{className:"inline-flex items-center gap-1",children:[g?jsx(LoaderIcon,{className:"animate-spin","data-icon":"inline-start"}):jsx(DownloadIcon,{"data-icon":"inline-start"}),r??"Download"]})}),s&&d.phase==="error"&&jsxs("div",{className:"flex min-w-0 items-start gap-1.5 text-xs",children:[jsx(AlertCircleIcon,{className:"mt-0.5 size-3.5 shrink-0 text-destructive"}),jsx("p",{className:"min-w-0 [overflow-wrap:anywhere] text-destructive",children:d.error??"Download failed"})]})]})}var st=(e,t=100)=>e.length>t?e.slice(0,t)+"\u2026":e;function nt({api:e,objectKey:t,fileName:o,fileSize:r,bucket:l,label:n,className:i,fillClassName:s,disabled:d,tooltipText:g="Download file",toast:D=true,showStatus:U=true,beforeDownload:Q,onDownloadStart:Y,onProgress:Z,onSuccess:K,onError:j,onCancel:V}){let x=o??t.split("/").pop()??t,f=useFetchDownload({api:e,bucket:l,beforeDownload:Q,onDownloadStart:Y,onProgress:Z,onSuccess:(v,P)=>{D&&(toast.dismiss(`dl-${t}`),toast.success("Download complete",{description:`${P}${r!=null?` \xB7 ${formatFileSize(r)}`:""}`})),K?.(v,P);},onError:(v,P,te)=>{D&&(toast.dismiss(`dl-${t}`),toast.error("Download failed",{description:st(P instanceof Error?P.message:"Unknown error")})),j?.(v,P,te);},onCancel:v=>{D&&(toast.dismiss(`dl-${t}`),toast.info("Download cancelled",{description:x})),V?.(v);}}),k=f.phase==="downloading"||f.phase==="presigning",ee=()=>{if(k){f.cancel();return}f.download(t,o);};return jsxs("div",{className:a("inline-flex flex-col gap-1.5",i),children:[jsx(B,{children:jsxs(S,{children:[jsxs(I,{render:jsx(c,{size:"default",variant:"outline",disabled:d,className:a("relative min-w-24 overflow-hidden"),onClick:ee}),children:[k&&jsx("span",{className:a("absolute inset-0 bg-primary/15 transition-[width] duration-200",s),style:{width:`${f.progress.percent}%`}}),jsxs("span",{className:"relative z-10 inline-flex items-center gap-1",children:[jsx(DownloadIcon,{"data-icon":"inline-start"}),k?formatFileSize(f.progress.loaded):n??"Download"]})]}),jsx($,{children:k?"Cancel download":g})]})}),U&&f.phase==="error"&&jsxs("div",{className:"flex min-w-0 items-start gap-1.5 text-xs",children:[jsx(AlertCircleIcon,{className:"mt-0.5 size-3.5 shrink-0 text-destructive"}),jsx("p",{className:"min-w-0 [overflow-wrap:anywhere] text-destructive",children:f.error??"Download failed"})]})]})}function me({...e}){return jsx(AlertDialog.Root,{"data-slot":"alert-dialog",...e})}function ge({...e}){return jsx(AlertDialog.Trigger,{"data-slot":"alert-dialog-trigger",...e})}function lt({...e}){return jsx(AlertDialog.Portal,{"data-slot":"alert-dialog-portal",...e})}function dt({className:e,...t}){return jsx(AlertDialog.Backdrop,{"data-slot":"alert-dialog-overlay",className:a("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",e),...t})}function fe({className:e,size:t="default",...o}){return jsxs(lt,{children:[jsx(dt,{}),jsx(AlertDialog.Popup,{"data-slot":"alert-dialog-content","data-size":t,className:a("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",e),...o})]})}function ve({className:e,...t}){return jsx("div",{"data-slot":"alert-dialog-header",className:a("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]",e),...t})}function xe({className:e,...t}){return jsx("div",{"data-slot":"alert-dialog-footer",className:a("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",e),...t})}function Pe({className:e,...t}){return jsx("div",{"data-slot":"alert-dialog-media",className:a("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",e),...t})}function he({className:e,...t}){return jsx(AlertDialog.Title,{"data-slot":"alert-dialog-title",className:a("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",e),...t})}function be({className:e,...t}){return jsx(AlertDialog.Description,{"data-slot":"alert-dialog-description",className:a("text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",e),...t})}function we({className:e,...t}){return jsx(c,{"data-slot":"alert-dialog-action",className:a(e),...t})}function De({className:e,variant:t="outline",size:o="default",...r}){return jsx(AlertDialog.Close,{"data-slot":"alert-dialog-cancel",className:a(e),render:jsx(c,{variant:t,size:o}),...r})}var vt=(e,t=100)=>e.length>t?e.slice(0,t)+"\u2026":e;function xt({api:e,objectKey:t,fileName:o,fileSize:r,bucket:l,label:n,className:i,disabled:s,tooltipText:d="Delete file",toast:g=true,showStatus:D=true,confirmTitle:U="Delete file?",confirmDescription:Q,beforeDelete:Y,onDeleteStart:Z,onSuccess:K,onError:j}){let V=o??t.split("/").pop()??t,x=useDelete({api:e,bucket:l,beforeDelete:Y,onDeleteStart:Z,onSuccess:v=>{g&&toast.success("File deleted",{description:V}),K?.(v);},onError:(v,P,te)=>{g&&toast.error("Delete failed",{description:vt(P instanceof Error?P.message:"Unknown error")}),j?.(v,P,te);}}),f=x.phase==="deleting",k=s||f,ee=Q??`Are you sure you want to delete "${V}"${r!=null?` (${formatFileSize(r)})`:""}? This action cannot be undone.`;return jsxs("div",{className:a("inline-flex flex-col gap-1.5",i),children:[jsx("div",{className:"inline-flex items-center gap-2",children:jsxs(me,{open:x.phase==="confirming",onOpenChange:v=>{v||x.cancelDelete();},children:[jsx(B,{children:jsxs(S,{children:[jsxs(I,{render:jsx(ge,{disabled:k,onClick:()=>x.requestDelete(t),render:jsx(c,{size:"default",variant:"destructive",disabled:k})}),children:[f?jsx(LoaderIcon,{className:"animate-spin","data-icon":"inline-start"}):jsx(Trash2Icon,{"data-icon":"inline-start"}),n??"Delete"]}),jsx($,{children:d})]})}),jsxs(fe,{children:[jsxs(ve,{children:[jsx(Pe,{children:jsx(Trash2Icon,{})}),jsx(he,{children:U}),jsx(be,{className:"[overflow-wrap:anywhere]",children:ee})]}),jsxs(xe,{children:[jsx(De,{children:"Cancel"}),jsx(we,{variant:"destructive",onClick:()=>x.confirmDelete(),children:"Delete"})]})]})]})}),D&&x.phase==="success"&&jsxs("div",{className:"flex min-w-0 items-center gap-1.5 text-xs",children:[jsx(CheckCircle2Icon,{className:"size-3.5 shrink-0 text-green-600"}),jsxs("p",{className:"min-w-0 [overflow-wrap:anywhere] text-green-600",children:["\u201C",jsx("span",{className:"inline-block max-w-[14ch] truncate align-bottom",children:V}),"\u201D deleted"]})]}),D&&x.phase==="error"&&jsxs("div",{className:"flex min-w-0 items-start gap-1.5 text-xs",children:[jsx(AlertCircleIcon,{className:"mt-0.5 size-3.5 shrink-0 text-destructive"}),jsx("p",{className:"min-w-0 [overflow-wrap:anywhere] text-destructive",children:x.error??"Delete failed"})]})]})}export{xt as DeleteButton,ot as DownloadButton,H as MultiUploadStatus,nt as ProgressDownloadButton,Xe as UploadButton,Qe as UploadDropzone,O as UploadStatus};//# sourceMappingURL=index.js.map
|
|
1
|
+
import { XIcon, CheckCircleIcon, AlertCircleIcon, UploadIcon, LoaderIcon, DownloadIcon, Trash2Icon, CheckCircle2Icon } from 'lucide-react';
|
|
2
|
+
import { formatFileSize, useUploadControls, useDownload, useFetchDownload, useDelete } from '@better-s3/react';
|
|
3
|
+
import { clsx } from 'clsx';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
|
+
import { Button as Button$1 } from '@base-ui/react/button';
|
|
6
|
+
import { cva } from 'class-variance-authority';
|
|
7
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
+
import { Tooltip as Tooltip$1 } from '@base-ui/react/tooltip';
|
|
9
|
+
import { Progress as Progress$1 } from '@base-ui/react/progress';
|
|
10
|
+
import { useRef, useEffect } from 'react';
|
|
11
|
+
import { toast } from 'sonner';
|
|
12
|
+
import { AlertDialog as AlertDialog$1 } from '@base-ui/react/alert-dialog';
|
|
13
|
+
|
|
14
|
+
function cn(...inputs) {
|
|
15
|
+
return twMerge(clsx(inputs));
|
|
16
|
+
}
|
|
17
|
+
var buttonVariants = cva(
|
|
18
|
+
"group/button cursor-pointer inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
19
|
+
{
|
|
20
|
+
variants: {
|
|
21
|
+
variant: {
|
|
22
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
|
23
|
+
outline: "border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30",
|
|
24
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
25
|
+
ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
26
|
+
destructive: "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",
|
|
27
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
28
|
+
},
|
|
29
|
+
size: {
|
|
30
|
+
default: "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",
|
|
31
|
+
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",
|
|
32
|
+
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",
|
|
33
|
+
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",
|
|
34
|
+
icon: "size-7 [&_svg:not([class*='size-'])]:size-3.5",
|
|
35
|
+
"icon-xs": "size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5",
|
|
36
|
+
"icon-sm": "size-6 [&_svg:not([class*='size-'])]:size-3",
|
|
37
|
+
"icon-lg": "size-8 [&_svg:not([class*='size-'])]:size-4"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
defaultVariants: {
|
|
41
|
+
variant: "default",
|
|
42
|
+
size: "default"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
function Button({
|
|
47
|
+
className,
|
|
48
|
+
variant = "default",
|
|
49
|
+
size = "default",
|
|
50
|
+
...props
|
|
51
|
+
}) {
|
|
52
|
+
return /* @__PURE__ */ jsx(
|
|
53
|
+
Button$1,
|
|
54
|
+
{
|
|
55
|
+
"data-slot": "button",
|
|
56
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
57
|
+
...props
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
function TooltipProvider({
|
|
62
|
+
delay = 0,
|
|
63
|
+
...props
|
|
64
|
+
}) {
|
|
65
|
+
return /* @__PURE__ */ jsx(
|
|
66
|
+
Tooltip$1.Provider,
|
|
67
|
+
{
|
|
68
|
+
"data-slot": "tooltip-provider",
|
|
69
|
+
delay,
|
|
70
|
+
...props
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
function Tooltip({ ...props }) {
|
|
75
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Root, { "data-slot": "tooltip", ...props });
|
|
76
|
+
}
|
|
77
|
+
function TooltipTrigger({ ...props }) {
|
|
78
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
79
|
+
}
|
|
80
|
+
function TooltipContent({
|
|
81
|
+
className,
|
|
82
|
+
side = "top",
|
|
83
|
+
sideOffset = 4,
|
|
84
|
+
align = "center",
|
|
85
|
+
alignOffset = 0,
|
|
86
|
+
children,
|
|
87
|
+
...props
|
|
88
|
+
}) {
|
|
89
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsx(
|
|
90
|
+
Tooltip$1.Positioner,
|
|
91
|
+
{
|
|
92
|
+
align,
|
|
93
|
+
alignOffset,
|
|
94
|
+
side,
|
|
95
|
+
sideOffset,
|
|
96
|
+
className: "isolate z-50",
|
|
97
|
+
children: /* @__PURE__ */ jsxs(
|
|
98
|
+
Tooltip$1.Popup,
|
|
99
|
+
{
|
|
100
|
+
"data-slot": "tooltip-content",
|
|
101
|
+
className: cn(
|
|
102
|
+
"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",
|
|
103
|
+
className
|
|
104
|
+
),
|
|
105
|
+
...props,
|
|
106
|
+
children: [
|
|
107
|
+
children,
|
|
108
|
+
/* @__PURE__ */ jsx(Tooltip$1.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" })
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
) });
|
|
114
|
+
}
|
|
115
|
+
function CircleProgress({
|
|
116
|
+
percent,
|
|
117
|
+
size = 20,
|
|
118
|
+
strokeWidth = 2.5
|
|
119
|
+
}) {
|
|
120
|
+
const r = (size - strokeWidth) / 2;
|
|
121
|
+
const c = 2 * Math.PI * r;
|
|
122
|
+
const offset = c - percent / 100 * c;
|
|
123
|
+
return /* @__PURE__ */ jsxs("svg", { width: size, height: size, className: "shrink-0 -rotate-90", children: [
|
|
124
|
+
/* @__PURE__ */ jsx(
|
|
125
|
+
"circle",
|
|
126
|
+
{
|
|
127
|
+
cx: size / 2,
|
|
128
|
+
cy: size / 2,
|
|
129
|
+
r,
|
|
130
|
+
fill: "none",
|
|
131
|
+
stroke: "currentColor",
|
|
132
|
+
strokeWidth,
|
|
133
|
+
className: "text-muted-foreground/20"
|
|
134
|
+
}
|
|
135
|
+
),
|
|
136
|
+
/* @__PURE__ */ jsx(
|
|
137
|
+
"circle",
|
|
138
|
+
{
|
|
139
|
+
cx: size / 2,
|
|
140
|
+
cy: size / 2,
|
|
141
|
+
r,
|
|
142
|
+
fill: "none",
|
|
143
|
+
stroke: "currentColor",
|
|
144
|
+
strokeWidth,
|
|
145
|
+
strokeDasharray: c,
|
|
146
|
+
strokeDashoffset: offset,
|
|
147
|
+
strokeLinecap: "round",
|
|
148
|
+
className: "text-primary transition-[stroke-dashoffset] duration-200"
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
] });
|
|
152
|
+
}
|
|
153
|
+
function UploadStatus({
|
|
154
|
+
phase,
|
|
155
|
+
progress,
|
|
156
|
+
error,
|
|
157
|
+
fileInfo,
|
|
158
|
+
onCancel
|
|
159
|
+
}) {
|
|
160
|
+
if (phase === "idle") return null;
|
|
161
|
+
if (phase === "uploading" && fileInfo) {
|
|
162
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-1.5 text-xs", children: [
|
|
163
|
+
/* @__PURE__ */ jsx(CircleProgress, { percent: progress.percent, size: 14, strokeWidth: 2 }),
|
|
164
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-32 min-w-16 truncate sm:max-w-48", children: fileInfo.name }),
|
|
165
|
+
/* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
|
|
166
|
+
formatFileSize(progress.loaded),
|
|
167
|
+
" / ",
|
|
168
|
+
formatFileSize(fileInfo.size),
|
|
169
|
+
" (",
|
|
170
|
+
progress.percent,
|
|
171
|
+
"%)"
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ jsx(
|
|
174
|
+
Button,
|
|
175
|
+
{
|
|
176
|
+
variant: "ghost",
|
|
177
|
+
size: "icon",
|
|
178
|
+
className: "ml-auto size-6 shrink-0",
|
|
179
|
+
onClick: (e) => {
|
|
180
|
+
e.stopPropagation();
|
|
181
|
+
onCancel?.();
|
|
182
|
+
},
|
|
183
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-3.5" })
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
] });
|
|
187
|
+
}
|
|
188
|
+
if (phase === "success" && fileInfo) {
|
|
189
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [
|
|
190
|
+
/* @__PURE__ */ jsx(CheckCircleIcon, { className: "size-3.5 shrink-0 text-green-600" }),
|
|
191
|
+
/* @__PURE__ */ jsx("span", { className: "[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48", children: fileInfo.name }),
|
|
192
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: formatFileSize(fileInfo.size) })
|
|
193
|
+
] });
|
|
194
|
+
}
|
|
195
|
+
if (phase === "error") {
|
|
196
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-1.5 text-xs", children: [
|
|
197
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0 text-destructive" }),
|
|
198
|
+
/* @__PURE__ */ jsx("p", { className: "min-w-0 [overflow-wrap:anywhere] text-destructive", children: error ?? "Upload failed" })
|
|
199
|
+
] });
|
|
200
|
+
}
|
|
201
|
+
if (phase === "validating" || phase === "presigning") {
|
|
202
|
+
return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Preparing\u2026" });
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
function Progress({
|
|
207
|
+
className,
|
|
208
|
+
children,
|
|
209
|
+
value,
|
|
210
|
+
...props
|
|
211
|
+
}) {
|
|
212
|
+
return /* @__PURE__ */ jsxs(
|
|
213
|
+
Progress$1.Root,
|
|
214
|
+
{
|
|
215
|
+
value,
|
|
216
|
+
"data-slot": "progress",
|
|
217
|
+
className: cn("flex flex-wrap gap-3", className),
|
|
218
|
+
...props,
|
|
219
|
+
children: [
|
|
220
|
+
children,
|
|
221
|
+
/* @__PURE__ */ jsx(ProgressTrack, { children: /* @__PURE__ */ jsx(ProgressIndicator, {}) })
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
function ProgressTrack({ className, ...props }) {
|
|
227
|
+
return /* @__PURE__ */ jsx(
|
|
228
|
+
Progress$1.Track,
|
|
229
|
+
{
|
|
230
|
+
className: cn(
|
|
231
|
+
"relative flex h-1 w-full items-center overflow-x-hidden rounded-md bg-muted",
|
|
232
|
+
className
|
|
233
|
+
),
|
|
234
|
+
"data-slot": "progress-track",
|
|
235
|
+
...props
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
function ProgressIndicator({
|
|
240
|
+
className,
|
|
241
|
+
...props
|
|
242
|
+
}) {
|
|
243
|
+
return /* @__PURE__ */ jsx(
|
|
244
|
+
Progress$1.Indicator,
|
|
245
|
+
{
|
|
246
|
+
"data-slot": "progress-indicator",
|
|
247
|
+
className: cn("h-full bg-primary transition-all", className),
|
|
248
|
+
...props
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
function ProgressLabel({ className, ...props }) {
|
|
253
|
+
return /* @__PURE__ */ jsx(
|
|
254
|
+
Progress$1.Label,
|
|
255
|
+
{
|
|
256
|
+
className: cn("text-xs/relaxed font-medium", className),
|
|
257
|
+
"data-slot": "progress-label",
|
|
258
|
+
...props
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
function ProgressValue({ className, ...props }) {
|
|
263
|
+
return /* @__PURE__ */ jsx(
|
|
264
|
+
Progress$1.Value,
|
|
265
|
+
{
|
|
266
|
+
className: cn(
|
|
267
|
+
"ms-auto text-xs/relaxed text-muted-foreground tabular-nums",
|
|
268
|
+
className
|
|
269
|
+
),
|
|
270
|
+
"data-slot": "progress-value",
|
|
271
|
+
...props
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
function MultiUploadStatus({
|
|
276
|
+
phase,
|
|
277
|
+
files,
|
|
278
|
+
totalProgress,
|
|
279
|
+
error,
|
|
280
|
+
onCancel
|
|
281
|
+
}) {
|
|
282
|
+
if (phase === "idle") return null;
|
|
283
|
+
if (phase === "uploading") {
|
|
284
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-2", children: [
|
|
285
|
+
/* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-1.5", children: [
|
|
286
|
+
/* @__PURE__ */ jsxs(Progress, { value: totalProgress.percent, className: "flex-1", children: [
|
|
287
|
+
/* @__PURE__ */ jsxs(ProgressLabel, { children: [
|
|
288
|
+
files.filter((f) => f.status === "success").length,
|
|
289
|
+
"/",
|
|
290
|
+
files.length,
|
|
291
|
+
" files"
|
|
292
|
+
] }),
|
|
293
|
+
/* @__PURE__ */ jsx(ProgressValue, {})
|
|
294
|
+
] }),
|
|
295
|
+
/* @__PURE__ */ jsx(
|
|
296
|
+
Button,
|
|
297
|
+
{
|
|
298
|
+
variant: "ghost",
|
|
299
|
+
size: "icon",
|
|
300
|
+
className: "size-7 shrink-0",
|
|
301
|
+
onClick: (e) => {
|
|
302
|
+
e.stopPropagation();
|
|
303
|
+
onCancel?.();
|
|
304
|
+
},
|
|
305
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-4" })
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
] }),
|
|
309
|
+
/* @__PURE__ */ jsx(FileList, { files })
|
|
310
|
+
] });
|
|
311
|
+
}
|
|
312
|
+
if (phase === "success") {
|
|
313
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-1", children: [
|
|
314
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-green-600", children: [
|
|
315
|
+
"All ",
|
|
316
|
+
files.length,
|
|
317
|
+
" file(s) uploaded"
|
|
318
|
+
] }),
|
|
319
|
+
/* @__PURE__ */ jsx(FileList, { files })
|
|
320
|
+
] });
|
|
321
|
+
}
|
|
322
|
+
if (phase === "error") {
|
|
323
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-1", children: [
|
|
324
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-destructive", children: error ?? "Upload failed" }),
|
|
325
|
+
files.length > 0 && /* @__PURE__ */ jsx(FileList, { files })
|
|
326
|
+
] });
|
|
327
|
+
}
|
|
328
|
+
if (phase === "validating") {
|
|
329
|
+
return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Validating\u2026" });
|
|
330
|
+
}
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
function FileList({ files }) {
|
|
334
|
+
return /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1", children: files.map((f) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-0.5 text-xs", children: [
|
|
335
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
336
|
+
f.status === "success" && /* @__PURE__ */ jsx(CheckCircleIcon, { className: "size-3.5 shrink-0 text-green-600" }),
|
|
337
|
+
f.status === "error" && /* @__PURE__ */ jsx(AlertCircleIcon, { className: "size-3.5 shrink-0 text-destructive" }),
|
|
338
|
+
(f.status === "pending" || f.status === "uploading") && /* @__PURE__ */ jsx(
|
|
339
|
+
CircleProgress,
|
|
340
|
+
{
|
|
341
|
+
percent: f.status === "uploading" ? f.progress.percent : 0,
|
|
342
|
+
size: 14,
|
|
343
|
+
strokeWidth: 2
|
|
344
|
+
}
|
|
345
|
+
),
|
|
346
|
+
/* @__PURE__ */ jsx("span", { className: "[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48", children: f.fileName }),
|
|
347
|
+
f.status === "uploading" ? /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
|
|
348
|
+
formatFileSize(f.progress.loaded),
|
|
349
|
+
" /",
|
|
350
|
+
" ",
|
|
351
|
+
formatFileSize(f.fileSize),
|
|
352
|
+
" (",
|
|
353
|
+
f.progress.percent,
|
|
354
|
+
"%)"
|
|
355
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: formatFileSize(f.fileSize) })
|
|
356
|
+
] }),
|
|
357
|
+
f.status === "error" && f.error && /* @__PURE__ */ jsx("span", { className: "truncate [overflow-wrap:anywhere] pl-5 text-destructive", children: f.error })
|
|
358
|
+
] }, f.id)) });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ../../registry/registry/better-s3-ui/lib/truncate-msg.ts
|
|
362
|
+
function truncateMsg(msg, max = 100) {
|
|
363
|
+
return msg.length > max ? msg.slice(0, max) + "..." : msg;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ../../registry/registry/better-s3-ui/hooks/use-upload-toast.ts
|
|
367
|
+
function useUploadToast(ctrl, enabled) {
|
|
368
|
+
const toastIdRef = useRef(null);
|
|
369
|
+
const isMulti = ctrl.mode === "multi";
|
|
370
|
+
const prevPhaseRef = useRef(ctrl.phase);
|
|
371
|
+
if (prevPhaseRef.current !== ctrl.phase) {
|
|
372
|
+
prevPhaseRef.current = ctrl.phase;
|
|
373
|
+
if (enabled) {
|
|
374
|
+
if (ctrl.phase === "idle" && toastIdRef.current) {
|
|
375
|
+
toast.dismiss(toastIdRef.current);
|
|
376
|
+
toastIdRef.current = null;
|
|
377
|
+
}
|
|
378
|
+
if (ctrl.phase === "success") {
|
|
379
|
+
if (toastIdRef.current) toast.dismiss(toastIdRef.current);
|
|
380
|
+
if (isMulti) {
|
|
381
|
+
toast.success(`${ctrl.files.length} file(s) uploaded`, {
|
|
382
|
+
description: formatFileSize(ctrl.totalProgress.total)
|
|
383
|
+
});
|
|
384
|
+
} else if (ctrl.fileInfo) {
|
|
385
|
+
toast.success("Upload complete", {
|
|
386
|
+
description: formatFileSize(ctrl.fileInfo.size)
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
toastIdRef.current = null;
|
|
390
|
+
}
|
|
391
|
+
if (ctrl.phase === "error") {
|
|
392
|
+
if (toastIdRef.current) toast.dismiss(toastIdRef.current);
|
|
393
|
+
if (isMulti && ctrl.files.length > 0) {
|
|
394
|
+
const succeeded = ctrl.files.filter(
|
|
395
|
+
(f) => f.status === "success"
|
|
396
|
+
).length;
|
|
397
|
+
const failed = ctrl.files.filter((f) => f.status === "error").length;
|
|
398
|
+
toast.error("Upload finished with errors", {
|
|
399
|
+
description: `${succeeded} succeeded, ${failed} failed`
|
|
400
|
+
});
|
|
401
|
+
} else {
|
|
402
|
+
toast.error("Upload failed", {
|
|
403
|
+
description: truncateMsg(ctrl.error ?? "Unknown error")
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
toastIdRef.current = null;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
useEffect(() => {
|
|
411
|
+
if (!enabled || ctrl.phase !== "uploading") return;
|
|
412
|
+
const id = toastIdRef.current ?? `upload-${Date.now()}`;
|
|
413
|
+
toastIdRef.current = id;
|
|
414
|
+
if (isMulti) {
|
|
415
|
+
const done = ctrl.files.filter((f) => f.status === "success").length;
|
|
416
|
+
toast.loading(`Uploading... ${done}/${ctrl.files.length}`, {
|
|
417
|
+
id,
|
|
418
|
+
description: `${formatFileSize(ctrl.totalProgress.loaded)} / ${formatFileSize(ctrl.totalProgress.total)} (${ctrl.totalProgress.percent}%)`,
|
|
419
|
+
cancel: { label: "Cancel", onClick: () => ctrl.cancel() }
|
|
420
|
+
});
|
|
421
|
+
} else if (ctrl.fileInfo) {
|
|
422
|
+
toast.loading("Uploading...", {
|
|
423
|
+
id,
|
|
424
|
+
description: `${formatFileSize(ctrl.progress.loaded)} / ${formatFileSize(ctrl.fileInfo.size)} (${ctrl.progress.percent}%)`,
|
|
425
|
+
cancel: { label: "Cancel", onClick: () => ctrl.cancel() }
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}, [
|
|
429
|
+
enabled,
|
|
430
|
+
ctrl.phase,
|
|
431
|
+
isMulti,
|
|
432
|
+
ctrl.progress.loaded,
|
|
433
|
+
ctrl.progress.percent,
|
|
434
|
+
ctrl.totalProgress.loaded,
|
|
435
|
+
ctrl.totalProgress.total,
|
|
436
|
+
ctrl.totalProgress.percent,
|
|
437
|
+
ctrl.fileInfo,
|
|
438
|
+
ctrl.files,
|
|
439
|
+
ctrl.cancel
|
|
440
|
+
]);
|
|
441
|
+
}
|
|
442
|
+
function UploadButton({
|
|
443
|
+
className,
|
|
444
|
+
label,
|
|
445
|
+
disabled,
|
|
446
|
+
tooltipText,
|
|
447
|
+
toast: enableToast = true,
|
|
448
|
+
showStatus = true,
|
|
449
|
+
...options
|
|
450
|
+
}) {
|
|
451
|
+
const ctrl = useUploadControls(options);
|
|
452
|
+
const isMulti = ctrl.mode === "multi";
|
|
453
|
+
const isDisabled = disabled || ctrl.isUploading;
|
|
454
|
+
useUploadToast(ctrl, enableToast);
|
|
455
|
+
const status = showStatus ? isMulti ? /* @__PURE__ */ jsx(
|
|
456
|
+
MultiUploadStatus,
|
|
457
|
+
{
|
|
458
|
+
phase: ctrl.phase,
|
|
459
|
+
files: ctrl.files,
|
|
460
|
+
totalProgress: ctrl.totalProgress,
|
|
461
|
+
error: ctrl.error,
|
|
462
|
+
onCancel: ctrl.cancel
|
|
463
|
+
}
|
|
464
|
+
) : /* @__PURE__ */ jsx(
|
|
465
|
+
UploadStatus,
|
|
466
|
+
{
|
|
467
|
+
phase: ctrl.phase,
|
|
468
|
+
progress: ctrl.progress,
|
|
469
|
+
error: ctrl.error,
|
|
470
|
+
fileInfo: ctrl.fileInfo,
|
|
471
|
+
onCancel: ctrl.cancel
|
|
472
|
+
}
|
|
473
|
+
) : null;
|
|
474
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col gap-2", className), children: [
|
|
475
|
+
/* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-2", children: [
|
|
476
|
+
/* @__PURE__ */ jsx("input", { ...ctrl.inputProps }),
|
|
477
|
+
/* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
478
|
+
/* @__PURE__ */ jsxs(
|
|
479
|
+
TooltipTrigger,
|
|
480
|
+
{
|
|
481
|
+
render: /* @__PURE__ */ jsx(
|
|
482
|
+
Button,
|
|
483
|
+
{
|
|
484
|
+
size: "default",
|
|
485
|
+
disabled: isDisabled,
|
|
486
|
+
onClick: ctrl.openFilePicker
|
|
487
|
+
}
|
|
488
|
+
),
|
|
489
|
+
children: [
|
|
490
|
+
/* @__PURE__ */ jsx(UploadIcon, { "data-icon": "inline-start" }),
|
|
491
|
+
label ?? (isMulti ? "Upload files" : "Upload file")
|
|
492
|
+
]
|
|
493
|
+
}
|
|
494
|
+
),
|
|
495
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: tooltipText ?? (isMulti ? "Upload files" : "Upload file") })
|
|
496
|
+
] }) })
|
|
497
|
+
] }),
|
|
498
|
+
status
|
|
499
|
+
] });
|
|
500
|
+
}
|
|
501
|
+
function UploadDropzone({
|
|
502
|
+
className,
|
|
503
|
+
label,
|
|
504
|
+
disabled,
|
|
505
|
+
toast: enableToast = true,
|
|
506
|
+
showStatus = true,
|
|
507
|
+
...options
|
|
508
|
+
}) {
|
|
509
|
+
const ctrl = useUploadControls(options);
|
|
510
|
+
const isMulti = ctrl.mode === "multi";
|
|
511
|
+
const isDisabled = disabled || ctrl.isUploading;
|
|
512
|
+
useUploadToast(ctrl, enableToast);
|
|
513
|
+
const status = showStatus ? isMulti ? /* @__PURE__ */ jsx(
|
|
514
|
+
MultiUploadStatus,
|
|
515
|
+
{
|
|
516
|
+
phase: ctrl.phase,
|
|
517
|
+
files: ctrl.files,
|
|
518
|
+
totalProgress: ctrl.totalProgress,
|
|
519
|
+
error: ctrl.error,
|
|
520
|
+
onCancel: ctrl.cancel
|
|
521
|
+
}
|
|
522
|
+
) : /* @__PURE__ */ jsx(
|
|
523
|
+
UploadStatus,
|
|
524
|
+
{
|
|
525
|
+
phase: ctrl.phase,
|
|
526
|
+
progress: ctrl.progress,
|
|
527
|
+
error: ctrl.error,
|
|
528
|
+
fileInfo: ctrl.fileInfo,
|
|
529
|
+
onCancel: ctrl.cancel
|
|
530
|
+
}
|
|
531
|
+
) : null;
|
|
532
|
+
return /* @__PURE__ */ jsxs(
|
|
533
|
+
"div",
|
|
534
|
+
{
|
|
535
|
+
className: cn(
|
|
536
|
+
"flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed p-6 text-center transition-colors",
|
|
537
|
+
isDisabled ? "cursor-not-allowed border-muted-foreground/25" : "cursor-pointer border-muted-foreground/25 hover:border-primary/50",
|
|
538
|
+
className
|
|
539
|
+
),
|
|
540
|
+
onClick: isDisabled ? void 0 : ctrl.openFilePicker,
|
|
541
|
+
...isDisabled ? {} : ctrl.dropHandlers,
|
|
542
|
+
children: [
|
|
543
|
+
/* @__PURE__ */ jsx("input", { ...ctrl.inputProps }),
|
|
544
|
+
/* @__PURE__ */ jsx(
|
|
545
|
+
UploadIcon,
|
|
546
|
+
{
|
|
547
|
+
className: cn(
|
|
548
|
+
"size-6 text-muted-foreground",
|
|
549
|
+
isDisabled && "opacity-50"
|
|
550
|
+
)
|
|
551
|
+
}
|
|
552
|
+
),
|
|
553
|
+
/* @__PURE__ */ jsx(
|
|
554
|
+
"p",
|
|
555
|
+
{
|
|
556
|
+
className: cn(
|
|
557
|
+
"text-sm text-muted-foreground",
|
|
558
|
+
isDisabled && "opacity-50"
|
|
559
|
+
),
|
|
560
|
+
children: label ?? (isMulti ? "Click or drag & drop files to upload" : "Click or drag & drop to upload")
|
|
561
|
+
}
|
|
562
|
+
),
|
|
563
|
+
status && /* @__PURE__ */ jsx("div", { className: "w-full text-left", children: status })
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
function useDownloadToast({
|
|
569
|
+
enabled = true,
|
|
570
|
+
objectKey,
|
|
571
|
+
fileName,
|
|
572
|
+
fileSize
|
|
573
|
+
}) {
|
|
574
|
+
const buildErrorDescription = (error) => truncateMsg(error instanceof Error ? error.message : "Unknown error");
|
|
575
|
+
const displayName = truncateMsg(
|
|
576
|
+
fileName ?? objectKey.split("/").pop() ?? objectKey,
|
|
577
|
+
60
|
|
578
|
+
);
|
|
579
|
+
const onInitiated = () => {
|
|
580
|
+
if (enabled) toast.success("Download started");
|
|
581
|
+
};
|
|
582
|
+
const onSuccess = (_key, actualFileName) => {
|
|
583
|
+
if (!enabled) return;
|
|
584
|
+
toast.dismiss(`dl-${objectKey}`);
|
|
585
|
+
const safeFileName = truncateMsg(actualFileName, 60);
|
|
586
|
+
toast.success("Download complete", {
|
|
587
|
+
description: `${safeFileName}${fileSize != null ? ` \xB7 ${formatFileSize(fileSize)}` : ""}`
|
|
588
|
+
});
|
|
589
|
+
};
|
|
590
|
+
const onError = (_key, error) => {
|
|
591
|
+
if (!enabled) return;
|
|
592
|
+
toast.dismiss(`dl-${objectKey}`);
|
|
593
|
+
toast.error("Download failed", {
|
|
594
|
+
description: buildErrorDescription(error)
|
|
595
|
+
});
|
|
596
|
+
};
|
|
597
|
+
const onErrorWithPhase = (_key, error, _phase) => {
|
|
598
|
+
if (!enabled) return;
|
|
599
|
+
toast.dismiss(`dl-${objectKey}`);
|
|
600
|
+
toast.error("Download failed", {
|
|
601
|
+
description: buildErrorDescription(error)
|
|
602
|
+
});
|
|
603
|
+
};
|
|
604
|
+
const onCancel = (_key) => {
|
|
605
|
+
if (!enabled) return;
|
|
606
|
+
toast.dismiss(`dl-${objectKey}`);
|
|
607
|
+
toast.info("Download cancelled", { description: displayName });
|
|
608
|
+
};
|
|
609
|
+
return { onInitiated, onSuccess, onError, onErrorWithPhase, onCancel };
|
|
610
|
+
}
|
|
611
|
+
function DownloadButton({
|
|
612
|
+
api,
|
|
613
|
+
objectKey,
|
|
614
|
+
fileName,
|
|
615
|
+
label,
|
|
616
|
+
className,
|
|
617
|
+
disabled,
|
|
618
|
+
toast: enableToast = true,
|
|
619
|
+
showStatus = true
|
|
620
|
+
}) {
|
|
621
|
+
const toastHandlers = useDownloadToast({
|
|
622
|
+
enabled: enableToast,
|
|
623
|
+
objectKey,
|
|
624
|
+
fileName
|
|
625
|
+
});
|
|
626
|
+
const dl = useDownload({
|
|
627
|
+
api,
|
|
628
|
+
onInitiated: () => {
|
|
629
|
+
toastHandlers.onInitiated();
|
|
630
|
+
},
|
|
631
|
+
onError: (key, error) => {
|
|
632
|
+
toastHandlers.onError(key, error);
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
const isPending = dl.phase === "presigning";
|
|
636
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col gap-1.5", className), children: [
|
|
637
|
+
/* @__PURE__ */ jsx(
|
|
638
|
+
Button,
|
|
639
|
+
{
|
|
640
|
+
size: "default",
|
|
641
|
+
variant: "outline",
|
|
642
|
+
disabled: disabled || isPending,
|
|
643
|
+
onClick: () => dl.download(objectKey, fileName),
|
|
644
|
+
children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
645
|
+
isPending ? /* @__PURE__ */ jsx(LoaderIcon, { className: "animate-spin", "data-icon": "inline-start" }) : /* @__PURE__ */ jsx(DownloadIcon, { "data-icon": "inline-start" }),
|
|
646
|
+
label ?? "Download"
|
|
647
|
+
] })
|
|
648
|
+
}
|
|
649
|
+
),
|
|
650
|
+
showStatus && dl.phase === "error" && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-1.5 text-xs", children: [
|
|
651
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0 text-destructive" }),
|
|
652
|
+
/* @__PURE__ */ jsx("p", { className: "min-w-0 [overflow-wrap:anywhere] text-destructive", children: dl.error ?? "Download failed" })
|
|
653
|
+
] })
|
|
654
|
+
] });
|
|
655
|
+
}
|
|
656
|
+
function ProgressDownloadButton({
|
|
657
|
+
api,
|
|
658
|
+
objectKey,
|
|
659
|
+
fileName,
|
|
660
|
+
fileSize,
|
|
661
|
+
bucket,
|
|
662
|
+
label,
|
|
663
|
+
className,
|
|
664
|
+
fillClassName,
|
|
665
|
+
disabled,
|
|
666
|
+
tooltipText = "Download file",
|
|
667
|
+
toast: enableToast = true,
|
|
668
|
+
showStatus = true,
|
|
669
|
+
beforeDownload,
|
|
670
|
+
onDownloadStart,
|
|
671
|
+
onProgress,
|
|
672
|
+
onSuccess,
|
|
673
|
+
onError,
|
|
674
|
+
onCancel
|
|
675
|
+
}) {
|
|
676
|
+
const toastHandlers = useDownloadToast({
|
|
677
|
+
enabled: enableToast,
|
|
678
|
+
objectKey,
|
|
679
|
+
fileName,
|
|
680
|
+
fileSize
|
|
681
|
+
});
|
|
682
|
+
const dl = useFetchDownload({
|
|
683
|
+
api,
|
|
684
|
+
bucket,
|
|
685
|
+
beforeDownload,
|
|
686
|
+
onDownloadStart,
|
|
687
|
+
onProgress,
|
|
688
|
+
onSuccess: (key, actualFileName) => {
|
|
689
|
+
toastHandlers.onSuccess(key, actualFileName);
|
|
690
|
+
onSuccess?.(key, actualFileName);
|
|
691
|
+
},
|
|
692
|
+
onError: (key, error, phase) => {
|
|
693
|
+
toastHandlers.onErrorWithPhase(key, error, phase);
|
|
694
|
+
onError?.(key, error, phase);
|
|
695
|
+
},
|
|
696
|
+
onCancel: (key) => {
|
|
697
|
+
toastHandlers.onCancel(key);
|
|
698
|
+
onCancel?.(key);
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
const isDownloading = dl.phase === "downloading" || dl.phase === "presigning";
|
|
702
|
+
const handleClick = () => {
|
|
703
|
+
if (isDownloading) {
|
|
704
|
+
dl.cancel();
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
dl.download(objectKey, fileName);
|
|
708
|
+
};
|
|
709
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col gap-1.5", className), children: [
|
|
710
|
+
/* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
711
|
+
/* @__PURE__ */ jsxs(
|
|
712
|
+
TooltipTrigger,
|
|
713
|
+
{
|
|
714
|
+
render: /* @__PURE__ */ jsx(
|
|
715
|
+
Button,
|
|
716
|
+
{
|
|
717
|
+
size: "default",
|
|
718
|
+
variant: "outline",
|
|
719
|
+
disabled,
|
|
720
|
+
className: cn("relative min-w-24 overflow-hidden"),
|
|
721
|
+
onClick: handleClick
|
|
722
|
+
}
|
|
723
|
+
),
|
|
724
|
+
children: [
|
|
725
|
+
isDownloading && /* @__PURE__ */ jsx(
|
|
726
|
+
"span",
|
|
727
|
+
{
|
|
728
|
+
className: cn(
|
|
729
|
+
"absolute inset-0 bg-primary/15 transition-[width] duration-200",
|
|
730
|
+
fillClassName
|
|
731
|
+
),
|
|
732
|
+
style: { width: `${dl.progress.percent}%` }
|
|
733
|
+
}
|
|
734
|
+
),
|
|
735
|
+
/* @__PURE__ */ jsxs("span", { className: "relative z-10 inline-flex items-center gap-1", children: [
|
|
736
|
+
/* @__PURE__ */ jsx(DownloadIcon, { "data-icon": "inline-start" }),
|
|
737
|
+
isDownloading ? formatFileSize(dl.progress.loaded) : label ?? "Download"
|
|
738
|
+
] })
|
|
739
|
+
]
|
|
740
|
+
}
|
|
741
|
+
),
|
|
742
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: isDownloading ? "Cancel download" : tooltipText })
|
|
743
|
+
] }) }),
|
|
744
|
+
showStatus && dl.phase === "error" && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-1.5 text-xs", children: [
|
|
745
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0 text-destructive" }),
|
|
746
|
+
/* @__PURE__ */ jsx("p", { className: "min-w-0 [overflow-wrap:anywhere] text-destructive", children: dl.error ?? "Download failed" })
|
|
747
|
+
] })
|
|
748
|
+
] });
|
|
749
|
+
}
|
|
750
|
+
function AlertDialog({ ...props }) {
|
|
751
|
+
return /* @__PURE__ */ jsx(AlertDialog$1.Root, { "data-slot": "alert-dialog", ...props });
|
|
752
|
+
}
|
|
753
|
+
function AlertDialogTrigger({ ...props }) {
|
|
754
|
+
return /* @__PURE__ */ jsx(AlertDialog$1.Trigger, { "data-slot": "alert-dialog-trigger", ...props });
|
|
755
|
+
}
|
|
756
|
+
function AlertDialogPortal({ ...props }) {
|
|
757
|
+
return /* @__PURE__ */ jsx(AlertDialog$1.Portal, { "data-slot": "alert-dialog-portal", ...props });
|
|
758
|
+
}
|
|
759
|
+
function AlertDialogOverlay({
|
|
760
|
+
className,
|
|
761
|
+
...props
|
|
762
|
+
}) {
|
|
763
|
+
return /* @__PURE__ */ jsx(
|
|
764
|
+
AlertDialog$1.Backdrop,
|
|
765
|
+
{
|
|
766
|
+
"data-slot": "alert-dialog-overlay",
|
|
767
|
+
className: cn(
|
|
768
|
+
"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",
|
|
769
|
+
className
|
|
770
|
+
),
|
|
771
|
+
...props
|
|
772
|
+
}
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
function AlertDialogContent({
|
|
776
|
+
className,
|
|
777
|
+
size = "default",
|
|
778
|
+
...props
|
|
779
|
+
}) {
|
|
780
|
+
return /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [
|
|
781
|
+
/* @__PURE__ */ jsx(AlertDialogOverlay, {}),
|
|
782
|
+
/* @__PURE__ */ jsx(
|
|
783
|
+
AlertDialog$1.Popup,
|
|
784
|
+
{
|
|
785
|
+
"data-slot": "alert-dialog-content",
|
|
786
|
+
"data-size": size,
|
|
787
|
+
className: cn(
|
|
788
|
+
"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",
|
|
789
|
+
className
|
|
790
|
+
),
|
|
791
|
+
...props
|
|
792
|
+
}
|
|
793
|
+
)
|
|
794
|
+
] });
|
|
795
|
+
}
|
|
796
|
+
function AlertDialogHeader({
|
|
797
|
+
className,
|
|
798
|
+
...props
|
|
799
|
+
}) {
|
|
800
|
+
return /* @__PURE__ */ jsx(
|
|
801
|
+
"div",
|
|
802
|
+
{
|
|
803
|
+
"data-slot": "alert-dialog-header",
|
|
804
|
+
className: cn(
|
|
805
|
+
"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]",
|
|
806
|
+
className
|
|
807
|
+
),
|
|
808
|
+
...props
|
|
809
|
+
}
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
function AlertDialogFooter({
|
|
813
|
+
className,
|
|
814
|
+
...props
|
|
815
|
+
}) {
|
|
816
|
+
return /* @__PURE__ */ jsx(
|
|
817
|
+
"div",
|
|
818
|
+
{
|
|
819
|
+
"data-slot": "alert-dialog-footer",
|
|
820
|
+
className: cn(
|
|
821
|
+
"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",
|
|
822
|
+
className
|
|
823
|
+
),
|
|
824
|
+
...props
|
|
825
|
+
}
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
function AlertDialogMedia({
|
|
829
|
+
className,
|
|
830
|
+
...props
|
|
831
|
+
}) {
|
|
832
|
+
return /* @__PURE__ */ jsx(
|
|
833
|
+
"div",
|
|
834
|
+
{
|
|
835
|
+
"data-slot": "alert-dialog-media",
|
|
836
|
+
className: cn(
|
|
837
|
+
"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",
|
|
838
|
+
className
|
|
839
|
+
),
|
|
840
|
+
...props
|
|
841
|
+
}
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
function AlertDialogTitle({
|
|
845
|
+
className,
|
|
846
|
+
...props
|
|
847
|
+
}) {
|
|
848
|
+
return /* @__PURE__ */ jsx(
|
|
849
|
+
AlertDialog$1.Title,
|
|
850
|
+
{
|
|
851
|
+
"data-slot": "alert-dialog-title",
|
|
852
|
+
className: cn(
|
|
853
|
+
"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",
|
|
854
|
+
className
|
|
855
|
+
),
|
|
856
|
+
...props
|
|
857
|
+
}
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
function AlertDialogDescription({
|
|
861
|
+
className,
|
|
862
|
+
...props
|
|
863
|
+
}) {
|
|
864
|
+
return /* @__PURE__ */ jsx(
|
|
865
|
+
AlertDialog$1.Description,
|
|
866
|
+
{
|
|
867
|
+
"data-slot": "alert-dialog-description",
|
|
868
|
+
className: cn(
|
|
869
|
+
"text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
870
|
+
className
|
|
871
|
+
),
|
|
872
|
+
...props
|
|
873
|
+
}
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
function AlertDialogAction({
|
|
877
|
+
className,
|
|
878
|
+
...props
|
|
879
|
+
}) {
|
|
880
|
+
return /* @__PURE__ */ jsx(
|
|
881
|
+
Button,
|
|
882
|
+
{
|
|
883
|
+
"data-slot": "alert-dialog-action",
|
|
884
|
+
className: cn(className),
|
|
885
|
+
...props
|
|
886
|
+
}
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
function AlertDialogCancel({
|
|
890
|
+
className,
|
|
891
|
+
variant = "outline",
|
|
892
|
+
size = "default",
|
|
893
|
+
...props
|
|
894
|
+
}) {
|
|
895
|
+
return /* @__PURE__ */ jsx(
|
|
896
|
+
AlertDialog$1.Close,
|
|
897
|
+
{
|
|
898
|
+
"data-slot": "alert-dialog-cancel",
|
|
899
|
+
className: cn(className),
|
|
900
|
+
render: /* @__PURE__ */ jsx(Button, { variant, size }),
|
|
901
|
+
...props
|
|
902
|
+
}
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
function useDeleteToast({ enabled = true, displayName }) {
|
|
906
|
+
const safeDisplayName = truncateMsg(displayName, 60);
|
|
907
|
+
const onSuccess = (_key) => {
|
|
908
|
+
if (!enabled) return;
|
|
909
|
+
toast.success("File deleted", { description: safeDisplayName });
|
|
910
|
+
};
|
|
911
|
+
const onError = (_key, error) => {
|
|
912
|
+
if (!enabled) return;
|
|
913
|
+
toast.error("Delete failed", {
|
|
914
|
+
description: truncateMsg(
|
|
915
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
916
|
+
)
|
|
917
|
+
});
|
|
918
|
+
};
|
|
919
|
+
return { onSuccess, onError };
|
|
920
|
+
}
|
|
921
|
+
function DeleteButton({
|
|
922
|
+
api,
|
|
923
|
+
objectKey,
|
|
924
|
+
fileName,
|
|
925
|
+
fileSize,
|
|
926
|
+
bucket,
|
|
927
|
+
label,
|
|
928
|
+
className,
|
|
929
|
+
disabled,
|
|
930
|
+
tooltipText = "Delete file",
|
|
931
|
+
toast: enableToast = true,
|
|
932
|
+
showStatus = true,
|
|
933
|
+
confirmTitle = "Delete file?",
|
|
934
|
+
confirmDescription,
|
|
935
|
+
beforeDelete,
|
|
936
|
+
onDeleteStart,
|
|
937
|
+
onSuccess,
|
|
938
|
+
onError
|
|
939
|
+
}) {
|
|
940
|
+
const displayName = fileName ?? objectKey.split("/").pop() ?? objectKey;
|
|
941
|
+
const toastHandlers = useDeleteToast({
|
|
942
|
+
enabled: enableToast,
|
|
943
|
+
displayName
|
|
944
|
+
});
|
|
945
|
+
const del = useDelete({
|
|
946
|
+
api,
|
|
947
|
+
bucket,
|
|
948
|
+
beforeDelete,
|
|
949
|
+
onDeleteStart,
|
|
950
|
+
onSuccess: (key) => {
|
|
951
|
+
toastHandlers.onSuccess(key);
|
|
952
|
+
onSuccess?.(key);
|
|
953
|
+
},
|
|
954
|
+
onError: (key, error, phase) => {
|
|
955
|
+
toastHandlers.onError(key, error);
|
|
956
|
+
onError?.(key, error, phase);
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
const isDeleting = del.phase === "deleting";
|
|
960
|
+
const isDisabled = disabled || isDeleting;
|
|
961
|
+
const description = confirmDescription ?? `Are you sure you want to delete "${displayName}"${fileSize != null ? ` (${formatFileSize(fileSize)})` : ""}? This action cannot be undone.`;
|
|
962
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex flex-col gap-1.5", className), children: [
|
|
963
|
+
/* @__PURE__ */ jsx("div", { className: "inline-flex items-center gap-2", children: /* @__PURE__ */ jsxs(
|
|
964
|
+
AlertDialog,
|
|
965
|
+
{
|
|
966
|
+
open: del.phase === "confirming",
|
|
967
|
+
onOpenChange: (open) => {
|
|
968
|
+
if (!open) del.cancelDelete();
|
|
969
|
+
},
|
|
970
|
+
children: [
|
|
971
|
+
/* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
972
|
+
/* @__PURE__ */ jsxs(
|
|
973
|
+
TooltipTrigger,
|
|
974
|
+
{
|
|
975
|
+
render: /* @__PURE__ */ jsx(
|
|
976
|
+
AlertDialogTrigger,
|
|
977
|
+
{
|
|
978
|
+
disabled: isDisabled,
|
|
979
|
+
onClick: () => del.requestDelete(objectKey),
|
|
980
|
+
render: /* @__PURE__ */ jsx(
|
|
981
|
+
Button,
|
|
982
|
+
{
|
|
983
|
+
size: "default",
|
|
984
|
+
variant: "destructive",
|
|
985
|
+
disabled: isDisabled
|
|
986
|
+
}
|
|
987
|
+
)
|
|
988
|
+
}
|
|
989
|
+
),
|
|
990
|
+
children: [
|
|
991
|
+
isDeleting ? /* @__PURE__ */ jsx(
|
|
992
|
+
LoaderIcon,
|
|
993
|
+
{
|
|
994
|
+
className: "animate-spin",
|
|
995
|
+
"data-icon": "inline-start"
|
|
996
|
+
}
|
|
997
|
+
) : /* @__PURE__ */ jsx(Trash2Icon, { "data-icon": "inline-start" }),
|
|
998
|
+
label ?? "Delete"
|
|
999
|
+
]
|
|
1000
|
+
}
|
|
1001
|
+
),
|
|
1002
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: tooltipText })
|
|
1003
|
+
] }) }),
|
|
1004
|
+
/* @__PURE__ */ jsxs(AlertDialogContent, { children: [
|
|
1005
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
|
|
1006
|
+
/* @__PURE__ */ jsx(AlertDialogMedia, { children: /* @__PURE__ */ jsx(Trash2Icon, {}) }),
|
|
1007
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { children: confirmTitle }),
|
|
1008
|
+
/* @__PURE__ */ jsx(AlertDialogDescription, { className: "[overflow-wrap:anywhere]", children: description })
|
|
1009
|
+
] }),
|
|
1010
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
|
|
1011
|
+
/* @__PURE__ */ jsx(AlertDialogCancel, { children: "Cancel" }),
|
|
1012
|
+
/* @__PURE__ */ jsx(
|
|
1013
|
+
AlertDialogAction,
|
|
1014
|
+
{
|
|
1015
|
+
variant: "destructive",
|
|
1016
|
+
onClick: () => del.confirmDelete(),
|
|
1017
|
+
children: "Delete"
|
|
1018
|
+
}
|
|
1019
|
+
)
|
|
1020
|
+
] })
|
|
1021
|
+
] })
|
|
1022
|
+
]
|
|
1023
|
+
}
|
|
1024
|
+
) }),
|
|
1025
|
+
showStatus && del.phase === "success" && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-1.5 text-xs", children: [
|
|
1026
|
+
/* @__PURE__ */ jsx(CheckCircle2Icon, { className: "size-3.5 shrink-0 text-green-600" }),
|
|
1027
|
+
/* @__PURE__ */ jsxs("p", { className: "min-w-0 [overflow-wrap:anywhere] text-green-600", children: [
|
|
1028
|
+
"\u201C",
|
|
1029
|
+
/* @__PURE__ */ jsx("span", { className: "inline-block max-w-[14ch] truncate align-bottom", children: displayName }),
|
|
1030
|
+
"\u201D deleted"
|
|
1031
|
+
] })
|
|
1032
|
+
] }),
|
|
1033
|
+
showStatus && del.phase === "error" && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-1.5 text-xs", children: [
|
|
1034
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0 text-destructive" }),
|
|
1035
|
+
/* @__PURE__ */ jsx("p", { className: "min-w-0 [overflow-wrap:anywhere] text-destructive", children: del.error ?? "Delete failed" })
|
|
1036
|
+
] })
|
|
1037
|
+
] });
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
export { DeleteButton, DownloadButton, MultiUploadStatus, ProgressDownloadButton, UploadButton, UploadDropzone, UploadStatus };
|
|
1041
|
+
//# sourceMappingURL=index.js.map
|
|
2
1042
|
//# sourceMappingURL=index.js.map
|