@empoleon/solid-dropzone
Version:
Simple HTML5 drag-drop zone with SolidJS
2 lines (1 loc) • 5.74 kB
JavaScript
import{memo as e}from"solid-js/web";import{splitProps as o,mergeProps as n,createSignal as t,createMemo as r,createEffect as i,onCleanup as a}from"solid-js";import{acceptPropAsAcceptAttr as l,pickerOptionsFromAccept as s,canUseFileSystemAccessAPI as c,onDocumentDragOver as p,composeEventHandlers as u,isAbort as d,isSecurityError as g,isEvtWithFiles as D,isPropagationStopped as f,allFilesAccepted as v,fileAccepted as m,fileMatchSize as F,isIeOrEdge as h,TOO_MANY_FILES_REJECTION as E}from"./utils/index.js";export{ErrorCode}from"./utils/index.js";import{fromEvent as y}from"./types.js";export{fromEvent}from"./types.js";const x={disabled:!1,getFilesFromEvent:y,maxSize:1/0,minSize:0,multiple:!0,maxFiles:0,preventDropOnDocument:!0,noClick:!1,noKeyboard:!1,noDrag:!1,noDragEventsBubbling:!1,useFsAccessApi:!1,autoFocus:!1},b=n=>{const[t,r]=o(n,["children","ref"]),i=w(r);t.ref&&(t.ref.open=i.open);const a=t.children;return e(()=>"function"==typeof a?a(i):a)};function w(e={}){const y=n(x,e),[b]=o(y,["accept","disabled","getFilesFromEvent","maxSize","minSize","multiple","maxFiles","onDragEnter","onDragLeave","onDragOver","onDrop","onDropAccepted","onDropRejected","onFileDialogCancel","onFileDialogOpen","useFsAccessApi","autoFocus","preventDropOnDocument","noClick","noKeyboard","noDrag","noDragEventsBubbling","onError","validator"]),[w,k]=t(!1),[A,O]=t(!1),[L,S]=t(!1),[j,z]=t(!1),[K,B]=t(!1),[P,R]=t([]),[T,I]=t([]);let q,N,G=!1;const H=r(()=>l(b.accept)),J=r(()=>s(b.accept)),M=r(()=>"function"==typeof b.onFileDialogOpen?b.onFileDialogOpen:C),Q=r(()=>"function"==typeof b.onFileDialogCancel?b.onFileDialogCancel:C);let U=[],V="undefined"!=typeof window&&window.isSecureContext&&b.useFsAccessApi&&c();const W=()=>{!V&&A()&&setTimeout(()=>{if(N){const{files:e}=N;null!=e&&e.length||(O(!1),Q()())}},300)};i(()=>{window.addEventListener("focus",W,!1),a(()=>{window.removeEventListener("focus",W,!1)})});const X=e=>{q&&q.contains(e.target)||(e.preventDefault(),U=[])};i(()=>{b.preventDropOnDocument&&(document.addEventListener("dragover",p,!1),document.addEventListener("drop",X,!1),a(()=>{document.removeEventListener("dragover",p),document.removeEventListener("drop",X)}))}),i(()=>{!b.disabled&&b.autoFocus&&q&&q.focus()});const Y=e=>{console.error("[useDropzone] Error:",e),b.onError?b.onError(e):console.error(e)},Z=e=>{e.preventDefault(),pe(e),U=[...U,e.target],D(e)&&Promise.resolve(b.getFilesFromEvent(e)).then(o=>{if(f(e)&&!b.noDragEventsBubbling)return;const n=o.length,t=n>0&&v({files:o,accept:H(),minSize:b.minSize,maxSize:b.maxSize,multiple:b.multiple,maxFiles:b.maxFiles,validator:b.validator}),r=n>0&&!t;z(t),B(r),S(!0),b.onDragEnter&&b.onDragEnter(e)}).catch(e=>Y(e))},$=e=>{e.preventDefault(),pe(e);const o=D(e);if(o&&e.dataTransfer)try{e.dataTransfer.dropEffect="copy"}catch{}return o&&b.onDragOver&&b.onDragOver(e),!1},_=e=>{e.preventDefault(),pe(e);const o=U.filter(e=>q&&q.contains(e)),n=o.indexOf(e.target);-1!==n&&o.splice(n,1),U=o,o.length>0||(S(!1),z(!1),B(!1),D(e)&&b.onDragLeave&&b.onDragLeave(e))},ee=(e,o)=>{const n=[],t=[];e.forEach(e=>{const[o,r]=m(e,H()),[i,a]=F(e,b.minSize,b.maxSize),l=b.validator?b.validator(e):null;if(o&&i&&!l)n.push(e);else{let o=[r,a].filter(e=>null!==e);l&&(o=o.concat(Array.isArray(l)?l:[l])),t.push({file:e,errors:o})}}),(!b.multiple&&n.length>1||b.multiple&&b.maxFiles>=1&&n.length>b.maxFiles)&&(n.forEach(e=>{t.push({file:e,errors:[E]})}),n.splice(0)),R(n),I(t),B(t.length>0),b.onDrop&&o&&b.onDrop(n,t,o),t.length>0&&b.onDropRejected&&o&&b.onDropRejected(t,o),n.length>0&&b.onDropAccepted&&o&&b.onDropAccepted(n,o)},oe=e=>{e.preventDefault(),pe(e),U=[],D(e)&&Promise.resolve(b.getFilesFromEvent(e)).then(o=>{f(e)&&!b.noDragEventsBubbling||ee(o,e)}).catch(e=>Y(e)),S(!1),z(!1),B(!1)},ne=()=>{if(V){O(!0),M()();const e={multiple:b.multiple,types:J()};return void window.showOpenFilePicker(e).then(e=>b.getFilesFromEvent(e)).then(e=>{ee(e,null),O(!1)}).catch(e=>{d(e)?(Q()(),O(!1)):g(e)?(V=!1,N?(N.value="",N.click()):Y(new Error("Cannot open the file picker because the File System Access API is not supported and no <input> was provided."))):Y(e)})}N&&(O(!0),M()(),N.value="",N.click())},te=e=>{q&&q.isEqualNode(e.target)&&(" "!==e.key&&"Enter"!==e.key&&32!==e.keyCode&&13!==e.keyCode||(e.preventDefault(),ne()))},re=()=>{k(!0)},ie=()=>{k(!1)},ae=()=>{b.noClick||G||(h()?setTimeout(ne,0):ne())},le=e=>b.disabled?void 0:e,se=e=>b.noKeyboard?void 0:le(e),ce=e=>b.noDrag?void 0:le(e),pe=e=>{b.noDragEventsBubbling&&e.stopPropagation()},ue=e=>{e.stopPropagation()};return{isFocused:()=>w()&&!b.disabled,isFileDialogActive:A(),isDragActive:L,isDragAccept:j,isDragReject:K,acceptedFiles:P,fileRejections:T,getRootProps:(e={})=>{const[n,t]=o(e,["refKey","role","onKeyDown","onFocus","onBlur","onClick","onDragEnter","onDragOver","onDragLeave","onDrop"]),r=n.refKey||"ref";return{onKeyDown:se(u(n.onKeyDown,te)),onFocus:se(u(n.onFocus,re)),onBlur:se(u(n.onBlur,ie)),onClick:le(u(n.onClick,ae)),onDragEnter:ce(u(n.onDragEnter,Z)),onDragOver:ce(u(n.onDragOver,$)),onDragLeave:ce(u(n.onDragLeave,_)),onDrop:ce(u(n.onDrop,oe)),role:n.role?n.role:"presentation",[r]:e=>{q=e},...b.disabled||b.noKeyboard?{}:{tabIndex:0},...t}},getInputProps:(e={})=>{const[n,t]=o(e,["refKey","onChange","onClick"]),r=n.refKey||"ref";return{...{accept:H(),multiple:b.multiple,type:"file",style:{border:"0px",clip:"rect(0, 0, 0, 0)","clip-path":"inset(50%)",height:"1px",margin:"0px -1px -1px 0px",overflow:"hidden",padding:"0px",position:"absolute",width:"1px","white-space":"nowrap"},onChange:le(u(n.onChange,oe)),onClick:le(u(n.onClick,ue)),tabIndex:-1,[r]:e=>{N=e}},...t}},rootRef:q,inputRef:N,open:()=>{b.disabled||(G=!0,ne(),setTimeout(()=>{G=!1},0))}}}function C(){}export{b as default,w as useDropzone};