UNPKG

6.24 kBJavaScriptView Raw
1"use strict";
2
3exports.__esModule = true;
4exports.isNodeBeforeScroll = exports.isNodeAfterScroll = exports.findVisibleParent = exports.makeNodeUnfocusable = exports.makeNodeFocusable = exports.copyAttribute = exports.setTabIndex = exports.setFocusWithoutScroll = exports.getNewContainer = exports.getBodyChildElements = exports.getFirstFocusableDescendant = exports.findScrollParents = exports.filterByFocusable = void 0;
5
6var filterByFocusable = function filterByFocusable(elements) {
7 return Array.prototype.filter.call(elements || [], function (element) {
8 var currentTag = element.tagName.toLowerCase();
9 var validTags = /(svg|a|area|input|select|textarea|button|iframe|div)$/;
10 var isValidTag = currentTag.match(validTags) && element.focus;
11
12 if (currentTag === 'a') {
13 return isValidTag && element.childNodes.length > 0 && element.getAttribute('href');
14 }
15
16 if (currentTag === 'svg' || currentTag === 'div') {
17 return isValidTag && element.hasAttribute('tabindex') && element.getAttribute('tabindex') !== '-1';
18 }
19
20 return isValidTag;
21 });
22};
23
24exports.filterByFocusable = filterByFocusable;
25
26var findScrollParents = function findScrollParents(element, horizontal) {
27 var result = [];
28
29 if (element) {
30 var parent = element.parentNode;
31
32 while (parent && parent.getBoundingClientRect) {
33 var rect = parent.getBoundingClientRect(); // 10px is to account for borders and scrollbars in a lazy way
34
35 if (horizontal) {
36 if (rect.width && parent.scrollWidth > rect.width + 10) {
37 result.push(parent);
38 }
39 } else if (rect.height && parent.scrollHeight > rect.height + 10) {
40 result.push(parent);
41 }
42
43 parent = parent.parentNode;
44 } // last scrollable element will be the document
45 // if nothing else is scrollable in the page
46
47
48 if (result.length === 0) {
49 result.push(document);
50 }
51 }
52
53 return result;
54};
55
56exports.findScrollParents = findScrollParents;
57
58var getFirstFocusableDescendant = function getFirstFocusableDescendant(element) {
59 var children = element.getElementsByTagName('*');
60
61 for (var i = 0; i < children.length; i += 1) {
62 var child = children[i];
63 var tagName = child.tagName.toLowerCase();
64
65 if (tagName === 'input' || tagName === 'select') {
66 return child;
67 }
68 }
69
70 return undefined;
71};
72
73exports.getFirstFocusableDescendant = getFirstFocusableDescendant;
74
75var getBodyChildElements = function getBodyChildElements() {
76 var excludeMatch = /^(script|link)$/i;
77 var children = [];
78 [].forEach.call(document.body.children, function (node) {
79 if (!excludeMatch.test(node.tagName)) {
80 children.push(node);
81 }
82 });
83 return children;
84};
85
86exports.getBodyChildElements = getBodyChildElements;
87
88var getNewContainer = function getNewContainer() {
89 // setup DOM
90 var container = document.createElement('div');
91 document.body.appendChild(container);
92 return container;
93};
94
95exports.getNewContainer = getNewContainer;
96
97var setFocusWithoutScroll = function setFocusWithoutScroll(element) {
98 var x = window.scrollX;
99 var y = window.scrollY;
100 element.focus();
101 window.scrollTo(x, y);
102};
103
104exports.setFocusWithoutScroll = setFocusWithoutScroll;
105
106var setTabIndex = function setTabIndex(tabIndex) {
107 return function (element) {
108 element.setAttribute('tabindex', tabIndex);
109 };
110};
111
112exports.setTabIndex = setTabIndex;
113
114var copyAttribute = function copyAttribute(source) {
115 return function (target) {
116 return function (element) {
117 element.setAttribute(target, element.getAttribute(source));
118 };
119 };
120};
121
122exports.copyAttribute = copyAttribute;
123
124var deleteAttribute = function deleteAttribute(attribute) {
125 return function (element) {
126 return element.removeAttribute(attribute);
127 };
128};
129
130var unsetTabIndex = setTabIndex(-1);
131var saveTabIndex = copyAttribute('tabindex')('data-g-tabindex');
132var restoreTabIndex = copyAttribute('data-g-tabindex')('tabindex');
133var deleteTabIndex = deleteAttribute('tabindex');
134var deleteTabIndexCopy = deleteAttribute('data-g-tabindex');
135
136var makeNodeFocusable = function makeNodeFocusable(node) {
137 // do not touch aria live containers so that announcements work
138 if (!node.hasAttribute('aria-live')) {
139 node.setAttribute('aria-hidden', false); // allow children to receive focus again
140
141 filterByFocusable(node.getElementsByTagName('*')).forEach(function (child) {
142 if (child.hasAttribute('data-g-tabindex')) {
143 restoreTabIndex(child);
144 } else {
145 deleteTabIndex(child);
146 }
147
148 deleteTabIndexCopy(child);
149 });
150 }
151};
152
153exports.makeNodeFocusable = makeNodeFocusable;
154
155var makeNodeUnfocusable = function makeNodeUnfocusable(node) {
156 // do not touch aria live containers so that announcements work
157 if (!node.hasAttribute('aria-live')) {
158 node.setAttribute('aria-hidden', true); // prevent children to receive focus
159
160 filterByFocusable(node.getElementsByTagName('*')).forEach(function (child) {
161 if (child.hasAttribute('tabindex')) {
162 saveTabIndex(child);
163 }
164
165 unsetTabIndex(child);
166 });
167 }
168};
169
170exports.makeNodeUnfocusable = makeNodeUnfocusable;
171
172var findVisibleParent = function findVisibleParent(element) {
173 if (element) {
174 return element.offsetParent ? element : findVisibleParent(element.parentElement) || element;
175 }
176
177 return undefined;
178};
179
180exports.findVisibleParent = findVisibleParent;
181
182var isNodeAfterScroll = function isNodeAfterScroll(node, target) {
183 if (target === void 0) {
184 target = window;
185 }
186
187 var _node$getBoundingClie = node.getBoundingClientRect(),
188 bottom = _node$getBoundingClie.bottom;
189
190 var _target$getBoundingCl = target.getBoundingClientRect(),
191 height = _target$getBoundingCl.height,
192 top = _target$getBoundingCl.top;
193
194 return bottom >= top + height;
195};
196
197exports.isNodeAfterScroll = isNodeAfterScroll;
198
199var isNodeBeforeScroll = function isNodeBeforeScroll(node, target) {
200 if (target === void 0) {
201 target = window;
202 }
203
204 var _node$getBoundingClie2 = node.getBoundingClientRect(),
205 top = _node$getBoundingClie2.top;
206
207 var _target$getBoundingCl2 = target.getBoundingClientRect(),
208 targetTop = _target$getBoundingCl2.top;
209
210 return top <= targetTop;
211};
212
213exports.isNodeBeforeScroll = isNodeBeforeScroll;
\No newline at end of file