-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathgetNextFocusable.js
35 lines (32 loc) · 1.44 KB
/
getNextFocusable.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* Returns next focusable DOM element
* Params:
* currentElement
* (object) DOM element - starting element for search. Returns next focused element AFTER this element.
* containing
* (bool) Default: true. Will return the next focusable item within the current element.
*/
import contains from 'dom-helpers/query/contains';
export default function getNextFocusable(currentElement, containing = true) { // eslint-disable-line consistent-return
// add all elements we want to include in our selection
// eslint-disable-next-line max-len
const focusableElements = 'a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"]), [tabIndex="-1"]:not([disabled]):focus';
let focusable = Array.prototype.filter.call(document.querySelectorAll(focusableElements),
(element) => {
// check for visibility while always include the current activeElement
return element.offsetWidth > 0 || element.offsetHeight > 0 || element === document.activeElement;
});
if (!containing) {
const outside = Array.prototype.filter.call(focusable, (element) => {
if (element === currentElement) {
return element;
}
return !contains(currentElement, element);
});
focusable = outside;
}
const index = focusable.indexOf(currentElement);
if (index > -1) {
const nextElement = focusable[index + 1] || focusable[0];
return nextElement;
}
}