1 |
|
2 |
|
3 | export const candidateSelectors = [
|
4 | 'input',
|
5 | 'select',
|
6 | 'textarea',
|
7 | 'a[href]',
|
8 | 'button',
|
9 | '[tabindex]',
|
10 | 'audio[controls]',
|
11 | 'video[controls]',
|
12 | '[contenteditable]:not([contenteditable="false"])',
|
13 | ];
|
14 |
|
15 | function isHidden(node: any) {
|
16 |
|
17 |
|
18 | return (
|
19 | node.offsetParent === null || getComputedStyle(node).visibility === 'hidden'
|
20 | );
|
21 | }
|
22 |
|
23 | export function getAllTabbingElements(parentElem: any) {
|
24 | var tabbableNodes = parentElem.querySelectorAll(candidateSelectors.join(','));
|
25 | var onlyTabbable = [];
|
26 | for (var i = 0; i < tabbableNodes.length; i++) {
|
27 | var node = tabbableNodes[i];
|
28 | if (!node.disabled && getTabindex(node) > -1 && !isHidden(node)) {
|
29 | onlyTabbable.push(node);
|
30 | }
|
31 | }
|
32 | return onlyTabbable;
|
33 | }
|
34 |
|
35 | export function tabTrappingKey(event: any, parentElem: any) {
|
36 |
|
37 | if (!event || event.key !== 'Tab') return;
|
38 |
|
39 | if (!parentElem || !parentElem.contains) {
|
40 | if (process && process.env.NODE_ENV === 'development') {
|
41 | console.warn('focus-trap-js: parent element is not defined');
|
42 | }
|
43 | return false;
|
44 | }
|
45 |
|
46 | if (!parentElem.contains(event.target)) {
|
47 | return false;
|
48 | }
|
49 |
|
50 | var allTabbingElements = getAllTabbingElements(parentElem);
|
51 | var firstFocusableElement = allTabbingElements[0];
|
52 | var lastFocusableElement = allTabbingElements[allTabbingElements.length - 1];
|
53 |
|
54 | if (event.shiftKey && event.target === firstFocusableElement) {
|
55 | lastFocusableElement.focus();
|
56 | event.preventDefault();
|
57 | return true;
|
58 | } else if (!event.shiftKey && event.target === lastFocusableElement) {
|
59 | firstFocusableElement.focus();
|
60 | event.preventDefault();
|
61 | return true;
|
62 | }
|
63 | return false;
|
64 | }
|
65 |
|
66 | function getTabindex(node: any) {
|
67 | var tabindexAttr = parseInt(node.getAttribute('tabindex'), 10);
|
68 |
|
69 | if (!isNaN(tabindexAttr)) return tabindexAttr;
|
70 |
|
71 |
|
72 |
|
73 | if (isContentEditable(node)) return 0;
|
74 | return node.tabIndex;
|
75 | }
|
76 |
|
77 | function isContentEditable(node: any) {
|
78 | return node.getAttribute('contentEditable');
|
79 | }
|