@mage-ui/components 1.0.130 → 1.0.132

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.
Files changed (67) hide show
  1. package/dist/components/controls/dropzone/Dropzone.d.mts +24 -93
  2. package/dist/components/controls/dropzone/Dropzone.d.mts.map +1 -1
  3. package/dist/components/controls/dropzone/Dropzone.mjs +1 -1
  4. package/dist/components/controls/dropzone/Dropzone.mjs.map +1 -1
  5. package/dist/components/controls/dropzone/DropzoneBase.d.mts +87 -0
  6. package/dist/components/controls/dropzone/DropzoneBase.d.mts.map +1 -0
  7. package/dist/components/controls/dropzone/DropzoneBase.mjs +2 -0
  8. package/dist/components/controls/dropzone/DropzoneBase.mjs.map +1 -0
  9. package/dist/components/controls/dropzone/DropzoneS3.d.mts +30 -0
  10. package/dist/components/controls/dropzone/DropzoneS3.d.mts.map +1 -0
  11. package/dist/components/controls/dropzone/DropzoneS3.mjs +2 -0
  12. package/dist/components/controls/dropzone/DropzoneS3.mjs.map +1 -0
  13. package/dist/components/controls/{avatar-dropzone → dropzone/avatar}/AvatarDropzone.d.mts +2 -2
  14. package/dist/components/controls/dropzone/avatar/AvatarDropzone.d.mts.map +1 -0
  15. package/dist/components/controls/dropzone/avatar/AvatarDropzone.mjs +2 -0
  16. package/dist/components/controls/dropzone/avatar/AvatarDropzone.mjs.map +1 -0
  17. package/dist/components/controls/dropzone/avatar/AvatarDropzoneS3.d.mts +41 -0
  18. package/dist/components/controls/dropzone/avatar/AvatarDropzoneS3.d.mts.map +1 -0
  19. package/dist/components/controls/dropzone/avatar/AvatarDropzoneS3.mjs +2 -0
  20. package/dist/components/controls/dropzone/avatar/AvatarDropzoneS3.mjs.map +1 -0
  21. package/dist/components/controls/dropzone/use-dropzone-state.mjs.map +1 -1
  22. package/dist/components/controls/dropzone/use-s3-upload.d.mts +70 -0
  23. package/dist/components/controls/dropzone/use-s3-upload.d.mts.map +1 -0
  24. package/dist/components/controls/dropzone/use-s3-upload.mjs +2 -0
  25. package/dist/components/controls/dropzone/use-s3-upload.mjs.map +1 -0
  26. package/dist/components/controls/index.d.mts +6 -5
  27. package/dist/components/data-display/index.d.mts +1 -0
  28. package/dist/components/data-display/resource-item/ResourceItem.mjs +1 -1
  29. package/dist/components/data-display/resource-item/ResourceItem.mjs.map +1 -1
  30. package/dist/components/data-display/uploaded-file/UploadedFile.mjs.map +1 -1
  31. package/dist/components/data-display/uploaded-files/UploadedFiles.d.mts +42 -0
  32. package/dist/components/data-display/uploaded-files/UploadedFiles.d.mts.map +1 -0
  33. package/dist/components/data-display/uploaded-files/UploadedFiles.mjs +2 -0
  34. package/dist/components/data-display/uploaded-files/UploadedFiles.mjs.map +1 -0
  35. package/dist/components/forms/Form.d.mts +5 -4
  36. package/dist/components/forms/Form.d.mts.map +1 -1
  37. package/dist/components/forms/Form.mjs +1 -1
  38. package/dist/components/forms/Form.mjs.map +1 -1
  39. package/dist/components/forms/controls/FormDropzoneS3.d.mts +12 -0
  40. package/dist/components/forms/controls/FormDropzoneS3.d.mts.map +1 -0
  41. package/dist/components/forms/controls/FormDropzoneS3.mjs +2 -0
  42. package/dist/components/forms/controls/FormDropzoneS3.mjs.map +1 -0
  43. package/dist/components/forms/controls/index.mjs +1 -1
  44. package/dist/components/forms/controls/index.mjs.map +1 -1
  45. package/dist/components/forms/controls/register-components.mjs +1 -1
  46. package/dist/components/forms/controls/register-components.mjs.map +1 -1
  47. package/dist/components/forms/rules/extract-form-rules.mjs +1 -1
  48. package/dist/components/forms/rules/extract-form-rules.mjs.map +1 -1
  49. package/dist/components/index.d.mts +7 -5
  50. package/dist/index.d.mts +8 -6
  51. package/dist/index.mjs +1 -1
  52. package/package.json +2 -2
  53. package/dist/components/controls/avatar-dropzone/AvatarDropzone.d.mts.map +0 -1
  54. package/dist/components/controls/avatar-dropzone/AvatarDropzone.mjs +0 -2
  55. package/dist/components/controls/avatar-dropzone/AvatarDropzone.mjs.map +0 -1
  56. package/dist/components/controls/dropzone-files/DropzoneFiles.d.mts +0 -62
  57. package/dist/components/controls/dropzone-files/DropzoneFiles.d.mts.map +0 -1
  58. package/dist/components/controls/dropzone-files/DropzoneFiles.mjs +0 -2
  59. package/dist/components/controls/dropzone-files/DropzoneFiles.mjs.map +0 -1
  60. package/dist/components/controls/dropzone-s3/DropzoneS3.d.mts +0 -114
  61. package/dist/components/controls/dropzone-s3/DropzoneS3.d.mts.map +0 -1
  62. package/dist/components/controls/dropzone-s3/DropzoneS3.mjs +0 -2
  63. package/dist/components/controls/dropzone-s3/DropzoneS3.mjs.map +0 -1
  64. package/dist/components/forms/controls/FormDropzoneFiles.d.mts +0 -12
  65. package/dist/components/forms/controls/FormDropzoneFiles.d.mts.map +0 -1
  66. package/dist/components/forms/controls/FormDropzoneFiles.mjs +0 -2
  67. package/dist/components/forms/controls/FormDropzoneFiles.mjs.map +0 -1
@@ -1,109 +1,40 @@
1
- import { IconProps } from "../../data-display/icons/icon/Icon.mjs";
2
- import { LoaderOvalProps } from "../../data-display/loader-oval/LoaderOval.mjs";
3
- import { UploadProgress, UploadResponse, Uploader } from "./upload-service.mjs";
1
+ import { UploadedFileProps } from "../../data-display/uploaded-file/UploadedFile.mjs";
2
+ import { DropzoneBaseProps, FileData } from "./DropzoneBase.mjs";
4
3
  import * as react_jsx_runtime0 from "react/jsx-runtime";
5
4
  import { ReactNode } from "react";
6
5
 
7
6
  //#region src/components/controls/dropzone/Dropzone.d.ts
8
- type FileData = {
9
- name: string;
10
- size: number;
11
- type: string;
12
- date: string;
13
- uploaded: boolean;
14
- loading: boolean;
15
- url: string;
16
- error?: string;
17
- progress?: number;
18
- };
19
- type DropzoneProps = {
20
- children: ({
21
- files,
22
- isUploading,
23
- removeFile
24
- }: {
25
- files: Record<string, FileData>;
26
- isUploading: boolean;
27
- removeFile: (fileName: string) => void;
28
- }) => ReactNode;
29
- initialFiles?: Record<string, FileData>;
30
- maxFiles?: number;
31
- /**
32
- * Endpoint used by the built-in FormData uploader. Required when
33
- * `autoSend=true` (default) AND no custom `uploader` is provided.
34
- * Ignored if `uploader` is provided.
35
- */
36
- url?: string;
37
- /**
38
- * Custom upload function that replaces the built-in FormData POST.
39
- * Use it for multi-step flows (e.g. presigned S3) or any non-standard
40
- * transport. When set, the `url` prop is ignored.
41
- */
42
- uploader?: Uploader; /** When false, files are added to state but not uploaded automatically. Default: true. */
43
- autoSend?: boolean; /** Maximum file size in bytes. Files exceeding this will be rejected. */
44
- maxSize?: number; /** Called when the file list changes (added or removed). Useful when autoSend=false. */
45
- onChange?: (files: File[]) => void;
46
- data?: Record<string, unknown>;
47
- headers?: Record<string, string>;
48
- /**
49
- * Files the dropzone accepts. Forwarded directly to Mantine's
50
- * `<Dropzone accept>`.
51
- *
52
- * Two formats are supported:
53
- * - **Map (preferred)**: `{ [mimeType]: ['.ext', ...] }` — matches
54
- * the native `react-dropzone` shape and produces a correct
55
- * `<input accept>` with MIME + extension pairs. Required when any
56
- * key would otherwise be a bare extension string.
57
- * - **Array**: `string[]` of MIME types (no `.ext` entries) — kept
58
- * for backward compatibility. Mixing `.ext` strings into the
59
- * array triggers a `Skipped "..." because it is not a valid MIME
60
- * type` warning from `react-dropzone` v15+.
61
- */
62
- accept?: string[] | Record<string, string[]>;
63
- title?: ReactNode;
64
- subtitle?: ReactNode;
65
- hint?: ReactNode;
66
- inputId?: string;
67
- onFileUploaded?: (file: FileData) => void;
68
- hideWhenFull?: boolean;
7
+ type DropzoneProps = Omit<DropzoneBaseProps, 'children' | 'classNames'> & {
8
+ children?: ReactNode;
9
+ label?: ReactNode;
10
+ description?: ReactNode;
11
+ error?: ReactNode;
12
+ fileListHeight?: number | string;
69
13
  classNames?: {
70
14
  dropzone?: string;
71
15
  root?: string;
72
- dropzoneDropzone?: {
73
- root?: string;
74
- inner?: string;
75
- };
76
- iconSlot?: string;
77
- dropzoneIcon?: IconProps['classNames'];
78
- loader?: LoaderOvalProps['classNames'];
79
- textSlot?: string;
80
- title?: string;
81
- subtitle?: string;
82
- hint?: string;
16
+ labelWrapper?: string;
17
+ label?: string;
18
+ description?: string;
19
+ error?: string;
20
+ uploadedFiles?: string;
21
+ uploadedFilesRoot?: string;
22
+ uploadedFilesListItem?: string;
23
+ uploadedFile?: UploadedFileProps['classNames'];
24
+ dropzoneDropzone?: DropzoneBaseProps['classNames'];
83
25
  };
84
- direction?: 'default' | 'reverse';
85
26
  };
86
27
  declare const Dropzone: ({
87
- data,
88
- headers,
89
28
  children,
90
- initialFiles,
91
- maxFiles,
92
- url,
93
- uploader,
94
- autoSend,
95
- maxSize,
96
- onChange,
97
- accept,
98
- title,
99
- subtitle,
100
- hint,
101
- inputId,
102
- onFileUploaded,
29
+ label,
30
+ description,
31
+ error,
32
+ fileListHeight: _fileListHeight,
103
33
  classNames,
34
+ inputId,
104
35
  direction,
105
- hideWhenFull
36
+ ...baseProps
106
37
  }: DropzoneProps) => react_jsx_runtime0.JSX.Element;
107
38
  //#endregion
108
- export { Dropzone, DropzoneProps, FileData };
39
+ export { Dropzone, DropzoneProps };
109
40
  //# sourceMappingURL=Dropzone.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Dropzone.d.mts","names":[],"sources":["../../../../src/components/controls/dropzone/Dropzone.tsx"],"mappings":";;;;;;;KAkCY,QAAA;EACV,IAAA;EACA,IAAA;EACA,IAAA;EACA,IAAA;EACA,QAAA;EACA,OAAA;EACA,GAAA;EACA,KAAA;EACA,QAAA;AAAA;AAAA,KAGU,aAAA;EACV,QAAA;IACE,KAAA;IACA,WAAA;IACA;EAAA;IAEA,KAAA,EAAO,MAAA,SAAe,QAAA;IACtB,WAAA;IACA,UAAA,GAAa,QAAA;EAAA,MACT,SAAA;EACN,YAAA,GAAe,MAAA,SAAe,QAAA;EAC9B,QAAA;EAXU;;;;;EAiBV,GAAA;EAXwB;;;;;EAiBxB,QAAA,GAAW,QAAA,EAMQ;EAJnB,QAAA,YAMU;EAJV,OAAA,WAoBQ;EAlBR,QAAA,IAAY,KAAA,EAAO,IAAA;EACnB,IAAA,GAAO,MAAA;EACP,OAAA,GAAU,MAAA;EA8BO;;;;;;;;;;;;;;EAfjB,MAAA,cAAoB,MAAA;EACpB,KAAA,GAAQ,SAAA;EACR,QAAA,GAAW,SAAA;EACX,IAAA,GAAO,SAAA;EACP,OAAA;EACA,cAAA,IAAkB,IAAA,EAAM,QAAA;EACxB,YAAA;EACA,UAAA;IACE,QAAA;IACA,IAAA;IACA,gBAAA;MACE,IAAA;MACA,KAAA;IAAA;IAEF,QAAA;IACA,YAAA,GAAe,SAAA;IACf,MAAA,GAAS,eAAA;IACT,QAAA;IACA,KAAA;IACA,QAAA;IACA,IAAA;EAAA;EAEF,SAAA;AAAA;AAAA,cAGW,QAAA;EAAY,IAAA;EAAA,OAAA;EAAA,QAAA;EAAA,YAAA;EAAA,QAAA;EAAA,GAAA;EAAA,QAAA;EAAA,QAAA;EAAA,OAAA;EAAA,QAAA;EAAA,MAAA;EAAA,KAAA;EAAA,QAAA;EAAA,IAAA;EAAA,OAAA;EAAA,cAAA;EAAA,UAAA;EAAA,SAAA;EAAA;AAAA,GAoBtB,aAAA,KAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"Dropzone.d.mts","names":[],"sources":["../../../../src/components/controls/dropzone/Dropzone.tsx"],"mappings":";;;;;;KA0BY,aAAA,GAAgB,IAAA,CAC1B,iBAAA;EAGA,QAAA,GAAW,SAAA;EACX,KAAA,GAAQ,SAAA;EACR,WAAA,GAAc,SAAA;EACd,KAAA,GAAQ,SAAA;EACR,cAAA;EACA,UAAA;IACE,QAAA;IACA,IAAA;IACA,YAAA;IACA,KAAA;IACA,WAAA;IACA,KAAA;IACA,aAAA;IACA,iBAAA;IACA,qBAAA;IACA,YAAA,GAAe,iBAAA;IACf,gBAAA,GAAmB,iBAAA;EAAA;AAAA;AAAA,cAMV,QAAA;EAAY,QAAA;EAAA,KAAA;EAAA,WAAA;EAAA,KAAA;EAAA,cAAA,EAAA,eAAA;EAAA,UAAA;EAAA,OAAA;EAAA,SAAA;EAAA,GAAA;AAAA,GAUtB,aAAA,KAAa,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -1,2 +1,2 @@
1
- import{Icon as e}from"../../data-display/icons/icon/Icon.mjs";import{LoaderOval as t}from"../../data-display/loader-oval/LoaderOval.mjs";import{useDropzoneState as n}from"./use-dropzone-state.mjs";import{cx as r}from"@mage-ui/styled-system/css";import{dropzone as i,dropzoneDropzoneInner as a,dropzoneDropzoneRoot as o,dropzoneHint as s,dropzoneIcon as c,dropzoneIconSlot as l,dropzoneLoader as u,dropzoneLoaderRoot as d,dropzoneRoot as f,dropzoneSubtitle as p,dropzoneTextSlot as m,dropzoneTitle as h}from"@mage-ui/styled-system/recipes";import{Fragment as g,jsx as _,jsxs as v}from"react/jsx-runtime";import{useCallback as y,useRef as b}from"react";import{Dropzone as x}from"@mantine/dropzone";const S=({data:S,headers:C,children:w,initialFiles:T={},maxFiles:E,url:D,uploader:O,autoSend:k=!0,maxSize:A,onChange:j,accept:M,title:N,subtitle:P,hint:F,inputId:I,onFileUploaded:L,classNames:R,direction:z=`default`,hideWhenFull:B=!1})=>{let V=b(null),H=b(new Map),{files:U,isUploading:W,uploadMultipleFiles:G,addFile:K,removeFile:q}=n(D,T,L,C,O),J=y(e=>{q(e),H.current.delete(e),!k&&j&&j(Array.from(H.current.values()))},[q,k,j]),Y=y(async e=>{let t=Object.keys(U).length,n=(E??1/0)-t;if(n<=0)return;let r=e.slice(0,n);if(k)await G(r,S);else{for(let e of r)K(e),H.current.set(e.name,e);j?.(Array.from(H.current.values()))}},[k,G,K,S,U,E,j]),X=E!==void 0&&Object.keys(U).length>=E;return v(`div`,{className:r(R?.dropzone??i(),R?.root??f()),"data-direction":z,children:[(!B||!X)&&v(x,{ref:V,onDrop:Y,disabled:X,loading:W,accept:M,maxSize:A,preventDropOnDocument:!0,inputProps:{id:I},classNames:{root:R?.dropzoneDropzone?.root??r(o(),`group`),inner:R?.dropzoneDropzone?.inner??a()},children:[_(`div`,{className:R?.iconSlot??l(),children:W?_(t,{classNames:{loader:R?.loader?.loader??u(),root:R?.loader?.root??d()}}):v(g,{children:[_(x.Idle,{children:_(e,{name:`mage-dropzone-upload-01`,path:`/icons/sprite-mage.svg`,classNames:{icon:R?.dropzoneIcon?.icon??c()}})}),_(x.Accept,{children:_(e,{name:`mage-dropzone-thumbs-up`,path:`/icons/sprite-mage.svg`,classNames:{icon:R?.dropzoneIcon?.icon??c()}})}),_(x.Reject,{children:_(e,{name:`mage-dropzone-thumbs-down`,path:`/icons/sprite-mage.svg`,classNames:{icon:R?.dropzoneIcon?.icon??c()}})})]})}),v(`div`,{className:R?.textSlot??m(),children:[_(`span`,{className:R?.title??h(),children:N||`Upload files`}),_(`span`,{className:R?.subtitle??p(),children:P||`Drag images here or click to select files`}),_(`span`,{className:R?.hint??s(),children:F||`Attach as many files as you like, each file should not exceed 5mb`})]})]}),w({files:U,isUploading:W,removeFile:J})]})};export{S as Dropzone};
1
+ import{UploadedFiles as e}from"../../data-display/uploaded-files/UploadedFiles.mjs";import{DropzoneBase as t}from"./DropzoneBase.mjs";import{cx as n}from"@mage-ui/styled-system/css";import{dropzone as r,dropzoneDescription as i,dropzoneDropzone as a,dropzoneError as o,dropzoneLabel as s,dropzoneLabelWrapper as c,dropzoneRoot as l,dropzoneUploadedFile as u,dropzoneUploadedFiles as d,dropzoneUploadedFilesListItem as f}from"@mage-ui/styled-system/recipes";import{jsx as p,jsxs as m}from"react/jsx-runtime";import{useId as h}from"react";const g=({children:g,label:_,description:v,error:y,fileListHeight:b,classNames:x,inputId:S,direction:C=`default`,...w})=>{let T=h(),E=S??T;return m(`div`,{className:n(x?.dropzone??r(),x?.root??l()),children:[(_||v)&&m(`div`,{className:x?.labelWrapper??c(),children:[_&&p(`label`,{htmlFor:E,className:x?.label??s(),children:_}),v&&p(`p`,{className:x?.description??i(),children:v})]}),p(t,{...w,inputId:E,direction:C,classNames:{...x?.dropzoneDropzone??{},dropzoneBase:x?.dropzoneDropzone?.dropzoneBase??a()},children:({files:t,removeFile:n})=>g===void 0?Object.keys(t).length>0?p(e,{classNames:{uploadedFiles:x?.uploadedFiles??d(),root:x?.uploadedFilesRoot},children:Object.values(t).map(t=>p(e.Item,{fileName:t.name,fileType:t.type,fileSize:`${(t.size/1024).toFixed(1)} KB`,fileDate:t.date,url:t.url,onRemove:()=>n(t.name),classNames:{listItem:x?.uploadedFilesListItem??f(),uploadedFile:{...x?.uploadedFile,uploadedFile:x?.uploadedFile?.uploadedFile??u()}}},t.name))}):null:g}),y&&p(`p`,{className:x?.error??o(),children:y})]})};export{g as Dropzone};
2
2
  //# sourceMappingURL=Dropzone.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Dropzone.mjs","names":["Dropzone","MantineDropzone"],"sources":["../../../../src/components/controls/dropzone/Dropzone.tsx"],"sourcesContent":["import { type ReactNode, useCallback, useRef } from 'react';\n\nimport { cx } from '@mage-ui/styled-system/css';\nimport {\n dropzone,\n dropzoneDropzoneInner,\n dropzoneDropzoneRoot,\n dropzoneHint,\n dropzoneIcon,\n dropzoneIconSlot,\n dropzoneLoader,\n dropzoneLoaderRoot,\n dropzoneRoot,\n dropzoneSubtitle,\n dropzoneTextSlot,\n dropzoneTitle,\n} from '@mage-ui/styled-system/recipes';\nimport { Dropzone as MantineDropzone } from '@mantine/dropzone';\nimport {\n Icon,\n type IconProps,\n LoaderOval,\n type LoaderOvalProps,\n} from '@/components/data-display';\n\nimport type {\n Uploader,\n UploadProgress,\n UploadResponse,\n} from './upload-service';\nimport { useDropzoneState } from './use-dropzone-state';\n\nexport type { Uploader, UploadProgress, UploadResponse };\n\nexport type FileData = {\n name: string;\n size: number;\n type: string;\n date: string;\n uploaded: boolean;\n loading: boolean;\n url: string;\n error?: string;\n progress?: number; // (0-100)\n};\n\nexport type DropzoneProps = {\n children: ({\n files,\n isUploading,\n removeFile,\n }: {\n files: Record<string, FileData>;\n isUploading: boolean;\n removeFile: (fileName: string) => void;\n }) => ReactNode;\n initialFiles?: Record<string, FileData>;\n maxFiles?: number;\n /**\n * Endpoint used by the built-in FormData uploader. Required when\n * `autoSend=true` (default) AND no custom `uploader` is provided.\n * Ignored if `uploader` is provided.\n */\n url?: string;\n /**\n * Custom upload function that replaces the built-in FormData POST.\n * Use it for multi-step flows (e.g. presigned S3) or any non-standard\n * transport. When set, the `url` prop is ignored.\n */\n uploader?: Uploader;\n /** When false, files are added to state but not uploaded automatically. Default: true. */\n autoSend?: boolean;\n /** Maximum file size in bytes. Files exceeding this will be rejected. */\n maxSize?: number;\n /** Called when the file list changes (added or removed). Useful when autoSend=false. */\n onChange?: (files: File[]) => void;\n data?: Record<string, unknown>;\n headers?: Record<string, string>;\n /**\n * Files the dropzone accepts. Forwarded directly to Mantine's\n * `<Dropzone accept>`.\n *\n * Two formats are supported:\n * - **Map (preferred)**: `{ [mimeType]: ['.ext', ...] }` — matches\n * the native `react-dropzone` shape and produces a correct\n * `<input accept>` with MIME + extension pairs. Required when any\n * key would otherwise be a bare extension string.\n * - **Array**: `string[]` of MIME types (no `.ext` entries) — kept\n * for backward compatibility. Mixing `.ext` strings into the\n * array triggers a `Skipped \"...\" because it is not a valid MIME\n * type` warning from `react-dropzone` v15+.\n */\n accept?: string[] | Record<string, string[]>;\n title?: ReactNode;\n subtitle?: ReactNode;\n hint?: ReactNode;\n inputId?: string;\n onFileUploaded?: (file: FileData) => void;\n hideWhenFull?: boolean;\n classNames?: {\n dropzone?: string;\n root?: string;\n dropzoneDropzone?: {\n root?: string;\n inner?: string;\n };\n iconSlot?: string;\n dropzoneIcon?: IconProps['classNames'];\n loader?: LoaderOvalProps['classNames'];\n textSlot?: string;\n title?: string;\n subtitle?: string;\n hint?: string;\n };\n direction?: 'default' | 'reverse';\n};\n\nexport const Dropzone = ({\n data,\n headers,\n children,\n initialFiles = {},\n maxFiles,\n url,\n uploader,\n autoSend = true,\n maxSize,\n onChange,\n accept,\n title,\n subtitle,\n hint,\n inputId,\n onFileUploaded,\n classNames,\n direction = 'default',\n hideWhenFull = false,\n}: DropzoneProps) => {\n const dropzoneRef = useRef<HTMLDivElement>(null);\n const rawFilesRef = useRef<Map<string, File>>(new Map());\n const {\n files,\n isUploading,\n uploadMultipleFiles,\n addFile,\n removeFile: hookRemoveFile,\n } = useDropzoneState(url, initialFiles, onFileUploaded, headers, uploader);\n\n const removeFile = useCallback(\n (fileName: string) => {\n hookRemoveFile(fileName);\n rawFilesRef.current.delete(fileName);\n if (!autoSend && onChange) {\n onChange(Array.from(rawFilesRef.current.values()));\n }\n },\n [hookRemoveFile, autoSend, onChange],\n );\n\n const handleDrop = useCallback(\n async (acceptedFiles: File[]) => {\n const currentCount = Object.keys(files).length;\n const max = maxFiles ?? Number.POSITIVE_INFINITY;\n const remainingSlots = max - currentCount;\n if (remainingSlots <= 0) {\n return;\n }\n const filesToProcess = acceptedFiles.slice(0, remainingSlots);\n if (autoSend) {\n await uploadMultipleFiles(filesToProcess, data);\n } else {\n for (const file of filesToProcess) {\n addFile(file);\n rawFilesRef.current.set(file.name, file);\n }\n onChange?.(Array.from(rawFilesRef.current.values()));\n }\n },\n [autoSend, uploadMultipleFiles, addFile, data, files, maxFiles, onChange],\n );\n\n const isFull =\n maxFiles !== undefined && Object.keys(files).length >= maxFiles;\n\n return (\n <div\n className={cx(\n classNames?.dropzone ?? dropzone(),\n classNames?.root ?? dropzoneRoot(),\n )}\n data-direction={direction}\n >\n {(!hideWhenFull || !isFull) && (\n <MantineDropzone\n ref={dropzoneRef}\n onDrop={handleDrop}\n disabled={isFull}\n loading={isUploading}\n accept={accept}\n maxSize={maxSize}\n preventDropOnDocument\n inputProps={{ id: inputId }}\n classNames={{\n root:\n classNames?.dropzoneDropzone?.root ??\n cx(dropzoneDropzoneRoot(), 'group'),\n inner:\n classNames?.dropzoneDropzone?.inner ?? dropzoneDropzoneInner(),\n }}\n >\n <div className={classNames?.iconSlot ?? dropzoneIconSlot()}>\n {isUploading ? (\n <LoaderOval\n classNames={{\n loader: classNames?.loader?.loader ?? dropzoneLoader(),\n root: classNames?.loader?.root ?? dropzoneLoaderRoot(),\n }}\n />\n ) : (\n <>\n <MantineDropzone.Idle>\n <Icon\n name='mage-dropzone-upload-01'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.dropzoneIcon?.icon ?? dropzoneIcon(),\n }}\n />\n </MantineDropzone.Idle>\n <MantineDropzone.Accept>\n <Icon\n name='mage-dropzone-thumbs-up'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.dropzoneIcon?.icon ?? dropzoneIcon(),\n }}\n />\n </MantineDropzone.Accept>\n <MantineDropzone.Reject>\n <Icon\n name='mage-dropzone-thumbs-down'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.dropzoneIcon?.icon ?? dropzoneIcon(),\n }}\n />\n </MantineDropzone.Reject>\n </>\n )}\n </div>\n <div className={classNames?.textSlot ?? dropzoneTextSlot()}>\n <span className={classNames?.title ?? dropzoneTitle()}>\n {title || 'Upload files'}\n </span>\n <span className={classNames?.subtitle ?? dropzoneSubtitle()}>\n {subtitle || 'Drag images here or click to select files'}\n </span>\n <span className={classNames?.hint ?? dropzoneHint()}>\n {hint ||\n 'Attach as many files as you like, each file should not exceed 5mb'}\n </span>\n </div>\n </MantineDropzone>\n )}\n {children({ files, isUploading, removeFile })}\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"Dropzone.mjs","names":[],"sources":["../../../../src/components/controls/dropzone/Dropzone.tsx"],"sourcesContent":["import { type ReactNode, useId } from 'react';\n\nimport { cx } from '@mage-ui/styled-system/css';\nimport {\n dropzone,\n dropzoneDescription,\n dropzoneDropzone,\n dropzoneError,\n dropzoneLabel,\n dropzoneLabelWrapper,\n dropzoneRoot,\n dropzoneUploadedFile,\n dropzoneUploadedFiles,\n dropzoneUploadedFilesListItem,\n} from '@mage-ui/styled-system/recipes';\nimport {\n type UploadedFileProps,\n UploadedFiles,\n} from '@/components/data-display';\n\nimport {\n DropzoneBase,\n type DropzoneBaseProps,\n type FileData,\n} from './DropzoneBase';\n\nexport type DropzoneProps = Omit<\n DropzoneBaseProps,\n 'children' | 'classNames'\n> & {\n children?: ReactNode;\n label?: ReactNode;\n description?: ReactNode;\n error?: ReactNode;\n fileListHeight?: number | string;\n classNames?: {\n dropzone?: string;\n root?: string;\n labelWrapper?: string;\n label?: string;\n description?: string;\n error?: string;\n uploadedFiles?: string;\n uploadedFilesRoot?: string;\n uploadedFilesListItem?: string;\n uploadedFile?: UploadedFileProps['classNames'];\n dropzoneDropzone?: DropzoneBaseProps['classNames'];\n };\n};\n\nexport type { FileData };\n\nexport const Dropzone = ({\n children,\n label,\n description,\n error,\n fileListHeight: _fileListHeight,\n classNames,\n inputId,\n direction = 'default',\n ...baseProps\n}: DropzoneProps) => {\n const generatedId = useId();\n const groupId = inputId ?? generatedId;\n\n return (\n <div\n className={cx(\n classNames?.dropzone ?? dropzone(),\n classNames?.root ?? dropzoneRoot(),\n )}\n >\n {(label || description) && (\n <div className={classNames?.labelWrapper ?? dropzoneLabelWrapper()}>\n {label && (\n <label\n htmlFor={groupId}\n className={classNames?.label ?? dropzoneLabel()}\n >\n {label}\n </label>\n )}\n {description && (\n <p className={classNames?.description ?? dropzoneDescription()}>\n {description}\n </p>\n )}\n </div>\n )}\n <DropzoneBase\n {...baseProps}\n inputId={groupId}\n direction={direction}\n classNames={{\n ...(classNames?.dropzoneDropzone ?? {}),\n dropzoneBase:\n classNames?.dropzoneDropzone?.dropzoneBase ?? dropzoneDropzone(),\n }}\n >\n {({ files, removeFile }) => {\n if (children !== undefined) {\n return children;\n }\n return Object.keys(files).length > 0 ? (\n <UploadedFiles\n classNames={{\n uploadedFiles:\n classNames?.uploadedFiles ?? dropzoneUploadedFiles(),\n root: classNames?.uploadedFilesRoot,\n }}\n >\n {Object.values(files).map((file) => (\n <UploadedFiles.Item\n key={file.name}\n fileName={file.name}\n fileType={file.type}\n fileSize={`${(file.size / 1024).toFixed(1)} KB`}\n fileDate={file.date}\n url={file.url}\n onRemove={() => removeFile(file.name)}\n classNames={{\n listItem:\n classNames?.uploadedFilesListItem ??\n dropzoneUploadedFilesListItem(),\n uploadedFile: {\n ...classNames?.uploadedFile,\n uploadedFile:\n classNames?.uploadedFile?.uploadedFile ??\n dropzoneUploadedFile(),\n },\n }}\n />\n ))}\n </UploadedFiles>\n ) : null;\n }}\n </DropzoneBase>\n {error && <p className={classNames?.error ?? dropzoneError()}>{error}</p>}\n </div>\n );\n};\n"],"mappings":"yhBAoDA,MAAa,GAAY,CACvB,WACA,QACA,cACA,QACA,eAAgB,EAChB,aACA,UACA,YAAY,UACZ,GAAG,KACgB,CACnB,IAAM,EAAc,GAAO,CACrB,EAAU,GAAW,EAE3B,OACE,EAAC,MAAD,CACE,UAAW,EACT,GAAY,UAAY,GAAU,CAClC,GAAY,MAAQ,GAAc,CACnC,UAJH,EAMI,GAAS,IACT,EAAC,MAAD,CAAK,UAAW,GAAY,cAAgB,GAAsB,UAAlE,CACG,GACC,EAAC,QAAD,CACE,QAAS,EACT,UAAW,GAAY,OAAS,GAAe,UAE9C,EACK,CAAA,CAET,GACC,EAAC,IAAD,CAAG,UAAW,GAAY,aAAe,GAAqB,UAC3D,EACC,CAAA,CAEF,GAER,EAAC,EAAD,CACE,GAAI,EACJ,QAAS,EACE,YACX,WAAY,CACV,GAAI,GAAY,kBAAoB,EAAE,CACtC,aACE,GAAY,kBAAkB,cAAgB,GAAkB,CACnE,WAEC,CAAE,QAAO,gBACL,IAAa,IAAA,GAGV,OAAO,KAAK,EAAM,CAAC,OAAS,EACjC,EAAC,EAAD,CACE,WAAY,CACV,cACE,GAAY,eAAiB,GAAuB,CACtD,KAAM,GAAY,kBACnB,UAEA,OAAO,OAAO,EAAM,CAAC,IAAK,GACzB,EAAC,EAAc,KAAf,CAEE,SAAU,EAAK,KACf,SAAU,EAAK,KACf,SAAU,IAAI,EAAK,KAAO,MAAM,QAAQ,EAAE,CAAC,KAC3C,SAAU,EAAK,KACf,IAAK,EAAK,IACV,aAAgB,EAAW,EAAK,KAAK,CACrC,WAAY,CACV,SACE,GAAY,uBACZ,GAA+B,CACjC,aAAc,CACZ,GAAG,GAAY,aACf,aACE,GAAY,cAAc,cAC1B,GAAsB,CACzB,CACF,CACD,CAlBK,EAAK,KAkBV,CACF,CACY,CAAA,CACd,KAjCK,EAmCE,CAAA,CACd,GAAS,EAAC,IAAD,CAAG,UAAW,GAAY,OAAS,GAAe,UAAG,EAAU,CAAA,CACrE"}
@@ -0,0 +1,87 @@
1
+ import { IconProps } from "../../data-display/icons/icon/Icon.mjs";
2
+ import { LoaderOvalProps } from "../../data-display/loader-oval/LoaderOval.mjs";
3
+ import { UploadProgress, UploadResponse, Uploader } from "./upload-service.mjs";
4
+ import { ReactNode } from "react";
5
+
6
+ //#region src/components/controls/dropzone/DropzoneBase.d.ts
7
+ type FileData = {
8
+ name: string;
9
+ size: number;
10
+ type: string;
11
+ date: string;
12
+ uploaded: boolean;
13
+ loading: boolean;
14
+ url: string;
15
+ error?: string;
16
+ progress?: number;
17
+ };
18
+ type DropzoneBaseProps = {
19
+ children: ({
20
+ files,
21
+ isUploading,
22
+ removeFile
23
+ }: {
24
+ files: Record<string, FileData>;
25
+ isUploading: boolean;
26
+ removeFile: (fileName: string) => void;
27
+ }) => ReactNode;
28
+ initialFiles?: Record<string, FileData>;
29
+ maxFiles?: number;
30
+ /**
31
+ * Endpoint used by the built-in FormData uploader. Required when
32
+ * `autoSend=true` (default) AND no custom `uploader` is provided.
33
+ * Ignored if `uploader` is provided.
34
+ */
35
+ url?: string;
36
+ /**
37
+ * Custom upload function that replaces the built-in FormData POST.
38
+ * Use it for multi-step flows (e.g. presigned S3) or any non-standard
39
+ * transport. When set, the `url` prop is ignored.
40
+ */
41
+ uploader?: Uploader; /** When false, files are added to state but not uploaded automatically. Default: true. */
42
+ autoSend?: boolean; /** Maximum file size in bytes. Files exceeding this will be rejected. */
43
+ maxSize?: number; /** Called when the file list changes (added or removed). Useful when autoSend=false. */
44
+ onChange?: (files: File[]) => void;
45
+ data?: Record<string, unknown>;
46
+ headers?: Record<string, string>;
47
+ /**
48
+ * Files the dropzone accepts. Forwarded directly to Mantine's
49
+ * `<Dropzone accept>`.
50
+ *
51
+ * Two formats are supported:
52
+ * - **Map (preferred)**: `{ [mimeType]: ['.ext', ...] }` — matches
53
+ * the native `react-dropzone` shape and produces a correct
54
+ * `<input accept>` with MIME + extension pairs. Required when any
55
+ * key would otherwise be a bare extension string.
56
+ * - **Array**: `string[]` of MIME types (no `.ext` entries) — kept
57
+ * for backward compatibility. Mixing `.ext` strings into the
58
+ * array triggers a `Skipped "..." because it is not a valid MIME
59
+ * type` warning from `react-dropzone` v15+.
60
+ */
61
+ accept?: string[] | Record<string, string[]>;
62
+ title?: ReactNode;
63
+ subtitle?: ReactNode;
64
+ hint?: ReactNode;
65
+ inputId?: string;
66
+ onFileUploaded?: (file: FileData) => void;
67
+ hideWhenFull?: boolean;
68
+ classNames?: {
69
+ dropzoneBase?: string;
70
+ root?: string;
71
+ input?: {
72
+ root?: string;
73
+ inner?: string;
74
+ };
75
+ iconSlot?: string;
76
+ dropzoneIcon?: IconProps['classNames'];
77
+ loader?: LoaderOvalProps['classNames'];
78
+ textSlot?: string;
79
+ title?: string;
80
+ subtitle?: string;
81
+ hint?: string;
82
+ };
83
+ direction?: 'default' | 'reverse';
84
+ };
85
+ //#endregion
86
+ export { DropzoneBaseProps, FileData };
87
+ //# sourceMappingURL=DropzoneBase.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropzoneBase.d.mts","names":[],"sources":["../../../../src/components/controls/dropzone/DropzoneBase.tsx"],"mappings":";;;;;;KAkCY,QAAA;EACV,IAAA;EACA,IAAA;EACA,IAAA;EACA,IAAA;EACA,QAAA;EACA,OAAA;EACA,GAAA;EACA,KAAA;EACA,QAAA;AAAA;AAAA,KAGU,iBAAA;EACV,QAAA;IACE,KAAA;IACA,WAAA;IACA;EAAA;IAEA,KAAA,EAAO,MAAA,SAAe,QAAA;IACtB,WAAA;IACA,UAAA,GAAa,QAAA;EAAA,MACT,SAAA;EACN,YAAA,GAAe,MAAA,SAAe,QAAA;EAC9B,QAAA;EAXU;;;;;EAiBV,GAAA;EAXwB;;;;;EAiBxB,QAAA,GAAW,QAAA,EAMQ;EAJnB,QAAA,YAMU;EAJV,OAAA,WAoBQ;EAlBR,QAAA,IAAY,KAAA,EAAO,IAAA;EACnB,IAAA,GAAO,MAAA;EACP,OAAA,GAAU,MAAA;EA8BO;;;;;;;;;;;;;;EAfjB,MAAA,cAAoB,MAAA;EACpB,KAAA,GAAQ,SAAA;EACR,QAAA,GAAW,SAAA;EACX,IAAA,GAAO,SAAA;EACP,OAAA;EACA,cAAA,IAAkB,IAAA,EAAM,QAAA;EACxB,YAAA;EACA,UAAA;IACE,YAAA;IACA,IAAA;IACA,KAAA;MACE,IAAA;MACA,KAAA;IAAA;IAEF,QAAA;IACA,YAAA,GAAe,SAAA;IACf,MAAA,GAAS,eAAA;IACT,QAAA;IACA,KAAA;IACA,QAAA;IACA,IAAA;EAAA;EAEF,SAAA;AAAA"}
@@ -0,0 +1,2 @@
1
+ import{Icon as e}from"../../data-display/icons/icon/Icon.mjs";import{LoaderOval as t}from"../../data-display/loader-oval/LoaderOval.mjs";import{useDropzoneState as n}from"./use-dropzone-state.mjs";import{cx as r}from"@mage-ui/styled-system/css";import{dropzoneBase as i,dropzoneBaseHint as a,dropzoneBaseIcon as o,dropzoneBaseIconSlot as s,dropzoneBaseInput as c,dropzoneBaseInputInner as l,dropzoneBaseLoader as u,dropzoneBaseLoaderRoot as d,dropzoneBaseRoot as f,dropzoneBaseSubtitle as p,dropzoneBaseTextSlot as m,dropzoneBaseTitle as h}from"@mage-ui/styled-system/recipes";import{Fragment as g,jsx as _,jsxs as v}from"react/jsx-runtime";import{useCallback as y,useRef as b}from"react";import{Dropzone as x}from"@mantine/dropzone";const S=({data:S,headers:C,children:w,initialFiles:T={},maxFiles:E,url:D,uploader:O,autoSend:k=!0,maxSize:A,onChange:j,accept:M,title:N,subtitle:P,hint:F,inputId:I,onFileUploaded:L,classNames:R,direction:z=`default`,hideWhenFull:B=!1})=>{let V=b(null),H=b(new Map),{files:U,isUploading:W,uploadMultipleFiles:G,addFile:K,removeFile:q}=n(D,T,L,C,O),J=y(e=>{q(e),H.current.delete(e),!k&&j&&j(Array.from(H.current.values()))},[q,k,j]),Y=y(async e=>{let t=Object.keys(U).length,n=(E??1/0)-t;if(n<=0)return;let r=e.slice(0,n);if(k)await G(r,S);else{for(let e of r)K(e),H.current.set(e.name,e);j?.(Array.from(H.current.values()))}},[k,G,K,S,U,E,j]),X=E!==void 0&&Object.keys(U).length>=E;return v(`div`,{className:r(R?.dropzoneBase??i(),R?.root??f()),"data-direction":z,children:[(!B||!X)&&v(x,{ref:V,onDrop:Y,disabled:X,loading:W,accept:M,maxSize:A,preventDropOnDocument:!0,inputProps:{id:I},classNames:{root:R?.input?.root??r(c(),`group`),inner:R?.input?.inner??l()},children:[_(`div`,{className:R?.iconSlot??s(),children:W?_(t,{classNames:{loader:R?.loader?.loader??u(),root:R?.loader?.root??d()}}):v(g,{children:[_(x.Idle,{children:_(e,{name:`mage-dropzone-upload-01`,path:`/icons/sprite-mage.svg`,classNames:{icon:R?.dropzoneIcon?.icon??o()}})}),_(x.Accept,{children:_(e,{name:`mage-dropzone-thumbs-up`,path:`/icons/sprite-mage.svg`,classNames:{icon:R?.dropzoneIcon?.icon??o()}})}),_(x.Reject,{children:_(e,{name:`mage-dropzone-thumbs-down`,path:`/icons/sprite-mage.svg`,classNames:{icon:R?.dropzoneIcon?.icon??o()}})})]})}),v(`div`,{className:R?.textSlot??m(),children:[_(`span`,{className:R?.title??h(),children:N||`Upload files`}),_(`span`,{className:R?.subtitle??p(),children:P||`Drag images here or click to select files`}),_(`span`,{className:R?.hint??a(),children:F||`Attach as many files as you like, each file should not exceed 5mb`})]})]}),w({files:U,isUploading:W,removeFile:J})]})};export{S as DropzoneBase};
2
+ //# sourceMappingURL=DropzoneBase.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropzoneBase.mjs","names":["MantineDropzone"],"sources":["../../../../src/components/controls/dropzone/DropzoneBase.tsx"],"sourcesContent":["import { type ReactNode, useCallback, useRef } from 'react';\n\nimport { cx } from '@mage-ui/styled-system/css';\nimport {\n dropzoneBase,\n dropzoneBaseHint,\n dropzoneBaseIcon,\n dropzoneBaseIconSlot,\n dropzoneBaseInput,\n dropzoneBaseInputInner,\n dropzoneBaseLoader,\n dropzoneBaseLoaderRoot,\n dropzoneBaseRoot,\n dropzoneBaseSubtitle,\n dropzoneBaseTextSlot,\n dropzoneBaseTitle,\n} from '@mage-ui/styled-system/recipes';\nimport { Dropzone as MantineDropzone } from '@mantine/dropzone';\nimport {\n Icon,\n type IconProps,\n LoaderOval,\n type LoaderOvalProps,\n} from '@/components/data-display';\n\nimport type {\n Uploader,\n UploadProgress,\n UploadResponse,\n} from './upload-service';\nimport { useDropzoneState } from './use-dropzone-state';\n\nexport type { Uploader, UploadProgress, UploadResponse };\n\nexport type FileData = {\n name: string;\n size: number;\n type: string;\n date: string;\n uploaded: boolean;\n loading: boolean;\n url: string;\n error?: string;\n progress?: number; // (0-100)\n};\n\nexport type DropzoneBaseProps = {\n children: ({\n files,\n isUploading,\n removeFile,\n }: {\n files: Record<string, FileData>;\n isUploading: boolean;\n removeFile: (fileName: string) => void;\n }) => ReactNode;\n initialFiles?: Record<string, FileData>;\n maxFiles?: number;\n /**\n * Endpoint used by the built-in FormData uploader. Required when\n * `autoSend=true` (default) AND no custom `uploader` is provided.\n * Ignored if `uploader` is provided.\n */\n url?: string;\n /**\n * Custom upload function that replaces the built-in FormData POST.\n * Use it for multi-step flows (e.g. presigned S3) or any non-standard\n * transport. When set, the `url` prop is ignored.\n */\n uploader?: Uploader;\n /** When false, files are added to state but not uploaded automatically. Default: true. */\n autoSend?: boolean;\n /** Maximum file size in bytes. Files exceeding this will be rejected. */\n maxSize?: number;\n /** Called when the file list changes (added or removed). Useful when autoSend=false. */\n onChange?: (files: File[]) => void;\n data?: Record<string, unknown>;\n headers?: Record<string, string>;\n /**\n * Files the dropzone accepts. Forwarded directly to Mantine's\n * `<Dropzone accept>`.\n *\n * Two formats are supported:\n * - **Map (preferred)**: `{ [mimeType]: ['.ext', ...] }` — matches\n * the native `react-dropzone` shape and produces a correct\n * `<input accept>` with MIME + extension pairs. Required when any\n * key would otherwise be a bare extension string.\n * - **Array**: `string[]` of MIME types (no `.ext` entries) — kept\n * for backward compatibility. Mixing `.ext` strings into the\n * array triggers a `Skipped \"...\" because it is not a valid MIME\n * type` warning from `react-dropzone` v15+.\n */\n accept?: string[] | Record<string, string[]>;\n title?: ReactNode;\n subtitle?: ReactNode;\n hint?: ReactNode;\n inputId?: string;\n onFileUploaded?: (file: FileData) => void;\n hideWhenFull?: boolean;\n classNames?: {\n dropzoneBase?: string;\n root?: string;\n input?: {\n root?: string;\n inner?: string;\n };\n iconSlot?: string;\n dropzoneIcon?: IconProps['classNames'];\n loader?: LoaderOvalProps['classNames'];\n textSlot?: string;\n title?: string;\n subtitle?: string;\n hint?: string;\n };\n direction?: 'default' | 'reverse';\n};\n\nexport const DropzoneBase = ({\n data,\n headers,\n children,\n initialFiles = {},\n maxFiles,\n url,\n uploader,\n autoSend = true,\n maxSize,\n onChange,\n accept,\n title,\n subtitle,\n hint,\n inputId,\n onFileUploaded,\n classNames,\n direction = 'default',\n hideWhenFull = false,\n}: DropzoneBaseProps) => {\n const dropzoneRef = useRef<HTMLDivElement>(null);\n const rawFilesRef = useRef<Map<string, File>>(new Map());\n const {\n files,\n isUploading,\n uploadMultipleFiles,\n addFile,\n removeFile: hookRemoveFile,\n } = useDropzoneState(url, initialFiles, onFileUploaded, headers, uploader);\n\n const removeFile = useCallback(\n (fileName: string) => {\n hookRemoveFile(fileName);\n rawFilesRef.current.delete(fileName);\n if (!autoSend && onChange) {\n onChange(Array.from(rawFilesRef.current.values()));\n }\n },\n [hookRemoveFile, autoSend, onChange],\n );\n\n const handleDrop = useCallback(\n async (acceptedFiles: File[]) => {\n const currentCount = Object.keys(files).length;\n const max = maxFiles ?? Number.POSITIVE_INFINITY;\n const remainingSlots = max - currentCount;\n if (remainingSlots <= 0) {\n return;\n }\n const filesToProcess = acceptedFiles.slice(0, remainingSlots);\n if (autoSend) {\n await uploadMultipleFiles(filesToProcess, data);\n } else {\n for (const file of filesToProcess) {\n addFile(file);\n rawFilesRef.current.set(file.name, file);\n }\n onChange?.(Array.from(rawFilesRef.current.values()));\n }\n },\n [autoSend, uploadMultipleFiles, addFile, data, files, maxFiles, onChange],\n );\n\n const isFull =\n maxFiles !== undefined && Object.keys(files).length >= maxFiles;\n\n return (\n <div\n className={cx(\n classNames?.dropzoneBase ?? dropzoneBase(),\n classNames?.root ?? dropzoneBaseRoot(),\n )}\n data-direction={direction}\n >\n {(!hideWhenFull || !isFull) && (\n <MantineDropzone\n ref={dropzoneRef}\n onDrop={handleDrop}\n disabled={isFull}\n loading={isUploading}\n accept={accept}\n maxSize={maxSize}\n preventDropOnDocument\n inputProps={{ id: inputId }}\n classNames={{\n root: classNames?.input?.root ?? cx(dropzoneBaseInput(), 'group'),\n inner: classNames?.input?.inner ?? dropzoneBaseInputInner(),\n }}\n >\n <div className={classNames?.iconSlot ?? dropzoneBaseIconSlot()}>\n {isUploading ? (\n <LoaderOval\n classNames={{\n loader: classNames?.loader?.loader ?? dropzoneBaseLoader(),\n root: classNames?.loader?.root ?? dropzoneBaseLoaderRoot(),\n }}\n />\n ) : (\n <>\n <MantineDropzone.Idle>\n <Icon\n name='mage-dropzone-upload-01'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon:\n classNames?.dropzoneIcon?.icon ?? dropzoneBaseIcon(),\n }}\n />\n </MantineDropzone.Idle>\n <MantineDropzone.Accept>\n <Icon\n name='mage-dropzone-thumbs-up'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon:\n classNames?.dropzoneIcon?.icon ?? dropzoneBaseIcon(),\n }}\n />\n </MantineDropzone.Accept>\n <MantineDropzone.Reject>\n <Icon\n name='mage-dropzone-thumbs-down'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon:\n classNames?.dropzoneIcon?.icon ?? dropzoneBaseIcon(),\n }}\n />\n </MantineDropzone.Reject>\n </>\n )}\n </div>\n <div className={classNames?.textSlot ?? dropzoneBaseTextSlot()}>\n <span className={classNames?.title ?? dropzoneBaseTitle()}>\n {title || 'Upload files'}\n </span>\n <span className={classNames?.subtitle ?? dropzoneBaseSubtitle()}>\n {subtitle || 'Drag images here or click to select files'}\n </span>\n <span className={classNames?.hint ?? dropzoneBaseHint()}>\n {hint ||\n 'Attach as many files as you like, each file should not exceed 5mb'}\n </span>\n </div>\n </MantineDropzone>\n )}\n {children({ files, isUploading, removeFile })}\n </div>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { DropzoneS3Texts, S3FileMeta, S3InitBody, S3InitResponse, S3UploadConfig, getFileExtension } from "./use-s3-upload.mjs";
2
+ import { DropzoneProps } from "./Dropzone.mjs";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+
5
+ //#region src/components/controls/dropzone/DropzoneS3.d.ts
6
+ type DropzoneS3Props<TInitBody extends S3InitBody = S3InitBody> = Omit<DropzoneProps, 'uploader' | 'url' | 'accept' | 'title' | 'subtitle' | 'hint'> & S3UploadConfig<TInitBody> & {
7
+ /**
8
+ * Explicit accept list forwarded to the underlying Mantine dropzone.
9
+ * Takes precedence over `acceptedTypes`. Prefer the map shape
10
+ * `{ [mimeType]: ['.ext', ...] }` — passing a `.ext` entry inside a
11
+ * plain `string[]` triggers a "Skipped … not a valid MIME type"
12
+ * warning in react-dropzone v15+.
13
+ */
14
+ accept?: string[] | Record<string, string[]>;
15
+ };
16
+ declare const DropzoneS3: <TInitBody extends S3InitBody = S3InitBody>({
17
+ texts,
18
+ acceptedTypes,
19
+ accept,
20
+ initUrl,
21
+ buildInitBody,
22
+ register,
23
+ getHeaders,
24
+ getErrorMessage,
25
+ resolveUploadedUrl,
26
+ ...dropzoneProps
27
+ }: DropzoneS3Props<TInitBody>) => react_jsx_runtime0.JSX.Element;
28
+ //#endregion
29
+ export { DropzoneS3, DropzoneS3Props };
30
+ //# sourceMappingURL=DropzoneS3.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropzoneS3.d.mts","names":[],"sources":["../../../../src/components/controls/dropzone/DropzoneS3.tsx"],"mappings":";;;;;KAiBY,eAAA,mBAAkC,UAAA,GAAa,UAAA,IAAc,IAAA,CACvE,aAAA,mEAGA,cAAA,CAAe,SAAA;EAJL;;;;;;;EAYR,MAAA,cAAoB,MAAA;AAAA;AAAA,cAGX,UAAA,qBAAgC,UAAA,GAAa,UAAA;EAAY,KAAA;EAAA,aAAA;EAAA,MAAA;EAAA,OAAA;EAAA,aAAA;EAAA,QAAA;EAAA,UAAA;EAAA,eAAA;EAAA,kBAAA;EAAA,GAAA;AAAA,GAWnE,eAAA,CAAgB,SAAA,MAAU,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,2 @@
1
+ import{buildAcceptMap as e,defaultGetErrorMessage as t,useS3Upload as n}from"./use-s3-upload.mjs";import{Dropzone as r}from"./Dropzone.mjs";import{jsx as i}from"react/jsx-runtime";const a=({texts:a,acceptedTypes:o,accept:s,initUrl:c,buildInitBody:l,register:u,getHeaders:d,getErrorMessage:f=t,resolveUploadedUrl:p,...m})=>{let h=s??e(o),{upload:g}=n({initUrl:c,buildInitBody:l,register:u,getHeaders:d,getErrorMessage:f,resolveUploadedUrl:p,acceptedTypes:o,texts:a}),_=async(e,{onProgress:t})=>({body:{url:await g(e,n=>t?.({loaded:0,total:e.size,percentage:n}))}});return i(r,{...m,title:a?.title,subtitle:a?.subtitle,hint:a?.hint,accept:h,uploader:_})};export{a as DropzoneS3};
2
+ //# sourceMappingURL=DropzoneS3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropzoneS3.mjs","names":[],"sources":["../../../../src/components/controls/dropzone/DropzoneS3.tsx"],"sourcesContent":["import { Dropzone, type DropzoneProps } from './Dropzone';\nimport type { Uploader } from './upload-service';\nimport {\n buildAcceptMap,\n type DropzoneS3Texts,\n defaultGetErrorMessage,\n getFileExtension,\n type S3FileMeta,\n type S3InitBody,\n type S3InitResponse,\n type S3UploadConfig,\n useS3Upload,\n} from './use-s3-upload';\n\nexport type { DropzoneS3Texts, S3FileMeta, S3InitBody, S3InitResponse };\nexport { getFileExtension };\n\nexport type DropzoneS3Props<TInitBody extends S3InitBody = S3InitBody> = Omit<\n DropzoneProps,\n 'uploader' | 'url' | 'accept' | 'title' | 'subtitle' | 'hint'\n> &\n S3UploadConfig<TInitBody> & {\n /**\n * Explicit accept list forwarded to the underlying Mantine dropzone.\n * Takes precedence over `acceptedTypes`. Prefer the map shape\n * `{ [mimeType]: ['.ext', ...] }` — passing a `.ext` entry inside a\n * plain `string[]` triggers a \"Skipped … not a valid MIME type\"\n * warning in react-dropzone v15+.\n */\n accept?: string[] | Record<string, string[]>;\n };\n\nexport const DropzoneS3 = <TInitBody extends S3InitBody = S3InitBody>({\n texts,\n acceptedTypes,\n accept,\n initUrl,\n buildInitBody,\n register,\n getHeaders,\n getErrorMessage = defaultGetErrorMessage,\n resolveUploadedUrl,\n ...dropzoneProps\n}: DropzoneS3Props<TInitBody>) => {\n const acceptList = accept ?? buildAcceptMap(acceptedTypes);\n const { upload } = useS3Upload<TInitBody>({\n initUrl,\n buildInitBody,\n register,\n getHeaders,\n getErrorMessage,\n resolveUploadedUrl,\n acceptedTypes,\n texts,\n });\n\n const uploader: Uploader = async (file, { onProgress }) => {\n const url = await upload(file, (p) =>\n onProgress?.({ loaded: 0, total: file.size, percentage: p }),\n );\n return { body: { url } };\n };\n\n return (\n <Dropzone\n {...dropzoneProps}\n title={texts?.title}\n subtitle={texts?.subtitle}\n hint={texts?.hint}\n accept={acceptList}\n uploader={uploader}\n />\n );\n};\n"],"mappings":"oLAgCA,MAAa,GAAyD,CACpE,QACA,gBACA,SACA,UACA,gBACA,WACA,aACA,kBAAkB,EAClB,qBACA,GAAG,KAC6B,CAChC,IAAM,EAAa,GAAU,EAAe,EAAc,CACpD,CAAE,UAAW,EAAuB,CACxC,UACA,gBACA,WACA,aACA,kBACA,qBACA,gBACA,QACD,CAAC,CAEI,EAAqB,MAAO,EAAM,CAAE,iBAIjC,CAAE,KAAM,CAAE,IAHL,MAAM,EAAO,EAAO,GAC9B,IAAa,CAAE,OAAQ,EAAG,MAAO,EAAK,KAAM,WAAY,EAAG,CAAC,CAC7D,CACqB,CAAE,EAG1B,OACE,EAAC,EAAD,CACE,GAAI,EACJ,MAAO,GAAO,MACd,SAAU,GAAO,SACjB,KAAM,GAAO,KACb,OAAQ,EACE,WACV,CAAA"}
@@ -1,7 +1,7 @@
1
- import { IconProps } from "../../data-display/icons/icon/Icon.mjs";
1
+ import { IconProps } from "../../../data-display/icons/icon/Icon.mjs";
2
2
  import * as react_jsx_runtime0 from "react/jsx-runtime";
3
3
 
4
- //#region src/components/controls/avatar-dropzone/AvatarDropzone.d.ts
4
+ //#region src/components/controls/dropzone/avatar/AvatarDropzone.d.ts
5
5
  type AvatarDropzoneProps = {
6
6
  value?: string;
7
7
  onChange?: (file: File) => void;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarDropzone.d.mts","names":[],"sources":["../../../../../src/components/controls/dropzone/avatar/AvatarDropzone.tsx"],"mappings":";;;;KAmBY,mBAAA;EACV,KAAA;EACA,QAAA,IAAY,IAAA,EAAM,IAAA;EAClB,OAAA;EACA,UAAA;IACE,QAAA;IACA,IAAA;IACA,KAAA;IACA,KAAA;IACA,OAAA;IACA,eAAA;IACA,QAAA;IACA,IAAA,GAAO,SAAA;EAAA;AAAA;AAAA,cAIE,cAAA;EAAkB,KAAA;EAAA,QAAA;EAAA,OAAA;EAAA;AAAA,GAK5B,mBAAA,KAAmB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,2 @@
1
+ import{Icon as e}from"../../../data-display/icons/icon/Icon.mjs";import{cx as t}from"@mage-ui/styled-system/css";import{avatarDropzone as n,avatarDropzoneIcon as r,avatarDropzoneIconSlot as i,avatarDropzoneImage as a,avatarDropzoneInner as o,avatarDropzoneOverlay as s,avatarDropzoneOverlayIconSlot as c,avatarDropzoneRoot as l}from"@mage-ui/styled-system/recipes";import{Fragment as u,jsx as d,jsxs as f}from"react/jsx-runtime";import{useCallback as p,useState as m}from"react";import{Dropzone as h,IMAGE_MIME_TYPE as g}from"@mantine/dropzone";const _=({value:_,onChange:v,maxSize:y,classNames:b})=>{let[x,S]=m(_??null);return f(h,{onDrop:p(e=>{let t=e[0];t&&(S(URL.createObjectURL(t)),v?.(t))},[v]),accept:g,maxFiles:1,maxSize:y,classNames:{root:t(b?.dropzone??n(),b?.root??l(),`group`),inner:b?.inner??o()},children:[d(h.Idle,{children:x?f(u,{children:[d(`img`,{src:x,alt:`Avatar`,className:b?.image??a()}),d(`div`,{className:b?.overlay??s()}),d(`div`,{className:b?.overlayIconSlot??c(),children:d(e,{name:`mage-avatar-dropzone-camera-plus`,path:`/icons/sprite-mage.svg`,classNames:{icon:b?.icon?.icon??r()}})})]}):d(`div`,{className:b?.iconSlot??i(),children:d(e,{name:`mage-avatar-dropzone-camera-plus`,path:`/icons/sprite-mage.svg`,classNames:{icon:b?.icon?.icon??r()}})})}),d(h.Accept,{children:d(`div`,{className:b?.iconSlot??i(),children:d(e,{name:`mage-dropzone-thumbs-up`,path:`/icons/sprite-mage.svg`,classNames:{icon:b?.icon?.icon??r()}})})}),d(h.Reject,{children:d(`div`,{className:b?.iconSlot??i(),children:d(e,{name:`mage-dropzone-thumbs-down`,path:`/icons/sprite-mage.svg`,classNames:{icon:b?.icon?.icon??r()}})})})]})};export{_ as AvatarDropzone};
2
+ //# sourceMappingURL=AvatarDropzone.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarDropzone.mjs","names":["MantineDropzone"],"sources":["../../../../../src/components/controls/dropzone/avatar/AvatarDropzone.tsx"],"sourcesContent":["import { useCallback, useState } from 'react';\n\nimport { cx } from '@mage-ui/styled-system/css';\nimport {\n avatarDropzone,\n avatarDropzoneIcon,\n avatarDropzoneIconSlot,\n avatarDropzoneImage,\n avatarDropzoneInner,\n avatarDropzoneOverlay,\n avatarDropzoneOverlayIconSlot,\n avatarDropzoneRoot,\n} from '@mage-ui/styled-system/recipes';\nimport {\n IMAGE_MIME_TYPE,\n Dropzone as MantineDropzone,\n} from '@mantine/dropzone';\nimport { Icon, type IconProps } from '@/components/data-display';\n\nexport type AvatarDropzoneProps = {\n value?: string;\n onChange?: (file: File) => void;\n maxSize?: number;\n classNames?: {\n dropzone?: string;\n root?: string;\n inner?: string;\n image?: string;\n overlay?: string;\n overlayIconSlot?: string;\n iconSlot?: string;\n icon?: IconProps['classNames'];\n };\n};\n\nexport const AvatarDropzone = ({\n value,\n onChange,\n maxSize,\n classNames,\n}: AvatarDropzoneProps) => {\n const [preview, setPreview] = useState<string | null>(value ?? null);\n\n const handleDrop = useCallback(\n (files: File[]) => {\n const file = files[0];\n if (!file) return;\n const url = URL.createObjectURL(file);\n setPreview(url);\n onChange?.(file);\n },\n [onChange],\n );\n\n return (\n <MantineDropzone\n onDrop={handleDrop}\n accept={IMAGE_MIME_TYPE}\n maxFiles={1}\n maxSize={maxSize}\n classNames={{\n root: cx(\n classNames?.dropzone ?? avatarDropzone(),\n classNames?.root ?? avatarDropzoneRoot(),\n 'group',\n ),\n inner: classNames?.inner ?? avatarDropzoneInner(),\n }}\n >\n <MantineDropzone.Idle>\n {preview ? (\n <>\n <img\n src={preview}\n alt='Avatar'\n className={classNames?.image ?? avatarDropzoneImage()}\n />\n <div className={classNames?.overlay ?? avatarDropzoneOverlay()} />\n <div\n className={\n classNames?.overlayIconSlot ?? avatarDropzoneOverlayIconSlot()\n }\n >\n <Icon\n name='mage-avatar-dropzone-camera-plus'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.icon?.icon ?? avatarDropzoneIcon(),\n }}\n />\n </div>\n </>\n ) : (\n <div className={classNames?.iconSlot ?? avatarDropzoneIconSlot()}>\n <Icon\n name='mage-avatar-dropzone-camera-plus'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.icon?.icon ?? avatarDropzoneIcon(),\n }}\n />\n </div>\n )}\n </MantineDropzone.Idle>\n <MantineDropzone.Accept>\n <div className={classNames?.iconSlot ?? avatarDropzoneIconSlot()}>\n <Icon\n name='mage-dropzone-thumbs-up'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.icon?.icon ?? avatarDropzoneIcon(),\n }}\n />\n </div>\n </MantineDropzone.Accept>\n <MantineDropzone.Reject>\n <div className={classNames?.iconSlot ?? avatarDropzoneIconSlot()}>\n <Icon\n name='mage-dropzone-thumbs-down'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.icon?.icon ?? avatarDropzoneIcon(),\n }}\n />\n </div>\n </MantineDropzone.Reject>\n </MantineDropzone>\n );\n};\n"],"mappings":"iiBAmCA,MAAa,GAAkB,CAC7B,QACA,WACA,UACA,gBACyB,CACzB,GAAM,CAAC,EAAS,GAAc,EAAwB,GAAS,KAAK,CAapE,OACE,EAACA,EAAD,CACE,OAbe,EAChB,GAAkB,CACjB,IAAM,EAAO,EAAM,GACd,IAEL,EADY,IAAI,gBAAgB,EAAK,CACtB,CACf,IAAW,EAAK,GAElB,CAAC,EAAS,CACX,CAKG,OAAQ,EACR,SAAU,EACD,UACT,WAAY,CACV,KAAM,EACJ,GAAY,UAAY,GAAgB,CACxC,GAAY,MAAQ,GAAoB,CACxC,QACD,CACD,MAAO,GAAY,OAAS,GAAqB,CAClD,UAZH,CAcE,EAACA,EAAgB,KAAjB,CAAA,SACG,EACC,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,MAAD,CACE,IAAK,EACL,IAAI,SACJ,UAAW,GAAY,OAAS,GAAqB,CACrD,CAAA,CACF,EAAC,MAAD,CAAK,UAAW,GAAY,SAAW,GAAuB,CAAI,CAAA,CAClE,EAAC,MAAD,CACE,UACE,GAAY,iBAAmB,GAA+B,UAGhE,EAAC,EAAD,CACE,KAAK,mCACL,KAAK,yBACL,WAAY,CACV,KAAM,GAAY,MAAM,MAAQ,GAAoB,CACrD,CACD,CAAA,CACE,CAAA,CACL,CAAA,CAAA,CAEH,EAAC,MAAD,CAAK,UAAW,GAAY,UAAY,GAAwB,UAC9D,EAAC,EAAD,CACE,KAAK,mCACL,KAAK,yBACL,WAAY,CACV,KAAM,GAAY,MAAM,MAAQ,GAAoB,CACrD,CACD,CAAA,CACE,CAAA,CAEa,CAAA,CACvB,EAACA,EAAgB,OAAjB,CAAA,SACE,EAAC,MAAD,CAAK,UAAW,GAAY,UAAY,GAAwB,UAC9D,EAAC,EAAD,CACE,KAAK,0BACL,KAAK,yBACL,WAAY,CACV,KAAM,GAAY,MAAM,MAAQ,GAAoB,CACrD,CACD,CAAA,CACE,CAAA,CACiB,CAAA,CACzB,EAACA,EAAgB,OAAjB,CAAA,SACE,EAAC,MAAD,CAAK,UAAW,GAAY,UAAY,GAAwB,UAC9D,EAAC,EAAD,CACE,KAAK,4BACL,KAAK,yBACL,WAAY,CACV,KAAM,GAAY,MAAM,MAAQ,GAAoB,CACrD,CACD,CAAA,CACE,CAAA,CACiB,CAAA,CACT"}
@@ -0,0 +1,41 @@
1
+ import { IconProps } from "../../../data-display/icons/icon/Icon.mjs";
2
+ import { LoaderOvalProps } from "../../../data-display/loader-oval/LoaderOval.mjs";
3
+ import { S3InitBody, S3UploadConfig } from "../use-s3-upload.mjs";
4
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
5
+
6
+ //#region src/components/controls/dropzone/avatar/AvatarDropzoneS3.d.ts
7
+ type AvatarDropzoneS3Props<TInitBody extends S3InitBody = S3InitBody> = S3UploadConfig<TInitBody> & {
8
+ value?: string;
9
+ onChange?: (url: string) => void;
10
+ onError?: (message: string) => void;
11
+ maxSize?: number;
12
+ classNames?: {
13
+ dropzone?: string;
14
+ root?: string;
15
+ inner?: string;
16
+ image?: string;
17
+ overlay?: string;
18
+ overlayIconSlot?: string;
19
+ iconSlot?: string;
20
+ icon?: IconProps['classNames'];
21
+ loader?: LoaderOvalProps['classNames'];
22
+ };
23
+ };
24
+ declare const AvatarDropzoneS3: <TInitBody extends S3InitBody = S3InitBody>({
25
+ value,
26
+ onChange,
27
+ onError,
28
+ maxSize,
29
+ classNames,
30
+ initUrl,
31
+ buildInitBody,
32
+ register,
33
+ getHeaders,
34
+ getErrorMessage,
35
+ resolveUploadedUrl,
36
+ acceptedTypes,
37
+ texts
38
+ }: AvatarDropzoneS3Props<TInitBody>) => react_jsx_runtime0.JSX.Element;
39
+ //#endregion
40
+ export { AvatarDropzoneS3, AvatarDropzoneS3Props };
41
+ //# sourceMappingURL=AvatarDropzoneS3.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarDropzoneS3.d.mts","names":[],"sources":["../../../../../src/components/controls/dropzone/avatar/AvatarDropzoneS3.tsx"],"mappings":";;;;;;KA8BY,qBAAA,mBAAwC,UAAA,GAAa,UAAA,IAC/D,cAAA,CAAe,SAAA;EACb,KAAA;EACA,QAAA,IAAY,GAAA;EACZ,OAAA,IAAW,OAAA;EACX,OAAA;EACA,UAAA;IACE,QAAA;IACA,IAAA;IACA,KAAA;IACA,KAAA;IACA,OAAA;IACA,eAAA;IACA,QAAA;IACA,IAAA,GAAO,SAAA;IACP,MAAA,GAAS,eAAA;EAAA;AAAA;AAAA,cAIF,gBAAA,qBAAsC,UAAA,GAAa,UAAA;EAAY,KAAA;EAAA,QAAA;EAAA,OAAA;EAAA,OAAA;EAAA,UAAA;EAAA,OAAA;EAAA,aAAA;EAAA,QAAA;EAAA,UAAA;EAAA,eAAA;EAAA,kBAAA;EAAA,aAAA;EAAA;AAAA,GAczE,qBAAA,CAAsB,SAAA,MAAU,kBAAA,CAAA,GAAA,CAAA,OAAA"}
@@ -0,0 +1,2 @@
1
+ import{Icon as e}from"../../../data-display/icons/icon/Icon.mjs";import{LoaderOval as t}from"../../../data-display/loader-oval/LoaderOval.mjs";import{useS3Upload as n}from"../use-s3-upload.mjs";import{cx as r}from"@mage-ui/styled-system/css";import{avatarDropzone as i,avatarDropzoneIcon as a,avatarDropzoneIconSlot as o,avatarDropzoneImage as s,avatarDropzoneInner as c,avatarDropzoneOverlay as l,avatarDropzoneOverlayIconSlot as u,avatarDropzoneRoot as d}from"@mage-ui/styled-system/recipes";import{Fragment as f,jsx as p,jsxs as m}from"react/jsx-runtime";import{useCallback as h,useState as g}from"react";import{Dropzone as _,IMAGE_MIME_TYPE as v}from"@mantine/dropzone";const y=({value:y,onChange:b,onError:x,maxSize:S,classNames:C,initUrl:w,buildInitBody:T,register:E,getHeaders:D,getErrorMessage:O,resolveUploadedUrl:k,acceptedTypes:A,texts:j})=>{let[M,N]=g(y??null),{upload:P,isUploading:F}=n({initUrl:w,buildInitBody:T,register:E,getHeaders:D,getErrorMessage:O,resolveUploadedUrl:k,acceptedTypes:A,texts:j});return m(_,{onDrop:h(async e=>{let t=e[0];if(t){N(URL.createObjectURL(t));try{let e=await P(t);b?.(e)}catch(e){N(y??null),x?.(e.message)}}},[P,b,x,y]),accept:v,maxFiles:1,maxSize:S,loading:F,classNames:{root:r(C?.dropzone??i(),C?.root??d(),`group`),inner:C?.inner??c()},children:[p(_.Idle,{children:F?p(`div`,{className:C?.iconSlot??o(),children:p(t,{classNames:C?.loader})}):M?m(f,{children:[p(`img`,{src:M,alt:`Avatar`,className:C?.image??s()}),p(`div`,{className:C?.overlay??l()}),p(`div`,{className:C?.overlayIconSlot??u(),children:p(e,{name:`mage-avatar-dropzone-camera-plus`,path:`/icons/sprite-mage.svg`,classNames:{icon:C?.icon?.icon??a()}})})]}):p(`div`,{className:C?.iconSlot??o(),children:p(e,{name:`mage-avatar-dropzone-camera-plus`,path:`/icons/sprite-mage.svg`,classNames:{icon:C?.icon?.icon??a()}})})}),p(_.Accept,{children:p(`div`,{className:C?.iconSlot??o(),children:p(e,{name:`mage-dropzone-thumbs-up`,path:`/icons/sprite-mage.svg`,classNames:{icon:C?.icon?.icon??a()}})})}),p(_.Reject,{children:p(`div`,{className:C?.iconSlot??o(),children:p(e,{name:`mage-dropzone-thumbs-down`,path:`/icons/sprite-mage.svg`,classNames:{icon:C?.icon?.icon??a()}})})})]})};export{y as AvatarDropzoneS3};
2
+ //# sourceMappingURL=AvatarDropzoneS3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarDropzoneS3.mjs","names":["MantineDropzone"],"sources":["../../../../../src/components/controls/dropzone/avatar/AvatarDropzoneS3.tsx"],"sourcesContent":["import { useCallback, useState } from 'react';\n\nimport { cx } from '@mage-ui/styled-system/css';\nimport {\n avatarDropzone,\n avatarDropzoneIcon,\n avatarDropzoneIconSlot,\n avatarDropzoneImage,\n avatarDropzoneInner,\n avatarDropzoneOverlay,\n avatarDropzoneOverlayIconSlot,\n avatarDropzoneRoot,\n} from '@mage-ui/styled-system/recipes';\nimport {\n IMAGE_MIME_TYPE,\n Dropzone as MantineDropzone,\n} from '@mantine/dropzone';\nimport {\n Icon,\n type IconProps,\n LoaderOval,\n type LoaderOvalProps,\n} from '@/components/data-display';\n\nimport {\n type S3InitBody,\n type S3UploadConfig,\n useS3Upload,\n} from '../use-s3-upload';\n\nexport type AvatarDropzoneS3Props<TInitBody extends S3InitBody = S3InitBody> =\n S3UploadConfig<TInitBody> & {\n value?: string;\n onChange?: (url: string) => void;\n onError?: (message: string) => void;\n maxSize?: number;\n classNames?: {\n dropzone?: string;\n root?: string;\n inner?: string;\n image?: string;\n overlay?: string;\n overlayIconSlot?: string;\n iconSlot?: string;\n icon?: IconProps['classNames'];\n loader?: LoaderOvalProps['classNames'];\n };\n };\n\nexport const AvatarDropzoneS3 = <TInitBody extends S3InitBody = S3InitBody>({\n value,\n onChange,\n onError,\n maxSize,\n classNames,\n initUrl,\n buildInitBody,\n register,\n getHeaders,\n getErrorMessage,\n resolveUploadedUrl,\n acceptedTypes,\n texts,\n}: AvatarDropzoneS3Props<TInitBody>) => {\n const [preview, setPreview] = useState<string | null>(value ?? null);\n const { upload, isUploading } = useS3Upload<TInitBody>({\n initUrl,\n buildInitBody,\n register,\n getHeaders,\n getErrorMessage,\n resolveUploadedUrl,\n acceptedTypes,\n texts,\n });\n\n const handleDrop = useCallback(\n async (files: File[]) => {\n const file = files[0];\n if (!file) return;\n setPreview(URL.createObjectURL(file));\n try {\n const url = await upload(file);\n onChange?.(url);\n } catch (err) {\n setPreview(value ?? null);\n onError?.((err as Error).message);\n }\n },\n [upload, onChange, onError, value],\n );\n\n return (\n <MantineDropzone\n onDrop={handleDrop}\n accept={IMAGE_MIME_TYPE}\n maxFiles={1}\n maxSize={maxSize}\n loading={isUploading}\n classNames={{\n root: cx(\n classNames?.dropzone ?? avatarDropzone(),\n classNames?.root ?? avatarDropzoneRoot(),\n 'group',\n ),\n inner: classNames?.inner ?? avatarDropzoneInner(),\n }}\n >\n <MantineDropzone.Idle>\n {isUploading ? (\n <div className={classNames?.iconSlot ?? avatarDropzoneIconSlot()}>\n <LoaderOval classNames={classNames?.loader} />\n </div>\n ) : preview ? (\n <>\n <img\n src={preview}\n alt='Avatar'\n className={classNames?.image ?? avatarDropzoneImage()}\n />\n <div className={classNames?.overlay ?? avatarDropzoneOverlay()} />\n <div\n className={\n classNames?.overlayIconSlot ?? avatarDropzoneOverlayIconSlot()\n }\n >\n <Icon\n name='mage-avatar-dropzone-camera-plus'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.icon?.icon ?? avatarDropzoneIcon(),\n }}\n />\n </div>\n </>\n ) : (\n <div className={classNames?.iconSlot ?? avatarDropzoneIconSlot()}>\n <Icon\n name='mage-avatar-dropzone-camera-plus'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.icon?.icon ?? avatarDropzoneIcon(),\n }}\n />\n </div>\n )}\n </MantineDropzone.Idle>\n <MantineDropzone.Accept>\n <div className={classNames?.iconSlot ?? avatarDropzoneIconSlot()}>\n <Icon\n name='mage-dropzone-thumbs-up'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.icon?.icon ?? avatarDropzoneIcon(),\n }}\n />\n </div>\n </MantineDropzone.Accept>\n <MantineDropzone.Reject>\n <div className={classNames?.iconSlot ?? avatarDropzoneIconSlot()}>\n <Icon\n name='mage-dropzone-thumbs-down'\n path='/icons/sprite-mage.svg'\n classNames={{\n icon: classNames?.icon?.icon ?? avatarDropzoneIcon(),\n }}\n />\n </div>\n </MantineDropzone.Reject>\n </MantineDropzone>\n );\n};\n"],"mappings":"kqBAiDA,MAAa,GAA+D,CAC1E,QACA,WACA,UACA,UACA,aACA,UACA,gBACA,WACA,aACA,kBACA,qBACA,gBACA,WACsC,CACtC,GAAM,CAAC,EAAS,GAAc,EAAwB,GAAS,KAAK,CAC9D,CAAE,SAAQ,eAAgB,EAAuB,CACrD,UACA,gBACA,WACA,aACA,kBACA,qBACA,gBACA,QACD,CAAC,CAkBF,OACE,EAACA,EAAD,CACE,OAlBe,EACjB,KAAO,IAAkB,CACvB,IAAM,EAAO,EAAM,GACd,KACL,GAAW,IAAI,gBAAgB,EAAK,CAAC,CACrC,GAAI,CACF,IAAM,EAAM,MAAM,EAAO,EAAK,CAC9B,IAAW,EAAI,OACR,EAAK,CACZ,EAAW,GAAS,KAAK,CACzB,IAAW,EAAc,QAAQ,IAGrC,CAAC,EAAQ,EAAU,EAAS,EAAM,CACnC,CAKG,OAAQ,EACR,SAAU,EACD,UACT,QAAS,EACT,WAAY,CACV,KAAM,EACJ,GAAY,UAAY,GAAgB,CACxC,GAAY,MAAQ,GAAoB,CACxC,QACD,CACD,MAAO,GAAY,OAAS,GAAqB,CAClD,UAbH,CAeE,EAACA,EAAgB,KAAjB,CAAA,SACG,EACC,EAAC,MAAD,CAAK,UAAW,GAAY,UAAY,GAAwB,UAC9D,EAAC,EAAD,CAAY,WAAY,GAAY,OAAU,CAAA,CAC1C,CAAA,CACJ,EACF,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,MAAD,CACE,IAAK,EACL,IAAI,SACJ,UAAW,GAAY,OAAS,GAAqB,CACrD,CAAA,CACF,EAAC,MAAD,CAAK,UAAW,GAAY,SAAW,GAAuB,CAAI,CAAA,CAClE,EAAC,MAAD,CACE,UACE,GAAY,iBAAmB,GAA+B,UAGhE,EAAC,EAAD,CACE,KAAK,mCACL,KAAK,yBACL,WAAY,CACV,KAAM,GAAY,MAAM,MAAQ,GAAoB,CACrD,CACD,CAAA,CACE,CAAA,CACL,CAAA,CAAA,CAEH,EAAC,MAAD,CAAK,UAAW,GAAY,UAAY,GAAwB,UAC9D,EAAC,EAAD,CACE,KAAK,mCACL,KAAK,yBACL,WAAY,CACV,KAAM,GAAY,MAAM,MAAQ,GAAoB,CACrD,CACD,CAAA,CACE,CAAA,CAEa,CAAA,CACvB,EAACA,EAAgB,OAAjB,CAAA,SACE,EAAC,MAAD,CAAK,UAAW,GAAY,UAAY,GAAwB,UAC9D,EAAC,EAAD,CACE,KAAK,0BACL,KAAK,yBACL,WAAY,CACV,KAAM,GAAY,MAAM,MAAQ,GAAoB,CACrD,CACD,CAAA,CACE,CAAA,CACiB,CAAA,CACzB,EAACA,EAAgB,OAAjB,CAAA,SACE,EAAC,MAAD,CAAK,UAAW,GAAY,UAAY,GAAwB,UAC9D,EAAC,EAAD,CACE,KAAK,4BACL,KAAK,yBACL,WAAY,CACV,KAAM,GAAY,MAAM,MAAQ,GAAoB,CACrD,CACD,CAAA,CACE,CAAA,CACiB,CAAA,CACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-dropzone-state.mjs","names":[],"sources":["../../../../src/components/controls/dropzone/use-dropzone-state.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nimport type { FileData } from './Dropzone';\nimport {\n type Uploader,\n type UploadProgress,\n uploadFile,\n} from './upload-service';\n\nexport const useDropzoneState = (\n url: string | undefined,\n initialFiles: Record<string, FileData> | FileData | null | undefined = {},\n onFileUploaded?: (file: FileData) => void,\n headers?: Record<string, string>,\n uploader?: Uploader,\n) => {\n const normalizeInitialFiles = (): Record<string, FileData> => {\n if (!initialFiles) return {};\n\n if (typeof initialFiles === 'object' && !('name' in initialFiles)) {\n return initialFiles;\n }\n\n if (typeof initialFiles === 'object' && 'name' in initialFiles) {\n const fileData = initialFiles as FileData;\n return {\n [fileData.name]: {\n name: fileData.name,\n size: fileData.size,\n type: fileData.type,\n date: fileData.date,\n uploaded: fileData.uploaded ?? true,\n loading: fileData.loading ?? false,\n url: fileData.url,\n error: fileData.error,\n progress: fileData.progress,\n },\n };\n }\n\n return {};\n };\n\n const [files, setFiles] = useState<Record<string, FileData>>(\n normalizeInitialFiles(),\n );\n const [isUploading, setIsUploading] = useState(false);\n const uploadQueue = useRef<Set<string>>(new Set());\n\n const addFile = useCallback((file: File, date?: string) => {\n const fileData: FileData = {\n name: file.name,\n size: file.size,\n type: file.type,\n url: '',\n uploaded: false,\n loading: false,\n progress: 0,\n date:\n date ??\n new Date().toLocaleString('es-ES', {\n timeZone: 'Europe/Madrid',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n }),\n };\n\n setFiles((prev) => ({\n ...prev,\n [file.name]: fileData,\n }));\n\n return file.name;\n }, []);\n\n const updateFileProgress = useCallback(\n (fileName: string, progress: number) => {\n setFiles((prev) => ({\n ...prev,\n [fileName]: {\n ...prev[fileName],\n progress,\n loading: progress < 100,\n },\n }));\n },\n [],\n );\n\n const markFileAsUploaded = useCallback((fileName: string, url: string) => {\n setFiles((prev) => ({\n ...prev,\n [fileName]: {\n ...prev[fileName],\n uploaded: true,\n loading: false,\n progress: 100,\n url,\n },\n }));\n }, []);\n\n const markFileAsError = useCallback((fileName: string, error: string) => {\n setFiles((prev) => ({\n ...prev,\n [fileName]: {\n ...prev[fileName],\n uploaded: false,\n loading: false,\n progress: 0,\n error,\n },\n }));\n }, []);\n\n const removeFile = useCallback((fileName: string) => {\n setFiles((prev) => {\n const newFiles = { ...prev };\n delete newFiles[fileName];\n return newFiles;\n });\n uploadQueue.current.delete(fileName);\n }, []);\n\n const clearFiles = useCallback(() => {\n setFiles({});\n uploadQueue.current.clear();\n }, []);\n\n const isFileUploading = useCallback((fileName: string) => {\n return uploadQueue.current.has(fileName);\n }, []);\n\n const addToUploadQueue = useCallback((fileName: string) => {\n uploadQueue.current.add(fileName);\n }, []);\n\n const removeFromUploadQueue = useCallback((fileName: string) => {\n uploadQueue.current.delete(fileName);\n }, []);\n\n const uploadFileToServer = useCallback(\n async (file: File, data?: Record<string, unknown>) => {\n const date = new Date().toLocaleString('es-ES', {\n timeZone: 'Europe/Madrid',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n const fileName = addFile(file, date);\n addToUploadQueue(fileName);\n\n try {\n const onProgress = (progress: UploadProgress) => {\n updateFileProgress(fileName, progress.percentage);\n };\n const { body } = uploader\n ? await uploader(file, { data, onProgress, headers })\n : await uploadFile(url ?? '', file, data, onProgress, headers);\n\n markFileAsUploaded(fileName, body.url);\n onFileUploaded?.({\n name: file.name,\n size: file.size,\n type: file.type,\n date,\n uploaded: true,\n loading: false,\n progress: 100,\n url: body.url,\n });\n } catch (error) {\n console.error('Error al subir archivo:', error);\n markFileAsError(\n fileName,\n error instanceof Error ? error.message : 'Error desconocido',\n );\n } finally {\n removeFromUploadQueue(fileName);\n }\n },\n [\n addFile,\n addToUploadQueue,\n updateFileProgress,\n markFileAsUploaded,\n markFileAsError,\n removeFromUploadQueue,\n onFileUploaded,\n url,\n headers,\n uploader,\n ],\n );\n\n const uploadMultipleFiles = useCallback(\n async (acceptedFiles: File[], data?: Record<string, unknown>) => {\n if (isUploading) {\n console.warn('Ya hay una subida en progreso');\n return;\n }\n\n setIsUploading(true);\n\n try {\n for (const file of acceptedFiles) {\n await uploadFileToServer(file, data);\n }\n } finally {\n setIsUploading(false);\n }\n },\n [isUploading, setIsUploading, uploadFileToServer],\n );\n\n return {\n files,\n isUploading,\n setIsUploading,\n addFile,\n updateFileProgress,\n markFileAsUploaded,\n markFileAsError,\n removeFile,\n clearFiles,\n isFileUploading,\n addToUploadQueue,\n removeFromUploadQueue,\n uploadFileToServer,\n uploadMultipleFiles,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-dropzone-state.mjs","names":[],"sources":["../../../../src/components/controls/dropzone/use-dropzone-state.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nimport type { FileData } from './DropzoneBase';\nimport {\n type Uploader,\n type UploadProgress,\n uploadFile,\n} from './upload-service';\n\nexport const useDropzoneState = (\n url: string | undefined,\n initialFiles: Record<string, FileData> | FileData | null | undefined = {},\n onFileUploaded?: (file: FileData) => void,\n headers?: Record<string, string>,\n uploader?: Uploader,\n) => {\n const normalizeInitialFiles = (): Record<string, FileData> => {\n if (!initialFiles) return {};\n\n if (typeof initialFiles === 'object' && !('name' in initialFiles)) {\n return initialFiles;\n }\n\n if (typeof initialFiles === 'object' && 'name' in initialFiles) {\n const fileData = initialFiles as FileData;\n return {\n [fileData.name]: {\n name: fileData.name,\n size: fileData.size,\n type: fileData.type,\n date: fileData.date,\n uploaded: fileData.uploaded ?? true,\n loading: fileData.loading ?? false,\n url: fileData.url,\n error: fileData.error,\n progress: fileData.progress,\n },\n };\n }\n\n return {};\n };\n\n const [files, setFiles] = useState<Record<string, FileData>>(\n normalizeInitialFiles(),\n );\n const [isUploading, setIsUploading] = useState(false);\n const uploadQueue = useRef<Set<string>>(new Set());\n\n const addFile = useCallback((file: File, date?: string) => {\n const fileData: FileData = {\n name: file.name,\n size: file.size,\n type: file.type,\n url: '',\n uploaded: false,\n loading: false,\n progress: 0,\n date:\n date ??\n new Date().toLocaleString('es-ES', {\n timeZone: 'Europe/Madrid',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n }),\n };\n\n setFiles((prev) => ({\n ...prev,\n [file.name]: fileData,\n }));\n\n return file.name;\n }, []);\n\n const updateFileProgress = useCallback(\n (fileName: string, progress: number) => {\n setFiles((prev) => ({\n ...prev,\n [fileName]: {\n ...prev[fileName],\n progress,\n loading: progress < 100,\n },\n }));\n },\n [],\n );\n\n const markFileAsUploaded = useCallback((fileName: string, url: string) => {\n setFiles((prev) => ({\n ...prev,\n [fileName]: {\n ...prev[fileName],\n uploaded: true,\n loading: false,\n progress: 100,\n url,\n },\n }));\n }, []);\n\n const markFileAsError = useCallback((fileName: string, error: string) => {\n setFiles((prev) => ({\n ...prev,\n [fileName]: {\n ...prev[fileName],\n uploaded: false,\n loading: false,\n progress: 0,\n error,\n },\n }));\n }, []);\n\n const removeFile = useCallback((fileName: string) => {\n setFiles((prev) => {\n const newFiles = { ...prev };\n delete newFiles[fileName];\n return newFiles;\n });\n uploadQueue.current.delete(fileName);\n }, []);\n\n const clearFiles = useCallback(() => {\n setFiles({});\n uploadQueue.current.clear();\n }, []);\n\n const isFileUploading = useCallback((fileName: string) => {\n return uploadQueue.current.has(fileName);\n }, []);\n\n const addToUploadQueue = useCallback((fileName: string) => {\n uploadQueue.current.add(fileName);\n }, []);\n\n const removeFromUploadQueue = useCallback((fileName: string) => {\n uploadQueue.current.delete(fileName);\n }, []);\n\n const uploadFileToServer = useCallback(\n async (file: File, data?: Record<string, unknown>) => {\n const date = new Date().toLocaleString('es-ES', {\n timeZone: 'Europe/Madrid',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n const fileName = addFile(file, date);\n addToUploadQueue(fileName);\n\n try {\n const onProgress = (progress: UploadProgress) => {\n updateFileProgress(fileName, progress.percentage);\n };\n const { body } = uploader\n ? await uploader(file, { data, onProgress, headers })\n : await uploadFile(url ?? '', file, data, onProgress, headers);\n\n markFileAsUploaded(fileName, body.url);\n onFileUploaded?.({\n name: file.name,\n size: file.size,\n type: file.type,\n date,\n uploaded: true,\n loading: false,\n progress: 100,\n url: body.url,\n });\n } catch (error) {\n console.error('Error al subir archivo:', error);\n markFileAsError(\n fileName,\n error instanceof Error ? error.message : 'Error desconocido',\n );\n } finally {\n removeFromUploadQueue(fileName);\n }\n },\n [\n addFile,\n addToUploadQueue,\n updateFileProgress,\n markFileAsUploaded,\n markFileAsError,\n removeFromUploadQueue,\n onFileUploaded,\n url,\n headers,\n uploader,\n ],\n );\n\n const uploadMultipleFiles = useCallback(\n async (acceptedFiles: File[], data?: Record<string, unknown>) => {\n if (isUploading) {\n console.warn('Ya hay una subida en progreso');\n return;\n }\n\n setIsUploading(true);\n\n try {\n for (const file of acceptedFiles) {\n await uploadFileToServer(file, data);\n }\n } finally {\n setIsUploading(false);\n }\n },\n [isUploading, setIsUploading, uploadFileToServer],\n );\n\n return {\n files,\n isUploading,\n setIsUploading,\n addFile,\n updateFileProgress,\n markFileAsUploaded,\n markFileAsError,\n removeFile,\n clearFiles,\n isFileUploading,\n addToUploadQueue,\n removeFromUploadQueue,\n uploadFileToServer,\n uploadMultipleFiles,\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { ReactNode } from "react";
2
+
3
+ //#region src/components/controls/dropzone/use-s3-upload.d.ts
4
+ type S3InitBody = {
5
+ url: string;
6
+ headers?: Record<string, string | string[]>;
7
+ } & Record<string, unknown>;
8
+ type S3InitResponse<TBody extends S3InitBody = S3InitBody> = {
9
+ body: TBody;
10
+ };
11
+ /** Metadata derived from the file that body builders frequently need. */
12
+ type S3FileMeta = {
13
+ /**
14
+ * Best-effort MIME type. When `acceptedTypes` is provided and the
15
+ * browser-reported `file.type` is empty or unknown, this falls back to
16
+ * the MIME mapped from the file extension.
17
+ */
18
+ mimeType: string; /** Lowercase file extension without the leading dot. */
19
+ extension: string;
20
+ };
21
+ /** All replaceable UI and error strings surfaced by S3 upload components. */
22
+ type DropzoneS3Texts = {
23
+ /** Main dropzone heading. */title?: ReactNode; /** Secondary dropzone text. */
24
+ subtitle?: ReactNode; /** Small helper text below the subtitle. */
25
+ hint?: ReactNode; /** Fallback shown when the init request fails without a parseable body. */
26
+ initFailed?: (status: number) => string; /** Fallback shown when the register request fails without a parseable body. */
27
+ registerFailed?: (status: number) => string; /** Error when the S3 PUT returns a non-2xx status. */
28
+ uploadFailed?: (status: number, statusText: string) => string; /** Error when the network fails during the PUT. */
29
+ networkError?: string; /** Error when the PUT is aborted. */
30
+ uploadAborted?: string; /** Error when the PUT times out. */
31
+ uploadTimedOut?: string;
32
+ };
33
+ /** Lowercase extension without leading dot, or empty string. */
34
+ declare const getFileExtension: (filename: string) => string;
35
+ type S3UploadConfig<TInitBody extends S3InitBody = S3InitBody> = {
36
+ /** POST endpoint that returns `{ body: { url, headers?, ...extras } }`. */initUrl: string; /** Build the init request JSON body from the file and resolved meta. */
37
+ buildInitBody: (file: File, meta: S3FileMeta) => Record<string, unknown>;
38
+ /**
39
+ * Optional post-upload registration step. When set, a POST is sent to
40
+ * `register.url` with the body produced by `register.buildBody`.
41
+ */
42
+ register?: {
43
+ url: string;
44
+ buildBody: (file: File, init: TInitBody, meta: S3FileMeta) => Record<string, unknown>;
45
+ };
46
+ /**
47
+ * Called on every outbound request (init, register). Use it to supply
48
+ * auth/CSRF headers that may rotate during the session.
49
+ */
50
+ getHeaders?: () => Record<string, string>;
51
+ /**
52
+ * Customize how an error response is turned into a human-readable
53
+ * message. Defaults to common Laravel-style error shapes.
54
+ */
55
+ getErrorMessage?: (res: Response, fallback: string) => Promise<string>;
56
+ /**
57
+ * URL stored after a successful upload. Defaults to `init.body.key`
58
+ * when present, falling back to the presigned URL stripped of its query string.
59
+ */
60
+ resolveUploadedUrl?: (init: TInitBody, file: File) => string;
61
+ /**
62
+ * Map of file extension → MIME type used to resolve `meta.mimeType`
63
+ * and build the `accept` map for the dropzone.
64
+ */
65
+ acceptedTypes?: Record<string, string>; /** All replaceable UI and error strings. */
66
+ texts?: DropzoneS3Texts;
67
+ };
68
+ //#endregion
69
+ export { DropzoneS3Texts, S3FileMeta, S3InitBody, S3InitResponse, S3UploadConfig, getFileExtension };
70
+ //# sourceMappingURL=use-s3-upload.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-s3-upload.d.mts","names":[],"sources":["../../../../src/components/controls/dropzone/use-s3-upload.ts"],"mappings":";;;KAGY,UAAA;EACV,GAAA;EACA,OAAA,GAAU,MAAA;AAAA,IACR,MAAA;AAAA,KAEQ,cAAA,eAA6B,UAAA,GAAa,UAAA;EACpD,IAAA,EAAM,KAAA;AAAA;;KAII,UAAA;EAPR;;;AAEJ;;EAWE,QAAA,UAXuC;EAavC,SAAA;AAAA;;KAIU,eAAA;EAjBe,6BAmBzB,KAAA,GAAQ,SAAA,EAnB4C;EAqBpD,QAAA,GAAW,SAAA,EApBL;EAsBN,IAAA,GAAO,SAAA,EAtBI;EAwBX,UAAA,IAAc,MAAA,qBApBM;EAsBpB,cAAA,IAAkB,MAAA,qBAhBlB;EAkBA,YAAA,IAAgB,MAAA,UAAgB,UAAA,qBAZtB;EAcV,YAAA;EAEA,aAAA,WAZW;EAcX,cAAA;AAAA;;cAuEW,gBAAA,GAAoB,QAAA;AAAA,KA8DrB,cAAA,mBAAiC,UAAA,GAAa,UAAA;EA3IxD,2EA6IA,OAAA,UA7IgC;EA+IhC,aAAA,GAAgB,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,UAAA,KAAe,MAAA;EA3IjD;;;;EAgJA,QAAA;IACE,GAAA;IACA,SAAA,GACE,IAAA,EAAM,IAAA,EACN,IAAA,EAAM,SAAA,EACN,IAAA,EAAM,UAAA,KACH,MAAA;EAAA;EA7EwC;AA8DjD;;;EAqBE,UAAA,SAAmB,MAAA;EArBqC;;;;EA0BxD,eAAA,IAAmB,GAAA,EAAK,QAAA,EAAU,QAAA,aAAqB,OAAA;EAb7C;;;;EAkBV,kBAAA,IAAsB,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,IAAA;EALU;;;;EAUvD,aAAA,GAAgB,MAAA,kBAEO;EAAvB,KAAA,GAAQ,eAAA;AAAA"}