-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutilities.js
121 lines (105 loc) · 3.06 KB
/
utilities.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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* @fileoverview:
* Helper functions and constants to aid a11y-related issues.
*
* @namespace FocusManager.Utilities
*/
/**
* Used to keep track of focus. Defaults to body.
* @memberof FocusManager.Utilities
* @type {HTMLElement}
* @private
*/
let _focusStorage = document.body;
/**
* Constants to prevent hardcoded logic in the actual code.
* @memberof FocusManager.Utilities
* @type {object}
* @property {{NAME: string, VALUE: string}} INERT
* @property {{NAME: string, VALUE: string}} ARIA_HIDDEN
* @property {string} SECTION_SELECTOR
*/
export const ATTRIBUTES = {
INERT: {
NAME: 'inert',
VALUE: '',
},
ARIA_HIDDEN: {
NAME: 'aria-hidden',
VALUE: 'hidden',
},
SECTION_SELECTOR: '[data-focus-section]',
};
/**
* Set the aria-hidden state to an element.
* @memberof FocusManager.Utilities
* @param {HTMLElement} element - DOM node where we set state.
* @param {boolean} flag - Whether the DOM node should be hidden.
* @see {@link https://goo.gl/qwzZk7 | Google Developers}
*/
export function ariaHidden(element, flag) {
if (flag) {
element.setAttribute(ATTRIBUTES.ARIA_HIDDEN.NAME, ATTRIBUTES.ARIA_HIDDEN.VALUE);
} else {
element.removeAttribute(ATTRIBUTES.ARIA_HIDDEN.NAME);
}
}
/**
* Apply inert to an element.
* @memberof FocusManager.Utilities
* @param {HTMLElement} element - DOM node where we set state.
* @param {boolean} flag - Whether the DOM node should have inert.
*/
export function inert(element, flag) {
if (flag) {
element.setAttribute(ATTRIBUTES.INERT.NAME, ATTRIBUTES.INERT.VALUE);
} else {
element.removeAttribute(ATTRIBUTES.INERT.NAME);
}
}
/**
* Save the currently focused element.
* Useful if you want to save and restore focus to a specific element after e.g an alert or dialog.
* @memberof FocusManager.Utilities
*/
export function saveFocus() {
_focusStorage = /** @type {HTMLElement} */ (document.activeElement);
}
/**
* Restore the focus to an element.
* @memberof FocusManager.Utilities
* @param {boolean} [waitAFrame=false] - Whether we should wait a frame before restoring
* focus to an element. Useful when dealing with toggling elements.
* @return {HTMLElement} - Returns the saved element as a convenience.
*/
export function restoreFocus(waitAFrame = false) {
if (waitAFrame) {
requestAnimationFrame(() => requestAnimationFrame(() => {
_focusStorage.focus();
return _focusStorage;
}));
} else {
_focusStorage.focus();
return _focusStorage;
}
}
/**
* Set an element to be focusable or not.
* @memberof FocusManager.Utilities
* @param {HTMLElement} element
* @param {boolean} shouldBeFocusable - Whether the element is allowed focus or not.
*/
export function focusable(element, shouldBeFocusable) {
const giveFocus = !shouldBeFocusable;
ariaHidden(element, giveFocus);
inert(element, giveFocus);
}
/**
* Whether the given element is focusable or not.
* @memberof FocusManager.Utilities
* @param {HTMLElement} element
* @return {boolean}
*/
export function isHidden(element) {
return element.hasAttribute(ATTRIBUTES.INERT.NAME);
}