1 | import { useMemo, useRef } from 'react';
|
2 | import useEventListener from '@restart/hooks/useEventListener';
|
3 | const defaultSelector = ['input', 'textarea', 'select', 'button:not([tabindex="-1"])', '[tabindex="0"]'].join(',');
|
4 |
|
5 | const getDocument = () => document;
|
6 |
|
7 | export default function useTabTrap(ref, selector = defaultSelector) {
|
8 | const startedRef = useRef(false);
|
9 | useEventListener(getDocument, 'keydown', event => {
|
10 | if (!startedRef.current || !ref.current || event.key !== 'Tab') {
|
11 | return;
|
12 | }
|
13 |
|
14 | const tabbables = ref.current.querySelectorAll(selector);
|
15 |
|
16 | if (event.shiftKey && event.target === tabbables[0]) {
|
17 | tabbables[tabbables.length - 1].focus();
|
18 | event.preventDefault();
|
19 | } else if (!event.shiftKey && event.target === tabbables[tabbables.length - 1] || !ref.current.contains(event.target)) {
|
20 | tabbables[0].focus();
|
21 | event.preventDefault();
|
22 | }
|
23 | });
|
24 | return useMemo(() => ({
|
25 | focus() {
|
26 | const tabbables = ref.current.querySelectorAll(selector);
|
27 | const first = tabbables[0];
|
28 | if (first) first.focus();
|
29 | },
|
30 |
|
31 | start() {
|
32 | startedRef.current = true;
|
33 | },
|
34 |
|
35 | stop() {
|
36 | startedRef.current = false;
|
37 | }
|
38 |
|
39 | }), [ref, selector]);
|
40 | } |
\ | No newline at end of file |