react-filezone
Advanced tools
Comparing version
@@ -37,2 +37,3 @@ import * as axios from 'axios'; | ||
allowedFileTypes?: string[]; | ||
disabled?: boolean; | ||
}; | ||
@@ -55,4 +56,5 @@ metadata?: Record<string, any>; | ||
restartUpload: (fileId: string) => void; | ||
disabled: boolean; | ||
}; | ||
export { useUpload }; |
@@ -1,2 +0,2 @@ | ||
"use strict";var e=require("react"),t=require("uuid"),r=require("axios");exports.useUpload=({action:a,globalConfig:i={},metadata:l={},onUploadStart:s,onUploadComplete:o,onError:n,headers:d})=>{const{mode:c="multiple",maxFiles:u=3,maxFileSize:p=10737418240,allowedFileTypes:f=["*/*"],maxConcurrentUploads:m=5}=i,[g,h]=e.useState(!1),[w,v]=e.useState([]),[y,b]=e.useState([]),P=e.useRef(new Map),U=e.useRef([]),$=e.useRef(new Set),[C,x]=e.useState(!1),S=e.useCallback((e=>new Promise(((t,r)=>{const a=e.type||"",i=f.some((e=>{if(e.endsWith("*")){const t=e.slice(0,-1);return a.startsWith(t)}return a===e}));if(i&&(a.startsWith("image/")||f.includes("image/*"))){const a=new FileReader;a.onloadend=()=>{t({imagePreview:a.result})},a.onerror=r,a.readAsDataURL(e)}else if(i&&(f.includes("video/*")||f.includes(a)||f.some((e=>e.startsWith("video/")&&e===a)))){const a=document.createElement("video");a.preload="metadata";const i=URL.createObjectURL(e);a.onloadedmetadata=()=>{const e=document.createElement("canvas");e.width=a.videoWidth||320,e.height=a.videoHeight||240;const r=e.getContext("2d");r?.drawImage(a,0,0,e.width,e.height),URL.revokeObjectURL(i),t({videoPreview:i})},a.onerror=r,a.src=i}else t({})}))),[f]),k=e.useCallback((e=>f.some((t=>{if(t.endsWith("*")){const r=t.slice(0,-1);return e.type.startsWith(r)}return e.type===t}))?e.size>p?{valid:!1,error:`File too large: ${e.name}. Max size: ${p/1048576}MB`}:"single"===c&&w.length>=1?{valid:!1,error:"Only one file allowed in single mode"}:"multiple"===c&&w.length>=u?{valid:!1,error:`Maximum ${u} files allowed`}:{valid:!0}:{valid:!1,error:`Invalid file type: ${e.type}. Allowed types: ${f.join(", ")}`}),[f,p,c,u,w]),D=async(e,t)=>{const{method:a="POST",body:i,headers:l={},signal:s,startByte:o=0,fileId:n,onUploadProgress:d}=t,c=i instanceof FormData?Array.from(i.values()).reduce(((e,t)=>e+(t instanceof Blob?t.size:new Blob([t]).size)),0):i.size;return r({url:e,method:a,data:i,headers:{...l},signal:s&&s.aborted?s:void 0,onUploadProgress:e=>{const t=e.loaded+o,r=Math.min(Math.round(t/c*100),100);v((e=>e.map((e=>e.id===n?{...e,state:{...e.state,progress:r}}:e)))),d?.({loaded:t,total:c,progress:r})}}).then((e=>e)).catch((e=>{if(r.isCancel(e))throw new Error("Upload aborted");throw e}))},M=e.useCallback((async e=>{const t=w.findIndex((t=>t.id===e));if(-1===t)return;const r=w[t];if(["uploading","completed"].includes(r.state.status))return;const i=new AbortController;P.current.set(e,i);try{v((t=>t.map((t=>t.id===e?{...t,state:{...t.state,status:"uploading",progress:0,errors:[]}}:t))));const t=new FormData;t.append("file",r.file);const l=await D(a,{method:"POST",body:t,headers:{...d},signal:i.signal,fileId:e,onUploadProgress:t=>{v((r=>r.map((r=>r.id===e?{...r,state:{...r.state,progress:t.progress,status:100===t.progress?"completed":"uploading"}}:r))))}});if("object"==typeof l&&null!==l&&"status"in l){if(!l)throw new Error(`Upload failed with status: ${l}`)}else if("string"==typeof l)throw new Error("Unexpected response format");return o?.(l.data),l}catch(t){throw v((r=>r.map((r=>r.id===e?{...r,state:{...r.state,status:"error",progress:0,errors:[t.message||"Upload failed"]}}:r)))),n?.(t,r),t}finally{P.current.delete(e)}}),[w,a,o,n,D]),E=e.useCallback((async()=>{if("single"!==c)for(;U.current.length>0;){const e=U.current.filter((e=>{const t=w.find((t=>t.id===e));return"pending"===t?.state.status&&!$.current.has(e)}));if(0===e.length)break;const t=m-$.current.size;if(t<=0){await new Promise((e=>setTimeout(e,100)));continue}e.slice(0,t).forEach((async e=>{if(!$.current.has(e)){$.current.add(e);try{await M(e)}catch(e){}finally{$.current.delete(e),U.current=U.current.filter((t=>t!==e))}}})),await new Promise((e=>setTimeout(e,100)))}}),[M,m,w]),F=e.useCallback((async e=>{x(!0);try{const r=e=>`${e.name}-${e.size}-${e.lastModified}`,a=Array.from(new Map(e.map((e=>[r(e),e]))).values()),i=new Set(w.map((e=>r(e.file)))),o=a.filter((e=>!i.has(r(e))));if("single"===c){if(o.length>1)return void b((e=>[...e,"Only one file can be selected in single mode."]));if(w.length>0){const e=w[0].id,t=P.current.get(e);t&&(t.abort(),P.current.delete(e))}if(0===o.length)return;const e=o[0],{imagePreview:r,videoPreview:a}=await S(e);v([{id:t.v4(),file:e,previewUrl:r,videoPreviewUrl:a,state:{status:"idle",progress:0,errors:[]},metadata:{...l}}])}else{if(w.length+o.length>u){const e=o.slice(0,u-w.length);b((t=>[...t,`Maximum ${u} files allowed. Only ${e.length} files were added.`])),o.splice(0,e.length)}const e=await Promise.all(o.map((async e=>{const{imagePreview:r,videoPreview:a}=await S(e),i=k(e);return i.valid?{fileState:{id:t.v4(),file:e,previewUrl:r,videoPreviewUrl:a,state:{status:"pending",progress:0,errors:[]},metadata:{...l}}}:{error:i.error||"Validation failed"}}))),r=e.filter((e=>void 0!==e.error)).map((e=>e.error)),a=e.filter((e=>void 0!==e.fileState)).map((e=>e.fileState));r.length>0&&b((e=>[...e,...r])),v((e=>(U.current=[...U.current,...a.map((e=>e.id))],s?.(a),E(),[...e,...a])))}}finally{x(!1)}}),[k,l,s,E,w,c,u,S]),O=e.useCallback((e=>{const t=P.current.get(e);if(t){try{t.abort()}catch(t){console.warn(`Error aborting upload for file ${e}:`,t)}P.current.delete(e)}v((t=>t.filter((t=>t.id!==e))))}),[]),R=e.useCallback((e=>{v((t=>t.map((t=>t.id===e?{...t,state:{...t.state,status:"pending",progress:0,errors:[]}}:t)))),M(e)}),[M]),A=e.useCallback((()=>({onDragEnter:e=>{e.preventDefault(),e.stopPropagation(),h(!0)},onDragLeave:e=>{e.preventDefault(),e.stopPropagation(),h(!1)},onDragOver:e=>{e.preventDefault(),e.stopPropagation(),g||h(!0)},onDrop:e=>{e.preventDefault(),e.stopPropagation(),h(!1);const t=Array.from(e.dataTransfer.files);if("multiple"===c&&t.length+w.length>u){const e=t.slice(0,u-w.length);F(e),b((t=>[...t,`Maximum ${u} files allowed. Only ${e.length} files were added.`]))}else F(t)},onClick:()=>{const e=document.createElement("input");e.type="file",e.multiple="multiple"===c,e.max="multiple"===c?u.toString():"1",e.accept=f.join(","),e.onchange=e=>{const t=e.target;if(t.files){const e=Array.from(t.files);if("multiple"===c&&e.length>u){const t=e.slice(0,u);F(t),b((e=>[...e,`Maximum ${u} files allowed. Only ${t.length} files were added.`]))}else F(e)}},e.click()}})),[F,c,f,u,w,g]),z=e.useCallback((()=>({type:"file",multiple:"multiple"===c,accept:f.join(","),max:"multiple"===c?u.toString():"1",onChange:e=>{const t=e.target;if(t.files){const e=Array.from(t.files);if("multiple"===c&&e.length>u){const t=e.slice(0,u);F(t),b((e=>[...e,`Maximum ${u} files allowed. Only ${t.length} files were added.`]))}else F(e)}}})),[F,c,f,u]);return e.useEffect((()=>{"multiple"===c&&U.current.length>0&&E()}),[c,E,w]),{acceptedFiles:w,errors:y,getRootProps:A,getInputProps:z,removeFile:O,uploadFile:M,isDragActive:g,isValidatingFiles:C,restartUpload:R}}; | ||
"use strict";var e=require("react"),t=require("uuid"),r=require("axios");function i(e,t,r,i){return new(r||(r=Promise))((function(a,n){function s(e){try{l(i.next(e))}catch(e){n(e)}}function o(e){try{l(i.throw(e))}catch(e){n(e)}}function l(e){var t;e.done?a(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,o)}l((i=i.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;exports.useUpload=({action:a,globalConfig:n={},metadata:s={},onUploadStart:o,onUploadComplete:l,onError:d,headers:c})=>{const{mode:u="multiple",maxFiles:p=3,maxFileSize:g=10737418240,allowedFileTypes:f=["*/*"],maxConcurrentUploads:m=5,disabled:v=!1}=n,[h,b]=e.useState(!1),[w,y]=e.useState([]),[O,j]=e.useState([]),P=e.useRef(new Map),U=e.useRef([]),C=e.useRef(new Set),[D,x]=e.useState(!1),$=e.useCallback((e=>new Promise(((t,r)=>{const i=e.type||"",a=f.some((e=>{if(e.endsWith("*")){const t=e.slice(0,-1);return i.startsWith(t)}return i===e}));if(a&&(i.startsWith("image/")||f.includes("image/*"))){const i=new FileReader;i.onloadend=()=>{t({imagePreview:i.result})},i.onerror=r,i.readAsDataURL(e)}else if(a&&(f.includes("video/*")||f.includes(i)||f.some((e=>e.startsWith("video/")&&e===i)))){const i=document.createElement("video");i.preload="metadata";const a=URL.createObjectURL(e);i.onloadedmetadata=()=>{const e=document.createElement("canvas");e.width=i.videoWidth||320,e.height=i.videoHeight||240;const r=e.getContext("2d");null==r||r.drawImage(i,0,0,e.width,e.height),URL.revokeObjectURL(a),t({videoPreview:a})},i.onerror=r,i.src=a}else t({})}))),[f]),S=e.useCallback((e=>f.some((t=>{if(t.endsWith("*")){const r=t.slice(0,-1);return e.type.startsWith(r)}return e.type===t}))?e.size>g?{valid:!1,error:`File too large: ${e.name}. Max size: ${g/1048576}MB`}:"single"===u&&w.length>=1?{valid:!1,error:"Only one file allowed in single mode"}:"multiple"===u&&w.length>=p?{valid:!1,error:`Maximum ${p} files allowed`}:{valid:!0}:{valid:!1,error:`Invalid file type: ${e.type}. Allowed types: ${f.join(", ")}`}),[f,g,u,p,w]),k=(e,t)=>i(void 0,void 0,void 0,(function*(){const{method:i="POST",body:a,headers:n={"Content-Type":"multipart/form-data"},signal:s,startByte:o=0,fileId:l,onUploadProgress:d}=t,c=a instanceof FormData?Array.from(a.values()).reduce(((e,t)=>e+(t instanceof Blob?t.size:new Blob([t]).size)),0):a.size;return r({url:e,method:i,data:a,headers:Object.assign({},n),signal:s&&s.aborted?s:void 0,onUploadProgress:e=>{const t=e.loaded+o,r=Math.min(Math.round(t/c*100),100);y((e=>e.map((e=>e.id===l?Object.assign(Object.assign({},e),{state:Object.assign(Object.assign({},e.state),{progress:r})}):e)))),null==d||d({loaded:t,total:c,progress:r})}}).then((e=>e)).catch((e=>{if(r.isCancel(e))throw new Error("Upload aborted");throw e}))})),E=e.useCallback((e=>i(void 0,void 0,void 0,(function*(){if(v)return;const t=w.findIndex((t=>t.id===e));if(-1===t)return;const r=w[t];if(["uploading","completed"].includes(r.state.status))return;const i=new AbortController;P.current.set(e,i);try{y((t=>t.map((t=>t.id===e?Object.assign(Object.assign({},t),{state:Object.assign(Object.assign({},t.state),{status:"uploading",progress:0,errors:[]})}):t))));const t=new FormData;t.append("file",r.file);const n=yield k(a,{method:"POST",body:t,headers:Object.assign({},c),signal:i.signal,fileId:e,onUploadProgress:t=>{y((r=>r.map((r=>r.id===e?Object.assign(Object.assign({},r),{state:Object.assign(Object.assign({},r.state),{progress:t.progress,status:100===t.progress?"completed":"uploading"})}):r))))}});if("object"==typeof n&&null!==n&&"status"in n){if(!n)throw new Error(`Upload failed with status: ${n}`)}else if("string"==typeof n)throw new Error("Unexpected response format");return null==l||l(n.data),n}catch(t){throw y((r=>r.map((r=>r.id===e?Object.assign(Object.assign({},r),{state:Object.assign(Object.assign({},r.state),{status:"error",progress:0,errors:[t.message||"Upload failed"]})}):r)))),null==d||d(t,r),t}finally{P.current.delete(e)}}))),[w,a,l,d,k,v]),M=e.useCallback((()=>i(void 0,void 0,void 0,(function*(){if("single"!==u)for(;U.current.length>0;){const e=U.current.filter((e=>{const t=w.find((t=>t.id===e));return"pending"===(null==t?void 0:t.state.status)&&!C.current.has(e)}));if(0===e.length)break;const t=m-C.current.size;if(t<=0){yield new Promise((e=>setTimeout(e,100)));continue}e.slice(0,t).forEach((e=>i(void 0,void 0,void 0,(function*(){if(!C.current.has(e)){C.current.add(e);try{yield E(e)}catch(e){}finally{C.current.delete(e),U.current=U.current.filter((t=>t!==e))}}})))),yield new Promise((e=>setTimeout(e,100)))}}))),[E,m,w]),F=e.useCallback((e=>i(void 0,void 0,void 0,(function*(){x(!0);try{const r=e=>`${e.name}-${e.size}-${e.lastModified}`,a=Array.from(new Map(e.map((e=>[r(e),e]))).values()),n=new Set(w.map((e=>r(e.file)))),l=a.filter((e=>!n.has(r(e))));if("single"===u){if(l.length>1)return void j((e=>[...e,"Only one file can be selected in single mode."]));if(w.length>0){const e=w[0].id,t=P.current.get(e);t&&(t.abort(),P.current.delete(e))}if(0===l.length)return;const e=l[0],{imagePreview:r,videoPreview:i}=yield $(e);y([{id:t.v4(),file:e,previewUrl:r,videoPreviewUrl:i,state:{status:"idle",progress:0,errors:[]},metadata:Object.assign({},s)}])}else{if(w.length+l.length>p){const e=l.slice(0,p-w.length);j((t=>[...t,`Maximum ${p} files allowed. Only ${e.length} files were added.`])),l.splice(0,e.length)}const e=yield Promise.all(l.map((e=>i(void 0,void 0,void 0,(function*(){const{imagePreview:r,videoPreview:i}=yield $(e),a=S(e);return a.valid?{fileState:{id:t.v4(),file:e,previewUrl:r,videoPreviewUrl:i,state:{status:"pending",progress:0,errors:[]},metadata:Object.assign({},s)}}:{error:a.error||"Validation failed"}}))))),r=e.filter((e=>void 0!==e.error)).map((e=>e.error)),a=e.filter((e=>void 0!==e.fileState)).map((e=>e.fileState));r.length>0&&j((e=>[...e,...r])),y((e=>(U.current=[...U.current,...a.map((e=>e.id))],null==o||o(a),M(),[...e,...a])))}}finally{x(!1)}}))),[S,s,o,M,w,u,p,$]),R=e.useCallback((e=>{const t=P.current.get(e);if(t){try{t.abort()}catch(t){console.warn(`Error aborting upload for file ${e}:`,t)}P.current.delete(e)}y((t=>t.filter((t=>t.id!==e))))}),[]),A=e.useCallback((e=>{y((t=>t.map((t=>t.id===e?Object.assign(Object.assign({},t),{state:Object.assign(Object.assign({},t.state),{status:"pending",progress:0,errors:[]})}):t)))),E(e)}),[E]),z=e.useCallback((()=>v?{onDragEnter:e=>{e.preventDefault(),e.stopPropagation()},onDragLeave:e=>{e.preventDefault(),e.stopPropagation()},onDragOver:e=>{e.preventDefault(),e.stopPropagation()},onDrop:e=>{e.preventDefault(),e.stopPropagation()},onClick:()=>{}}:{onDragEnter:e=>{e.preventDefault(),e.stopPropagation(),b(!0)},onDragLeave:e=>{e.preventDefault(),e.stopPropagation(),b(!1)},onDragOver:e=>{e.preventDefault(),e.stopPropagation(),h||b(!0)},onDrop:e=>{e.preventDefault(),e.stopPropagation(),b(!1);const t=Array.from(e.dataTransfer.files);if("multiple"===u&&t.length+w.length>p){const e=t.slice(0,p-w.length);F(e),j((t=>[...t,`Maximum ${p} files allowed. Only ${e.length} files were added.`]))}else F(t)},onClick:()=>{const e=document.createElement("input");e.type="file",e.multiple="multiple"===u,e.max="multiple"===u?p.toString():"1",e.accept=f.join(","),e.onchange=e=>{const t=e.target;if(t.files){const e=Array.from(t.files);if("multiple"===u&&e.length>p){const t=e.slice(0,p);F(t),j((e=>[...e,`Maximum ${p} files allowed. Only ${t.length} files were added.`]))}else F(e)}},e.click()}}),[F,u,f,p,w,h,v]),L=e.useCallback((()=>v?{type:"file",multiple:!1,accept:"",max:"0",onChange:()=>{}}:{type:"file",multiple:"multiple"===u,accept:f.join(","),max:"multiple"===u?p.toString():"1",onChange:e=>{const t=e.target;if(t.files){const e=Array.from(t.files);if("multiple"===u&&e.length>p){const t=e.slice(0,p);F(t),j((e=>[...e,`Maximum ${p} files allowed. Only ${t.length} files were added.`]))}else F(e)}}}),[F,u,f,p,v]);return e.useEffect((()=>{"multiple"===u&&U.current.length>0&&M()}),[u,M,w]),{acceptedFiles:w,errors:O,getRootProps:z,getInputProps:L,removeFile:R,uploadFile:E,isDragActive:h,isValidatingFiles:D,restartUpload:A,disabled:v}}; | ||
//# sourceMappingURL=index.js.map |
@@ -35,2 +35,3 @@ interface getRootFileZoneProps { | ||
allowedFileTypes?: string[]; | ||
disabled?: boolean; | ||
}; | ||
@@ -53,3 +54,4 @@ metadata?: Record<string, any>; | ||
restartUpload: (fileId: string) => void; | ||
disabled: boolean; | ||
}; | ||
export {}; |
{ | ||
"name": "react-filezone", | ||
"version": "0.1.1", | ||
"version": "0.2.1", | ||
"description": "filezone: A Robust, Flexible React File Upload Library with Advanced Features and Seamless User Experience", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
152933
46.93%175
8.7%