@better-s3/ui 1.0.0 → 2.1.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/README.md CHANGED
@@ -1,98 +1,54 @@
1
1
  # @better-s3/ui
2
2
 
3
- Pre-built React UI components for S3 file upload, download, and delete built with [shadcn/ui](https://ui.shadcn.com) patterns and Tailwind CSS.
3
+ Pre-built React components for S3 file operations — upload (button & dropzone), download, and delete with confirmation. Built with [shadcn/ui](https://ui.shadcn.com) and Tailwind CSS.
4
4
 
5
- > **Don't need pre-built UI?** Use [`@better-s3/react`](../better-s3-react) for headless hooks and bring your own components.
6
-
7
- > **shadcn CLI**: You can also install individual components via `npx shadcn add` (coming soon).
5
+ > **Need full control?** Use [`@better-s3/react`](../better-s3-react) for headless hooks.
8
6
 
9
7
  ## Install
10
8
 
11
9
  ```bash
12
- pnpm add @better-s3/ui @better-s3/core
10
+ pnpm add @better-s3/ui @better-s3/server
13
11
  ```
14
12
 
15
- **Peer dependencies:** `react`, `@base-ui/react`, `sonner`, `lucide-react`, `class-variance-authority`, `clsx`, `tailwind-merge`
13
+ **Peer deps:** `react`, `sonner`, `lucide-react`, `clsx`, `tailwind-merge`
16
14
 
17
15
  ## Setup
18
16
 
19
- Import the stylesheet in your app:
20
-
21
17
  ```tsx
22
18
  import "@better-s3/ui/styles.css";
23
19
  ```
24
20
 
25
21
  ## Components
26
22
 
27
- ### `<Upload />` — Single file upload
28
-
29
23
  ```tsx
30
- import { Upload } from "@better-s3/ui";
31
- import { createPresignApi } from "@better-s3/core";
24
+ import { createPresignApi } from "@better-s3/server";
25
+ import { Upload, MultiUpload, DownloadButton, DeleteButton } from "@better-s3/ui";
32
26
 
33
- const presignApi = createPresignApi({ basePath: "/api/s3" });
27
+ const presignApi = createPresignApi("/api/s3");
34
28
 
29
+ // Single upload (button or dropzone)
35
30
  <Upload
36
31
  presignApi={presignApi}
37
32
  objectKey={(file) => `uploads/${file.name}`}
38
- variant="dropzone" // "button" | "dropzone"
33
+ variant="dropzone"
39
34
  accept={["image/*"]}
40
35
  maxFileSize={10 * 1024 * 1024}
41
- toast={true} // sonner toast notifications
42
- showStatus={true} // inline progress display
43
- />;
44
- ```
45
-
46
- ### `<MultiUpload />` — Batch file upload
47
-
48
- ```tsx
49
- import { MultiUpload } from "@better-s3/ui";
36
+ />
50
37
 
38
+ // Batch upload
51
39
  <MultiUpload
52
40
  presignApi={presignApi}
53
41
  objectKey={(file) => `uploads/${file.name}`}
54
42
  maxFiles={10}
55
- variant="dropzone"
56
- />;
57
- ```
43
+ />
58
44
 
59
- ### `<DownloadButton />` — File download
45
+ // Download
46
+ <DownloadButton presignApi={presignApi} objectKey="report.pdf" fileName="report.pdf" />
60
47
 
61
- ```tsx
62
- import { DownloadButton } from "@better-s3/ui";
63
-
64
- <DownloadButton
65
- presignApi={presignApi}
66
- objectKey="uploads/report.pdf"
67
- fileName="report.pdf"
68
- mode="native" // "native" | "fetch"
69
- />;
70
- ```
71
-
72
- ### `<DeleteButton />` — File delete with confirmation
73
-
74
- ```tsx
75
- import { DeleteButton } from "@better-s3/ui";
76
-
77
- <DeleteButton
78
- presignApi={presignApi}
79
- objectKey="uploads/report.pdf"
80
- fileName="report.pdf"
81
- confirmTitle="Delete file?"
82
- confirmDescription="This action cannot be undone."
83
- />;
48
+ // Delete with confirmation dialog
49
+ <DeleteButton presignApi={presignApi} objectKey="report.pdf" />
84
50
  ```
85
51
 
86
- ## Features
87
-
88
- - **Two upload variants** — compact button or drag-and-drop dropzone
89
- - **Toast notifications** — loading, success, and error toasts via Sonner
90
- - **Inline progress** — progress bar with file name and phase icons
91
- - **Delete confirmation** — AlertDialog before destructive actions
92
- - **Download modes** — native browser download or streaming with progress
93
- - **Tailwind CSS** — fully styled, customizable via className props
94
- - **Accessible** — built on Base UI primitives
95
-
96
52
  ## License
97
53
 
98
54
  MIT
@@ -1,9 +1,11 @@
1
- import type { PresignApi, DeleteHooks } from "@better-s3/core";
1
+ import type { PresignApi, DeleteHooks } from "@better-s3/react";
2
2
  type DeleteButtonProps = DeleteHooks & {
3
3
  presignApi: PresignApi;
4
4
  objectKey: string;
5
5
  fileName?: string;
6
6
  fileSize?: number;
7
+ /** Target bucket (overrides server default) */
8
+ bucket?: string;
7
9
  label?: string;
8
10
  className?: string;
9
11
  disabled?: boolean;
@@ -15,5 +17,5 @@ type DeleteButtonProps = DeleteHooks & {
15
17
  confirmTitle?: string;
16
18
  confirmDescription?: string;
17
19
  };
18
- export declare function DeleteButton({ presignApi, objectKey, fileName, fileSize, label, className, disabled, tooltipText, toast: enableToast, showStatus, confirmTitle, confirmDescription, beforeDelete, onDeleteStart, onSuccess, onError, }: DeleteButtonProps): import("react/jsx-runtime").JSX.Element;
20
+ export declare function DeleteButton({ presignApi, objectKey, fileName, fileSize, bucket, label, className, disabled, tooltipText, toast: enableToast, showStatus, confirmTitle, confirmDescription, beforeDelete, onDeleteStart, onSuccess, onError, }: DeleteButtonProps): import("react/jsx-runtime").JSX.Element;
19
21
  export {};
@@ -1,23 +1,19 @@
1
- import type { PresignApi, DownloadHooks } from "@better-s3/core";
1
+ import type { PresignApi, DownloadHooks } from "@better-s3/react";
2
2
  type DownloadButtonProps = DownloadHooks & {
3
3
  presignApi: PresignApi;
4
4
  objectKey: string;
5
5
  fileName?: string;
6
6
  fileSize?: number;
7
+ /** Target bucket (overrides server default) */
8
+ bucket?: string;
7
9
  label?: string;
8
10
  className?: string;
9
- fillClassName?: string;
10
11
  disabled?: boolean;
11
12
  tooltipText?: string;
12
13
  /** Enable sonner toasts (default: `true`) */
13
14
  toast?: boolean;
14
15
  /** Show inline error status below the button (default: `true`) */
15
16
  showStatus?: boolean;
16
- /**
17
- * `"native"` — browser handles download natively via presigned URL (default)
18
- * `"fetch"` — streams via fetch, shows in-button progress
19
- */
20
- mode?: "native" | "fetch";
21
17
  };
22
- export declare function DownloadButton({ presignApi, objectKey, fileName, fileSize, label, className, fillClassName, disabled, tooltipText, toast: enableToast, showStatus, mode, beforeDownload, onDownloadStart, onProgress, onSuccess, onError, onCancel, }: DownloadButtonProps): import("react/jsx-runtime").JSX.Element;
18
+ export declare function DownloadButton({ presignApi, objectKey, fileName, fileSize, bucket, label, className, disabled, tooltipText, toast: enableToast, showStatus, beforeDownload, onSuccess, onError, }: DownloadButtonProps): import("react/jsx-runtime").JSX.Element;
23
19
  export {};
@@ -0,0 +1,20 @@
1
+ import type { PresignApi, FetchDownloadHooks } from "@better-s3/react";
2
+ type FetchDownloadButtonProps = FetchDownloadHooks & {
3
+ presignApi: PresignApi;
4
+ objectKey: string;
5
+ fileName?: string;
6
+ fileSize?: number;
7
+ /** Target bucket (overrides server default) */
8
+ bucket?: string;
9
+ label?: string;
10
+ className?: string;
11
+ fillClassName?: string;
12
+ disabled?: boolean;
13
+ tooltipText?: string;
14
+ /** Enable sonner toasts (default: `true`) */
15
+ toast?: boolean;
16
+ /** Show inline error status below the button (default: `true`) */
17
+ showStatus?: boolean;
18
+ };
19
+ export declare function FetchDownloadButton({ presignApi, objectKey, fileName, fileSize, bucket, label, className, fillClassName, disabled, tooltipText, toast: enableToast, showStatus, beforeDownload, onDownloadStart, onProgress, onSuccess, onError, onCancel, }: FetchDownloadButtonProps): import("react/jsx-runtime").JSX.Element;
20
+ export {};
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export { MultiUpload, type MultiUploadProps } from "./upload/multi-upload";
3
3
  export { UploadStatus } from "./upload/upload-status";
4
4
  export { MultiUploadStatus } from "./upload/multi-upload-status";
5
5
  export { DownloadButton } from "./download/download-button";
6
+ export { FetchDownloadButton } from "./download/fetch-download-button";
6
7
  export { DeleteButton } from "./delete/delete-button";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {useRef,useEffect}from'react';import {toast}from'sonner';import {XIcon,CheckCircleIcon,AlertCircleIcon,UploadIcon,DownloadIcon,LoaderIcon,Trash2Icon}from'lucide-react';import {formatFileSize}from'@better-s3/core';import {useUploadControls,useMultiUploadControls,useDownload,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,Fragment}from'react/jsx-runtime';import {Tooltip}from'@base-ui/react/tooltip';import {Progress}from'@base-ui/react/progress';import {AlertDialog}from'@base-ui/react/alert-dialog';function r(...o){return twMerge(clsx(o))}var Se=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:o,variant:e="default",size:a="default",...i}){return jsx(Button,{"data-slot":"button",className:r(Se({variant:e,size:a,className:o})),...i})}function C({delay:o=0,...e}){return jsx(Tooltip.Provider,{"data-slot":"tooltip-provider",delay:o,...e})}function y({...o}){return jsx(Tooltip.Root,{"data-slot":"tooltip",...o})}function A({...o}){return jsx(Tooltip.Trigger,{"data-slot":"tooltip-trigger",...o})}function U({className:o,side:e="top",sideOffset:a=4,align:i="center",alignOffset:l=0,children:d,...g}){return jsx(Tooltip.Portal,{children:jsx(Tooltip.Positioner,{align:i,alignOffset:l,side:e,sideOffset:a,className:"isolate z-50",children:jsxs(Tooltip.Popup,{"data-slot":"tooltip-content",className:r("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",o),...g,children:[d,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 Z({percent:o,size:e=20,strokeWidth:a=2.5}){let i=(e-a)/2,l=2*Math.PI*i,d=l-o/100*l;return jsxs("svg",{width:e,height:e,className:"shrink-0 -rotate-90",children:[jsx("circle",{cx:e/2,cy:e/2,r:i,fill:"none",stroke:"currentColor",strokeWidth:a,className:"text-muted-foreground/20"}),jsx("circle",{cx:e/2,cy:e/2,r:i,fill:"none",stroke:"currentColor",strokeWidth:a,strokeDasharray:l,strokeDashoffset:d,strokeLinecap:"round",className:"text-primary transition-[stroke-dashoffset] duration-200"})]})}function ee({phase:o,progress:e,error:a,fileInfo:i,onCancel:l}){return o==="idle"?null:o==="uploading"&&i?jsxs("div",{className:"flex w-full items-center gap-1.5 text-xs",children:[jsx(Z,{percent:e.percent,size:14,strokeWidth:2}),jsx("span",{className:"max-w-32 min-w-16 truncate sm:max-w-48",children:i.name}),jsxs("span",{className:"shrink-0 text-muted-foreground",children:[formatFileSize(e.loaded)," / ",formatFileSize(i.size)," (",e.percent,"%)"]}),jsx(c,{variant:"ghost",size:"icon",className:"ml-auto size-6 shrink-0",onClick:d=>{d.stopPropagation(),l?.();},children:jsx(XIcon,{className:"size-3.5"})})]}):o==="success"&&i?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:"max-w-32 min-w-16 truncate sm:max-w-48",children:i.name}),jsx("span",{className:"shrink-0 text-muted-foreground",children:formatFileSize(i.size)})]}):o==="error"?jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),i&&jsxs(Fragment,{children:[jsx("span",{className:"max-w-32 min-w-16 truncate sm:max-w-48",children:i.name}),jsx("span",{className:"shrink-0 text-muted-foreground",children:formatFileSize(i.size)})]})]}),jsx("span",{className:"text-destructive",children:a??"Upload failed"})]}):o==="validating"||o==="presigning"?jsx("span",{className:"text-xs text-muted-foreground",children:"Preparing\u2026"}):null}function Le({variant:o="button",objectKey:e,className:a,label:i,disabled:l,tooltipText:d="Upload file",toast:g=true,showStatus:$=true,...T}){let t=useUploadControls({...T,objectKey:e}),s=useRef(null),n=l||t.isUploading,D=useRef(t.phase);D.current!==t.phase&&(D.current=t.phase,g&&(t.phase==="idle"&&s.current&&(toast.dismiss(s.current),s.current=null),t.phase==="success"&&t.fileInfo&&(s.current&&toast.dismiss(s.current),toast.success("Upload complete",{description:formatFileSize(t.fileInfo.size)}),s.current=null),t.phase==="error"&&(s.current&&toast.dismiss(s.current),toast.error("Upload failed",{description:t.error??"Unknown error"}),s.current=null))),useEffect(()=>{if(g&&t.phase==="uploading"&&t.fileInfo){let P=s.current??`upload-${Date.now()}`;s.current=P,toast.loading("Uploading\u2026",{id:P,description:`${formatFileSize(t.progress.loaded)} / ${formatFileSize(t.fileInfo.size)} (${t.progress.percent}%)`,cancel:{label:"Cancel",onClick:()=>t.cancel()}});}},[g,t.phase,t.progress.percent,t.progress.loaded,t.fileInfo,t.cancel]);let v=$?jsx(ee,{phase:t.phase,progress:t.progress,error:t.error,fileInfo:t.fileInfo,onCancel:t.cancel}):null;return o==="dropzone"?jsxs("div",{className:r("flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed p-6 text-center transition-colors",n?"cursor-not-allowed border-muted-foreground/25":"cursor-pointer border-muted-foreground/25 hover:border-primary/50",a),onClick:n?void 0:t.openFilePicker,...n?{}:t.dropHandlers,children:[jsx("input",{...t.inputProps}),jsx(UploadIcon,{className:r("size-6 text-muted-foreground",n&&"opacity-50")}),jsx("p",{className:r("text-sm text-muted-foreground",n&&"opacity-50"),children:i??"Click or drag & drop to upload"}),v&&jsx("div",{className:"w-full text-left",children:v})]}):jsxs("div",{className:r("inline-flex flex-col gap-2",a),children:[jsxs("div",{className:"inline-flex items-center gap-2",children:[jsx("input",{...t.inputProps}),jsx(C,{children:jsxs(y,{children:[jsxs(A,{render:jsx(c,{size:"default",disabled:n,onClick:t.openFilePicker}),children:[jsx(UploadIcon,{"data-icon":"inline-start"}),i??"Upload file"]}),jsx(U,{children:d})]})})]}),v]})}function de({className:o,children:e,value:a,...i}){return jsxs(Progress.Root,{value:a,"data-slot":"progress",className:r("flex flex-wrap gap-3",o),...i,children:[e,jsx(Ee,{children:jsx(We,{})})]})}function Ee({className:o,...e}){return jsx(Progress.Track,{className:r("relative flex h-1 w-full items-center overflow-x-hidden rounded-md bg-muted",o),"data-slot":"progress-track",...e})}function We({className:o,...e}){return jsx(Progress.Indicator,{"data-slot":"progress-indicator",className:r("h-full bg-primary transition-all",o),...e})}function pe({className:o,...e}){return jsx(Progress.Label,{className:r("text-xs/relaxed font-medium",o),"data-slot":"progress-label",...e})}function ce({className:o,...e}){return jsx(Progress.Value,{className:r("ms-auto text-xs/relaxed text-muted-foreground tabular-nums",o),"data-slot":"progress-value",...e})}function ie({phase:o,files:e,totalProgress:a,error:i,onCancel:l}){return o==="idle"?null:o==="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(de,{value:a.percent,className:"flex-1",children:[jsxs(pe,{children:[e.filter(d=>d.status==="success").length,"/",e.length," files"]}),jsx(ce,{})]}),jsx(c,{variant:"ghost",size:"icon",className:"size-7 shrink-0",onClick:d=>{d.stopPropagation(),l?.();},children:jsx(XIcon,{className:"size-4"})})]}),jsx(re,{files:e})]}):o==="success"?jsxs("div",{className:"flex w-full flex-col gap-1",children:[jsxs("span",{className:"text-xs text-green-600",children:["All ",e.length," file(s) uploaded"]}),jsx(re,{files:e})]}):o==="error"?jsxs("div",{className:"flex w-full flex-col gap-1",children:[jsx("span",{className:"text-xs text-destructive",children:i??"Upload failed"}),e.length>0&&jsx(re,{files:e})]}):o==="validating"?jsx("span",{className:"text-xs text-muted-foreground",children:"Validating\u2026"}):null}function re({files:o}){return jsx("ul",{className:"flex flex-col gap-1",children:o.map(e=>jsxs("li",{className:"flex flex-col gap-0.5 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[e.status==="success"&&jsx(CheckCircleIcon,{className:"size-3.5 shrink-0 text-green-600"}),e.status==="error"&&jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),(e.status==="pending"||e.status==="uploading")&&jsx(Z,{percent:e.status==="uploading"?e.progress.percent:0,size:14,strokeWidth:2}),jsx("span",{className:"max-w-32 min-w-16 truncate sm:max-w-48",children:e.fileName}),e.status==="uploading"?jsxs("span",{className:"shrink-0 text-muted-foreground",children:[formatFileSize(e.progress.loaded)," /"," ",formatFileSize(e.fileSize)," (",e.progress.percent,"%)"]}):jsx("span",{className:"shrink-0 text-muted-foreground",children:formatFileSize(e.fileSize)})]}),e.status==="error"&&e.error&&jsx("span",{className:"pl-5 text-destructive",children:e.error})]},e.id))})}function Ze({variant:o="button",objectKey:e,className:a,label:i,disabled:l,tooltipText:d="Upload files",toast:g=true,showStatus:$=true,...T}){let t=useMultiUploadControls({...T,objectKey:e}),s=useRef(null),n=l||t.isUploading,D=useRef(t.phase);if(D.current!==t.phase&&(D.current=t.phase,g&&(t.phase==="idle"&&s.current&&(toast.dismiss(s.current),s.current=null),t.phase==="success"&&(s.current&&toast.dismiss(s.current),toast.success(`${t.files.length} file(s) uploaded`,{description:formatFileSize(t.totalProgress.total)}),s.current=null),t.phase==="error"&&t.files.length>0))){let P=t.files.filter(h=>h.status==="success").length,F=t.files.filter(h=>h.status==="error").length;s.current&&toast.dismiss(s.current),toast.error("Upload finished with errors",{description:`${P} succeeded, ${F} failed`}),s.current=null;}useEffect(()=>{if(g&&t.phase==="uploading"){let P=s.current??`multi-upload-${Date.now()}`;s.current=P;let F=t.files.filter(h=>h.status==="success").length;toast.loading(`Uploading\u2026 ${F}/${t.files.length}`,{id:P,description:`${formatFileSize(t.totalProgress.loaded)} / ${formatFileSize(t.totalProgress.total)} (${t.totalProgress.percent}%)`,cancel:{label:"Cancel",onClick:()=>t.cancel()}});}},[g,t.phase,t.totalProgress.percent,t.totalProgress.loaded,t.files,t.cancel]);let v=$?jsx(ie,{phase:t.phase,files:t.files,totalProgress:t.totalProgress,error:t.error,onCancel:t.cancel}):null;return o==="dropzone"?jsxs("div",{className:r("flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed p-6 text-center transition-colors",n?"cursor-not-allowed border-muted-foreground/25":"cursor-pointer border-muted-foreground/25 hover:border-primary/50",a),onClick:n?void 0:t.openFilePicker,...n?{}:t.dropHandlers,children:[jsx("input",{...t.inputProps}),jsx(UploadIcon,{className:r("size-6 text-muted-foreground",n&&"opacity-50")}),jsx("p",{className:r("text-sm text-muted-foreground",n&&"opacity-50"),children:i??"Click or drag & drop files to upload"}),v&&jsx("div",{className:"w-full text-left",children:v})]}):jsxs("div",{className:r("inline-flex flex-col gap-2",a),children:[jsxs("div",{className:"inline-flex items-center gap-2",children:[jsx("input",{...t.inputProps}),jsx(C,{children:jsxs(y,{children:[jsxs(A,{render:jsx(c,{size:"default",disabled:n,onClick:t.openFilePicker}),children:[jsx(UploadIcon,{"data-icon":"inline-start"}),i??"Upload files"]}),jsx(U,{children:d})]})})]}),v]})}function tt({presignApi:o,objectKey:e,fileName:a,fileSize:i,label:l,className:d,fillClassName:g,disabled:$,tooltipText:T="Download file",toast:t=true,showStatus:s=true,mode:n="native",beforeDownload:D,onDownloadStart:v,onProgress:P,onSuccess:F,onError:h,onCancel:k}){let R=a??e.split("/").pop()??e,f=useDownload({presignApi:o,mode:n,beforeDownload:D,onDownloadStart:v,onProgress:P,onSuccess:_=>{t&&(toast.dismiss(`dl-${e}`),toast.success("Download complete",{description:`${R}${i!=null?` \xB7 ${formatFileSize(i)}`:""}`})),F?.(_);},onError:(_,j,Ce)=>{t&&(toast.dismiss(`dl-${e}`),toast.error("Download failed",{description:j instanceof Error?j.message:"Unknown error"})),h?.(_,j,Ce);},onCancel:_=>{t&&(toast.dismiss(`dl-${e}`),toast.info("Download cancelled",{description:R})),k?.(_);}}),I=n==="fetch"&&(f.phase==="downloading"||f.phase==="presigning"),M=n==="native"?f.phase==="presigning":I,G=()=>{if(n==="fetch"&&I){f.cancel();return}f.download(e,R);};return jsxs("div",{className:r("inline-flex flex-col gap-1.5",d),children:[jsx(C,{children:jsxs(y,{children:[jsxs(A,{render:jsx(c,{size:"default",variant:"outline",disabled:$||n==="native"&&M,className:r(n==="fetch"&&"relative min-w-24 overflow-hidden"),onClick:G}),children:[I&&jsx("span",{className:r("absolute inset-0 bg-primary/15 transition-[width] duration-200",g),style:{width:`${f.progress.percent}%`}}),jsxs("span",{className:r("inline-flex items-center gap-1",n==="fetch"&&"relative z-10"),children:[jsx(DownloadIcon,{"data-icon":"inline-start"}),I?formatFileSize(f.progress.loaded):l??"Download"]})]}),jsx(U,{children:I?"Cancel download":T})]})}),s&&f.phase==="error"&&jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),jsx("span",{className:"max-w-32 min-w-16 truncate sm:max-w-48",children:f.fileName??R})]}),jsx("span",{className:"text-destructive",children:f.error??"Download failed"})]})]})}function fe({...o}){return jsx(AlertDialog.Root,{"data-slot":"alert-dialog",...o})}function xe({...o}){return jsx(AlertDialog.Trigger,{"data-slot":"alert-dialog-trigger",...o})}function ot({...o}){return jsx(AlertDialog.Portal,{"data-slot":"alert-dialog-portal",...o})}function rt({className:o,...e}){return jsx(AlertDialog.Backdrop,{"data-slot":"alert-dialog-overlay",className:r("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",o),...e})}function ve({className:o,size:e="default",...a}){return jsxs(ot,{children:[jsx(rt,{}),jsx(AlertDialog.Popup,{"data-slot":"alert-dialog-content","data-size":e,className:r("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",o),...a})]})}function Pe({className:o,...e}){return jsx("div",{"data-slot":"alert-dialog-header",className:r("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]",o),...e})}function he({className:o,...e}){return jsx("div",{"data-slot":"alert-dialog-footer",className:r("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",o),...e})}function be({className:o,...e}){return jsx("div",{"data-slot":"alert-dialog-media",className:r("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",o),...e})}function Ne({className:o,...e}){return jsx(AlertDialog.Title,{"data-slot":"alert-dialog-title",className:r("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",o),...e})}function ze({className:o,...e}){return jsx(AlertDialog.Description,{"data-slot":"alert-dialog-description",className:r("text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",o),...e})}function De({className:o,...e}){return jsx(c,{"data-slot":"alert-dialog-action",className:r(o),...e})}function ke({className:o,variant:e="outline",size:a="default",...i}){return jsx(AlertDialog.Close,{"data-slot":"alert-dialog-cancel",className:r(o),render:jsx(c,{variant:e,size:a}),...i})}function dt({presignApi:o,objectKey:e,fileName:a,fileSize:i,label:l,className:d,disabled:g,tooltipText:$="Delete file",toast:T=true,showStatus:t=true,confirmTitle:s="Delete file?",confirmDescription:n,beforeDelete:D,onDeleteStart:v,onSuccess:P,onError:F}){let h=a??e.split("/").pop()??e,k=useDelete({presignApi:o,beforeDelete:D,onDeleteStart:v,onSuccess:M=>{T&&toast.success("File deleted",{description:h}),P?.(M);},onError:(M,G,_)=>{T&&toast.error("Delete failed",{description:G instanceof Error?G.message:"Unknown error"}),F?.(M,G,_);}}),R=k.phase==="deleting",f=g||R,I=n??`Are you sure you want to delete "${h}"${i!=null?` (${formatFileSize(i)})`:""}? This action cannot be undone.`;return jsxs("div",{className:r("inline-flex flex-col gap-1.5",d),children:[jsx("div",{className:"inline-flex items-center gap-2",children:jsxs(fe,{open:k.phase==="confirming",onOpenChange:M=>{M||k.cancelDelete();},children:[jsx(C,{children:jsxs(y,{children:[jsxs(A,{render:jsx(xe,{disabled:f,onClick:()=>k.requestDelete(e),render:jsx(c,{size:"default",variant:"destructive",disabled:f})}),children:[R?jsx(LoaderIcon,{className:"animate-spin","data-icon":"inline-start"}):jsx(Trash2Icon,{"data-icon":"inline-start"}),l??"Delete"]}),jsx(U,{children:$})]})}),jsxs(ve,{children:[jsxs(Pe,{children:[jsx(be,{children:jsx(Trash2Icon,{})}),jsx(Ne,{children:s}),jsx(ze,{children:I})]}),jsxs(he,{children:[jsx(ke,{children:"Cancel"}),jsx(De,{variant:"destructive",onClick:()=>k.confirmDelete(),children:"Delete"})]})]})]})}),t&&k.phase==="error"&&jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),jsx("span",{className:"max-w-32 truncate sm:max-w-48",children:h})]}),jsx("span",{className:"text-destructive",children:k.error??"Delete failed"})]})]})}export{dt as DeleteButton,tt as DownloadButton,Ze as MultiUpload,ie as MultiUploadStatus,Le as Upload,ee as UploadStatus};//# sourceMappingURL=index.js.map
1
+ import {useRef,useEffect}from'react';import {toast}from'sonner';import {XIcon,CheckCircleIcon,AlertCircleIcon,UploadIcon,LoaderIcon,DownloadIcon,Trash2Icon}from'lucide-react';import {formatFileSize,useUploadControls,useMultiUploadControls,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,Fragment}from'react/jsx-runtime';import {Tooltip}from'@base-ui/react/tooltip';import {Progress}from'@base-ui/react/progress';import {AlertDialog}from'@base-ui/react/alert-dialog';function i(...o){return twMerge(clsx(o))}var $e=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 p({className:o,variant:e="default",size:s="default",...r}){return jsx(Button,{"data-slot":"button",className:i($e({variant:e,size:s,className:o})),...r})}function z({delay:o=0,...e}){return jsx(Tooltip.Provider,{"data-slot":"tooltip-provider",delay:o,...e})}function k({...o}){return jsx(Tooltip.Root,{"data-slot":"tooltip",...o})}function T({...o}){return jsx(Tooltip.Trigger,{"data-slot":"tooltip-trigger",...o})}function C({className:o,side:e="top",sideOffset:s=4,align:r="center",alignOffset:n=0,children:l,...m}){return jsx(Tooltip.Portal,{children:jsx(Tooltip.Positioner,{align:r,alignOffset:n,side:e,sideOffset:s,className:"isolate z-50",children:jsxs(Tooltip.Popup,{"data-slot":"tooltip-content",className:i("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",o),...m,children:[l,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 K({percent:o,size:e=20,strokeWidth:s=2.5}){let r=(e-s)/2,n=2*Math.PI*r,l=n-o/100*n;return jsxs("svg",{width:e,height:e,className:"shrink-0 -rotate-90",children:[jsx("circle",{cx:e/2,cy:e/2,r,fill:"none",stroke:"currentColor",strokeWidth:s,className:"text-muted-foreground/20"}),jsx("circle",{cx:e/2,cy:e/2,r,fill:"none",stroke:"currentColor",strokeWidth:s,strokeDasharray:n,strokeDashoffset:l,strokeLinecap:"round",className:"text-primary transition-[stroke-dashoffset] duration-200"})]})}function oe({phase:o,progress:e,error:s,fileInfo:r,onCancel:n}){return o==="idle"?null:o==="uploading"&&r?jsxs("div",{className:"flex w-full items-center gap-1.5 text-xs",children:[jsx(K,{percent:e.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(e.loaded)," / ",formatFileSize(r.size)," (",e.percent,"%)"]}),jsx(p,{variant:"ghost",size:"icon",className:"ml-auto size-6 shrink-0",onClick:l=>{l.stopPropagation(),n?.();},children:jsx(XIcon,{className:"size-3.5"})})]}):o==="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:"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)})]}):o==="error"?jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),r&&jsxs(Fragment,{children:[jsx("span",{className:"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)})]})]}),jsx("span",{className:"text-destructive",children:s??"Upload failed"})]}):o==="validating"||o==="presigning"?jsx("span",{className:"text-xs text-muted-foreground",children:"Preparing\u2026"}):null}function We({variant:o="button",objectKey:e,className:s,label:r,disabled:n,tooltipText:l="Upload file",toast:m=true,showStatus:B=true,...F}){let t=useUploadControls({...F,objectKey:e}),a=useRef(null),d=n||t.isUploading,D=useRef(t.phase);D.current!==t.phase&&(D.current=t.phase,m&&(t.phase==="idle"&&a.current&&(toast.dismiss(a.current),a.current=null),t.phase==="success"&&t.fileInfo&&(a.current&&toast.dismiss(a.current),toast.success("Upload complete",{description:formatFileSize(t.fileInfo.size)}),a.current=null),t.phase==="error"&&(a.current&&toast.dismiss(a.current),toast.error("Upload failed",{description:t.error??"Unknown error"}),a.current=null))),useEffect(()=>{if(m&&t.phase==="uploading"&&t.fileInfo){let g=a.current??`upload-${Date.now()}`;a.current=g,toast.loading("Uploading\u2026",{id:g,description:`${formatFileSize(t.progress.loaded)} / ${formatFileSize(t.fileInfo.size)} (${t.progress.percent}%)`,cancel:{label:"Cancel",onClick:()=>t.cancel()}});}},[m,t.phase,t.progress.percent,t.progress.loaded,t.fileInfo,t.cancel]);let v=B?jsx(oe,{phase:t.phase,progress:t.progress,error:t.error,fileInfo:t.fileInfo,onCancel:t.cancel}):null;return o==="dropzone"?jsxs("div",{className:i("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",s),onClick:d?void 0:t.openFilePicker,...d?{}:t.dropHandlers,children:[jsx("input",{...t.inputProps}),jsx(UploadIcon,{className:i("size-6 text-muted-foreground",d&&"opacity-50")}),jsx("p",{className:i("text-sm text-muted-foreground",d&&"opacity-50"),children:r??"Click or drag & drop to upload"}),v&&jsx("div",{className:"w-full text-left",children:v})]}):jsxs("div",{className:i("inline-flex flex-col gap-2",s),children:[jsxs("div",{className:"inline-flex items-center gap-2",children:[jsx("input",{...t.inputProps}),jsx(z,{children:jsxs(k,{children:[jsxs(T,{render:jsx(p,{size:"default",disabled:d,onClick:t.openFilePicker}),children:[jsx(UploadIcon,{"data-icon":"inline-start"}),r??"Upload file"]}),jsx(C,{children:l})]})})]}),v]})}function ce({className:o,children:e,value:s,...r}){return jsxs(Progress.Root,{value:s,"data-slot":"progress",className:i("flex flex-wrap gap-3",o),...r,children:[e,jsx(Xe,{children:jsx(qe,{})})]})}function Xe({className:o,...e}){return jsx(Progress.Track,{className:i("relative flex h-1 w-full items-center overflow-x-hidden rounded-md bg-muted",o),"data-slot":"progress-track",...e})}function qe({className:o,...e}){return jsx(Progress.Indicator,{"data-slot":"progress-indicator",className:i("h-full bg-primary transition-all",o),...e})}function ue({className:o,...e}){return jsx(Progress.Label,{className:i("text-xs/relaxed font-medium",o),"data-slot":"progress-label",...e})}function me({className:o,...e}){return jsx(Progress.Value,{className:i("ms-auto text-xs/relaxed text-muted-foreground tabular-nums",o),"data-slot":"progress-value",...e})}function se({phase:o,files:e,totalProgress:s,error:r,onCancel:n}){return o==="idle"?null:o==="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(ce,{value:s.percent,className:"flex-1",children:[jsxs(ue,{children:[e.filter(l=>l.status==="success").length,"/",e.length," files"]}),jsx(me,{})]}),jsx(p,{variant:"ghost",size:"icon",className:"size-7 shrink-0",onClick:l=>{l.stopPropagation(),n?.();},children:jsx(XIcon,{className:"size-4"})})]}),jsx(ae,{files:e})]}):o==="success"?jsxs("div",{className:"flex w-full flex-col gap-1",children:[jsxs("span",{className:"text-xs text-green-600",children:["All ",e.length," file(s) uploaded"]}),jsx(ae,{files:e})]}):o==="error"?jsxs("div",{className:"flex w-full flex-col gap-1",children:[jsx("span",{className:"text-xs text-destructive",children:r??"Upload failed"}),e.length>0&&jsx(ae,{files:e})]}):o==="validating"?jsx("span",{className:"text-xs text-muted-foreground",children:"Validating\u2026"}):null}function ae({files:o}){return jsx("ul",{className:"flex flex-col gap-1",children:o.map(e=>jsxs("li",{className:"flex flex-col gap-0.5 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[e.status==="success"&&jsx(CheckCircleIcon,{className:"size-3.5 shrink-0 text-green-600"}),e.status==="error"&&jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),(e.status==="pending"||e.status==="uploading")&&jsx(K,{percent:e.status==="uploading"?e.progress.percent:0,size:14,strokeWidth:2}),jsx("span",{className:"max-w-32 min-w-16 truncate sm:max-w-48",children:e.fileName}),e.status==="uploading"?jsxs("span",{className:"shrink-0 text-muted-foreground",children:[formatFileSize(e.progress.loaded)," /"," ",formatFileSize(e.fileSize)," (",e.progress.percent,"%)"]}):jsx("span",{className:"shrink-0 text-muted-foreground",children:formatFileSize(e.fileSize)})]}),e.status==="error"&&e.error&&jsx("span",{className:"pl-5 text-destructive",children:e.error})]},e.id))})}function je({variant:o="button",objectKey:e,className:s,label:r,disabled:n,tooltipText:l="Upload files",toast:m=true,showStatus:B=true,...F}){let t=useMultiUploadControls({...F,objectKey:e}),a=useRef(null),d=n||t.isUploading,D=useRef(t.phase);if(D.current!==t.phase&&(D.current=t.phase,m&&(t.phase==="idle"&&a.current&&(toast.dismiss(a.current),a.current=null),t.phase==="success"&&(a.current&&toast.dismiss(a.current),toast.success(`${t.files.length} file(s) uploaded`,{description:formatFileSize(t.totalProgress.total)}),a.current=null),t.phase==="error"&&t.files.length>0))){let g=t.files.filter(h=>h.status==="success").length,P=t.files.filter(h=>h.status==="error").length;a.current&&toast.dismiss(a.current),toast.error("Upload finished with errors",{description:`${g} succeeded, ${P} failed`}),a.current=null;}useEffect(()=>{if(m&&t.phase==="uploading"){let g=a.current??`multi-upload-${Date.now()}`;a.current=g;let P=t.files.filter(h=>h.status==="success").length;toast.loading(`Uploading\u2026 ${P}/${t.files.length}`,{id:g,description:`${formatFileSize(t.totalProgress.loaded)} / ${formatFileSize(t.totalProgress.total)} (${t.totalProgress.percent}%)`,cancel:{label:"Cancel",onClick:()=>t.cancel()}});}},[m,t.phase,t.totalProgress.percent,t.totalProgress.loaded,t.files,t.cancel]);let v=B?jsx(se,{phase:t.phase,files:t.files,totalProgress:t.totalProgress,error:t.error,onCancel:t.cancel}):null;return o==="dropzone"?jsxs("div",{className:i("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",s),onClick:d?void 0:t.openFilePicker,...d?{}:t.dropHandlers,children:[jsx("input",{...t.inputProps}),jsx(UploadIcon,{className:i("size-6 text-muted-foreground",d&&"opacity-50")}),jsx("p",{className:i("text-sm text-muted-foreground",d&&"opacity-50"),children:r??"Click or drag & drop files to upload"}),v&&jsx("div",{className:"w-full text-left",children:v})]}):jsxs("div",{className:i("inline-flex flex-col gap-2",s),children:[jsxs("div",{className:"inline-flex items-center gap-2",children:[jsx("input",{...t.inputProps}),jsx(z,{children:jsxs(k,{children:[jsxs(T,{render:jsx(p,{size:"default",disabled:d,onClick:t.openFilePicker}),children:[jsx(UploadIcon,{"data-icon":"inline-start"}),r??"Upload files"]}),jsx(C,{children:l})]})})]}),v]})}function at({presignApi:o,objectKey:e,fileName:s,fileSize:r,bucket:n,label:l,className:m,disabled:B,tooltipText:F="Download file",toast:t=true,showStatus:a=true,beforeDownload:d,onSuccess:D,onError:v}){let g=s??e.split("/").pop()??e,P=useDownload({presignApi:o,bucket:n,beforeDownload:d,onSuccess:S=>{t&&toast.success("Download complete",{description:`${g}${r!=null?` \xB7 ${formatFileSize(r)}`:""}`}),D?.(S);},onError:(S,c)=>{t&&toast.error("Download failed",{description:c instanceof Error?c.message:"Unknown error"}),v?.(S,c);}}),h=P.phase==="downloading";return jsxs("div",{className:i("inline-flex flex-col gap-1.5",m),children:[jsx(z,{children:jsxs(k,{children:[jsx(T,{render:jsx(p,{size:"default",variant:"outline",disabled:B||h,onClick:()=>P.download(e,g)}),children:jsxs("span",{className:"inline-flex items-center gap-1",children:[h?jsx(LoaderIcon,{className:"animate-spin","data-icon":"inline-start"}):jsx(DownloadIcon,{"data-icon":"inline-start"}),l??"Download"]})}),jsx(C,{children:F})]})}),a&&P.phase==="error"&&jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),jsx("span",{className:"max-w-32 min-w-16 truncate sm:max-w-48",children:P.fileName??g})]}),jsx("span",{className:"text-destructive",children:P.error??"Download failed"})]})]})}function dt({presignApi:o,objectKey:e,fileName:s,fileSize:r,bucket:n,label:l,className:m,fillClassName:B,disabled:F,tooltipText:t="Download file",toast:a=true,showStatus:d=true,beforeDownload:D,onDownloadStart:v,onProgress:g,onSuccess:P,onError:h,onCancel:S}){let c=s??e.split("/").pop()??e,b=useFetchDownload({presignApi:o,bucket:n,beforeDownload:D,onDownloadStart:v,onProgress:g,onSuccess:w=>{a&&(toast.dismiss(`dl-${e}`),toast.success("Download complete",{description:`${c}${r!=null?` \xB7 ${formatFileSize(r)}`:""}`})),P?.(w);},onError:(w,V,te)=>{a&&(toast.dismiss(`dl-${e}`),toast.error("Download failed",{description:V instanceof Error?V.message:"Unknown error"})),h?.(w,V,te);},onCancel:w=>{a&&(toast.dismiss(`dl-${e}`),toast.info("Download cancelled",{description:c})),S?.(w);}}),_=b.phase==="downloading"||b.phase==="presigning",ee=()=>{if(_){b.cancel();return}b.download(e,c);};return jsxs("div",{className:i("inline-flex flex-col gap-1.5",m),children:[jsx(z,{children:jsxs(k,{children:[jsxs(T,{render:jsx(p,{size:"default",variant:"outline",disabled:F,className:i("relative min-w-24 overflow-hidden"),onClick:ee}),children:[_&&jsx("span",{className:i("absolute inset-0 bg-primary/15 transition-[width] duration-200",B),style:{width:`${b.progress.percent}%`}}),jsxs("span",{className:"relative z-10 inline-flex items-center gap-1",children:[jsx(DownloadIcon,{"data-icon":"inline-start"}),_?formatFileSize(b.progress.loaded):l??"Download"]})]}),jsx(C,{children:_?"Cancel download":t})]})}),d&&b.phase==="error"&&jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),jsx("span",{className:"max-w-32 min-w-16 truncate sm:max-w-48",children:b.fileName??c})]}),jsx("span",{className:"text-destructive",children:b.error??"Download failed"})]})]})}function Pe({...o}){return jsx(AlertDialog.Root,{"data-slot":"alert-dialog",...o})}function he({...o}){return jsx(AlertDialog.Trigger,{"data-slot":"alert-dialog-trigger",...o})}function pt({...o}){return jsx(AlertDialog.Portal,{"data-slot":"alert-dialog-portal",...o})}function ct({className:o,...e}){return jsx(AlertDialog.Backdrop,{"data-slot":"alert-dialog-overlay",className:i("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",o),...e})}function be({className:o,size:e="default",...s}){return jsxs(pt,{children:[jsx(ct,{}),jsx(AlertDialog.Popup,{"data-slot":"alert-dialog-content","data-size":e,className:i("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",o),...s})]})}function Ne({className:o,...e}){return jsx("div",{"data-slot":"alert-dialog-header",className:i("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]",o),...e})}function De({className:o,...e}){return jsx("div",{"data-slot":"alert-dialog-footer",className:i("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",o),...e})}function we({className:o,...e}){return jsx("div",{"data-slot":"alert-dialog-media",className:i("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",o),...e})}function ze({className:o,...e}){return jsx(AlertDialog.Title,{"data-slot":"alert-dialog-title",className:i("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",o),...e})}function ke({className:o,...e}){return jsx(AlertDialog.Description,{"data-slot":"alert-dialog-description",className:i("text-xs/relaxed text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",o),...e})}function Te({className:o,...e}){return jsx(p,{"data-slot":"alert-dialog-action",className:i(o),...e})}function Ce({className:o,variant:e="outline",size:s="default",...r}){return jsx(AlertDialog.Close,{"data-slot":"alert-dialog-cancel",className:i(o),render:jsx(p,{variant:e,size:s}),...r})}function vt({presignApi:o,objectKey:e,fileName:s,fileSize:r,bucket:n,label:l,className:m,disabled:B,tooltipText:F="Delete file",toast:t=true,showStatus:a=true,confirmTitle:d="Delete file?",confirmDescription:D,beforeDelete:v,onDeleteStart:g,onSuccess:P,onError:h}){let S=s??e.split("/").pop()??e,c=useDelete({presignApi:o,bucket:n,beforeDelete:v,onDeleteStart:g,onSuccess:w=>{t&&toast.success("File deleted",{description:S}),P?.(w);},onError:(w,V,te)=>{t&&toast.error("Delete failed",{description:V instanceof Error?V.message:"Unknown error"}),h?.(w,V,te);}}),b=c.phase==="deleting",_=B||b,ee=D??`Are you sure you want to delete "${S}"${r!=null?` (${formatFileSize(r)})`:""}? This action cannot be undone.`;return jsxs("div",{className:i("inline-flex flex-col gap-1.5",m),children:[jsx("div",{className:"inline-flex items-center gap-2",children:jsxs(Pe,{open:c.phase==="confirming",onOpenChange:w=>{w||c.cancelDelete();},children:[jsx(z,{children:jsxs(k,{children:[jsxs(T,{render:jsx(he,{disabled:_,onClick:()=>c.requestDelete(e),render:jsx(p,{size:"default",variant:"destructive",disabled:_})}),children:[b?jsx(LoaderIcon,{className:"animate-spin","data-icon":"inline-start"}):jsx(Trash2Icon,{"data-icon":"inline-start"}),l??"Delete"]}),jsx(C,{children:F})]})}),jsxs(be,{children:[jsxs(Ne,{children:[jsx(we,{children:jsx(Trash2Icon,{})}),jsx(ze,{children:d}),jsx(ke,{children:ee})]}),jsxs(De,{children:[jsx(Ce,{children:"Cancel"}),jsx(Te,{variant:"destructive",onClick:()=>c.confirmDelete(),children:"Delete"})]})]})]})}),a&&c.phase==="error"&&jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[jsxs("div",{className:"flex items-center gap-1.5",children:[jsx(AlertCircleIcon,{className:"size-3.5 shrink-0 text-destructive"}),jsx("span",{className:"max-w-32 truncate sm:max-w-48",children:S})]}),jsx("span",{className:"text-destructive",children:c.error??"Delete failed"})]})]})}export{vt as DeleteButton,at as DownloadButton,dt as FetchDownloadButton,je as MultiUpload,se as MultiUploadStatus,We as Upload,oe 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/upload/upload.tsx","../src/components/ui/progress.tsx","../src/upload/multi-upload-status.tsx","../src/upload/multi-upload.tsx","../src/download/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","r","c","offset","UploadStatus","phase","progress","error","fileInfo","onCancel","formatFileSize","e","XIcon","CheckCircleIcon","AlertCircleIcon","Fragment","Upload","objectKey","label","disabled","tooltipText","enableToast","showStatus","options","ctrl","useUploadControls","toastIdRef","useRef","isDisabled","prevPhaseRef","toast","useEffect","id","status","UploadIcon","Progress","value","ProgressPrimitive","ProgressTrack","ProgressIndicator","ProgressLabel","ProgressValue","MultiUploadStatus","files","totalProgress","f","FileList","MultiUpload","useMultiUploadControls","succeeded","failed","done","DownloadButton","presignApi","fileName","fileSize","fillClassName","mode","beforeDownload","onDownloadStart","onProgress","onSuccess","onError","displayName","dl","useDownload","key","isFetchDownloading","isLoading","handleClick","DownloadIcon","AlertDialog","AlertDialogPrimitive","AlertDialogTrigger","AlertDialogPortal","AlertDialogOverlay","AlertDialogContent","AlertDialogHeader","AlertDialogFooter","AlertDialogMedia","AlertDialogTitle","AlertDialogDescription","AlertDialogAction","AlertDialogCancel","DeleteButton","confirmTitle","confirmDescription","beforeDelete","onDeleteStart","del","useDelete","isDeleting","description","open","LoaderIcon","Trash2Icon"],"mappings":"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","file":"index.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","\"use client\"\n\nimport { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button cursor-pointer inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n xs: \"h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-2.5\",\n sm: \"h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3\",\n lg: \"h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2 [&_svg:not([class*='size-'])]:size-4\",\n icon: \"size-7 [&_svg:not([class*='size-'])]:size-3.5\",\n \"icon-xs\": \"size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5\",\n \"icon-sm\": \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n \"icon-lg\": \"size-8 [&_svg:not([class*='size-'])]:size-4\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","\"use client\"\n\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction TooltipProvider({\n delay = 0,\n ...props\n}: TooltipPrimitive.Provider.Props) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delay={delay}\n {...props}\n />\n )\n}\n\nfunction Tooltip({ ...props }: TooltipPrimitive.Root.Props) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n}\n\nfunction TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />\n}\n\nfunction TooltipContent({\n className,\n side = \"top\",\n sideOffset = 4,\n align = \"center\",\n alignOffset = 0,\n children,\n ...props\n}: TooltipPrimitive.Popup.Props &\n Pick<\n TooltipPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\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/core\";\nimport type { UploadPhase, UploadProgress } from \"@better-s3/core\";\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=\"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 flex-col gap-1 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n {fileInfo && (\n <>\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(fileInfo.size)}\n </span>\n </>\n )}\n </div>\n <span className=\"text-destructive\">{error ?? \"Upload failed\"}</span>\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 { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { UploadIcon } from \"lucide-react\";\nimport { formatFileSize } from \"@better-s3/core\";\nimport type { UseUploadOptions } 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\";\n\nexport type UploadProps = UseUploadOptions & {\n objectKey: string | ((file: File) => string);\n variant?: \"button\" | \"dropzone\";\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 trigger (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function Upload({\n variant = \"button\",\n objectKey,\n className,\n label,\n disabled,\n tooltipText = \"Upload file\",\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadProps) {\n const ctrl = useUploadControls({ ...options, objectKey });\n const toastIdRef = useRef<string | null>(null);\n const isDisabled = disabled || ctrl.isUploading;\n\n // ── Toast ─────────────────────────────────────────────────────────\n\n const prevPhaseRef = useRef(ctrl.phase);\n if (prevPhaseRef.current !== ctrl.phase) {\n prevPhaseRef.current = ctrl.phase;\n if (enableToast) {\n if (ctrl.phase === \"idle\" && toastIdRef.current) {\n toast.dismiss(toastIdRef.current);\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"success\" && ctrl.fileInfo) {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n toast.success(\"Upload complete\", {\n description: formatFileSize(ctrl.fileInfo.size),\n });\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"error\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n toast.error(\"Upload failed\", {\n description: ctrl.error ?? \"Unknown error\",\n });\n toastIdRef.current = null;\n }\n }\n }\n\n useEffect(() => {\n if (enableToast && ctrl.phase === \"uploading\" && ctrl.fileInfo) {\n const id = toastIdRef.current ?? `upload-${Date.now()}`;\n toastIdRef.current = id;\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 enableToast,\n ctrl.phase,\n ctrl.progress.percent,\n ctrl.progress.loaded,\n ctrl.fileInfo,\n ctrl.cancel,\n ]);\n\n // ── Render ────────────────────────────────────────────────────────\n\n const status = showStatus ? (\n <UploadStatus\n phase={ctrl.phase}\n progress={ctrl.progress}\n error={ctrl.error}\n fileInfo={ctrl.fileInfo}\n onCancel={ctrl.cancel}\n />\n ) : null;\n\n if (variant === \"dropzone\") {\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 ?? \"Click or drag & drop to upload\"}\n </p>\n {status && <div className=\"w-full text-left\">{status}</div>}\n </div>\n );\n }\n\n return (\n <div className={cn(\"inline-flex flex-col gap-2\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <input {...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 ?? \"Upload file\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n {status}\n </div>\n );\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/core\";\nimport type { UploadProgress, MultiUploadFileState } from \"@better-s3/core\";\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=\"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=\"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 { UploadIcon } from \"lucide-react\";\nimport { formatFileSize } from \"@better-s3/core\";\nimport type { UseMultiUploadOptions } from \"@better-s3/react\";\nimport { useMultiUploadControls } 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 { MultiUploadStatus } from \"./multi-upload-status\";\n\nexport type MultiUploadProps = UseMultiUploadOptions & {\n objectKey: (file: File) => string;\n variant?: \"button\" | \"dropzone\";\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 trigger (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function MultiUpload({\n variant = \"button\",\n objectKey,\n className,\n label,\n disabled,\n tooltipText = \"Upload files\",\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: MultiUploadProps) {\n const ctrl = useMultiUploadControls({ ...options, objectKey });\n const toastIdRef = useRef<string | null>(null);\n const isDisabled = disabled || ctrl.isUploading;\n\n // ── Toast ─────────────────────────────────────────────────────────\n\n const prevPhaseRef = useRef(ctrl.phase);\n if (prevPhaseRef.current !== ctrl.phase) {\n prevPhaseRef.current = ctrl.phase;\n if (enableToast) {\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 toast.success(`${ctrl.files.length} file(s) uploaded`, {\n description: formatFileSize(ctrl.totalProgress.total),\n });\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"error\" && 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 if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n toast.error(\"Upload finished with errors\", {\n description: `${succeeded} succeeded, ${failed} failed`,\n });\n toastIdRef.current = null;\n }\n }\n }\n\n useEffect(() => {\n if (enableToast && ctrl.phase === \"uploading\") {\n const id = toastIdRef.current ?? `multi-upload-${Date.now()}`;\n toastIdRef.current = id;\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 }\n }, [\n enableToast,\n ctrl.phase,\n ctrl.totalProgress.percent,\n ctrl.totalProgress.loaded,\n ctrl.files,\n ctrl.cancel,\n ]);\n\n // ── Render ────────────────────────────────────────────────────────\n\n const status = showStatus ? (\n <MultiUploadStatus\n phase={ctrl.phase}\n files={ctrl.files}\n totalProgress={ctrl.totalProgress}\n error={ctrl.error}\n onCancel={ctrl.cancel}\n />\n ) : null;\n\n if (variant === \"dropzone\") {\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 ?? \"Click or drag & drop files to upload\"}\n </p>\n {status && <div className=\"w-full text-left\">{status}</div>}\n </div>\n );\n }\n\n return (\n <div className={cn(\"inline-flex flex-col gap-2\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <input {...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 ?? \"Upload files\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n {status}\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/core\";\nimport type { PresignApi, DownloadHooks } from \"@better-s3/core\";\nimport { useDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\ntype DownloadButtonProps = DownloadHooks & {\n presignApi: PresignApi;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\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 * `\"native\"` — browser handles download natively via presigned URL (default)\n * `\"fetch\"` — streams via fetch, shows in-button progress\n */\n mode?: \"native\" | \"fetch\";\n};\n\nexport function DownloadButton({\n presignApi,\n objectKey,\n fileName,\n fileSize,\n label,\n className,\n fillClassName,\n disabled,\n tooltipText = \"Download file\",\n toast: enableToast = true,\n showStatus = true,\n mode = \"native\",\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess,\n onError,\n onCancel,\n}: DownloadButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const dl = useDownload({\n presignApi,\n mode,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess: (key) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.success(\"Download complete\", {\n description: `${displayName}${fileSize != null ? ` · ${formatFileSize(fileSize)}` : \"\"}`,\n });\n }\n onSuccess?.(key);\n },\n onError: (key, error, phase) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.error(\"Download failed\", {\n description: error instanceof Error ? error.message : \"Unknown error\",\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 isFetchDownloading =\n mode === \"fetch\" &&\n (dl.phase === \"downloading\" || dl.phase === \"presigning\");\n\n const isLoading =\n mode === \"native\" ? dl.phase === \"presigning\" : isFetchDownloading;\n\n const handleClick = () => {\n if (mode === \"fetch\" && isFetchDownloading) {\n dl.cancel();\n return;\n }\n dl.download(objectKey, displayName);\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 || (mode === \"native\" && isLoading)}\n className={cn(\n mode === \"fetch\" && \"relative min-w-24 overflow-hidden\",\n )}\n onClick={handleClick}\n />\n }>\n {isFetchDownloading && (\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\n className={cn(\n \"inline-flex items-center gap-1\",\n mode === \"fetch\" && \"relative z-10\",\n )}>\n <DownloadIcon data-icon=\"inline-start\" />\n {isFetchDownloading\n ? formatFileSize(dl.progress.loaded)\n : (label ?? \"Download\")}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {isFetchDownloading ? \"Cancel download\" : tooltipText}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex flex-col gap-1 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n <span className=\"max-w-32 min-w-16 truncate sm:max-w-48\">\n {dl.fileName ?? displayName}\n </span>\n </div>\n <span className=\"text-destructive\">\n {dl.error ?? \"Download failed\"}\n </span>\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 { Trash2Icon, LoaderIcon, AlertCircleIcon } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/core\";\nimport type { PresignApi, DeleteHooks } from \"@better-s3/core\";\nimport { useDelete } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@/components/ui/alert-dialog\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\ntype DeleteButtonProps = DeleteHooks & {\n presignApi: PresignApi;\n objectKey: string;\n fileName?: string;\n fileSize?: number;\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 presignApi,\n objectKey,\n fileName,\n fileSize,\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 presignApi,\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: error instanceof Error ? error.message : \"Unknown error\",\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 === \"error\" && (\n <div className=\"flex flex-col gap-1 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n <span className=\"max-w-32 truncate sm:max-w-48\">{displayName}</span>\n </div>\n <span className=\"text-destructive\">\n {del.error ?? \"Delete failed\"}\n </span>\n </div>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/button.tsx","../src/components/ui/tooltip.tsx","../src/components/ui/circle-progress.tsx","../src/upload/upload-status.tsx","../src/upload/upload.tsx","../src/components/ui/progress.tsx","../src/upload/multi-upload-status.tsx","../src/upload/multi-upload.tsx","../src/download/download-button.tsx","../src/download/fetch-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","Fragment","Upload","objectKey","label","disabled","tooltipText","enableToast","showStatus","options","ctrl","useUploadControls","toastIdRef","useRef","isDisabled","prevPhaseRef","toast","useEffect","id","status","UploadIcon","Progress","value","ProgressPrimitive","ProgressTrack","ProgressIndicator","ProgressLabel","ProgressValue","MultiUploadStatus","files","totalProgress","f","FileList","MultiUpload","useMultiUploadControls","succeeded","failed","done","DownloadButton","presignApi","fileName","fileSize","bucket","beforeDownload","onSuccess","onError","displayName","dl","useDownload","key","isLoading","LoaderIcon","DownloadIcon","FetchDownloadButton","fillClassName","onDownloadStart","onProgress","useFetchDownload","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"],"mappings":"ooBAGO,SAASA,KAAMC,CAAAA,CAAsB,CAC1C,OAAOC,OAAAA,CAAQC,IAAAA,CAAKF,CAAM,CAAC,CAC7B,CCEA,IAAMG,EAAAA,CAAiBC,IACrB,mnBAAA,CACA,CACE,SAAU,CACR,OAAA,CAAS,CACP,OAAA,CAAS,wDAAA,CACT,QACE,6HAAA,CACF,SAAA,CACE,kIACF,KAAA,CACE,kHAAA,CACF,YACE,6NAAA,CACF,IAAA,CAAM,iDACR,CAAA,CACA,IAAA,CAAM,CACJ,OAAA,CACE,6IAAA,CACF,GAAI,wJAAA,CACJ,EAAA,CAAI,4IACJ,EAAA,CAAI,yIAAA,CACJ,KAAM,+CAAA,CACN,SAAA,CAAW,2DACX,SAAA,CAAW,6CAAA,CACX,UAAW,6CACb,CACF,CAAA,CACA,eAAA,CAAiB,CACf,OAAA,CAAS,SAAA,CACT,KAAM,SACR,CACF,CACF,CAAA,CAEA,SAASC,EAAO,CACd,SAAA,CAAAC,EACA,OAAA,CAAAC,CAAAA,CAAU,UACV,IAAA,CAAAC,CAAAA,CAAO,UACP,GAAGC,CACL,EAAgE,CAC9D,OACEC,IAACC,MAAAA,CAAA,CACC,YAAU,QAAA,CACV,SAAA,CAAWZ,EAAGI,EAAAA,CAAe,CAAE,QAAAI,CAAAA,CAAS,IAAA,CAAAC,EAAM,SAAA,CAAAF,CAAU,CAAC,CAAC,CAAA,CACzD,GAAGG,CAAAA,CACN,CAEJ,CCjDA,SAASG,CAAAA,CAAgB,CACvB,KAAA,CAAAC,CAAAA,CAAQ,EACR,GAAGJ,CACL,EAAoC,CAClC,OACEC,IAACI,OAAAA,CAAiB,QAAA,CAAjB,CACC,WAAA,CAAU,kBAAA,CACV,MAAOD,CAAAA,CACN,GAAGJ,EACN,CAEJ,CAEA,SAASM,CAAAA,CAAQ,CAAE,GAAGN,CAAM,CAAA,CAAgC,CAC1D,OAAOC,GAAAA,CAACI,QAAiB,IAAA,CAAjB,CAAsB,YAAU,SAAA,CAAW,GAAGL,CAAAA,CAAO,CAC/D,CAEA,SAASO,CAAAA,CAAe,CAAE,GAAGP,CAAM,EAAmC,CACpE,OAAOC,IAACI,OAAAA,CAAiB,OAAA,CAAjB,CAAyB,WAAA,CAAU,iBAAA,CAAmB,GAAGL,CAAAA,CAAO,CAC1E,CAEA,SAASQ,CAAAA,CAAe,CACtB,SAAA,CAAAX,CAAAA,CACA,KAAAY,CAAAA,CAAO,KAAA,CACP,WAAAC,CAAAA,CAAa,CAAA,CACb,MAAAC,CAAAA,CAAQ,QAAA,CACR,YAAAC,CAAAA,CAAc,CAAA,CACd,SAAAC,CAAAA,CACA,GAAGb,CACL,CAAA,CAIK,CACH,OACEC,GAAAA,CAACI,OAAAA,CAAiB,OAAjB,CACC,QAAA,CAAAJ,IAACI,OAAAA,CAAiB,UAAA,CAAjB,CACC,KAAA,CAAOM,CAAAA,CACP,YAAaC,CAAAA,CACb,IAAA,CAAMH,EACN,UAAA,CAAYC,CAAAA,CACZ,UAAU,cAAA,CAEV,QAAA,CAAAI,KAACT,OAAAA,CAAiB,KAAA,CAAjB,CACC,WAAA,CAAU,iBAAA,CACV,UAAWf,CAAAA,CACT,gwBAAA,CACAO,CACF,CAAA,CACC,GAAGG,EAEH,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,QAAAC,CAAAA,CACA,IAAA,CAAAjB,EAAO,EAAA,CACP,WAAA,CAAAkB,EAAc,GAChB,CAAA,CAIG,CACD,IAAM,CAAA,CAAA,CAAKlB,EAAOkB,CAAAA,EAAe,CAAA,CAC3BC,EAAI,CAAA,CAAI,IAAA,CAAK,GAAK,CAAA,CAClBC,CAAAA,CAASD,EAAKF,CAAAA,CAAU,GAAA,CAAOE,EACrC,OACEJ,IAAAA,CAAC,OAAI,KAAA,CAAOf,CAAAA,CAAM,OAAQA,CAAAA,CAAM,SAAA,CAAU,sBACxC,QAAA,CAAA,CAAAE,GAAAA,CAAC,UACC,EAAA,CAAIF,CAAAA,CAAO,EACX,EAAA,CAAIA,CAAAA,CAAO,EACX,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,YAAakB,CAAAA,CACb,eAAA,CAAiBC,EACjB,gBAAA,CAAkBC,CAAAA,CAClB,cAAc,OAAA,CACd,SAAA,CAAU,2DACZ,CAAA,CAAA,CACF,CAEJ,CC/BO,SAASC,EAAAA,CAAa,CAC3B,KAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CACA,KAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CACA,SAAAC,CACF,CAAA,CAMG,CACD,OAAIJ,CAAAA,GAAU,OAAe,IAAA,CAEzBA,CAAAA,GAAU,aAAeG,CAAAA,CAEzBV,IAAAA,CAAC,OAAI,SAAA,CAAU,0CAAA,CACb,UAAAb,GAAAA,CAACc,CAAAA,CAAA,CAAe,OAAA,CAASO,CAAAA,CAAS,QAAS,IAAA,CAAM,EAAA,CAAI,YAAa,CAAA,CAAG,CAAA,CACrErB,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,wCAAA,CACb,QAAA,CAAAuB,EAAS,IAAA,CACZ,CAAA,CACAV,KAAC,MAAA,CAAA,CAAK,SAAA,CAAU,iCACb,QAAA,CAAA,CAAAY,cAAAA,CAAeJ,EAAS,MAAM,CAAA,CAAE,MAAII,cAAAA,CAAeF,CAAAA,CAAS,IAAI,CAAA,CAAE,IAAA,CAClEF,EAAS,OAAA,CAAQ,IAAA,CAAA,CACpB,EACArB,GAAAA,CAACL,CAAAA,CAAA,CACC,OAAA,CAAQ,OAAA,CACR,KAAK,MAAA,CACL,SAAA,CAAU,0BACV,OAAA,CAAU+B,CAAAA,EAAM,CACdA,CAAAA,CAAE,eAAA,GACFF,CAAAA,KACF,EACA,QAAA,CAAAxB,GAAAA,CAAC2B,KAAAA,CAAA,CAAM,UAAU,UAAA,CAAW,CAAA,CAC9B,GACF,CAAA,CAIAP,CAAAA,GAAU,WAAaG,CAAAA,CAEvBV,IAAAA,CAAC,OAAI,SAAA,CAAU,mCAAA,CACb,UAAAb,GAAAA,CAAC4B,eAAAA,CAAA,CAAgB,SAAA,CAAU,kCAAA,CAAmC,EAC9D5B,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,wCAAA,CACb,QAAA,CAAAuB,EAAS,IAAA,CACZ,CAAA,CACAvB,IAAC,MAAA,CAAA,CAAK,SAAA,CAAU,iCACb,QAAA,CAAAyB,cAAAA,CAAeF,EAAS,IAAI,CAAA,CAC/B,GACF,CAAA,CAIAH,CAAAA,GAAU,QAEVP,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,6BAAA,CACb,QAAA,CAAA,CAAAA,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,4BACb,QAAA,CAAA,CAAAb,GAAAA,CAAC6B,gBAAA,CAAgB,SAAA,CAAU,qCAAqC,CAAA,CAC/DN,CAAAA,EACCV,KAAAiB,QAAAA,CAAA,CACE,UAAA9B,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,wCAAA,CACb,QAAA,CAAAuB,EAAS,IAAA,CACZ,CAAA,CACAvB,IAAC,MAAA,CAAA,CAAK,SAAA,CAAU,iCACb,QAAA,CAAAyB,cAAAA,CAAeF,EAAS,IAAI,CAAA,CAC/B,GACF,CAAA,CAAA,CAEJ,CAAA,CACAvB,IAAC,MAAA,CAAA,CAAK,SAAA,CAAU,mBAAoB,QAAA,CAAAsB,CAAAA,EAAS,gBAAgB,CAAA,CAAA,CAC/D,CAAA,CAIAF,IAAU,YAAA,EAAgBA,CAAAA,GAAU,YAAA,CAC/BpB,GAAAA,CAAC,QAAK,SAAA,CAAU,+BAAA,CAAgC,2BAAU,CAAA,CAG5D,IACT,CC1DO,SAAS+B,EAAAA,CAAO,CACrB,QAAAlC,CAAAA,CAAU,QAAA,CACV,UAAAmC,CAAAA,CACA,SAAA,CAAApC,EACA,KAAA,CAAAqC,CAAAA,CACA,SAAAC,CAAAA,CACA,WAAA,CAAAC,EAAc,aAAA,CACd,KAAA,CAAOC,EAAc,IAAA,CACrB,UAAA,CAAAC,EAAa,IAAA,CACb,GAAGC,CACL,CAAA,CAAgB,CACd,IAAMC,CAAAA,CAAOC,iBAAAA,CAAkB,CAAE,GAAGF,CAAAA,CAAS,UAAAN,CAAU,CAAC,EAClDS,CAAAA,CAAaC,MAAAA,CAAsB,IAAI,CAAA,CACvCC,CAAAA,CAAaT,GAAYK,CAAAA,CAAK,WAAA,CAI9BK,EAAeF,MAAAA,CAAOH,CAAAA,CAAK,KAAK,CAAA,CAClCK,CAAAA,CAAa,UAAYL,CAAAA,CAAK,KAAA,GAChCK,EAAa,OAAA,CAAUL,CAAAA,CAAK,MACxBH,CAAAA,GACEG,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,EAAaA,EAAK,QAAA,GAC/BE,CAAAA,CAAW,SAASI,KAAAA,CAAM,OAAA,CAAQJ,CAAAA,CAAW,OAAO,EACxDI,KAAAA,CAAM,OAAA,CAAQ,kBAAmB,CAC/B,WAAA,CAAapB,eAAec,CAAAA,CAAK,QAAA,CAAS,IAAI,CAChD,CAAC,EACDE,CAAAA,CAAW,OAAA,CAAU,MAEnBF,CAAAA,CAAK,KAAA,GAAU,UACbE,CAAAA,CAAW,OAAA,EAASI,MAAM,OAAA,CAAQJ,CAAAA,CAAW,OAAO,CAAA,CACxDI,KAAAA,CAAM,MAAM,eAAA,CAAiB,CAC3B,YAAaN,CAAAA,CAAK,KAAA,EAAS,eAC7B,CAAC,CAAA,CACDE,EAAW,OAAA,CAAU,IAAA,CAAA,CAAA,CAAA,CAK3BK,UAAU,IAAM,CACd,GAAIV,CAAAA,EAAeG,CAAAA,CAAK,QAAU,WAAA,EAAeA,CAAAA,CAAK,SAAU,CAC9D,IAAMQ,EAAKN,CAAAA,CAAW,OAAA,EAAW,UAAU,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,CACrDA,CAAAA,CAAW,QAAUM,CAAAA,CACrBF,KAAAA,CAAM,QAAQ,iBAAA,CAAc,CAC1B,GAAAE,CAAAA,CACA,WAAA,CAAa,GAAGtB,cAAAA,CAAec,CAAAA,CAAK,SAAS,MAAM,CAAC,MAAMd,cAAAA,CAAec,CAAAA,CAAK,SAAS,IAAI,CAAC,KAAKA,CAAAA,CAAK,QAAA,CAAS,OAAO,CAAA,EAAA,CAAA,CACtH,MAAA,CAAQ,CAAE,KAAA,CAAO,QAAA,CAAU,QAAS,IAAMA,CAAAA,CAAK,MAAA,EAAS,CAC1D,CAAC,EACH,CACF,CAAA,CAAG,CACDH,EACAG,CAAAA,CAAK,KAAA,CACLA,EAAK,QAAA,CAAS,OAAA,CACdA,EAAK,QAAA,CAAS,MAAA,CACdA,EAAK,QAAA,CACLA,CAAAA,CAAK,MACP,CAAC,CAAA,CAID,IAAMS,CAAAA,CAASX,CAAAA,CACbrC,IAACmB,EAAAA,CAAA,CACC,MAAOoB,CAAAA,CAAK,KAAA,CACZ,SAAUA,CAAAA,CAAK,QAAA,CACf,MAAOA,CAAAA,CAAK,KAAA,CACZ,SAAUA,CAAAA,CAAK,QAAA,CACf,SAAUA,CAAAA,CAAK,MAAA,CACjB,EACE,IAAA,CAEJ,OAAI1C,CAAAA,GAAY,UAAA,CAEZgB,KAAC,KAAA,CAAA,CACC,SAAA,CAAWxB,EACT,qHAAA,CACAsD,CAAAA,CACI,gDACA,mEAAA,CACJ/C,CACF,EACA,OAAA,CAAS+C,CAAAA,CAAa,OAAYJ,CAAAA,CAAK,cAAA,CACtC,GAAII,CAAAA,CAAa,GAAKJ,CAAAA,CAAK,YAAA,CAC5B,UAAAvC,GAAAA,CAAC,OAAA,CAAA,CAAO,GAAGuC,CAAAA,CAAK,UAAA,CAAY,EAC5BvC,GAAAA,CAACiD,UAAAA,CAAA,CACC,SAAA,CAAW5D,CAAAA,CACT,+BACAsD,CAAAA,EAAc,YAChB,EACF,CAAA,CACA3C,GAAAA,CAAC,KACC,SAAA,CAAWX,CAAAA,CACT,gCACAsD,CAAAA,EAAc,YAChB,CAAA,CACC,QAAA,CAAAV,GAAS,gCAAA,CACZ,CAAA,CACCe,GAAUhD,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,kBAAA,CAAoB,QAAA,CAAAgD,EAAO,CAAA,CAAA,CACvD,CAAA,CAKFnC,KAAC,KAAA,CAAA,CAAI,SAAA,CAAWxB,EAAG,4BAAA,CAA8BO,CAAS,EACxD,QAAA,CAAA,CAAAiB,IAAAA,CAAC,OAAI,SAAA,CAAU,gCAAA,CACb,UAAAb,GAAAA,CAAC,OAAA,CAAA,CAAO,GAAGuC,CAAAA,CAAK,UAAA,CAAY,EAC5BvC,GAAAA,CAACE,CAAAA,CAAA,CACC,QAAA,CAAAW,IAAAA,CAACR,EAAA,CACC,QAAA,CAAA,CAAAQ,KAACP,CAAAA,CAAA,CACC,OACEN,GAAAA,CAACL,CAAAA,CAAA,CACC,IAAA,CAAK,SAAA,CACL,SAAUgD,CAAAA,CACV,OAAA,CAASJ,EAAK,cAAA,CAChB,CAAA,CAEF,UAAAvC,GAAAA,CAACiD,UAAAA,CAAA,CAAW,WAAA,CAAU,cAAA,CAAe,EACpChB,CAAAA,EAAS,aAAA,CAAA,CACZ,EACAjC,GAAAA,CAACO,CAAAA,CAAA,CAAgB,QAAA,CAAA4B,CAAAA,CAAY,GAC/B,CAAA,CACF,CAAA,CAAA,CACF,EACCa,CAAAA,CAAAA,CACH,CAEJ,CCxJA,SAASE,EAAAA,CAAS,CAChB,SAAA,CAAAtD,CAAAA,CACA,SAAAgB,CAAAA,CACA,KAAA,CAAAuC,EACA,GAAGpD,CACL,EAAiC,CAC/B,OACEc,KAACuC,QAAAA,CAAkB,IAAA,CAAlB,CACC,KAAA,CAAOD,CAAAA,CACP,YAAU,UAAA,CACV,SAAA,CAAW9D,EAAG,sBAAA,CAAwBO,CAAS,EAC9C,GAAGG,CAAAA,CAEH,UAAAa,CAAAA,CACDZ,GAAAA,CAACqD,GAAA,CACC,QAAA,CAAArD,IAACsD,EAAAA,CAAA,EAAkB,EACrB,CAAA,CAAA,CACF,CAEJ,CAEA,SAASD,EAAAA,CAAc,CAAE,SAAA,CAAAzD,CAAAA,CAAW,GAAGG,CAAM,CAAA,CAAkC,CAC7E,OACEC,GAAAA,CAACoD,SAAkB,KAAA,CAAlB,CACC,UAAW/D,CAAAA,CACT,6EAAA,CACAO,CACF,CAAA,CACA,WAAA,CAAU,iBACT,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASuD,EAAAA,CAAkB,CACzB,UAAA1D,CAAAA,CACA,GAAGG,CACL,CAAA,CAAsC,CACpC,OACEC,GAAAA,CAACoD,QAAAA,CAAkB,UAAlB,CACC,WAAA,CAAU,qBACV,SAAA,CAAW/D,CAAAA,CAAG,mCAAoCO,CAAS,CAAA,CAC1D,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASwD,EAAAA,CAAc,CAAE,SAAA,CAAA3D,CAAAA,CAAW,GAAGG,CAAM,CAAA,CAAkC,CAC7E,OACEC,GAAAA,CAACoD,SAAkB,KAAA,CAAlB,CACC,UAAW/D,CAAAA,CAAG,6BAAA,CAA+BO,CAAS,CAAA,CACtD,WAAA,CAAU,iBACT,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASyD,GAAc,CAAE,SAAA,CAAA5D,EAAW,GAAGG,CAAM,EAAkC,CAC7E,OACEC,IAACoD,QAAAA,CAAkB,KAAA,CAAlB,CACC,SAAA,CAAW/D,CAAAA,CACT,6DACAO,CACF,CAAA,CACA,YAAU,gBAAA,CACT,GAAGG,EACN,CAEJ,CC7DO,SAAS0D,EAAAA,CAAkB,CAChC,MAAArC,CAAAA,CACA,KAAA,CAAAsC,EACA,aAAA,CAAAC,CAAAA,CACA,MAAArC,CAAAA,CACA,QAAA,CAAAE,CACF,CAAA,CAMG,CACD,OAAIJ,CAAAA,GAAU,OAAe,IAAA,CAEzBA,CAAAA,GAAU,YAEVP,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,4BAAA,CACb,QAAA,CAAA,CAAAA,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,mCACb,QAAA,CAAA,CAAAA,IAAAA,CAACqC,GAAA,CAAS,KAAA,CAAOS,EAAc,OAAA,CAAS,SAAA,CAAU,SAChD,QAAA,CAAA,CAAA9C,IAAAA,CAAC0C,GAAA,CACE,QAAA,CAAA,CAAAG,EAAM,MAAA,CAAQE,CAAAA,EAAMA,EAAE,MAAA,GAAW,SAAS,EAAE,MAAA,CAAO,GAAA,CACnDF,EAAM,MAAA,CAAO,QAAA,CAAA,CAChB,EACA1D,GAAAA,CAACwD,EAAAA,CAAA,EAAc,CAAA,CAAA,CACjB,CAAA,CACAxD,IAACL,CAAAA,CAAA,CACC,QAAQ,OAAA,CACR,IAAA,CAAK,OACL,SAAA,CAAU,iBAAA,CACV,QAAU+B,CAAAA,EAAM,CACdA,EAAE,eAAA,EAAgB,CAClBF,MACF,CAAA,CACA,SAAAxB,GAAAA,CAAC2B,KAAAA,CAAA,CAAM,SAAA,CAAU,QAAA,CAAS,EAC5B,CAAA,CAAA,CACF,CAAA,CACA3B,IAAC6D,EAAAA,CAAA,CAAS,MAAOH,CAAAA,CAAO,CAAA,CAAA,CAC1B,EAIAtC,CAAAA,GAAU,SAAA,CAEVP,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,6BACb,QAAA,CAAA,CAAAA,IAAAA,CAAC,QAAK,SAAA,CAAU,wBAAA,CAAyB,iBAClC6C,CAAAA,CAAM,MAAA,CAAO,mBAAA,CAAA,CACpB,CAAA,CACA1D,IAAC6D,EAAAA,CAAA,CAAS,MAAOH,CAAAA,CAAO,CAAA,CAAA,CAC1B,EAIAtC,CAAAA,GAAU,OAAA,CAEVP,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,6BACb,QAAA,CAAA,CAAAb,GAAAA,CAAC,QAAK,SAAA,CAAU,0BAAA,CACb,SAAAsB,CAAAA,EAAS,eAAA,CACZ,EACCoC,CAAAA,CAAM,MAAA,CAAS,GAAK1D,GAAAA,CAAC6D,EAAAA,CAAA,CAAS,KAAA,CAAOH,CAAAA,CAAO,GAC/C,CAAA,CAIAtC,CAAAA,GAAU,aACLpB,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,+BAAA,CAAgC,QAAA,CAAA,kBAAA,CAAW,EAG7D,IACT,CAIA,SAAS6D,EAAAA,CAAS,CAAE,MAAAH,CAAM,CAAA,CAAsC,CAC9D,OACE1D,GAAAA,CAAC,MAAG,SAAA,CAAU,qBAAA,CACX,SAAA0D,CAAAA,CAAM,GAAA,CAAKE,GACV/C,IAAAA,CAAC,IAAA,CAAA,CAAc,UAAU,+BAAA,CACvB,QAAA,CAAA,CAAAA,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,4BACZ,QAAA,CAAA,CAAA+C,CAAAA,CAAE,SAAW,SAAA,EACZ5D,GAAAA,CAAC4B,gBAAA,CAAgB,SAAA,CAAU,mCAAmC,CAAA,CAE/DgC,CAAAA,CAAE,SAAW,OAAA,EACZ5D,GAAAA,CAAC6B,gBAAA,CAAgB,SAAA,CAAU,qCAAqC,CAAA,CAAA,CAEhE+B,CAAAA,CAAE,SAAW,SAAA,EAAaA,CAAAA,CAAE,SAAW,WAAA,GACvC5D,GAAAA,CAACc,CAAAA,CAAA,CACC,QAAS8C,CAAAA,CAAE,MAAA,GAAW,YAAcA,CAAAA,CAAE,QAAA,CAAS,QAAU,CAAA,CACzD,IAAA,CAAM,GACN,WAAA,CAAa,CAAA,CACf,EAEF5D,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,wCAAA,CACb,QAAA,CAAA4D,EAAE,QAAA,CACL,CAAA,CACCA,EAAE,MAAA,GAAW,WAAA,CACZ/C,KAAC,MAAA,CAAA,CAAK,SAAA,CAAU,iCACb,QAAA,CAAA,CAAAY,cAAAA,CAAemC,EAAE,QAAA,CAAS,MAAM,EAAE,IAAA,CAAG,GAAA,CACrCnC,eAAemC,CAAAA,CAAE,QAAQ,EAAE,IAAA,CAAGA,CAAAA,CAAE,SAAS,OAAA,CAAQ,IAAA,CAAA,CACpD,EAEA5D,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,gCAAA,CACb,QAAA,CAAAyB,eAAemC,CAAAA,CAAE,QAAQ,EAC5B,CAAA,CAAA,CAEJ,CAAA,CACCA,EAAE,MAAA,GAAW,OAAA,EAAWA,EAAE,KAAA,EACzB5D,GAAAA,CAAC,QAAK,SAAA,CAAU,uBAAA,CAAyB,SAAA4D,CAAAA,CAAE,KAAA,CAAM,IA9B5CA,CAAAA,CAAE,EAgCX,CACD,CAAA,CACH,CAEJ,CChGO,SAASE,EAAAA,CAAY,CAC1B,QAAAjE,CAAAA,CAAU,QAAA,CACV,UAAAmC,CAAAA,CACA,SAAA,CAAApC,EACA,KAAA,CAAAqC,CAAAA,CACA,QAAA,CAAAC,CAAAA,CACA,YAAAC,CAAAA,CAAc,cAAA,CACd,MAAOC,CAAAA,CAAc,IAAA,CACrB,WAAAC,CAAAA,CAAa,IAAA,CACb,GAAGC,CACL,CAAA,CAAqB,CACnB,IAAMC,CAAAA,CAAOwB,uBAAuB,CAAE,GAAGzB,EAAS,SAAA,CAAAN,CAAU,CAAC,CAAA,CACvDS,CAAAA,CAAaC,OAAsB,IAAI,CAAA,CACvCC,EAAaT,CAAAA,EAAYK,CAAAA,CAAK,YAI9BK,CAAAA,CAAeF,MAAAA,CAAOH,EAAK,KAAK,CAAA,CACtC,GAAIK,CAAAA,CAAa,OAAA,GAAYL,EAAK,KAAA,GAChCK,CAAAA,CAAa,QAAUL,CAAAA,CAAK,KAAA,CACxBH,IACEG,CAAAA,CAAK,KAAA,GAAU,QAAUE,CAAAA,CAAW,OAAA,GACtCI,MAAM,OAAA,CAAQJ,CAAAA,CAAW,OAAO,CAAA,CAChCA,CAAAA,CAAW,QAAU,IAAA,CAAA,CAEnBF,CAAAA,CAAK,QAAU,SAAA,GACbE,CAAAA,CAAW,SAASI,KAAAA,CAAM,OAAA,CAAQJ,EAAW,OAAO,CAAA,CACxDI,MAAM,OAAA,CAAQ,CAAA,EAAGN,EAAK,KAAA,CAAM,MAAM,oBAAqB,CACrD,WAAA,CAAad,eAAec,CAAAA,CAAK,aAAA,CAAc,KAAK,CACtD,CAAC,EACDE,CAAAA,CAAW,OAAA,CAAU,MAEnBF,CAAAA,CAAK,KAAA,GAAU,SAAWA,CAAAA,CAAK,KAAA,CAAM,MAAA,CAAS,CAAA,CAAA,CAAA,CAAG,CACnD,IAAMyB,CAAAA,CAAYzB,EAAK,KAAA,CAAM,MAAA,CAC1BqB,GAAMA,CAAAA,CAAE,MAAA,GAAW,SACtB,CAAA,CAAE,MAAA,CACIK,EAAS1B,CAAAA,CAAK,KAAA,CAAM,OAAQqB,CAAAA,EAAMA,CAAAA,CAAE,SAAW,OAAO,CAAA,CAAE,OAC1DnB,CAAAA,CAAW,OAAA,EAASI,MAAM,OAAA,CAAQJ,CAAAA,CAAW,OAAO,CAAA,CACxDI,KAAAA,CAAM,MAAM,6BAAA,CAA+B,CACzC,YAAa,CAAA,EAAGmB,CAAS,eAAeC,CAAM,CAAA,OAAA,CAChD,CAAC,CAAA,CACDxB,CAAAA,CAAW,QAAU,KACvB,CAIJK,SAAAA,CAAU,IAAM,CACd,GAAIV,CAAAA,EAAeG,EAAK,KAAA,GAAU,WAAA,CAAa,CAC7C,IAAMQ,CAAAA,CAAKN,EAAW,OAAA,EAAW,CAAA,aAAA,EAAgB,KAAK,GAAA,EAAK,GAC3DA,CAAAA,CAAW,OAAA,CAAUM,EACrB,IAAMmB,CAAAA,CAAO3B,EAAK,KAAA,CAAM,MAAA,CAAQqB,GAAMA,CAAAA,CAAE,MAAA,GAAW,SAAS,CAAA,CAAE,MAAA,CAC9Df,MAAM,OAAA,CAAQ,CAAA,gBAAA,EAAcqB,CAAI,CAAA,CAAA,EAAI3B,CAAAA,CAAK,MAAM,MAAM,CAAA,CAAA,CAAI,CACvD,EAAA,CAAAQ,CAAAA,CACA,YAAa,CAAA,EAAGtB,cAAAA,CAAec,CAAAA,CAAK,aAAA,CAAc,MAAM,CAAC,CAAA,GAAA,EAAMd,eAAec,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,MAAA,EAAS,CAC1D,CAAC,EACH,CACF,CAAA,CAAG,CACDH,CAAAA,CACAG,CAAAA,CAAK,MACLA,CAAAA,CAAK,aAAA,CAAc,QACnBA,CAAAA,CAAK,aAAA,CAAc,OACnBA,CAAAA,CAAK,KAAA,CACLA,EAAK,MACP,CAAC,EAID,IAAMS,CAAAA,CAASX,EACbrC,GAAAA,CAACyD,EAAAA,CAAA,CACC,KAAA,CAAOlB,CAAAA,CAAK,MACZ,KAAA,CAAOA,CAAAA,CAAK,MACZ,aAAA,CAAeA,CAAAA,CAAK,cACpB,KAAA,CAAOA,CAAAA,CAAK,MACZ,QAAA,CAAUA,CAAAA,CAAK,OACjB,CAAA,CACE,IAAA,CAEJ,OAAI1C,CAAAA,GAAY,UAAA,CAEZgB,KAAC,KAAA,CAAA,CACC,SAAA,CAAWxB,EACT,qHAAA,CACAsD,CAAAA,CACI,gDACA,mEAAA,CACJ/C,CACF,EACA,OAAA,CAAS+C,CAAAA,CAAa,OAAYJ,CAAAA,CAAK,cAAA,CACtC,GAAII,CAAAA,CAAa,GAAKJ,CAAAA,CAAK,YAAA,CAC5B,UAAAvC,GAAAA,CAAC,OAAA,CAAA,CAAO,GAAGuC,CAAAA,CAAK,WAAY,CAAA,CAC5BvC,GAAAA,CAACiD,WAAA,CACC,SAAA,CAAW5D,EACT,8BAAA,CACAsD,CAAAA,EAAc,YAChB,CAAA,CACF,CAAA,CACA3C,IAAC,GAAA,CAAA,CACC,SAAA,CAAWX,EACT,+BAAA,CACAsD,CAAAA,EAAc,YAChB,CAAA,CACC,QAAA,CAAAV,GAAS,sCAAA,CACZ,CAAA,CACCe,GAAUhD,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,kBAAA,CAAoB,QAAA,CAAAgD,EAAO,CAAA,CAAA,CACvD,CAAA,CAKFnC,KAAC,KAAA,CAAA,CAAI,SAAA,CAAWxB,EAAG,4BAAA,CAA8BO,CAAS,EACxD,QAAA,CAAA,CAAAiB,IAAAA,CAAC,OAAI,SAAA,CAAU,gCAAA,CACb,UAAAb,GAAAA,CAAC,OAAA,CAAA,CAAO,GAAGuC,CAAAA,CAAK,UAAA,CAAY,EAC5BvC,GAAAA,CAACE,CAAAA,CAAA,CACC,QAAA,CAAAW,IAAAA,CAACR,EAAA,CACC,QAAA,CAAA,CAAAQ,KAACP,CAAAA,CAAA,CACC,OACEN,GAAAA,CAACL,CAAAA,CAAA,CACC,IAAA,CAAK,SAAA,CACL,SAAUgD,CAAAA,CACV,OAAA,CAASJ,EAAK,cAAA,CAChB,CAAA,CAEF,UAAAvC,GAAAA,CAACiD,UAAAA,CAAA,CAAW,WAAA,CAAU,cAAA,CAAe,EACpChB,CAAAA,EAAS,cAAA,CAAA,CACZ,EACAjC,GAAAA,CAACO,CAAAA,CAAA,CAAgB,QAAA,CAAA4B,CAAAA,CAAY,GAC/B,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CACCa,CAAAA,CAAAA,CACH,CAEJ,CClIO,SAASmB,EAAAA,CAAe,CAC7B,WAAAC,CAAAA,CACA,SAAA,CAAApC,EACA,QAAA,CAAAqC,CAAAA,CACA,SAAAC,CAAAA,CACA,MAAA,CAAAC,EACA,KAAA,CAAAtC,CAAAA,CACA,UAAArC,CAAAA,CACA,QAAA,CAAAsC,EACA,WAAA,CAAAC,CAAAA,CAAc,gBACd,KAAA,CAAOC,CAAAA,CAAc,KACrB,UAAA,CAAAC,CAAAA,CAAa,KACb,cAAA,CAAAmC,CAAAA,CACA,UAAAC,CAAAA,CACA,OAAA,CAAAC,CACF,CAAA,CAAwB,CACtB,IAAMC,CAAAA,CAAcN,CAAAA,EAAYrC,EAAU,KAAA,CAAM,GAAG,EAAE,GAAA,EAAI,EAAKA,EAExD4C,CAAAA,CAAKC,WAAAA,CAAY,CACrB,UAAA,CAAAT,CAAAA,CACA,OAAAG,CAAAA,CACA,cAAA,CAAAC,EACA,SAAA,CAAYM,CAAAA,EAAQ,CACd1C,CAAAA,EACFS,KAAAA,CAAM,QAAQ,mBAAA,CAAqB,CACjC,YAAa,CAAA,EAAG8B,CAAW,CAAA,EAAGL,CAAAA,EAAY,KAAO,CAAA,MAAA,EAAM7C,cAAAA,CAAe6C,CAAQ,CAAC,CAAA,CAAA,CAAK,EAAE,CAAA,CACxF,CAAC,EAEHG,CAAAA,GAAYK,CAAG,EACjB,CAAA,CACA,OAAA,CAAS,CAACA,CAAAA,CAAKxD,CAAAA,GAAU,CACnBc,CAAAA,EACFS,KAAAA,CAAM,MAAM,iBAAA,CAAmB,CAC7B,YAAavB,CAAAA,YAAiB,KAAA,CAAQA,EAAM,OAAA,CAAU,eACxD,CAAC,CAAA,CAEHoD,CAAAA,GAAUI,EAAKxD,CAAK,EACtB,CACF,CAAC,CAAA,CAEKyD,EAAYH,CAAAA,CAAG,KAAA,GAAU,cAE/B,OACE/D,IAAAA,CAAC,OAAI,SAAA,CAAWxB,CAAAA,CAAG,+BAAgCO,CAAS,CAAA,CAC1D,UAAAI,GAAAA,CAACE,CAAAA,CAAA,CACC,QAAA,CAAAW,IAAAA,CAACR,EAAA,CACC,QAAA,CAAA,CAAAL,IAACM,CAAAA,CAAA,CACC,OACEN,GAAAA,CAACL,CAAAA,CAAA,CACC,IAAA,CAAK,SAAA,CACL,QAAQ,SAAA,CACR,QAAA,CAAUuC,GAAY6C,CAAAA,CACtB,OAAA,CAAS,IAAMH,CAAAA,CAAG,QAAA,CAAS5C,EAAW2C,CAAW,CAAA,CACnD,EAEF,QAAA,CAAA9D,IAAAA,CAAC,QAAK,SAAA,CAAU,gCAAA,CACb,UAAAkE,CAAAA,CACC/E,GAAAA,CAACgF,WAAA,CAAW,SAAA,CAAU,cAAA,CAAe,WAAA,CAAU,eAAe,CAAA,CAE9DhF,GAAAA,CAACiF,aAAA,CAAa,WAAA,CAAU,eAAe,CAAA,CAExChD,CAAAA,EAAS,YACZ,CAAA,CACF,CAAA,CACAjC,IAACO,CAAAA,CAAA,CAAgB,SAAA4B,CAAAA,CAAY,CAAA,CAAA,CAC/B,EACF,CAAA,CAECE,CAAAA,EAAcuC,EAAG,KAAA,GAAU,OAAA,EAC1B/D,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,8BACb,QAAA,CAAA,CAAAA,IAAAA,CAAC,OAAI,SAAA,CAAU,2BAAA,CACb,UAAAb,GAAAA,CAAC6B,eAAAA,CAAA,CAAgB,SAAA,CAAU,oCAAA,CAAqC,EAChE7B,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,wCAAA,CACb,QAAA,CAAA4E,EAAG,QAAA,EAAYD,CAAAA,CAClB,GACF,CAAA,CACA3E,GAAAA,CAAC,QAAK,SAAA,CAAU,kBAAA,CACb,SAAA4E,CAAAA,CAAG,KAAA,EAAS,kBACf,CAAA,CAAA,CACF,CAAA,CAAA,CAEJ,CAEJ,CClFO,SAASM,EAAAA,CAAoB,CAClC,UAAA,CAAAd,CAAAA,CACA,UAAApC,CAAAA,CACA,QAAA,CAAAqC,CAAAA,CACA,QAAA,CAAAC,EACA,MAAA,CAAAC,CAAAA,CACA,MAAAtC,CAAAA,CACA,SAAA,CAAArC,EACA,aAAA,CAAAuF,CAAAA,CACA,SAAAjD,CAAAA,CACA,WAAA,CAAAC,EAAc,eAAA,CACd,KAAA,CAAOC,EAAc,IAAA,CACrB,UAAA,CAAAC,EAAa,IAAA,CACb,cAAA,CAAAmC,EACA,eAAA,CAAAY,CAAAA,CACA,WAAAC,CAAAA,CACA,SAAA,CAAAZ,EACA,OAAA,CAAAC,CAAAA,CACA,SAAAlD,CACF,CAAA,CAA6B,CAC3B,IAAMmD,CAAAA,CAAcN,GAAYrC,CAAAA,CAAU,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,IAASA,CAAAA,CAExD4C,CAAAA,CAAKU,iBAAiB,CAC1B,UAAA,CAAAlB,EACA,MAAA,CAAAG,CAAAA,CACA,eAAAC,CAAAA,CACA,eAAA,CAAAY,EACA,UAAA,CAAAC,CAAAA,CACA,UAAYP,CAAAA,EAAQ,CACd1C,IACFS,KAAAA,CAAM,OAAA,CAAQ,MAAMb,CAAS,CAAA,CAAE,EAC/Ba,KAAAA,CAAM,OAAA,CAAQ,oBAAqB,CACjC,WAAA,CAAa,GAAG8B,CAAW,CAAA,EAAGL,GAAY,IAAA,CAAO,CAAA,MAAA,EAAM7C,eAAe6C,CAAQ,CAAC,GAAK,EAAE,CAAA,CACxF,CAAC,CAAA,CAAA,CAEHG,CAAAA,GAAYK,CAAG,EACjB,CAAA,CACA,QAAS,CAACA,CAAAA,CAAKxD,CAAAA,CAAOF,EAAAA,GAAU,CAC1BgB,CAAAA,GACFS,KAAAA,CAAM,QAAQ,CAAA,GAAA,EAAMb,CAAS,EAAE,CAAA,CAC/Ba,KAAAA,CAAM,MAAM,iBAAA,CAAmB,CAC7B,YAAavB,CAAAA,YAAiB,KAAA,CAAQA,EAAM,OAAA,CAAU,eACxD,CAAC,CAAA,CAAA,CAEHoD,CAAAA,GAAUI,EAAKxD,CAAAA,CAAOF,EAAK,EAC7B,CAAA,CACA,QAAA,CAAW0D,GAAQ,CACb1C,CAAAA,GACFS,MAAM,OAAA,CAAQ,CAAA,GAAA,EAAMb,CAAS,CAAA,CAAE,CAAA,CAC/Ba,MAAM,IAAA,CAAK,oBAAA,CAAsB,CAAE,WAAA,CAAa8B,CAAY,CAAC,CAAA,CAAA,CAE/DnD,CAAAA,GAAWsD,CAAG,EAChB,CACF,CAAC,CAAA,CAEKS,CAAAA,CAAgBX,EAAG,KAAA,GAAU,aAAA,EAAiBA,EAAG,KAAA,GAAU,YAAA,CAE3DY,GAAc,IAAM,CACxB,GAAID,CAAAA,CAAe,CACjBX,EAAG,MAAA,EAAO,CACV,MACF,CACAA,CAAAA,CAAG,SAAS5C,CAAAA,CAAW2C,CAAW,EACpC,CAAA,CAEA,OACE9D,KAAC,KAAA,CAAA,CAAI,SAAA,CAAWxB,EAAG,8BAAA,CAAgCO,CAAS,EAC1D,QAAA,CAAA,CAAAI,GAAAA,CAACE,EAAA,CACC,QAAA,CAAAW,KAACR,CAAAA,CAAA,CACC,UAAAQ,IAAAA,CAACP,CAAAA,CAAA,CACC,MAAA,CACEN,IAACL,CAAAA,CAAA,CACC,KAAK,SAAA,CACL,OAAA,CAAQ,UACR,QAAA,CAAUuC,CAAAA,CACV,UAAW7C,CAAAA,CAAG,mCAAmC,EACjD,OAAA,CAASmG,EAAAA,CACX,EAED,QAAA,CAAA,CAAAD,CAAAA,EACCvF,IAAC,MAAA,CAAA,CACC,SAAA,CAAWX,EACT,gEAAA,CACA8F,CACF,EACA,KAAA,CAAO,CAAE,MAAO,CAAA,EAAGP,CAAAA,CAAG,SAAS,OAAO,CAAA,CAAA,CAAI,EAC5C,CAAA,CAEF/D,IAAAA,CAAC,QAAK,SAAA,CAAU,8CAAA,CACd,UAAAb,GAAAA,CAACiF,YAAAA,CAAA,CAAa,WAAA,CAAU,cAAA,CAAe,CAAA,CACtCM,CAAAA,CACG9D,eAAemD,CAAAA,CAAG,QAAA,CAAS,MAAM,CAAA,CAChC3C,CAAAA,EAAS,YAChB,CAAA,CAAA,CACF,CAAA,CACAjC,IAACO,CAAAA,CAAA,CACE,SAAAgF,CAAAA,CAAgB,iBAAA,CAAoBpD,EACvC,CAAA,CAAA,CACF,CAAA,CACF,EAECE,CAAAA,EAAcuC,CAAAA,CAAG,QAAU,OAAA,EAC1B/D,IAAAA,CAAC,OAAI,SAAA,CAAU,6BAAA,CACb,UAAAA,IAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,2BAAA,CACb,QAAA,CAAA,CAAAb,IAAC6B,eAAAA,CAAA,CAAgB,UAAU,oCAAA,CAAqC,CAAA,CAChE7B,IAAC,MAAA,CAAA,CAAK,SAAA,CAAU,yCACb,QAAA,CAAA4E,CAAAA,CAAG,QAAA,EAAYD,CAAAA,CAClB,GACF,CAAA,CACA3E,GAAAA,CAAC,QAAK,SAAA,CAAU,kBAAA,CACb,SAAA4E,CAAAA,CAAG,KAAA,EAAS,kBACf,CAAA,CAAA,CACF,CAAA,CAAA,CAEJ,CAEJ,CC9IA,SAASa,EAAAA,CAAY,CAAE,GAAG1F,CAAM,EAAoC,CAClE,OAAOC,IAAC0F,WAAAA,CAAqB,IAAA,CAArB,CAA0B,WAAA,CAAU,cAAA,CAAgB,GAAG3F,CAAAA,CAAO,CACxE,CAEA,SAAS4F,EAAAA,CAAmB,CAAE,GAAG5F,CAAM,EAAuC,CAC5E,OACEC,IAAC0F,WAAAA,CAAqB,OAAA,CAArB,CAA6B,WAAA,CAAU,sBAAA,CAAwB,GAAG3F,CAAAA,CAAO,CAE9E,CAEA,SAAS6F,EAAAA,CAAkB,CAAE,GAAG7F,CAAM,EAAsC,CAC1E,OACEC,IAAC0F,WAAAA,CAAqB,MAAA,CAArB,CAA4B,WAAA,CAAU,qBAAA,CAAuB,GAAG3F,CAAAA,CAAO,CAE5E,CAEA,SAAS8F,GAAmB,CAC1B,SAAA,CAAAjG,EACA,GAAGG,CACL,EAAwC,CACtC,OACEC,IAAC0F,WAAAA,CAAqB,QAAA,CAArB,CACC,WAAA,CAAU,sBAAA,CACV,UAAWrG,CAAAA,CACT,uLAAA,CACAO,CACF,CAAA,CACC,GAAGG,EACN,CAEJ,CAEA,SAAS+F,EAAAA,CAAmB,CAC1B,UAAAlG,CAAAA,CACA,IAAA,CAAAE,EAAO,SAAA,CACP,GAAGC,CACL,CAAA,CAEG,CACD,OACEc,IAAAA,CAAC+E,EAAAA,CAAA,CACC,QAAA,CAAA,CAAA5F,GAAAA,CAAC6F,GAAA,EAAmB,CAAA,CACpB7F,IAAC0F,WAAAA,CAAqB,KAAA,CAArB,CACC,WAAA,CAAU,sBAAA,CACV,YAAW5F,CAAAA,CACX,SAAA,CAAWT,EACT,icAAA,CACAO,CACF,EACC,GAAGG,CAAAA,CACN,GACF,CAEJ,CAEA,SAASgG,EAAAA,CAAkB,CACzB,UAAAnG,CAAAA,CACA,GAAGG,CACL,CAAA,CAAgC,CAC9B,OACEC,GAAAA,CAAC,KAAA,CAAA,CACC,YAAU,qBAAA,CACV,SAAA,CAAWX,EACT,mZAAA,CACAO,CACF,EACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASiG,GAAkB,CACzB,SAAA,CAAApG,CAAAA,CACA,GAAGG,CACL,CAAA,CAAgC,CAC9B,OACEC,GAAAA,CAAC,KAAA,CAAA,CACC,YAAU,qBAAA,CACV,SAAA,CAAWX,EACT,6JAAA,CACAO,CACF,EACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASkG,GAAiB,CACxB,SAAA,CAAArG,EACA,GAAGG,CACL,EAAgC,CAC9B,OACEC,IAAC,KAAA,CAAA,CACC,WAAA,CAAU,qBACV,SAAA,CAAWX,CAAAA,CACT,4KACAO,CACF,CAAA,CACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASmG,EAAAA,CAAiB,CACxB,SAAA,CAAAtG,CAAAA,CACA,GAAGG,CACL,CAAA,CAA4D,CAC1D,OACEC,GAAAA,CAAC0F,YAAqB,KAAA,CAArB,CACC,YAAU,oBAAA,CACV,SAAA,CAAWrG,EACT,8JAAA,CACAO,CACF,EACC,GAAGG,CAAAA,CACN,CAEJ,CAEA,SAASoG,GAAuB,CAC9B,SAAA,CAAAvG,EACA,GAAGG,CACL,EAAkE,CAChE,OACEC,IAAC0F,WAAAA,CAAqB,WAAA,CAArB,CACC,WAAA,CAAU,0BAAA,CACV,UAAWrG,CAAAA,CACT,wIAAA,CACAO,CACF,CAAA,CACC,GAAGG,EACN,CAEJ,CAEA,SAASqG,EAAAA,CAAkB,CACzB,SAAA,CAAAxG,CAAAA,CACA,GAAGG,CACL,CAAA,CAAwC,CACtC,OACEC,GAAAA,CAACL,EAAA,CACC,WAAA,CAAU,sBACV,SAAA,CAAWN,CAAAA,CAAGO,CAAS,CAAA,CACtB,GAAGG,EACN,CAEJ,CAEA,SAASsG,EAAAA,CAAkB,CACzB,UAAAzG,CAAAA,CACA,OAAA,CAAAC,EAAU,SAAA,CACV,IAAA,CAAAC,EAAO,SAAA,CACP,GAAGC,CACL,CAAA,CACiE,CAC/D,OACEC,GAAAA,CAAC0F,WAAAA,CAAqB,MAArB,CACC,WAAA,CAAU,sBACV,SAAA,CAAWrG,CAAAA,CAAGO,CAAS,CAAA,CACvB,MAAA,CAAQI,IAACL,CAAAA,CAAA,CAAO,QAASE,CAAAA,CAAS,IAAA,CAAMC,EAAM,CAAA,CAC7C,GAAGC,EACN,CAEJ,CC5HO,SAASuG,EAAAA,CAAa,CAC3B,WAAAlC,CAAAA,CACA,SAAA,CAAApC,EACA,QAAA,CAAAqC,CAAAA,CACA,SAAAC,CAAAA,CACA,MAAA,CAAAC,EACA,KAAA,CAAAtC,CAAAA,CACA,UAAArC,CAAAA,CACA,QAAA,CAAAsC,EACA,WAAA,CAAAC,CAAAA,CAAc,cACd,KAAA,CAAOC,CAAAA,CAAc,KACrB,UAAA,CAAAC,CAAAA,CAAa,KACb,YAAA,CAAAkE,CAAAA,CAAe,cAAA,CACf,kBAAA,CAAAC,EACA,YAAA,CAAAC,CAAAA,CACA,cAAAC,CAAAA,CACA,SAAA,CAAAjC,EACA,OAAA,CAAAC,CACF,EAAsB,CACpB,IAAMC,EAAcN,CAAAA,EAAYrC,CAAAA,CAAU,MAAM,GAAG,CAAA,CAAE,KAAI,EAAKA,CAAAA,CAExD2E,EAAMC,SAAAA,CAAU,CACpB,WAAAxC,CAAAA,CACA,MAAA,CAAAG,EACA,YAAA,CAAAkC,CAAAA,CACA,cAAAC,CAAAA,CACA,SAAA,CAAY5B,GAAQ,CACd1C,CAAAA,EACFS,MAAM,OAAA,CAAQ,cAAA,CAAgB,CAAE,WAAA,CAAa8B,CAAY,CAAC,CAAA,CAE5DF,CAAAA,GAAYK,CAAG,EACjB,CAAA,CACA,QAAS,CAACA,CAAAA,CAAKxD,EAAOF,EAAAA,GAAU,CAC1BgB,GACFS,KAAAA,CAAM,KAAA,CAAM,gBAAiB,CAC3B,WAAA,CAAavB,aAAiB,KAAA,CAAQA,CAAAA,CAAM,QAAU,eACxD,CAAC,EAEHoD,CAAAA,GAAUI,CAAAA,CAAKxD,EAAOF,EAAK,EAC7B,CACF,CAAC,CAAA,CAEKyF,EAAaF,CAAAA,CAAI,KAAA,GAAU,WAC3BhE,CAAAA,CAAaT,CAAAA,EAAY2E,EAEzBC,EAAAA,CACJN,CAAAA,EACA,oCAAoC7B,CAAW,CAAA,CAAA,EAAIL,GAAY,IAAA,CAAO,CAAA,EAAA,EAAK7C,eAAe6C,CAAQ,CAAC,CAAA,CAAA,CAAA,CAAM,EAAE,kCAE7G,OACEzD,IAAAA,CAAC,OAAI,SAAA,CAAWxB,CAAAA,CAAG,+BAAgCO,CAAS,CAAA,CAC1D,UAAAI,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAU,gCAAA,CACb,QAAA,CAAAa,KAAC4E,EAAAA,CAAA,CACC,KAAMkB,CAAAA,CAAI,KAAA,GAAU,aACpB,YAAA,CAAeI,CAAAA,EAAS,CACjBA,CAAAA,EAAMJ,CAAAA,CAAI,eACjB,CAAA,CACA,UAAA3G,GAAAA,CAACE,CAAAA,CAAA,CACC,QAAA,CAAAW,IAAAA,CAACR,EAAA,CACC,QAAA,CAAA,CAAAQ,KAACP,CAAAA,CAAA,CACC,OACEN,GAAAA,CAAC2F,EAAAA,CAAA,CACC,QAAA,CAAUhD,CAAAA,CACV,QAAS,IAAMgE,CAAAA,CAAI,cAAc3E,CAAS,CAAA,CAC1C,OACEhC,GAAAA,CAACL,CAAAA,CAAA,CACC,IAAA,CAAK,SAAA,CACL,QAAQ,aAAA,CACR,QAAA,CAAUgD,EACZ,CAAA,CAEJ,CAAA,CAED,UAAAkE,CAAAA,CACC7G,GAAAA,CAACgF,WAAA,CACC,SAAA,CAAU,eACV,WAAA,CAAU,cAAA,CACZ,EAEAhF,GAAAA,CAACgH,UAAAA,CAAA,CAAW,WAAA,CAAU,cAAA,CAAe,EAEtC/E,CAAAA,EAAS,QAAA,CAAA,CACZ,EACAjC,GAAAA,CAACO,CAAAA,CAAA,CAAgB,QAAA,CAAA4B,CAAAA,CAAY,GAC/B,CAAA,CACF,CAAA,CAEAtB,IAAAA,CAACiF,EAAAA,CAAA,CACC,QAAA,CAAA,CAAAjF,IAAAA,CAACkF,GAAA,CACC,QAAA,CAAA,CAAA/F,IAACiG,EAAAA,CAAA,CACC,SAAAjG,GAAAA,CAACgH,UAAAA,CAAA,EAAW,CAAA,CACd,CAAA,CACAhH,IAACkG,EAAAA,CAAA,CAAkB,SAAAK,CAAAA,CAAa,CAAA,CAChCvG,IAACmG,EAAAA,CAAA,CAAwB,SAAAW,EAAAA,CAAY,CAAA,CAAA,CACvC,EACAjG,IAAAA,CAACmF,EAAAA,CAAA,CACC,QAAA,CAAA,CAAAhG,GAAAA,CAACqG,GAAA,CAAkB,QAAA,CAAA,QAAA,CAAM,EACzBrG,GAAAA,CAACoG,EAAAA,CAAA,CACC,OAAA,CAAQ,aAAA,CACR,QAAS,IAAMO,CAAAA,CAAI,eAAc,CAAG,QAAA,CAAA,QAAA,CAEtC,GACF,CAAA,CAAA,CACF,CAAA,CAAA,CACF,EACF,CAAA,CAECtE,CAAAA,EAAcsE,EAAI,KAAA,GAAU,OAAA,EAC3B9F,KAAC,KAAA,CAAA,CAAI,SAAA,CAAU,8BACb,QAAA,CAAA,CAAAA,IAAAA,CAAC,OAAI,SAAA,CAAU,2BAAA,CACb,UAAAb,GAAAA,CAAC6B,eAAAA,CAAA,CAAgB,SAAA,CAAU,oCAAA,CAAqC,EAChE7B,GAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,+BAAA,CAAiC,QAAA,CAAA2E,EAAY,CAAA,CAAA,CAC/D,CAAA,CACA3E,IAAC,MAAA,CAAA,CAAK,SAAA,CAAU,mBACb,QAAA,CAAA2G,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=\"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 flex-col gap-1 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n {fileInfo && (\n <>\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(fileInfo.size)}\n </span>\n </>\n )}\n </div>\n <span className=\"text-destructive\">{error ?? \"Upload failed\"}</span>\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 { useEffect, useRef } from \"react\";\nimport { toast } from \"sonner\";\nimport { UploadIcon } from \"lucide-react\";\nimport { formatFileSize } from \"@better-s3/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\";\n\nexport type UploadProps = UseUploadControlsOptions & {\n variant?: \"button\" | \"dropzone\";\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 trigger (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function Upload({\n variant = \"button\",\n objectKey,\n className,\n label,\n disabled,\n tooltipText = \"Upload file\",\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: UploadProps) {\n const ctrl = useUploadControls({ ...options, objectKey });\n const toastIdRef = useRef<string | null>(null);\n const isDisabled = disabled || ctrl.isUploading;\n\n // ── Toast ─────────────────────────────────────────────────────────\n\n const prevPhaseRef = useRef(ctrl.phase);\n if (prevPhaseRef.current !== ctrl.phase) {\n prevPhaseRef.current = ctrl.phase;\n if (enableToast) {\n if (ctrl.phase === \"idle\" && toastIdRef.current) {\n toast.dismiss(toastIdRef.current);\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"success\" && ctrl.fileInfo) {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n toast.success(\"Upload complete\", {\n description: formatFileSize(ctrl.fileInfo.size),\n });\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"error\") {\n if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n toast.error(\"Upload failed\", {\n description: ctrl.error ?? \"Unknown error\",\n });\n toastIdRef.current = null;\n }\n }\n }\n\n useEffect(() => {\n if (enableToast && ctrl.phase === \"uploading\" && ctrl.fileInfo) {\n const id = toastIdRef.current ?? `upload-${Date.now()}`;\n toastIdRef.current = id;\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 enableToast,\n ctrl.phase,\n ctrl.progress.percent,\n ctrl.progress.loaded,\n ctrl.fileInfo,\n ctrl.cancel,\n ]);\n\n // ── Render ────────────────────────────────────────────────────────\n\n const status = showStatus ? (\n <UploadStatus\n phase={ctrl.phase}\n progress={ctrl.progress}\n error={ctrl.error}\n fileInfo={ctrl.fileInfo}\n onCancel={ctrl.cancel}\n />\n ) : null;\n\n if (variant === \"dropzone\") {\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 ?? \"Click or drag & drop to upload\"}\n </p>\n {status && <div className=\"w-full text-left\">{status}</div>}\n </div>\n );\n }\n\n return (\n <div className={cn(\"inline-flex flex-col gap-2\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <input {...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 ?? \"Upload file\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n {status}\n </div>\n );\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=\"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=\"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 { UploadIcon } from \"lucide-react\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { UseMultiUploadControlsOptions } from \"@better-s3/react\";\nimport { useMultiUploadControls } 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 { MultiUploadStatus } from \"./multi-upload-status\";\n\nexport type MultiUploadProps = UseMultiUploadControlsOptions & {\n variant?: \"button\" | \"dropzone\";\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 trigger (default: `true`) */\n showStatus?: boolean;\n};\n\nexport function MultiUpload({\n variant = \"button\",\n objectKey,\n className,\n label,\n disabled,\n tooltipText = \"Upload files\",\n toast: enableToast = true,\n showStatus = true,\n ...options\n}: MultiUploadProps) {\n const ctrl = useMultiUploadControls({ ...options, objectKey });\n const toastIdRef = useRef<string | null>(null);\n const isDisabled = disabled || ctrl.isUploading;\n\n // ── Toast ─────────────────────────────────────────────────────────\n\n const prevPhaseRef = useRef(ctrl.phase);\n if (prevPhaseRef.current !== ctrl.phase) {\n prevPhaseRef.current = ctrl.phase;\n if (enableToast) {\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 toast.success(`${ctrl.files.length} file(s) uploaded`, {\n description: formatFileSize(ctrl.totalProgress.total),\n });\n toastIdRef.current = null;\n }\n if (ctrl.phase === \"error\" && 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 if (toastIdRef.current) toast.dismiss(toastIdRef.current);\n toast.error(\"Upload finished with errors\", {\n description: `${succeeded} succeeded, ${failed} failed`,\n });\n toastIdRef.current = null;\n }\n }\n }\n\n useEffect(() => {\n if (enableToast && ctrl.phase === \"uploading\") {\n const id = toastIdRef.current ?? `multi-upload-${Date.now()}`;\n toastIdRef.current = id;\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 }\n }, [\n enableToast,\n ctrl.phase,\n ctrl.totalProgress.percent,\n ctrl.totalProgress.loaded,\n ctrl.files,\n ctrl.cancel,\n ]);\n\n // ── Render ────────────────────────────────────────────────────────\n\n const status = showStatus ? (\n <MultiUploadStatus\n phase={ctrl.phase}\n files={ctrl.files}\n totalProgress={ctrl.totalProgress}\n error={ctrl.error}\n onCancel={ctrl.cancel}\n />\n ) : null;\n\n if (variant === \"dropzone\") {\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 ?? \"Click or drag & drop files to upload\"}\n </p>\n {status && <div className=\"w-full text-left\">{status}</div>}\n </div>\n );\n }\n\n return (\n <div className={cn(\"inline-flex flex-col gap-2\", className)}>\n <div className=\"inline-flex items-center gap-2\">\n <input {...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 ?? \"Upload files\"}\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n {status}\n </div>\n );\n}\n","\"use client\";\n\nimport { DownloadIcon, AlertCircleIcon, LoaderIcon } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { PresignApi, DownloadHooks } from \"@better-s3/react\";\nimport { useDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\ntype DownloadButtonProps = DownloadHooks & {\n presignApi: PresignApi;\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};\n\nexport function DownloadButton({\n presignApi,\n objectKey,\n fileName,\n fileSize,\n bucket,\n label,\n className,\n disabled,\n tooltipText = \"Download file\",\n toast: enableToast = true,\n showStatus = true,\n beforeDownload,\n onSuccess,\n onError,\n}: DownloadButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const dl = useDownload({\n presignApi,\n bucket,\n beforeDownload,\n onSuccess: (key) => {\n if (enableToast) {\n toast.success(\"Download complete\", {\n description: `${displayName}${fileSize != null ? ` · ${formatFileSize(fileSize)}` : \"\"}`,\n });\n }\n onSuccess?.(key);\n },\n onError: (key, error) => {\n if (enableToast) {\n toast.error(\"Download failed\", {\n description: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n onError?.(key, error);\n },\n });\n\n const isLoading = dl.phase === \"downloading\";\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 || isLoading}\n onClick={() => dl.download(objectKey, displayName)}\n />\n }>\n <span className=\"inline-flex items-center gap-1\">\n {isLoading ? (\n <LoaderIcon className=\"animate-spin\" data-icon=\"inline-start\" />\n ) : (\n <DownloadIcon data-icon=\"inline-start\" />\n )}\n {label ?? \"Download\"}\n </span>\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n\n {showStatus && dl.phase === \"error\" && (\n <div className=\"flex flex-col gap-1 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n <span className=\"max-w-32 min-w-16 truncate sm:max-w-48\">\n {dl.fileName ?? displayName}\n </span>\n </div>\n <span className=\"text-destructive\">\n {dl.error ?? \"Download failed\"}\n </span>\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 { PresignApi, FetchDownloadHooks } from \"@better-s3/react\";\nimport { useFetchDownload } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\ntype FetchDownloadButtonProps = FetchDownloadHooks & {\n presignApi: PresignApi;\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 FetchDownloadButton({\n presignApi,\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}: FetchDownloadButtonProps) {\n const displayName = fileName ?? objectKey.split(\"/\").pop() ?? objectKey;\n\n const dl = useFetchDownload({\n presignApi,\n bucket,\n beforeDownload,\n onDownloadStart,\n onProgress,\n onSuccess: (key) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.success(\"Download complete\", {\n description: `${displayName}${fileSize != null ? ` · ${formatFileSize(fileSize)}` : \"\"}`,\n });\n }\n onSuccess?.(key);\n },\n onError: (key, error, phase) => {\n if (enableToast) {\n toast.dismiss(`dl-${objectKey}`);\n toast.error(\"Download failed\", {\n description: error instanceof Error ? error.message : \"Unknown error\",\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, displayName);\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 flex-col gap-1 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n <span className=\"max-w-32 min-w-16 truncate sm:max-w-48\">\n {dl.fileName ?? displayName}\n </span>\n </div>\n <span className=\"text-destructive\">\n {dl.error ?? \"Download failed\"}\n </span>\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 { Trash2Icon, LoaderIcon, AlertCircleIcon } from \"lucide-react\";\nimport { toast } from \"sonner\";\nimport { cn } from \"@/lib/utils\";\nimport { formatFileSize } from \"@better-s3/react\";\nimport type { PresignApi, DeleteHooks } from \"@better-s3/react\";\nimport { useDelete } from \"@better-s3/react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@/components/ui/alert-dialog\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\ntype DeleteButtonProps = DeleteHooks & {\n presignApi: PresignApi;\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 presignApi,\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 presignApi,\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: error instanceof Error ? error.message : \"Unknown error\",\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 === \"error\" && (\n <div className=\"flex flex-col gap-1 text-xs\">\n <div className=\"flex items-center gap-1.5\">\n <AlertCircleIcon className=\"size-3.5 shrink-0 text-destructive\" />\n <span className=\"max-w-32 truncate sm:max-w-48\">{displayName}</span>\n </div>\n <span className=\"text-destructive\">\n {del.error ?? \"Delete failed\"}\n </span>\n </div>\n )}\n </div>\n );\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { UploadProgress, MultiUploadFileState } from "@better-s3/core";
1
+ import type { UploadProgress, MultiUploadFileState } from "@better-s3/react";
2
2
  export declare function MultiUploadStatus({ phase, files, totalProgress, error, onCancel, }: {
3
3
  phase: string;
4
4
  files: MultiUploadFileState[];
@@ -1,6 +1,5 @@
1
- import type { UseMultiUploadOptions } from "@better-s3/react";
2
- export type MultiUploadProps = UseMultiUploadOptions & {
3
- objectKey: (file: File) => string;
1
+ import type { UseMultiUploadControlsOptions } from "@better-s3/react";
2
+ export type MultiUploadProps = UseMultiUploadControlsOptions & {
4
3
  variant?: "button" | "dropzone";
5
4
  className?: string;
6
5
  label?: string;
@@ -1,4 +1,4 @@
1
- import type { UploadPhase, UploadProgress } from "@better-s3/core";
1
+ import type { UploadPhase, UploadProgress } from "@better-s3/react";
2
2
  export declare function UploadStatus({ phase, progress, error, fileInfo, onCancel, }: {
3
3
  phase: UploadPhase;
4
4
  progress: UploadProgress;
@@ -1,6 +1,5 @@
1
- import type { UseUploadOptions } from "@better-s3/react";
2
- export type UploadProps = UseUploadOptions & {
3
- objectKey: string | ((file: File) => string);
1
+ import type { UseUploadControlsOptions } from "@better-s3/react";
2
+ export type UploadProps = UseUploadControlsOptions & {
4
3
  variant?: "button" | "dropzone";
5
4
  className?: string;
6
5
  label?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-s3/ui",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Pre-built React UI components for S3 file upload, download, and delete",
5
5
  "keywords": [
6
6
  "s3",
@@ -36,8 +36,7 @@
36
36
  "styles.css"
37
37
  ],
38
38
  "dependencies": {
39
- "@better-s3/core": "1.0.0",
40
- "@better-s3/react": "1.0.0"
39
+ "@better-s3/react": "2.1.0"
41
40
  },
42
41
  "peerDependencies": {
43
42
  "@base-ui/react": ">=1.0.0",
@@ -49,17 +48,17 @@
49
48
  "tailwind-merge": ">=2.0.0"
50
49
  },
51
50
  "devDependencies": {
52
- "@base-ui/react": "^1.3.0",
53
- "@types/react": "^19.0.0",
51
+ "@base-ui/react": "^1.4.0",
52
+ "@types/react": "^19.2.14",
54
53
  "class-variance-authority": "^0.7.1",
55
54
  "clsx": "^2.1.1",
56
- "lucide-react": "^0.500.0",
57
- "react": "^19.0.0",
58
- "sonner": "^2.0.0",
59
- "tailwind-merge": "^3.0.0",
55
+ "lucide-react": "^1.8.0",
56
+ "react": "^19.2.5",
57
+ "sonner": "^2.0.7",
58
+ "tailwind-merge": "^3.5.0",
60
59
  "tsc-alias": "^1.8.16",
61
60
  "tsup": "^8.5.1",
62
- "typescript": "^5.8.3"
61
+ "typescript": "^6.0.3"
63
62
  },
64
63
  "publishConfig": {
65
64
  "access": "public"