react-dropzone
Advanced tools
Comparing version
@@ -40,3 +40,3 @@ var _excluded = ["children"], | ||
import { fromEvent } from "file-selector"; | ||
import { allFilesAccepted, composeEventHandlers, fileAccepted, fileMatchSize, filePickerOptionsTypes, canUseFileSystemAccessAPI, isEvtWithFiles, isIeOrEdge, isPropagationStopped, onDocumentDragOver, TOO_MANY_FILES_REJECTION } from "./utils/index"; | ||
import { allFilesAccepted, composeEventHandlers, fileAccepted, fileMatchSize, filePickerOptionsTypes, canUseFileSystemAccessAPI, isAbort, isEvtWithFiles, isIeOrEdge, isPropagationStopped, isSecurityError, onDocumentDragOver, TOO_MANY_FILES_REJECTION } from "./utils/index"; | ||
/** | ||
@@ -469,7 +469,8 @@ * Convenience wrapper component for the `useDropzone` hook | ||
isFileDialogActive = state.isFileDialogActive, | ||
draggedFiles = state.draggedFiles; // Update file dialog active state when the window is focused on | ||
draggedFiles = state.draggedFiles; | ||
var fsAccessApiWorksRef = useRef(window.isSecureContext && useFsAccessApi && canUseFileSystemAccessAPI()); // Update file dialog active state when the window is focused on | ||
var onWindowFocus = function onWindowFocus() { | ||
// Execute the timeout only if the file dialog is opened in the browser | ||
if (isFileDialogActive) { | ||
if (!fsAccessApiWorksRef.current && isFileDialogActive) { | ||
setTimeout(function () { | ||
@@ -491,6 +492,2 @@ if (inputRef.current) { | ||
useEffect(function () { | ||
if (window.isSecureContext && useFsAccessApi && canUseFileSystemAccessAPI()) { | ||
return function () {}; | ||
} | ||
window.addEventListener("focus", onWindowFocus, false); | ||
@@ -500,3 +497,3 @@ return function () { | ||
}; | ||
}, [inputRef, isFileDialogActive, onFileDialogCancelCb, useFsAccessApi]); | ||
}, [inputRef, isFileDialogActive, onFileDialogCancelCb, fsAccessApiWorksRef]); | ||
var dragTargetsRef = useRef([]); | ||
@@ -692,3 +689,3 @@ | ||
// https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#feature_detection | ||
if (window.isSecureContext && useFsAccessApi && canUseFileSystemAccessAPI()) { | ||
if (fsAccessApiWorksRef.current) { | ||
dispatch({ | ||
@@ -706,9 +703,22 @@ type: "openDialog" | ||
}).then(function (files) { | ||
return setFiles(files, null); | ||
}).catch(function (e) { | ||
return onFileDialogCancelCb(e); | ||
}).finally(function () { | ||
return dispatch({ | ||
setFiles(files, null); | ||
dispatch({ | ||
type: "closeDialog" | ||
}); | ||
}).catch(function (e) { | ||
// AbortError means the user canceled | ||
if (isAbort(e)) { | ||
onFileDialogCancelCb(e); | ||
dispatch({ | ||
type: "closeDialog" | ||
}); | ||
} else if (isSecurityError(e)) { | ||
fsAccessApiWorksRef.current = false; // CORS, so cannot use this API | ||
// Try using the input | ||
if (inputRef.current) { | ||
inputRef.current.value = null; | ||
inputRef.current.click(); | ||
} | ||
} | ||
}); | ||
@@ -738,3 +748,3 @@ return; | ||
} | ||
}, [rootRef, inputRef, openFileDialog]); // Update focus state for the dropzone | ||
}, [rootRef, openFileDialog]); // Update focus state for the dropzone | ||
@@ -765,3 +775,3 @@ var onFocusCb = useCallback(function () { | ||
} | ||
}, [inputRef, noClick, openFileDialog]); | ||
}, [noClick, openFileDialog]); | ||
@@ -768,0 +778,0 @@ var composeHandler = function composeHandler(fn) { |
@@ -205,2 +205,24 @@ 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; } | ||
}]; | ||
} | ||
/** | ||
* Check if v is an exception caused by aborting a request (e.g window.showOpenFilePicker()). | ||
* | ||
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMException. | ||
* @param {any} v | ||
* @returns {boolean} True if v is an abort exception. | ||
*/ | ||
export function isAbort(v) { | ||
return v instanceof DOMException && (v.name === "AbortError" || v.code === v.ABORT_ERR); | ||
} | ||
/** | ||
* Check if v is a security error. | ||
* | ||
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMException. | ||
* @param {any} v | ||
* @returns {boolean} True if v is a security error. | ||
*/ | ||
export function isSecurityError(v) { | ||
return v instanceof DOMException && (v.name === "SecurityError" || v.code === v.SECURITY_ERR); | ||
} |
@@ -174,3 +174,3 @@ { | ||
"typings": "typings/react-dropzone.d.ts", | ||
"version": "12.0.2", | ||
"version": "12.0.3", | ||
"engines": { | ||
@@ -177,0 +177,0 @@ "node": ">= 10.13" |
@@ -21,5 +21,7 @@ /* eslint prefer-template: 0 */ | ||
canUseFileSystemAccessAPI, | ||
isAbort, | ||
isEvtWithFiles, | ||
isIeOrEdge, | ||
isPropagationStopped, | ||
isSecurityError, | ||
onDocumentDragOver, | ||
@@ -455,6 +457,10 @@ TOO_MANY_FILES_REJECTION, | ||
const fsAccessApiWorksRef = useRef( | ||
window.isSecureContext && useFsAccessApi && canUseFileSystemAccessAPI() | ||
); | ||
// Update file dialog active state when the window is focused on | ||
const onWindowFocus = () => { | ||
// Execute the timeout only if the file dialog is opened in the browser | ||
if (isFileDialogActive) { | ||
if (!fsAccessApiWorksRef.current && isFileDialogActive) { | ||
setTimeout(() => { | ||
@@ -473,10 +479,2 @@ if (inputRef.current) { | ||
useEffect(() => { | ||
if ( | ||
window.isSecureContext && | ||
useFsAccessApi && | ||
canUseFileSystemAccessAPI() | ||
) { | ||
return () => {}; | ||
} | ||
window.addEventListener("focus", onWindowFocus, false); | ||
@@ -486,3 +484,3 @@ return () => { | ||
}; | ||
}, [inputRef, isFileDialogActive, onFileDialogCancelCb, useFsAccessApi]); | ||
}, [inputRef, isFileDialogActive, onFileDialogCancelCb, fsAccessApiWorksRef]); | ||
@@ -691,7 +689,3 @@ const dragTargetsRef = useRef([]); | ||
// https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#feature_detection | ||
if ( | ||
window.isSecureContext && | ||
useFsAccessApi && | ||
canUseFileSystemAccessAPI() | ||
) { | ||
if (fsAccessApiWorksRef.current) { | ||
dispatch({ type: "openDialog" }); | ||
@@ -707,5 +701,21 @@ onFileDialogOpenCb(); | ||
.then((handles) => getFilesFromEvent(handles)) | ||
.then((files) => setFiles(files, null)) | ||
.catch((e) => onFileDialogCancelCb(e)) | ||
.finally(() => dispatch({ type: "closeDialog" })); | ||
.then((files) => { | ||
setFiles(files, null); | ||
dispatch({ type: "closeDialog" }); | ||
}) | ||
.catch((e) => { | ||
// AbortError means the user canceled | ||
if (isAbort(e)) { | ||
onFileDialogCancelCb(e); | ||
dispatch({ type: "closeDialog" }); | ||
} else if (isSecurityError(e)) { | ||
fsAccessApiWorksRef.current = false; | ||
// CORS, so cannot use this API | ||
// Try using the input | ||
if (inputRef.current) { | ||
inputRef.current.value = null; | ||
inputRef.current.click(); | ||
} | ||
} | ||
}); | ||
return; | ||
@@ -743,3 +753,3 @@ } | ||
}, | ||
[rootRef, inputRef, openFileDialog] | ||
[rootRef, openFileDialog] | ||
); | ||
@@ -769,3 +779,3 @@ | ||
} | ||
}, [inputRef, noClick, openFileDialog]); | ||
}, [noClick, openFileDialog]); | ||
@@ -772,0 +782,0 @@ const composeHandler = (fn) => { |
@@ -206,1 +206,29 @@ import accepts from "attr-accept"; | ||
} | ||
/** | ||
* Check if v is an exception caused by aborting a request (e.g window.showOpenFilePicker()). | ||
* | ||
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMException. | ||
* @param {any} v | ||
* @returns {boolean} True if v is an abort exception. | ||
*/ | ||
export function isAbort(v) { | ||
return ( | ||
v instanceof DOMException && | ||
(v.name === "AbortError" || v.code === v.ABORT_ERR) | ||
); | ||
} | ||
/** | ||
* Check if v is a security error. | ||
* | ||
* See https://developer.mozilla.org/en-US/docs/Web/API/DOMException. | ||
* @param {any} v | ||
* @returns {boolean} True if v is a security error. | ||
*/ | ||
export function isSecurityError(v) { | ||
return ( | ||
v instanceof DOMException && | ||
(v.name === "SecurityError" || v.code === v.SECURITY_ERR) | ||
); | ||
} |
@@ -429,2 +429,56 @@ beforeEach(() => { | ||
describe("isAbort()", () => { | ||
let utils; | ||
beforeEach(async () => { | ||
utils = await import("./index"); | ||
}); | ||
it("should work as expected", () => { | ||
expect(utils.isAbort(new DOMException())).toBe(false); | ||
expect(utils.isAbort(new DOMException("some err"))).toBe(false); | ||
expect(utils.isAbort(new DOMException("some err", "Noop"))).toBe(false); | ||
expect(utils.isAbort(new DOMException("some err", "AbortError"))).toBe( | ||
true | ||
); | ||
const err = new DOMException("some err"); | ||
const e = new Proxy(err, { | ||
get(t, p) { | ||
if (p === "code") { | ||
return 20; | ||
} | ||
return t[p]; | ||
}, | ||
}); | ||
expect(utils.isAbort(e)).toBe(true); | ||
}); | ||
}); | ||
describe("isSecurityError()", () => { | ||
let utils; | ||
beforeEach(async () => { | ||
utils = await import("./index"); | ||
}); | ||
it("should work as expected", () => { | ||
expect(utils.isSecurityError(new DOMException())).toBe(false); | ||
expect(utils.isSecurityError(new DOMException("some err"))).toBe(false); | ||
expect(utils.isSecurityError(new DOMException("some err", "Noop"))).toBe( | ||
false | ||
); | ||
expect( | ||
utils.isSecurityError(new DOMException("some err", "SecurityError")) | ||
).toBe(true); | ||
const err = new DOMException("some err"); | ||
const e = new Proxy(err, { | ||
get(t, p) { | ||
if (p === "code") { | ||
return 18; | ||
} | ||
return t[p]; | ||
}, | ||
}); | ||
expect(utils.isSecurityError(e)).toBe(true); | ||
}); | ||
}); | ||
function createFile(name, size, type) { | ||
@@ -431,0 +485,0 @@ const file = new File([], name, { type }); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
414534
2.29%6602
3.22%