Skip to content

Commit

Permalink
feat: add option to auto focus the root and close #1145
Browse files Browse the repository at this point in the history
  • Loading branch information
rolandjitsu committed May 2, 2022
1 parent 7a2f405 commit 1b91e50
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/index.js
Expand Up @@ -68,6 +68,7 @@ const defaultProps = {
noDragEventsBubbling: false,
validator: null,
useFsAccessApi: true,
autoFocus: false,
};

Dropzone.defaultProps = defaultProps;
Expand Down Expand Up @@ -173,6 +174,11 @@ Dropzone.propTypes = {
*/
useFsAccessApi: PropTypes.bool,

/**
* Set to true to focus the root element on render
*/
autoFocus: PropTypes.bool,

/**
* Cb for when the `dragenter` event occurs.
*
Expand Down Expand Up @@ -381,6 +387,7 @@ const initialState = {
* @param {Function} [props.onFileDialogCancel] Cb for when closing the file dialog with no selection
* @param {boolean} [props.useFsAccessApi] Set to true to use the https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API
* to open the file picker instead of using an `<input type="file">` click event.
* @param {boolean} autoFocus Set to true to auto focus the root element.
* @param {Function} [props.onFileDialogOpen] Cb for when opening the file dialog
* @param {dragCb} [props.onDragEnter] Cb for when the `dragenter` event occurs.
* @param {dragCb} [props.onDragLeave] Cb for when the `dragleave` event occurs
Expand Down Expand Up @@ -433,6 +440,7 @@ export function useDropzone(props = {}) {
onFileDialogCancel,
onFileDialogOpen,
useFsAccessApi,
autoFocus,
preventDropOnDocument,
noClick,
noKeyboard,
Expand All @@ -458,7 +466,12 @@ export function useDropzone(props = {}) {
[onFileDialogCancel]
);

/**
* @constant
* @type {React.MutableRefObject<HTMLElement>}
*/
const rootRef = useRef(null);

const inputRef = useRef(null);

const [state, dispatch] = useReducer(reducer, initialState);
Expand Down Expand Up @@ -518,6 +531,14 @@ export function useDropzone(props = {}) {
};
}, [rootRef, preventDropOnDocument]);

// Auto focus the root when autoFocus is true
useEffect(() => {
if (!disabled && autoFocus && rootRef.current) {
rootRef.current.focus();
}
return () => {};
}, [rootRef, autoFocus, disabled]);

const onErrCb = useCallback(
(e) => {
if (onError) {
Expand Down
45 changes: 45 additions & 0 deletions src/index.spec.js
Expand Up @@ -1064,6 +1064,51 @@ describe("useDropzone() hook", () => {
fireEvent.focus(dropzone);
expect(dropzone.querySelector("#focus")).not.toBeNull();
});

it("{autoFocus} sets the focus state on render", () => {
const { container, rerender } = render(
<Dropzone>
{({ getRootProps, getInputProps, isFocused }) => (
<div {...getRootProps()}>
<input {...getInputProps()} />
{isFocused && <div id="focus" />}
</div>
)}
</Dropzone>
);

const dropzone = container.querySelector("div");

expect(dropzone.querySelector("#focus")).toBeNull();

rerender(
/* eslint-disable-next-line jsx-a11y/no-autofocus */
<Dropzone autoFocus>
{({ getRootProps, getInputProps, isFocused }) => (
<div {...getRootProps()}>
<input {...getInputProps()} />
{isFocused && <div id="focus" />}
</div>
)}
</Dropzone>
);

expect(dropzone.querySelector("#focus")).not.toBeNull();

rerender(
/* eslint-disable-next-line jsx-a11y/no-autofocus */
<Dropzone autoFocus disabled>
{({ getRootProps, getInputProps, isFocused }) => (
<div {...getRootProps()}>
<input {...getInputProps()} />
{isFocused && <div id="focus" />}
</div>
)}
</Dropzone>
);

expect(dropzone.querySelector("#focus")).toBeNull();
});
});

describe("onBlur", () => {
Expand Down
1 change: 1 addition & 0 deletions typings/react-dropzone.d.ts
Expand Up @@ -52,6 +52,7 @@ export type DropzoneOptions = Pick<React.HTMLProps<HTMLElement>, PropTypes> & {
onFileDialogOpen?: () => void;
validator?: <T extends File>(file: T) => FileError | FileError[] | null;
useFsAccessApi?: boolean;
autoFocus?: boolean;
};

export type DropEvent =
Expand Down

0 comments on commit 1b91e50

Please sign in to comment.