@khanacademy/wonder-blocks-modal 2.3.5 → 2.3.6
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/CHANGELOG.md +6 -0
- package/dist/es/index.js +18 -69
- package/dist/index.js +180 -164
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +208 -208
- package/src/components/__docs__/modal-dialog.stories.js +308 -0
- package/src/components/__docs__/modal-footer.stories.js +337 -0
- package/src/components/__docs__/modal-header.argtypes.js +76 -0
- package/src/components/__docs__/modal-header.stories.js +294 -0
- package/src/components/__docs__/modal-launcher.argtypes.js +78 -0
- package/src/components/__docs__/modal-launcher.stories.js +512 -0
- package/src/components/__docs__/modal-panel.stories.js +414 -0
- package/src/components/__docs__/one-pane-dialog.argtypes.js +102 -0
- package/src/components/__docs__/one-pane-dialog.stories.js +582 -0
- package/src/components/__tests__/focus-trap.test.js +101 -0
- package/src/components/focus-trap.js +47 -98
- package/src/components/modal-footer.js +8 -0
- package/src/components/one-pane-dialog.js +26 -1
- package/src/components/one-pane-dialog.stories.js +0 -248
package/CHANGELOG.md
CHANGED
package/dist/es/index.js
CHANGED
|
@@ -205,9 +205,10 @@ const styleSheets$2 = {
|
|
|
205
205
|
})
|
|
206
206
|
};
|
|
207
207
|
|
|
208
|
+
const FOCUSABLE_ELEMENTS$1 = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
208
209
|
class FocusTrap extends React.Component {
|
|
209
|
-
constructor(
|
|
210
|
-
super(
|
|
210
|
+
constructor(...args) {
|
|
211
|
+
super(...args);
|
|
211
212
|
|
|
212
213
|
this.getModalRoot = node => {
|
|
213
214
|
if (!node) {
|
|
@@ -223,87 +224,31 @@ class FocusTrap extends React.Component {
|
|
|
223
224
|
this.modalRoot = modalRoot;
|
|
224
225
|
};
|
|
225
226
|
|
|
226
|
-
this.
|
|
227
|
-
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const target = e.target;
|
|
232
|
-
|
|
233
|
-
if (!(target instanceof Node)) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const modalRoot = this.modalRoot;
|
|
238
|
-
|
|
239
|
-
if (!modalRoot) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (modalRoot.contains(target)) {
|
|
244
|
-
this.lastNodeFocusedInModal = target;
|
|
245
|
-
} else {
|
|
246
|
-
this.focusFirstElementIn(modalRoot);
|
|
247
|
-
|
|
248
|
-
if (document.activeElement === this.lastNodeFocusedInModal) {
|
|
249
|
-
this.focusLastElementIn(modalRoot);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
this.lastNodeFocusedInModal = document.activeElement;
|
|
253
|
-
}
|
|
227
|
+
this.handleFocusMoveToLast = () => {
|
|
228
|
+
this.focusElementIn(false);
|
|
254
229
|
};
|
|
255
230
|
|
|
256
|
-
this.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
componentDidMount() {
|
|
261
|
-
window.addEventListener("focus", this.handleGlobalFocus, true);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
componentWillUnmount() {
|
|
265
|
-
window.removeEventListener("focus", this.handleGlobalFocus, true);
|
|
231
|
+
this.handleFocusMoveToFirst = () => {
|
|
232
|
+
this.focusElementIn(true);
|
|
233
|
+
};
|
|
266
234
|
}
|
|
267
235
|
|
|
268
236
|
tryToFocus(node) {
|
|
269
237
|
if (node instanceof HTMLElement) {
|
|
270
|
-
this.ignoreFocusChanges = true;
|
|
271
|
-
|
|
272
238
|
try {
|
|
273
239
|
node.focus();
|
|
274
240
|
} catch (e) {}
|
|
275
241
|
|
|
276
|
-
this.ignoreFocusChanges = false;
|
|
277
242
|
return document.activeElement === node;
|
|
278
243
|
}
|
|
279
244
|
}
|
|
280
245
|
|
|
281
|
-
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (this.tryToFocus(child) || this.focusFirstElementIn(child)) {
|
|
288
|
-
return true;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
return false;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
focusLastElementIn(currentParent) {
|
|
296
|
-
const children = currentParent.childNodes;
|
|
297
|
-
|
|
298
|
-
for (let i = children.length - 1; i >= 0; i--) {
|
|
299
|
-
const child = children[i];
|
|
300
|
-
|
|
301
|
-
if (this.tryToFocus(child) || this.focusLastElementIn(child)) {
|
|
302
|
-
return true;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return false;
|
|
246
|
+
focusElementIn(isLast) {
|
|
247
|
+
const modalRootAsHtmlEl = this.modalRoot;
|
|
248
|
+
const focusableNodes = Array.from(modalRootAsHtmlEl.querySelectorAll(FOCUSABLE_ELEMENTS$1));
|
|
249
|
+
const nodeIndex = !isLast ? focusableNodes.length - 1 : 0;
|
|
250
|
+
const focusableNode = focusableNodes[nodeIndex];
|
|
251
|
+
this.tryToFocus(focusableNode);
|
|
307
252
|
}
|
|
308
253
|
|
|
309
254
|
render() {
|
|
@@ -312,6 +257,8 @@ class FocusTrap extends React.Component {
|
|
|
312
257
|
} = this.props;
|
|
313
258
|
return React.createElement(React.Fragment, null, React.createElement("div", {
|
|
314
259
|
tabIndex: "0",
|
|
260
|
+
className: "modal-focus-trap-first",
|
|
261
|
+
onFocus: this.handleFocusMoveToLast,
|
|
315
262
|
style: {
|
|
316
263
|
position: "fixed"
|
|
317
264
|
}
|
|
@@ -320,6 +267,8 @@ class FocusTrap extends React.Component {
|
|
|
320
267
|
ref: this.getModalRoot
|
|
321
268
|
}, this.props.children), React.createElement("div", {
|
|
322
269
|
tabIndex: "0",
|
|
270
|
+
className: "modal-focus-trap-last",
|
|
271
|
+
onFocus: this.handleFocusMoveToFirst,
|
|
323
272
|
style: {
|
|
324
273
|
position: "fixed"
|
|
325
274
|
}
|