Dropzone Prevent Multiple Uploads With Ctrl Click
react-dropzone
Simple React claw to create a HTML5-compliant drag'n'drib zone for files.
Documentation and examples at https://react-dropzone.js.org. Source lawmaking at https://github.com/react-dropzone/react-dropzone/.
Installation
Install it from npm and include it in your React build process (using Webpack, Browserify, etc).
npm install --salvage react-dropzone
or:
Usage
You can either apply the hook:
import React , { useCallback } from 'react' import { useDropzone } from 'react-dropzone' function MyDropzone ( ) { const onDrop = useCallback ( acceptedFiles => { // Practise something with the files } , [ ] ) const {getRootProps, getInputProps, isDragActive} = useDropzone ( {onDrop} ) render ( < div {...getRootProps ( ) } > < input {...getInputProps ( ) } / > { isDragActive ? < p >Drib the files here ...< / p > : < p >Drag 'due north' driblet some files here, or click to select files< / p > } < / div > ) }
Or the wrapper component for the hook:
import React from 'react' import Dropzone from 'react-dropzone' < Dropzone onDrop = { acceptedFiles => console . log ( acceptedFiles ) } > { ( {getRootProps, getInputProps} ) => ( < section > < div {...getRootProps ( ) } > < input {...getInputProps ( ) } / > < p >Drag 'northward' drop some files hither, or click to select files< / p > < / div > < / section > ) } < / Dropzone >
If you want to access file contents you have to employ the FileReader API:
import React , { useCallback } from 'react' import { useDropzone } from 'react-dropzone' function MyDropzone ( ) { const onDrop = useCallback ( ( acceptedFiles ) => { acceptedFiles . forEach ( ( file ) => { const reader = new FileReader ( ) reader . onabort = ( ) => console . log ( 'file reading was aborted' ) reader . onerror = ( ) => console . log ( 'file reading has failed' ) reader . onload = ( ) => { // Do whatever you want with the file contents const binaryStr = reader . result console . log ( binaryStr ) } reader . readAsArrayBuffer ( file ) } ) } , [ ] ) const {getRootProps, getInputProps} = useDropzone ( {onDrop} ) return ( < div {...getRootProps ( ) } > < input {...getInputProps ( ) } / > < p >Elevate 'north' drib some files hither, or click to select files< / p > < / div > ) }
Dropzone Props Getters
The dropzone property getters are just two functions that render objects with properties which you need to use to create the elevate 'northward' drop zone. The root backdrop tin exist applied to any element you desire, whereas the input backdrop must be applied to an <input>
:
import React from 'react' import { useDropzone } from 'react-dropzone' office MyDropzone ( ) { const {getRootProps, getInputProps} = useDropzone ( ) render ( < div {...getRootProps ( ) } > < input {...getInputProps ( ) } / > < p >Drag 'n' drop some files here, or click to select files< / p > < / div > ) }
Annotation that whatsoever other props you want to add to the element where the props from getRootProps()
are set, you should always pass them through that function rather than applying them on the element itself. This is in lodge to avoid your props beingness overridden (or overriding the props returned by getRootProps()
):
< div {...getRootProps ( { onClick: event => console . log ( event ) , function: 'button' , 'aria-label': 'drag and drop expanse' , ... } ) } / >
In the example above, the provided {onClick}
handler volition be invoked before the internal one, therefore, internal callbacks tin be prevented by only using stopPropagation. Run across Events for more examples.
Important: if you omit rendering an <input>
and/or bounden the props from getInputProps()
, opening a file dialog volition not be possible.
Refs
Both getRootProps
and getInputProps
accept a custom refKey
(defaults to ref
) as ane of the attributes passed downward in the parameter.
This tin be useful when the chemical element y'all're trying to apply the props from either one of those fns does non expose a reference to the element, e.g:
import React from 'react' import { useDropzone } from 'react-dropzone' // Annotation: After v4.0.0, styled components exposes a ref using forwardRef, // therefore, no need for using innerRef as refKey import styled from 'styled-components' const StyledDiv = styled . div ` // Some styling here ` office Example ( ) { const {getRootProps, getInputProps} = useDropzone ( ) < StyledDiv {...getRootProps ( { refKey: 'innerRef' } ) } > < input {...getInputProps ( ) } / > < p > Drag 'n' drop some files here , or click to select files < /p> < /StyledDiv> }
If y'all're working with Material UI v4 and would like to apply the root props on some component that does not betrayal a ref, apply RootRef:
import React from 'react' import { useDropzone } from 'react-dropzone' import RootRef from '@fabric-ui/core/RootRef' function PaperDropzone ( ) { const {getRootProps, getInputProps} = useDropzone ( ) const {ref, ...rootProps } = getRootProps ( ) < RootRef rootRef = {ref} > < Paper {...rootProps } > < input {...getInputProps ( ) } / > < p >Elevate 'n' drop some files here, or click to select files< / p > < / Paper > < /RootRef> }
IMPORTANT: exercise not ready the ref
prop on the elements where getRootProps()
/getInputProps()
props are ready, instead, get the refs from the hook itself:
import React from 'react' import { useDropzone } from 'react-dropzone' function Refs ( ) { const { getRootProps, getInputProps, rootRef, // Ref to the `<div>` inputRef // Ref to the `<input>` } = useDropzone ( ) < div {...getRootProps ( ) } > < input {...getInputProps ( ) } / > < p > Drag 'due north' drop some files here , or click to select files < /p> < /div > }
If y'all're using the <Dropzone>
component, though, yous tin set the ref
prop on the component itself which volition expose the {open}
prop that can exist used to open the file dialog programmatically:
import React , { createRef } from 'react' import Dropzone from 'react-dropzone' const dropzoneRef = createRef ( ) < Dropzone ref = {dropzoneRef} > { ( {getRootProps, getInputProps} ) => ( < div {...getRootProps ( ) } > < input {...getInputProps ( ) } / > < p >Drag 'north' drop some files here, or click to select files< / p > < / div > ) } < / Dropzone > dropzoneRef.open up()
Testing
react-dropzone
makes some of its drag 'n' driblet callbacks asynchronous to enable promise based getFilesFromEvent()
functions. In social club to test components that employ this library, you demand to use the react-testing-library:
import React from 'react' import Dropzone from 'react-dropzone' import { act , fireEvent , render , waitFor } from '@testing-library/react' test ( 'invoke onDragEnter when dragenter event occurs' , async ( ) => { const file = new File ( [ JSON . stringify ( { ping: true } ) ] , 'ping.json' , { type: 'application/json' } ) const data = mockData ( [ file ] ) const onDragEnter = jest . fn ( ) const ui = ( < Dropzone onDragEnter = { onDragEnter } > { ( { getRootProps, getInputProps } ) => ( < div {...getRootProps ( ) } > < input {...getInputProps ( ) } / > < / div > ) } < / Dropzone > ) const { container, rerender } = render ( ui ) const dropzone = container . querySelector ( 'div' ) dispatchEvt ( dropzone , 'dragenter' , data ) look flushPromises ( rerender , ui ) expect ( onDragEnter ) . toHaveBeenCalled ( ) } ) async function flushPromises ( rerender , ui ) { look act ( ( ) => waitFor ( ( ) => rerender ( ui ) ) ) } role dispatchEvt ( node , type , data ) { const result = new Event ( type , { bubbles: true } ) Object . assign ( result , data ) fireEvent ( node , event ) } function mockData ( files ) { return { dataTransfer: { files, items: files . map ( file => ( { kind: 'file' , blazon: file . blazon , getAsFile: ( ) => file } ) ) , types: [ 'Files' ] } } }
Note: using Enzyme for testing is not supported at the moment, see #2011.
More examples for this can be constitute in react-dropzone
'south own examination suites.
Caveats
Required React Version
React 16.8 or above is required because we use hooks (the lib itself is a claw).
File Paths
Files returned by the hook or passed every bit arg to the onDrop
cb won't have the properties path
or fullPath
. For more inf bank check this SO question and this issue.
Not a File Uploader
This lib is non a file uploader; equally such, it does not process files or provide any mode to make HTTP requests to some server; if you're looking for that, checkout filepond or uppy.io.
Using <label> as Root
If you use <label> as the root element, the file dialog will be opened twice; run across #1107 why. To avoid this, employ noClick
:
import React , { useCallback } from 'react' import { useDropzone } from 'react-dropzone' function MyDropzone ( ) { const {getRootProps, getInputProps} = useDropzone ( { noClick: true } ) return ( < label {...getRootProps ( ) } > < input {...getInputProps ( ) } / > < / characterization > ) }
Using open() on Click
If you bind a click event on an inner chemical element and use open()
, information technology volition trigger a click on the root element also, resulting in the file dialog opening twice. To preclude this, utilise the noClick
on the root:
import React , { useCallback } from 'react' import { useDropzone } from 'react-dropzone' function MyDropzone ( ) { const {getRootProps, getInputProps, open} = useDropzone ( { noClick: true } ) return ( < div {...getRootProps ( ) } > < input {...getInputProps ( ) } / > < push button type = "button" onClick = { open up } > Open < / push button > < / div > ) }
File Dialog Cancel Callback
The onFileDialogCancel()
cb is unstable in most browsers, pregnant, in that location'southward a good chance of it being triggered even though you lot have selected files.
We rely on using a timeout of 300ms
after the window is focused (the window onfocus
effect is triggered when the file select dialog is airtight) to check if any files were selected and trigger onFileDialogCancel
if none were selected.
As i can imagine, this doesn't really work if in that location's a lot of files or big files equally by the time we trigger the bank check, the browser is nevertheless processing the files and no onchange
events are triggered notwithstanding on the input. Check #1031 for more info.
Fortunately, there's the File System Access API, which is currently a working draft and some browsers support information technology (see browser compatibility), that provides a reliable manner to prompt the user for file choice and capture cancellation.
And this lib makes utilise of it if bachelor. Though, there's a small catch: using file extensions for the accept
property is not supported; you must utilise MIME types as described in common MIME types. Also check accepting specific file types for more info on the bailiwick of accept
limitations.
Also keep in heed that the FS access API can only be used in secure contexts.
NOTE You tin can disable using the FS admission API with the useFsAccessApi
property: useDropzone({useFsAccessApi: false})
.
Supported Browsers
We use browserslist config to country the browser support for this lib, so check it out on browserslist.dev.
Need epitome editing?
React Dropzone integrates perfectly with Pintura Paradigm Editor, creating a modern image editing experience. Pintura supports crop aspect ratios, resizing, rotating, cropping, annotating, filtering, and much more than.
Checkout the Pintura integration instance.
Support
Backers
Support us with a monthly donation and help united states continue our activities. [Go a backer]
Sponsors
Become a sponsor and get your logo on our README on Github with a link to your site. [Go a sponsor]
Hosting
react-dropzone.js.org hosting provided past netlify.
License
MIT
spellmanrouresing77.blogspot.com
Source: https://github.com/react-dropzone/react-dropzone
0 Response to "Dropzone Prevent Multiple Uploads With Ctrl Click"
Post a Comment