@zohodesk/components 1.0.0-alpha-246 → 1.0.0-alpha-247
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/es/MultiSelect/AdvancedGroupMultiSelect.js +1 -1
- package/es/index.js +0 -4
- package/lib/MultiSelect/AdvancedGroupMultiSelect.js +1 -1
- package/lib/index.js +0 -36
- package/package.json +6 -6
- package/es/a11y/FocusScope/FocusScope.js +0 -370
- package/es/a11y/FocusScope/docs/FocusScope__default.docs.js +0 -139
- package/es/beta/FocusRing/FocusRing.js +0 -281
- package/es/beta/FocusRing/FocusRing.module.css +0 -152
- package/es/beta/FocusRing/docs/FocusRing__default.docs.js +0 -48
- package/lib/a11y/FocusScope/FocusScope.js +0 -443
- package/lib/a11y/FocusScope/docs/FocusScope__default.docs.js +0 -191
- package/lib/beta/FocusRing/FocusRing.js +0 -338
- package/lib/beta/FocusRing/FocusRing.module.css +0 -152
- package/lib/beta/FocusRing/docs/FocusRing__default.docs.js +0 -101
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
/**** Components ****/
|
|
4
4
|
|
|
5
|
-
import Loader from '@zohodesk/svg/lib/
|
|
5
|
+
import Loader from '@zohodesk/svg/lib/Loader/Loader';
|
|
6
6
|
import Popup from '../Popup/Popup';
|
|
7
7
|
import TextBoxIcon from '../TextBoxIcon/TextBoxIcon';
|
|
8
8
|
import { Container, Box } from '../Layout';
|
package/es/index.js
CHANGED
|
@@ -149,9 +149,5 @@ export { default as Provider__Zindex_For_FunctionComponent } from './Provider/do
|
|
|
149
149
|
|
|
150
150
|
export { default as SemanticButton } from './semantic/Button/Button';
|
|
151
151
|
export { default as SemanticButton__default } from './semantic/Button/docs/Button__default.docs.js';
|
|
152
|
-
export { default as FocusScope } from './a11y/FocusScope/FocusScope';
|
|
153
|
-
export { default as FocusScope__default } from './a11y/FocusScope/docs/FocusScope__default.docs';
|
|
154
|
-
export { default as FocusRing } from './beta/FocusRing/FocusRing';
|
|
155
|
-
export { default as FocusRing__default } from './beta/FocusRing/docs/FocusRing__default.docs';
|
|
156
152
|
export { default as LightNightMode__AlternativeColors } from './LightNightMode/docs/AlternativeColors.docs';
|
|
157
153
|
export { default as ResponsiveDropBox } from './ResponsiveDropBox/ResponsiveDropBox';
|
|
@@ -11,7 +11,7 @@ var _react = _interopRequireDefault(require("react"));
|
|
|
11
11
|
|
|
12
12
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
13
13
|
|
|
14
|
-
var _Loader = _interopRequireDefault(require("@zohodesk/svg/lib/
|
|
14
|
+
var _Loader = _interopRequireDefault(require("@zohodesk/svg/lib/Loader/Loader"));
|
|
15
15
|
|
|
16
16
|
var _Popup = _interopRequireDefault(require("../Popup/Popup"));
|
|
17
17
|
|
package/lib/index.js
CHANGED
|
@@ -150,10 +150,6 @@ var _exportNames = {
|
|
|
150
150
|
Provider__Zindex_For_FunctionComponent: true,
|
|
151
151
|
SemanticButton: true,
|
|
152
152
|
SemanticButton__default: true,
|
|
153
|
-
FocusScope: true,
|
|
154
|
-
FocusScope__default: true,
|
|
155
|
-
FocusRing: true,
|
|
156
|
-
FocusRing__default: true,
|
|
157
153
|
LightNightMode__AlternativeColors: true,
|
|
158
154
|
ResponsiveDropBox: true
|
|
159
155
|
};
|
|
@@ -469,30 +465,6 @@ Object.defineProperty(exports, "DropDownHeading__Heading", {
|
|
|
469
465
|
return _DropDownHeading__default["default"];
|
|
470
466
|
}
|
|
471
467
|
});
|
|
472
|
-
Object.defineProperty(exports, "FocusRing", {
|
|
473
|
-
enumerable: true,
|
|
474
|
-
get: function get() {
|
|
475
|
-
return _FocusRing["default"];
|
|
476
|
-
}
|
|
477
|
-
});
|
|
478
|
-
Object.defineProperty(exports, "FocusRing__default", {
|
|
479
|
-
enumerable: true,
|
|
480
|
-
get: function get() {
|
|
481
|
-
return _FocusRing__default["default"];
|
|
482
|
-
}
|
|
483
|
-
});
|
|
484
|
-
Object.defineProperty(exports, "FocusScope", {
|
|
485
|
-
enumerable: true,
|
|
486
|
-
get: function get() {
|
|
487
|
-
return _FocusScope["default"];
|
|
488
|
-
}
|
|
489
|
-
});
|
|
490
|
-
Object.defineProperty(exports, "FocusScope__default", {
|
|
491
|
-
enumerable: true,
|
|
492
|
-
get: function get() {
|
|
493
|
-
return _FocusScope__default["default"];
|
|
494
|
-
}
|
|
495
|
-
});
|
|
496
468
|
Object.defineProperty(exports, "GroupSelect", {
|
|
497
469
|
enumerable: true,
|
|
498
470
|
get: function get() {
|
|
@@ -1406,14 +1378,6 @@ var _Button2 = _interopRequireDefault(require("./semantic/Button/Button"));
|
|
|
1406
1378
|
|
|
1407
1379
|
var _Button__defaultDocs = _interopRequireDefault(require("./semantic/Button/docs/Button__default.docs.js"));
|
|
1408
1380
|
|
|
1409
|
-
var _FocusScope = _interopRequireDefault(require("./a11y/FocusScope/FocusScope"));
|
|
1410
|
-
|
|
1411
|
-
var _FocusScope__default = _interopRequireDefault(require("./a11y/FocusScope/docs/FocusScope__default.docs"));
|
|
1412
|
-
|
|
1413
|
-
var _FocusRing = _interopRequireDefault(require("./beta/FocusRing/FocusRing"));
|
|
1414
|
-
|
|
1415
|
-
var _FocusRing__default = _interopRequireDefault(require("./beta/FocusRing/docs/FocusRing__default.docs"));
|
|
1416
|
-
|
|
1417
1381
|
var _AlternativeColors = _interopRequireDefault(require("./LightNightMode/docs/AlternativeColors.docs"));
|
|
1418
1382
|
|
|
1419
1383
|
var _ResponsiveDropBox = _interopRequireDefault(require("./ResponsiveDropBox/ResponsiveDropBox"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zohodesk/components",
|
|
3
|
-
"version": "1.0.0-alpha-
|
|
3
|
+
"version": "1.0.0-alpha-247",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"module": "es/index.js",
|
|
6
6
|
"jsnext:main": "es/index.js",
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@zohodesk/docstool": "1.0.0-alpha-2",
|
|
39
39
|
"@zohodesk/variables": "1.0.0-beta.29",
|
|
40
|
-
"@zohodesk/icons": "1.0.0-beta.
|
|
40
|
+
"@zohodesk/icons": "1.0.0-beta.109",
|
|
41
41
|
"@zohodesk/virtualizer": "1.0.3",
|
|
42
42
|
"velocity-react": "1.4.3",
|
|
43
43
|
"react-sortable-hoc": "^0.8.3",
|
|
44
|
-
"@zohodesk/svg": "1.0.0-beta.
|
|
44
|
+
"@zohodesk/svg": "1.0.0-beta.48"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"hoist-non-react-statics": "3.0.1",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"selectn": "1.1.2"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@zohodesk/icons": "1.0.0-beta.
|
|
53
|
+
"@zohodesk/icons": "1.0.0-beta.109",
|
|
54
54
|
"@zohodesk/variables": "1.0.0-beta.29",
|
|
55
|
-
"@zohodesk/svg": "1.0.0-beta.
|
|
55
|
+
"@zohodesk/svg": "1.0.0-beta.49",
|
|
56
56
|
"@zohodesk/virtualizer": "1.0.3",
|
|
57
57
|
"velocity-react": "1.4.3",
|
|
58
58
|
"react-sortable-hoc": "^0.8.3"
|
|
@@ -72,4 +72,4 @@
|
|
|
72
72
|
"hasRTL": true
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
}
|
|
75
|
+
}
|
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
import React, { useContext, useEffect, useRef } from 'react';
|
|
2
|
-
let scopes = new Set();
|
|
3
|
-
let activeScope = null;
|
|
4
|
-
const FocusContext = /*#__PURE__*/React.createContext(null); // interface FocusManager {
|
|
5
|
-
// /** Moves focus to the next focusable or tabbable element in the focus scope. */
|
|
6
|
-
// focusNext(opts?: FocusManagerOptions): HTMLElement,
|
|
7
|
-
// /** Moves focus to the previous focusable or tabbable element in the focus scope. */
|
|
8
|
-
// focusPrevious(opts?: FocusManagerOptions): HTMLElement
|
|
9
|
-
// }
|
|
10
|
-
|
|
11
|
-
export const useLayoutEffect = window !== 'undefined' ? React.useLayoutEffect : () => {};
|
|
12
|
-
export default function FocusScope(props) {
|
|
13
|
-
let {
|
|
14
|
-
children,
|
|
15
|
-
contain = true,
|
|
16
|
-
restoreFocus = true,
|
|
17
|
-
autoFocus = true
|
|
18
|
-
} = props;
|
|
19
|
-
let startRef = useRef();
|
|
20
|
-
let endRef = useRef();
|
|
21
|
-
let scopeRef = useRef([]);
|
|
22
|
-
useLayoutEffect(() => {
|
|
23
|
-
// Find all rendered nodes between the sentinels and add them to the scope.
|
|
24
|
-
let node = startRef.current.nextSibling;
|
|
25
|
-
let nodes = [];
|
|
26
|
-
|
|
27
|
-
while (node && node !== endRef.current) {
|
|
28
|
-
nodes.push(node);
|
|
29
|
-
node = node.nextSibling;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
scopeRef.current = nodes;
|
|
33
|
-
scopes.add(scopeRef);
|
|
34
|
-
return () => {
|
|
35
|
-
scopes.delete(scopeRef);
|
|
36
|
-
};
|
|
37
|
-
}, [children]);
|
|
38
|
-
useFocusContainment(scopeRef, contain);
|
|
39
|
-
useRestoreFocus(scopeRef, restoreFocus, contain);
|
|
40
|
-
useAutoFocus(scopeRef, autoFocus);
|
|
41
|
-
let focusManager = createFocusManager(scopeRef);
|
|
42
|
-
return /*#__PURE__*/React.createElement(FocusContext.Provider, {
|
|
43
|
-
value: focusManager
|
|
44
|
-
}, /*#__PURE__*/React.createElement("span", {
|
|
45
|
-
hidden: true,
|
|
46
|
-
ref: startRef
|
|
47
|
-
}), children, /*#__PURE__*/React.createElement("span", {
|
|
48
|
-
hidden: true,
|
|
49
|
-
ref: endRef
|
|
50
|
-
}));
|
|
51
|
-
}
|
|
52
|
-
export function useFocusManager() {
|
|
53
|
-
return useContext(FocusContext);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function createFocusManager(scopeRef) {
|
|
57
|
-
return {
|
|
58
|
-
focusNext(opts) {
|
|
59
|
-
let node = opts.from || document.activeElement;
|
|
60
|
-
let focusable = getFocusableElementsInScope(scopeRef.current, opts);
|
|
61
|
-
let nextNode = focusable.find(n => !!(node.compareDocumentPosition(n) & (Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY)));
|
|
62
|
-
|
|
63
|
-
if (!nextNode && opts.wrap) {
|
|
64
|
-
nextNode = focusable[0];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (nextNode) {
|
|
68
|
-
nextNode.focus();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return nextNode;
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
focusPrevious(opts) {
|
|
75
|
-
let node = opts.from || document.activeElement;
|
|
76
|
-
let focusable = getFocusableElementsInScope(scopeRef.current, opts).reverse();
|
|
77
|
-
let previousNode = focusable.find(n => !!(node.compareDocumentPosition(n) & (Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINED_BY)));
|
|
78
|
-
|
|
79
|
-
if (!previousNode && opts.wrap) {
|
|
80
|
-
previousNode = focusable[0];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (previousNode) {
|
|
84
|
-
previousNode.focus();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return previousNode;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const focusableElements = ['input:not([disabled]):not([type=hidden])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', 'a[href]', 'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])', 'details>summary:first-of-type', 'details', 'area[href]', 'summary', 'iframe', 'object', 'embed'];
|
|
94
|
-
const FOCUSABLE_ELEMENT_SELECTOR = focusableElements.join(',') + ',[tabindex]';
|
|
95
|
-
focusableElements.push('[tabindex]:not([tabindex="-1"])');
|
|
96
|
-
const TABBABLE_ELEMENT_SELECTOR = focusableElements.join(':not([tabindex="-1"]),');
|
|
97
|
-
|
|
98
|
-
function useAutoFocus(scopeRef, autoFocus) {
|
|
99
|
-
useEffect(() => {
|
|
100
|
-
if (autoFocus) {
|
|
101
|
-
activeScope = scopeRef;
|
|
102
|
-
|
|
103
|
-
if (!isElementInScope(document.activeElement, activeScope.current)) {
|
|
104
|
-
focusFirstInScope(scopeRef.current);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}, [scopeRef, autoFocus]);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function getFocusableElementsInScope(scope, opts) {
|
|
111
|
-
let res = [],
|
|
112
|
-
response = [];
|
|
113
|
-
let selector = opts.tabbable ? TABBABLE_ELEMENT_SELECTOR : FOCUSABLE_ELEMENT_SELECTOR;
|
|
114
|
-
|
|
115
|
-
for (let node of scope) {
|
|
116
|
-
if (node.matches(selector)) {
|
|
117
|
-
res.push(node);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
response.push(...Array.from(node.querySelectorAll(selector)));
|
|
121
|
-
res = response.filter(element => {
|
|
122
|
-
return !(window.getComputedStyle(element).display === 'none');
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
;
|
|
127
|
-
return res;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function useFocusContainment(scopeRef, contain) {
|
|
131
|
-
let focusedNode = useRef();
|
|
132
|
-
let raf = useRef(null);
|
|
133
|
-
useEffect(() => {
|
|
134
|
-
let scope = scopeRef.current;
|
|
135
|
-
|
|
136
|
-
if (!contain) {
|
|
137
|
-
return;
|
|
138
|
-
} // Handle the Tab key to contain focus within the scope
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
let onKeyDown = e => {
|
|
142
|
-
if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
let elements = getFocusableElementsInScope(scope, {
|
|
147
|
-
tabbable: true
|
|
148
|
-
});
|
|
149
|
-
let focusedElement = document.activeElement;
|
|
150
|
-
|
|
151
|
-
if (!isElementInScope(focusedElement, scope)) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
let position = elements.indexOf(focusedElement);
|
|
156
|
-
let lastPosition = elements.length - 1;
|
|
157
|
-
let nextElement = null;
|
|
158
|
-
|
|
159
|
-
if (e.shiftKey) {
|
|
160
|
-
if (position <= 0) {
|
|
161
|
-
nextElement = elements[lastPosition];
|
|
162
|
-
} else {
|
|
163
|
-
nextElement = elements[position - 1];
|
|
164
|
-
}
|
|
165
|
-
} else {
|
|
166
|
-
if (position === lastPosition) {
|
|
167
|
-
nextElement = elements[0];
|
|
168
|
-
} else {
|
|
169
|
-
nextElement = elements[position + 1];
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
e.preventDefault();
|
|
174
|
-
|
|
175
|
-
if (nextElement) {
|
|
176
|
-
focusElement(nextElement, true);
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
let onFocus = e => {
|
|
181
|
-
// If a focus event occurs outside the active scope (e.g. user tabs from browser location bar),
|
|
182
|
-
// restore focus to the previously focused node or the first tabbable element in the active scope.
|
|
183
|
-
let isInAnyScope = isElementInAnyScope(e.target, scopes);
|
|
184
|
-
|
|
185
|
-
if (!isInAnyScope) {
|
|
186
|
-
if (focusedNode.current) {
|
|
187
|
-
focusedNode.current.focus();
|
|
188
|
-
} else if (activeScope) {
|
|
189
|
-
focusFirstInScope(activeScope.current);
|
|
190
|
-
}
|
|
191
|
-
} else {
|
|
192
|
-
activeScope = scopeRef;
|
|
193
|
-
focusedNode.current = e.target;
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
let onBlur = e => {
|
|
198
|
-
// Firefox doesn't shift focus back to the Dialog properly without this
|
|
199
|
-
raf.current = requestAnimationFrame(() => {
|
|
200
|
-
// Use document.activeElement instead of e.relatedTarget so we can tell if user clicked into iframe
|
|
201
|
-
let isInAnyScope = isElementInAnyScope(document.activeElement, scopes);
|
|
202
|
-
|
|
203
|
-
if (!isInAnyScope) {
|
|
204
|
-
activeScope = scopeRef;
|
|
205
|
-
focusedNode.current = e.target;
|
|
206
|
-
focusedNode.current.focus();
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
document.addEventListener('keydown', onKeyDown, false);
|
|
212
|
-
document.addEventListener('focusin', onFocus, false);
|
|
213
|
-
scope.forEach(element => element.addEventListener('focusin', onFocus, false));
|
|
214
|
-
scope.forEach(element => element.addEventListener('focusout', onBlur, false));
|
|
215
|
-
return () => {
|
|
216
|
-
document.removeEventListener('keydown', onKeyDown, false);
|
|
217
|
-
document.removeEventListener('focusin', onFocus, false);
|
|
218
|
-
scope.forEach(element => element.removeEventListener('focusin', onFocus, false));
|
|
219
|
-
scope.forEach(element => element.removeEventListener('focusout', onBlur, false));
|
|
220
|
-
};
|
|
221
|
-
}, [scopeRef, contain]); // eslint-disable-next-line arrow-body-style
|
|
222
|
-
|
|
223
|
-
useEffect(() => {
|
|
224
|
-
return () => cancelAnimationFrame(raf.current);
|
|
225
|
-
}, [raf]);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function isElementInAnyScope(element) {
|
|
229
|
-
let scopes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
230
|
-
|
|
231
|
-
for (let scope of scopes.values()) {
|
|
232
|
-
if (isElementInScope(element, scope.current)) {
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function isElementInScope(element) {
|
|
241
|
-
let scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
242
|
-
return scope.some(node => node.contains(element));
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function focusElement() {
|
|
246
|
-
let element = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
247
|
-
|
|
248
|
-
if (element != null) {
|
|
249
|
-
element.focus();
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function findElement(elements) {
|
|
254
|
-
let ele = [];
|
|
255
|
-
|
|
256
|
-
for (let element = 0; element < elements.length; element++) {
|
|
257
|
-
let elem = elements[element];
|
|
258
|
-
|
|
259
|
-
if (elem.getAttribute('data-auto-focus')) {
|
|
260
|
-
ele.push(elem);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return ele.length ? ele[0] : null;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function focusFirstInScope() {
|
|
268
|
-
let scope = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
269
|
-
let elements = getFocusableElementsInScope(scope, {
|
|
270
|
-
tabbable: true
|
|
271
|
-
});
|
|
272
|
-
let element = findElement(elements);
|
|
273
|
-
focusElement(element ? element : elements[0]);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function useRestoreFocus(scopeRef, restoreFocus, contain) {
|
|
277
|
-
// useLayoutEffect instead of useEffect so the active element is saved synchronously instead of asynchronously.
|
|
278
|
-
useLayoutEffect(() => {
|
|
279
|
-
let scope = scopeRef.current;
|
|
280
|
-
let nodeToRestore = document.activeElement; // Handle the Tab key so that tabbing out of the scope goes to the next element
|
|
281
|
-
// after the node that had focus when the scope mounted. This is important when
|
|
282
|
-
// using portals for overlays, so that focus goes to the expected element when
|
|
283
|
-
// tabbing out of the overlay.
|
|
284
|
-
|
|
285
|
-
let onKeyDown = e => {
|
|
286
|
-
if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey) {
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
let focusedElement = document.activeElement;
|
|
291
|
-
|
|
292
|
-
if (!isElementInScope(focusedElement, scope)) {
|
|
293
|
-
return;
|
|
294
|
-
} // Create a DOM tree walker that matches all tabbable elements
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
let walker = getFocusableTreeWalker(document.body, {
|
|
298
|
-
tabbable: true
|
|
299
|
-
}); // Find the next tabbable element after the currently focused element
|
|
300
|
-
|
|
301
|
-
walker.currentNode = focusedElement;
|
|
302
|
-
let nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode(); // If there is no next element, or it is outside the current scope, move focus to the
|
|
303
|
-
// next element after the node to restore to instead.
|
|
304
|
-
|
|
305
|
-
if ((!nextElement || !isElementInScope(nextElement, scope)) && nodeToRestore) {
|
|
306
|
-
walker.currentNode = nodeToRestore; // Skip over elements within the scope, in case the scope immediately follows the node to restore.
|
|
307
|
-
|
|
308
|
-
do {
|
|
309
|
-
nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
310
|
-
} while (isElementInScope(nextElement, scope));
|
|
311
|
-
|
|
312
|
-
e.preventDefault();
|
|
313
|
-
e.stopPropagation();
|
|
314
|
-
|
|
315
|
-
if (nextElement) {
|
|
316
|
-
nextElement.focus();
|
|
317
|
-
} else {
|
|
318
|
-
// If there is no next element, blur the focused element to move focus to the body.
|
|
319
|
-
focusedElement.blur();
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
if (!contain) {
|
|
325
|
-
document.addEventListener('keydown', onKeyDown, true);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return () => {
|
|
329
|
-
if (!contain) {
|
|
330
|
-
document.removeEventListener('keydown', onKeyDown, true);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (restoreFocus && nodeToRestore && isElementInScope(document.activeElement, scope)) {
|
|
334
|
-
requestAnimationFrame(() => {
|
|
335
|
-
if (document.body.contains(nodeToRestore)) {
|
|
336
|
-
focusElement(nodeToRestore);
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
}, [scopeRef, restoreFocus, contain]);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
export function getFocusableTreeWalker(root, opts) {
|
|
345
|
-
let selector = opts && opts.tabbable ? TABBABLE_ELEMENT_SELECTOR : FOCUSABLE_ELEMENT_SELECTOR;
|
|
346
|
-
let walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
|
|
347
|
-
acceptNode(node) {
|
|
348
|
-
// Skip nodes inside the starting node.
|
|
349
|
-
if (opts && opts.from && opts.from.contains(node)) {
|
|
350
|
-
return NodeFilter.FILTER_REJECT;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
if (node.matches(selector)) {
|
|
354
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
return NodeFilter.FILTER_SKIP;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
}, false);
|
|
361
|
-
|
|
362
|
-
if (opts && opts.from) {
|
|
363
|
-
walker.currentNode = opts.from;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return walker;
|
|
367
|
-
}
|
|
368
|
-
FocusScope.docs = {
|
|
369
|
-
componentGroup: 'Atom'
|
|
370
|
-
};
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import FocusScope, { useFocusManager } from '../FocusScope';
|
|
4
|
-
import style from '../../../beta/FocusRing/FocusRing.module.css';
|
|
5
|
-
export default class FocusScope__default extends React.Component {
|
|
6
|
-
constructor(props) {
|
|
7
|
-
super(props);
|
|
8
|
-
this.state = {
|
|
9
|
-
isOpen: false,
|
|
10
|
-
isSub: false
|
|
11
|
-
};
|
|
12
|
-
this.handleSubmit = this.handleSubmit.bind(this);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
handleSubmit(e, issub) {
|
|
16
|
-
this.setState({
|
|
17
|
-
isSub: issub,
|
|
18
|
-
isOpen: e
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
render() {
|
|
23
|
-
const {
|
|
24
|
-
isOpen,
|
|
25
|
-
isSub
|
|
26
|
-
} = this.state;
|
|
27
|
-
console.log(this.state);
|
|
28
|
-
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
|
|
29
|
-
className: style.primary,
|
|
30
|
-
type: "button",
|
|
31
|
-
onClick: this.handleSubmit.bind(this, true, false)
|
|
32
|
-
}, "Focusscope"), isOpen ? /*#__PURE__*/React.createElement("div", {
|
|
33
|
-
className: style.freezeLayer
|
|
34
|
-
}, /*#__PURE__*/React.createElement(FocusScope, {
|
|
35
|
-
contain: true,
|
|
36
|
-
autoFocus: true,
|
|
37
|
-
restoreFocus: true
|
|
38
|
-
}, /*#__PURE__*/React.createElement(FormContainer, {
|
|
39
|
-
onSubmit: this.handleSubmit.bind(this, true, true),
|
|
40
|
-
onCancel: this.handleSubmit.bind(this, false, false)
|
|
41
|
-
}), isSub ? /*#__PURE__*/React.createElement(FocusScope, {
|
|
42
|
-
contain: true,
|
|
43
|
-
restoreFocus: true,
|
|
44
|
-
autoFocus: true
|
|
45
|
-
}, /*#__PURE__*/React.createElement("span", {
|
|
46
|
-
className: `${style.container} ${isSub && style.box1} ${isSub && style.manage}`
|
|
47
|
-
}, /*#__PURE__*/React.createElement(ToolbarButton, null, "Cut"), /*#__PURE__*/React.createElement(ToolbarButton, null, "Copy"), /*#__PURE__*/React.createElement(ToolbarButton, null, "Paste"), /*#__PURE__*/React.createElement(ToolbarButton, {
|
|
48
|
-
onClick: this.handleSubmit.bind(this, true, false)
|
|
49
|
-
}, "Close"))) : null)) : null);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function ToolbarButton(props) {
|
|
55
|
-
const focusManager = useFocusManager();
|
|
56
|
-
|
|
57
|
-
const onKeyDown = e => {
|
|
58
|
-
switch (e.key) {
|
|
59
|
-
case 'ArrowRight':
|
|
60
|
-
focusManager.focusNext({
|
|
61
|
-
wrap: true
|
|
62
|
-
});
|
|
63
|
-
break;
|
|
64
|
-
|
|
65
|
-
case 'ArrowLeft':
|
|
66
|
-
focusManager.focusPrevious({
|
|
67
|
-
wrap: true
|
|
68
|
-
});
|
|
69
|
-
break;
|
|
70
|
-
|
|
71
|
-
default:
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const {
|
|
76
|
-
onClick,
|
|
77
|
-
children
|
|
78
|
-
} = props;
|
|
79
|
-
return /*#__PURE__*/React.createElement("button", {
|
|
80
|
-
className: style.primary,
|
|
81
|
-
type: "button",
|
|
82
|
-
onClick: onClick,
|
|
83
|
-
onKeyDown: onKeyDown
|
|
84
|
-
}, children);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
ToolbarButton.propTypes = {
|
|
88
|
-
children: PropTypes.string.isRequired,
|
|
89
|
-
onClick: PropTypes.func
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
function FormContainer(props) {
|
|
93
|
-
const {
|
|
94
|
-
onSubmit,
|
|
95
|
-
onCancel
|
|
96
|
-
} = props;
|
|
97
|
-
const options = ['apple', 'MSoffice'];
|
|
98
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
99
|
-
className: `${style.container} ${style.box1}`
|
|
100
|
-
}, /*#__PURE__*/React.createElement("button", {
|
|
101
|
-
className: style.secondary,
|
|
102
|
-
type: "button",
|
|
103
|
-
onClick: onCancel
|
|
104
|
-
}, "close"), /*#__PURE__*/React.createElement("form", {
|
|
105
|
-
className: style.formContainer
|
|
106
|
-
}, /*#__PURE__*/React.createElement("h3", null, "name"), /*#__PURE__*/React.createElement("input", {
|
|
107
|
-
type: "text",
|
|
108
|
-
value: "Input A",
|
|
109
|
-
className: `${style.input} ${style.inpFocus}`,
|
|
110
|
-
name: "name"
|
|
111
|
-
}), /*#__PURE__*/React.createElement("h3", null, "contact"), /*#__PURE__*/React.createElement("input", {
|
|
112
|
-
type: "text",
|
|
113
|
-
value: "Input A",
|
|
114
|
-
className: `${style.input} ${style.inpFocus}`,
|
|
115
|
-
name: "contact"
|
|
116
|
-
}), /*#__PURE__*/React.createElement("h3", null, "select"), /*#__PURE__*/React.createElement("select", {
|
|
117
|
-
options: options,
|
|
118
|
-
name: "select",
|
|
119
|
-
className: `${style.input} ${style.inpFocus}`
|
|
120
|
-
}, options.map((item, i) => /*#__PURE__*/React.createElement("option", {
|
|
121
|
-
key: `item-${i}`
|
|
122
|
-
}, item)))), /*#__PURE__*/React.createElement("button", {
|
|
123
|
-
className: style.primary,
|
|
124
|
-
type: "submit",
|
|
125
|
-
onClick: onSubmit
|
|
126
|
-
}, "Submit"), /*#__PURE__*/React.createElement("button", {
|
|
127
|
-
className: style.secondary,
|
|
128
|
-
type: "button",
|
|
129
|
-
onClick: onCancel
|
|
130
|
-
}, "Cancel"));
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
FormContainer.propTypes = {
|
|
134
|
-
onCancel: PropTypes.func,
|
|
135
|
-
onSubmit: PropTypes.func
|
|
136
|
-
};
|
|
137
|
-
FocusScope__default.docs = {
|
|
138
|
-
componentGroup: 'Atom'
|
|
139
|
-
};
|