@better-s3/ui 3.1044.0 → 3.1045.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.
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
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 v=o??t.split("/").pop()??t,f=useFetchDownload({api:e,bucket:l,beforeDownload:Q,onDownloadStart:Y,onProgress:Z,onSuccess:(x,P)=>{D&&(toast.dismiss(`dl-${t}`),toast.success("Download complete",{description:`${P}${r!=null?` \xB7 ${formatFileSize(r)}`:""}`})),K?.(x,P);},onError:(x,P,te)=>{D&&(toast.dismiss(`dl-${t}`),toast.error("Download failed",{description:st(P instanceof Error?P.message:"Unknown error")})),j?.(x,P,te);},onCancel:x=>{D&&(toast.dismiss(`dl-${t}`),toast.info("Download cancelled",{description:v})),V?.(x);}}),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 xe({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 ve({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 xt=(e,t=100)=>e.length>t?e.slice(0,t)+"\u2026":e;function vt({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,v=useDelete({api:e,bucket:l,beforeDelete:Y,onDeleteStart:Z,onSuccess:x=>{g&&toast.success("File deleted",{description:V}),K?.(x);},onError:(x,P,te)=>{g&&toast.error("Delete failed",{description:xt(P instanceof Error?P.message:"Unknown error")}),j?.(x,P,te);}}),f=v.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:v.phase==="confirming",onOpenChange:x=>{x||v.cancelDelete();},children:[jsx(B,{children:jsxs(S,{children:[jsxs(I,{render:jsx(ge,{disabled:k,onClick:()=>v.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(xe,{children:[jsx(Pe,{children:jsx(Trash2Icon,{})}),jsx(he,{children:U}),jsx(be,{children:ee})]}),jsxs(ve,{children:[jsx(De,{children:"Cancel"}),jsx(we,{variant:"destructive",onClick:()=>v.confirmDelete(),children:"Delete"})]})]})]})}),D&&v.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&&v.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:v.error??"Delete failed"})]})]})}export{vt 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';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
2
2
  //# sourceMappingURL=index.js.map
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/upload/upload-status.tsx","../src/components/ui/progress.tsx","../src/upload/multi-upload-status.tsx","../src/upload/use-upload-toast.ts","../src/upload/upload-button.tsx","../src/upload/upload-dropzone.tsx","../src/download/download-button.tsx","../src/download/progress-download-button.tsx","../src/components/ui/alert-dialog.tsx","../src/delete/delete-button.tsx"],"names":["cn","inputs","twMerge","clsx","buttonVariants","cva","Button","className","variant","size","props","jsx","ButtonPrimitive","TooltipProvider","delay","TooltipPrimitive","Tooltip","TooltipTrigger","TooltipContent","side","sideOffset","align","alignOffset","children","jsxs","CircleProgress","percent","strokeWidth","c","offset","UploadStatus","phase","progress","error","fileInfo","onCancel","formatFileSize","e","XIcon","CheckCircleIcon","AlertCircleIcon","Progress","value","ProgressPrimitive","ProgressTrack","ProgressIndicator","ProgressLabel","ProgressValue","MultiUploadStatus","files","totalProgress","f","FileList","truncateMsg","msg","max","useUploadToast","ctrl","enabled","toastIdRef","useRef","isMulti","prevPhaseRef","toast","succeeded","failed","useEffect","id","done","UploadButton","label","disabled","tooltipText","enableToast","showStatus","options","useUploadControls","isDisabled","status","UploadIcon","UploadDropzone","DownloadButton","api","objectKey","fileName","dl","useDownload","_key","isPending","LoaderIcon","DownloadIcon","ProgressDownloadButton","fileSize","bucket","fillClassName","beforeDownload","onDownloadStart","onProgress","onSuccess","onError","displayName","useFetchDownload","key","actualFileName","isDownloading","handleClick","AlertDialog","AlertDialogPrimitive","AlertDialogTrigger","AlertDialogPortal","AlertDialogOverlay","AlertDialogContent","AlertDialogHeader","AlertDialogFooter","AlertDialogMedia","AlertDialogTitle","AlertDialogDescription","AlertDialogAction","AlertDialogCancel","DeleteButton","confirmTitle","confirmDescription","beforeDelete","onDeleteStart","del","useDelete","isDeleting","description","open","Trash2Icon","CheckCircle2Icon"],"mappings":"qnBAGO,SAASA,CAAAA,CAAAA,GAAMC,EAAsB,CAC1C,OAAOC,OAAAA,CAAQC,IAAAA,CAAKF,CAAM,CAAC,CAC7B,CCEA,IAAMG,EAAAA,CAAiBC,IACrB,mnBAAA,CACA,CACE,QAAA,CAAU,CACR,QAAS,CACP,OAAA,CAAS,yDACT,OAAA,CACE,6HAAA,CACF,UACE,iIAAA,CACF,KAAA,CACE,kHAAA,CACF,WAAA,CACE,8NACF,IAAA,CAAM,iDACR,EACA,IAAA,CAAM,CACJ,QACE,6IAAA,CACF,EAAA,CAAI,wJAAA,CACJ,EAAA,CAAI,4IACJ,EAAA,CAAI,yIAAA,CACJ,KAAM,+CAAA,CACN,SAAA,CAAW,2DACX,SAAA,CAAW,6CAAA,CACX,SAAA,CAAW,6CACb,CACF,CAAA,CACA,eAAA,CAAiB,CACf,OAAA,CAAS,SAAA,CACT,KAAM,SACR,CACF,CACF,CAAA,CAEA,SAASC,CAAAA,CAAO,CACd,UAAAC,CAAAA,CACA,OAAA,CAAAC,EAAU,SAAA,CACV,IAAA,CAAAC,CAAAA,CAAO,SAAA,CACP,GAAGC,CACL,CAAA,CAAgE,CAC9D,OACEC,GAAAA,CAACC,OAAA,CACC,WAAA,CAAU,QAAA,CACV,SAAA,CAAWZ,EAAGI,EAAAA,CAAe,CAAE,QAAAI,CAAAA,CAAS,IAAA,CAAAC,EAAM,SAAA,CAAAF,CAAU,CAAC,CAAC,EACzD,GAAGG,CAAAA,CACN,CAEJ,CCjDA,SAASG,CAAAA,CAAgB,CACvB,MAAAC,CAAAA,CAAQ,CAAA,CACR,GAAGJ,CACL,EAAoC,CAClC,OACEC,IAACI,OAAAA,CAAiB,QAAA,CAAjB,CACC,WAAA,CAAU,kBAAA,CACV,KAAA,CAAOD,CAAAA,CACN,GAAGJ,CAAAA,CACN,CAEJ,CAEA,SAASM,CAAAA,CAAQ,CAAE,GAAGN,CAAM,CAAA,CAAgC,CAC1D,OAAOC,GAAAA,CAACI,OAAAA,CAAiB,KAAjB,CAAsB,WAAA,CAAU,UAAW,GAAGL,CAAAA,CAAO,CAC/D,CAEA,SAASO,CAAAA,CAAe,CAAE,GAAGP,CAAM,CAAA,CAAmC,CACpE,OAAOC,GAAAA,CAACI,OAAAA,CAAiB,OAAA,CAAjB,CAAyB,WAAA,CAAU,iBAAA,CAAmB,GAAGL,CAAAA,CAAO,CAC1E,CAEA,SAASQ,CAAAA,CAAe,CACtB,SAAA,CAAAX,EACA,IAAA,CAAAY,CAAAA,CAAO,MACP,UAAA,CAAAC,CAAAA,CAAa,EACb,KAAA,CAAAC,CAAAA,CAAQ,QAAA,CACR,WAAA,CAAAC,EAAc,CAAA,CACd,QAAA,CAAAC,EACA,GAAGb,CACL,EAIK,CACH,OACEC,GAAAA,CAACI,OAAAA,CAAiB,OAAjB,CACC,QAAA,CAAAJ,IAACI,OAAAA,CAAiB,UAAA,CAAjB,CACC,KAAA,CAAOM,CAAAA,CACP,WAAA,CAAaC,CAAAA,CACb,KAAMH,CAAAA,CACN,UAAA,CAAYC,EACZ,SAAA,CAAU,cAAA,CAEV,SAAAI,IAAAA,CAACT,OAAAA,CAAiB,KAAA,CAAjB,CACC,YAAU,iBAAA,CACV,SAAA,CAAWf,EACT,gwBAAA,CACAO,CACF,EACC,GAAGG,CAAAA,CAEH,QAAA,CAAA,CAAAa,CAAAA,CACDZ,IAACI,OAAAA,CAAiB,KAAA,CAAjB,CAAuB,SAAA,CAAU,yhBAAA,CAA0hB,GAC9jB,CAAA,CACF,CAAA,CACF,CAEJ,CC7DO,SAASU,CAAAA,CAAe,CAC7B,OAAA,CAAAC,EACA,IAAA,CAAAjB,CAAAA,CAAO,GACP,WAAA,CAAAkB,CAAAA,CAAc,GAChB,CAAA,CAIG,CACD,IAAM,CAAA,CAAA,CAAKlB,EAAOkB,CAAAA,EAAe,CAAA,CAC3BC,EAAI,CAAA,CAAI,IAAA,CAAK,GAAK,CAAA,CAClBC,CAAAA,CAASD,CAAAA,CAAKF,CAAAA,CAAU,IAAOE,CAAAA,CACrC,OACEJ,KAAC,KAAA,CAAA,CAAI,KAAA,CAAOf,EAAM,MAAA,CAAQA,CAAAA,CAAM,SAAA,CAAU,qBAAA,CACxC,UAAAE,GAAAA,CAAC,QAAA,CAAA,CACC,GAAIF,CAAAA,CAAO,CAAA,CACX,GAAIA,CAAAA,CAAO,CAAA,CACX,CAAA,CACA,IAAA,CAAK,OACL,MAAA,CAAO,cAAA,CACP,YAAakB,CAAAA,CACb,SAAA,CAAU,2BACZ,CAAA,CACAhB,GAAAA,CAAC,UACC,EAAA,CAAIF,CAAAA,CAAO,EACX,EAAA,CAAIA,CAAAA,CAAO,EACX,CAAA,CACA,IAAA,CAAK,OACL,MAAA,CAAO,cAAA,CACP,WAAA,CAAakB,CAAAA,CACb,gBAAiBC,CAAAA,CACjB,gBAAA,CAAkBC,EAClB,aAAA,CAAc,OAAA,CACd,UAAU,0DAAA,CACZ,CAAA,CAAA,CACF,CAEJ,CC/BO,SAASC,EAAa,CAC3B,KAAA,CAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,KAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,QAAA,CAAAC,CACF,CAAA,CAMG,CACD,OAAIJ,CAAAA,GAAU,OAAe,IAAA,CAEzBA,CAAAA,GAAU,aAAeG,CAAAA,CAEzBV,IAAAA,CAAC,OAAI,SAAA,CAAU,0CAAA,CACb,QAAA,CAAA,CAAAb,GAAAA,CAACc,EAAA,CAAe,OAAA,CAASO,EAAS,OAAA,CAAS,IAAA,CAAM,GAAI,WAAA,CAAa,CAAA,CAAG,CAAA,CACrErB,GAAAA,CAAC,QAAK,SAAA,CAAU,wCAAA,CACb,SAAAuB,CAAAA,CAAS,IAAA,CACZ,EACAV,IAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,gCAAA,CACb,UAAAY,cAAAA,CAAeJ,CAAAA,CAAS,MAAM,CAAA,CAAE,KAAA,CAAII,eAAeF,CAAAA,CAAS,IAAI,CAAA,CAAE,IAAA,CAClEF,EAAS,OAAA,CAAQ,IAAA,CAAA,CACpB,EACArB,GAAAA,CAACL,CAAAA,CAAA,CACC,OAAA,CAAQ,OAAA,CACR,IAAA,CAAK,MAAA,CACL,UAAU,yBAAA,CACV,OAAA,CAAU+B,GAAM,CACdA,CAAAA,CAAE,iBAAgB,CAClBF,CAAAA,KACF,CAAA,CACA,SAAAxB,GAAAA,CAAC2B,KAAAA,CAAA,CAAM,SAAA,CAAU,UAAA,CAAW,EAC9B,CAAA,CAAA,CACF,CAAA,CAIAP,CAAAA,GAAU,SAAA,EAAaG,EAEvBV,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,mCAAA,CACb,QAAA,CAAA,CAAAb,IAAC4B,eAAAA,CAAA,CAAgB,SAAA,CAAU,kCAAA,CAAmC,EAC9D5B,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,iEAAA,CACb,QAAA,CAAAuB,EAAS,IAAA,CACZ,CAAA,CACAvB,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,gCAAA,CACb,QAAA,CAAAyB,eAAeF,CAAAA,CAAS,IAAI,EAC/B,CAAA,CAAA,CACF,CAAA,CAIAH,CAAAA,GAAU,OAAA,CAEVP,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,2CACb,QAAA,CAAA,CAAAb,GAAAA,CAAC6B,gBAAA,CAAgB,SAAA,CAAU,2CAAA,CAA4C,CAAA,CACvE7B,IAAC,GAAA,CAAA,CAAE,SAAA,CAAU,oDACV,QAAA,CAAAsB,CAAAA,EAAS,gBACZ,CAAA,CAAA,CACF,CAAA,CAIAF,IAAU,YAAA,EAAgBA,CAAAA,GAAU,aAC/BpB,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,+BAAA,CAAgC,QAAA,CAAA,iBAAA,CAAU,EAG5D,IACT,CCxEA,SAAS8B,EAAAA,CAAS,CAChB,SAAA,CAAAlC,CAAAA,CACA,SAAAgB,CAAAA,CACA,KAAA,CAAAmB,EACA,GAAGhC,CACL,CAAA,CAAiC,CAC/B,OACEc,IAAAA,CAACmB,QAAAA,CAAkB,KAAlB,CACC,KAAA,CAAOD,EACP,WAAA,CAAU,UAAA,CACV,SAAA,CAAW1C,CAAAA,CAAG,uBAAwBO,CAAS,CAAA,CAC9C,GAAGG,CAAAA,CAEH,QAAA,CAAA,CAAAa,EACDZ,GAAAA,CAACiC,EAAAA,CAAA,CACC,QAAA,CAAAjC,IAACkC,EAAAA,CAAA,EAAkB,EACrB,CAAA,CAAA,CACF,CAEJ,CAEA,SAASD,EAAAA,CAAc,CAAE,SAAA,CAAArC,EAAW,GAAGG,CAAM,EAAkC,CAC7E,OACEC,IAACgC,QAAAA,CAAkB,KAAA,CAAlB,CACC,SAAA,CAAW3C,EACT,6EAAA,CACAO,CACF,EACA,WAAA,CAAU,gBAAA,CACT,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASmC,GAAkB,CACzB,SAAA,CAAAtC,EACA,GAAGG,CACL,EAAsC,CACpC,OACEC,GAAAA,CAACgC,QAAAA,CAAkB,UAAlB,CACC,WAAA,CAAU,qBACV,SAAA,CAAW3C,CAAAA,CAAG,mCAAoCO,CAAS,CAAA,CAC1D,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASoC,GAAc,CAAE,SAAA,CAAAvC,EAAW,GAAGG,CAAM,CAAA,CAAkC,CAC7E,OACEC,GAAAA,CAACgC,QAAAA,CAAkB,MAAlB,CACC,SAAA,CAAW3C,EAAG,6BAAA,CAA+BO,CAAS,CAAA,CACtD,WAAA,CAAU,iBACT,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASqC,GAAc,CAAE,SAAA,CAAAxC,CAAAA,CAAW,GAAGG,CAAM,CAAA,CAAkC,CAC7E,OACEC,GAAAA,CAACgC,QAAAA,CAAkB,MAAlB,CACC,SAAA,CAAW3C,CAAAA,CACT,4DAAA,CACAO,CACF,CAAA,CACA,WAAA,CAAU,iBACT,GAAGG,CAAAA,CACN,CAEJ,CC7DO,SAASsC,EAAkB,CAChC,KAAA,CAAAjB,EACA,KAAA,CAAAkB,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,MAAAjB,CAAAA,CACA,QAAA,CAAAE,CACF,CAAA,CAMG,CACD,OAAIJ,CAAAA,GAAU,MAAA,CAAe,IAAA,CAEzBA,CAAAA,GAAU,YAEVP,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,4BAAA,CACb,QAAA,CAAA,CAAAA,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,kCAAA,CACb,QAAA,CAAA,CAAAA,KAACiB,EAAAA,CAAA,CAAS,MAAOS,CAAAA,CAAc,OAAA,CAAS,UAAU,QAAA,CAChD,QAAA,CAAA,CAAA1B,IAAAA,CAACsB,EAAAA,CAAA,CACE,QAAA,CAAA,CAAAG,CAAAA,CAAM,OAAQE,CAAAA,EAAMA,CAAAA,CAAE,SAAW,SAAS,CAAA,CAAE,MAAA,CAAO,GAAA,CACnDF,EAAM,MAAA,CAAO,QAAA,CAAA,CAChB,EACAtC,GAAAA,CAACoC,EAAAA,CAAA,EAAc,CAAA,CAAA,CACjB,CAAA,CACApC,GAAAA,CAACL,CAAAA,CAAA,CACC,OAAA,CAAQ,OAAA,CACR,KAAK,MAAA,CACL,SAAA,CAAU,kBACV,OAAA,CAAU+B,CAAAA,EAAM,CACdA,CAAAA,CAAE,iBAAgB,CAClBF,CAAAA,KACF,CAAA,CACA,QAAA,CAAAxB,IAAC2B,KAAAA,CAAA,CAAM,SAAA,CAAU,QAAA,CAAS,EAC5B,CAAA,CAAA,CACF,CAAA,CACA3B,IAACyC,EAAAA,CAAA,CAAS,MAAOH,CAAAA,CAAO,CAAA,CAAA,CAC1B,CAAA,CAIAlB,CAAAA,GAAU,UAEVP,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,4BAAA,CACb,QAAA,CAAA,CAAAA,KAAC,MAAA,CAAA,CAAK,SAAA,CAAU,wBAAA,CAAyB,QAAA,CAAA,CAAA,MAAA,CAClCyB,EAAM,MAAA,CAAO,mBAAA,CAAA,CACpB,EACAtC,GAAAA,CAACyC,EAAAA,CAAA,CAAS,KAAA,CAAOH,CAAAA,CAAO,CAAA,CAAA,CAC1B,CAAA,CAIAlB,IAAU,OAAA,CAEVP,IAAAA,CAAC,OAAI,SAAA,CAAU,4BAAA,CACb,UAAAb,GAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,0BAAA,CACb,SAAAsB,CAAAA,EAAS,eAAA,CACZ,EACCgB,CAAAA,CAAM,MAAA,CAAS,GAAKtC,GAAAA,CAACyC,EAAAA,CAAA,CAAS,KAAA,CAAOH,EAAO,CAAA,CAAA,CAC/C,CAAA,CAIAlB,IAAU,YAAA,CACLpB,GAAAA,CAAC,QAAK,SAAA,CAAU,+BAAA,CAAgC,QAAA,CAAA,kBAAA,CAAW,CAAA,CAG7D,IACT,CAIA,SAASyC,GAAS,CAAE,KAAA,CAAAH,CAAM,CAAA,CAAsC,CAC9D,OACEtC,GAAAA,CAAC,MAAG,SAAA,CAAU,qBAAA,CACX,SAAAsC,CAAAA,CAAM,GAAA,CAAKE,GACV3B,IAAAA,CAAC,IAAA,CAAA,CAAc,SAAA,CAAU,+BAAA,CACvB,UAAAA,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,2BAAA,CACZ,QAAA,CAAA,CAAA2B,EAAE,MAAA,GAAW,SAAA,EACZxC,GAAAA,CAAC4B,eAAAA,CAAA,CAAgB,SAAA,CAAU,kCAAA,CAAmC,EAE/DY,CAAAA,CAAE,MAAA,GAAW,SACZxC,GAAAA,CAAC6B,eAAAA,CAAA,CAAgB,SAAA,CAAU,qCAAqC,CAAA,CAAA,CAEhEW,CAAAA,CAAE,SAAW,SAAA,EAAaA,CAAAA,CAAE,SAAW,WAAA,GACvCxC,GAAAA,CAACc,CAAAA,CAAA,CACC,QAAS0B,CAAAA,CAAE,MAAA,GAAW,YAAcA,CAAAA,CAAE,QAAA,CAAS,QAAU,CAAA,CACzD,IAAA,CAAM,EAAA,CACN,WAAA,CAAa,EACf,CAAA,CAEFxC,GAAAA,CAAC,QAAK,SAAA,CAAU,iEAAA,CACb,SAAAwC,CAAAA,CAAE,QAAA,CACL,CAAA,CACCA,CAAAA,CAAE,SAAW,WAAA,CACZ3B,IAAAA,CAAC,QAAK,SAAA,CAAU,gCAAA,CACb,UAAAY,cAAAA,CAAee,CAAAA,CAAE,QAAA,CAAS,MAAM,EAAE,IAAA,CAAG,GAAA,CACrCf,eAAee,CAAAA,CAAE,QAAQ,EAAE,IAAA,CAAGA,CAAAA,CAAE,QAAA,CAAS,OAAA,CAAQ,MACpD,CAAA,CAEAxC,GAAAA,CAAC,QAAK,SAAA,CAAU,gCAAA,CACb,SAAAyB,cAAAA,CAAee,CAAAA,CAAE,QAAQ,CAAA,CAC5B,GAEJ,CAAA,CACCA,CAAAA,CAAE,SAAW,OAAA,EAAWA,CAAAA,CAAE,OACzBxC,GAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,yDAAA,CAA2D,SAAAwC,CAAAA,CAAE,KAAA,CAAM,IA9B9EA,CAAAA,CAAE,EAgCX,CACD,CAAA,CACH,CAEJ,CCxHA,IAAME,GAAc,CAACC,CAAAA,CAAaC,EAAM,GAAA,GACtCD,CAAAA,CAAI,MAAA,CAASC,CAAAA,CAAMD,EAAI,KAAA,CAAM,CAAA,CAAGC,CAAG,CAAA,CAAI,QAAA,CAAMD,EAOxC,SAASE,CAAAA,CACdC,CAAAA,CAWAC,CAAAA,CACA,CACA,IAAMC,CAAAA,CAAaC,OAAsB,IAAI,CAAA,CACvCC,EAAUJ,CAAAA,CAAK,IAAA,GAAS,OAAA,CAGxBK,CAAAA,CAAeF,OAAOH,CAAAA,CAAK,KAAK,EACtC,GAAIK,CAAAA,CAAa,UAAYL,CAAAA,CAAK,KAAA,GAChCK,CAAAA,CAAa,OAAA,CAAUL,EAAK,KAAA,CACxBC,CAAAA,GACED,EAAK,KAAA,GAAU,MAAA,EAAUE,EAAW,OAAA,GACtCI,KAAAA,CAAM,QAAQJ,CAAAA,CAAW,OAAO,EAChCA,CAAAA,CAAW,OAAA,CAAU,MAEnBF,CAAAA,CAAK,KAAA,GAAU,YACbE,CAAAA,CAAW,OAAA,EAASI,KAAAA,CAAM,OAAA,CAAQJ,EAAW,OAAO,CAAA,CACpDE,EACFE,KAAAA,CAAM,OAAA,CAAQ,GAAGN,CAAAA,CAAK,KAAA,CAAM,MAAM,CAAA,iBAAA,CAAA,CAAqB,CACrD,WAAA,CAAarB,cAAAA,CAAeqB,EAAK,aAAA,CAAc,KAAK,CACtD,CAAC,CAAA,CACQA,CAAAA,CAAK,QAAA,EACdM,MAAM,OAAA,CAAQ,iBAAA,CAAmB,CAC/B,WAAA,CAAa3B,cAAAA,CAAeqB,EAAK,QAAA,CAAS,IAAI,CAChD,CAAC,EAEHE,CAAAA,CAAW,OAAA,CAAU,MAEnBF,CAAAA,CAAK,KAAA,GAAU,UAAS,CAE1B,GADIE,CAAAA,CAAW,OAAA,EAASI,MAAM,OAAA,CAAQJ,CAAAA,CAAW,OAAO,CAAA,CACpDE,CAAAA,EAAWJ,EAAK,KAAA,CAAM,MAAA,CAAS,CAAA,CAAG,CACpC,IAAMO,CAAAA,CAAYP,CAAAA,CAAK,MAAM,MAAA,CAC1BN,CAAAA,EAAMA,EAAE,MAAA,GAAW,SACtB,CAAA,CAAE,MAAA,CACIc,EAASR,CAAAA,CAAK,KAAA,CAAM,OAAQN,CAAAA,EAAMA,CAAAA,CAAE,SAAW,OAAO,CAAA,CAAE,MAAA,CAC9DY,KAAAA,CAAM,MAAM,6BAAA,CAA+B,CACzC,YAAa,CAAA,EAAGC,CAAS,eAAeC,CAAM,CAAA,OAAA,CAChD,CAAC,EACH,MACEF,KAAAA,CAAM,KAAA,CAAM,gBAAiB,CAC3B,WAAA,CAAaV,GAAYI,CAAAA,CAAK,KAAA,EAAS,eAAe,CACxD,CAAC,CAAA,CAEHE,CAAAA,CAAW,QAAU,KACvB,CAKJO,UAAU,IAAM,CACd,GAAI,CAACR,GAAWD,CAAAA,CAAK,KAAA,GAAU,YAAa,OAC5C,IAAMU,EAAKR,CAAAA,CAAW,OAAA,EAAW,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAA,CAErD,GADAA,CAAAA,CAAW,OAAA,CAAUQ,EACjBN,CAAAA,CAAS,CACX,IAAMO,CAAAA,CAAOX,EAAK,KAAA,CAAM,MAAA,CAAQN,GAAMA,CAAAA,CAAE,MAAA,GAAW,SAAS,CAAA,CAAE,MAAA,CAC9DY,KAAAA,CAAM,OAAA,CAAQ,mBAAcK,CAAI,CAAA,CAAA,EAAIX,EAAK,KAAA,CAAM,MAAM,GAAI,CACvD,EAAA,CAAAU,CAAAA,CACA,WAAA,CAAa,GAAG/B,cAAAA,CAAeqB,CAAAA,CAAK,cAAc,MAAM,CAAC,MAAMrB,cAAAA,CAAeqB,CAAAA,CAAK,cAAc,KAAK,CAAC,KAAKA,CAAAA,CAAK,aAAA,CAAc,OAAO,CAAA,EAAA,CAAA,CACtI,MAAA,CAAQ,CAAE,KAAA,CAAO,QAAA,CAAU,OAAA,CAAS,IAAMA,EAAK,MAAA,EAAS,CAC1D,CAAC,EACH,MAAWA,CAAAA,CAAK,QAAA,EACdM,KAAAA,CAAM,OAAA,CAAQ,kBAAc,CAC1B,EAAA,CAAAI,EACA,WAAA,CAAa,CAAA,EAAG/B,eAAeqB,CAAAA,CAAK,QAAA,CAAS,MAAM,CAAC,MAAMrB,cAAAA,CAAeqB,CAAAA,CAAK,SAAS,IAAI,CAAC,KAAKA,CAAAA,CAAK,QAAA,CAAS,OAAO,CAAA,EAAA,CAAA,CACtH,OAAQ,CAAE,KAAA,CAAO,SAAU,OAAA,CAAS,IAAMA,EAAK,MAAA,EAAS,CAC1D,CAAC,EAEL,CAAA,CAAG,CACDC,EACAD,CAAAA,CAAK,KAAA,CACLI,EACAJ,CAAAA,CAAK,QAAA,CAAS,MAAA,CACdA,CAAAA,CAAK,SAAS,OAAA,CACdA,CAAAA,CAAK,cAAc,MAAA,CACnBA,CAAAA,CAAK,cAAc,KAAA,CACnBA,CAAAA,CAAK,aAAA,CAAc,OAAA,CACnBA,EAAK,QAAA,CACLA,CAAAA,CAAK,MACLA,CAAAA,CAAK,MACP,CAAC,EACH,CC7EO,SAASY,EAAAA,CAAa,CAC3B,UAAA9D,CAAAA,CACA,KAAA,CAAA+D,CAAAA,CACA,QAAA,CAAAC,EACA,WAAA,CAAAC,CAAAA,CACA,MAAOC,CAAAA,CAAc,IAAA,CACrB,WAAAC,CAAAA,CAAa,IAAA,CACb,GAAGC,CACL,EAAsB,CACpB,IAAMlB,EAAOmB,iBAAAA,CAAkBD,CAAO,EAChCd,CAAAA,CAAUJ,CAAAA,CAAK,IAAA,GAAS,OAAA,CACxBoB,EAAaN,CAAAA,EAAYd,CAAAA,CAAK,YAEpCD,CAAAA,CAAeC,CAAAA,CAAMgB,CAAW,CAAA,CAEhC,IAAMK,CAAAA,CAASJ,CAAAA,CACbb,EACElD,GAAAA,CAACqC,CAAAA,CAAA,CACC,KAAA,CAAOS,CAAAA,CAAK,MACZ,KAAA,CAAOA,CAAAA,CAAK,KAAA,CACZ,aAAA,CAAeA,EAAK,aAAA,CACpB,KAAA,CAAOA,EAAK,KAAA,CACZ,QAAA,CAAUA,EAAK,MAAA,CACjB,CAAA,CAEA9C,GAAAA,CAACmB,CAAAA,CAAA,CACC,KAAA,CAAO2B,CAAAA,CAAK,MACZ,QAAA,CAAUA,CAAAA,CAAK,SACf,KAAA,CAAOA,CAAAA,CAAK,KAAA,CACZ,QAAA,CAAUA,EAAK,QAAA,CACf,QAAA,CAAUA,EAAK,MAAA,CACjB,CAAA,CAEA,KAEJ,OACEjC,IAAAA,CAAC,OAAI,SAAA,CAAWxB,CAAAA,CAAG,6BAA8BO,CAAS,CAAA,CACxD,UAAAiB,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,gCAAA,CACb,QAAA,CAAA,CAAAb,GAAAA,CAAC,OAAA,CAAA,CAAO,GAAG8C,CAAAA,CAAK,UAAA,CAAY,EAC5B9C,GAAAA,CAACE,CAAAA,CAAA,CACC,QAAA,CAAAW,IAAAA,CAACR,CAAAA,CAAA,CACC,UAAAQ,IAAAA,CAACP,CAAAA,CAAA,CACC,MAAA,CACEN,GAAAA,CAACL,EAAA,CACC,IAAA,CAAK,SAAA,CACL,QAAA,CAAUuE,EACV,OAAA,CAASpB,CAAAA,CAAK,eAChB,CAAA,CAEF,QAAA,CAAA,CAAA9C,IAACoE,UAAAA,CAAA,CAAW,WAAA,CAAU,cAAA,CAAe,EACpCT,CAAAA,GAAUT,CAAAA,CAAU,eAAiB,aAAA,CAAA,CAAA,CACxC,CAAA,CACAlD,IAACO,CAAAA,CAAA,CACE,QAAA,CAAAsD,CAAAA,GAAgBX,EAAU,cAAA,CAAiB,aAAA,CAAA,CAC9C,GACF,CAAA,CACF,CAAA,CAAA,CACF,EACCiB,CAAAA,CAAAA,CACH,CAEJ,CCrEO,SAASE,EAAAA,CAAe,CAC7B,SAAA,CAAAzE,CAAAA,CACA,MAAA+D,CAAAA,CACA,QAAA,CAAAC,CAAAA,CACA,KAAA,CAAOE,EAAc,IAAA,CACrB,UAAA,CAAAC,EAAa,IAAA,CACb,GAAGC,CACL,CAAA,CAAwB,CACtB,IAAMlB,CAAAA,CAAOmB,kBAAkBD,CAAO,CAAA,CAChCd,EAAUJ,CAAAA,CAAK,IAAA,GAAS,QACxBoB,CAAAA,CAAaN,CAAAA,EAAYd,CAAAA,CAAK,WAAA,CAEpCD,EAAeC,CAAAA,CAAMgB,CAAW,EAEhC,IAAMK,CAAAA,CAASJ,EACbb,CAAAA,CACElD,GAAAA,CAACqC,CAAAA,CAAA,CACC,MAAOS,CAAAA,CAAK,KAAA,CACZ,MAAOA,CAAAA,CAAK,KAAA,CACZ,cAAeA,CAAAA,CAAK,aAAA,CACpB,KAAA,CAAOA,CAAAA,CAAK,MACZ,QAAA,CAAUA,CAAAA,CAAK,OACjB,CAAA,CAEA9C,GAAAA,CAACmB,EAAA,CACC,KAAA,CAAO2B,CAAAA,CAAK,KAAA,CACZ,SAAUA,CAAAA,CAAK,QAAA,CACf,MAAOA,CAAAA,CAAK,KAAA,CACZ,SAAUA,CAAAA,CAAK,QAAA,CACf,QAAA,CAAUA,CAAAA,CAAK,OACjB,CAAA,CAEA,IAAA,CAEJ,OACEjC,IAAAA,CAAC,KAAA,CAAA,CACC,UAAWxB,CAAAA,CACT,qHAAA,CACA6E,CAAAA,CACI,+CAAA,CACA,oEACJtE,CACF,CAAA,CACA,QAASsE,CAAAA,CAAa,MAAA,CAAYpB,EAAK,cAAA,CACtC,GAAIoB,CAAAA,CAAa,GAAKpB,CAAAA,CAAK,YAAA,CAC5B,UAAA9C,GAAAA,CAAC,OAAA,CAAA,CAAO,GAAG8C,CAAAA,CAAK,UAAA,CAAY,CAAA,CAC5B9C,GAAAA,CAACoE,WAAA,CACC,SAAA,CAAW/E,EACT,8BAAA,CACA6E,CAAAA,EAAc,YAChB,CAAA,CACF,CAAA,CACAlE,GAAAA,CAAC,GAAA,CAAA,CACC,UAAWX,CAAAA,CACT,+BAAA,CACA6E,GAAc,YAChB,CAAA,CACC,SAAAP,CAAAA,GACET,CAAAA,CACG,sCAAA,CACA,gCAAA,CAAA,CACR,EACCiB,CAAAA,EAAUnE,GAAAA,CAAC,OAAI,SAAA,CAAU,kBAAA,CAAoB,SAAAmE,CAAAA,CAAO,CAAA,CAAA,CACvD,CAEJ,CC7EA,IAAMzB,EAAAA,CAAc,CAACC,EAAaC,CAAAA,CAAM,GAAA,GACtCD,EAAI,MAAA,CAASC,CAAAA,CAAMD,CAAAA,CAAI,KAAA,CAAM,EAAGC,CAAG,CAAA,CAAI,SAAMD,CAAAA,CAgBxC,SAAS2B,GAAe,CAC7B,GAAA,CAAAC,CAAAA,CACA,SAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CACA,MAAAd,CAAAA,CACA,SAAA,CAAA/D,EACA,QAAA,CAAAgE,CAAAA,CACA,KAAA,CAAOE,CAAAA,CAAc,KACrB,UAAA,CAAAC,CAAAA,CAAa,IACf,CAAA,CAAwB,CACtB,IAAMW,CAAAA,CAAKC,WAAAA,CAAY,CACrB,GAAA,CAAAJ,EACA,WAAA,CAAa,IAAM,CACbT,CAAAA,EAAaV,KAAAA,CAAM,QAAQ,kBAAkB,EACnD,CAAA,CACA,OAAA,CAAS,CAACwB,CAAAA,CAAMtD,CAAAA,GAAU,CACpBwC,CAAAA,EACFV,KAAAA,CAAM,MAAM,iBAAA,CAAmB,CAC7B,WAAA,CAAaV,EAAAA,CACXpB,aAAiB,KAAA,CAAQA,CAAAA,CAAM,QAAU,eAC3C,CACF,CAAC,EAEL,CACF,CAAC,CAAA,CAEKuD,EAAYH,CAAAA,CAAG,KAAA,GAAU,aAE/B,OACE7D,IAAAA,CAAC,OAAI,SAAA,CAAWxB,CAAAA,CAAG,8BAAA,CAAgCO,CAAS,EAC1D,QAAA,CAAA,CAAAI,GAAAA,CAACL,EAAA,CACC,IAAA,CAAK,UACL,OAAA,CAAQ,SAAA,CACR,QAAA,CAAUiE,CAAAA,EAAYiB,EACtB,OAAA,CAAS,IAAMH,EAAG,QAAA,CAASF,CAAAA,CAAWC,CAAQ,CAAA,CAC9C,QAAA,CAAA5D,KAAC,MAAA,CAAA,CAAK,SAAA,CAAU,iCACb,QAAA,CAAA,CAAAgE,CAAAA,CACC7E,IAAC8E,UAAAA,CAAA,CAAW,UAAU,cAAA,CAAe,WAAA,CAAU,cAAA,CAAe,CAAA,CAE9D9E,IAAC+E,YAAAA,CAAA,CAAa,YAAU,cAAA,CAAe,CAAA,CAExCpB,GAAS,UAAA,CAAA,CACZ,CAAA,CACF,CAAA,CAECI,CAAAA,EAAcW,EAAG,KAAA,GAAU,OAAA,EAC1B7D,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,2CACb,QAAA,CAAA,CAAAb,GAAAA,CAAC6B,eAAAA,CAAA,CAAgB,UAAU,2CAAA,CAA4C,CAAA,CACvE7B,IAAC,GAAA,CAAA,CAAE,SAAA,CAAU,oDACV,QAAA,CAAA0E,CAAAA,CAAG,KAAA,EAAS,iBAAA,CACf,GACF,CAAA,CAAA,CAEJ,CAEJ,CCvEA,IAAMhC,GAAc,CAACC,CAAAA,CAAaC,CAAAA,CAAM,GAAA,GACtCD,EAAI,MAAA,CAASC,CAAAA,CAAMD,EAAI,KAAA,CAAM,CAAA,CAAGC,CAAG,CAAA,CAAI,QAAA,CAAMD,CAAAA,CA2BxC,SAASqC,GAAuB,CACrC,GAAA,CAAAT,EACA,SAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,QAAA,CAAAQ,CAAAA,CACA,MAAA,CAAAC,EACA,KAAA,CAAAvB,CAAAA,CACA,UAAA/D,CAAAA,CACA,aAAA,CAAAuF,EACA,QAAA,CAAAvB,CAAAA,CACA,WAAA,CAAAC,CAAAA,CAAc,gBACd,KAAA,CAAOC,CAAAA,CAAc,KACrB,UAAA,CAAAC,CAAAA,CAAa,KACb,cAAA,CAAAqB,CAAAA,CACA,eAAA,CAAAC,CAAAA,CACA,WAAAC,CAAAA,CACA,SAAA,CAAAC,EACA,OAAA,CAAAC,CAAAA,CACA,SAAAhE,CACF,CAAA,CAAgC,CAC9B,IAAMiE,EAAchB,CAAAA,EAAYD,CAAAA,CAAU,MAAM,GAAG,CAAA,CAAE,KAAI,EAAKA,CAAAA,CAExDE,CAAAA,CAAKgB,gBAAAA,CAAiB,CAC1B,GAAA,CAAAnB,CAAAA,CACA,OAAAW,CAAAA,CACA,cAAA,CAAAE,EACA,eAAA,CAAAC,CAAAA,CACA,UAAA,CAAAC,CAAAA,CACA,UAAW,CAACK,CAAAA,CAAKC,IAAmB,CAC9B9B,CAAAA,GACFV,MAAM,OAAA,CAAQ,CAAA,GAAA,EAAMoB,CAAS,CAAA,CAAE,EAC/BpB,KAAAA,CAAM,OAAA,CAAQ,oBAAqB,CACjC,WAAA,CAAa,GAAGwC,CAAc,CAAA,EAAGX,GAAY,IAAA,CAAO,CAAA,MAAA,EAAMxD,eAAewD,CAAQ,CAAC,GAAK,EAAE,CAAA,CAC3F,CAAC,CAAA,CAAA,CAEHM,CAAAA,GAAYI,CAAAA,CAAKC,CAAc,EACjC,CAAA,CACA,OAAA,CAAS,CAACD,CAAAA,CAAKrE,CAAAA,CAAOF,KAAU,CAC1B0C,CAAAA,GACFV,KAAAA,CAAM,OAAA,CAAQ,MAAMoB,CAAS,CAAA,CAAE,EAC/BpB,KAAAA,CAAM,KAAA,CAAM,kBAAmB,CAC7B,WAAA,CAAaV,EAAAA,CACXpB,CAAAA,YAAiB,MAAQA,CAAAA,CAAM,OAAA,CAAU,eAC3C,CACF,CAAC,GAEHkE,CAAAA,GAAUG,CAAAA,CAAKrE,CAAAA,CAAOF,EAAK,EAC7B,CAAA,CACA,QAAA,CAAWuE,GAAQ,CACb7B,CAAAA,GACFV,MAAM,OAAA,CAAQ,CAAA,GAAA,EAAMoB,CAAS,CAAA,CAAE,EAC/BpB,KAAAA,CAAM,IAAA,CAAK,qBAAsB,CAAE,WAAA,CAAaqC,CAAY,CAAC,CAAA,CAAA,CAE/DjE,CAAAA,GAAWmE,CAAG,EAChB,CACF,CAAC,EAEKE,CAAAA,CAAgBnB,CAAAA,CAAG,QAAU,aAAA,EAAiBA,CAAAA,CAAG,KAAA,GAAU,YAAA,CAE3DoB,GAAc,IAAM,CACxB,GAAID,CAAAA,CAAe,CACjBnB,EAAG,MAAA,EAAO,CACV,MACF,CACAA,EAAG,QAAA,CAASF,CAAAA,CAAWC,CAAQ,EACjC,CAAA,CAEA,OACE5D,IAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAWxB,CAAAA,CAAG,+BAAgCO,CAAS,CAAA,CAC1D,UAAAI,GAAAA,CAACE,CAAAA,CAAA,CACC,QAAA,CAAAW,IAAAA,CAACR,CAAAA,CAAA,CACC,UAAAQ,IAAAA,CAACP,CAAAA,CAAA,CACC,MAAA,CACEN,GAAAA,CAACL,EAAA,CACC,IAAA,CAAK,SAAA,CACL,OAAA,CAAQ,UACR,QAAA,CAAUiE,CAAAA,CACV,UAAWvE,CAAAA,CAAG,mCAAmC,EACjD,OAAA,CAASyG,EAAAA,CACX,CAAA,CAED,QAAA,CAAA,CAAAD,GACC7F,GAAAA,CAAC,MAAA,CAAA,CACC,UAAWX,CAAAA,CACT,gEAAA,CACA8F,CACF,CAAA,CACA,KAAA,CAAO,CAAE,KAAA,CAAO,GAAGT,CAAAA,CAAG,QAAA,CAAS,OAAO,CAAA,CAAA,CAAI,CAAA,CAC5C,EAEF7D,IAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,8CAAA,CACd,UAAAb,GAAAA,CAAC+E,YAAAA,CAAA,CAAa,WAAA,CAAU,cAAA,CAAe,EACtCc,CAAAA,CACGpE,cAAAA,CAAeiD,CAAAA,CAAG,QAAA,CAAS,MAAM,CAAA,CAChCf,CAAAA,EAAS,YAChB,CAAA,CAAA,CACF,CAAA,CACA3D,IAACO,CAAAA,CAAA,CACE,SAAAsF,CAAAA,CAAgB,iBAAA,CAAoBhC,EACvC,CAAA,CAAA,CACF,CAAA,CACF,EAECE,CAAAA,EAAcW,CAAAA,CAAG,QAAU,OAAA,EAC1B7D,IAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,2CACb,QAAA,CAAA,CAAAb,GAAAA,CAAC6B,gBAAA,CAAgB,SAAA,CAAU,4CAA4C,CAAA,CACvE7B,GAAAA,CAAC,GAAA,CAAA,CAAE,SAAA,CAAU,oDACV,QAAA,CAAA0E,CAAAA,CAAG,OAAS,iBAAA,CACf,CAAA,CAAA,CACF,GAEJ,CAEJ,CC9IA,SAASqB,EAAAA,CAAY,CAAE,GAAGhG,CAAM,CAAA,CAAoC,CAClE,OAAOC,GAAAA,CAACgG,WAAAA,CAAqB,KAArB,CAA0B,WAAA,CAAU,cAAA,CAAgB,GAAGjG,EAAO,CACxE,CAEA,SAASkG,EAAAA,CAAmB,CAAE,GAAGlG,CAAM,CAAA,CAAuC,CAC5E,OACEC,IAACgG,WAAAA,CAAqB,OAAA,CAArB,CAA6B,WAAA,CAAU,sBAAA,CAAwB,GAAGjG,CAAAA,CAAO,CAE9E,CAEA,SAASmG,GAAkB,CAAE,GAAGnG,CAAM,CAAA,CAAsC,CAC1E,OACEC,GAAAA,CAACgG,WAAAA,CAAqB,MAAA,CAArB,CAA4B,YAAU,qBAAA,CAAuB,GAAGjG,EAAO,CAE5E,CAEA,SAASoG,EAAAA,CAAmB,CAC1B,SAAA,CAAAvG,CAAAA,CACA,GAAGG,CACL,CAAA,CAAwC,CACtC,OACEC,GAAAA,CAACgG,YAAqB,QAAA,CAArB,CACC,WAAA,CAAU,sBAAA,CACV,UAAW3G,CAAAA,CACT,uLAAA,CACAO,CACF,CAAA,CACC,GAAGG,EACN,CAEJ,CAEA,SAASqG,EAAAA,CAAmB,CAC1B,SAAA,CAAAxG,CAAAA,CACA,KAAAE,CAAAA,CAAO,SAAA,CACP,GAAGC,CACL,CAAA,CAEG,CACD,OACEc,KAACqF,EAAAA,CAAA,CACC,UAAAlG,GAAAA,CAACmG,EAAAA,CAAA,EAAmB,CAAA,CACpBnG,GAAAA,CAACgG,WAAAA,CAAqB,KAAA,CAArB,CACC,WAAA,CAAU,sBAAA,CACV,YAAWlG,CAAAA,CACX,SAAA,CAAWT,EACT,icAAA,CACAO,CACF,EACC,GAAGG,CAAAA,CACN,GACF,CAEJ,CAEA,SAASsG,EAAAA,CAAkB,CACzB,UAAAzG,CAAAA,CACA,GAAGG,CACL,CAAA,CAAgC,CAC9B,OACEC,GAAAA,CAAC,OACC,WAAA,CAAU,qBAAA,CACV,UAAWX,CAAAA,CACT,mZAAA,CACAO,CACF,CAAA,CACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASuG,EAAAA,CAAkB,CACzB,SAAA,CAAA1G,CAAAA,CACA,GAAGG,CACL,EAAgC,CAC9B,OACEC,IAAC,KAAA,CAAA,CACC,WAAA,CAAU,sBACV,SAAA,CAAWX,CAAAA,CACT,6JAAA,CACAO,CACF,EACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASwG,GAAiB,CACxB,SAAA,CAAA3G,CAAAA,CACA,GAAGG,CACL,CAAA,CAAgC,CAC9B,OACEC,GAAAA,CAAC,KAAA,CAAA,CACC,YAAU,oBAAA,CACV,SAAA,CAAWX,CAAAA,CACT,2KAAA,CACAO,CACF,CAAA,CACC,GAAGG,EACN,CAEJ,CAEA,SAASyG,EAAAA,CAAiB,CACxB,SAAA,CAAA5G,CAAAA,CACA,GAAGG,CACL,CAAA,CAA4D,CAC1D,OACEC,GAAAA,CAACgG,YAAqB,KAAA,CAArB,CACC,WAAA,CAAU,oBAAA,CACV,UAAW3G,CAAAA,CACT,8JAAA,CACAO,CACF,CAAA,CACC,GAAGG,EACN,CAEJ,CAEA,SAAS0G,EAAAA,CAAuB,CAC9B,SAAA,CAAA7G,CAAAA,CACA,GAAGG,CACL,CAAA,CAAkE,CAChE,OACEC,GAAAA,CAACgG,WAAAA,CAAqB,WAAA,CAArB,CACC,WAAA,CAAU,0BAAA,CACV,UAAW3G,CAAAA,CACT,wIAAA,CACAO,CACF,CAAA,CACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAAS2G,EAAAA,CAAkB,CACzB,SAAA,CAAA9G,CAAAA,CACA,GAAGG,CACL,CAAA,CAAwC,CACtC,OACEC,IAACL,CAAAA,CAAA,CACC,YAAU,qBAAA,CACV,SAAA,CAAWN,EAAGO,CAAS,CAAA,CACtB,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAAS4G,GAAkB,CACzB,SAAA,CAAA/G,EACA,OAAA,CAAAC,CAAAA,CAAU,SAAA,CACV,IAAA,CAAAC,EAAO,SAAA,CACP,GAAGC,CACL,CAAA,CACiE,CAC/D,OACEC,GAAAA,CAACgG,WAAAA,CAAqB,KAAA,CAArB,CACC,YAAU,qBAAA,CACV,SAAA,CAAW3G,EAAGO,CAAS,CAAA,CACvB,OAAQI,GAAAA,CAACL,CAAAA,CAAA,CAAO,OAAA,CAASE,CAAAA,CAAS,KAAMC,CAAAA,CAAM,CAAA,CAC7C,GAAGC,CAAAA,CACN,CAEJ,CC7JA,IAAM2C,GAAc,CAACC,CAAAA,CAAaC,EAAM,GAAA,GACtCD,CAAAA,CAAI,MAAA,CAASC,CAAAA,CAAMD,EAAI,KAAA,CAAM,CAAA,CAAGC,CAAG,CAAA,CAAI,QAAA,CAAMD,EAwCxC,SAASiE,EAAAA,CAAa,CAC3B,GAAA,CAAArC,EACA,SAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,QAAA,CAAAQ,EACA,MAAA,CAAAC,CAAAA,CACA,KAAA,CAAAvB,CAAAA,CACA,UAAA/D,CAAAA,CACA,QAAA,CAAAgE,EACA,WAAA,CAAAC,CAAAA,CAAc,cACd,KAAA,CAAOC,CAAAA,CAAc,IAAA,CACrB,UAAA,CAAAC,EAAa,IAAA,CACb,YAAA,CAAA8C,EAAe,cAAA,CACf,kBAAA,CAAAC,EACA,YAAA,CAAAC,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,UAAAzB,CAAAA,CACA,OAAA,CAAAC,CACF,CAAA,CAAsB,CACpB,IAAMC,CAAAA,CAAchB,CAAAA,EAAYD,CAAAA,CAAU,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,IAASA,CAAAA,CAExDyC,CAAAA,CAAMC,UAAU,CACpB,GAAA,CAAA3C,CAAAA,CACA,MAAA,CAAAW,EACA,YAAA,CAAA6B,CAAAA,CACA,cAAAC,CAAAA,CACA,SAAA,CAAYrB,GAAQ,CACd7B,CAAAA,EACFV,KAAAA,CAAM,OAAA,CAAQ,eAAgB,CAAE,WAAA,CAAaqC,CAAY,CAAC,CAAA,CAE5DF,IAAYI,CAAG,EACjB,CAAA,CACA,OAAA,CAAS,CAACA,CAAAA,CAAKrE,CAAAA,CAAOF,KAAU,CAC1B0C,CAAAA,EACFV,MAAM,KAAA,CAAM,eAAA,CAAiB,CAC3B,WAAA,CAAaV,GACXpB,CAAAA,YAAiB,KAAA,CAAQA,EAAM,OAAA,CAAU,eAC3C,CACF,CAAC,CAAA,CAEHkE,CAAAA,GAAUG,CAAAA,CAAKrE,EAAOF,EAAK,EAC7B,CACF,CAAC,CAAA,CAEK+F,EAAaF,CAAAA,CAAI,KAAA,GAAU,UAAA,CAC3B/C,CAAAA,CAAaN,GAAYuD,CAAAA,CAEzBC,EAAAA,CACJN,GACA,CAAA,iCAAA,EAAoCrB,CAAW,IAAIR,CAAAA,EAAY,IAAA,CAAO,CAAA,EAAA,EAAKxD,cAAAA,CAAewD,CAAQ,CAAC,CAAA,CAAA,CAAA,CAAM,EAAE,CAAA,+BAAA,CAAA,CAE7G,OACEpE,KAAC,KAAA,CAAA,CAAI,SAAA,CAAWxB,CAAAA,CAAG,8BAAA,CAAgCO,CAAS,CAAA,CAC1D,QAAA,CAAA,CAAAI,IAAC,KAAA,CAAA,CAAI,SAAA,CAAU,iCACb,QAAA,CAAAa,IAAAA,CAACkF,GAAA,CACC,IAAA,CAAMkB,EAAI,KAAA,GAAU,YAAA,CACpB,aAAeI,CAAAA,EAAS,CACjBA,GAAMJ,CAAAA,CAAI,YAAA,GACjB,CAAA,CACA,UAAAjH,GAAAA,CAACE,CAAAA,CAAA,CACC,QAAA,CAAAW,IAAAA,CAACR,EAAA,CACC,QAAA,CAAA,CAAAQ,IAAAA,CAACP,CAAAA,CAAA,CACC,MAAA,CACEN,GAAAA,CAACiG,GAAA,CACC,QAAA,CAAU/B,EACV,OAAA,CAAS,IAAM+C,CAAAA,CAAI,aAAA,CAAczC,CAAS,CAAA,CAC1C,MAAA,CACExE,IAACL,CAAAA,CAAA,CACC,KAAK,SAAA,CACL,OAAA,CAAQ,aAAA,CACR,QAAA,CAAUuE,EACZ,CAAA,CAEJ,CAAA,CAED,UAAAiD,CAAAA,CACCnH,GAAAA,CAAC8E,WAAA,CACC,SAAA,CAAU,cAAA,CACV,WAAA,CAAU,eACZ,CAAA,CAEA9E,GAAAA,CAACsH,WAAA,CAAW,WAAA,CAAU,eAAe,CAAA,CAEtC3D,CAAAA,EAAS,QAAA,CAAA,CACZ,CAAA,CACA3D,IAACO,CAAAA,CAAA,CAAgB,SAAAsD,CAAAA,CAAY,CAAA,CAAA,CAC/B,EACF,CAAA,CAEAhD,IAAAA,CAACuF,EAAAA,CAAA,CACC,UAAAvF,IAAAA,CAACwF,EAAAA,CAAA,CACC,QAAA,CAAA,CAAArG,GAAAA,CAACuG,GAAA,CACC,QAAA,CAAAvG,GAAAA,CAACsH,UAAAA,CAAA,EAAW,CAAA,CACd,CAAA,CACAtH,IAACwG,EAAAA,CAAA,CAAkB,SAAAK,CAAAA,CAAa,CAAA,CAChC7G,GAAAA,CAACyG,EAAAA,CAAA,CAAwB,QAAA,CAAAW,EAAAA,CAAY,GACvC,CAAA,CACAvG,IAAAA,CAACyF,GAAA,CACC,QAAA,CAAA,CAAAtG,GAAAA,CAAC2G,EAAAA,CAAA,CAAkB,QAAA,CAAA,QAAA,CAAM,CAAA,CACzB3G,IAAC0G,EAAAA,CAAA,CACC,QAAQ,aAAA,CACR,OAAA,CAAS,IAAMO,CAAAA,CAAI,eAAc,CAAG,QAAA,CAAA,QAAA,CAEtC,GACF,CAAA,CAAA,CACF,CAAA,CAAA,CACF,EACF,CAAA,CAEClD,CAAAA,EAAckD,CAAAA,CAAI,KAAA,GAAU,WAC3BpG,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,2CAAA,CACb,QAAA,CAAA,CAAAb,IAACuH,gBAAAA,CAAA,CAAiB,SAAA,CAAU,kCAAA,CAAmC,EAC/D1G,IAAAA,CAAC,GAAA,CAAA,CAAE,UAAU,iDAAA,CAAkD,QAAA,CAAA,CAAA,QAAA,CAE7Db,IAAC,MAAA,CAAA,CAAK,SAAA,CAAU,iDAAA,CACb,QAAA,CAAAyF,EACH,CAAA,CAAO,gBAAA,CAAA,CAET,GACF,CAAA,CAGD1B,CAAAA,EAAckD,EAAI,KAAA,GAAU,OAAA,EAC3BpG,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,0CAAA,CACb,QAAA,CAAA,CAAAb,IAAC6B,eAAAA,CAAA,CAAgB,UAAU,2CAAA,CAA4C,CAAA,CACvE7B,IAAC,GAAA,CAAA,CAAE,SAAA,CAAU,oDACV,QAAA,CAAAiH,CAAAA,CAAI,OAAS,eAAA,CAChB,CAAA,CAAA,CACF,GAEJ,CAEJ","file":"index.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","\"use client\"\n\nimport { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button cursor-pointer inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n xs: \"h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-2.5\",\n sm: \"h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3\",\n lg: \"h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2 [&_svg:not([class*='size-'])]:size-4\",\n icon: \"size-7 [&_svg:not([class*='size-'])]:size-3.5\",\n \"icon-xs\": \"size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5\",\n \"icon-sm\": \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n \"icon-lg\": \"size-8 [&_svg:not([class*='size-'])]:size-4\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","\"use client\"\n\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction TooltipProvider({\n delay = 0,\n ...props\n}: TooltipPrimitive.Provider.Props) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delay={delay}\n {...props}\n />\n )\n}\n\nfunction Tooltip({ ...props }: TooltipPrimitive.Root.Props) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n}\n\nfunction TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />\n}\n\nfunction TooltipContent({\n className,\n side = \"top\",\n sideOffset = 4,\n align = \"center\",\n alignOffset = 0,\n children,\n ...props\n}: TooltipPrimitive.Popup.Props &\n Pick<\n TooltipPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\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 >\n {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-start-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-end-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5\" />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n )\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }\n","\"use client\"\n\nexport function CircleProgress({\n percent,\n size = 20,\n strokeWidth = 2.5,\n}: {\n percent: number\n size?: number\n strokeWidth?: number\n}) {\n const r = (size - strokeWidth) / 2\n const c = 2 * Math.PI * r\n const offset = c - (percent / 100) * c\n return (\n <svg width={size} height={size} className=\"shrink-0 -rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n className=\"text-muted-foreground/20\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n strokeDasharray={c}\n strokeDashoffset={offset}\n strokeLinecap=\"round\"\n className=\"text-primary transition-[stroke-dashoffset] duration-200\"\n />\n </svg>\n )\n}\n","\"use client\";\n\nimport { XIcon, CheckCircleIcon, AlertCircleIcon } from \"lucide-react\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { UploadPhase, UploadProgress } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport { CircleProgress } from \"@/components/ui/circle-progress\";\n\nexport function UploadStatus({\n phase,\n progress,\n error,\n fileInfo,\n onCancel,\n}: {\n phase: UploadPhase;\n progress: UploadProgress;\n error: string | null;\n fileInfo: { name: string; size: number } | null;\n onCancel?: () => void;\n}) {\n if (phase === \"idle\") return null;\n\n if (phase === \"uploading\" && fileInfo) {\n return (\n <div className=\"flex w-full items-center gap-1.5 text-xs\">\n <CircleProgress percent={progress.percent} size={14} strokeWidth={2} />\n <span className=\"max-w-32 min-w-16 truncate sm:max-w-48\">\n {fileInfo.name}\n </span>\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(progress.loaded)} / {formatFileSize(fileInfo.size)} (\n {progress.percent}%)\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"ml-auto size-6 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\n }}>\n <XIcon className=\"size-3.5\" />\n </Button>\n </div>\n );\n }\n\n if (phase === \"success\" && fileInfo) {\n return (\n <div className=\"flex items-center gap-1.5 text-xs\">\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n <span className=\"[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48\">\n {fileInfo.name}\n </span>\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(fileInfo.size)}\n </span>\n </div>\n );\n }\n\n if (phase === \"error\") {\n return (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {error ?? \"Upload failed\"}\n </p>\n </div>\n );\n }\n\n if (phase === \"validating\" || phase === \"presigning\") {\n return <span className=\"text-xs text-muted-foreground\">Preparing…</span>;\n }\n\n return null;\n}\n","\"use client\"\n\nimport { Progress as ProgressPrimitive } from \"@base-ui/react/progress\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Progress({\n className,\n children,\n value,\n ...props\n}: ProgressPrimitive.Root.Props) {\n return (\n <ProgressPrimitive.Root\n value={value}\n data-slot=\"progress\"\n className={cn(\"flex flex-wrap gap-3\", className)}\n {...props}\n >\n {children}\n <ProgressTrack>\n <ProgressIndicator />\n </ProgressTrack>\n </ProgressPrimitive.Root>\n )\n}\n\nfunction ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {\n return (\n <ProgressPrimitive.Track\n className={cn(\n \"relative flex h-1 w-full items-center overflow-x-hidden rounded-md bg-muted\",\n className\n )}\n data-slot=\"progress-track\"\n {...props}\n />\n )\n}\n\nfunction ProgressIndicator({\n className,\n ...props\n}: ProgressPrimitive.Indicator.Props) {\n return (\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className={cn(\"h-full bg-primary transition-all\", className)}\n {...props}\n />\n )\n}\n\nfunction ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {\n return (\n <ProgressPrimitive.Label\n className={cn(\"text-xs/relaxed font-medium\", className)}\n data-slot=\"progress-label\"\n {...props}\n />\n )\n}\n\nfunction ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {\n return (\n <ProgressPrimitive.Value\n className={cn(\n \"ms-auto text-xs/relaxed text-muted-foreground tabular-nums\",\n className\n )}\n data-slot=\"progress-value\"\n {...props}\n />\n )\n}\n\nexport {\n Progress,\n ProgressTrack,\n ProgressIndicator,\n ProgressLabel,\n ProgressValue,\n}\n","\"use client\";\n\nimport { XIcon, CheckCircleIcon, AlertCircleIcon } from \"lucide-react\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { UploadProgress, MultiUploadFileState } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Progress,\n ProgressLabel,\n ProgressValue,\n} from \"@/components/ui/progress\";\nimport { CircleProgress } from \"@/components/ui/circle-progress\";\n\nexport function MultiUploadStatus({\n phase,\n files,\n totalProgress,\n error,\n onCancel,\n}: {\n phase: string;\n files: MultiUploadFileState[];\n totalProgress: UploadProgress;\n error: string | null;\n onCancel?: () => void;\n}) {\n if (phase === \"idle\") return null;\n\n if (phase === \"uploading\") {\n return (\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"flex w-full items-center gap-1.5\">\n <Progress value={totalProgress.percent} className=\"flex-1\">\n <ProgressLabel>\n {files.filter((f) => f.status === \"success\").length}/\n {files.length} files\n </ProgressLabel>\n <ProgressValue />\n </Progress>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\n }}>\n <XIcon className=\"size-4\" />\n </Button>\n </div>\n <FileList files={files} />\n </div>\n );\n }\n\n if (phase === \"success\") {\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <span className=\"text-xs text-green-600\">\n All {files.length} file(s) uploaded\n </span>\n <FileList files={files} />\n </div>\n );\n }\n\n if (phase === \"error\") {\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <span className=\"text-xs text-destructive\">\n {error ?? \"Upload failed\"}\n </span>\n {files.length > 0 && <FileList files={files} />}\n </div>\n );\n }\n\n if (phase === \"validating\") {\n return <span className=\"text-xs text-muted-foreground\">Validating…</span>;\n }\n\n return null;\n}\n\n// ─── File List ──────────────────────────────────────────────────────────\n\nfunction FileList({ files }: { files: MultiUploadFileState[] }) {\n return (\n <ul className=\"flex flex-col gap-1\">\n {files.map((f) => (\n <li key={f.id} className=\"flex flex-col gap-0.5 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n {f.status === \"success\" && (\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n )}\n {f.status === \"error\" && (\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n )}\n {(f.status === \"pending\" || f.status === \"uploading\") && (\n <CircleProgress\n percent={f.status === \"uploading\" ? f.progress.percent : 0}\n size={14}\n strokeWidth={2}\n />\n )}\n <span className=\"[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48\">\n {f.fileName}\n </span>\n {f.status === \"uploading\" ? (\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(f.progress.loaded)} /{\" \"}\n {formatFileSize(f.fileSize)} ({f.progress.percent}%)\n </span>\n ) : (\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(f.fileSize)}\n </span>\n )}\n </div>\n {f.status === \"error\" && f.error && (\n <span className=\"truncate [overflow-wrap:anywhere] pl-5 text-destructive\">{f.error}</span>\n )}\n </li>\n ))}\n </ul>\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { formatFileSize } from \"@better-s3/react\";\n\nconst truncateMsg = (msg: string, max = 100) =>\n msg.length > max ? msg.slice(0, max) + \"…\" : msg;\nimport type { UseUploadControlsReturn } from \"@better-s3/react\";\n\n/**\n * Drives sonner toasts for upload progress/success/error.\n * Shared between UploadButton and UploadDropzone.\n */\nexport function useUploadToast(\n ctrl: Pick<\n UseUploadControlsReturn,\n | \"mode\"\n | \"phase\"\n | \"fileInfo\"\n | \"progress\"\n | \"files\"\n | \"totalProgress\"\n | \"error\"\n | \"cancel\"\n >,\n enabled: boolean,\n) {\n const toastIdRef = useRef<string | null>(null);\n const isMulti = ctrl.mode === \"multi\";\n\n // Phase-transition toasts (runs synchronously during render to fire exactly once)\n const prevPhaseRef = useRef(ctrl.phase);\n if (prevPhaseRef.current !== ctrl.phase) {\n prevPhaseRef.current = ctrl.phase;\n if (enabled) {\n if (ctrl.phase === \"idle\" && toastIdRef.current) {\n toast.dismiss(toastIdRef.current);\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"success\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n if (isMulti) {\n toast.success(`${ctrl.files.length} file(s) uploaded`, {\n description: formatFileSize(ctrl.totalProgress.total),\n });\n } else if (ctrl.fileInfo) {\n toast.success(\"Upload complete\", {\n description: formatFileSize(ctrl.fileInfo.size),\n });\n }\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"error\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n if (isMulti && ctrl.files.length > 0) {\n const succeeded = ctrl.files.filter(\n (f) => f.status === \"success\",\n ).length;\n const failed = ctrl.files.filter((f) => f.status === \"error\").length;\n toast.error(\"Upload finished with errors\", {\n description: `${succeeded} succeeded, ${failed} failed`,\n });\n } else {\n toast.error(\"Upload failed\", {\n description: truncateMsg(ctrl.error ?? \"Unknown error\"),\n });\n }\n toastIdRef.current = null;\n }\n }\n }\n\n // Progress toast (updated on each progress tick)\n useEffect(() => {\n if (!enabled || ctrl.phase !== \"uploading\") return;\n const id = toastIdRef.current ?? `upload-${Date.now()}`;\n toastIdRef.current = id;\n if (isMulti) {\n const done = ctrl.files.filter((f) => f.status === \"success\").length;\n toast.loading(`Uploading… ${done}/${ctrl.files.length}`, {\n id,\n description: `${formatFileSize(ctrl.totalProgress.loaded)} / ${formatFileSize(ctrl.totalProgress.total)} (${ctrl.totalProgress.percent}%)`,\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n } else if (ctrl.fileInfo) {\n toast.loading(\"Uploading…\", {\n id,\n description: `${formatFileSize(ctrl.progress.loaded)} / ${formatFileSize(ctrl.fileInfo.size)} (${ctrl.progress.percent}%)`,\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n }\n }, [\n enabled,\n ctrl.phase,\n isMulti,\n ctrl.progress.loaded,\n ctrl.progress.percent,\n ctrl.totalProgress.loaded,\n ctrl.totalProgress.total,\n ctrl.totalProgress.percent,\n ctrl.fileInfo,\n ctrl.files,\n ctrl.cancel,\n ]);\n}\n","\"use client\";\n\nimport { UploadIcon } from \"lucide-react\";\nimport type { UseUploadControlsOptions } from \"@better-s3/react\";\nimport { useUploadControls } from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { UploadStatus } from \"./upload-status\";\nimport { MultiUploadStatus } from \"./multi-upload-status\";\nimport { useUploadToast } from \"./use-upload-toast\";\n\nexport type UploadButtonProps = UseUploadControlsOptions & {\n className?: string;\n label?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline status below the button (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function UploadButton({\n className,\n label,\n disabled,\n tooltipText,\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadButtonProps) {\n const ctrl = useUploadControls(options);\n const isMulti = ctrl.mode === \"multi\";\n const isDisabled = disabled || ctrl.isUploading;\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <MultiUploadStatus\n phase={ctrl.phase}\n files={ctrl.files}\n totalProgress={ctrl.totalProgress}\n error={ctrl.error}\n onCancel={ctrl.cancel}\n />\n ) : (\n <UploadStatus\n phase={ctrl.phase}\n progress={ctrl.progress}\n error={ctrl.error}\n fileInfo={ctrl.fileInfo}\n onCancel={ctrl.cancel}\n />\n )\n ) : null;\n\n return (\n <div className={cn(\"inline-flex flex-col gap-2\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <input {...ctrl.inputProps} />\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n size=\"default\"\n disabled={isDisabled}\n onClick={ctrl.openFilePicker}\n />\n }>\n <UploadIcon data-icon=\"inline-start\" />\n {label ?? (isMulti ? \"Upload files\" : \"Upload file\")}\n </TooltipTrigger>\n <TooltipContent>\n {tooltipText ?? (isMulti ? \"Upload files\" : \"Upload file\")}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n {status}\n </div>\n );\n}\n","\"use client\";\n\nimport { UploadIcon } from \"lucide-react\";\nimport type { UseUploadControlsOptions } from \"@better-s3/react\";\nimport { useUploadControls } from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { UploadStatus } from \"./upload-status\";\nimport { MultiUploadStatus } from \"./multi-upload-status\";\nimport { useUploadToast } from \"./use-upload-toast\";\n\nexport type UploadDropzoneProps = UseUploadControlsOptions & {\n className?: string;\n label?: string;\n disabled?: boolean;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline status inside the dropzone (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function UploadDropzone({\n className,\n label,\n disabled,\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadDropzoneProps) {\n const ctrl = useUploadControls(options);\n const isMulti = ctrl.mode === \"multi\";\n const isDisabled = disabled || ctrl.isUploading;\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <MultiUploadStatus\n phase={ctrl.phase}\n files={ctrl.files}\n totalProgress={ctrl.totalProgress}\n error={ctrl.error}\n onCancel={ctrl.cancel}\n />\n ) : (\n <UploadStatus\n phase={ctrl.phase}\n progress={ctrl.progress}\n error={ctrl.error}\n fileInfo={ctrl.fileInfo}\n onCancel={ctrl.cancel}\n />\n )\n ) : null;\n\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed p-6 text-center transition-colors\",\n isDisabled\n ? \"cursor-not-allowed border-muted-foreground/25\"\n : \"cursor-pointer border-muted-foreground/25 hover:border-primary/50\",\n className,\n )}\n onClick={isDisabled ? undefined : ctrl.openFilePicker}\n {...(isDisabled ? {} : ctrl.dropHandlers)}>\n <input {...ctrl.inputProps} />\n <UploadIcon\n className={cn(\n \"size-6 text-muted-foreground\",\n isDisabled && \"opacity-50\",\n )}\n />\n <p\n className={cn(\n \"text-sm text-muted-foreground\",\n isDisabled && \"opacity-50\",\n )}>\n {label ??\n (isMulti\n ? \"Click or drag & drop files to upload\"\n : \"Click or drag & drop to upload\")}\n </p>\n {status && <div className=\"w-full text-left\">{status}</div>}\n </div>\n );\n}\n","\"use client\";\n\nimport { AlertCircleIcon, DownloadIcon, LoaderIcon } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport type { S3Api } from \"@better-s3/react\";\nimport { useDownload } from \"@better-s3/react\";\n\nconst truncateMsg = (msg: string, max = 100) =>\n msg.length > max ? msg.slice(0, max) + \"…\" : msg;\nimport { Button } from \"@/components/ui/button\";\n\ntype DownloadButtonProps = {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n label?: string;\n className?: string;\n disabled?: boolean;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status below the button (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function DownloadButton({\n api,\n objectKey,\n fileName,\n label,\n className,\n disabled,\n toast: enableToast = true,\n showStatus = true,\n}: DownloadButtonProps) {\n const dl = useDownload({\n api,\n onInitiated: () => {\n if (enableToast) toast.success(\"Download started\");\n },\n onError: (_key, error) => {\n if (enableToast) {\n toast.error(\"Download failed\", {\n description: truncateMsg(\n error instanceof Error ? error.message : \"Unknown error\",\n ),\n });\n }\n },\n });\n\n const isPending = dl.phase === \"presigning\";\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <Button\n size=\"default\"\n variant=\"outline\"\n disabled={disabled || isPending}\n onClick={() => dl.download(objectKey, fileName)}>\n <span className=\"inline-flex items-center gap-1\">\n {isPending ? (\n <LoaderIcon className=\"animate-spin\" data-icon=\"inline-start\" />\n ) : (\n <DownloadIcon data-icon=\"inline-start\" />\n )}\n {label ?? \"Download\"}\n </span>\n </Button>\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {dl.error ?? \"Download failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { DownloadIcon, AlertCircleIcon } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { S3Api, FetchDownloadHooks } from \"@better-s3/react\";\nimport { useFetchDownload } from \"@better-s3/react\";\n\nconst truncateMsg = (msg: string, max = 100) =>\n msg.length > max ? msg.slice(0, max) + \"…\" : msg;\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\ntype ProgressDownloadButtonProps = FetchDownloadHooks & {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n /** Target bucket (overrides server default) */\n bucket?: string;\n label?: string;\n className?: string;\n fillClassName?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status below the button (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function ProgressDownloadButton({\n api,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n fillClassName,\n disabled,\n tooltipText = \"Download file\",\n toast: enableToast = true,\n showStatus = true,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess,\n onError,\n onCancel,\n}: ProgressDownloadButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const dl = useFetchDownload({\n api,\n bucket,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess: (key, actualFileName) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.success(\"Download complete\", {\n description: `${actualFileName}${fileSize != null ? ` · ${formatFileSize(fileSize)}` : \"\"}`,\n });\n }\n onSuccess?.(key, actualFileName);\n },\n onError: (key, error, phase) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.error(\"Download failed\", {\n description: truncateMsg(\n error instanceof Error ? error.message : \"Unknown error\",\n ),\n });\n }\n onError?.(key, error, phase);\n },\n onCancel: (key) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.info(\"Download cancelled\", { description: displayName });\n }\n onCancel?.(key);\n },\n });\n\n const isDownloading = dl.phase === \"downloading\" || dl.phase === \"presigning\";\n\n const handleClick = () => {\n if (isDownloading) {\n dl.cancel();\n return;\n }\n dl.download(objectKey, fileName);\n };\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n size=\"default\"\n variant=\"outline\"\n disabled={disabled}\n className={cn(\"relative min-w-24 overflow-hidden\")}\n onClick={handleClick}\n />\n }>\n {isDownloading && (\n <span\n className={cn(\n \"absolute inset-0 bg-primary/15 transition-[width] duration-200\",\n fillClassName,\n )}\n style={{ width: `${dl.progress.percent}%` }}\n />\n )}\n <span className=\"relative z-10 inline-flex items-center gap-1\">\n <DownloadIcon data-icon=\"inline-start\" />\n {isDownloading\n ? formatFileSize(dl.progress.loaded)\n : (label ?? \"Download\")}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {isDownloading ? \"Cancel download\" : tooltipText}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {dl.error ?? \"Download failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport { AlertDialog as AlertDialogPrimitive } from \"@base-ui/react/alert-dialog\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\n\nfunction AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {\n return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />\n}\n\nfunction AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {\n return (\n <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n )\n}\n\nfunction AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {\n return (\n <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n )\n}\n\nfunction AlertDialogOverlay({\n className,\n ...props\n}: AlertDialogPrimitive.Backdrop.Props) {\n return (\n <AlertDialogPrimitive.Backdrop\n data-slot=\"alert-dialog-overlay\"\n className={cn(\n \"fixed inset-0 isolate z-50 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogContent({\n className,\n size = \"default\",\n ...props\n}: AlertDialogPrimitive.Popup.Props & {\n size?: \"default\" | \"sm\"\n}) {\n return (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Popup\n data-slot=\"alert-dialog-content\"\n data-size={size}\n className={cn(\n \"group/alert-dialog-content fixed top-1/2 start-1/2 z-50 grid w-full -translate-x-1/2 rtl:translate-x-1/2 -translate-y-1/2 gap-3 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-64 data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n className\n )}\n {...props}\n />\n </AlertDialogPortal>\n )\n}\n\nfunction AlertDialogHeader({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-header\"\n className={cn(\n \"grid grid-rows-[auto_1fr] place-items-center gap-1 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-start sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogFooter({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogMedia({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-media\"\n className={cn(\n \"mb-2 inline-flex size-8 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n return (\n <AlertDialogPrimitive.Title\n data-slot=\"alert-dialog-title\"\n className={cn(\n \"font-heading text-sm font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n return (\n <AlertDialogPrimitive.Description\n data-slot=\"alert-dialog-description\"\n className={cn(\n \"text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogAction({\n className,\n ...props\n}: React.ComponentProps<typeof Button>) {\n return (\n <Button\n data-slot=\"alert-dialog-action\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AlertDialogCancel({\n className,\n variant = \"outline\",\n size = \"default\",\n ...props\n}: AlertDialogPrimitive.Close.Props &\n Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n return (\n <AlertDialogPrimitive.Close\n data-slot=\"alert-dialog-cancel\"\n className={cn(className)}\n render={<Button variant={variant} size={size} />}\n {...props}\n />\n )\n}\n\nexport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogTitle,\n AlertDialogTrigger,\n}\n","\"use client\";\n\nimport {\n Trash2Icon,\n LoaderIcon,\n AlertCircleIcon,\n CheckCircle2Icon,\n} from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { S3Api, DeleteHooks } from \"@better-s3/react\";\nimport { useDelete } from \"@better-s3/react\";\n\nconst truncateMsg = (msg: string, max = 100) =>\n msg.length > max ? msg.slice(0, max) + \"…\" : msg;\nimport { Button } from \"@/components/ui/button\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@/components/ui/alert-dialog\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\ntype DeleteButtonProps = DeleteHooks & {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n /** Target bucket (overrides server default) */\n bucket?: string;\n label?: string;\n className?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status below the button (default: `true`) */\n showStatus?: boolean;\n confirmTitle?: string;\n confirmDescription?: string;\n};\n\nexport function DeleteButton({\n api,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n disabled,\n tooltipText = \"Delete file\",\n toast: enableToast = true,\n showStatus = true,\n confirmTitle = \"Delete file?\",\n confirmDescription,\n beforeDelete,\n onDeleteStart,\n onSuccess,\n onError,\n}: DeleteButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const del = useDelete({\n api,\n bucket,\n beforeDelete,\n onDeleteStart,\n onSuccess: (key) => {\n if (enableToast) {\n toast.success(\"File deleted\", { description: displayName });\n }\n onSuccess?.(key);\n },\n onError: (key, error, phase) => {\n if (enableToast) {\n toast.error(\"Delete failed\", {\n description: truncateMsg(\n error instanceof Error ? error.message : \"Unknown error\",\n ),\n });\n }\n onError?.(key, error, phase);\n },\n });\n\n const isDeleting = del.phase === \"deleting\";\n const isDisabled = disabled || isDeleting;\n\n const description =\n confirmDescription ??\n `Are you sure you want to delete \"${displayName}\"${fileSize != null ? ` (${formatFileSize(fileSize)})` : \"\"}? This action cannot be undone.`;\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <AlertDialog\n open={del.phase === \"confirming\"}\n onOpenChange={(open) => {\n if (!open) del.cancelDelete();\n }}>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger\n render={\n <AlertDialogTrigger\n disabled={isDisabled}\n onClick={() => del.requestDelete(objectKey)}\n render={\n <Button\n size=\"default\"\n variant=\"destructive\"\n disabled={isDisabled}\n />\n }\n />\n }>\n {isDeleting ? (\n <LoaderIcon\n className=\"animate-spin\"\n data-icon=\"inline-start\"\n />\n ) : (\n <Trash2Icon data-icon=\"inline-start\" />\n )}\n {label ?? \"Delete\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogMedia>\n <Trash2Icon />\n </AlertDialogMedia>\n <AlertDialogTitle>{confirmTitle}</AlertDialogTitle>\n <AlertDialogDescription>{description}</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => del.confirmDelete()}>\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n\n {showStatus && del.phase === \"success\" && (\n <div className=\"flex min-w-0 items-center gap-1.5 text-xs\">\n <CheckCircle2Icon className=\"size-3.5 shrink-0 text-green-600\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-green-600\">\n &ldquo;\n <span className=\"inline-block max-w-[14ch] truncate align-bottom\">\n {displayName}\n </span>\n &rdquo; deleted\n </p>\n </div>\n )}\n\n {showStatus && del.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {del.error ?? \"Delete failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/ui/button.tsx","../src/ui/tooltip.tsx","../src/ui/circle-progress.tsx","../src/upload/upload-status.tsx","../src/ui/progress.tsx","../src/upload/multi-upload-status.tsx","../src/upload/use-upload-toast.ts","../src/upload/upload-button.tsx","../src/upload/upload-dropzone.tsx","../src/download/download-button.tsx","../src/download/progress-download-button.tsx","../src/ui/alert-dialog.tsx","../src/delete/delete-button.tsx"],"names":["cn","inputs","twMerge","clsx","buttonVariants","cva","Button","className","variant","size","props","jsx","ButtonPrimitive","TooltipProvider","delay","TooltipPrimitive","Tooltip","TooltipTrigger","TooltipContent","side","sideOffset","align","alignOffset","children","jsxs","CircleProgress","percent","strokeWidth","c","offset","UploadStatus","phase","progress","error","fileInfo","onCancel","formatFileSize","e","XIcon","CheckCircleIcon","AlertCircleIcon","Progress","value","ProgressPrimitive","ProgressTrack","ProgressIndicator","ProgressLabel","ProgressValue","MultiUploadStatus","files","totalProgress","f","FileList","truncateMsg","msg","max","useUploadToast","ctrl","enabled","toastIdRef","useRef","isMulti","prevPhaseRef","toast","succeeded","failed","useEffect","id","done","UploadButton","label","disabled","tooltipText","enableToast","showStatus","options","useUploadControls","isDisabled","status","UploadIcon","UploadDropzone","DownloadButton","api","objectKey","fileName","dl","useDownload","_key","isPending","LoaderIcon","DownloadIcon","ProgressDownloadButton","fileSize","bucket","fillClassName","beforeDownload","onDownloadStart","onProgress","onSuccess","onError","displayName","useFetchDownload","key","actualFileName","isDownloading","handleClick","AlertDialog","AlertDialogPrimitive","AlertDialogTrigger","AlertDialogPortal","AlertDialogOverlay","AlertDialogContent","AlertDialogHeader","AlertDialogFooter","AlertDialogMedia","AlertDialogTitle","AlertDialogDescription","AlertDialogAction","AlertDialogCancel","DeleteButton","confirmTitle","confirmDescription","beforeDelete","onDeleteStart","del","useDelete","isDeleting","description","open","Trash2Icon","CheckCircle2Icon"],"mappings":"qnBAGO,SAASA,CAAAA,CAAAA,GAAMC,EAAsB,CAC1C,OAAOC,OAAAA,CAAQC,IAAAA,CAAKF,CAAM,CAAC,CAC7B,CCEA,IAAMG,EAAAA,CAAiBC,IACrB,mnBAAA,CACA,CACE,QAAA,CAAU,CACR,QAAS,CACP,OAAA,CAAS,yDACT,OAAA,CACE,6HAAA,CACF,UACE,iIAAA,CACF,KAAA,CACE,kHAAA,CACF,WAAA,CACE,8NACF,IAAA,CAAM,iDACR,EACA,IAAA,CAAM,CACJ,QACE,6IAAA,CACF,EAAA,CAAI,wJAAA,CACJ,EAAA,CAAI,4IACJ,EAAA,CAAI,yIAAA,CACJ,KAAM,+CAAA,CACN,SAAA,CAAW,2DACX,SAAA,CAAW,6CAAA,CACX,SAAA,CAAW,6CACb,CACF,CAAA,CACA,eAAA,CAAiB,CACf,OAAA,CAAS,SAAA,CACT,KAAM,SACR,CACF,CACF,CAAA,CAEA,SAASC,CAAAA,CAAO,CACd,UAAAC,CAAAA,CACA,OAAA,CAAAC,EAAU,SAAA,CACV,IAAA,CAAAC,CAAAA,CAAO,SAAA,CACP,GAAGC,CACL,CAAA,CAAgE,CAC9D,OACEC,GAAAA,CAACC,OAAA,CACC,WAAA,CAAU,QAAA,CACV,SAAA,CAAWZ,EAAGI,EAAAA,CAAe,CAAE,QAAAI,CAAAA,CAAS,IAAA,CAAAC,EAAM,SAAA,CAAAF,CAAU,CAAC,CAAC,EACzD,GAAGG,CAAAA,CACN,CAEJ,CCjDA,SAASG,CAAAA,CAAgB,CACvB,MAAAC,CAAAA,CAAQ,CAAA,CACR,GAAGJ,CACL,EAAoC,CAClC,OACEC,IAACI,OAAAA,CAAiB,QAAA,CAAjB,CACC,WAAA,CAAU,kBAAA,CACV,KAAA,CAAOD,CAAAA,CACN,GAAGJ,CAAAA,CACN,CAEJ,CAEA,SAASM,CAAAA,CAAQ,CAAE,GAAGN,CAAM,CAAA,CAAgC,CAC1D,OAAOC,GAAAA,CAACI,OAAAA,CAAiB,KAAjB,CAAsB,WAAA,CAAU,UAAW,GAAGL,CAAAA,CAAO,CAC/D,CAEA,SAASO,CAAAA,CAAe,CAAE,GAAGP,CAAM,CAAA,CAAmC,CACpE,OAAOC,GAAAA,CAACI,OAAAA,CAAiB,OAAA,CAAjB,CAAyB,WAAA,CAAU,iBAAA,CAAmB,GAAGL,CAAAA,CAAO,CAC1E,CAEA,SAASQ,CAAAA,CAAe,CACtB,SAAA,CAAAX,EACA,IAAA,CAAAY,CAAAA,CAAO,MACP,UAAA,CAAAC,CAAAA,CAAa,EACb,KAAA,CAAAC,CAAAA,CAAQ,QAAA,CACR,WAAA,CAAAC,EAAc,CAAA,CACd,QAAA,CAAAC,EACA,GAAGb,CACL,EAIK,CACH,OACEC,GAAAA,CAACI,OAAAA,CAAiB,OAAjB,CACC,QAAA,CAAAJ,IAACI,OAAAA,CAAiB,UAAA,CAAjB,CACC,KAAA,CAAOM,CAAAA,CACP,WAAA,CAAaC,CAAAA,CACb,KAAMH,CAAAA,CACN,UAAA,CAAYC,EACZ,SAAA,CAAU,cAAA,CAEV,SAAAI,IAAAA,CAACT,OAAAA,CAAiB,KAAA,CAAjB,CACC,YAAU,iBAAA,CACV,SAAA,CAAWf,EACT,gwBAAA,CACAO,CACF,EACC,GAAGG,CAAAA,CAEH,QAAA,CAAA,CAAAa,CAAAA,CACDZ,IAACI,OAAAA,CAAiB,KAAA,CAAjB,CAAuB,SAAA,CAAU,yhBAAA,CAA0hB,GAC9jB,CAAA,CACF,CAAA,CACF,CAEJ,CC7DO,SAASU,CAAAA,CAAe,CAC7B,OAAA,CAAAC,EACA,IAAA,CAAAjB,CAAAA,CAAO,GACP,WAAA,CAAAkB,CAAAA,CAAc,GAChB,CAAA,CAIG,CACD,IAAM,CAAA,CAAA,CAAKlB,EAAOkB,CAAAA,EAAe,CAAA,CAC3BC,EAAI,CAAA,CAAI,IAAA,CAAK,GAAK,CAAA,CAClBC,CAAAA,CAASD,CAAAA,CAAKF,CAAAA,CAAU,IAAOE,CAAAA,CACrC,OACEJ,KAAC,KAAA,CAAA,CAAI,KAAA,CAAOf,EAAM,MAAA,CAAQA,CAAAA,CAAM,SAAA,CAAU,qBAAA,CACxC,UAAAE,GAAAA,CAAC,QAAA,CAAA,CACC,GAAIF,CAAAA,CAAO,CAAA,CACX,GAAIA,CAAAA,CAAO,CAAA,CACX,CAAA,CACA,IAAA,CAAK,OACL,MAAA,CAAO,cAAA,CACP,YAAakB,CAAAA,CACb,SAAA,CAAU,2BACZ,CAAA,CACAhB,GAAAA,CAAC,UACC,EAAA,CAAIF,CAAAA,CAAO,EACX,EAAA,CAAIA,CAAAA,CAAO,EACX,CAAA,CACA,IAAA,CAAK,OACL,MAAA,CAAO,cAAA,CACP,WAAA,CAAakB,CAAAA,CACb,gBAAiBC,CAAAA,CACjB,gBAAA,CAAkBC,EAClB,aAAA,CAAc,OAAA,CACd,UAAU,0DAAA,CACZ,CAAA,CAAA,CACF,CAEJ,CC/BO,SAASC,EAAa,CAC3B,KAAA,CAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,KAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,QAAA,CAAAC,CACF,CAAA,CAMG,CACD,OAAIJ,CAAAA,GAAU,OAAe,IAAA,CAEzBA,CAAAA,GAAU,aAAeG,CAAAA,CAEzBV,IAAAA,CAAC,OAAI,SAAA,CAAU,0CAAA,CACb,QAAA,CAAA,CAAAb,GAAAA,CAACc,EAAA,CAAe,OAAA,CAASO,EAAS,OAAA,CAAS,IAAA,CAAM,GAAI,WAAA,CAAa,CAAA,CAAG,CAAA,CACrErB,GAAAA,CAAC,QAAK,SAAA,CAAU,wCAAA,CACb,SAAAuB,CAAAA,CAAS,IAAA,CACZ,EACAV,IAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,gCAAA,CACb,UAAAY,cAAAA,CAAeJ,CAAAA,CAAS,MAAM,CAAA,CAAE,KAAA,CAAII,eAAeF,CAAAA,CAAS,IAAI,CAAA,CAAE,IAAA,CAClEF,EAAS,OAAA,CAAQ,IAAA,CAAA,CACpB,EACArB,GAAAA,CAACL,CAAAA,CAAA,CACC,OAAA,CAAQ,OAAA,CACR,IAAA,CAAK,MAAA,CACL,UAAU,yBAAA,CACV,OAAA,CAAU+B,GAAM,CACdA,CAAAA,CAAE,iBAAgB,CAClBF,CAAAA,KACF,CAAA,CACA,SAAAxB,GAAAA,CAAC2B,KAAAA,CAAA,CAAM,SAAA,CAAU,UAAA,CAAW,EAC9B,CAAA,CAAA,CACF,CAAA,CAIAP,CAAAA,GAAU,SAAA,EAAaG,EAEvBV,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,mCAAA,CACb,QAAA,CAAA,CAAAb,IAAC4B,eAAAA,CAAA,CAAgB,SAAA,CAAU,kCAAA,CAAmC,EAC9D5B,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,iEAAA,CACb,QAAA,CAAAuB,EAAS,IAAA,CACZ,CAAA,CACAvB,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,gCAAA,CACb,QAAA,CAAAyB,eAAeF,CAAAA,CAAS,IAAI,EAC/B,CAAA,CAAA,CACF,CAAA,CAIAH,CAAAA,GAAU,OAAA,CAEVP,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,2CACb,QAAA,CAAA,CAAAb,GAAAA,CAAC6B,gBAAA,CAAgB,SAAA,CAAU,2CAAA,CAA4C,CAAA,CACvE7B,IAAC,GAAA,CAAA,CAAE,SAAA,CAAU,oDACV,QAAA,CAAAsB,CAAAA,EAAS,gBACZ,CAAA,CAAA,CACF,CAAA,CAIAF,IAAU,YAAA,EAAgBA,CAAAA,GAAU,aAC/BpB,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,+BAAA,CAAgC,QAAA,CAAA,iBAAA,CAAU,EAG5D,IACT,CCxEA,SAAS8B,EAAAA,CAAS,CAChB,SAAA,CAAAlC,CAAAA,CACA,SAAAgB,CAAAA,CACA,KAAA,CAAAmB,EACA,GAAGhC,CACL,CAAA,CAAiC,CAC/B,OACEc,IAAAA,CAACmB,QAAAA,CAAkB,KAAlB,CACC,KAAA,CAAOD,EACP,WAAA,CAAU,UAAA,CACV,SAAA,CAAW1C,CAAAA,CAAG,uBAAwBO,CAAS,CAAA,CAC9C,GAAGG,CAAAA,CAEH,QAAA,CAAA,CAAAa,EACDZ,GAAAA,CAACiC,EAAAA,CAAA,CACC,QAAA,CAAAjC,IAACkC,EAAAA,CAAA,EAAkB,EACrB,CAAA,CAAA,CACF,CAEJ,CAEA,SAASD,EAAAA,CAAc,CAAE,SAAA,CAAArC,EAAW,GAAGG,CAAM,EAAkC,CAC7E,OACEC,IAACgC,QAAAA,CAAkB,KAAA,CAAlB,CACC,SAAA,CAAW3C,EACT,6EAAA,CACAO,CACF,EACA,WAAA,CAAU,gBAAA,CACT,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASmC,GAAkB,CACzB,SAAA,CAAAtC,EACA,GAAGG,CACL,EAAsC,CACpC,OACEC,GAAAA,CAACgC,QAAAA,CAAkB,UAAlB,CACC,WAAA,CAAU,qBACV,SAAA,CAAW3C,CAAAA,CAAG,mCAAoCO,CAAS,CAAA,CAC1D,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASoC,GAAc,CAAE,SAAA,CAAAvC,EAAW,GAAGG,CAAM,CAAA,CAAkC,CAC7E,OACEC,GAAAA,CAACgC,QAAAA,CAAkB,MAAlB,CACC,SAAA,CAAW3C,EAAG,6BAAA,CAA+BO,CAAS,CAAA,CACtD,WAAA,CAAU,iBACT,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASqC,GAAc,CAAE,SAAA,CAAAxC,CAAAA,CAAW,GAAGG,CAAM,CAAA,CAAkC,CAC7E,OACEC,GAAAA,CAACgC,QAAAA,CAAkB,MAAlB,CACC,SAAA,CAAW3C,CAAAA,CACT,4DAAA,CACAO,CACF,CAAA,CACA,WAAA,CAAU,iBACT,GAAGG,CAAAA,CACN,CAEJ,CCjEO,SAASsC,EAAkB,CAChC,KAAA,CAAAjB,EACA,KAAA,CAAAkB,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,MAAAjB,CAAAA,CACA,QAAA,CAAAE,CACF,CAAA,CAMG,CACD,OAAIJ,CAAAA,GAAU,MAAA,CAAe,IAAA,CAEzBA,CAAAA,GAAU,YAEVP,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,4BAAA,CACb,QAAA,CAAA,CAAAA,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,kCAAA,CACb,QAAA,CAAA,CAAAA,KAACiB,EAAAA,CAAA,CAAS,MAAOS,CAAAA,CAAc,OAAA,CAAS,UAAU,QAAA,CAChD,QAAA,CAAA,CAAA1B,IAAAA,CAACsB,EAAAA,CAAA,CACE,QAAA,CAAA,CAAAG,CAAAA,CAAM,OAAQE,CAAAA,EAAMA,CAAAA,CAAE,SAAW,SAAS,CAAA,CAAE,MAAA,CAAO,GAAA,CACnDF,EAAM,MAAA,CAAO,QAAA,CAAA,CAChB,EACAtC,GAAAA,CAACoC,EAAAA,CAAA,EAAc,CAAA,CAAA,CACjB,CAAA,CACApC,GAAAA,CAACL,CAAAA,CAAA,CACC,OAAA,CAAQ,OAAA,CACR,KAAK,MAAA,CACL,SAAA,CAAU,kBACV,OAAA,CAAU+B,CAAAA,EAAM,CACdA,CAAAA,CAAE,iBAAgB,CAClBF,CAAAA,KACF,CAAA,CACA,QAAA,CAAAxB,IAAC2B,KAAAA,CAAA,CAAM,SAAA,CAAU,QAAA,CAAS,EAC5B,CAAA,CAAA,CACF,CAAA,CACA3B,IAACyC,EAAAA,CAAA,CAAS,MAAOH,CAAAA,CAAO,CAAA,CAAA,CAC1B,CAAA,CAIAlB,CAAAA,GAAU,UAEVP,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,4BAAA,CACb,QAAA,CAAA,CAAAA,KAAC,MAAA,CAAA,CAAK,SAAA,CAAU,wBAAA,CAAyB,QAAA,CAAA,CAAA,MAAA,CAClCyB,EAAM,MAAA,CAAO,mBAAA,CAAA,CACpB,EACAtC,GAAAA,CAACyC,EAAAA,CAAA,CAAS,KAAA,CAAOH,CAAAA,CAAO,CAAA,CAAA,CAC1B,CAAA,CAIAlB,IAAU,OAAA,CAEVP,IAAAA,CAAC,OAAI,SAAA,CAAU,4BAAA,CACb,UAAAb,GAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,0BAAA,CACb,SAAAsB,CAAAA,EAAS,eAAA,CACZ,EACCgB,CAAAA,CAAM,MAAA,CAAS,GAAKtC,GAAAA,CAACyC,EAAAA,CAAA,CAAS,KAAA,CAAOH,EAAO,CAAA,CAAA,CAC/C,CAAA,CAIAlB,IAAU,YAAA,CACLpB,GAAAA,CAAC,QAAK,SAAA,CAAU,+BAAA,CAAgC,QAAA,CAAA,kBAAA,CAAW,CAAA,CAG7D,IACT,CAIA,SAASyC,GAAS,CAAE,KAAA,CAAAH,CAAM,CAAA,CAAsC,CAC9D,OACEtC,GAAAA,CAAC,MAAG,SAAA,CAAU,qBAAA,CACX,SAAAsC,CAAAA,CAAM,GAAA,CAAKE,GACV3B,IAAAA,CAAC,IAAA,CAAA,CAAc,UAAU,+BAAA,CACvB,QAAA,CAAA,CAAAA,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,4BACZ,QAAA,CAAA,CAAA2B,CAAAA,CAAE,SAAW,SAAA,EACZxC,GAAAA,CAAC4B,eAAAA,CAAA,CAAgB,UAAU,kCAAA,CAAmC,CAAA,CAE/DY,EAAE,MAAA,GAAW,OAAA,EACZxC,IAAC6B,eAAAA,CAAA,CAAgB,SAAA,CAAU,oCAAA,CAAqC,GAEhEW,CAAAA,CAAE,MAAA,GAAW,WAAaA,CAAAA,CAAE,MAAA,GAAW,cACvCxC,GAAAA,CAACc,CAAAA,CAAA,CACC,OAAA,CAAS0B,EAAE,MAAA,GAAW,WAAA,CAAcA,EAAE,QAAA,CAAS,OAAA,CAAU,EACzD,IAAA,CAAM,EAAA,CACN,WAAA,CAAa,CAAA,CACf,EAEFxC,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,iEAAA,CACb,QAAA,CAAAwC,EAAE,QAAA,CACL,CAAA,CACCA,CAAAA,CAAE,MAAA,GAAW,YACZ3B,IAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,gCAAA,CACb,QAAA,CAAA,CAAAY,eAAee,CAAAA,CAAE,QAAA,CAAS,MAAM,CAAA,CAAE,KAAG,GAAA,CACrCf,cAAAA,CAAee,EAAE,QAAQ,CAAA,CAAE,KAAGA,CAAAA,CAAE,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAA,CACpD,EAEAxC,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,gCAAA,CACb,QAAA,CAAAyB,eAAee,CAAAA,CAAE,QAAQ,CAAA,CAC5B,CAAA,CAAA,CAEJ,EACCA,CAAAA,CAAE,MAAA,GAAW,SAAWA,CAAAA,CAAE,KAAA,EACzBxC,IAAC,MAAA,CAAA,CAAK,SAAA,CAAU,yDAAA,CACb,QAAA,CAAAwC,EAAE,KAAA,CACL,CAAA,CAAA,CAAA,CAhCKA,EAAE,EAkCX,CACD,EACH,CAEJ,CCtHA,IAAME,EAAAA,CAAc,CAACC,CAAAA,CAAaC,CAAAA,CAAM,MACtCD,CAAAA,CAAI,MAAA,CAASC,CAAAA,CAAMD,CAAAA,CAAI,MAAM,CAAA,CAAGC,CAAG,EAAI,QAAA,CAAMD,CAAAA,CAOxC,SAASE,CAAAA,CACdC,CAAAA,CAWAC,CAAAA,CACA,CACA,IAAMC,CAAAA,CAAaC,MAAAA,CAAsB,IAAI,CAAA,CACvCC,CAAAA,CAAUJ,EAAK,IAAA,GAAS,OAAA,CAGxBK,CAAAA,CAAeF,MAAAA,CAAOH,EAAK,KAAK,CAAA,CACtC,GAAIK,CAAAA,CAAa,OAAA,GAAYL,EAAK,KAAA,GAChCK,CAAAA,CAAa,OAAA,CAAUL,CAAAA,CAAK,MACxBC,CAAAA,GACED,CAAAA,CAAK,QAAU,MAAA,EAAUE,CAAAA,CAAW,UACtCI,KAAAA,CAAM,OAAA,CAAQJ,EAAW,OAAO,CAAA,CAChCA,EAAW,OAAA,CAAU,IAAA,CAAA,CAEnBF,EAAK,KAAA,GAAU,SAAA,GACbE,EAAW,OAAA,EAASI,KAAAA,CAAM,OAAA,CAAQJ,CAAAA,CAAW,OAAO,CAAA,CACpDE,CAAAA,CACFE,MAAM,OAAA,CAAQ,CAAA,EAAGN,EAAK,KAAA,CAAM,MAAM,CAAA,iBAAA,CAAA,CAAqB,CACrD,YAAarB,cAAAA,CAAeqB,CAAAA,CAAK,cAAc,KAAK,CACtD,CAAC,CAAA,CACQA,CAAAA,CAAK,QAAA,EACdM,KAAAA,CAAM,QAAQ,iBAAA,CAAmB,CAC/B,YAAa3B,cAAAA,CAAeqB,CAAAA,CAAK,SAAS,IAAI,CAChD,CAAC,CAAA,CAEHE,EAAW,OAAA,CAAU,IAAA,CAAA,CAEnBF,EAAK,KAAA,GAAU,OAAA,CAAA,CAAA,CAAS,CAE1B,GADIE,CAAAA,CAAW,OAAA,EAASI,KAAAA,CAAM,QAAQJ,CAAAA,CAAW,OAAO,EACpDE,CAAAA,EAAWJ,CAAAA,CAAK,MAAM,MAAA,CAAS,CAAA,CAAG,CACpC,IAAMO,EAAYP,CAAAA,CAAK,KAAA,CAAM,OAC1BN,CAAAA,EAAMA,CAAAA,CAAE,SAAW,SACtB,CAAA,CAAE,MAAA,CACIc,CAAAA,CAASR,EAAK,KAAA,CAAM,MAAA,CAAQN,GAAMA,CAAAA,CAAE,MAAA,GAAW,OAAO,CAAA,CAAE,MAAA,CAC9DY,KAAAA,CAAM,KAAA,CAAM,8BAA+B,CACzC,WAAA,CAAa,GAAGC,CAAS,CAAA,YAAA,EAAeC,CAAM,CAAA,OAAA,CAChD,CAAC,EACH,CAAA,KACEF,MAAM,KAAA,CAAM,eAAA,CAAiB,CAC3B,WAAA,CAAaV,EAAAA,CAAYI,EAAK,KAAA,EAAS,eAAe,CACxD,CAAC,EAEHE,CAAAA,CAAW,OAAA,CAAU,KACvB,CAKJO,SAAAA,CAAU,IAAM,CACd,GAAI,CAACR,CAAAA,EAAWD,EAAK,KAAA,GAAU,WAAA,CAAa,OAC5C,IAAMU,CAAAA,CAAKR,EAAW,OAAA,EAAW,CAAA,OAAA,EAAU,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,CAErD,GADAA,EAAW,OAAA,CAAUQ,CAAAA,CACjBN,EAAS,CACX,IAAMO,CAAAA,CAAOX,CAAAA,CAAK,MAAM,MAAA,CAAQN,CAAAA,EAAMA,EAAE,MAAA,GAAW,SAAS,EAAE,MAAA,CAC9DY,KAAAA,CAAM,OAAA,CAAQ,CAAA,gBAAA,EAAcK,CAAI,CAAA,CAAA,EAAIX,CAAAA,CAAK,MAAM,MAAM,CAAA,CAAA,CAAI,CACvD,EAAA,CAAAU,CAAAA,CACA,WAAA,CAAa,CAAA,EAAG/B,eAAeqB,CAAAA,CAAK,aAAA,CAAc,MAAM,CAAC,CAAA,GAAA,EAAMrB,eAAeqB,CAAAA,CAAK,aAAA,CAAc,KAAK,CAAC,CAAA,EAAA,EAAKA,EAAK,aAAA,CAAc,OAAO,KACtI,MAAA,CAAQ,CAAE,MAAO,QAAA,CAAU,OAAA,CAAS,IAAMA,CAAAA,CAAK,QAAS,CAC1D,CAAC,EACH,CAAA,KAAWA,EAAK,QAAA,EACdM,KAAAA,CAAM,OAAA,CAAQ,iBAAA,CAAc,CAC1B,EAAA,CAAAI,CAAAA,CACA,YAAa,CAAA,EAAG/B,cAAAA,CAAeqB,EAAK,QAAA,CAAS,MAAM,CAAC,CAAA,GAAA,EAAMrB,eAAeqB,CAAAA,CAAK,QAAA,CAAS,IAAI,CAAC,CAAA,EAAA,EAAKA,EAAK,QAAA,CAAS,OAAO,CAAA,EAAA,CAAA,CACtH,MAAA,CAAQ,CAAE,KAAA,CAAO,QAAA,CAAU,QAAS,IAAMA,CAAAA,CAAK,QAAS,CAC1D,CAAC,EAEL,EAAG,CACDC,CAAAA,CACAD,EAAK,KAAA,CACLI,CAAAA,CACAJ,EAAK,QAAA,CAAS,MAAA,CACdA,CAAAA,CAAK,QAAA,CAAS,QACdA,CAAAA,CAAK,aAAA,CAAc,OACnBA,CAAAA,CAAK,aAAA,CAAc,MACnBA,CAAAA,CAAK,aAAA,CAAc,OAAA,CACnBA,CAAAA,CAAK,SACLA,CAAAA,CAAK,KAAA,CACLA,EAAK,MACP,CAAC,EACH,CC7EO,SAASY,GAAa,CAC3B,SAAA,CAAA9D,EACA,KAAA,CAAA+D,CAAAA,CACA,QAAA,CAAAC,CAAAA,CACA,YAAAC,CAAAA,CACA,KAAA,CAAOC,EAAc,IAAA,CACrB,UAAA,CAAAC,EAAa,IAAA,CACb,GAAGC,CACL,CAAA,CAAsB,CACpB,IAAMlB,CAAAA,CAAOmB,kBAAkBD,CAAO,CAAA,CAChCd,EAAUJ,CAAAA,CAAK,IAAA,GAAS,OAAA,CACxBoB,CAAAA,CAAaN,GAAYd,CAAAA,CAAK,WAAA,CAEpCD,EAAeC,CAAAA,CAAMgB,CAAW,EAEhC,IAAMK,CAAAA,CAASJ,CAAAA,CACbb,CAAAA,CACElD,IAACqC,CAAAA,CAAA,CACC,MAAOS,CAAAA,CAAK,KAAA,CACZ,MAAOA,CAAAA,CAAK,KAAA,CACZ,aAAA,CAAeA,CAAAA,CAAK,cACpB,KAAA,CAAOA,CAAAA,CAAK,MACZ,QAAA,CAAUA,CAAAA,CAAK,OACjB,CAAA,CAEA9C,GAAAA,CAACmB,CAAAA,CAAA,CACC,MAAO2B,CAAAA,CAAK,KAAA,CACZ,SAAUA,CAAAA,CAAK,QAAA,CACf,MAAOA,CAAAA,CAAK,KAAA,CACZ,QAAA,CAAUA,CAAAA,CAAK,SACf,QAAA,CAAUA,CAAAA,CAAK,OACjB,CAAA,CAEA,IAAA,CAEJ,OACEjC,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAWxB,CAAAA,CAAG,4BAAA,CAA8BO,CAAS,CAAA,CACxD,QAAA,CAAA,CAAAiB,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,iCACb,QAAA,CAAA,CAAAb,GAAAA,CAAC,OAAA,CAAA,CAAO,GAAG8C,EAAK,UAAA,CAAY,CAAA,CAC5B9C,IAACE,CAAAA,CAAA,CACC,SAAAW,IAAAA,CAACR,CAAAA,CAAA,CACC,QAAA,CAAA,CAAAQ,KAACP,CAAAA,CAAA,CACC,OACEN,GAAAA,CAACL,CAAAA,CAAA,CACC,IAAA,CAAK,SAAA,CACL,QAAA,CAAUuE,CAAAA,CACV,QAASpB,CAAAA,CAAK,cAAA,CAChB,EAEF,QAAA,CAAA,CAAA9C,GAAAA,CAACoE,WAAA,CAAW,WAAA,CAAU,cAAA,CAAe,CAAA,CACpCT,IAAUT,CAAAA,CAAU,cAAA,CAAiB,gBACxC,CAAA,CACAlD,GAAAA,CAACO,EAAA,CACE,QAAA,CAAAsD,CAAAA,GAAgBX,CAAAA,CAAU,eAAiB,aAAA,CAAA,CAC9C,CAAA,CAAA,CACF,EACF,CAAA,CAAA,CACF,CAAA,CACCiB,GACH,CAEJ,CCrEO,SAASE,EAAAA,CAAe,CAC7B,UAAAzE,CAAAA,CACA,KAAA,CAAA+D,EACA,QAAA,CAAAC,CAAAA,CACA,KAAA,CAAOE,CAAAA,CAAc,KACrB,UAAA,CAAAC,CAAAA,CAAa,KACb,GAAGC,CACL,EAAwB,CACtB,IAAMlB,CAAAA,CAAOmB,iBAAAA,CAAkBD,CAAO,CAAA,CAChCd,CAAAA,CAAUJ,EAAK,IAAA,GAAS,OAAA,CACxBoB,EAAaN,CAAAA,EAAYd,CAAAA,CAAK,WAAA,CAEpCD,CAAAA,CAAeC,EAAMgB,CAAW,CAAA,CAEhC,IAAMK,CAAAA,CAASJ,CAAAA,CACbb,EACElD,GAAAA,CAACqC,CAAAA,CAAA,CACC,KAAA,CAAOS,EAAK,KAAA,CACZ,KAAA,CAAOA,EAAK,KAAA,CACZ,aAAA,CAAeA,EAAK,aAAA,CACpB,KAAA,CAAOA,CAAAA,CAAK,KAAA,CACZ,SAAUA,CAAAA,CAAK,MAAA,CACjB,EAEA9C,GAAAA,CAACmB,CAAAA,CAAA,CACC,KAAA,CAAO2B,CAAAA,CAAK,KAAA,CACZ,QAAA,CAAUA,EAAK,QAAA,CACf,KAAA,CAAOA,EAAK,KAAA,CACZ,QAAA,CAAUA,EAAK,QAAA,CACf,QAAA,CAAUA,CAAAA,CAAK,MAAA,CACjB,EAEA,IAAA,CAEJ,OACEjC,KAAC,KAAA,CAAA,CACC,SAAA,CAAWxB,EACT,qHAAA,CACA6E,CAAAA,CACI,+CAAA,CACA,mEAAA,CACJtE,CACF,CAAA,CACA,OAAA,CAASsE,EAAa,MAAA,CAAYpB,CAAAA,CAAK,eACtC,GAAIoB,CAAAA,CAAa,EAAC,CAAIpB,CAAAA,CAAK,aAC5B,QAAA,CAAA,CAAA9C,GAAAA,CAAC,SAAO,GAAG8C,CAAAA,CAAK,WAAY,CAAA,CAC5B9C,GAAAA,CAACoE,UAAAA,CAAA,CACC,UAAW/E,CAAAA,CACT,8BAAA,CACA6E,GAAc,YAChB,CAAA,CACF,EACAlE,GAAAA,CAAC,GAAA,CAAA,CACC,SAAA,CAAWX,CAAAA,CACT,gCACA6E,CAAAA,EAAc,YAChB,EACC,QAAA,CAAAP,CAAAA,GACET,EACG,sCAAA,CACA,gCAAA,CAAA,CACR,CAAA,CACCiB,CAAAA,EAAUnE,IAAC,KAAA,CAAA,CAAI,SAAA,CAAU,mBAAoB,QAAA,CAAAmE,CAAAA,CAAO,GACvD,CAEJ,CC7EA,IAAMzB,EAAAA,CAAc,CAACC,CAAAA,CAAaC,CAAAA,CAAM,MACtCD,CAAAA,CAAI,MAAA,CAASC,EAAMD,CAAAA,CAAI,KAAA,CAAM,CAAA,CAAGC,CAAG,EAAI,QAAA,CAAMD,CAAAA,CAgBxC,SAAS2B,EAAAA,CAAe,CAC7B,IAAAC,CAAAA,CACA,SAAA,CAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,KAAA,CAAAd,CAAAA,CACA,UAAA/D,CAAAA,CACA,QAAA,CAAAgE,EACA,KAAA,CAAOE,CAAAA,CAAc,IAAA,CACrB,UAAA,CAAAC,EAAa,IACf,CAAA,CAAwB,CACtB,IAAMW,CAAAA,CAAKC,YAAY,CACrB,GAAA,CAAAJ,CAAAA,CACA,WAAA,CAAa,IAAM,CACbT,CAAAA,EAAaV,MAAM,OAAA,CAAQ,kBAAkB,EACnD,CAAA,CACA,OAAA,CAAS,CAACwB,CAAAA,CAAMtD,IAAU,CACpBwC,CAAAA,EACFV,MAAM,KAAA,CAAM,iBAAA,CAAmB,CAC7B,WAAA,CAAaV,EAAAA,CACXpB,CAAAA,YAAiB,KAAA,CAAQA,EAAM,OAAA,CAAU,eAC3C,CACF,CAAC,EAEL,CACF,CAAC,CAAA,CAEKuD,CAAAA,CAAYH,CAAAA,CAAG,QAAU,YAAA,CAE/B,OACE7D,KAAC,KAAA,CAAA,CAAI,SAAA,CAAWxB,EAAG,8BAAA,CAAgCO,CAAS,CAAA,CAC1D,QAAA,CAAA,CAAAI,IAACL,CAAAA,CAAA,CACC,KAAK,SAAA,CACL,OAAA,CAAQ,UACR,QAAA,CAAUiE,CAAAA,EAAYiB,CAAAA,CACtB,OAAA,CAAS,IAAMH,CAAAA,CAAG,QAAA,CAASF,EAAWC,CAAQ,CAAA,CAC9C,SAAA5D,IAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,gCAAA,CACb,QAAA,CAAA,CAAAgE,EACC7E,GAAAA,CAAC8E,UAAAA,CAAA,CAAW,SAAA,CAAU,cAAA,CAAe,YAAU,cAAA,CAAe,CAAA,CAE9D9E,GAAAA,CAAC+E,YAAAA,CAAA,CAAa,WAAA,CAAU,cAAA,CAAe,EAExCpB,CAAAA,EAAS,UAAA,CAAA,CACZ,EACF,CAAA,CAECI,CAAAA,EAAcW,CAAAA,CAAG,KAAA,GAAU,SAC1B7D,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,0CAAA,CACb,QAAA,CAAA,CAAAb,IAAC6B,eAAAA,CAAA,CAAgB,SAAA,CAAU,2CAAA,CAA4C,EACvE7B,GAAAA,CAAC,GAAA,CAAA,CAAE,UAAU,mDAAA,CACV,QAAA,CAAA0E,EAAG,KAAA,EAAS,iBAAA,CACf,CAAA,CAAA,CACF,CAAA,CAAA,CAEJ,CAEJ,CCvEA,IAAMhC,EAAAA,CAAc,CAACC,EAAaC,CAAAA,CAAM,GAAA,GACtCD,CAAAA,CAAI,MAAA,CAASC,EAAMD,CAAAA,CAAI,KAAA,CAAM,EAAGC,CAAG,CAAA,CAAI,SAAMD,CAAAA,CA2BxC,SAASqC,EAAAA,CAAuB,CACrC,IAAAT,CAAAA,CACA,SAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CACA,SAAAQ,CAAAA,CACA,MAAA,CAAAC,CAAAA,CACA,KAAA,CAAAvB,EACA,SAAA,CAAA/D,CAAAA,CACA,cAAAuF,CAAAA,CACA,QAAA,CAAAvB,EACA,WAAA,CAAAC,CAAAA,CAAc,eAAA,CACd,KAAA,CAAOC,EAAc,IAAA,CACrB,UAAA,CAAAC,EAAa,IAAA,CACb,cAAA,CAAAqB,EACA,eAAA,CAAAC,CAAAA,CACA,UAAA,CAAAC,CAAAA,CACA,UAAAC,CAAAA,CACA,OAAA,CAAAC,EACA,QAAA,CAAAhE,CACF,EAAgC,CAC9B,IAAMiE,CAAAA,CAAchB,CAAAA,EAAYD,EAAU,KAAA,CAAM,GAAG,EAAE,GAAA,EAAI,EAAKA,EAExDE,CAAAA,CAAKgB,gBAAAA,CAAiB,CAC1B,GAAA,CAAAnB,EACA,MAAA,CAAAW,CAAAA,CACA,eAAAE,CAAAA,CACA,eAAA,CAAAC,EACA,UAAA,CAAAC,CAAAA,CACA,SAAA,CAAW,CAACK,EAAKC,CAAAA,GAAmB,CAC9B9B,IACFV,KAAAA,CAAM,OAAA,CAAQ,MAAMoB,CAAS,CAAA,CAAE,CAAA,CAC/BpB,KAAAA,CAAM,QAAQ,mBAAA,CAAqB,CACjC,YAAa,CAAA,EAAGwC,CAAc,GAAGX,CAAAA,EAAY,IAAA,CAAO,SAAMxD,cAAAA,CAAewD,CAAQ,CAAC,CAAA,CAAA,CAAK,EAAE,EAC3F,CAAC,CAAA,CAAA,CAEHM,IAAYI,CAAAA,CAAKC,CAAc,EACjC,CAAA,CACA,QAAS,CAACD,CAAAA,CAAKrE,EAAOF,EAAAA,GAAU,CAC1B0C,IACFV,KAAAA,CAAM,OAAA,CAAQ,CAAA,GAAA,EAAMoB,CAAS,EAAE,CAAA,CAC/BpB,KAAAA,CAAM,MAAM,iBAAA,CAAmB,CAC7B,YAAaV,EAAAA,CACXpB,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAM,QAAU,eAC3C,CACF,CAAC,CAAA,CAAA,CAEHkE,CAAAA,GAAUG,EAAKrE,CAAAA,CAAOF,EAAK,EAC7B,CAAA,CACA,SAAWuE,CAAAA,EAAQ,CACb7B,IACFV,KAAAA,CAAM,OAAA,CAAQ,MAAMoB,CAAS,CAAA,CAAE,CAAA,CAC/BpB,KAAAA,CAAM,KAAK,oBAAA,CAAsB,CAAE,YAAaqC,CAAY,CAAC,GAE/DjE,CAAAA,GAAWmE,CAAG,EAChB,CACF,CAAC,CAAA,CAEKE,CAAAA,CAAgBnB,EAAG,KAAA,GAAU,aAAA,EAAiBA,EAAG,KAAA,GAAU,YAAA,CAE3DoB,EAAAA,CAAc,IAAM,CACxB,GAAID,CAAAA,CAAe,CACjBnB,CAAAA,CAAG,MAAA,GACH,MACF,CACAA,CAAAA,CAAG,QAAA,CAASF,EAAWC,CAAQ,EACjC,EAEA,OACE5D,IAAAA,CAAC,OAAI,SAAA,CAAWxB,CAAAA,CAAG,8BAAA,CAAgCO,CAAS,EAC1D,QAAA,CAAA,CAAAI,GAAAA,CAACE,EAAA,CACC,QAAA,CAAAW,KAACR,CAAAA,CAAA,CACC,QAAA,CAAA,CAAAQ,IAAAA,CAACP,EAAA,CACC,MAAA,CACEN,IAACL,CAAAA,CAAA,CACC,KAAK,SAAA,CACL,OAAA,CAAQ,SAAA,CACR,QAAA,CAAUiE,EACV,SAAA,CAAWvE,CAAAA,CAAG,mCAAmC,CAAA,CACjD,OAAA,CAASyG,GACX,CAAA,CAED,QAAA,CAAA,CAAAD,CAAAA,EACC7F,GAAAA,CAAC,QACC,SAAA,CAAWX,CAAAA,CACT,iEACA8F,CACF,CAAA,CACA,MAAO,CAAE,KAAA,CAAO,CAAA,EAAGT,CAAAA,CAAG,SAAS,OAAO,CAAA,CAAA,CAAI,EAC5C,CAAA,CAEF7D,IAAAA,CAAC,QAAK,SAAA,CAAU,8CAAA,CACd,QAAA,CAAA,CAAAb,GAAAA,CAAC+E,aAAA,CAAa,WAAA,CAAU,eAAe,CAAA,CACtCc,CAAAA,CACGpE,eAAeiD,CAAAA,CAAG,QAAA,CAAS,MAAM,CAAA,CAChCf,GAAS,UAAA,CAAA,CAChB,CAAA,CAAA,CACF,EACA3D,GAAAA,CAACO,CAAAA,CAAA,CACE,QAAA,CAAAsF,CAAAA,CAAgB,kBAAoBhC,CAAAA,CACvC,CAAA,CAAA,CACF,EACF,CAAA,CAECE,CAAAA,EAAcW,EAAG,KAAA,GAAU,OAAA,EAC1B7D,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,0CAAA,CACb,QAAA,CAAA,CAAAb,IAAC6B,eAAAA,CAAA,CAAgB,UAAU,2CAAA,CAA4C,CAAA,CACvE7B,IAAC,GAAA,CAAA,CAAE,SAAA,CAAU,mDAAA,CACV,QAAA,CAAA0E,EAAG,KAAA,EAAS,iBAAA,CACf,GACF,CAAA,CAAA,CAEJ,CAEJ,CC9IA,SAASqB,GAAY,CAAE,GAAGhG,CAAM,CAAA,CAAoC,CAClE,OAAOC,GAAAA,CAACgG,YAAqB,IAAA,CAArB,CAA0B,YAAU,cAAA,CAAgB,GAAGjG,CAAAA,CAAO,CACxE,CAEA,SAASkG,EAAAA,CAAmB,CAAE,GAAGlG,CAAM,EAAuC,CAC5E,OACEC,GAAAA,CAACgG,WAAAA,CAAqB,QAArB,CAA6B,WAAA,CAAU,uBAAwB,GAAGjG,CAAAA,CAAO,CAE9E,CAEA,SAASmG,EAAAA,CAAkB,CAAE,GAAGnG,CAAM,CAAA,CAAsC,CAC1E,OACEC,GAAAA,CAACgG,YAAqB,MAAA,CAArB,CAA4B,WAAA,CAAU,qBAAA,CAAuB,GAAGjG,CAAAA,CAAO,CAE5E,CAEA,SAASoG,EAAAA,CAAmB,CAC1B,SAAA,CAAAvG,CAAAA,CACA,GAAGG,CACL,EAAwC,CACtC,OACEC,IAACgG,WAAAA,CAAqB,QAAA,CAArB,CACC,WAAA,CAAU,sBAAA,CACV,SAAA,CAAW3G,CAAAA,CACT,wLACAO,CACF,CAAA,CACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASqG,EAAAA,CAAmB,CAC1B,SAAA,CAAAxG,EACA,IAAA,CAAAE,CAAAA,CAAO,UACP,GAAGC,CACL,EAEG,CACD,OACEc,IAAAA,CAACqF,EAAAA,CAAA,CACC,QAAA,CAAA,CAAAlG,GAAAA,CAACmG,GAAA,EAAmB,CAAA,CACpBnG,IAACgG,WAAAA,CAAqB,KAAA,CAArB,CACC,WAAA,CAAU,uBACV,WAAA,CAAWlG,CAAAA,CACX,UAAWT,CAAAA,CACT,icAAA,CACAO,CACF,CAAA,CACC,GAAGG,EACN,CAAA,CAAA,CACF,CAEJ,CAEA,SAASsG,EAAAA,CAAkB,CACzB,SAAA,CAAAzG,CAAAA,CACA,GAAGG,CACL,CAAA,CAAgC,CAC9B,OACEC,IAAC,KAAA,CAAA,CACC,WAAA,CAAU,sBACV,SAAA,CAAWX,CAAAA,CACT,oZACAO,CACF,CAAA,CACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASuG,GAAkB,CACzB,SAAA,CAAA1G,EACA,GAAGG,CACL,CAAA,CAAgC,CAC9B,OACEC,GAAAA,CAAC,KAAA,CAAA,CACC,YAAU,qBAAA,CACV,SAAA,CAAWX,EACT,6JAAA,CACAO,CACF,CAAA,CACC,GAAGG,EACN,CAEJ,CAEA,SAASwG,EAAAA,CAAiB,CACxB,UAAA3G,CAAAA,CACA,GAAGG,CACL,CAAA,CAAgC,CAC9B,OACEC,GAAAA,CAAC,OACC,WAAA,CAAU,oBAAA,CACV,UAAWX,CAAAA,CACT,2KAAA,CACAO,CACF,CAAA,CACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASyG,EAAAA,CAAiB,CACxB,SAAA,CAAA5G,CAAAA,CACA,GAAGG,CACL,EAA4D,CAC1D,OACEC,IAACgG,WAAAA,CAAqB,KAAA,CAArB,CACC,WAAA,CAAU,oBAAA,CACV,SAAA,CAAW3G,CAAAA,CACT,+JACAO,CACF,CAAA,CACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAAS0G,EAAAA,CAAuB,CAC9B,SAAA,CAAA7G,EACA,GAAGG,CACL,EAAkE,CAChE,OACEC,IAACgG,WAAAA,CAAqB,WAAA,CAArB,CACC,WAAA,CAAU,2BACV,SAAA,CAAW3G,CAAAA,CACT,yIACAO,CACF,CAAA,CACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAAS2G,GAAkB,CACzB,SAAA,CAAA9G,EACA,GAAGG,CACL,EAAwC,CACtC,OACEC,GAAAA,CAACL,CAAAA,CAAA,CACC,WAAA,CAAU,qBAAA,CACV,UAAWN,CAAAA,CAAGO,CAAS,EACtB,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAAS4G,EAAAA,CAAkB,CACzB,UAAA/G,CAAAA,CACA,OAAA,CAAAC,EAAU,SAAA,CACV,IAAA,CAAAC,CAAAA,CAAO,SAAA,CACP,GAAGC,CACL,CAAA,CACiE,CAC/D,OACEC,GAAAA,CAACgG,YAAqB,KAAA,CAArB,CACC,WAAA,CAAU,qBAAA,CACV,UAAW3G,CAAAA,CAAGO,CAAS,EACvB,MAAA,CAAQI,GAAAA,CAACL,EAAA,CAAO,OAAA,CAASE,EAAS,IAAA,CAAMC,CAAAA,CAAM,EAC7C,GAAGC,CAAAA,CACN,CAEJ,CC7JA,IAAM2C,EAAAA,CAAc,CAACC,EAAaC,CAAAA,CAAM,GAAA,GACtCD,EAAI,MAAA,CAASC,CAAAA,CAAMD,CAAAA,CAAI,KAAA,CAAM,EAAGC,CAAG,CAAA,CAAI,SAAMD,CAAAA,CAwCxC,SAASiE,GAAa,CAC3B,GAAA,CAAArC,CAAAA,CACA,SAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CACA,SAAAQ,CAAAA,CACA,MAAA,CAAAC,EACA,KAAA,CAAAvB,CAAAA,CACA,SAAA,CAAA/D,CAAAA,CACA,SAAAgE,CAAAA,CACA,WAAA,CAAAC,EAAc,aAAA,CACd,KAAA,CAAOC,EAAc,IAAA,CACrB,UAAA,CAAAC,CAAAA,CAAa,IAAA,CACb,aAAA8C,CAAAA,CAAe,cAAA,CACf,mBAAAC,CAAAA,CACA,YAAA,CAAAC,EACA,aAAA,CAAAC,CAAAA,CACA,SAAA,CAAAzB,CAAAA,CACA,QAAAC,CACF,CAAA,CAAsB,CACpB,IAAMC,CAAAA,CAAchB,GAAYD,CAAAA,CAAU,KAAA,CAAM,GAAG,CAAA,CAAE,KAAI,EAAKA,CAAAA,CAExDyC,EAAMC,SAAAA,CAAU,CACpB,IAAA3C,CAAAA,CACA,MAAA,CAAAW,CAAAA,CACA,YAAA,CAAA6B,EACA,aAAA,CAAAC,CAAAA,CACA,UAAYrB,CAAAA,EAAQ,CACd7B,GACFV,KAAAA,CAAM,OAAA,CAAQ,cAAA,CAAgB,CAAE,YAAaqC,CAAY,CAAC,EAE5DF,CAAAA,GAAYI,CAAG,EACjB,CAAA,CACA,OAAA,CAAS,CAACA,CAAAA,CAAKrE,EAAOF,EAAAA,GAAU,CAC1B0C,GACFV,KAAAA,CAAM,KAAA,CAAM,gBAAiB,CAC3B,WAAA,CAAaV,EAAAA,CACXpB,CAAAA,YAAiB,MAAQA,CAAAA,CAAM,OAAA,CAAU,eAC3C,CACF,CAAC,EAEHkE,CAAAA,GAAUG,CAAAA,CAAKrE,CAAAA,CAAOF,EAAK,EAC7B,CACF,CAAC,EAEK+F,CAAAA,CAAaF,CAAAA,CAAI,QAAU,UAAA,CAC3B/C,CAAAA,CAAaN,CAAAA,EAAYuD,CAAAA,CAEzBC,GACJN,CAAAA,EACA,CAAA,iCAAA,EAAoCrB,CAAW,CAAA,CAAA,EAAIR,CAAAA,EAAY,KAAO,CAAA,EAAA,EAAKxD,cAAAA,CAAewD,CAAQ,CAAC,IAAM,EAAE,CAAA,+BAAA,CAAA,CAE7G,OACEpE,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAWxB,CAAAA,CAAG,8BAAA,CAAgCO,CAAS,CAAA,CAC1D,UAAAI,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,gCAAA,CACb,QAAA,CAAAa,KAACkF,EAAAA,CAAA,CACC,KAAMkB,CAAAA,CAAI,KAAA,GAAU,aACpB,YAAA,CAAeI,CAAAA,EAAS,CACjBA,CAAAA,EAAMJ,CAAAA,CAAI,eACjB,CAAA,CACA,QAAA,CAAA,CAAAjH,GAAAA,CAACE,EAAA,CACC,QAAA,CAAAW,KAACR,CAAAA,CAAA,CACC,UAAAQ,IAAAA,CAACP,CAAAA,CAAA,CACC,MAAA,CACEN,IAACiG,EAAAA,CAAA,CACC,SAAU/B,CAAAA,CACV,OAAA,CAAS,IAAM+C,CAAAA,CAAI,aAAA,CAAczC,CAAS,CAAA,CAC1C,OACExE,GAAAA,CAACL,CAAAA,CAAA,CACC,IAAA,CAAK,SAAA,CACL,QAAQ,aAAA,CACR,QAAA,CAAUuE,CAAAA,CACZ,CAAA,CAEJ,EAED,QAAA,CAAA,CAAAiD,CAAAA,CACCnH,IAAC8E,UAAAA,CAAA,CACC,UAAU,cAAA,CACV,WAAA,CAAU,cAAA,CACZ,CAAA,CAEA9E,IAACsH,UAAAA,CAAA,CAAW,YAAU,cAAA,CAAe,CAAA,CAEtC3D,GAAS,QAAA,CAAA,CACZ,CAAA,CACA3D,GAAAA,CAACO,CAAAA,CAAA,CAAgB,QAAA,CAAAsD,CAAAA,CAAY,GAC/B,CAAA,CACF,CAAA,CAEAhD,KAACuF,EAAAA,CAAA,CACC,QAAA,CAAA,CAAAvF,IAAAA,CAACwF,GAAA,CACC,QAAA,CAAA,CAAArG,IAACuG,EAAAA,CAAA,CACC,SAAAvG,GAAAA,CAACsH,UAAAA,CAAA,EAAW,CAAA,CACd,EACAtH,GAAAA,CAACwG,EAAAA,CAAA,CAAkB,QAAA,CAAAK,CAAAA,CAAa,EAChC7G,GAAAA,CAACyG,EAAAA,CAAA,CAAuB,SAAA,CAAU,2BAA4B,QAAA,CAAAW,EAAAA,CAAY,GAC5E,CAAA,CACAvG,IAAAA,CAACyF,GAAA,CACC,QAAA,CAAA,CAAAtG,GAAAA,CAAC2G,EAAAA,CAAA,CAAkB,QAAA,CAAA,QAAA,CAAM,CAAA,CACzB3G,IAAC0G,EAAAA,CAAA,CACC,QAAQ,aAAA,CACR,OAAA,CAAS,IAAMO,CAAAA,CAAI,eAAc,CAAG,QAAA,CAAA,QAAA,CAEtC,GACF,CAAA,CAAA,CACF,CAAA,CAAA,CACF,EACF,CAAA,CAEClD,CAAAA,EAAckD,CAAAA,CAAI,KAAA,GAAU,WAC3BpG,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,2CAAA,CACb,QAAA,CAAA,CAAAb,IAACuH,gBAAAA,CAAA,CAAiB,SAAA,CAAU,kCAAA,CAAmC,EAC/D1G,IAAAA,CAAC,GAAA,CAAA,CAAE,UAAU,iDAAA,CAAkD,QAAA,CAAA,CAAA,QAAA,CAE7Db,IAAC,MAAA,CAAA,CAAK,SAAA,CAAU,iDAAA,CACb,QAAA,CAAAyF,EACH,CAAA,CAAO,gBAAA,CAAA,CAET,GACF,CAAA,CAGD1B,CAAAA,EAAckD,EAAI,KAAA,GAAU,OAAA,EAC3BpG,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,0CAAA,CACb,QAAA,CAAA,CAAAb,IAAC6B,eAAAA,CAAA,CAAgB,UAAU,2CAAA,CAA4C,CAAA,CACvE7B,IAAC,GAAA,CAAA,CAAE,SAAA,CAAU,oDACV,QAAA,CAAAiH,CAAAA,CAAI,OAAS,eAAA,CAChB,CAAA,CAAA,CACF,GAEJ,CAEJ","file":"index.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","\"use client\"\n\nimport { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button cursor-pointer inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n xs: \"h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-2.5\",\n sm: \"h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3\",\n lg: \"h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2 [&_svg:not([class*='size-'])]:size-4\",\n icon: \"size-7 [&_svg:not([class*='size-'])]:size-3.5\",\n \"icon-xs\": \"size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5\",\n \"icon-sm\": \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n \"icon-lg\": \"size-8 [&_svg:not([class*='size-'])]:size-4\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","\"use client\"\n\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction TooltipProvider({\n delay = 0,\n ...props\n}: TooltipPrimitive.Provider.Props) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delay={delay}\n {...props}\n />\n )\n}\n\nfunction Tooltip({ ...props }: TooltipPrimitive.Root.Props) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n}\n\nfunction TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />\n}\n\nfunction TooltipContent({\n className,\n side = \"top\",\n sideOffset = 4,\n align = \"center\",\n alignOffset = 0,\n children,\n ...props\n}: TooltipPrimitive.Popup.Props &\n Pick<\n TooltipPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\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 >\n {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-start-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-end-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5\" />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n )\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }\n","\"use client\"\n\nexport function CircleProgress({\n percent,\n size = 20,\n strokeWidth = 2.5,\n}: {\n percent: number\n size?: number\n strokeWidth?: number\n}) {\n const r = (size - strokeWidth) / 2\n const c = 2 * Math.PI * r\n const offset = c - (percent / 100) * c\n return (\n <svg width={size} height={size} className=\"shrink-0 -rotate-90\">\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n className=\"text-muted-foreground/20\"\n />\n <circle\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n strokeDasharray={c}\n strokeDashoffset={offset}\n strokeLinecap=\"round\"\n className=\"text-primary transition-[stroke-dashoffset] duration-200\"\n />\n </svg>\n )\n}\n","\"use client\";\n\nimport { XIcon, CheckCircleIcon, AlertCircleIcon } from \"lucide-react\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { UploadPhase, UploadProgress } from \"@better-s3/react\";\nimport { Button } from \"@/ui/button\";\nimport { CircleProgress } from \"@/ui/circle-progress\";\n\nexport function UploadStatus({\n phase,\n progress,\n error,\n fileInfo,\n onCancel,\n}: {\n phase: UploadPhase;\n progress: UploadProgress;\n error: string | null;\n fileInfo: { name: string; size: number } | null;\n onCancel?: () => void;\n}) {\n if (phase === \"idle\") return null;\n\n if (phase === \"uploading\" && fileInfo) {\n return (\n <div className=\"flex w-full items-center gap-1.5 text-xs\">\n <CircleProgress percent={progress.percent} size={14} strokeWidth={2} />\n <span className=\"max-w-32 min-w-16 truncate sm:max-w-48\">\n {fileInfo.name}\n </span>\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(progress.loaded)} / {formatFileSize(fileInfo.size)} (\n {progress.percent}%)\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"ml-auto size-6 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\n }}>\n <XIcon className=\"size-3.5\" />\n </Button>\n </div>\n );\n }\n\n if (phase === \"success\" && fileInfo) {\n return (\n <div className=\"flex items-center gap-1.5 text-xs\">\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n <span className=\"[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48\">\n {fileInfo.name}\n </span>\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(fileInfo.size)}\n </span>\n </div>\n );\n }\n\n if (phase === \"error\") {\n return (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {error ?? \"Upload failed\"}\n </p>\n </div>\n );\n }\n\n if (phase === \"validating\" || phase === \"presigning\") {\n return <span className=\"text-xs text-muted-foreground\">Preparing…</span>;\n }\n\n return null;\n}\n","\"use client\"\n\nimport { Progress as ProgressPrimitive } from \"@base-ui/react/progress\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Progress({\n className,\n children,\n value,\n ...props\n}: ProgressPrimitive.Root.Props) {\n return (\n <ProgressPrimitive.Root\n value={value}\n data-slot=\"progress\"\n className={cn(\"flex flex-wrap gap-3\", className)}\n {...props}\n >\n {children}\n <ProgressTrack>\n <ProgressIndicator />\n </ProgressTrack>\n </ProgressPrimitive.Root>\n )\n}\n\nfunction ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {\n return (\n <ProgressPrimitive.Track\n className={cn(\n \"relative flex h-1 w-full items-center overflow-x-hidden rounded-md bg-muted\",\n className\n )}\n data-slot=\"progress-track\"\n {...props}\n />\n )\n}\n\nfunction ProgressIndicator({\n className,\n ...props\n}: ProgressPrimitive.Indicator.Props) {\n return (\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className={cn(\"h-full bg-primary transition-all\", className)}\n {...props}\n />\n )\n}\n\nfunction ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {\n return (\n <ProgressPrimitive.Label\n className={cn(\"text-xs/relaxed font-medium\", className)}\n data-slot=\"progress-label\"\n {...props}\n />\n )\n}\n\nfunction ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {\n return (\n <ProgressPrimitive.Value\n className={cn(\n \"ms-auto text-xs/relaxed text-muted-foreground tabular-nums\",\n className\n )}\n data-slot=\"progress-value\"\n {...props}\n />\n )\n}\n\nexport {\n Progress,\n ProgressTrack,\n ProgressIndicator,\n ProgressLabel,\n ProgressValue,\n}\n","\"use client\";\n\nimport { XIcon, CheckCircleIcon, AlertCircleIcon } from \"lucide-react\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { UploadProgress, MultiUploadFileState } from \"@better-s3/react\";\nimport { Button } from \"@/ui/button\";\nimport { Progress, ProgressLabel, ProgressValue } from \"@/ui/progress\";\nimport { CircleProgress } from \"@/ui/circle-progress\";\n\nexport function MultiUploadStatus({\n phase,\n files,\n totalProgress,\n error,\n onCancel,\n}: {\n phase: string;\n files: MultiUploadFileState[];\n totalProgress: UploadProgress;\n error: string | null;\n onCancel?: () => void;\n}) {\n if (phase === \"idle\") return null;\n\n if (phase === \"uploading\") {\n return (\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"flex w-full items-center gap-1.5\">\n <Progress value={totalProgress.percent} className=\"flex-1\">\n <ProgressLabel>\n {files.filter((f) => f.status === \"success\").length}/\n {files.length} files\n </ProgressLabel>\n <ProgressValue />\n </Progress>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7 shrink-0\"\n onClick={(e) => {\n e.stopPropagation();\n onCancel?.();\n }}>\n <XIcon className=\"size-4\" />\n </Button>\n </div>\n <FileList files={files} />\n </div>\n );\n }\n\n if (phase === \"success\") {\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <span className=\"text-xs text-green-600\">\n All {files.length} file(s) uploaded\n </span>\n <FileList files={files} />\n </div>\n );\n }\n\n if (phase === \"error\") {\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <span className=\"text-xs text-destructive\">\n {error ?? \"Upload failed\"}\n </span>\n {files.length > 0 && <FileList files={files} />}\n </div>\n );\n }\n\n if (phase === \"validating\") {\n return <span className=\"text-xs text-muted-foreground\">Validating…</span>;\n }\n\n return null;\n}\n\n// ─── File List ──────────────────────────────────────────────────────────\n\nfunction FileList({ files }: { files: MultiUploadFileState[] }) {\n return (\n <ul className=\"flex flex-col gap-1\">\n {files.map((f) => (\n <li key={f.id} className=\"flex flex-col gap-0.5 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n {f.status === \"success\" && (\n <CheckCircleIcon className=\"size-3.5 shrink-0 text-green-600\" />\n )}\n {f.status === \"error\" && (\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n )}\n {(f.status === \"pending\" || f.status === \"uploading\") && (\n <CircleProgress\n percent={f.status === \"uploading\" ? f.progress.percent : 0}\n size={14}\n strokeWidth={2}\n />\n )}\n <span className=\"[overflow-wrap:anywhere] max-w-32 min-w-16 truncate sm:max-w-48\">\n {f.fileName}\n </span>\n {f.status === \"uploading\" ? (\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(f.progress.loaded)} /{\" \"}\n {formatFileSize(f.fileSize)} ({f.progress.percent}%)\n </span>\n ) : (\n <span className=\"shrink-0 text-muted-foreground\">\n {formatFileSize(f.fileSize)}\n </span>\n )}\n </div>\n {f.status === \"error\" && f.error && (\n <span className=\"truncate [overflow-wrap:anywhere] pl-5 text-destructive\">\n {f.error}\n </span>\n )}\n </li>\n ))}\n </ul>\n );\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { formatFileSize } from \"@better-s3/react\";\n\nconst truncateMsg = (msg: string, max = 100) =>\n msg.length > max ? msg.slice(0, max) + \"…\" : msg;\nimport type { UseUploadControlsReturn } from \"@better-s3/react\";\n\n/**\n * Drives sonner toasts for upload progress/success/error.\n * Shared between UploadButton and UploadDropzone.\n */\nexport function useUploadToast(\n ctrl: Pick<\n UseUploadControlsReturn,\n | \"mode\"\n | \"phase\"\n | \"fileInfo\"\n | \"progress\"\n | \"files\"\n | \"totalProgress\"\n | \"error\"\n | \"cancel\"\n >,\n enabled: boolean,\n) {\n const toastIdRef = useRef<string | null>(null);\n const isMulti = ctrl.mode === \"multi\";\n\n // Phase-transition toasts (runs synchronously during render to fire exactly once)\n const prevPhaseRef = useRef(ctrl.phase);\n if (prevPhaseRef.current !== ctrl.phase) {\n prevPhaseRef.current = ctrl.phase;\n if (enabled) {\n if (ctrl.phase === \"idle\" && toastIdRef.current) {\n toast.dismiss(toastIdRef.current);\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"success\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n if (isMulti) {\n toast.success(`${ctrl.files.length} file(s) uploaded`, {\n description: formatFileSize(ctrl.totalProgress.total),\n });\n } else if (ctrl.fileInfo) {\n toast.success(\"Upload complete\", {\n description: formatFileSize(ctrl.fileInfo.size),\n });\n }\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"error\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n if (isMulti && ctrl.files.length > 0) {\n const succeeded = ctrl.files.filter(\n (f) => f.status === \"success\",\n ).length;\n const failed = ctrl.files.filter((f) => f.status === \"error\").length;\n toast.error(\"Upload finished with errors\", {\n description: `${succeeded} succeeded, ${failed} failed`,\n });\n } else {\n toast.error(\"Upload failed\", {\n description: truncateMsg(ctrl.error ?? \"Unknown error\"),\n });\n }\n toastIdRef.current = null;\n }\n }\n }\n\n // Progress toast (updated on each progress tick)\n useEffect(() => {\n if (!enabled || ctrl.phase !== \"uploading\") return;\n const id = toastIdRef.current ?? `upload-${Date.now()}`;\n toastIdRef.current = id;\n if (isMulti) {\n const done = ctrl.files.filter((f) => f.status === \"success\").length;\n toast.loading(`Uploading… ${done}/${ctrl.files.length}`, {\n id,\n description: `${formatFileSize(ctrl.totalProgress.loaded)} / ${formatFileSize(ctrl.totalProgress.total)} (${ctrl.totalProgress.percent}%)`,\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n } else if (ctrl.fileInfo) {\n toast.loading(\"Uploading…\", {\n id,\n description: `${formatFileSize(ctrl.progress.loaded)} / ${formatFileSize(ctrl.fileInfo.size)} (${ctrl.progress.percent}%)`,\n cancel: { label: \"Cancel\", onClick: () => ctrl.cancel() },\n });\n }\n }, [\n enabled,\n ctrl.phase,\n isMulti,\n ctrl.progress.loaded,\n ctrl.progress.percent,\n ctrl.totalProgress.loaded,\n ctrl.totalProgress.total,\n ctrl.totalProgress.percent,\n ctrl.fileInfo,\n ctrl.files,\n ctrl.cancel,\n ]);\n}\n","\"use client\";\n\nimport { UploadIcon } from \"lucide-react\";\nimport type { UseUploadControlsOptions } from \"@better-s3/react\";\nimport { useUploadControls } from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/ui/tooltip\";\nimport { UploadStatus } from \"./upload-status\";\nimport { MultiUploadStatus } from \"./multi-upload-status\";\nimport { useUploadToast } from \"./use-upload-toast\";\n\nexport type UploadButtonProps = UseUploadControlsOptions & {\n className?: string;\n label?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline status below the button (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function UploadButton({\n className,\n label,\n disabled,\n tooltipText,\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadButtonProps) {\n const ctrl = useUploadControls(options);\n const isMulti = ctrl.mode === \"multi\";\n const isDisabled = disabled || ctrl.isUploading;\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <MultiUploadStatus\n phase={ctrl.phase}\n files={ctrl.files}\n totalProgress={ctrl.totalProgress}\n error={ctrl.error}\n onCancel={ctrl.cancel}\n />\n ) : (\n <UploadStatus\n phase={ctrl.phase}\n progress={ctrl.progress}\n error={ctrl.error}\n fileInfo={ctrl.fileInfo}\n onCancel={ctrl.cancel}\n />\n )\n ) : null;\n\n return (\n <div className={cn(\"inline-flex flex-col gap-2\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <input {...ctrl.inputProps} />\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n size=\"default\"\n disabled={isDisabled}\n onClick={ctrl.openFilePicker}\n />\n }>\n <UploadIcon data-icon=\"inline-start\" />\n {label ?? (isMulti ? \"Upload files\" : \"Upload file\")}\n </TooltipTrigger>\n <TooltipContent>\n {tooltipText ?? (isMulti ? \"Upload files\" : \"Upload file\")}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n {status}\n </div>\n );\n}\n","\"use client\";\n\nimport { UploadIcon } from \"lucide-react\";\nimport type { UseUploadControlsOptions } from \"@better-s3/react\";\nimport { useUploadControls } from \"@better-s3/react\";\nimport { cn } from \"@/lib/utils\";\nimport { UploadStatus } from \"./upload-status\";\nimport { MultiUploadStatus } from \"./multi-upload-status\";\nimport { useUploadToast } from \"./use-upload-toast\";\n\nexport type UploadDropzoneProps = UseUploadControlsOptions & {\n className?: string;\n label?: string;\n disabled?: boolean;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline status inside the dropzone (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function UploadDropzone({\n className,\n label,\n disabled,\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadDropzoneProps) {\n const ctrl = useUploadControls(options);\n const isMulti = ctrl.mode === \"multi\";\n const isDisabled = disabled || ctrl.isUploading;\n\n useUploadToast(ctrl, enableToast);\n\n const status = showStatus ? (\n isMulti ? (\n <MultiUploadStatus\n phase={ctrl.phase}\n files={ctrl.files}\n totalProgress={ctrl.totalProgress}\n error={ctrl.error}\n onCancel={ctrl.cancel}\n />\n ) : (\n <UploadStatus\n phase={ctrl.phase}\n progress={ctrl.progress}\n error={ctrl.error}\n fileInfo={ctrl.fileInfo}\n onCancel={ctrl.cancel}\n />\n )\n ) : null;\n\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed p-6 text-center transition-colors\",\n isDisabled\n ? \"cursor-not-allowed border-muted-foreground/25\"\n : \"cursor-pointer border-muted-foreground/25 hover:border-primary/50\",\n className,\n )}\n onClick={isDisabled ? undefined : ctrl.openFilePicker}\n {...(isDisabled ? {} : ctrl.dropHandlers)}>\n <input {...ctrl.inputProps} />\n <UploadIcon\n className={cn(\n \"size-6 text-muted-foreground\",\n isDisabled && \"opacity-50\",\n )}\n />\n <p\n className={cn(\n \"text-sm text-muted-foreground\",\n isDisabled && \"opacity-50\",\n )}>\n {label ??\n (isMulti\n ? \"Click or drag & drop files to upload\"\n : \"Click or drag & drop to upload\")}\n </p>\n {status && <div className=\"w-full text-left\">{status}</div>}\n </div>\n );\n}\n","\"use client\";\n\nimport { AlertCircleIcon, DownloadIcon, LoaderIcon } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport type { S3Api } from \"@better-s3/react\";\nimport { useDownload } from \"@better-s3/react\";\n\nconst truncateMsg = (msg: string, max = 100) =>\n msg.length > max ? msg.slice(0, max) + \"…\" : msg;\nimport { Button } from \"@/ui/button\";\n\ntype DownloadButtonProps = {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n label?: string;\n className?: string;\n disabled?: boolean;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status below the button (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function DownloadButton({\n api,\n objectKey,\n fileName,\n label,\n className,\n disabled,\n toast: enableToast = true,\n showStatus = true,\n}: DownloadButtonProps) {\n const dl = useDownload({\n api,\n onInitiated: () => {\n if (enableToast) toast.success(\"Download started\");\n },\n onError: (_key, error) => {\n if (enableToast) {\n toast.error(\"Download failed\", {\n description: truncateMsg(\n error instanceof Error ? error.message : \"Unknown error\",\n ),\n });\n }\n },\n });\n\n const isPending = dl.phase === \"presigning\";\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <Button\n size=\"default\"\n variant=\"outline\"\n disabled={disabled || isPending}\n onClick={() => dl.download(objectKey, fileName)}>\n <span className=\"inline-flex items-center gap-1\">\n {isPending ? (\n <LoaderIcon className=\"animate-spin\" data-icon=\"inline-start\" />\n ) : (\n <DownloadIcon data-icon=\"inline-start\" />\n )}\n {label ?? \"Download\"}\n </span>\n </Button>\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {dl.error ?? \"Download failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { DownloadIcon, AlertCircleIcon } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { S3Api, FetchDownloadHooks } from \"@better-s3/react\";\nimport { useFetchDownload } from \"@better-s3/react\";\n\nconst truncateMsg = (msg: string, max = 100) =>\n msg.length > max ? msg.slice(0, max) + \"…\" : msg;\nimport { Button } from \"@/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/ui/tooltip\";\n\ntype ProgressDownloadButtonProps = FetchDownloadHooks & {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n /** Target bucket (overrides server default) */\n bucket?: string;\n label?: string;\n className?: string;\n fillClassName?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status below the button (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function ProgressDownloadButton({\n api,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n fillClassName,\n disabled,\n tooltipText = \"Download file\",\n toast: enableToast = true,\n showStatus = true,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess,\n onError,\n onCancel,\n}: ProgressDownloadButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const dl = useFetchDownload({\n api,\n bucket,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess: (key, actualFileName) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.success(\"Download complete\", {\n description: `${actualFileName}${fileSize != null ? ` · ${formatFileSize(fileSize)}` : \"\"}`,\n });\n }\n onSuccess?.(key, actualFileName);\n },\n onError: (key, error, phase) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.error(\"Download failed\", {\n description: truncateMsg(\n error instanceof Error ? error.message : \"Unknown error\",\n ),\n });\n }\n onError?.(key, error, phase);\n },\n onCancel: (key) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.info(\"Download cancelled\", { description: displayName });\n }\n onCancel?.(key);\n },\n });\n\n const isDownloading = dl.phase === \"downloading\" || dl.phase === \"presigning\";\n\n const handleClick = () => {\n if (isDownloading) {\n dl.cancel();\n return;\n }\n dl.download(objectKey, fileName);\n };\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger\n render={\n <Button\n size=\"default\"\n variant=\"outline\"\n disabled={disabled}\n className={cn(\"relative min-w-24 overflow-hidden\")}\n onClick={handleClick}\n />\n }>\n {isDownloading && (\n <span\n className={cn(\n \"absolute inset-0 bg-primary/15 transition-[width] duration-200\",\n fillClassName,\n )}\n style={{ width: `${dl.progress.percent}%` }}\n />\n )}\n <span className=\"relative z-10 inline-flex items-center gap-1\">\n <DownloadIcon data-icon=\"inline-start\" />\n {isDownloading\n ? formatFileSize(dl.progress.loaded)\n : (label ?? \"Download\")}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {isDownloading ? \"Cancel download\" : tooltipText}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {dl.error ?? \"Download failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { AlertDialog as AlertDialogPrimitive } from \"@base-ui/react/alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/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 {\n Trash2Icon,\n LoaderIcon,\n AlertCircleIcon,\n CheckCircle2Icon,\n} from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { S3Api, DeleteHooks } from \"@better-s3/react\";\nimport { useDelete } from \"@better-s3/react\";\n\nconst truncateMsg = (msg: string, max = 100) =>\n msg.length > max ? msg.slice(0, max) + \"…\" : msg;\nimport { Button } from \"@/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 \"@/ui/alert-dialog\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/ui/tooltip\";\n\ntype DeleteButtonProps = DeleteHooks & {\n api: S3Api;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\n /** Target bucket (overrides server default) */\n bucket?: string;\n label?: string;\n className?: string;\n disabled?: boolean;\n tooltipText?: string;\n /** Enable sonner toasts (default: `true`) */\n toast?: boolean;\n /** Show inline error status below the button (default: `true`) */\n showStatus?: boolean;\n confirmTitle?: string;\n confirmDescription?: string;\n};\n\nexport function DeleteButton({\n api,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n disabled,\n tooltipText = \"Delete file\",\n toast: enableToast = true,\n showStatus = true,\n confirmTitle = \"Delete file?\",\n confirmDescription,\n beforeDelete,\n onDeleteStart,\n onSuccess,\n onError,\n}: DeleteButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const del = useDelete({\n api,\n bucket,\n beforeDelete,\n onDeleteStart,\n onSuccess: (key) => {\n if (enableToast) {\n toast.success(\"File deleted\", { description: displayName });\n }\n onSuccess?.(key);\n },\n onError: (key, error, phase) => {\n if (enableToast) {\n toast.error(\"Delete failed\", {\n description: truncateMsg(\n error instanceof Error ? error.message : \"Unknown error\",\n ),\n });\n }\n onError?.(key, error, phase);\n },\n });\n\n const isDeleting = del.phase === \"deleting\";\n const isDisabled = disabled || isDeleting;\n\n const description =\n confirmDescription ??\n `Are you sure you want to delete \"${displayName}\"${fileSize != null ? ` (${formatFileSize(fileSize)})` : \"\"}? This action cannot be undone.`;\n\n return (\n <div className={cn(\"inline-flex flex-col gap-1.5\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <AlertDialog\n open={del.phase === \"confirming\"}\n onOpenChange={(open) => {\n if (!open) del.cancelDelete();\n }}>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger\n render={\n <AlertDialogTrigger\n disabled={isDisabled}\n onClick={() => del.requestDelete(objectKey)}\n render={\n <Button\n size=\"default\"\n variant=\"destructive\"\n disabled={isDisabled}\n />\n }\n />\n }>\n {isDeleting ? (\n <LoaderIcon\n className=\"animate-spin\"\n data-icon=\"inline-start\"\n />\n ) : (\n <Trash2Icon data-icon=\"inline-start\" />\n )}\n {label ?? \"Delete\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogMedia>\n <Trash2Icon />\n </AlertDialogMedia>\n <AlertDialogTitle>{confirmTitle}</AlertDialogTitle>\n <AlertDialogDescription className=\"[overflow-wrap:anywhere]\">{description}</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => del.confirmDelete()}>\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n\n {showStatus && del.phase === \"success\" && (\n <div className=\"flex min-w-0 items-center gap-1.5 text-xs\">\n <CheckCircle2Icon className=\"size-3.5 shrink-0 text-green-600\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-green-600\">\n &ldquo;\n <span className=\"inline-block max-w-[14ch] truncate align-bottom\">\n {displayName}\n </span>\n &rdquo; deleted\n </p>\n </div>\n )}\n\n {showStatus && del.phase === \"error\" && (\n <div className=\"flex min-w-0 items-start gap-1.5 text-xs\">\n <AlertCircleIcon className=\"mt-0.5 size-3.5 shrink-0 text-destructive\" />\n <p className=\"min-w-0 [overflow-wrap:anywhere] text-destructive\">\n {del.error ?? \"Delete failed\"}\n </p>\n </div>\n )}\n </div>\n );\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog";
3
- import { Button } from "../../components/ui/button";
3
+ import { Button } from "../ui/button";
4
4
  declare function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props): import("react/jsx-runtime").JSX.Element;
5
5
  declare function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props): import("react/jsx-runtime").JSX.Element;
6
6
  declare function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props): import("react/jsx-runtime").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-s3/ui",
3
- "version": "3.1044.0",
3
+ "version": "3.1045.0",
4
4
  "description": "Pre-built React UI components for S3 file upload, download, and delete",
5
5
  "keywords": [
6
6
  "s3",
@@ -36,7 +36,7 @@
36
36
  "styles.css"
37
37
  ],
38
38
  "dependencies": {
39
- "@better-s3/react": "3.1044.0"
39
+ "@better-s3/react": "3.1045.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@base-ui/react": ">=1.0.0",
File without changes
File without changes
File without changes
File without changes