react-filezone
Advanced tools
Comparing version
import React from 'react'; | ||
interface FileUploadConfig { | ||
chunkSize?: number; | ||
resumable?: boolean; | ||
encryption?: boolean; | ||
} | ||
interface getRootFileZoneProps { | ||
onDrop: (event: React.DragEvent<HTMLDivElement>) => void; | ||
onDragEnter: (event: React.DragEvent<HTMLDivElement>) => void; | ||
onDragLeave: (event: React.DragEvent<HTMLDivElement>) => void; | ||
onDragOver: (event: React.DragEvent<HTMLDivElement>) => void; | ||
onClick: () => void; | ||
@@ -22,2 +20,4 @@ } | ||
file: File; | ||
previewUrl?: string; | ||
videoPreviewUrl?: string; | ||
state: { | ||
@@ -27,3 +27,2 @@ status: "pending" | "uploading" | "paused" | "completed" | "error" | "cancelled" | "restarted" | "idle"; | ||
errors: string[]; | ||
uploadedBytes?: number; | ||
}; | ||
@@ -33,3 +32,2 @@ metadata?: Record<string, any>; | ||
interface UseUploadProps { | ||
id?: string; | ||
action: string; | ||
@@ -43,3 +41,2 @@ globalConfig?: { | ||
}; | ||
uploadConfig?: FileUploadConfig; | ||
metadata?: Record<string, any>; | ||
@@ -52,3 +49,3 @@ onUploadStart?: (files: FileState[]) => void; | ||
} | ||
declare const useUpload: ({ id, action, globalConfig, metadata, onUploadStart, onUploadComplete, onError, headers, }: UseUploadProps) => { | ||
declare const useUpload: ({ action, globalConfig, metadata, onUploadStart, onUploadComplete, onError, headers, }: UseUploadProps) => { | ||
acceptedFiles: FileState[]; | ||
@@ -60,2 +57,4 @@ errors: string[]; | ||
uploadFile: (fileId: string) => Promise<Response | undefined>; | ||
isDragActive: boolean; | ||
isValidatingFiles: boolean; | ||
restartUpload: (fileId: string) => void; | ||
@@ -62,0 +61,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
"use strict";var e=require("react"),t=require("uuid");exports.useUpload=({id:r,action:s,globalConfig:l={},metadata:a={},onUploadStart:n,onUploadComplete:i,onError:o,headers:d})=>{const{mode:c="multiple",maxFiles:u=3,maxFileSize:f=10737418240,allowedFileTypes:p=["*/*"],maxConcurrentUploads:m=5}=l,[g,h]=e.useState([]),[w,y]=e.useState([]),$=e.useRef(new Map),b=e.useRef([]),v=e.useRef(new Set),x=e.useCallback((e=>p.some((t=>{if(t.endsWith("*")){const r=t.slice(0,-1);return e.type.startsWith(r)}return e.type===t}))?e.size>f?{valid:!1,error:`File too large: ${e.name}. Max size: ${f/1048576}MB`}:"single"===c&&g.length>=1?{valid:!1,error:"Only one file allowed in single mode"}:"multiple"===c&&g.length>=u?{valid:!1,error:`Maximum ${u} files allowed`}:{valid:!0}:{valid:!1,error:`Invalid file type: ${e.type}. Allowed types: ${p.join(", ")}`}),[p,f,c,u,g]),C=async(e,t)=>new Promise(((r,s)=>{const l=new XMLHttpRequest,{method:a="POST",body:n,headers:i={},signal:o,startByte:d=0,onUploadProgress:c}=t;l.open(a,e,!0),Object.entries(i).forEach((([e,t])=>{l.setRequestHeader(e,t)}));const u=n instanceof FormData?Array.from(n.entries()).reduce(((e,[t,r])=>null==r?e:e+(r instanceof File?r.size:new Blob([r||""]).size)),0):n.size;l.upload&&(l.upload.onprogress=e=>{if(e.lengthComputable){const t=e.loaded+d,r=Math.min(Math.round(t/u*100),100);c?.({loaded:t,total:u,progress:r})}}),l.onload=()=>{const e=new Response(l.response,{status:l.status,statusText:l.statusText});r(e)},l.onerror=()=>s(new Error("Network error")),o&&o.addEventListener("abort",(()=>{l.abort(),s(new Error("Upload aborted"))})),l.send(n)})),M=e.useCallback((async e=>{const t=g.findIndex((t=>t.id===e));if(-1===t)return;const r=g[t];if(["uploading","completed"].includes(r.state.status))return;const l=new AbortController;$.current.set(e,l);try{h((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 a=await C(s,{method:"POST",body:t,headers:{...d},signal:l.signal,onUploadProgress:t=>{h((r=>r.map((r=>r.id===e?{...r,state:{...r.state,progress:t.progress,status:100===t.progress?"completed":"uploading"}}:r))))}});if(!a.ok)throw new Error(`HTTP error! status: ${a.status}`);return i?.(a,r),a}catch(t){throw h((r=>r.map((r=>r.id===e?{...r,state:{...r.state,status:"error",progress:0,errors:[t.message||"Upload failed"]}}:r)))),o?.(t,r),t}finally{$.current.delete(e)}}),[g,s,i,o,C]),S=e.useCallback((async()=>{if("single"!==c)for(;b.current.length>0;){const e=b.current.filter((e=>{const t=g.find((t=>t.id===e));return"pending"===t?.state.status&&!v.current.has(e)}));if(0===e.length)break;const t=m-v.current.size;if(t<=0){await new Promise((e=>setTimeout(e,100)));continue}e.slice(0,t).forEach((async e=>{if(!v.current.has(e)){v.current.add(e);try{await M(e)}catch(e){}finally{v.current.delete(e),b.current=b.current.filter((t=>t!==e))}}})),await new Promise((e=>setTimeout(e,100)))}}),[M,m,g]),k=e.useCallback((e=>{if("single"===c){if(e.length>1)return void y((e=>[...e,"Only one file can be selected in single mode."]));if(g.length>0){const e=g[0].id,t=$.current.get(e);t&&(t.abort(),$.current.delete(e))}h([{id:t.v4(),file:e[0],state:{status:"idle",progress:0,errors:[]},metadata:{...a,sectionId:r}}])}else{const s=g.length+e.length;"multiple"===c&&s>u&&(e=e.slice(0,u-g.length),s>u&&y((t=>[...t,`Maximum ${u} files allowed. Only ${e.length} files were added.`])));const l=Array.from(new Set(e.map((e=>`${e.name}-${e.size}-${e.lastModified}`))).values()).map((t=>e.find((e=>`${e.name}-${e.size}-${e.lastModified}`===t)))).filter((e=>void 0!==e)).map((e=>{const s=x(e);return s.valid?{file:e,fileState:{id:t.v4(),file:e,state:{status:"pending",progress:0,errors:[]},metadata:{...a,sectionId:r}}}:{error:s.error}})),i=l.filter((e=>"error"in e)).map((e=>e.error));i.length>0&&y((e=>[...e,...i])),h((e=>{const t=new Set(e.map((e=>`${e.file.name}-${e.file.size}-${e.file.lastModified}`))),r=l.filter((e=>"fileState"in e)).map((e=>e.fileState)).filter((e=>!t.has(`${e.file.name}-${e.file.size}-${e.file.lastModified}`)));return b.current=[...b.current,...r.map((e=>e.id))],n?.(r),S(),[...e,...r]}))}}),[x,a,r,n,S,g,c,u]),z=e.useCallback((e=>{const t=$.current.get(e);if(t){try{t.abort()}catch(t){console.warn(`Error aborting upload for file ${e}:`,t)}$.current.delete(e)}h((t=>t.filter((t=>t.id!==e))))}),[]),E=e.useCallback((e=>{h((t=>t.map((t=>t.id===e?{...t,state:{...t.state,status:"pending",progress:0,errors:[]}}:t)))),M(e)}),[M]),F=e.useCallback((()=>({onDrop:e=>{e.preventDefault();const t=Array.from(e.dataTransfer.files);if("multiple"===c&&t.length+g.length>u){const e=t.slice(0,u-g.length);k(e),y((t=>[...t,`Maximum ${u} files allowed. Only ${e.length} files were added.`]))}else k(t)},onClick:()=>{const e=document.createElement("input");e.type="file",e.multiple="multiple"===c,e.max="multiple"===c?u.toString():"1",e.accept=p.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);k(t),y((e=>[...e,`Maximum ${u} files allowed. Only ${t.length} files were added.`]))}else k(e)}},e.click()}})),[k,c,p,u,g]),P=e.useCallback((()=>({type:"file",multiple:"multiple"===c,accept:p.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);k(t),y((e=>[...e,`Maximum ${u} files allowed. Only ${t.length} files were added.`]))}else k(e)}}})),[k,c,p,u]);return e.useEffect((()=>{"multiple"===c&&b.current.length>0&&S()}),[c,S,g]),{acceptedFiles:g,errors:w,getRootProps:F,getInputProps:P,removeFile:z,uploadFile:M,restartUpload:E}}; | ||
"use strict";var e=require("react"),t=require("uuid");exports.useUpload=({action:r,globalConfig:a={},metadata:s={},onUploadStart:i,onUploadComplete:o,onError:l,headers:n})=>{const{mode:d="multiple",maxFiles:c=3,maxFileSize:u=10737418240,allowedFileTypes:p=["*/*"],maxConcurrentUploads:f=5}=a,[g,m]=e.useState(!1),[w,h]=e.useState([]),[v,y]=e.useState([]),P=e.useRef(new Map),b=e.useRef([]),U=e.useRef(new Set),[$,C]=e.useState(!1),x=e.useCallback((e=>new Promise(((t,r)=>{if(e.type.startsWith("image/")){const a=new FileReader;a.onloadend=()=>{t({imagePreview:a.result,videoPreview:void 0})},a.onerror=r,a.readAsDataURL(e)}else if(e.type.startsWith("video/")&&(p.includes("video/*")||p.some((e=>e.startsWith("video/"))))){const a=document.createElement("video");a.preload="metadata";const s=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);const i=e.toDataURL("image/jpeg");URL.revokeObjectURL(s),t({imagePreview:i,videoPreview:s})},a.onerror=r,a.src=s}else t({imagePreview:"",videoPreview:void 0})}))),[p]),k=e.useCallback((e=>p.some((t=>{if(t.endsWith("*")){const r=t.slice(0,-1);return e.type.startsWith(r)}return e.type===t}))?e.size>u?{valid:!1,error:`File too large: ${e.name}. Max size: ${u/1048576}MB`}:"single"===d&&w.length>=1?{valid:!1,error:"Only one file allowed in single mode"}:"multiple"===d&&w.length>=c?{valid:!1,error:`Maximum ${c} files allowed`}:{valid:!0}:{valid:!1,error:`Invalid file type: ${e.type}. Allowed types: ${p.join(", ")}`}),[p,u,d,c,w]),S=async(e,t)=>new Promise(((r,a)=>{const s=new XMLHttpRequest,{method:i="POST",body:o,headers:l={},signal:n,startByte:d=0,onUploadProgress:c}=t;s.open(i,e,!0),Object.entries(l).forEach((([e,t])=>{s.setRequestHeader(e,t)}));const u=o instanceof FormData?Array.from(o.values()).reduce(((e,t)=>e+(t instanceof Blob?t.size:new Blob([t]).size)),0):o.size;s.upload&&(s.upload.onprogress=e=>{if(e.lengthComputable){const t=e.loaded+d,r=Math.min(Math.round(t/u*100),100);c?.({loaded:t,total:u,progress:r})}}),s.onload=()=>{const e=new Response(s.response,{status:s.status,statusText:s.statusText});r(e)},s.onerror=()=>a(new Error("Network error")),n&&n.addEventListener("abort",(()=>{s.abort(),a(new Error("Upload aborted"))})),s.send(o)})),R=e.useCallback((async e=>{const t=w.findIndex((t=>t.id===e));if(-1===t)return;const a=w[t];if(["uploading","completed"].includes(a.state.status))return;const s=new AbortController;P.current.set(e,s);try{h((t=>t.map((t=>t.id===e?{...t,state:{...t.state,status:"uploading",progress:0,errors:[]}}:t))));const t=new FormData;t.append("file",a.file);const i=await S(r,{method:"POST",body:t,headers:{...n},signal:s.signal,onUploadProgress:t=>{h((r=>r.map((r=>r.id===e?{...r,state:{...r.state,progress:t.progress,status:100===t.progress?"completed":"uploading"}}:r))))}});if(!i.ok)throw new Error(`HTTP error! status: ${i.status}`);return o?.(i,a),i}catch(t){throw h((r=>r.map((r=>r.id===e?{...r,state:{...r.state,status:"error",progress:0,errors:[t.message||"Upload failed"]}}:r)))),l?.(t,a),t}finally{P.current.delete(e)}}),[w,r,o,l,S]),D=e.useCallback((async()=>{if("single"!==d)for(;b.current.length>0;){const e=b.current.filter((e=>{const t=w.find((t=>t.id===e));return"pending"===t?.state.status&&!U.current.has(e)}));if(0===e.length)break;const t=f-U.current.size;if(t<=0){await new Promise((e=>setTimeout(e,100)));continue}e.slice(0,t).forEach((async e=>{if(!U.current.has(e)){U.current.add(e);try{await R(e)}catch(e){}finally{U.current.delete(e),b.current=b.current.filter((t=>t!==e))}}})),await new Promise((e=>setTimeout(e,100)))}}),[R,f,w]),E=e.useCallback((async e=>{C(!0);try{const r=e=>`${e.name}-${e.size}-${e.lastModified}`,a=Array.from(new Map(e.map((e=>[r(e),e]))).values()),o=new Set(w.map((e=>r(e.file)))),l=a.filter((e=>!o.has(r(e))));if("single"===d){if(l.length>1)return void y((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:a}=await x(e);h([{id:t.v4(),file:e,previewUrl:r,videoPreviewUrl:a,state:{status:"idle",progress:0,errors:[]},metadata:{...s}}])}else{if(w.length+l.length>c){const e=l.slice(0,c-w.length);y((t=>[...t,`Maximum ${c} files allowed. Only ${e.length} files were added.`])),l.splice(0,e.length)}const e=await Promise.all(l.map((async e=>{const{imagePreview:r,videoPreview:a}=await x(e),i=k(e);return i.valid?{fileState:{id:t.v4(),file:e,previewUrl:r,videoPreviewUrl:a,state:{status:"pending",progress:0,errors:[]},metadata:{...s}}}:{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&&y((e=>[...e,...r])),h((e=>(b.current=[...b.current,...a.map((e=>e.id))],i?.(a),D(),[...e,...a])))}}finally{C(!1)}}),[k,s,i,D,w,d,c,x]),M=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)}h((t=>t.filter((t=>t.id!==e))))}),[]),O=e.useCallback((e=>{h((t=>t.map((t=>t.id===e?{...t,state:{...t.state,status:"pending",progress:0,errors:[]}}:t)))),R(e)}),[R]),F=e.useCallback((()=>({onDragEnter:e=>{e.preventDefault(),e.stopPropagation(),m(!0)},onDragLeave:e=>{e.preventDefault(),e.stopPropagation(),m(!1)},onDragOver:e=>{e.preventDefault(),e.stopPropagation(),g||m(!0)},onDrop:e=>{e.preventDefault(),e.stopPropagation(),m(!1);const t=Array.from(e.dataTransfer.files);if("multiple"===d&&t.length+w.length>c){const e=t.slice(0,c-w.length);E(e),y((t=>[...t,`Maximum ${c} files allowed. Only ${e.length} files were added.`]))}else E(t)},onClick:()=>{const e=document.createElement("input");e.type="file",e.multiple="multiple"===d,e.max="multiple"===d?c.toString():"1",e.accept=p.join(","),e.onchange=e=>{const t=e.target;if(t.files){const e=Array.from(t.files);if("multiple"===d&&e.length>c){const t=e.slice(0,c);E(t),y((e=>[...e,`Maximum ${c} files allowed. Only ${t.length} files were added.`]))}else E(e)}},e.click()}})),[E,d,p,c,w,g]),T=e.useCallback((()=>({type:"file",multiple:"multiple"===d,accept:p.join(","),max:"multiple"===d?c.toString():"1",onChange:e=>{const t=e.target;if(t.files){const e=Array.from(t.files);if("multiple"===d&&e.length>c){const t=e.slice(0,c);E(t),y((e=>[...e,`Maximum ${c} files allowed. Only ${t.length} files were added.`]))}else E(e)}}})),[E,d,p,c]);return e.useEffect((()=>{"multiple"===d&&b.current.length>0&&D()}),[d,D,w]),{acceptedFiles:w,errors:v,getRootProps:F,getInputProps:T,removeFile:M,uploadFile:R,isDragActive:g,isValidatingFiles:$,restartUpload:O}}; | ||
//# sourceMappingURL=index.js.map |
import React from "react"; | ||
interface FileUploadConfig { | ||
chunkSize?: number; | ||
resumable?: boolean; | ||
encryption?: boolean; | ||
} | ||
interface getRootFileZoneProps { | ||
onDrop: (event: React.DragEvent<HTMLDivElement>) => void; | ||
onDragEnter: (event: React.DragEvent<HTMLDivElement>) => void; | ||
onDragLeave: (event: React.DragEvent<HTMLDivElement>) => void; | ||
onDragOver: (event: React.DragEvent<HTMLDivElement>) => void; | ||
onClick: () => void; | ||
@@ -21,2 +19,4 @@ } | ||
file: File; | ||
previewUrl?: string; | ||
videoPreviewUrl?: string; | ||
state: { | ||
@@ -26,3 +26,2 @@ status: "pending" | "uploading" | "paused" | "completed" | "error" | "cancelled" | "restarted" | "idle"; | ||
errors: string[]; | ||
uploadedBytes?: number; | ||
}; | ||
@@ -32,3 +31,2 @@ metadata?: Record<string, any>; | ||
interface UseUploadProps { | ||
id?: string; | ||
action: string; | ||
@@ -42,3 +40,2 @@ globalConfig?: { | ||
}; | ||
uploadConfig?: FileUploadConfig; | ||
metadata?: Record<string, any>; | ||
@@ -51,3 +48,3 @@ onUploadStart?: (files: FileState[]) => void; | ||
} | ||
export declare const useUpload: ({ id, action, globalConfig, metadata, onUploadStart, onUploadComplete, onError, headers, }: UseUploadProps) => { | ||
export declare const useUpload: ({ action, globalConfig, metadata, onUploadStart, onUploadComplete, onError, headers, }: UseUploadProps) => { | ||
acceptedFiles: FileState[]; | ||
@@ -59,4 +56,6 @@ errors: string[]; | ||
uploadFile: (fileId: string) => Promise<Response | undefined>; | ||
isDragActive: boolean; | ||
isValidatingFiles: boolean; | ||
restartUpload: (fileId: string) => void; | ||
}; | ||
export {}; |
{ | ||
"name": "react-filezone", | ||
"version": "0.0.6", | ||
"version": "0.0.7", | ||
"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
99784
10.1%164
3.8%