@yunuenm23/react-file-uploader 0.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/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/fileuploader.d.ts +2 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +481 -0
- package/dist/react-file-uploader.css +1 -0
- package/dist/src/FileUploader.d.ts +3 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/types.d.ts +79 -0
- package/dist/src/useFileUploader.d.ts +17 -0
- package/dist/src/utils.d.ts +27 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yun
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# ReactFileUploader
|
|
2
|
+
|
|
3
|
+
Reusable React file uploader component without Ant Design or Next.js dependencies.
|
|
4
|
+
|
|
5
|
+
## Install locally
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run build
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Local documentation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm run dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Open `http://127.0.0.1:5173/`.
|
|
19
|
+
|
|
20
|
+
## Publish package
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm login
|
|
24
|
+
npm run typecheck
|
|
25
|
+
npm run build
|
|
26
|
+
npm publish --access public
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Deploy docs
|
|
30
|
+
|
|
31
|
+
Vercel:
|
|
32
|
+
|
|
33
|
+
- Build command: `npm run build:docs`
|
|
34
|
+
- Output directory: `docs-dist`
|
|
35
|
+
|
|
36
|
+
GitHub Pages:
|
|
37
|
+
|
|
38
|
+
- Push to `main`.
|
|
39
|
+
- Enable Pages with GitHub Actions as the source.
|
|
40
|
+
- The included workflow deploys `docs-dist`.
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { ReactFileUploader } from "@yunuenm23/react-file-uploader";
|
|
46
|
+
import "@yunuenm23/react-file-uploader/styles.css";
|
|
47
|
+
|
|
48
|
+
export function Example() {
|
|
49
|
+
return (
|
|
50
|
+
<ReactFileUploader
|
|
51
|
+
acceptFiles={["image/*", "video/*", "audio/*", "application/pdf"]}
|
|
52
|
+
maxFiles={3}
|
|
53
|
+
maxSizeFile={2}
|
|
54
|
+
multipleFiles
|
|
55
|
+
theme={{
|
|
56
|
+
accent: "#7c3aed",
|
|
57
|
+
accentSoft: "#ede9fe",
|
|
58
|
+
success: "#059669",
|
|
59
|
+
danger: "#e11d48",
|
|
60
|
+
}}
|
|
61
|
+
onFilesSelected={(files) => {
|
|
62
|
+
console.log(files);
|
|
63
|
+
}}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Main props
|
|
70
|
+
|
|
71
|
+
- `acceptFiles`: MIME types or extensions, for example `["image/*", "video/*", "audio/*", ".pdf"]`.
|
|
72
|
+
- `maxSizeFile`: max size in MB.
|
|
73
|
+
- `multipleFiles`: enables multi-file selection.
|
|
74
|
+
- `maxFiles`: approved file limit.
|
|
75
|
+
- `validateDimensions`: validates image width and height.
|
|
76
|
+
- `dimensions`: max image dimensions.
|
|
77
|
+
- `onFilesSelected`: receives one `File` or a `File[]`.
|
|
78
|
+
- `onFilesChange`: receives the full validated item list.
|
|
79
|
+
- `labels`: overrides the visible copy.
|
|
80
|
+
- `theme`: overrides the default colors.
|
|
81
|
+
|
|
82
|
+
Images, videos, and audio files render compact clickable thumbnails that open a larger preview. Document-like files render as downloadable items. The package also exports `useFileUploader` if you want to build a fully custom UI with the same validation logic.
|
|
83
|
+
|
|
84
|
+
You can theme the component with the `theme` prop or by overriding CSS variables such as `--file-uploader-accent`, `--file-uploader-surface`, and `--file-uploader-border`.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const a=require("react/jsx-runtime"),n=require("react"),z=["png","webp","jpeg","jpg","svg"],Z=["mp3","wav","ogg","mpeg","aac","flac"],G=["mp4","webm","ogg","mov","quicktime"],ee={audio:"MP3, WAV, OGG, AAC, FLAC",image:"PNG, JPG, JPEG, WEBP, SVG",video:"MP4, WEBM, OGG, MOV"},O=(e,s=" ")=>{const l=["Bytes","KB","MB","GB","TB"];if(e===0)return"n/a";const r=Math.floor(Math.log(e)/Math.log(1024));return`${r===0?e:(e/1024**r).toFixed(1)}${s}${l[r]}`},D=e=>{var r,o;const s=(r=e.name.split(".").pop())==null?void 0:r.toLowerCase();return((o=e.type.split("/")[1])==null?void 0:o.toLowerCase())||s||""},H=e=>e.map(s=>{const[l,r]=s.split("/");return r?r==="*"?ee[l]??`Cualquier ${l}`:r.toUpperCase():s.replace(".","").toUpperCase()}),N=e=>{const s=D(e);return e.type.startsWith("image/")||z.includes(s)},R=e=>{const s=D(e);return e.type.startsWith("audio/")||Z.includes(s)},T=e=>{const s=D(e);return e.type.startsWith("video/")||G.includes(s)},B=e=>N(e)||R(e)||T(e),W=e=>!B(e),q=(e,s)=>{if(s.length===0)return!0;const l=D(e);return s.some(r=>{const o=r.trim().toLowerCase();return o.startsWith(".")?o.slice(1)===l:o.endsWith("/*")?e.type.startsWith(o.replace("*","")):e.type.toLowerCase()===o||l===o})},ae=(e,s)=>new Promise(l=>{const r=URL.createObjectURL(e),o=new window.Image;o.onload=()=>{URL.revokeObjectURL(r),l(o.width<=s.width&&o.height<=s.height)},o.onerror=()=>{URL.revokeObjectURL(r),l(!1)},o.src=r}),P=async(e,s)=>{const l=[],r=s.maxSizeFile>0?s.maxSizeFile*1024*1024:0;r>0&&e.size>r&&l.push("file-size"),q(e,s.acceptFiles)||l.push("file-type"),s.validateDimensions&&N(e)&&(await ae(e,s.dimensions)||l.push("image-dimensions"));const o=l.length===0;return{id:`${e.name}-${e.size}-${e.lastModified}-${crypto.randomUUID()}`,file:e,status:o?"approved":"rejected",approve:o,reasons:l,previewUrl:B(e)?URL.createObjectURL(e):void 0}},S=e=>{e.forEach(s=>{s.previewUrl&&URL.revokeObjectURL(s.previewUrl)})},se=[],re={width:0,height:0},le=[],ie=e=>"dataTransfer"in e?Array.from(e.dataTransfer.files):Array.from(e.target.files??[]),J=({acceptFiles:e=se,dimensions:s=re,maxFiles:l=1,maxSizeFile:r=0,multipleFiles:o=!1,updateFiles:b=le,validateDimensions:g=!1,onFilesChange:m,onFilesSelected:v})=>{const x=n.useRef(null),U=n.useRef([]),[h,k]=n.useState([]),[y,L]=n.useState(!1),w=n.useMemo(()=>h.filter(d=>d.approve),[h]),C=n.useMemo(()=>H(e),[e]),u=o?w.length<l:h.length===0,j=n.useCallback(()=>{x.current&&(x.current.value="")},[]),c=n.useCallback(d=>{const f=d.filter(_=>_.approve).map(_=>_.file);if(m==null||m(d),o){v==null||v(f);return}f[0]&&(v==null||v(f[0]))},[o,m,v]),p=n.useCallback(d=>{k(f=>{const _=d(f),M=f.filter(E=>!_.some(Y=>Y.id===E.id));return S(M),U.current=_,_})},[]),t=n.useCallback(async d=>{d.preventDefault(),L(!1);const f=ie(d),_=await Promise.all(f.map(E=>P(E,{acceptFiles:e,dimensions:s,maxSizeFile:r,validateDimensions:g}))),M=o?[...h,..._.filter(E=>E.approve).slice(0,Math.max(l-w.length,0))]:_.slice(0,1);p(()=>M),c(M),j()},[e,w.length,j,s,c,h,l,r,o,p,g]),i=n.useCallback(d=>{const f=h.filter(_=>_.id!==d.id);p(()=>f),c(f),j()},[j,c,h,p]),A=n.useCallback(()=>{p(()=>[]),j(),m==null||m([])},[j,m,p]),I=n.useCallback(()=>{var d;(d=x.current)==null||d.click()},[]),K=n.useCallback(d=>{d.preventDefault(),L(!0)},[]),Q=n.useCallback(d=>{d.preventDefault(),L(!1)},[]),X=n.useCallback(d=>{if(u){t(d);return}d.preventDefault(),L(!1)},[u,t]);return n.useEffect(()=>{if(b.length===0)return;let d=!1;return Promise.all(b.map(f=>P(f,{acceptFiles:e,dimensions:s,maxSizeFile:r,validateDimensions:g}))).then(f=>{d||p(()=>f)}),()=>{d=!0}},[e,s,r,p,b,g]),n.useEffect(()=>{U.current=h},[h]),n.useEffect(()=>()=>{S(U.current)},[]),{acceptedFormats:C,approvedItems:w,canAddFiles:u,clear:A,handleFiles:t,inputRef:x,isDragging:y,items:h,onDragLeave:Q,onDragOver:K,onDrop:X,open:I,removeFile:i}},oe=[],te={width:0,height:0},ce=[],ne={idleTitle:a.jsxs(a.Fragment,{children:[a.jsx("span",{children:"Arrastra y suelta"})," tus archivos aqui"]}),idleHint:"Selecciona archivos desde tu equipo.",browseFile:"Buscar archivo",browseFiles:"Buscar archivos",limitReached:"Limite de archivos alcanzado",maxSize:e=>`Limite de ${e}MB por archivo.`,allowedFormats:e=>a.jsxs(a.Fragment,{children:["Archivos permitidos: ",a.jsx("span",{className:"file-uploader__format",children:e.join(", ")})]}),imageDimensions:(e,s)=>`Dimensiones de imagen: ${e}x${s}`,selectedCount:(e,s)=>`${e} / ${s} ${e===1?"archivo seleccionado":"archivos seleccionados"}`,removeFile:"Eliminar archivo",downloadFile:"Descargar archivo",previewFile:"Vista previa del archivo",closePreview:"Cerrar vista previa"},de=e=>{if(!e)return;const s={"--file-uploader-accent":e.accent,"--file-uploader-accent-soft":e.accentSoft,"--file-uploader-border":e.border,"--file-uploader-danger":e.danger,"--file-uploader-ink":e.ink,"--file-uploader-muted":e.muted,"--file-uploader-success":e.success,"--file-uploader-surface":e.surface,"--file-uploader-item-surface":e.itemSurface,"--file-uploader-modal-backdrop":e.modalBackdrop,"--file-uploader-modal-surface":e.modalSurface};return Object.keys(s).forEach(l=>{const r=l;s[r]===void 0&&delete s[r]}),s},ue=()=>a.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 640 512",children:a.jsx("path",{d:"M144 480C64.5 480 0 415.5 0 336c0-62.8 40.2-116.2 96.2-135.9C96.1 197.4 96 194.7 96 192c0-88.4 71.6-160 160-160c59.3 0 111 32.2 138.7 80.2C409.9 102 428.3 96 448 96c53 0 96 43 96 96c0 12.2-2.3 23.8-6.4 34.6C596 238.4 640 290.1 640 352c0 70.7-57.3 128-128 128H144Zm79-217c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l39-39V392c0 13.3 10.7 24 24 24s24-10.7 24-24V257.9l39 39c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-80-80c-9.4-9.4-24.6-9.4-33.9 0l-80 80Z"})}),pe=()=>a.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 384 512",children:a.jsx("path",{d:"M0 64C0 28.7 28.7 0 64 0h160v128c0 17.7 14.3 32 32 32h128v288c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64Zm384 64H256V0l128 128Z"})}),$=({approved:e})=>a.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 512 512",children:e?a.jsx("path",{d:"M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512Zm113-303L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9Z"}):a.jsx("path",{d:"M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512ZM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9Z"})}),fe=()=>a.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 512 512",children:a.jsx("path",{d:"M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32v242.7l-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7V32ZM64 352c-35.3 0-64 28.7-64 64v32c0 35.3 28.7 64 64 64h384c35.3 0 64-28.7 64-64v-32c0-35.3-28.7-64-64-64H346.5l-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352H64Z"})}),me=()=>a.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 384 512",children:a.jsx("path",{d:"M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80v352c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9l288-176c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39Z"})}),V=()=>a.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 512 512",children:a.jsx("path",{d:"M499.1 6.3c8.1 6 12.9 15.6 12.9 25.7v320c0 53-43 96-96 96s-96-43-96-96s43-96 96-96c11.2 0 22 1.9 32 5.5V111.9L192 160v224c0 53-43 96-96 96S0 437 0 384s43-96 96-96c11.2 0 22 1.9 32 5.5V128c0-15.4 10.9-28.6 26.1-31.5l320-60c9.9-1.9 20.1 .4 28.2 6.4Z"})}),ve=()=>a.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 384 512",children:a.jsx("path",{d:"M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6Z"})}),he=()=>a.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 448 512",children:a.jsx("path",{d:"m135.2 17.7L128 32H32C14.3 32 0 46.3 0 64s14.3 32 32 32h384c17.7 0 32-14.3 32-32s-14.3-32-32-32h-96l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7ZM416 128H32l21.2 339c1.6 25.3 22.6 45 47.9 45h245.8c25.3 0 46.3-19.7 47.9-45L416 128Z"})}),_e=e=>{const s=URL.createObjectURL(e),l=document.createElement("a");l.href=s,l.download=e.name||"archivo_descarga",document.body.appendChild(l),l.click(),document.body.removeChild(l),URL.revokeObjectURL(s)},F=n.forwardRef(({acceptFiles:e=oe,className:s="",dimensions:l=te,disabled:r=!1,fieldName:o="file-uploader",labels:b,maxFiles:g=1,maxSizeFile:m=0,multipleFiles:v=!1,onDeleteFiles:x,onFilesChange:U,onFilesSelected:h,showDownloadButton:k=!0,theme:y,updateFiles:L=ce,validateDimensions:w=!1},C)=>{const u={...ne,...b},j=de(y),[c,p]=n.useState(null),t=J({acceptFiles:e,dimensions:l,maxFiles:g,maxSizeFile:m,multipleFiles:v,onFilesChange:U,onFilesSelected:h,updateFiles:L,validateDimensions:w});return n.useImperativeHandle(C,()=>({clear:t.clear,open:t.open,files:()=>t.items}),[t.clear,t.items,t.open]),n.useEffect(()=>{if(!c)return;const i=A=>{A.key==="Escape"&&p(null)};return document.addEventListener("keydown",i),()=>document.removeEventListener("keydown",i)},[c]),n.useEffect(()=>{c&&!t.items.some(i=>i.id===c.id)&&p(null)},[c,t.items]),a.jsxs("section",{className:`file-uploader ${s}`.trim(),style:j,children:[a.jsxs("div",{className:["file-uploader__dropzone",t.items.length>0?"file-uploader__dropzone--active":"",t.isDragging?"file-uploader__dropzone--dragging":"",r?"file-uploader__dropzone--disabled":""].filter(Boolean).join(" "),onDrop:r?void 0:t.onDrop,onDragOver:r?void 0:t.onDragOver,onDragLeave:r?void 0:t.onDragLeave,children:[a.jsx("div",{className:"file-uploader__info",children:t.canAddFiles?a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"file-uploader__main-icon",children:a.jsx(ue,{})}),a.jsxs("div",{children:[a.jsx("p",{className:"file-uploader__title",children:u.idleTitle}),a.jsx("p",{className:"file-uploader__hint",children:u.idleHint}),m>0&&a.jsx("p",{children:u.maxSize(m)}),e.length>0&&a.jsx("p",{children:u.allowedFormats(t.acceptedFormats)}),w&&a.jsx("p",{children:u.imageDimensions(l.width,l.height)})]})]}):a.jsxs("div",{children:[a.jsx("span",{className:"file-uploader__success-mark",children:a.jsx($,{approved:!0})}),a.jsx("p",{className:"file-uploader__title",children:u.limitReached})]})}),a.jsx("input",{ref:t.inputRef,type:"file",id:o,name:o,className:"file-uploader__input",onChange:t.handleFiles,accept:e.join(","),multiple:v,disabled:r}),t.canAddFiles&&a.jsx("button",{type:"button",className:"file-uploader__browse",onClick:t.open,disabled:r,children:v?u.browseFiles:u.browseFile}),t.items.length>0&&a.jsx("div",{className:"file-uploader__list",children:t.items.map(i=>{const A=k&&i.approve&&W(i.file);return a.jsx(n.Fragment,{children:a.jsxs("div",{className:["file-uploader__item",i.approve?"file-uploader__item--success":"file-uploader__item--failed"].join(" "),children:[a.jsx("span",{className:"file-uploader__status",children:a.jsx($,{approved:i.approve})}),i.previewUrl&&a.jsxs("button",{type:"button",className:"file-uploader__preview-trigger",onClick:()=>p(i),"aria-label":`${u.previewFile}: ${i.file.name}`,title:u.previewFile,children:[N(i.file)&&a.jsx("img",{className:"file-uploader__thumbnail file-uploader__thumbnail--image",src:i.previewUrl,alt:""}),T(i.file)&&a.jsxs(a.Fragment,{children:[a.jsx("video",{className:"file-uploader__thumbnail file-uploader__thumbnail--video",src:i.previewUrl,preload:"metadata",muted:!0}),a.jsx("span",{className:"file-uploader__preview-badge",children:a.jsx(me,{})})]}),R(i.file)&&a.jsx("span",{className:"file-uploader__media-placeholder",children:a.jsx(V,{})})]}),!i.previewUrl&&a.jsx("span",{className:"file-uploader__file-icon",children:a.jsx(pe,{})}),a.jsxs("div",{className:"file-uploader__file-info",children:[a.jsx("p",{className:"file-uploader__name",children:i.file.name}),a.jsx("p",{className:"file-uploader__size",children:O(i.file.size)})]}),a.jsxs("div",{className:"file-uploader__actions",children:[A&&a.jsx("button",{type:"button",className:"file-uploader__icon-button",onClick:()=>_e(i.file),"aria-label":u.downloadFile,title:u.downloadFile,children:a.jsx(fe,{})}),a.jsx("button",{type:"button",className:"file-uploader__icon-button file-uploader__icon-button--danger",onClick:()=>{(c==null?void 0:c.id)===i.id&&p(null),t.removeFile(i),x==null||x(t.items.filter(I=>I.id!==i.id&&I.approve),i)},"aria-label":u.removeFile,title:u.removeFile,children:a.jsx(he,{})})]})]})},i.id)})}),v&&a.jsx("p",{className:"file-uploader__counter",children:u.selectedCount(t.approvedItems.length,g)})]}),(c==null?void 0:c.previewUrl)&&a.jsx("div",{className:"file-uploader__modal",role:"dialog","aria-modal":"true","aria-label":`${u.previewFile}: ${c.file.name}`,onMouseDown:i=>{i.currentTarget===i.target&&p(null)},children:a.jsxs("div",{className:"file-uploader__modal-panel",children:[a.jsxs("div",{className:"file-uploader__modal-header",children:[a.jsxs("div",{children:[a.jsx("p",{className:"file-uploader__modal-title",children:c.file.name}),a.jsx("p",{className:"file-uploader__modal-meta",children:O(c.file.size)})]}),a.jsx("button",{type:"button",className:"file-uploader__icon-button",onClick:()=>p(null),"aria-label":u.closePreview,title:u.closePreview,children:a.jsx(ve,{})})]}),a.jsxs("div",{className:"file-uploader__modal-content",children:[N(c.file)&&a.jsx("img",{className:"file-uploader__modal-image",src:c.previewUrl,alt:c.file.name}),T(c.file)&&a.jsx("video",{className:"file-uploader__modal-video",src:c.previewUrl,controls:!0,preload:"metadata"}),R(c.file)&&a.jsxs("div",{className:"file-uploader__modal-audio",children:[a.jsx(V,{}),a.jsx("audio",{src:c.previewUrl,controls:!0,preload:"metadata"})]})]})]})})]})});F.displayName="ReactFileUploader";const xe=F;exports.DEFAULT_AUDIO_FORMATS=Z;exports.DEFAULT_IMAGE_FORMATS=z;exports.DEFAULT_VIDEO_FORMATS=G;exports.FileUploader=xe;exports.ReactFileUploader=F;exports.bytesToSize=O;exports.default=F;exports.getFileExtension=D;exports.getReadableAcceptedFormats=H;exports.isAudioFile=R;exports.isDocumentFile=W;exports.isImageFile=N;exports.isPreviewableFile=B;exports.isVideoFile=T;exports.matchesAcceptedType=q;exports.useFileUploader=J;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import { jsxs as p, jsx as r, Fragment as T } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as j, useState as B, useMemo as F, useCallback as g, useEffect as M, forwardRef as Y, useImperativeHandle as ee, Fragment as re } from "react";
|
|
3
|
+
const ae = ["png", "webp", "jpeg", "jpg", "svg"], le = ["mp3", "wav", "ogg", "mpeg", "aac", "flac"], oe = ["mp4", "webm", "ogg", "mov", "quicktime"], ie = {
|
|
4
|
+
audio: "MP3, WAV, OGG, AAC, FLAC",
|
|
5
|
+
image: "PNG, JPG, JPEG, WEBP, SVG",
|
|
6
|
+
video: "MP4, WEBM, OGG, MOV"
|
|
7
|
+
}, z = (e, a = " ") => {
|
|
8
|
+
const o = ["Bytes", "KB", "MB", "GB", "TB"];
|
|
9
|
+
if (e === 0)
|
|
10
|
+
return "n/a";
|
|
11
|
+
const l = Math.floor(Math.log(e) / Math.log(1024));
|
|
12
|
+
return `${l === 0 ? e : (e / 1024 ** l).toFixed(1)}${a}${o[l]}`;
|
|
13
|
+
}, x = (e) => {
|
|
14
|
+
var l, t;
|
|
15
|
+
const a = (l = e.name.split(".").pop()) == null ? void 0 : l.toLowerCase();
|
|
16
|
+
return ((t = e.type.split("/")[1]) == null ? void 0 : t.toLowerCase()) || a || "";
|
|
17
|
+
}, te = (e) => e.map((a) => {
|
|
18
|
+
const [o, l] = a.split("/");
|
|
19
|
+
return l ? l === "*" ? ie[o] ?? `Cualquier ${o}` : l.toUpperCase() : a.replace(".", "").toUpperCase();
|
|
20
|
+
}), k = (e) => {
|
|
21
|
+
const a = x(e);
|
|
22
|
+
return e.type.startsWith("image/") || ae.includes(a);
|
|
23
|
+
}, P = (e) => {
|
|
24
|
+
const a = x(e);
|
|
25
|
+
return e.type.startsWith("audio/") || le.includes(a);
|
|
26
|
+
}, V = (e) => {
|
|
27
|
+
const a = x(e);
|
|
28
|
+
return e.type.startsWith("video/") || oe.includes(a);
|
|
29
|
+
}, W = (e) => k(e) || P(e) || V(e), ce = (e) => !W(e), ne = (e, a) => {
|
|
30
|
+
if (a.length === 0)
|
|
31
|
+
return !0;
|
|
32
|
+
const o = x(e);
|
|
33
|
+
return a.some((l) => {
|
|
34
|
+
const t = l.trim().toLowerCase();
|
|
35
|
+
return t.startsWith(".") ? t.slice(1) === o : t.endsWith("/*") ? e.type.startsWith(t.replace("*", "")) : e.type.toLowerCase() === t || o === t;
|
|
36
|
+
});
|
|
37
|
+
}, se = (e, a) => new Promise((o) => {
|
|
38
|
+
const l = URL.createObjectURL(e), t = new window.Image();
|
|
39
|
+
t.onload = () => {
|
|
40
|
+
URL.revokeObjectURL(l), o(t.width <= a.width && t.height <= a.height);
|
|
41
|
+
}, t.onerror = () => {
|
|
42
|
+
URL.revokeObjectURL(l), o(!1);
|
|
43
|
+
}, t.src = l;
|
|
44
|
+
}), Z = async (e, a) => {
|
|
45
|
+
const o = [], l = a.maxSizeFile > 0 ? a.maxSizeFile * 1024 * 1024 : 0;
|
|
46
|
+
l > 0 && e.size > l && o.push("file-size"), ne(e, a.acceptFiles) || o.push("file-type"), a.validateDimensions && k(e) && (await se(e, a.dimensions) || o.push("image-dimensions"));
|
|
47
|
+
const t = o.length === 0;
|
|
48
|
+
return {
|
|
49
|
+
id: `${e.name}-${e.size}-${e.lastModified}-${crypto.randomUUID()}`,
|
|
50
|
+
file: e,
|
|
51
|
+
status: t ? "approved" : "rejected",
|
|
52
|
+
approve: t,
|
|
53
|
+
reasons: o,
|
|
54
|
+
previewUrl: W(e) ? URL.createObjectURL(e) : void 0
|
|
55
|
+
};
|
|
56
|
+
}, S = (e) => {
|
|
57
|
+
e.forEach((a) => {
|
|
58
|
+
a.previewUrl && URL.revokeObjectURL(a.previewUrl);
|
|
59
|
+
});
|
|
60
|
+
}, de = [], pe = { width: 0, height: 0 }, ue = [], me = (e) => "dataTransfer" in e ? Array.from(e.dataTransfer.files) : Array.from(e.target.files ?? []), fe = ({
|
|
61
|
+
acceptFiles: e = de,
|
|
62
|
+
dimensions: a = pe,
|
|
63
|
+
maxFiles: o = 1,
|
|
64
|
+
maxSizeFile: l = 0,
|
|
65
|
+
multipleFiles: t = !1,
|
|
66
|
+
updateFiles: N = ue,
|
|
67
|
+
validateDimensions: U = !1,
|
|
68
|
+
onFilesChange: f,
|
|
69
|
+
onFilesSelected: h
|
|
70
|
+
}) => {
|
|
71
|
+
const w = j(null), E = j([]), [v, C] = B([]), [O, A] = B(!1), b = F(() => v.filter((s) => s.approve), [v]), $ = F(() => te(e), [e]), d = t ? b.length < o : v.length === 0, L = g(() => {
|
|
72
|
+
w.current && (w.current.value = "");
|
|
73
|
+
}, []), n = g(
|
|
74
|
+
(s) => {
|
|
75
|
+
const m = s.filter((_) => _.approve).map((_) => _.file);
|
|
76
|
+
if (f == null || f(s), t) {
|
|
77
|
+
h == null || h(m);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
m[0] && (h == null || h(m[0]));
|
|
81
|
+
},
|
|
82
|
+
[t, f, h]
|
|
83
|
+
), u = g((s) => {
|
|
84
|
+
C((m) => {
|
|
85
|
+
const _ = s(m), R = m.filter((I) => !_.some((X) => X.id === I.id));
|
|
86
|
+
return S(R), E.current = _, _;
|
|
87
|
+
});
|
|
88
|
+
}, []), c = g(
|
|
89
|
+
async (s) => {
|
|
90
|
+
s.preventDefault(), A(!1);
|
|
91
|
+
const m = me(s), _ = await Promise.all(
|
|
92
|
+
m.map(
|
|
93
|
+
(I) => Z(I, {
|
|
94
|
+
acceptFiles: e,
|
|
95
|
+
dimensions: a,
|
|
96
|
+
maxSizeFile: l,
|
|
97
|
+
validateDimensions: U
|
|
98
|
+
})
|
|
99
|
+
)
|
|
100
|
+
), R = t ? [...v, ..._.filter((I) => I.approve).slice(0, Math.max(o - b.length, 0))] : _.slice(0, 1);
|
|
101
|
+
u(() => R), n(R), L();
|
|
102
|
+
},
|
|
103
|
+
[
|
|
104
|
+
e,
|
|
105
|
+
b.length,
|
|
106
|
+
L,
|
|
107
|
+
a,
|
|
108
|
+
n,
|
|
109
|
+
v,
|
|
110
|
+
o,
|
|
111
|
+
l,
|
|
112
|
+
t,
|
|
113
|
+
u,
|
|
114
|
+
U
|
|
115
|
+
]
|
|
116
|
+
), i = g(
|
|
117
|
+
(s) => {
|
|
118
|
+
const m = v.filter((_) => _.id !== s.id);
|
|
119
|
+
u(() => m), n(m), L();
|
|
120
|
+
},
|
|
121
|
+
[L, n, v, u]
|
|
122
|
+
), D = g(() => {
|
|
123
|
+
u(() => []), L(), f == null || f([]);
|
|
124
|
+
}, [L, f, u]), y = g(() => {
|
|
125
|
+
var s;
|
|
126
|
+
(s = w.current) == null || s.click();
|
|
127
|
+
}, []), J = g((s) => {
|
|
128
|
+
s.preventDefault(), A(!0);
|
|
129
|
+
}, []), K = g((s) => {
|
|
130
|
+
s.preventDefault(), A(!1);
|
|
131
|
+
}, []), Q = g(
|
|
132
|
+
(s) => {
|
|
133
|
+
if (d) {
|
|
134
|
+
c(s);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
s.preventDefault(), A(!1);
|
|
138
|
+
},
|
|
139
|
+
[d, c]
|
|
140
|
+
);
|
|
141
|
+
return M(() => {
|
|
142
|
+
if (N.length === 0)
|
|
143
|
+
return;
|
|
144
|
+
let s = !1;
|
|
145
|
+
return Promise.all(
|
|
146
|
+
N.map(
|
|
147
|
+
(m) => Z(m, {
|
|
148
|
+
acceptFiles: e,
|
|
149
|
+
dimensions: a,
|
|
150
|
+
maxSizeFile: l,
|
|
151
|
+
validateDimensions: U
|
|
152
|
+
})
|
|
153
|
+
)
|
|
154
|
+
).then((m) => {
|
|
155
|
+
s || u(() => m);
|
|
156
|
+
}), () => {
|
|
157
|
+
s = !0;
|
|
158
|
+
};
|
|
159
|
+
}, [e, a, l, u, N, U]), M(() => {
|
|
160
|
+
E.current = v;
|
|
161
|
+
}, [v]), M(() => () => {
|
|
162
|
+
S(E.current);
|
|
163
|
+
}, []), {
|
|
164
|
+
acceptedFormats: $,
|
|
165
|
+
approvedItems: b,
|
|
166
|
+
canAddFiles: d,
|
|
167
|
+
clear: D,
|
|
168
|
+
handleFiles: c,
|
|
169
|
+
inputRef: w,
|
|
170
|
+
isDragging: O,
|
|
171
|
+
items: v,
|
|
172
|
+
onDragLeave: K,
|
|
173
|
+
onDragOver: J,
|
|
174
|
+
onDrop: Q,
|
|
175
|
+
open: y,
|
|
176
|
+
removeFile: i
|
|
177
|
+
};
|
|
178
|
+
}, he = [], ve = { width: 0, height: 0 }, _e = [], ge = {
|
|
179
|
+
idleTitle: /* @__PURE__ */ p(T, { children: [
|
|
180
|
+
/* @__PURE__ */ r("span", { children: "Arrastra y suelta" }),
|
|
181
|
+
" tus archivos aqui"
|
|
182
|
+
] }),
|
|
183
|
+
idleHint: "Selecciona archivos desde tu equipo.",
|
|
184
|
+
browseFile: "Buscar archivo",
|
|
185
|
+
browseFiles: "Buscar archivos",
|
|
186
|
+
limitReached: "Limite de archivos alcanzado",
|
|
187
|
+
maxSize: (e) => `Limite de ${e}MB por archivo.`,
|
|
188
|
+
allowedFormats: (e) => /* @__PURE__ */ p(T, { children: [
|
|
189
|
+
"Archivos permitidos: ",
|
|
190
|
+
/* @__PURE__ */ r("span", { className: "file-uploader__format", children: e.join(", ") })
|
|
191
|
+
] }),
|
|
192
|
+
imageDimensions: (e, a) => `Dimensiones de imagen: ${e}x${a}`,
|
|
193
|
+
selectedCount: (e, a) => `${e} / ${a} ${e === 1 ? "archivo seleccionado" : "archivos seleccionados"}`,
|
|
194
|
+
removeFile: "Eliminar archivo",
|
|
195
|
+
downloadFile: "Descargar archivo",
|
|
196
|
+
previewFile: "Vista previa del archivo",
|
|
197
|
+
closePreview: "Cerrar vista previa"
|
|
198
|
+
}, we = (e) => {
|
|
199
|
+
if (!e)
|
|
200
|
+
return;
|
|
201
|
+
const a = {
|
|
202
|
+
"--file-uploader-accent": e.accent,
|
|
203
|
+
"--file-uploader-accent-soft": e.accentSoft,
|
|
204
|
+
"--file-uploader-border": e.border,
|
|
205
|
+
"--file-uploader-danger": e.danger,
|
|
206
|
+
"--file-uploader-ink": e.ink,
|
|
207
|
+
"--file-uploader-muted": e.muted,
|
|
208
|
+
"--file-uploader-success": e.success,
|
|
209
|
+
"--file-uploader-surface": e.surface,
|
|
210
|
+
"--file-uploader-item-surface": e.itemSurface,
|
|
211
|
+
"--file-uploader-modal-backdrop": e.modalBackdrop,
|
|
212
|
+
"--file-uploader-modal-surface": e.modalSurface
|
|
213
|
+
};
|
|
214
|
+
return Object.keys(a).forEach((o) => {
|
|
215
|
+
const l = o;
|
|
216
|
+
a[l] === void 0 && delete a[l];
|
|
217
|
+
}), a;
|
|
218
|
+
}, Le = () => /* @__PURE__ */ r("svg", { "aria-hidden": "true", viewBox: "0 0 640 512", children: /* @__PURE__ */ r("path", { d: "M144 480C64.5 480 0 415.5 0 336c0-62.8 40.2-116.2 96.2-135.9C96.1 197.4 96 194.7 96 192c0-88.4 71.6-160 160-160c59.3 0 111 32.2 138.7 80.2C409.9 102 428.3 96 448 96c53 0 96 43 96 96c0 12.2-2.3 23.8-6.4 34.6C596 238.4 640 290.1 640 352c0 70.7-57.3 128-128 128H144Zm79-217c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l39-39V392c0 13.3 10.7 24 24 24s24-10.7 24-24V257.9l39 39c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-80-80c-9.4-9.4-24.6-9.4-33.9 0l-80 80Z" }) }), Ue = () => /* @__PURE__ */ r("svg", { "aria-hidden": "true", viewBox: "0 0 384 512", children: /* @__PURE__ */ r("path", { d: "M0 64C0 28.7 28.7 0 64 0h160v128c0 17.7 14.3 32 32 32h128v288c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64Zm384 64H256V0l128 128Z" }) }), H = ({ approved: e }) => /* @__PURE__ */ r("svg", { "aria-hidden": "true", viewBox: "0 0 512 512", children: e ? /* @__PURE__ */ r("path", { d: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512Zm113-303L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9Z" }) : /* @__PURE__ */ r("path", { d: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512ZM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9Z" }) }), be = () => /* @__PURE__ */ r("svg", { "aria-hidden": "true", viewBox: "0 0 512 512", children: /* @__PURE__ */ r("path", { d: "M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32v242.7l-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7V32ZM64 352c-35.3 0-64 28.7-64 64v32c0 35.3 28.7 64 64 64h384c35.3 0 64-28.7 64-64v-32c0-35.3-28.7-64-64-64H346.5l-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352H64Z" }) }), Ne = () => /* @__PURE__ */ r("svg", { "aria-hidden": "true", viewBox: "0 0 384 512", children: /* @__PURE__ */ r("path", { d: "M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80v352c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9l288-176c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39Z" }) }), G = () => /* @__PURE__ */ r("svg", { "aria-hidden": "true", viewBox: "0 0 512 512", children: /* @__PURE__ */ r("path", { d: "M499.1 6.3c8.1 6 12.9 15.6 12.9 25.7v320c0 53-43 96-96 96s-96-43-96-96s43-96 96-96c11.2 0 22 1.9 32 5.5V111.9L192 160v224c0 53-43 96-96 96S0 437 0 384s43-96 96-96c11.2 0 22 1.9 32 5.5V128c0-15.4 10.9-28.6 26.1-31.5l320-60c9.9-1.9 20.1 .4 28.2 6.4Z" }) }), Ae = () => /* @__PURE__ */ r("svg", { "aria-hidden": "true", viewBox: "0 0 384 512", children: /* @__PURE__ */ r("path", { d: "M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6Z" }) }), Ee = () => /* @__PURE__ */ r("svg", { "aria-hidden": "true", viewBox: "0 0 448 512", children: /* @__PURE__ */ r("path", { d: "m135.2 17.7L128 32H32C14.3 32 0 46.3 0 64s14.3 32 32 32h384c17.7 0 32-14.3 32-32s-14.3-32-32-32h-96l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7ZM416 128H32l21.2 339c1.6 25.3 22.6 45 47.9 45h245.8c25.3 0 46.3-19.7 47.9-45L416 128Z" }) }), De = (e) => {
|
|
219
|
+
const a = URL.createObjectURL(e), o = document.createElement("a");
|
|
220
|
+
o.href = a, o.download = e.name || "archivo_descarga", document.body.appendChild(o), o.click(), document.body.removeChild(o), URL.revokeObjectURL(a);
|
|
221
|
+
}, q = Y(
|
|
222
|
+
({
|
|
223
|
+
acceptFiles: e = he,
|
|
224
|
+
className: a = "",
|
|
225
|
+
dimensions: o = ve,
|
|
226
|
+
disabled: l = !1,
|
|
227
|
+
fieldName: t = "file-uploader",
|
|
228
|
+
labels: N,
|
|
229
|
+
maxFiles: U = 1,
|
|
230
|
+
maxSizeFile: f = 0,
|
|
231
|
+
multipleFiles: h = !1,
|
|
232
|
+
onDeleteFiles: w,
|
|
233
|
+
onFilesChange: E,
|
|
234
|
+
onFilesSelected: v,
|
|
235
|
+
showDownloadButton: C = !0,
|
|
236
|
+
theme: O,
|
|
237
|
+
updateFiles: A = _e,
|
|
238
|
+
validateDimensions: b = !1
|
|
239
|
+
}, $) => {
|
|
240
|
+
const d = { ...ge, ...N }, L = we(O), [n, u] = B(null), c = fe({
|
|
241
|
+
acceptFiles: e,
|
|
242
|
+
dimensions: o,
|
|
243
|
+
maxFiles: U,
|
|
244
|
+
maxSizeFile: f,
|
|
245
|
+
multipleFiles: h,
|
|
246
|
+
onFilesChange: E,
|
|
247
|
+
onFilesSelected: v,
|
|
248
|
+
updateFiles: A,
|
|
249
|
+
validateDimensions: b
|
|
250
|
+
});
|
|
251
|
+
return ee(
|
|
252
|
+
$,
|
|
253
|
+
() => ({
|
|
254
|
+
clear: c.clear,
|
|
255
|
+
open: c.open,
|
|
256
|
+
files: () => c.items
|
|
257
|
+
}),
|
|
258
|
+
[c.clear, c.items, c.open]
|
|
259
|
+
), M(() => {
|
|
260
|
+
if (!n)
|
|
261
|
+
return;
|
|
262
|
+
const i = (D) => {
|
|
263
|
+
D.key === "Escape" && u(null);
|
|
264
|
+
};
|
|
265
|
+
return document.addEventListener("keydown", i), () => document.removeEventListener("keydown", i);
|
|
266
|
+
}, [n]), M(() => {
|
|
267
|
+
n && !c.items.some((i) => i.id === n.id) && u(null);
|
|
268
|
+
}, [n, c.items]), /* @__PURE__ */ p("section", { className: `file-uploader ${a}`.trim(), style: L, children: [
|
|
269
|
+
/* @__PURE__ */ p(
|
|
270
|
+
"div",
|
|
271
|
+
{
|
|
272
|
+
className: [
|
|
273
|
+
"file-uploader__dropzone",
|
|
274
|
+
c.items.length > 0 ? "file-uploader__dropzone--active" : "",
|
|
275
|
+
c.isDragging ? "file-uploader__dropzone--dragging" : "",
|
|
276
|
+
l ? "file-uploader__dropzone--disabled" : ""
|
|
277
|
+
].filter(Boolean).join(" "),
|
|
278
|
+
onDrop: l ? void 0 : c.onDrop,
|
|
279
|
+
onDragOver: l ? void 0 : c.onDragOver,
|
|
280
|
+
onDragLeave: l ? void 0 : c.onDragLeave,
|
|
281
|
+
children: [
|
|
282
|
+
/* @__PURE__ */ r("div", { className: "file-uploader__info", children: c.canAddFiles ? /* @__PURE__ */ p(T, { children: [
|
|
283
|
+
/* @__PURE__ */ r("span", { className: "file-uploader__main-icon", children: /* @__PURE__ */ r(Le, {}) }),
|
|
284
|
+
/* @__PURE__ */ p("div", { children: [
|
|
285
|
+
/* @__PURE__ */ r("p", { className: "file-uploader__title", children: d.idleTitle }),
|
|
286
|
+
/* @__PURE__ */ r("p", { className: "file-uploader__hint", children: d.idleHint }),
|
|
287
|
+
f > 0 && /* @__PURE__ */ r("p", { children: d.maxSize(f) }),
|
|
288
|
+
e.length > 0 && /* @__PURE__ */ r("p", { children: d.allowedFormats(c.acceptedFormats) }),
|
|
289
|
+
b && /* @__PURE__ */ r("p", { children: d.imageDimensions(o.width, o.height) })
|
|
290
|
+
] })
|
|
291
|
+
] }) : /* @__PURE__ */ p("div", { children: [
|
|
292
|
+
/* @__PURE__ */ r("span", { className: "file-uploader__success-mark", children: /* @__PURE__ */ r(H, { approved: !0 }) }),
|
|
293
|
+
/* @__PURE__ */ r("p", { className: "file-uploader__title", children: d.limitReached })
|
|
294
|
+
] }) }),
|
|
295
|
+
/* @__PURE__ */ r(
|
|
296
|
+
"input",
|
|
297
|
+
{
|
|
298
|
+
ref: c.inputRef,
|
|
299
|
+
type: "file",
|
|
300
|
+
id: t,
|
|
301
|
+
name: t,
|
|
302
|
+
className: "file-uploader__input",
|
|
303
|
+
onChange: c.handleFiles,
|
|
304
|
+
accept: e.join(","),
|
|
305
|
+
multiple: h,
|
|
306
|
+
disabled: l
|
|
307
|
+
}
|
|
308
|
+
),
|
|
309
|
+
c.canAddFiles && /* @__PURE__ */ r(
|
|
310
|
+
"button",
|
|
311
|
+
{
|
|
312
|
+
type: "button",
|
|
313
|
+
className: "file-uploader__browse",
|
|
314
|
+
onClick: c.open,
|
|
315
|
+
disabled: l,
|
|
316
|
+
children: h ? d.browseFiles : d.browseFile
|
|
317
|
+
}
|
|
318
|
+
),
|
|
319
|
+
c.items.length > 0 && /* @__PURE__ */ r("div", { className: "file-uploader__list", children: c.items.map((i) => {
|
|
320
|
+
const D = C && i.approve && ce(i.file);
|
|
321
|
+
return /* @__PURE__ */ r(re, { children: /* @__PURE__ */ p(
|
|
322
|
+
"div",
|
|
323
|
+
{
|
|
324
|
+
className: [
|
|
325
|
+
"file-uploader__item",
|
|
326
|
+
i.approve ? "file-uploader__item--success" : "file-uploader__item--failed"
|
|
327
|
+
].join(" "),
|
|
328
|
+
children: [
|
|
329
|
+
/* @__PURE__ */ r("span", { className: "file-uploader__status", children: /* @__PURE__ */ r(H, { approved: i.approve }) }),
|
|
330
|
+
i.previewUrl && /* @__PURE__ */ p(
|
|
331
|
+
"button",
|
|
332
|
+
{
|
|
333
|
+
type: "button",
|
|
334
|
+
className: "file-uploader__preview-trigger",
|
|
335
|
+
onClick: () => u(i),
|
|
336
|
+
"aria-label": `${d.previewFile}: ${i.file.name}`,
|
|
337
|
+
title: d.previewFile,
|
|
338
|
+
children: [
|
|
339
|
+
k(i.file) && /* @__PURE__ */ r(
|
|
340
|
+
"img",
|
|
341
|
+
{
|
|
342
|
+
className: "file-uploader__thumbnail file-uploader__thumbnail--image",
|
|
343
|
+
src: i.previewUrl,
|
|
344
|
+
alt: ""
|
|
345
|
+
}
|
|
346
|
+
),
|
|
347
|
+
V(i.file) && /* @__PURE__ */ p(T, { children: [
|
|
348
|
+
/* @__PURE__ */ r(
|
|
349
|
+
"video",
|
|
350
|
+
{
|
|
351
|
+
className: "file-uploader__thumbnail file-uploader__thumbnail--video",
|
|
352
|
+
src: i.previewUrl,
|
|
353
|
+
preload: "metadata",
|
|
354
|
+
muted: !0
|
|
355
|
+
}
|
|
356
|
+
),
|
|
357
|
+
/* @__PURE__ */ r("span", { className: "file-uploader__preview-badge", children: /* @__PURE__ */ r(Ne, {}) })
|
|
358
|
+
] }),
|
|
359
|
+
P(i.file) && /* @__PURE__ */ r("span", { className: "file-uploader__media-placeholder", children: /* @__PURE__ */ r(G, {}) })
|
|
360
|
+
]
|
|
361
|
+
}
|
|
362
|
+
),
|
|
363
|
+
!i.previewUrl && /* @__PURE__ */ r("span", { className: "file-uploader__file-icon", children: /* @__PURE__ */ r(Ue, {}) }),
|
|
364
|
+
/* @__PURE__ */ p("div", { className: "file-uploader__file-info", children: [
|
|
365
|
+
/* @__PURE__ */ r("p", { className: "file-uploader__name", children: i.file.name }),
|
|
366
|
+
/* @__PURE__ */ r("p", { className: "file-uploader__size", children: z(i.file.size) })
|
|
367
|
+
] }),
|
|
368
|
+
/* @__PURE__ */ p("div", { className: "file-uploader__actions", children: [
|
|
369
|
+
D && /* @__PURE__ */ r(
|
|
370
|
+
"button",
|
|
371
|
+
{
|
|
372
|
+
type: "button",
|
|
373
|
+
className: "file-uploader__icon-button",
|
|
374
|
+
onClick: () => De(i.file),
|
|
375
|
+
"aria-label": d.downloadFile,
|
|
376
|
+
title: d.downloadFile,
|
|
377
|
+
children: /* @__PURE__ */ r(be, {})
|
|
378
|
+
}
|
|
379
|
+
),
|
|
380
|
+
/* @__PURE__ */ r(
|
|
381
|
+
"button",
|
|
382
|
+
{
|
|
383
|
+
type: "button",
|
|
384
|
+
className: "file-uploader__icon-button file-uploader__icon-button--danger",
|
|
385
|
+
onClick: () => {
|
|
386
|
+
(n == null ? void 0 : n.id) === i.id && u(null), c.removeFile(i), w == null || w(
|
|
387
|
+
c.items.filter((y) => y.id !== i.id && y.approve),
|
|
388
|
+
i
|
|
389
|
+
);
|
|
390
|
+
},
|
|
391
|
+
"aria-label": d.removeFile,
|
|
392
|
+
title: d.removeFile,
|
|
393
|
+
children: /* @__PURE__ */ r(Ee, {})
|
|
394
|
+
}
|
|
395
|
+
)
|
|
396
|
+
] })
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
) }, i.id);
|
|
400
|
+
}) }),
|
|
401
|
+
h && /* @__PURE__ */ r("p", { className: "file-uploader__counter", children: d.selectedCount(c.approvedItems.length, U) })
|
|
402
|
+
]
|
|
403
|
+
}
|
|
404
|
+
),
|
|
405
|
+
(n == null ? void 0 : n.previewUrl) && /* @__PURE__ */ r(
|
|
406
|
+
"div",
|
|
407
|
+
{
|
|
408
|
+
className: "file-uploader__modal",
|
|
409
|
+
role: "dialog",
|
|
410
|
+
"aria-modal": "true",
|
|
411
|
+
"aria-label": `${d.previewFile}: ${n.file.name}`,
|
|
412
|
+
onMouseDown: (i) => {
|
|
413
|
+
i.currentTarget === i.target && u(null);
|
|
414
|
+
},
|
|
415
|
+
children: /* @__PURE__ */ p("div", { className: "file-uploader__modal-panel", children: [
|
|
416
|
+
/* @__PURE__ */ p("div", { className: "file-uploader__modal-header", children: [
|
|
417
|
+
/* @__PURE__ */ p("div", { children: [
|
|
418
|
+
/* @__PURE__ */ r("p", { className: "file-uploader__modal-title", children: n.file.name }),
|
|
419
|
+
/* @__PURE__ */ r("p", { className: "file-uploader__modal-meta", children: z(n.file.size) })
|
|
420
|
+
] }),
|
|
421
|
+
/* @__PURE__ */ r(
|
|
422
|
+
"button",
|
|
423
|
+
{
|
|
424
|
+
type: "button",
|
|
425
|
+
className: "file-uploader__icon-button",
|
|
426
|
+
onClick: () => u(null),
|
|
427
|
+
"aria-label": d.closePreview,
|
|
428
|
+
title: d.closePreview,
|
|
429
|
+
children: /* @__PURE__ */ r(Ae, {})
|
|
430
|
+
}
|
|
431
|
+
)
|
|
432
|
+
] }),
|
|
433
|
+
/* @__PURE__ */ p("div", { className: "file-uploader__modal-content", children: [
|
|
434
|
+
k(n.file) && /* @__PURE__ */ r(
|
|
435
|
+
"img",
|
|
436
|
+
{
|
|
437
|
+
className: "file-uploader__modal-image",
|
|
438
|
+
src: n.previewUrl,
|
|
439
|
+
alt: n.file.name
|
|
440
|
+
}
|
|
441
|
+
),
|
|
442
|
+
V(n.file) && /* @__PURE__ */ r(
|
|
443
|
+
"video",
|
|
444
|
+
{
|
|
445
|
+
className: "file-uploader__modal-video",
|
|
446
|
+
src: n.previewUrl,
|
|
447
|
+
controls: !0,
|
|
448
|
+
preload: "metadata"
|
|
449
|
+
}
|
|
450
|
+
),
|
|
451
|
+
P(n.file) && /* @__PURE__ */ p("div", { className: "file-uploader__modal-audio", children: [
|
|
452
|
+
/* @__PURE__ */ r(G, {}),
|
|
453
|
+
/* @__PURE__ */ r("audio", { src: n.previewUrl, controls: !0, preload: "metadata" })
|
|
454
|
+
] })
|
|
455
|
+
] })
|
|
456
|
+
] })
|
|
457
|
+
}
|
|
458
|
+
)
|
|
459
|
+
] });
|
|
460
|
+
}
|
|
461
|
+
);
|
|
462
|
+
q.displayName = "ReactFileUploader";
|
|
463
|
+
const ye = q;
|
|
464
|
+
export {
|
|
465
|
+
le as DEFAULT_AUDIO_FORMATS,
|
|
466
|
+
ae as DEFAULT_IMAGE_FORMATS,
|
|
467
|
+
oe as DEFAULT_VIDEO_FORMATS,
|
|
468
|
+
ye as FileUploader,
|
|
469
|
+
q as ReactFileUploader,
|
|
470
|
+
z as bytesToSize,
|
|
471
|
+
q as default,
|
|
472
|
+
x as getFileExtension,
|
|
473
|
+
te as getReadableAcceptedFormats,
|
|
474
|
+
P as isAudioFile,
|
|
475
|
+
ce as isDocumentFile,
|
|
476
|
+
k as isImageFile,
|
|
477
|
+
W as isPreviewableFile,
|
|
478
|
+
V as isVideoFile,
|
|
479
|
+
ne as matchesAcceptedType,
|
|
480
|
+
fe as useFileUploader
|
|
481
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.file-uploader{--file-uploader-accent: #2563eb;--file-uploader-accent-soft: #dbeafe;--file-uploader-border: #cbd5e1;--file-uploader-danger: #dc2626;--file-uploader-ink: #0f172a;--file-uploader-muted: #64748b;--file-uploader-success: #16a34a;--file-uploader-surface: #ffffff;--file-uploader-item-surface: #f8fafc;--file-uploader-modal-backdrop: color-mix(in srgb, #0f172a 72%, transparent);--file-uploader-modal-surface: #ffffff;color:var(--file-uploader-ink);font-family:inherit}.file-uploader *,.file-uploader *:before,.file-uploader *:after{box-sizing:border-box}.file-uploader__dropzone{align-items:center;background:var(--file-uploader-surface);border:1px dashed var(--file-uploader-border);border-radius:8px;display:flex;flex-direction:column;gap:16px;min-height:240px;padding:24px;transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}.file-uploader__dropzone--active{border-style:solid}.file-uploader__dropzone--dragging{background:var(--file-uploader-accent-soft);border-color:var(--file-uploader-accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--file-uploader-accent) 16%,transparent)}.file-uploader__dropzone--disabled{cursor:not-allowed;opacity:.62}.file-uploader__info{align-items:center;display:flex;gap:16px;justify-content:center;text-align:left;width:100%}.file-uploader__main-icon,.file-uploader__success-mark{align-items:center;background:var(--file-uploader-accent-soft);border-radius:8px;color:var(--file-uploader-accent);display:inline-flex;flex:0 0 56px;height:56px;justify-content:center;width:56px}.file-uploader__main-icon svg,.file-uploader__success-mark svg,.file-uploader__status svg,.file-uploader__file-icon svg,.file-uploader__media-placeholder svg,.file-uploader__preview-badge svg,.file-uploader__icon-button svg{fill:currentColor;height:1em;width:1em}.file-uploader__main-icon svg,.file-uploader__success-mark svg{font-size:28px}.file-uploader__title,.file-uploader__hint,.file-uploader__info p,.file-uploader__counter,.file-uploader__name,.file-uploader__size{margin:0}.file-uploader__title{font-size:16px;font-weight:600;line-height:1.35}.file-uploader__title span,.file-uploader__format{color:var(--file-uploader-accent)}.file-uploader__hint,.file-uploader__info p,.file-uploader__counter,.file-uploader__size{color:var(--file-uploader-muted);font-size:13px;line-height:1.45}.file-uploader__input{display:none}.file-uploader__browse{background:var(--file-uploader-accent);border:0;border-radius:6px;color:#fff;cursor:pointer;font:inherit;font-weight:600;min-height:40px;padding:0 16px}.file-uploader__browse:disabled{cursor:not-allowed}.file-uploader__list{display:grid;gap:10px;width:100%}.file-uploader__item{align-items:center;background:var(--file-uploader-item-surface);border:1px solid #e2e8f0;border-radius:8px;display:grid;gap:12px;grid-template-columns:20px 72px minmax(0,1fr) auto;min-height:76px;padding:12px}.file-uploader__item--success .file-uploader__status{color:var(--file-uploader-success)}.file-uploader__item--failed .file-uploader__status{color:var(--file-uploader-danger)}.file-uploader__preview-trigger,.file-uploader__thumbnail,.file-uploader__file-icon{border-radius:6px}.file-uploader__preview-trigger{background:#e2e8f0;border:1px solid #cbd5e1;color:#334155;cursor:pointer;display:block;height:56px;overflow:hidden;padding:0;position:relative;width:72px}.file-uploader__thumbnail{background:#e2e8f0;display:block;height:100%;object-fit:cover;width:100%}.file-uploader__thumbnail--video{object-fit:contain}.file-uploader__preview-badge{align-items:center;background:var(--file-uploader-modal-backdrop);border-radius:999px;color:#fff;display:inline-flex;font-size:12px;height:26px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:26px}.file-uploader__media-placeholder{align-items:center;display:flex;font-size:24px;height:100%;justify-content:center;width:100%}.file-uploader__file-icon{align-items:center;background:#e2e8f0;color:#475569;display:inline-flex;font-size:20px;height:56px;justify-content:center;width:56px}.file-uploader__file-info{min-width:0}.file-uploader__name{font-size:14px;font-weight:600;line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-uploader__actions{display:flex;gap:6px}.file-uploader__icon-button{align-items:center;background:var(--file-uploader-modal-surface);border:1px solid #cbd5e1;border-radius:6px;color:#334155;cursor:pointer;display:inline-flex;font-size:14px;height:32px;justify-content:center;width:32px}.file-uploader__icon-button--danger{color:var(--file-uploader-danger)}.file-uploader__modal{align-items:center;background:color-mix(in srgb,#0f172a 72%,transparent);display:flex;top:0;right:0;bottom:0;left:0;justify-content:center;padding:20px;position:fixed;z-index:999}.file-uploader__modal-panel{background:#fff;border-radius:8px;box-shadow:0 24px 80px color-mix(in srgb,#0f172a 32%,transparent);display:grid;gap:14px;max-height:min(760px,calc(100vh - 40px));max-width:min(920px,calc(100vw - 40px));overflow:hidden;padding:14px;width:100%}.file-uploader__modal-header{align-items:center;display:flex;gap:16px;justify-content:space-between}.file-uploader__modal-title,.file-uploader__modal-meta{margin:0}.file-uploader__modal-title{font-size:15px;font-weight:700;line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-uploader__modal-meta{color:var(--file-uploader-muted);font-size:13px}.file-uploader__modal-content{align-items:center;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;display:flex;justify-content:center;min-height:240px;overflow:hidden}.file-uploader__modal-image,.file-uploader__modal-video{display:block;max-height:min(620px,calc(100vh - 180px));max-width:100%}.file-uploader__modal-video{width:100%}.file-uploader__modal-audio{align-items:center;color:#334155;display:grid;gap:18px;justify-items:center;padding:28px;width:min(520px,100%)}.file-uploader__modal-audio svg{fill:currentColor;height:46px;width:46px}.file-uploader__modal-audio audio{width:100%}@media(max-width:520px){.file-uploader__dropzone{padding:18px}.file-uploader__info{align-items:flex-start;flex-direction:column}.file-uploader__item{align-items:start;grid-template-columns:20px minmax(0,1fr)}.file-uploader__preview-trigger,.file-uploader__file-icon,.file-uploader__file-info,.file-uploader__actions{grid-column:2}}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { FileUploaderHandle, FileUploaderProps } from './types';
|
|
2
|
+
export declare const ReactFileUploader: import('react').ForwardRefExoticComponent<FileUploaderProps & import('react').RefAttributes<FileUploaderHandle>>;
|
|
3
|
+
export declare const FileUploader: import('react').ForwardRefExoticComponent<FileUploaderProps & import('react').RefAttributes<FileUploaderHandle>>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FileUploader, ReactFileUploader, ReactFileUploader as default } from './FileUploader';
|
|
2
|
+
export { useFileUploader } from './useFileUploader';
|
|
3
|
+
export { DEFAULT_IMAGE_FORMATS, DEFAULT_AUDIO_FORMATS, DEFAULT_VIDEO_FORMATS, bytesToSize, getFileExtension, getReadableAcceptedFormats, isAudioFile, isDocumentFile, isImageFile, isPreviewableFile, isVideoFile, matchesAcceptedType, } from './utils';
|
|
4
|
+
export type { FileUploaderHandle, FileUploaderItem, FileUploaderLabels, FileUploaderProps, FileUploaderRejectionReason, FileUploaderStatus, } from './types';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ChangeEvent, CSSProperties, DragEvent, ReactNode } from 'react';
|
|
2
|
+
export type FileUploaderStatus = "approved" | "rejected";
|
|
3
|
+
export type FileUploaderRejectionReason = "file-size" | "file-type" | "image-dimensions";
|
|
4
|
+
export type FileUploaderLabels = {
|
|
5
|
+
idleTitle: ReactNode;
|
|
6
|
+
idleHint: ReactNode;
|
|
7
|
+
browseFile: ReactNode;
|
|
8
|
+
browseFiles: ReactNode;
|
|
9
|
+
limitReached: ReactNode;
|
|
10
|
+
maxSize: (maxSizeMb: number) => ReactNode;
|
|
11
|
+
allowedFormats: (formats: string[]) => ReactNode;
|
|
12
|
+
imageDimensions: (width: number, height: number) => ReactNode;
|
|
13
|
+
selectedCount: (count: number, maxFiles: number) => ReactNode;
|
|
14
|
+
removeFile: string;
|
|
15
|
+
downloadFile: string;
|
|
16
|
+
previewFile: string;
|
|
17
|
+
closePreview: string;
|
|
18
|
+
};
|
|
19
|
+
export type FileUploaderItem = {
|
|
20
|
+
id: string;
|
|
21
|
+
file: File;
|
|
22
|
+
status: FileUploaderStatus;
|
|
23
|
+
approve: boolean;
|
|
24
|
+
reasons: FileUploaderRejectionReason[];
|
|
25
|
+
previewUrl?: string;
|
|
26
|
+
};
|
|
27
|
+
export type FileUploaderTheme = {
|
|
28
|
+
accent?: string;
|
|
29
|
+
accentSoft?: string;
|
|
30
|
+
border?: string;
|
|
31
|
+
danger?: string;
|
|
32
|
+
ink?: string;
|
|
33
|
+
muted?: string;
|
|
34
|
+
success?: string;
|
|
35
|
+
surface?: string;
|
|
36
|
+
itemSurface?: string;
|
|
37
|
+
modalBackdrop?: string;
|
|
38
|
+
modalSurface?: string;
|
|
39
|
+
};
|
|
40
|
+
export type FileUploaderThemeVars = CSSProperties & {
|
|
41
|
+
"--file-uploader-accent"?: string;
|
|
42
|
+
"--file-uploader-accent-soft"?: string;
|
|
43
|
+
"--file-uploader-border"?: string;
|
|
44
|
+
"--file-uploader-danger"?: string;
|
|
45
|
+
"--file-uploader-ink"?: string;
|
|
46
|
+
"--file-uploader-muted"?: string;
|
|
47
|
+
"--file-uploader-success"?: string;
|
|
48
|
+
"--file-uploader-surface"?: string;
|
|
49
|
+
"--file-uploader-item-surface"?: string;
|
|
50
|
+
"--file-uploader-modal-backdrop"?: string;
|
|
51
|
+
"--file-uploader-modal-surface"?: string;
|
|
52
|
+
};
|
|
53
|
+
export type FileUploaderHandle = {
|
|
54
|
+
clear: () => void;
|
|
55
|
+
open: () => void;
|
|
56
|
+
files: () => FileUploaderItem[];
|
|
57
|
+
};
|
|
58
|
+
export type FileUploaderProps = {
|
|
59
|
+
acceptFiles?: string[];
|
|
60
|
+
className?: string;
|
|
61
|
+
dimensions?: {
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
};
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
fieldName?: string;
|
|
67
|
+
labels?: Partial<FileUploaderLabels>;
|
|
68
|
+
maxFiles?: number;
|
|
69
|
+
maxSizeFile?: number;
|
|
70
|
+
multipleFiles?: boolean;
|
|
71
|
+
showDownloadButton?: boolean;
|
|
72
|
+
theme?: FileUploaderTheme;
|
|
73
|
+
updateFiles?: File[];
|
|
74
|
+
validateDimensions?: boolean;
|
|
75
|
+
onDeleteFiles?: (approvedFiles: FileUploaderItem[], removedFile: FileUploaderItem) => void;
|
|
76
|
+
onFilesChange?: (items: FileUploaderItem[]) => void;
|
|
77
|
+
onFilesSelected?: (files: File | File[]) => void;
|
|
78
|
+
};
|
|
79
|
+
export type FileInputEvent = ChangeEvent<HTMLInputElement> | DragEvent<HTMLElement>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ChangeEvent, DragEvent } from 'react';
|
|
2
|
+
import { FileUploaderItem, FileUploaderProps } from './types';
|
|
3
|
+
export declare const useFileUploader: ({ acceptFiles, dimensions, maxFiles, maxSizeFile, multipleFiles, updateFiles, validateDimensions, onFilesChange, onFilesSelected, }: Pick<FileUploaderProps, "acceptFiles" | "dimensions" | "maxFiles" | "maxSizeFile" | "multipleFiles" | "onFilesChange" | "onFilesSelected" | "updateFiles" | "validateDimensions">) => {
|
|
4
|
+
acceptedFormats: string[];
|
|
5
|
+
approvedItems: FileUploaderItem[];
|
|
6
|
+
canAddFiles: boolean;
|
|
7
|
+
clear: () => void;
|
|
8
|
+
handleFiles: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
9
|
+
inputRef: import('react').RefObject<HTMLInputElement | null>;
|
|
10
|
+
isDragging: boolean;
|
|
11
|
+
items: FileUploaderItem[];
|
|
12
|
+
onDragLeave: (event: DragEvent<HTMLElement>) => void;
|
|
13
|
+
onDragOver: (event: DragEvent<HTMLElement>) => void;
|
|
14
|
+
onDrop: (event: DragEvent<HTMLElement>) => void;
|
|
15
|
+
open: () => void;
|
|
16
|
+
removeFile: (itemToRemove: FileUploaderItem) => void;
|
|
17
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FileUploaderItem } from './types';
|
|
2
|
+
export declare const DEFAULT_IMAGE_FORMATS: string[];
|
|
3
|
+
export declare const DEFAULT_AUDIO_FORMATS: string[];
|
|
4
|
+
export declare const DEFAULT_VIDEO_FORMATS: string[];
|
|
5
|
+
export declare const bytesToSize: (bytes: number, separator?: string) => string;
|
|
6
|
+
export declare const getFileExtension: (file: File) => string;
|
|
7
|
+
export declare const getReadableAcceptedFormats: (acceptFiles: string[]) => string[];
|
|
8
|
+
export declare const isImageFile: (file: File) => boolean;
|
|
9
|
+
export declare const isAudioFile: (file: File) => boolean;
|
|
10
|
+
export declare const isVideoFile: (file: File) => boolean;
|
|
11
|
+
export declare const isPreviewableFile: (file: File) => boolean;
|
|
12
|
+
export declare const isDocumentFile: (file: File) => boolean;
|
|
13
|
+
export declare const matchesAcceptedType: (file: File, acceptFiles: string[]) => boolean;
|
|
14
|
+
export declare const validateImageDimensions: (file: File, dimensions: {
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
}) => Promise<boolean>;
|
|
18
|
+
export declare const createUploaderItem: (file: File, options: {
|
|
19
|
+
acceptFiles: string[];
|
|
20
|
+
dimensions: {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
};
|
|
24
|
+
maxSizeFile: number;
|
|
25
|
+
validateDimensions: boolean;
|
|
26
|
+
}) => Promise<FileUploaderItem>;
|
|
27
|
+
export declare const revokePreviewUrls: (items: FileUploaderItem[]) => void;
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yunuenm23/react-file-uploader",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Advanced React file uploader component with media previews, document downloads, and no UI framework dependency.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
},
|
|
18
|
+
"./styles.css": "./dist/react-file-uploader.css"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"dev": "vite --config vite.docs.config.ts --host 127.0.0.1",
|
|
25
|
+
"dev:docs": "vite --config vite.docs.config.ts --host 127.0.0.1",
|
|
26
|
+
"build": "vite build",
|
|
27
|
+
"build:docs": "vite build --config vite.docs.config.ts",
|
|
28
|
+
"build:all": "npm run build && npm run build:docs",
|
|
29
|
+
"pack:check": "npm pack --dry-run",
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"react": ">=18.0.0",
|
|
34
|
+
"react-dom": ">=18.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/react": "^19.2.17",
|
|
38
|
+
"@types/react-dom": "^19.2.3",
|
|
39
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
40
|
+
"react": "^19.2.3",
|
|
41
|
+
"react-dom": "^19.2.3",
|
|
42
|
+
"typescript": "^5.7.3",
|
|
43
|
+
"vite": "^6.0.7",
|
|
44
|
+
"vite-plugin-dts": "^4.4.0"
|
|
45
|
+
}
|
|
46
|
+
}
|