Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-dropzone

Package Overview
Dependencies
Maintainers
3
Versions
189
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-dropzone - npm Package Compare versions

Comparing version 11.5.3 to 11.6.0

.husky/commit-msg

272

dist/es/index.js

@@ -26,5 +26,5 @@ var _excluded = ["children"],

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }

@@ -41,3 +41,3 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

import { fromEvent } from 'file-selector';
import { allFilesAccepted, composeEventHandlers, fileAccepted, fileMatchSize, isEvtWithFiles, isIeOrEdge, isPropagationStopped, onDocumentDragOver, TOO_MANY_FILES_REJECTION } from './utils/index';
import { allFilesAccepted, composeEventHandlers, fileAccepted, fileMatchSize, filePickerOptionsTypes, canUseFileSystemAccessAPI, isEvtWithFiles, isIeOrEdge, isPropagationStopped, onDocumentDragOver, TOO_MANY_FILES_REJECTION } from './utils/index';
/**

@@ -444,2 +444,8 @@ * Convenience wrapper component for the `useDropzone` hook

var onFileDialogOpenCb = useMemo(function () {
return typeof onFileDialogOpen === 'function' ? onFileDialogOpen : noop;
}, [onFileDialogOpen]);
var onFileDialogCancelCb = useMemo(function () {
return typeof onFileDialogCancel === 'function' ? onFileDialogCancel : noop;
}, [onFileDialogCancel]);
var rootRef = useRef(null);

@@ -455,19 +461,4 @@ var inputRef = useRef(null);

isFileDialogActive = state.isFileDialogActive,
draggedFiles = state.draggedFiles; // Fn for opening the file dialog programmatically
draggedFiles = state.draggedFiles; // Update file dialog active state when the window is focused on
var openFileDialog = useCallback(function () {
if (inputRef.current) {
dispatch({
type: 'openDialog'
});
if (typeof onFileDialogOpen === 'function') {
onFileDialogOpen();
}
inputRef.current.value = null;
inputRef.current.click();
}
}, [dispatch, onFileDialogOpen]); // Update file dialog active state when the window is focused on
var onWindowFocus = function onWindowFocus() {

@@ -484,6 +475,3 @@ // Execute the timeout only if the file dialog is opened in the browser

});
if (typeof onFileDialogCancel === 'function') {
onFileDialogCancel();
}
onFileDialogCancelCb();
}

@@ -496,2 +484,6 @@ }

useEffect(function () {
if (canUseFileSystemAccessAPI()) {
return function () {};
}
window.addEventListener('focus', onWindowFocus, false);

@@ -501,41 +493,3 @@ return function () {

};
}, [inputRef, isFileDialogActive, onFileDialogCancel]); // Cb to open the file dialog when SPACE/ENTER occurs on the dropzone
var onKeyDownCb = useCallback(function (event) {
// Ignore keyboard events bubbling up the DOM tree
if (!rootRef.current || !rootRef.current.isEqualNode(event.target)) {
return;
}
if (event.keyCode === 32 || event.keyCode === 13) {
event.preventDefault();
openFileDialog();
}
}, [rootRef, inputRef, openFileDialog]); // Update focus state for the dropzone
var onFocusCb = useCallback(function () {
dispatch({
type: 'focus'
});
}, []);
var onBlurCb = useCallback(function () {
dispatch({
type: 'blur'
});
}, []); // Cb to open the file dialog when click occurs on the dropzone
var onClickCb = useCallback(function () {
if (noClick) {
return;
} // In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
// to ensure React can handle state changes
// See: https://github.com/react-dropzone/react-dropzone/issues/450
if (isIeOrEdge()) {
setTimeout(openFileDialog, 0);
} else {
openFileDialog();
}
}, [inputRef, noClick, openFileDialog]);
}, [inputRef, isFileDialogActive, onFileDialogCancelCb]);
var dragTargetsRef = useRef([]);

@@ -643,2 +597,65 @@

}, [rootRef, onDragLeave, noDragEventsBubbling]);
var setFiles = useCallback(function (files, event) {
var acceptedFiles = [];
var fileRejections = [];
files.forEach(function (file) {
var _fileAccepted = fileAccepted(file, accept),
_fileAccepted2 = _slicedToArray(_fileAccepted, 2),
accepted = _fileAccepted2[0],
acceptError = _fileAccepted2[1];
var _fileMatchSize = fileMatchSize(file, minSize, maxSize),
_fileMatchSize2 = _slicedToArray(_fileMatchSize, 2),
sizeMatch = _fileMatchSize2[0],
sizeError = _fileMatchSize2[1];
var customErrors = validator ? validator(file) : null;
if (accepted && sizeMatch && !customErrors) {
acceptedFiles.push(file);
} else {
var errors = [acceptError, sizeError];
if (customErrors) {
errors = errors.concat(customErrors);
}
fileRejections.push({
file: file,
errors: errors.filter(function (e) {
return e;
})
});
}
});
if (!multiple && acceptedFiles.length > 1 || multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles) {
// Reject everything and empty accepted files
acceptedFiles.forEach(function (file) {
fileRejections.push({
file: file,
errors: [TOO_MANY_FILES_REJECTION]
});
});
acceptedFiles.splice(0);
}
dispatch({
acceptedFiles: acceptedFiles,
fileRejections: fileRejections,
type: 'setFiles'
});
if (onDrop) {
onDrop(acceptedFiles, fileRejections, event);
}
if (fileRejections.length > 0 && onDropRejected) {
onDropRejected(fileRejections, event);
}
if (acceptedFiles.length > 0 && onDropAccepted) {
onDropAccepted(acceptedFiles, event);
}
}, [dispatch, multiple, accept, minSize, maxSize, maxFiles, onDrop, onDropAccepted, onDropRejected, validator]);
var onDropCb = useCallback(function (event) {

@@ -657,71 +674,84 @@ event.preventDefault(); // Persist here because we need the event later after getFilesFromEvent() is done

var acceptedFiles = [];
var fileRejections = [];
files.forEach(function (file) {
var _fileAccepted = fileAccepted(file, accept),
_fileAccepted2 = _slicedToArray(_fileAccepted, 2),
accepted = _fileAccepted2[0],
acceptError = _fileAccepted2[1];
setFiles(files, event);
});
}
var _fileMatchSize = fileMatchSize(file, minSize, maxSize),
_fileMatchSize2 = _slicedToArray(_fileMatchSize, 2),
sizeMatch = _fileMatchSize2[0],
sizeError = _fileMatchSize2[1];
dispatch({
type: 'reset'
});
}, [getFilesFromEvent, setFiles, noDragEventsBubbling]); // Fn for opening the file dialog programmatically
var customErrors = validator ? validator(file) : null;
var openFileDialog = useCallback(function () {
if (canUseFileSystemAccessAPI()) {
dispatch({
type: 'openDialog'
});
onFileDialogOpenCb(); // https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
if (accepted && sizeMatch && !customErrors) {
acceptedFiles.push(file);
} else {
var errors = [acceptError, sizeError];
var opts = {
multiple: multiple,
types: filePickerOptionsTypes(accept)
};
window.showOpenFilePicker(opts).then(function (handles) {
return getFilesFromEvent(handles);
}).then(function (files) {
return setFiles(files, null);
}).catch(function (e) {
return onFileDialogCancelCb(e);
}).finally(function () {
return dispatch({
type: 'closeDialog'
});
});
return;
}
if (customErrors) {
errors = errors.concat(customErrors);
}
if (inputRef.current) {
dispatch({
type: 'openDialog'
});
onFileDialogOpenCb();
inputRef.current.value = null;
inputRef.current.click();
}
}, [dispatch, onFileDialogOpenCb, onFileDialogCancelCb, setFiles, accept, multiple]); // Cb to open the file dialog when SPACE/ENTER occurs on the dropzone
fileRejections.push({
file: file,
errors: errors.filter(function (e) {
return e;
})
});
}
});
var onKeyDownCb = useCallback(function (event) {
// Ignore keyboard events bubbling up the DOM tree
if (!rootRef.current || !rootRef.current.isEqualNode(event.target)) {
return;
}
if (!multiple && acceptedFiles.length > 1 || multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles) {
// Reject everything and empty accepted files
acceptedFiles.forEach(function (file) {
fileRejections.push({
file: file,
errors: [TOO_MANY_FILES_REJECTION]
});
});
acceptedFiles.splice(0);
}
if (event.keyCode === 32 || event.keyCode === 13) {
event.preventDefault();
openFileDialog();
}
}, [rootRef, inputRef, openFileDialog]); // Update focus state for the dropzone
dispatch({
acceptedFiles: acceptedFiles,
fileRejections: fileRejections,
type: 'setFiles'
});
var onFocusCb = useCallback(function () {
dispatch({
type: 'focus'
});
}, []);
var onBlurCb = useCallback(function () {
dispatch({
type: 'blur'
});
}, []); // Cb to open the file dialog when click occurs on the dropzone
if (onDrop) {
onDrop(acceptedFiles, fileRejections, event);
}
var onClickCb = useCallback(function () {
if (noClick) {
return;
} // In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
// to ensure React can handle state changes
// See: https://github.com/react-dropzone/react-dropzone/issues/450
if (fileRejections.length > 0 && onDropRejected) {
onDropRejected(fileRejections, event);
}
if (acceptedFiles.length > 0 && onDropAccepted) {
onDropAccepted(acceptedFiles, event);
}
});
if (isIeOrEdge()) {
setTimeout(openFileDialog, 0);
} else {
openFileDialog();
}
}, [inputRef, noClick, openFileDialog]);
dispatch({
type: 'reset'
});
}, [multiple, accept, minSize, maxSize, maxFiles, getFilesFromEvent, onDrop, onDropAccepted, onDropRejected, noDragEventsBubbling, validator]);
var composeHandler = function composeHandler(fn) {

@@ -838,3 +868,3 @@ return disabled ? null : fn;

case 'openDialog':
return _objectSpread(_objectSpread({}, state), {}, {
return _objectSpread(_objectSpread({}, initialState), {}, {
isFileDialogActive: true

@@ -871,2 +901,4 @@ });

function noop() {}
export { ErrorCode } from './utils';

@@ -1,3 +0,9 @@

function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

@@ -169,2 +175,32 @@

};
}
/**
* canUseFileSystemAccessAPI checks if the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API)
* is supported by the browser.
* @returns {boolean}
*/
export function canUseFileSystemAccessAPI() {
return 'showOpenFilePicker' in window;
}
/**
* filePickerOptionsTypes returns the {types} option for https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
* based on the accept attr (see https://github.com/react-dropzone/attr-accept)
* E.g: converts ['image/*', 'text/*'] to {'image/*': [], 'text/*': []}
* @param {string|string[]} accept
*/
export function filePickerOptionsTypes(accept) {
accept = typeof accept === 'string' ? accept.split(',') : accept;
return [{
description: 'everything',
// TODO: Need to handle filtering more elegantly than this!
accept: Array.isArray(accept) // Accept just MIME types as per spec
// NOTE: accept can be https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers
? accept.filter(function (item) {
return item === 'audio/*' || item === 'video/*' || item === 'image/*' || item === 'text/*' || /\w+\/[-+.\w]+/g.test(item);
}).reduce(function (a, b) {
return _objectSpread(_objectSpread({}, a), {}, _defineProperty({}, b, []));
}, {}) : {}
}];
}

@@ -89,3 +89,3 @@ If you'd like to prevent drag events propagation from the child to parent, you can use the `{noDragEventsBubbling}` property on the child:

Note that you can prevent the default behavior for click and keyboard events if you omit the input:
Or you can prevent the default behavior for both click and keyboard events if you omit the input:
```jsx harmony

@@ -115,2 +115,4 @@ import React from 'react';

**NOTE** If the browser supports the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API), removing the `<input>` has no effect.
If you'd like to selectively turn off the default dropzone behavior for drag events, use the `{noDrag}` property:

@@ -117,0 +119,0 @@ ```jsx harmony

@@ -8,5 +8,5 @@ {

"scripts": {
"ci": "git-cz",
"cz": "git-cz",
"clean": "rimraf ./dist",
"build": "npm run clean && npm run build:umd && npm run build:es",
"build": "yarn clean && yarn build:umd && yarn build:es",
"build:umd": "cross-env NODE_ENV=es rollup -c",

@@ -16,8 +16,10 @@ "build:es": "cross-env BABEL_ENV=es babel ./src --out-dir ./dist/es --ignore '**/*.spec.js'",

"styleguide": "styleguidist build",
"test": "cross-env NODE_ENV=test npm run eslint:src && jest --coverage && npm run typescript",
"test": "cross-env NODE_ENV=test yarn eslint:src && jest --coverage && yarn typescript",
"test:watch": "cross-env NODE_ENV=test jest --watch",
"eslint:src": "eslint .",
"commitmsg": "commitlint -e",
"precommit": "lint-staged",
"prepublish": "npm run build && npm run size",
"prepublish": "yarn build && yarn size",
"_postinstall": "husky install",
"prepublishOnly": "pinst --disable",
"postpublish": "pinst --enable",
"logo": "cd logo && sketchtool export artboards logo.sketch",

@@ -41,14 +43,18 @@ "imagemin": "imagemin --out-dir=logo --plugin=pngquant --plugin=svgo",

"*.js": [
"eslint --fix",
"git add"
"eslint --fix"
],
"*.ts": [
"tslint"
"eslint ."
],
"*.{svg,png}": [
"imagemin",
"git add"
"imagemin"
]
},
"config": {
"commitizen": {
"path": "@commitlint/prompt"
}
},
"jest": {
"testEnvironment": "jsdom",
"clearMocks": true,

@@ -97,81 +103,78 @@ "setupFilesAfterEnv": [

"dependencies": {
"attr-accept": "^2.2.1",
"file-selector": "^0.2.2",
"prop-types": "^15.7.2"
"attr-accept": "^2.2.2",
"file-selector": "^0.4.0",
"prop-types": "^15.8.1"
},
"devDependencies": {
"@babel/cli": "^7.11.6",
"@babel/core": "^7.11.6",
"@babel/plugin-external-helpers": "^7.10.4",
"@babel/plugin-proposal-do-expressions": "^7.10.4",
"@babel/plugin-proposal-export-default-from": "^7.10.4",
"@babel/plugin-proposal-logical-assignment-operators": "^7.11.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
"@babel/plugin-proposal-pipeline-operator": "^7.10.5",
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"@babel/preset-react": "^7.10.4",
"@babel/register": "^7.11.5",
"@commitlint/cli": "^9.1.2",
"@commitlint/config-angular": "^9.1.2",
"@commitlint/prompt": "^9.1.2",
"@commitlint/prompt-cli": "^9.1.2",
"@size-limit/preset-small-lib": "^4.5.7",
"@testing-library/dom": "^8.0.0",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^12.0.0",
"@testing-library/react-hooks": "^7.0.0",
"@babel/cli": "^7.16.8",
"@babel/core": "^7.16.12",
"@babel/eslint-parser": "^7.16.5",
"@babel/plugin-external-helpers": "^7.16.7",
"@babel/plugin-proposal-do-expressions": "^7.16.7",
"@babel/plugin-proposal-export-default-from": "^7.16.7",
"@babel/plugin-proposal-logical-assignment-operators": "^7.16.7",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
"@babel/plugin-proposal-optional-chaining": "^7.16.7",
"@babel/plugin-proposal-pipeline-operator": "^7.16.7",
"@babel/plugin-transform-runtime": "^7.16.10",
"@babel/preset-env": "^7.16.11",
"@babel/preset-react": "^7.16.7",
"@babel/register": "^7.16.9",
"@commitlint/cli": "^16.1.0",
"@commitlint/config-angular": "^16.0.0",
"@commitlint/prompt": "^16.1.0",
"@commitlint/prompt-cli": "^16.1.0",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.1.3",
"@size-limit/preset-small-lib": "^7.0.5",
"@size-limit/webpack": "^7.0.5",
"@size-limit/webpack-why": "^7.0.5",
"@testing-library/dom": "^8.11.3",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/react-hooks": "^7.0.2",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"babel-eslint": "10.x",
"babel-jest": "^26.3.0",
"babel-plugin-add-module-exports": "^1.0.2",
"@typescript-eslint/eslint-plugin": "^5.10.1",
"@typescript-eslint/parser": "^5.10.1",
"babel-jest": "^27.4.6",
"babel-plugin-add-module-exports": "^1.0.4",
"babel-plugin-dynamic-import-node": "^2.3.3",
"commitizen": "^4.2.1",
"cross-env": "^7.0.2",
"eslint": "7.x",
"eslint-config-okonet": "^7.0.2",
"eslint-config-prettier": "6.x",
"eslint-plugin-import": "2.x",
"eslint-plugin-jsx-a11y": "6.x",
"eslint-plugin-node": "11.x",
"eslint-plugin-prettier": "3.x",
"eslint-plugin-react": "7.x",
"eslint-plugin-react-hooks": "4.x",
"husky": "^4.2.5",
"imagemin-cli": "^6.0.0",
"imagemin-pngquant": "^9.0.0",
"jest": "^26.4.2",
"lint-staged": "^10.3.0",
"markdownlint-cli": "^0.23.2",
"prettier": "*",
"commitizen": "^4.2.4",
"cross-env": "^7.0.3",
"eslint": "^8.8.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"husky": "^7.0.4",
"imagemin-cli": "^7.0.0",
"imagemin-pngquant": "^9.0.2",
"jest": "^27.4.7",
"lint-staged": "^12.3.2",
"markdownlint-cli": "^0.30.0",
"pinst": "^2.1.6",
"prettier": "^2.5.1",
"react": "^17.0.0",
"react-dom": "^17.0.0",
"react-styleguidist": "^11.0.10",
"react-styleguidist": "^11.2.0",
"react-test-renderer": "^17.0.0",
"rimraf": "^3.0.2",
"rollup": "^2.26.10",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-uglify": "^6.0.4",
"sinon": "^9.0.3",
"size-limit": "^4.5.7",
"style-loader": "^1.2.1",
"styled-components": "^5.2.0",
"tslint": "^6.1.3",
"rollup": "^2.66.1",
"rollup-plugin-terser": "^7.0.2",
"size-limit": "^7.0.5",
"style-loader": "^3.3.1",
"styled-components": "^5.3.3",
"typescript": "^4.0.2",
"webpack": "^4.44.1",
"webpack": "^5.67.0",
"webpack-blocks": "^2.1.0"
},
"typings": "typings/react-dropzone.d.ts",
"config": {
"commitizen": {
"path": "@commitlint/prompt"
}
},
"version": "11.5.3",
"version": "11.6.0",
"engines": {
"node": ">= 10"
"node": ">= 10.13"
},

@@ -178,0 +181,0 @@ "browserslist": [

![react-dropzone logo](https://raw.githubusercontent.com/react-dropzone/react-dropzone/master/logo/logo.png)
# react-dropzone
[![npm](https://img.shields.io/npm/v/react-dropzone.svg?style=flat-square)](https://www.npmjs.com/package/react-dropzone)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/react-dropzone/react-dropzone/Test?label=tests&style=flat-square)](https://github.com/react-dropzone/react-dropzone/actions?query=workflow%3ATest)
[![Tests](https://img.shields.io/github/workflow/status/react-dropzone/react-dropzone/Test?label=tests&style=flat-square)](https://github.com/react-dropzone/react-dropzone/actions?query=workflow%3ATest)
[![codecov](https://img.shields.io/codecov/c/gh/react-dropzone/react-dropzone/master.svg?style=flat-square)](https://codecov.io/gh/react-dropzone/react-dropzone)
[![Open Collective](https://img.shields.io/opencollective/backers/react-dropzone.svg?style=flat-square)](#backers)
[![Open Collective](https://img.shields.io/opencollective/sponsors/react-dropzone.svg?style=flat-square)](#sponsors)
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/react-dropzone/react-dropzone)
[![Open Collective Backers](https://img.shields.io/opencollective/backers/react-dropzone.svg?style=flat-square)](#backers)
[![Open Collective Sponsors](https://img.shields.io/opencollective/sponsors/react-dropzone.svg?style=flat-square)](#sponsors)
[![Gitpod](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square)](https://gitpod.io/#https://github.com/react-dropzone/react-dropzone)

@@ -18,3 +17,2 @@ Simple React hook to create a HTML5-compliant drag'n'drop zone for files.

## Installation
Install it from npm and include it in your React build process (using [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/), etc).

@@ -57,4 +55,2 @@

**IMPORTANT**: Under the hood, this lib makes use of [hooks](https://reactjs.org/docs/hooks-intro.html), therefore, using it requires React `>= 16.8`.
Or the wrapper component for the hook:

@@ -77,7 +73,4 @@ ```jsx static

If you want to access file contents you have to use the [FileReader API](https://developer.mozilla.org/en-US/docs/Web/API/FileReader):
**Warning**: On most recent browsers versions, the files given by `onDrop` won't have properties `path` or `fullPath`, see [this SO question](https://stackoverflow.com/a/23005925/2275818) and [this issue](https://github.com/react-dropzone/react-dropzone/issues/477).
Furthermore, if you want to access file contents you have to use the [FileReader API](https://developer.mozilla.org/en-US/docs/Web/API/FileReader):
```jsx static

@@ -116,3 +109,2 @@ import React, {useCallback} from 'react'

## Dropzone Props Getters
The dropzone property getters are just two functions that return objects with properties which you need to use to create the drag 'n' drop zone.

@@ -141,7 +133,9 @@ The root properties can be applied to whatever element you want, whereas the input properties must be applied to an `<input>`:

{...getRootProps({
onClick: event => console.log(event)
onClick: event => console.log(event),
role: 'button',
'aria-label': 'drag and drop area',
...
})}
/>
```
> ♿ this is also where you pass accessibility props like `role`, `aria-labelledby` ...etc.

@@ -154,6 +148,5 @@ In the example above, the provided `{onClick}` handler will be invoked before the internal one, therefore, internal callbacks can be prevented by simply using [stopPropagation](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation).

## Refs
Both `getRootProps` and `getInputProps` accept a custom `refKey` (defaults to `ref`) as one of the attributes passed down in the parameter.
This can be useful when the element you're trying to apply the props from either one of those fns does not expose a reference to the element, e.g.:
This can be useful when the element you're trying to apply the props from either one of those fns does not expose a reference to the element, e.g:

@@ -179,3 +172,3 @@ ```jsx static

If you're working with [Material UI](https://material-ui.com) and would like to apply the root props on some component that does not expose a ref, use [RootRef](https://material-ui.com/api/root-ref):
If you're working with [Material UI v4](https://v4.mui.com/) and would like to apply the root props on some component that does not expose a ref, use [RootRef](https://v4.mui.com/api/root-ref/):

@@ -200,3 +193,3 @@ ```jsx static

*Important*: do not set the `ref` prop on the elements where `getRootProps()`/`getInputProps()` props are set, instead, get the refs from the hook itself:
**IMPORTANT**: do not set the `ref` prop on the elements where `getRootProps()`/`getInputProps()` props are set, instead, get the refs from the hook itself:

@@ -243,8 +236,7 @@ ```jsx static

## Testing
*Important*: `react-dropzone` makes some of its drag 'n' drop callbacks asynchronous to enable promise based `getFilesFromEvent()` functions. In order to test components that use this library, you may want to use the [react-testing-library](https://github.com/testing-library/react-testing-library):
`react-dropzone` makes some of its drag 'n' drop callbacks asynchronous to enable promise based `getFilesFromEvent()` functions. In order to test components that use this library, you need to use the [react-testing-library](https://github.com/testing-library/react-testing-library):
```js static
import React from 'react'
import Dropzone from 'react-dropzone'
import { act, fireEvent, render, waitFor } from '@testing-library/react'
import {act, fireEvent, render, waitFor} from '@testing-library/react'

@@ -301,10 +293,70 @@ test('invoke onDragEnter when dragenter event occurs', async () => {

*Note*: using [Enzyme](https://airbnb.io/enzyme) for testing is not supported at the moment, see [#2011](https://github.com/airbnb/enzyme/issues/2011).
**NOTE**: using [Enzyme](https://airbnb.io/enzyme) for testing is not supported at the moment, see [#2011](https://github.com/airbnb/enzyme/issues/2011).
More examples for this can be found in `react-dropzone`s own [test suites](https://github.com/react-dropzone/react-dropzone/blob/master/src/index.spec.js).
More examples for this can be found in `react-dropzone`'s own [test suites](https://github.com/react-dropzone/react-dropzone/blob/master/src/index.spec.js).
## Need image editing?
## Caveats
### Required React Version
React [16.8](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html) or above is required because we use [hooks](https://reactjs.org/docs/hooks-intro.html) (the lib itself is a hook).
### File Paths
Files returned by the hook or passed as arg to the `onDrop` cb won't have the properties `path` or `fullPath`.
For more inf check [this SO question](https://stackoverflow.com/a/23005925/2275818) and [this issue](https://github.com/react-dropzone/react-dropzone/issues/477).
### Not a File Uploader
This lib is not a file uploader; as such, it does not process files or provide any way to make HTTP requests to some server; if you're looking for that, checkout [filepond](https://pqina.nl/filepond) or [uppy.io](https://uppy.io/).
### Using \<label\> as Root
If you use [\<label\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label) as the root element, the file dialog will be opened twice; see [#1107](https://github.com/react-dropzone/react-dropzone/issues/1107) why. To avoid this, use `noClick`:
```jsx static
import React, {useCallback} from 'react'
import {useDropzone} from 'react-dropzone'
function MyDropzone() {
const {getRootProps, getInputProps} = useDropzone({noClick: true})
return (
<label {...getRootProps()}>
<input {...getInputProps()} />
</label>
)
}
```
### Using open() on Click
If you bind a click event on an inner element and use `open()`, it will trigger a click on the root element too, resulting in the file dialog opening twice. To prevent this, use the `noClick` on the root:
```jsx static
import React, {useCallback} from 'react'
import {useDropzone} from 'react-dropzone'
function MyDropzone() {
const {getRootProps, getInputProps, open} = useDropzone({noClick: true})
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<button type="button" onClick={open}>
Open
</button>
</div>
)
}
```
### File Dialog Cancel Callback
The `onFileDialogCancel()` cb is unstable in most browsers, meaning, there's a good chance of it being triggered even though you have selected files.
We rely on using a timeout of `300ms` after the window is focused (the window `onfocus` event is triggered when the file select dialog is closed) to check if any files were selected and trigger `onFileDialogCancel` if none were selected.
As one can imagine, this doesn't really work if there's a lot of files or large files as by the time we trigger the check, the browser is still processing the files and no `onchange` events are triggered yet on the input. Check [#1031](https://github.com/react-dropzone/react-dropzone/issues/1031) for more info.
Fortunately, there's the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API), which is currently a working draft and some browsers support it (see [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker#browser_compatibility)), that provides a reliable way to prompt the user for file selection and capture cancellation.
And this lib makes use of it if available. Though, there's a small catch: using file extensions for the `accept` property is not supported; you must use MIME types as described in [common MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types). Also check [accepting specific file types](https://react-dropzone.js.org/#section-accepting-specific-file-types) for more info on the subject of `accept` limitations.
## Supported Browsers
We use [browserslist](https://github.com/browserslist/browserslist) config to state the browser support for this lib, so check it out on [browserslist.dev](https://browserslist.dev/?q=ZGVmYXVsdHM%3D).
## Need image editing?
React Dropzone integrates perfectly with [Pintura Image Editor](https://pqina.nl/pintura/?ref=react-dropzone), creating a modern image editing experience. Pintura supports crop aspect ratios, resizing, rotating, cropping, annotating, filtering, and much more.

@@ -314,6 +366,3 @@

## Supported Browsers
We use [browserslist](https://github.com/browserslist/browserslist) config to state the browser support for this lib, so check it out on [browserslist.dev](https://browserslist.dev/?q=ZGVmYXVsdHM%3D).
## Support

@@ -392,3 +441,2 @@

## License
MIT

@@ -1,5 +0,5 @@

const nodeResolve = require('rollup-plugin-node-resolve')
const commonjs = require('rollup-plugin-commonjs')
const babel = require('rollup-plugin-babel')
const { uglify } = require('rollup-plugin-uglify')
const { nodeResolve } = require('@rollup/plugin-node-resolve')
const commonjs = require('@rollup/plugin-commonjs')
const { babel } = require('@rollup/plugin-babel')
const { terser } = require('rollup-plugin-terser')

@@ -26,6 +26,9 @@ const umdGlobals = {

commonjs({ include: '**/node_modules/**' }),
babel({ exclude: '**/node_modules/**' }),
uglify()
babel({
exclude: '**/node_modules/**',
babelHelpers: 'bundled',
}),
terser()
]
}
]

@@ -13,3 +13,3 @@ /* eslint prefer-template: 0 */

import PropTypes from 'prop-types'
import { fromEvent } from 'file-selector'
import {fromEvent} from 'file-selector'
import {

@@ -20,2 +20,4 @@ allFilesAccepted,

fileMatchSize,
filePickerOptionsTypes,
canUseFileSystemAccessAPI,
isEvtWithFiles,

@@ -42,9 +44,9 @@ isIeOrEdge,

*/
const Dropzone = forwardRef(({ children, ...params }, ref) => {
const { open, ...props } = useDropzone(params)
const Dropzone = forwardRef(({children, ...params}, ref) => {
const {open, ...props} = useDropzone(params)
useImperativeHandle(ref, () => ({ open }), [open])
useImperativeHandle(ref, () => ({open}), [open])
// TODO: Figure out why react-styleguidist cannot create docs if we don't return a jsx element
return <Fragment>{children({ ...props, open })}</Fragment>
return <Fragment>{children({...props, open})}</Fragment>
})

@@ -164,5 +166,5 @@

/**
* Cb for when opening the file dialog
*/
/**
* Cb for when opening the file dialog
*/
onFileDialogOpen: PropTypes.func,

@@ -427,2 +429,9 @@

const onFileDialogOpenCb = useMemo(
() => typeof onFileDialogOpen === 'function' ? onFileDialogOpen : noop,
[onFileDialogOpen])
const onFileDialogCancelCb = useMemo(
() => typeof onFileDialogCancel === 'function' ? onFileDialogCancel : noop,
[onFileDialogCancel])
const rootRef = useRef(null)

@@ -432,16 +441,4 @@ const inputRef = useRef(null)

const [state, dispatch] = useReducer(reducer, initialState)
const { isFocused, isFileDialogActive, draggedFiles } = state
const {isFocused, isFileDialogActive, draggedFiles} = state
// Fn for opening the file dialog programmatically
const openFileDialog = useCallback(() => {
if (inputRef.current) {
dispatch({ type: 'openDialog' })
if (typeof onFileDialogOpen === 'function') {
onFileDialogOpen()
}
inputRef.current.value = null
inputRef.current.click()
}
}, [dispatch, onFileDialogOpen])
// Update file dialog active state when the window is focused on

@@ -453,10 +450,7 @@ const onWindowFocus = () => {

if (inputRef.current) {
const { files } = inputRef.current
const {files} = inputRef.current
if (!files.length) {
dispatch({ type: 'closeDialog' })
if (typeof onFileDialogCancel === 'function') {
onFileDialogCancel()
}
dispatch({type: 'closeDialog'})
onFileDialogCancelCb()
}

@@ -468,2 +462,6 @@ }

useEffect(() => {
if (canUseFileSystemAccessAPI()) {
return () => {}
}
window.addEventListener('focus', onWindowFocus, false)

@@ -473,44 +471,4 @@ return () => {

}
}, [inputRef, isFileDialogActive, onFileDialogCancel])
}, [inputRef, isFileDialogActive, onFileDialogCancelCb])
// Cb to open the file dialog when SPACE/ENTER occurs on the dropzone
const onKeyDownCb = useCallback(
event => {
// Ignore keyboard events bubbling up the DOM tree
if (!rootRef.current || !rootRef.current.isEqualNode(event.target)) {
return
}
if (event.keyCode === 32 || event.keyCode === 13) {
event.preventDefault()
openFileDialog()
}
},
[rootRef, inputRef, openFileDialog]
)
// Update focus state for the dropzone
const onFocusCb = useCallback(() => {
dispatch({ type: 'focus' })
}, [])
const onBlurCb = useCallback(() => {
dispatch({ type: 'blur' })
}, [])
// Cb to open the file dialog when click occurs on the dropzone
const onClickCb = useCallback(() => {
if (noClick) {
return
}
// In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
// to ensure React can handle state changes
// See: https://github.com/react-dropzone/react-dropzone/issues/450
if (isIeOrEdge()) {
setTimeout(openFileDialog, 0)
} else {
openFileDialog()
}
}, [inputRef, noClick, openFileDialog])
const dragTargetsRef = useRef([])

@@ -626,2 +584,62 @@ const onDocumentDrop = event => {

const setFiles = useCallback((files, event) => {
const acceptedFiles = []
const fileRejections = []
files.forEach(file => {
const [accepted, acceptError] = fileAccepted(file, accept)
const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize)
const customErrors = validator ? validator(file) : null;
if (accepted && sizeMatch && !customErrors) {
acceptedFiles.push(file)
} else {
let errors = [acceptError, sizeError];
if (customErrors) {
errors = errors.concat(customErrors);
}
fileRejections.push({file, errors: errors.filter(e => e)})
}
})
if ((!multiple && acceptedFiles.length > 1) || (multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles)) {
// Reject everything and empty accepted files
acceptedFiles.forEach(file => {
fileRejections.push({file, errors: [TOO_MANY_FILES_REJECTION]})
})
acceptedFiles.splice(0)
}
dispatch({
acceptedFiles,
fileRejections,
type: 'setFiles'
})
if (onDrop) {
onDrop(acceptedFiles, fileRejections, event)
}
if (fileRejections.length > 0 && onDropRejected) {
onDropRejected(fileRejections, event)
}
if (acceptedFiles.length > 0 && onDropAccepted) {
onDropAccepted(acceptedFiles, event)
}
}, [
dispatch,
multiple,
accept,
minSize,
maxSize,
maxFiles,
onDrop,
onDropAccepted,
onDropRejected,
validator
]);
const onDropCb = useCallback(

@@ -641,68 +659,87 @@ event => {

}
setFiles(files, event)
})
}
dispatch({type: 'reset'})
},
[
getFilesFromEvent,
setFiles,
noDragEventsBubbling
]
)
const acceptedFiles = []
const fileRejections = []
// Fn for opening the file dialog programmatically
const openFileDialog = useCallback(() => {
if (canUseFileSystemAccessAPI()) {
dispatch({type: 'openDialog'})
onFileDialogOpenCb()
// https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
const opts = {
multiple,
types: filePickerOptionsTypes(accept)
};
window.showOpenFilePicker(opts)
.then(handles => getFilesFromEvent(handles))
.then(files => setFiles(files, null))
.catch(e => onFileDialogCancelCb(e))
.finally(() => dispatch({type: 'closeDialog'}));
return
}
files.forEach(file => {
const [accepted, acceptError] = fileAccepted(file, accept)
const [sizeMatch, sizeError] = fileMatchSize(file, minSize, maxSize)
const customErrors = validator ? validator(file) : null;
if (inputRef.current) {
dispatch({type: 'openDialog'})
onFileDialogOpenCb()
inputRef.current.value = null
inputRef.current.click()
}
}, [
dispatch,
onFileDialogOpenCb,
onFileDialogCancelCb,
setFiles,
accept,
multiple
])
if (accepted && sizeMatch && !customErrors) {
acceptedFiles.push(file)
} else {
let errors = [acceptError, sizeError];
// Cb to open the file dialog when SPACE/ENTER occurs on the dropzone
const onKeyDownCb = useCallback(
event => {
// Ignore keyboard events bubbling up the DOM tree
if (!rootRef.current || !rootRef.current.isEqualNode(event.target)) {
return
}
if (customErrors) {
errors = errors.concat(customErrors);
}
if (event.keyCode === 32 || event.keyCode === 13) {
event.preventDefault()
openFileDialog()
}
},
[rootRef, inputRef, openFileDialog]
)
fileRejections.push({ file, errors: errors.filter(e => e) })
}
})
// Update focus state for the dropzone
const onFocusCb = useCallback(() => {
dispatch({type: 'focus'})
}, [])
const onBlurCb = useCallback(() => {
dispatch({type: 'blur'})
}, [])
if ((!multiple && acceptedFiles.length > 1) || (multiple && maxFiles >= 1 && acceptedFiles.length > maxFiles)) {
// Reject everything and empty accepted files
acceptedFiles.forEach(file => {
fileRejections.push({ file, errors: [TOO_MANY_FILES_REJECTION] })
})
acceptedFiles.splice(0)
}
// Cb to open the file dialog when click occurs on the dropzone
const onClickCb = useCallback(() => {
if (noClick) {
return
}
dispatch({
acceptedFiles,
fileRejections,
type: 'setFiles'
})
// In IE11/Edge the file-browser dialog is blocking, therefore, use setTimeout()
// to ensure React can handle state changes
// See: https://github.com/react-dropzone/react-dropzone/issues/450
if (isIeOrEdge()) {
setTimeout(openFileDialog, 0)
} else {
openFileDialog()
}
}, [inputRef, noClick, openFileDialog])
if (onDrop) {
onDrop(acceptedFiles, fileRejections, event)
}
if (fileRejections.length > 0 && onDropRejected) {
onDropRejected(fileRejections, event)
}
if (acceptedFiles.length > 0 && onDropAccepted) {
onDropAccepted(acceptedFiles, event)
}
})
}
dispatch({ type: 'reset' })
},
[
multiple,
accept,
minSize,
maxSize,
maxFiles,
getFilesFromEvent,
onDrop,
onDropAccepted,
onDropRejected,
noDragEventsBubbling,
validator
]
)
const composeHandler = fn => {

@@ -748,3 +785,3 @@ return disabled ? null : fn

[refKey]: rootRef,
...(!disabled && !noKeyboard ? { tabIndex: 0 } : {}),
...(!disabled && !noKeyboard ? {tabIndex: 0} : {}),
...rest

@@ -773,3 +810,3 @@ }),

const getInputProps = useMemo(
() => ({ refKey = 'ref', onChange, onClick, ...rest } = {}) => {
() => ({refKey = 'ref', onChange, onClick, ...rest} = {}) => {
const inputProps = {

@@ -779,3 +816,3 @@ accept,

type: 'file',
style: { display: 'none' },
style: {display: 'none'},
onChange: composeHandler(composeEventHandlers(onChange, onDropCb)),

@@ -797,3 +834,3 @@ onClick: composeHandler(composeEventHandlers(onClick, onInputElementClick)),

const fileCount = draggedFiles.length
const isDragAccept = fileCount > 0 && allFilesAccepted({ files: draggedFiles, accept, minSize, maxSize, multiple, maxFiles })
const isDragAccept = fileCount > 0 && allFilesAccepted({files: draggedFiles, accept, minSize, maxSize, multiple, maxFiles})
const isDragReject = fileCount > 0 && !isDragAccept

@@ -829,3 +866,3 @@

return {
...state,
...initialState,
isFileDialogActive: true

@@ -840,3 +877,3 @@ }

/* eslint no-case-declarations: 0 */
const { isDragActive, draggedFiles } = action
const {isDragActive, draggedFiles} = action
return {

@@ -862,2 +899,4 @@ ...state,

export { ErrorCode } from './utils'
function noop() {}
export {ErrorCode} from './utils'

@@ -69,4 +69,4 @@ import accepts from 'attr-accept'

export function allFilesAccepted({ files, accept, minSize, maxSize, multiple, maxFiles }) {
if ((!multiple && files.length > 1) || (multiple && maxFiles >= 1 && files.length > maxFiles) ) {
export function allFilesAccepted({files, accept, minSize, maxSize, multiple, maxFiles}) {
if ((!multiple && files.length > 1) || (multiple && maxFiles >= 1 && files.length > maxFiles)) {
return false;

@@ -146,1 +146,35 @@ }

}
/**
* canUseFileSystemAccessAPI checks if the [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API)
* is supported by the browser.
* @returns {boolean}
*/
export function canUseFileSystemAccessAPI() {
return 'showOpenFilePicker' in window;
}
/**
* filePickerOptionsTypes returns the {types} option for https://developer.mozilla.org/en-US/docs/Web/API/window/showOpenFilePicker
* based on the accept attr (see https://github.com/react-dropzone/attr-accept)
* E.g: converts ['image/*', 'text/*'] to {'image/*': [], 'text/*': []}
* @param {string|string[]} accept
*/
export function filePickerOptionsTypes(accept) {
accept = typeof accept === 'string' ? accept.split(',') : accept
return [{
description: 'everything',
// TODO: Need to handle filtering more elegantly than this!
accept: Array.isArray(accept)
// Accept just MIME types as per spec
// NOTE: accept can be https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers
? accept.filter(item =>
item === 'audio/*' ||
item === 'video/*' ||
item === 'image/*' ||
item === 'text/*' ||
/\w+\/[-+.\w]+/g.test(item)
).reduce((a, b) => ({...a, [b]: []}), {})
: {},
}];
}

@@ -5,8 +5,6 @@ beforeEach(() => {

describe('fileMatchSize()', () => {
let utils
beforeEach(async done => {
beforeEach(async () => {
utils = await import('./index')
done()
})

@@ -46,5 +44,4 @@

let utils
beforeEach(async done => {
beforeEach(async () => {
utils = await import('./index')
done()
})

@@ -94,5 +91,4 @@

let utils
beforeEach(async done => {
beforeEach(async () => {
utils = await import('./index')
done()
})

@@ -115,5 +111,4 @@

let utils
beforeEach(async done => {
beforeEach(async () => {
utils = await import('./index')
done()
})

@@ -152,5 +147,4 @@

let utils
beforeEach(async done => {
beforeEach(async () => {
utils = await import('./index')
done()
})

@@ -201,5 +195,4 @@

let utils
beforeEach(async done => {
beforeEach(async () => {
utils = await import('./index')
done()
})

@@ -241,5 +234,4 @@

let utils
beforeEach(async done => {
beforeEach(async () => {
utils = await import('./index')
done()
})

@@ -252,4 +244,4 @@ it('rejects file when multiple accept criteria', () => {

expect(utils.allFilesAccepted({ files, multiple: false, maxFiles: 10 })).toEqual(false)
expect(utils.allFilesAccepted({ files, multiple: true, accept:'image/jpeg' })).toEqual(false)
expect(utils.allFilesAccepted({ files: images, multiple: true,accept:'image/*' })).toEqual(true)
expect(utils.allFilesAccepted({ files, multiple: true, accept:'image/jpeg' })).toEqual(false)
expect(utils.allFilesAccepted({ files: images, multiple: true,accept:'image/*' })).toEqual(true)
expect(utils.allFilesAccepted({ files, multiple: true, minSize: 110 })).toEqual(false)

@@ -261,17 +253,6 @@ expect(utils.allFilesAccepted({ files, multiple: true, maxSize: 99 })).toEqual(false)

function createFile(name, size, type) {
const file = new File([], name, { type })
Object.defineProperty(file, 'size', {
get() {
return size
}
})
return file
}
describe('ErrorCode', () => {
let utils
beforeEach(async done => {
beforeEach(async () => {
utils = await import('./index')
done()
})

@@ -287,1 +268,83 @@

describe('canUseFileSystemAccessAPI()', () => {
let utils
beforeEach(async () => {
utils = await import('./index')
})
it('should return false if not', () => {
expect(utils.canUseFileSystemAccessAPI()).toBe(false)
})
it('should return true if yes', () => {
// TODO: If we use these in other tests, restore once test is done
window.showOpenFilePicker = jest.fn()
expect(utils.canUseFileSystemAccessAPI()).toBe(true)
})
})
describe('filePickerOptionsTypes()', () => {
let utils
beforeEach(async () => {
utils = await import('./index')
})
it('should return proper types when the arg is a MIME type', () => {
expect(utils.filePickerOptionsTypes('application/zip')).toEqual([{
description: 'everything',
accept: {'application/zip': []}
}])
})
it('should return proper types when the arg is an array of MIME types', () => {
expect(utils.filePickerOptionsTypes(['application/zip', 'application/json'])).toEqual([{
description: 'everything',
accept: {
'application/zip': [],
'application/json': []
}
}])
})
it("should exclude anything that's not a MIME type", () => {
expect(utils.filePickerOptionsTypes(['audio/*', 'video/*', 'image/*', '.txt', 'text/*'])).toEqual([{
description: 'everything',
accept: {
'audio/*': [],
'video/*': [],
'image/*': [],
'text/*': [],
}
}])
})
it("should work with comma separated string of MIME types", () => {
expect(utils.filePickerOptionsTypes('audio/*,video/*,image/*,.txt,text/*,application/zip')).toEqual([{
description: 'everything',
accept: {
'audio/*': [],
'video/*': [],
'image/*': [],
'text/*': [],
'application/zip': []
}
}])
})
it('should return empty otherwise', () => {
expect(utils.filePickerOptionsTypes('')).toEqual([{
description: 'everything',
accept: {}
}])
})
})
function createFile(name, size, type) {
const file = new File([], name, { type })
Object.defineProperty(file, 'size', {
get() {
return size
}
})
return file
}

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

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc