@khanacademy/wonder-blocks-modal 2.1.41 → 2.1.45

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/dist/es/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createElement, Component, Fragment, createContext, cloneElement } from 'react';
1
+ import { Component, createElement, Fragment, createContext, cloneElement } from 'react';
2
2
  import { StyleSheet } from 'aphrodite';
3
3
  import { MediaLayoutContext, MediaLayout, MEDIA_MODAL_SPEC } from '@khanacademy/wonder-blocks-layout';
4
4
  import { View, IDProvider } from '@khanacademy/wonder-blocks-core';
@@ -6,143 +6,10 @@ import Spacing from '@khanacademy/wonder-blocks-spacing';
6
6
  import Color from '@khanacademy/wonder-blocks-color';
7
7
  import { HeadingMedium, LabelSmall } from '@khanacademy/wonder-blocks-typography';
8
8
  import { findDOMNode, createPortal } from 'react-dom';
9
+ import _extends from '@babel/runtime/helpers/extends';
9
10
  import { icons } from '@khanacademy/wonder-blocks-icon';
10
11
  import IconButton from '@khanacademy/wonder-blocks-icon-button';
11
12
 
12
- function _classCallCheck(instance, Constructor) {
13
- if (!(instance instanceof Constructor)) {
14
- throw new TypeError("Cannot call a class as a function");
15
- }
16
- }
17
-
18
- function _defineProperties(target, props) {
19
- for (var i = 0; i < props.length; i++) {
20
- var descriptor = props[i];
21
- descriptor.enumerable = descriptor.enumerable || false;
22
- descriptor.configurable = true;
23
- if ("value" in descriptor) descriptor.writable = true;
24
- Object.defineProperty(target, descriptor.key, descriptor);
25
- }
26
- }
27
-
28
- function _createClass(Constructor, protoProps, staticProps) {
29
- if (protoProps) _defineProperties(Constructor.prototype, protoProps);
30
- if (staticProps) _defineProperties(Constructor, staticProps);
31
- return Constructor;
32
- }
33
-
34
- function _defineProperty(obj, key, value) {
35
- if (key in obj) {
36
- Object.defineProperty(obj, key, {
37
- value: value,
38
- enumerable: true,
39
- configurable: true,
40
- writable: true
41
- });
42
- } else {
43
- obj[key] = value;
44
- }
45
-
46
- return obj;
47
- }
48
-
49
- function _extends() {
50
- _extends = Object.assign || function (target) {
51
- for (var i = 1; i < arguments.length; i++) {
52
- var source = arguments[i];
53
-
54
- for (var key in source) {
55
- if (Object.prototype.hasOwnProperty.call(source, key)) {
56
- target[key] = source[key];
57
- }
58
- }
59
- }
60
-
61
- return target;
62
- };
63
-
64
- return _extends.apply(this, arguments);
65
- }
66
-
67
- function _inherits(subClass, superClass) {
68
- if (typeof superClass !== "function" && superClass !== null) {
69
- throw new TypeError("Super expression must either be null or a function");
70
- }
71
-
72
- subClass.prototype = Object.create(superClass && superClass.prototype, {
73
- constructor: {
74
- value: subClass,
75
- writable: true,
76
- configurable: true
77
- }
78
- });
79
- if (superClass) _setPrototypeOf(subClass, superClass);
80
- }
81
-
82
- function _getPrototypeOf(o) {
83
- _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
84
- return o.__proto__ || Object.getPrototypeOf(o);
85
- };
86
- return _getPrototypeOf(o);
87
- }
88
-
89
- function _setPrototypeOf(o, p) {
90
- _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
91
- o.__proto__ = p;
92
- return o;
93
- };
94
-
95
- return _setPrototypeOf(o, p);
96
- }
97
-
98
- function _isNativeReflectConstruct() {
99
- if (typeof Reflect === "undefined" || !Reflect.construct) return false;
100
- if (Reflect.construct.sham) return false;
101
- if (typeof Proxy === "function") return true;
102
-
103
- try {
104
- Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
105
- return true;
106
- } catch (e) {
107
- return false;
108
- }
109
- }
110
-
111
- function _assertThisInitialized(self) {
112
- if (self === void 0) {
113
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
114
- }
115
-
116
- return self;
117
- }
118
-
119
- function _possibleConstructorReturn(self, call) {
120
- if (call && (typeof call === "object" || typeof call === "function")) {
121
- return call;
122
- }
123
-
124
- return _assertThisInitialized(self);
125
- }
126
-
127
- function _createSuper(Derived) {
128
- var hasNativeReflectConstruct = _isNativeReflectConstruct();
129
-
130
- return function _createSuperInternal() {
131
- var Super = _getPrototypeOf(Derived),
132
- result;
133
-
134
- if (hasNativeReflectConstruct) {
135
- var NewTarget = _getPrototypeOf(this).constructor;
136
-
137
- result = Reflect.construct(Super, arguments, NewTarget);
138
- } else {
139
- result = Super.apply(this, arguments);
140
- }
141
-
142
- return _possibleConstructorReturn(this, result);
143
- };
144
- }
145
-
146
13
  /**
147
14
  * `ModalDialog` is a component that contains these elements:
148
15
  * - The visual dialog element itself (`<div role="dialog"/>`)
@@ -153,62 +20,47 @@ function _createSuper(Derived) {
153
20
  * - If there is a custom Dialog implementation (e.g. `TwoPaneDialog`), the dialog element doesn’t have to have
154
21
  * the `aria-labelledby` attribute however this is recommended. It should match the `id` of the dialog title.
155
22
  */
156
- var ModalDialog = /*#__PURE__*/function (_React$Component) {
157
- _inherits(ModalDialog, _React$Component);
158
-
159
- var _super = _createSuper(ModalDialog);
160
-
161
- function ModalDialog() {
162
- _classCallCheck(this, ModalDialog);
163
-
164
- return _super.apply(this, arguments);
23
+ class ModalDialog extends Component {
24
+ render() {
25
+ const {
26
+ above,
27
+ below,
28
+ role,
29
+ style,
30
+ children,
31
+ testId,
32
+ "aria-labelledby": ariaLabelledBy
33
+ } = this.props;
34
+ const contextValue = {
35
+ ssrSize: "large",
36
+ mediaSpec: MEDIA_MODAL_SPEC
37
+ };
38
+ return /*#__PURE__*/createElement(MediaLayoutContext.Provider, {
39
+ value: contextValue
40
+ }, /*#__PURE__*/createElement(MediaLayout, {
41
+ styleSheets: styleSheets
42
+ }, ({
43
+ styles
44
+ }) => /*#__PURE__*/createElement(View, {
45
+ style: [styles.wrapper, style]
46
+ }, below && /*#__PURE__*/createElement(View, {
47
+ style: styles.below
48
+ }, below), /*#__PURE__*/createElement(View, {
49
+ role: role,
50
+ "aria-modal": "true",
51
+ "aria-labelledby": ariaLabelledBy,
52
+ style: styles.dialog,
53
+ testId: testId
54
+ }, children), above && /*#__PURE__*/createElement(View, {
55
+ style: styles.above
56
+ }, above))));
165
57
  }
166
58
 
167
- _createClass(ModalDialog, [{
168
- key: "render",
169
- value: function render() {
170
- var _this$props = this.props,
171
- above = _this$props.above,
172
- below = _this$props.below,
173
- role = _this$props.role,
174
- style = _this$props.style,
175
- children = _this$props.children,
176
- testId = _this$props.testId,
177
- ariaLabelledBy = _this$props["aria-labelledby"];
178
- var contextValue = {
179
- ssrSize: "large",
180
- mediaSpec: MEDIA_MODAL_SPEC
181
- };
182
- return /*#__PURE__*/createElement(MediaLayoutContext.Provider, {
183
- value: contextValue
184
- }, /*#__PURE__*/createElement(MediaLayout, {
185
- styleSheets: styleSheets
186
- }, function (_ref) {
187
- var styles = _ref.styles;
188
- return /*#__PURE__*/createElement(View, {
189
- style: [styles.wrapper, style]
190
- }, below && /*#__PURE__*/createElement(View, {
191
- style: styles.below
192
- }, below), /*#__PURE__*/createElement(View, {
193
- role: role,
194
- "aria-modal": "true",
195
- "aria-labelledby": ariaLabelledBy,
196
- style: styles.dialog,
197
- testId: testId
198
- }, children), above && /*#__PURE__*/createElement(View, {
199
- style: styles.above
200
- }, above));
201
- }));
202
- }
203
- }]);
204
-
205
- return ModalDialog;
206
- }(Component);
207
-
208
- _defineProperty(ModalDialog, "defaultProps", {
59
+ }
60
+ ModalDialog.defaultProps = {
209
61
  role: "dialog"
210
- });
211
- var styleSheets = {
62
+ };
63
+ const styleSheets = {
212
64
  all: StyleSheet.create({
213
65
  wrapper: {
214
66
  display: "flex",
@@ -264,37 +116,23 @@ var styleSheets = {
264
116
  * - Make sure to include it as part of [ModalPanel](/#modalpanel) by using the `footer` prop.
265
117
  * - The footer is completely flexible. Meaning the developer needs to add its own custom layout to match design specs.
266
118
  */
267
- var ModalFooter = /*#__PURE__*/function (_React$Component) {
268
- _inherits(ModalFooter, _React$Component);
269
-
270
- var _super = _createSuper(ModalFooter);
271
-
272
- function ModalFooter() {
273
- _classCallCheck(this, ModalFooter);
274
-
275
- return _super.apply(this, arguments);
119
+ class ModalFooter extends Component {
120
+ static isClassOf(instance) {
121
+ return instance && instance.type && instance.type.__IS_MODAL_FOOTER__;
276
122
  }
277
123
 
278
- _createClass(ModalFooter, [{
279
- key: "render",
280
- value: function render() {
281
- var children = this.props.children;
282
- return /*#__PURE__*/createElement(View, {
283
- style: styles.footer
284
- }, children);
285
- }
286
- }], [{
287
- key: "isClassOf",
288
- value: function isClassOf(instance) {
289
- return instance && instance.type && instance.type.__IS_MODAL_FOOTER__;
290
- }
291
- }]);
292
-
293
- return ModalFooter;
294
- }(Component);
124
+ render() {
125
+ const {
126
+ children
127
+ } = this.props;
128
+ return /*#__PURE__*/createElement(View, {
129
+ style: styles.footer
130
+ }, children);
131
+ }
295
132
 
296
- _defineProperty(ModalFooter, "__IS_MODAL_FOOTER__", true);
297
- var styles = StyleSheet.create({
133
+ }
134
+ ModalFooter.__IS_MODAL_FOOTER__ = true;
135
+ const styles = StyleSheet.create({
298
136
  footer: {
299
137
  flex: "0 0 auto",
300
138
  boxSizing: "border-box",
@@ -307,7 +145,7 @@ var styles = StyleSheet.create({
307
145
  flexDirection: "row",
308
146
  alignItems: "center",
309
147
  justifyContent: "flex-end",
310
- boxShadow: "0px -1px 0px ".concat(Color.offBlack16)
148
+ boxShadow: `0px -1px 0px ${Color.offBlack16}`
311
149
  }
312
150
  });
313
151
 
@@ -354,69 +192,52 @@ var styles = StyleSheet.create({
354
192
  * />
355
193
  * ```
356
194
  */
357
- var ModalHeader = /*#__PURE__*/function (_React$Component) {
358
- _inherits(ModalHeader, _React$Component);
359
-
360
- var _super = _createSuper(ModalHeader);
361
-
362
- function ModalHeader() {
363
- _classCallCheck(this, ModalHeader);
364
-
365
- return _super.apply(this, arguments);
366
- }
367
-
368
- _createClass(ModalHeader, [{
369
- key: "render",
370
- value: function render() {
371
- var _this$props = this.props,
372
- _this$props$breadcrum = _this$props.breadcrumbs,
373
- breadcrumbs = _this$props$breadcrum === void 0 ? undefined : _this$props$breadcrum,
374
- light = _this$props.light,
375
- _this$props$subtitle = _this$props.subtitle,
376
- subtitle = _this$props$subtitle === void 0 ? undefined : _this$props$subtitle,
377
- testId = _this$props.testId,
378
- title = _this$props.title,
379
- titleId = _this$props.titleId;
380
-
381
- if (subtitle && breadcrumbs) {
382
- throw new Error("'subtitle' and 'breadcrumbs' can't be used together");
383
- }
384
-
385
- return /*#__PURE__*/createElement(MediaLayout, {
386
- styleSheets: styleSheets$1
387
- }, function (_ref) {
388
- var styles = _ref.styles;
389
- return /*#__PURE__*/createElement(View, {
390
- style: [styles.header, !light && styles.dark],
391
- testId: testId
392
- }, breadcrumbs && /*#__PURE__*/createElement(View, {
393
- style: styles.breadcrumbs
394
- }, breadcrumbs), /*#__PURE__*/createElement(HeadingMedium, {
395
- style: styles.title,
396
- id: titleId,
397
- testId: testId && "".concat(testId, "-title")
398
- }, title), subtitle && /*#__PURE__*/createElement(LabelSmall, {
399
- style: light && styles.subtitle,
400
- testId: testId && "".concat(testId, "-subtitle")
401
- }, subtitle));
402
- });
195
+ class ModalHeader extends Component {
196
+ render() {
197
+ const {
198
+ breadcrumbs = undefined,
199
+ light,
200
+ subtitle = undefined,
201
+ testId,
202
+ title,
203
+ titleId
204
+ } = this.props;
205
+
206
+ if (subtitle && breadcrumbs) {
207
+ throw new Error("'subtitle' and 'breadcrumbs' can't be used together");
403
208
  }
404
- }]);
405
209
 
406
- return ModalHeader;
407
- }(Component);
210
+ return /*#__PURE__*/createElement(MediaLayout, {
211
+ styleSheets: styleSheets$1
212
+ }, ({
213
+ styles
214
+ }) => /*#__PURE__*/createElement(View, {
215
+ style: [styles.header, !light && styles.dark],
216
+ testId: testId
217
+ }, breadcrumbs && /*#__PURE__*/createElement(View, {
218
+ style: styles.breadcrumbs
219
+ }, breadcrumbs), /*#__PURE__*/createElement(HeadingMedium, {
220
+ style: styles.title,
221
+ id: titleId,
222
+ testId: testId && `${testId}-title`
223
+ }, title), subtitle && /*#__PURE__*/createElement(LabelSmall, {
224
+ style: light && styles.subtitle,
225
+ testId: testId && `${testId}-subtitle`
226
+ }, subtitle)));
227
+ }
408
228
 
409
- _defineProperty(ModalHeader, "defaultProps", {
229
+ }
230
+ ModalHeader.defaultProps = {
410
231
  light: true
411
- });
412
- var styleSheets$1 = {
232
+ };
233
+ const styleSheets$1 = {
413
234
  all: StyleSheet.create({
414
235
  header: {
415
- boxShadow: "0px 1px 0px ".concat(Color.offBlack16),
236
+ boxShadow: `0px 1px 0px ${Color.offBlack16}`,
416
237
  display: "flex",
417
238
  flexDirection: "column",
418
239
  minHeight: 66,
419
- padding: "".concat(Spacing.large_24, "px ").concat(Spacing.xLarge_32, "px"),
240
+ padding: `${Spacing.large_24}px ${Spacing.xLarge_32}px`,
420
241
  position: "relative",
421
242
  width: "100%"
422
243
  },
@@ -448,11 +269,7 @@ var styleSheets$1 = {
448
269
  })
449
270
  };
450
271
 
451
- var FocusTrap = /*#__PURE__*/function (_React$Component) {
452
- _inherits(FocusTrap, _React$Component);
453
-
454
- var _super = _createSuper(FocusTrap);
455
-
272
+ class FocusTrap extends Component {
456
273
  /** The most recent node _inside this component_ to receive focus. */
457
274
 
458
275
  /**
@@ -463,49 +280,39 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
463
280
  /**
464
281
  * Tabbing is restricted to descendents of this element.
465
282
  */
466
- function FocusTrap(props) {
467
- var _this;
468
-
469
- _classCallCheck(this, FocusTrap);
470
-
471
- _this = _super.call(this, props);
283
+ constructor(props) {
284
+ super(props);
472
285
 
473
- _defineProperty(_assertThisInitialized(_this), "lastNodeFocusedInModal", void 0);
474
-
475
- _defineProperty(_assertThisInitialized(_this), "ignoreFocusChanges", void 0);
476
-
477
- _defineProperty(_assertThisInitialized(_this), "modalRoot", void 0);
478
-
479
- _defineProperty(_assertThisInitialized(_this), "getModalRoot", function (node) {
286
+ this.getModalRoot = node => {
480
287
  if (!node) {
481
288
  // The component is being umounted
482
289
  return;
483
290
  }
484
291
 
485
- var modalRoot = findDOMNode(node);
292
+ const modalRoot = findDOMNode(node);
486
293
 
487
294
  if (!modalRoot) {
488
295
  throw new Error("Assertion error: modal root should exist after mount");
489
296
  }
490
297
 
491
- _this.modalRoot = modalRoot;
492
- });
298
+ this.modalRoot = modalRoot;
299
+ };
493
300
 
494
- _defineProperty(_assertThisInitialized(_this), "handleGlobalFocus", function (e) {
301
+ this.handleGlobalFocus = e => {
495
302
  // If we're busy applying our own programmatic focus, we ignore focus
496
303
  // changes, to avoid an infinite loop.
497
- if (_this.ignoreFocusChanges) {
304
+ if (this.ignoreFocusChanges) {
498
305
  return;
499
306
  }
500
307
 
501
- var target = e.target;
308
+ const target = e.target;
502
309
 
503
310
  if (!(target instanceof Node)) {
504
311
  // Sometimes focus events trigger on the document itself. Ignore!
505
312
  return;
506
313
  }
507
314
 
508
- var modalRoot = _this.modalRoot;
315
+ const modalRoot = this.modalRoot;
509
316
 
510
317
  if (!modalRoot) {
511
318
  return;
@@ -514,141 +321,135 @@ var FocusTrap = /*#__PURE__*/function (_React$Component) {
514
321
  if (modalRoot.contains(target)) {
515
322
  // If the newly focused node is inside the modal, we just keep track
516
323
  // of that.
517
- _this.lastNodeFocusedInModal = target;
324
+ this.lastNodeFocusedInModal = target;
518
325
  } else {
519
326
  // If the newly focused node is outside the modal, we try refocusing
520
327
  // the first focusable node of the modal. (This could be the user
521
328
  // pressing Tab on the last node of the modal, or focus escaping in
522
329
  // some other way.)
523
- _this.focusFirstElementIn(modalRoot); // But, if it turns out that the first focusable node of the modal
330
+ this.focusFirstElementIn(modalRoot); // But, if it turns out that the first focusable node of the modal
524
331
  // was what we were previously focusing, then this is probably the
525
332
  // user pressing Shift-Tab on the first node, wanting to go to the
526
333
  // end. So, we instead try focusing the last focusable node of the
527
334
  // modal.
528
335
 
529
-
530
- if (document.activeElement === _this.lastNodeFocusedInModal) {
531
- _this.focusLastElementIn(modalRoot);
336
+ if (document.activeElement === this.lastNodeFocusedInModal) {
337
+ this.focusLastElementIn(modalRoot);
532
338
  } // Focus should now be inside the modal, so record the newly-focused
533
339
  // node as the last node focused in the modal.
534
340
 
535
341
 
536
- _this.lastNodeFocusedInModal = document.activeElement;
342
+ this.lastNodeFocusedInModal = document.activeElement;
537
343
  }
538
- });
344
+ };
539
345
 
540
- _this.lastNodeFocusedInModal = null;
541
- _this.ignoreFocusChanges = false;
542
- return _this;
346
+ this.lastNodeFocusedInModal = null;
347
+ this.ignoreFocusChanges = false;
543
348
  }
544
349
 
545
- _createClass(FocusTrap, [{
546
- key: "componentDidMount",
547
- value: function componentDidMount() {
548
- window.addEventListener("focus", this.handleGlobalFocus, true);
549
- }
550
- }, {
551
- key: "componentWillUnmount",
552
- value: function componentWillUnmount() {
553
- window.removeEventListener("focus", this.handleGlobalFocus, true);
554
- }
555
- }, {
556
- key: "tryToFocus",
350
+ componentDidMount() {
351
+ window.addEventListener("focus", this.handleGlobalFocus, true);
352
+ }
557
353
 
558
- /** Try to focus the given node. Return true iff successful. */
559
- value: function tryToFocus(node) {
560
- if (node instanceof HTMLElement) {
561
- this.ignoreFocusChanges = true;
354
+ componentWillUnmount() {
355
+ window.removeEventListener("focus", this.handleGlobalFocus, true);
356
+ }
562
357
 
563
- try {
564
- node.focus();
565
- } catch (e) {// ignore error
566
- }
358
+ /** Try to focus the given node. Return true iff successful. */
359
+ tryToFocus(node) {
360
+ if (node instanceof HTMLElement) {
361
+ this.ignoreFocusChanges = true;
567
362
 
568
- this.ignoreFocusChanges = false;
569
- return document.activeElement === node;
363
+ try {
364
+ node.focus();
365
+ } catch (e) {// ignore error
570
366
  }
367
+
368
+ this.ignoreFocusChanges = false;
369
+ return document.activeElement === node;
571
370
  }
572
- /**
573
- * Focus the first focusable descendant of the given node.
574
- *
575
- * Return true if we succeed. Or, if the given node has no focusable
576
- * descendants, return false.
577
- */
371
+ }
372
+ /**
373
+ * Focus the first focusable descendant of the given node.
374
+ *
375
+ * Return true if we succeed. Or, if the given node has no focusable
376
+ * descendants, return false.
377
+ */
578
378
 
579
- }, {
580
- key: "focusFirstElementIn",
581
- value: function focusFirstElementIn(currentParent) {
582
- var children = currentParent.childNodes;
583
379
 
584
- for (var i = 0; i < children.length; i++) {
585
- var child = children[i];
380
+ focusFirstElementIn(currentParent) {
381
+ const children = currentParent.childNodes;
586
382
 
587
- if (this.tryToFocus(child) || this.focusFirstElementIn(child)) {
588
- return true;
589
- }
590
- }
383
+ for (let i = 0; i < children.length; i++) {
384
+ const child = children[i];
591
385
 
592
- return false;
386
+ if (this.tryToFocus(child) || this.focusFirstElementIn(child)) {
387
+ return true;
388
+ }
593
389
  }
594
- /**
595
- * Focus the last focusable descendant of the given node.
596
- *
597
- * Return true if we succeed. Or, if the given node has no focusable
598
- * descendants, return false.
599
- */
600
390
 
601
- }, {
602
- key: "focusLastElementIn",
603
- value: function focusLastElementIn(currentParent) {
604
- var children = currentParent.childNodes;
391
+ return false;
392
+ }
393
+ /**
394
+ * Focus the last focusable descendant of the given node.
395
+ *
396
+ * Return true if we succeed. Or, if the given node has no focusable
397
+ * descendants, return false.
398
+ */
399
+
605
400
 
606
- for (var i = children.length - 1; i >= 0; i--) {
607
- var child = children[i];
401
+ focusLastElementIn(currentParent) {
402
+ const children = currentParent.childNodes;
608
403
 
609
- if (this.tryToFocus(child) || this.focusLastElementIn(child)) {
610
- return true;
611
- }
612
- }
404
+ for (let i = children.length - 1; i >= 0; i--) {
405
+ const child = children[i];
613
406
 
614
- return false;
615
- }
616
- /** This method is called when any node on the page is focused. */
617
-
618
- }, {
619
- key: "render",
620
- value: function render() {
621
- var style = this.props.style;
622
- return /*#__PURE__*/createElement(Fragment, null, /*#__PURE__*/createElement("div", {
623
- tabIndex: "0",
624
- style: {
625
- position: "fixed"
626
- }
627
- }), /*#__PURE__*/createElement(View, {
628
- style: style,
629
- ref: this.getModalRoot
630
- }, this.props.children), /*#__PURE__*/createElement("div", {
631
- tabIndex: "0",
632
- style: {
633
- position: "fixed"
634
- }
635
- }));
407
+ if (this.tryToFocus(child) || this.focusLastElementIn(child)) {
408
+ return true;
409
+ }
636
410
  }
637
- }]);
638
411
 
639
- return FocusTrap;
640
- }(Component);
412
+ return false;
413
+ }
414
+ /** This method is called when any node on the page is focused. */
415
+
416
+
417
+ render() {
418
+ const {
419
+ style
420
+ } = this.props;
421
+ return /*#__PURE__*/createElement(Fragment, null, /*#__PURE__*/createElement("div", {
422
+ tabIndex: "0",
423
+ style: {
424
+ position: "fixed"
425
+ }
426
+ }), /*#__PURE__*/createElement(View, {
427
+ style: style,
428
+ ref: this.getModalRoot
429
+ }, this.props.children), /*#__PURE__*/createElement("div", {
430
+ tabIndex: "0",
431
+ style: {
432
+ position: "fixed"
433
+ }
434
+ }));
435
+ }
436
+
437
+ }
641
438
 
642
439
  /**
643
440
  * The attribute used to identify a modal launcher portal.
644
441
  */
645
- var ModalLauncherPortalAttributeName = "data-modal-launcher-portal";
442
+ const ModalLauncherPortalAttributeName = "data-modal-launcher-portal";
646
443
 
647
444
  /**
648
445
  * List of elements that can be focused
649
446
  * @see https://www.w3.org/TR/html5/editing.html#can-be-focused
650
447
  */
651
- var FOCUSABLE_ELEMENTS = 'a[href], details, input, textarea, select, button:not([aria-label^="Close"])';
448
+ const FOCUSABLE_ELEMENTS = 'a[href], details, input, textarea, select, button:not([aria-label^="Close"])';
449
+ function findFocusableNodes(root) {
450
+ return Array.from(root.querySelectorAll(FOCUSABLE_ELEMENTS));
451
+ }
452
+
652
453
  /**
653
454
  * A private component used by ModalLauncher. This is the fixed-position
654
455
  * container element that gets mounted outside the DOM. It overlays the modal
@@ -659,125 +460,105 @@ var FOCUSABLE_ELEMENTS = 'a[href], details, input, textarea, select, button:not(
659
460
  * and adding an `onClose` prop that will call `onCloseModal`. If an
660
461
  * `onClose` prop is already provided, the two are merged.
661
462
  */
463
+ class ModalBackdrop extends Component {
464
+ constructor(...args) {
465
+ super(...args);
662
466
 
663
- var ModalBackdrop = /*#__PURE__*/function (_React$Component) {
664
- _inherits(ModalBackdrop, _React$Component);
665
-
666
- var _super = _createSuper(ModalBackdrop);
667
-
668
- function ModalBackdrop() {
669
- var _this;
670
-
671
- _classCallCheck(this, ModalBackdrop);
672
-
673
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
674
- args[_key] = arguments[_key];
675
- }
676
-
677
- _this = _super.call.apply(_super, [this].concat(args));
678
-
679
- _defineProperty(_assertThisInitialized(_this), "handleClick", function (e) {
467
+ this.handleClick = e => {
680
468
  // Was the lowest-level click target (`e.target`) the positioner element
681
469
  // (`e.currentTarget`)?
682
470
  if (e.target === e.currentTarget) {
683
- _this.props.onCloseModal();
471
+ this.props.onCloseModal();
684
472
  }
685
- });
686
-
687
- return _this;
473
+ };
688
474
  }
689
475
 
690
- _createClass(ModalBackdrop, [{
691
- key: "componentDidMount",
692
- value: function componentDidMount() {
693
- var node = findDOMNode(this);
476
+ componentDidMount() {
477
+ const node = findDOMNode(this);
694
478
 
695
- if (!node) {
696
- return;
697
- }
479
+ if (!node) {
480
+ return;
481
+ }
698
482
 
699
- var firstFocusableElement = // 1. try to get element specified by the user
700
- this._getInitialFocusElement(node) || // 2. get first occurence from list of focusable elements
701
- this._getFirstFocusableElement(node) || // 3. get the dialog itself
702
- this._getDialogElement(node); // wait for styles to applied
483
+ const firstFocusableElement = // 1. try to get element specified by the user
484
+ this._getInitialFocusElement(node) || // 2. get first occurence from list of focusable elements
485
+ this._getFirstFocusableElement(node) || // 3. get the dialog itself
486
+ this._getDialogElement(node); // wait for styles to applied
703
487
 
704
488
 
705
- setTimeout(function () {
706
- firstFocusableElement.focus();
707
- }, 0);
708
- }
709
- /**
710
- * Returns an element specified by the user
711
- */
489
+ setTimeout(() => {
490
+ firstFocusableElement.focus();
491
+ }, 0);
492
+ }
493
+ /**
494
+ * Returns an element specified by the user
495
+ */
712
496
 
713
- }, {
714
- key: "_getInitialFocusElement",
715
- value: function _getInitialFocusElement(node) {
716
- var initialFocusId = this.props.initialFocusId;
717
497
 
718
- if (!initialFocusId) {
719
- return null;
720
- }
498
+ _getInitialFocusElement(node) {
499
+ const {
500
+ initialFocusId
501
+ } = this.props;
721
502
 
722
- return findDOMNode(node.querySelector("#".concat(initialFocusId)));
503
+ if (!initialFocusId) {
504
+ return null;
723
505
  }
724
- /**
725
- * Returns the first focusable element found inside the Dialog
726
- */
727
506
 
728
- }, {
729
- key: "_getFirstFocusableElement",
730
- value: function _getFirstFocusableElement(node) {
731
- // get a collection of elements that can be focused
732
- var focusableElements = node.querySelectorAll(FOCUSABLE_ELEMENTS);
507
+ return findDOMNode(node.querySelector(`#${initialFocusId}`));
508
+ }
509
+ /**
510
+ * Returns the first focusable element found inside the Dialog
511
+ */
733
512
 
734
- if (!focusableElements) {
735
- return null;
736
- } // if found, return the first focusable element
737
513
 
514
+ _getFirstFocusableElement(node) {
515
+ // get a collection of elements that can be focused
516
+ const focusableElements = findFocusableNodes(node);
738
517
 
739
- return focusableElements[0];
740
- }
741
- /**
742
- * Returns the dialog element
743
- */
518
+ if (!focusableElements) {
519
+ return null;
520
+ } // if found, return the first focusable element
744
521
 
745
- }, {
746
- key: "_getDialogElement",
747
- value: function _getDialogElement(node) {
748
- // If no focusable elements are found,
749
- // the dialog content element itself will receive focus.
750
- var dialogElement = findDOMNode(node.querySelector('[role="dialog"]')); // add tabIndex to make the Dialog focusable
751
522
 
752
- dialogElement.tabIndex = -1;
753
- return dialogElement;
754
- }
755
- /**
756
- * When the user clicks on the gray backdrop area (i.e., the click came
757
- * _directly_ from the positioner, not bubbled up from its children), close
758
- * the modal.
759
- */
523
+ return focusableElements[0];
524
+ }
525
+ /**
526
+ * Returns the dialog element
527
+ */
760
528
 
761
- }, {
762
- key: "render",
763
- value: function render() {
764
- var _this$props = this.props,
765
- children = _this$props.children,
766
- testId = _this$props.testId;
767
529
 
768
- var backdropProps = _defineProperty({}, ModalLauncherPortalAttributeName, true);
530
+ _getDialogElement(node) {
531
+ // If no focusable elements are found,
532
+ // the dialog content element itself will receive focus.
533
+ const dialogElement = findDOMNode(node.querySelector('[role="dialog"]')); // add tabIndex to make the Dialog focusable
769
534
 
770
- return /*#__PURE__*/createElement(View, _extends({
771
- style: styles$1.modalPositioner,
772
- onClick: this.handleClick,
773
- testId: testId
774
- }, backdropProps), children);
775
- }
776
- }]);
535
+ dialogElement.tabIndex = -1;
536
+ return dialogElement;
537
+ }
538
+ /**
539
+ * When the user clicks on the gray backdrop area (i.e., the click came
540
+ * _directly_ from the positioner, not bubbled up from its children), close
541
+ * the modal.
542
+ */
543
+
544
+
545
+ render() {
546
+ const {
547
+ children,
548
+ testId
549
+ } = this.props;
550
+ const backdropProps = {
551
+ [ModalLauncherPortalAttributeName]: true
552
+ };
553
+ return /*#__PURE__*/createElement(View, _extends({
554
+ style: styles$1.modalPositioner,
555
+ onClick: this.handleClick,
556
+ testId: testId
557
+ }, backdropProps), children);
558
+ }
777
559
 
778
- return ModalBackdrop;
779
- }(Component);
780
- var styles$1 = StyleSheet.create({
560
+ }
561
+ const styles$1 = StyleSheet.create({
781
562
  modalPositioner: {
782
563
  position: "fixed",
783
564
  left: 0,
@@ -799,113 +580,98 @@ var styles$1 = StyleSheet.create({
799
580
  }
800
581
  });
801
582
 
802
- var needsHackyMobileSafariScrollDisabler = function () {
583
+ /**
584
+ * A UI-less component that lets `ModalLauncher` disable page scroll.
585
+ *
586
+ * The positioning of the modal requires some global page state changed
587
+ * unfortunately, and this handles that in an encapsulated way.
588
+ *
589
+ * NOTE(mdr): This component was copied from webapp. Be wary of sync issues. It
590
+ * also doesn't have unit tests, and we haven't added any, since it's a
591
+ * relatively stable component that has now been stress-tested lots in prod.
592
+ */
593
+
594
+ const needsHackyMobileSafariScrollDisabler = (() => {
803
595
  if (typeof window === "undefined") {
804
596
  return false;
805
597
  }
806
598
 
807
- var userAgent = window.navigator.userAgent;
599
+ const userAgent = window.navigator.userAgent;
808
600
  return userAgent.indexOf("iPad") > -1 || userAgent.indexOf("iPhone") > -1;
809
- }();
810
-
811
- var ScrollDisabler = /*#__PURE__*/function (_React$Component) {
812
- _inherits(ScrollDisabler, _React$Component);
813
-
814
- var _super = _createSuper(ScrollDisabler);
815
-
816
- function ScrollDisabler() {
817
- _classCallCheck(this, ScrollDisabler);
818
-
819
- return _super.apply(this, arguments);
820
- }
601
+ })();
821
602
 
822
- _createClass(ScrollDisabler, [{
823
- key: "componentDidMount",
824
- value: function componentDidMount() {
825
- if (ScrollDisabler.numModalsOpened === 0) {
826
- var body = document.body;
603
+ class ScrollDisabler extends Component {
604
+ componentDidMount() {
605
+ if (ScrollDisabler.numModalsOpened === 0) {
606
+ const body = document.body;
827
607
 
828
- if (!body) {
829
- throw new Error("couldn't find document.body");
830
- } // Prevent scrolling of the background, the first time a modal is
831
- // opened.
608
+ if (!body) {
609
+ throw new Error("couldn't find document.body");
610
+ } // Prevent scrolling of the background, the first time a modal is
611
+ // opened.
832
612
 
833
613
 
834
- ScrollDisabler.oldOverflow = body.style.overflow;
835
- ScrollDisabler.oldScrollY = window.scrollY; // We need to grab all of the original style properties before we
836
- // modified any of them.
614
+ ScrollDisabler.oldOverflow = body.style.overflow;
615
+ ScrollDisabler.oldScrollY = window.scrollY; // We need to grab all of the original style properties before we
616
+ // modified any of them.
837
617
 
838
- if (needsHackyMobileSafariScrollDisabler) {
839
- ScrollDisabler.oldPosition = body.style.position;
840
- ScrollDisabler.oldWidth = body.style.width;
841
- ScrollDisabler.oldTop = body.style.top;
842
- }
618
+ if (needsHackyMobileSafariScrollDisabler) {
619
+ ScrollDisabler.oldPosition = body.style.position;
620
+ ScrollDisabler.oldWidth = body.style.width;
621
+ ScrollDisabler.oldTop = body.style.top;
622
+ }
843
623
 
844
- body.style.overflow = "hidden"; // On mobile Safari, overflow: hidden is not enough, position:
845
- // fixed is also required. Setting style.top = -scollTop maintains
846
- // the scroll position (without which we'd scroll to the top).
624
+ body.style.overflow = "hidden"; // On mobile Safari, overflow: hidden is not enough, position:
625
+ // fixed is also required. Setting style.top = -scollTop maintains
626
+ // the scroll position (without which we'd scroll to the top).
847
627
 
848
- if (needsHackyMobileSafariScrollDisabler) {
849
- body.style.position = "fixed";
850
- body.style.width = "100%";
851
- body.style.top = "".concat(-ScrollDisabler.oldScrollY, "px");
852
- }
628
+ if (needsHackyMobileSafariScrollDisabler) {
629
+ body.style.position = "fixed";
630
+ body.style.width = "100%";
631
+ body.style.top = `${-ScrollDisabler.oldScrollY}px`;
853
632
  }
854
-
855
- ScrollDisabler.numModalsOpened++;
856
633
  }
857
- }, {
858
- key: "componentWillUnmount",
859
- value: function componentWillUnmount() {
860
- ScrollDisabler.numModalsOpened--;
861
-
862
- if (ScrollDisabler.numModalsOpened === 0) {
863
- var body = document.body;
864
-
865
- if (!body) {
866
- throw new Error("couldn't find document.body");
867
- } // Reset all values on the closing of the final modal.
868
634
 
635
+ ScrollDisabler.numModalsOpened++;
636
+ }
869
637
 
870
- body.style.overflow = ScrollDisabler.oldOverflow;
638
+ componentWillUnmount() {
639
+ ScrollDisabler.numModalsOpened--;
871
640
 
872
- if (needsHackyMobileSafariScrollDisabler) {
873
- body.style.position = ScrollDisabler.oldPosition;
874
- body.style.width = ScrollDisabler.oldWidth;
875
- body.style.top = ScrollDisabler.oldTop;
876
- }
641
+ if (ScrollDisabler.numModalsOpened === 0) {
642
+ const body = document.body;
877
643
 
878
- if (typeof window !== "undefined" && window.scrollTo) {
879
- window.scrollTo(0, ScrollDisabler.oldScrollY);
880
- }
881
- }
882
- }
883
- }, {
884
- key: "render",
885
- value: function render() {
886
- return null;
887
- }
888
- }]);
644
+ if (!body) {
645
+ throw new Error("couldn't find document.body");
646
+ } // Reset all values on the closing of the final modal.
889
647
 
890
- return ScrollDisabler;
891
- }(Component);
892
648
 
893
- _defineProperty(ScrollDisabler, "oldOverflow", void 0);
649
+ body.style.overflow = ScrollDisabler.oldOverflow;
894
650
 
895
- _defineProperty(ScrollDisabler, "oldPosition", void 0);
651
+ if (needsHackyMobileSafariScrollDisabler) {
652
+ body.style.position = ScrollDisabler.oldPosition;
653
+ body.style.width = ScrollDisabler.oldWidth;
654
+ body.style.top = ScrollDisabler.oldTop;
655
+ }
896
656
 
897
- _defineProperty(ScrollDisabler, "oldScrollY", void 0);
657
+ if (typeof window !== "undefined" && window.scrollTo) {
658
+ window.scrollTo(0, ScrollDisabler.oldScrollY);
659
+ }
660
+ }
661
+ }
898
662
 
899
- _defineProperty(ScrollDisabler, "oldWidth", void 0);
663
+ render() {
664
+ return null;
665
+ }
900
666
 
901
- _defineProperty(ScrollDisabler, "oldTop", void 0);
667
+ }
902
668
 
903
- _defineProperty(ScrollDisabler, "numModalsOpened", 0);
669
+ ScrollDisabler.numModalsOpened = 0;
904
670
 
905
- var defaultContext = {
671
+ const defaultContext = {
906
672
  closeModal: undefined
907
673
  };
908
- var ModalContext = createContext(defaultContext);
674
+ var ModalContext = /*#__PURE__*/createContext(defaultContext);
909
675
 
910
676
  /**
911
677
  * This component enables you to launch a modal, covering the screen.
@@ -923,164 +689,128 @@ var ModalContext = createContext(defaultContext);
923
689
  * like OnePaneDialog and is provided via
924
690
  * the `modal` prop.
925
691
  */
926
- var ModalLauncher = /*#__PURE__*/function (_React$Component) {
927
- _inherits(ModalLauncher, _React$Component);
928
-
929
- var _super = _createSuper(ModalLauncher);
930
-
931
- function ModalLauncher() {
932
- var _this;
933
-
934
- _classCallCheck(this, ModalLauncher);
935
-
936
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
937
- args[_key] = arguments[_key];
938
- }
939
-
940
- _this = _super.call.apply(_super, [this].concat(args));
941
-
942
- _defineProperty(_assertThisInitialized(_this), "lastElementFocusedOutsideModal", void 0);
943
-
944
- _defineProperty(_assertThisInitialized(_this), "state", {
692
+ class ModalLauncher extends Component {
693
+ constructor(...args) {
694
+ super(...args);
695
+ this.state = {
945
696
  opened: false
946
- });
697
+ };
947
698
 
948
- _defineProperty(_assertThisInitialized(_this), "_saveLastElementFocused", function () {
699
+ this._saveLastElementFocused = () => {
949
700
  // keep a reference of the element that triggers the modal
950
- _this.lastElementFocusedOutsideModal = document.activeElement;
951
- });
701
+ this.lastElementFocusedOutsideModal = document.activeElement;
702
+ };
952
703
 
953
- _defineProperty(_assertThisInitialized(_this), "_openModal", function () {
954
- _this._saveLastElementFocused();
704
+ this._openModal = () => {
705
+ this._saveLastElementFocused();
955
706
 
956
- _this.setState({
707
+ this.setState({
957
708
  opened: true
958
709
  });
959
- });
710
+ };
960
711
 
961
- _defineProperty(_assertThisInitialized(_this), "handleCloseModal", function () {
962
- _this.setState({
712
+ this.handleCloseModal = () => {
713
+ this.setState({
963
714
  opened: false
964
- }, function () {
965
- _this.props.onClose && _this.props.onClose();
715
+ }, () => {
716
+ this.props.onClose && this.props.onClose();
966
717
 
967
- if (_this.lastElementFocusedOutsideModal != null) {
718
+ if (this.lastElementFocusedOutsideModal != null) {
968
719
  // return focus to the element that triggered the modal
969
- _this.lastElementFocusedOutsideModal.focus();
720
+ this.lastElementFocusedOutsideModal.focus();
970
721
  }
971
722
  });
972
- });
973
-
974
- return _this;
723
+ };
975
724
  }
976
725
 
977
- _createClass(ModalLauncher, [{
978
- key: "componentDidUpdate",
979
- value: function componentDidUpdate(prevProps) {
980
- // ensures the element is stored only when the modal is opened
981
- if (!prevProps.opened && this.props.opened) {
982
- this._saveLastElementFocused();
983
- }
984
- }
985
- }, {
986
- key: "_renderModal",
987
- value: function _renderModal() {
988
- if (typeof this.props.modal === "function") {
989
- return this.props.modal({
990
- closeModal: this.handleCloseModal
991
- });
992
- } else {
993
- return this.props.modal;
994
- }
726
+ static getDerivedStateFromProps(props, state) {
727
+ if (typeof props.opened === "boolean" && props.children) {
728
+ // eslint-disable-next-line no-console
729
+ console.warn("'children' and 'opened' can't be used together");
995
730
  }
996
- }, {
997
- key: "render",
998
- value: function render() {
999
- var renderedChildren = this.props.children ? this.props.children({
1000
- openModal: this._openModal
1001
- }) : null;
1002
- var _document = document,
1003
- body = _document.body;
1004
731
 
1005
- if (!body) {
1006
- return null;
1007
- }
1008
-
1009
- return (
1010
- /*#__PURE__*/
1011
- // This flow check is valid, it's the babel plugin which is broken,
1012
- // see modal-context.js for details.
1013
- // $FlowFixMe
1014
- createElement(ModalContext.Provider, {
1015
- value: {
1016
- closeModal: this.handleCloseModal
1017
- }
1018
- }, renderedChildren, this.state.opened && createPortal(
1019
- /*#__PURE__*/
1020
-
1021
- /* We need the container View that FocusTrap creates to be at the
1022
- correct z-index so that it'll be above the global nav in webapp. */
1023
- createElement(FocusTrap, {
1024
- style: styles$2.container
1025
- }, /*#__PURE__*/createElement(ModalBackdrop, {
1026
- initialFocusId: this.props.initialFocusId,
1027
- testId: this.props.testId,
1028
- onCloseModal: this.props.backdropDismissEnabled ? this.handleCloseModal : function () {}
1029
- }, this._renderModal())), body), this.state.opened && /*#__PURE__*/createElement(ModalLauncherKeypressListener, {
1030
- onClose: this.handleCloseModal
1031
- }), this.state.opened && /*#__PURE__*/createElement(ScrollDisabler, null))
1032
- );
732
+ if (typeof props.opened === "boolean" && !props.onClose) {
733
+ // eslint-disable-next-line no-console
734
+ console.warn("'onClose' should be used with 'opened'");
1033
735
  }
1034
- }], [{
1035
- key: "getDerivedStateFromProps",
1036
- value: function getDerivedStateFromProps(props, state) {
1037
- if (typeof props.opened === "boolean" && props.children) {
1038
- // eslint-disable-next-line no-console
1039
- console.warn("'children' and 'opened' can't be used together");
1040
- }
1041
-
1042
- if (typeof props.opened === "boolean" && !props.onClose) {
1043
- // eslint-disable-next-line no-console
1044
- console.warn("'onClose' should be used with 'opened'");
1045
- }
1046
-
1047
- if (typeof props.opened !== "boolean" && !props.children) {
1048
- // eslint-disable-next-line no-console
1049
- console.warn("either 'children' or 'opened' must be set");
1050
- }
1051
736
 
1052
- return {
1053
- opened: typeof props.opened === "boolean" ? props.opened : state.opened
1054
- };
737
+ if (typeof props.opened !== "boolean" && !props.children) {
738
+ // eslint-disable-next-line no-console
739
+ console.warn("either 'children' or 'opened' must be set");
1055
740
  }
1056
- }]);
1057
741
 
1058
- return ModalLauncher;
1059
- }(Component);
1060
- /** A component that, when mounted, calls `onClose` when Escape is pressed. */
742
+ return {
743
+ opened: typeof props.opened === "boolean" ? props.opened : state.opened
744
+ };
745
+ }
1061
746
 
747
+ componentDidUpdate(prevProps) {
748
+ // ensures the element is stored only when the modal is opened
749
+ if (!prevProps.opened && this.props.opened) {
750
+ this._saveLastElementFocused();
751
+ }
752
+ }
1062
753
 
1063
- _defineProperty(ModalLauncher, "defaultProps", {
1064
- backdropDismissEnabled: true
1065
- });
754
+ _renderModal() {
755
+ if (typeof this.props.modal === "function") {
756
+ return this.props.modal({
757
+ closeModal: this.handleCloseModal
758
+ });
759
+ } else {
760
+ return this.props.modal;
761
+ }
762
+ }
1066
763
 
1067
- var ModalLauncherKeypressListener = /*#__PURE__*/function (_React$Component2) {
1068
- _inherits(ModalLauncherKeypressListener, _React$Component2);
764
+ render() {
765
+ const renderedChildren = this.props.children ? this.props.children({
766
+ openModal: this._openModal
767
+ }) : null;
768
+ const {
769
+ body
770
+ } = document;
1069
771
 
1070
- var _super2 = _createSuper(ModalLauncherKeypressListener);
772
+ if (!body) {
773
+ return null;
774
+ }
1071
775
 
1072
- function ModalLauncherKeypressListener() {
1073
- var _this2;
776
+ return (
777
+ /*#__PURE__*/
778
+ // This flow check is valid, it's the babel plugin which is broken,
779
+ // see modal-context.js for details.
780
+ // $FlowFixMe
781
+ createElement(ModalContext.Provider, {
782
+ value: {
783
+ closeModal: this.handleCloseModal
784
+ }
785
+ }, renderedChildren, this.state.opened && /*#__PURE__*/createPortal(
786
+ /*#__PURE__*/
787
+
788
+ /* We need the container View that FocusTrap creates to be at the
789
+ correct z-index so that it'll be above the global nav in webapp. */
790
+ createElement(FocusTrap, {
791
+ style: styles$2.container
792
+ }, /*#__PURE__*/createElement(ModalBackdrop, {
793
+ initialFocusId: this.props.initialFocusId,
794
+ testId: this.props.testId,
795
+ onCloseModal: this.props.backdropDismissEnabled ? this.handleCloseModal : () => {}
796
+ }, this._renderModal())), body), this.state.opened && /*#__PURE__*/createElement(ModalLauncherKeypressListener, {
797
+ onClose: this.handleCloseModal
798
+ }), this.state.opened && /*#__PURE__*/createElement(ScrollDisabler, null))
799
+ );
800
+ }
1074
801
 
1075
- _classCallCheck(this, ModalLauncherKeypressListener);
802
+ }
803
+ /** A component that, when mounted, calls `onClose` when Escape is pressed. */
1076
804
 
1077
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
1078
- args[_key2] = arguments[_key2];
1079
- }
805
+ ModalLauncher.defaultProps = {
806
+ backdropDismissEnabled: true
807
+ };
1080
808
 
1081
- _this2 = _super2.call.apply(_super2, [this].concat(args));
809
+ class ModalLauncherKeypressListener extends Component {
810
+ constructor(...args) {
811
+ super(...args);
1082
812
 
1083
- _defineProperty(_assertThisInitialized(_this2), "_handleKeyup", function (e) {
813
+ this._handleKeyup = e => {
1084
814
  // We check the key as that's keyboard layout agnostic and also avoids
1085
815
  // the minefield of deprecated number type properties like keyCode and
1086
816
  // which, with the replacement code, which uses a string instead.
@@ -1093,35 +823,26 @@ var ModalLauncherKeypressListener = /*#__PURE__*/function (_React$Component2) {
1093
823
  // unexpectedly cancels multiple things.
1094
824
  e.preventDefault();
1095
825
  e.stopPropagation();
1096
-
1097
- _this2.props.onClose();
826
+ this.props.onClose();
1098
827
  }
1099
- });
828
+ };
829
+ }
1100
830
 
1101
- return _this2;
831
+ componentDidMount() {
832
+ window.addEventListener("keyup", this._handleKeyup);
1102
833
  }
1103
834
 
1104
- _createClass(ModalLauncherKeypressListener, [{
1105
- key: "componentDidMount",
1106
- value: function componentDidMount() {
1107
- window.addEventListener("keyup", this._handleKeyup);
1108
- }
1109
- }, {
1110
- key: "componentWillUnmount",
1111
- value: function componentWillUnmount() {
1112
- window.removeEventListener("keyup", this._handleKeyup);
1113
- }
1114
- }, {
1115
- key: "render",
1116
- value: function render() {
1117
- return null;
1118
- }
1119
- }]);
835
+ componentWillUnmount() {
836
+ window.removeEventListener("keyup", this._handleKeyup);
837
+ }
1120
838
 
1121
- return ModalLauncherKeypressListener;
1122
- }(Component);
839
+ render() {
840
+ return null;
841
+ }
1123
842
 
1124
- var styles$2 = StyleSheet.create({
843
+ }
844
+
845
+ const styles$2 = StyleSheet.create({
1125
846
  container: {
1126
847
  // This z-index is copied from the Khan Academy webapp.
1127
848
  //
@@ -1135,51 +856,34 @@ var styles$2 = StyleSheet.create({
1135
856
  /**
1136
857
  * The Modal content included after the header
1137
858
  */
1138
- var ModalContent = /*#__PURE__*/function (_React$Component) {
1139
- _inherits(ModalContent, _React$Component);
1140
-
1141
- var _super = _createSuper(ModalContent);
1142
-
1143
- function ModalContent() {
1144
- _classCallCheck(this, ModalContent);
1145
-
1146
- return _super.apply(this, arguments);
859
+ class ModalContent extends Component {
860
+ static isClassOf(instance) {
861
+ return instance && instance.type && instance.type.__IS_MODAL_CONTENT__;
1147
862
  }
1148
863
 
1149
- _createClass(ModalContent, [{
1150
- key: "render",
1151
- value: function render() {
1152
- var _this$props = this.props,
1153
- scrollOverflow = _this$props.scrollOverflow,
1154
- style = _this$props.style,
1155
- children = _this$props.children;
1156
- return /*#__PURE__*/createElement(MediaLayout, {
1157
- styleSheets: styleSheets$2
1158
- }, function (_ref) {
1159
- var styles = _ref.styles;
1160
- return /*#__PURE__*/createElement(View, {
1161
- style: [styles.wrapper, scrollOverflow && styles.scrollOverflow]
1162
- }, /*#__PURE__*/createElement(View, {
1163
- style: [styles.content, style]
1164
- }, children));
1165
- });
1166
- }
1167
- }], [{
1168
- key: "isClassOf",
1169
- value: function isClassOf(instance) {
1170
- return instance && instance.type && instance.type.__IS_MODAL_CONTENT__;
1171
- }
1172
- }]);
1173
-
1174
- return ModalContent;
1175
- }(Component);
864
+ render() {
865
+ const {
866
+ scrollOverflow,
867
+ style,
868
+ children
869
+ } = this.props;
870
+ return /*#__PURE__*/createElement(MediaLayout, {
871
+ styleSheets: styleSheets$2
872
+ }, ({
873
+ styles
874
+ }) => /*#__PURE__*/createElement(View, {
875
+ style: [styles.wrapper, scrollOverflow && styles.scrollOverflow]
876
+ }, /*#__PURE__*/createElement(View, {
877
+ style: [styles.content, style]
878
+ }, children)));
879
+ }
1176
880
 
1177
- _defineProperty(ModalContent, "defaultProps", {
881
+ }
882
+ ModalContent.defaultProps = {
1178
883
  scrollOverflow: true
1179
- });
1180
-
1181
- _defineProperty(ModalContent, "__IS_MODAL_CONTENT__", true);
1182
- var styleSheets$2 = {
884
+ };
885
+ ModalContent.__IS_MODAL_CONTENT__ = true;
886
+ const styleSheets$2 = {
1183
887
  all: StyleSheet.create({
1184
888
  wrapper: {
1185
889
  flex: 1,
@@ -1199,54 +903,41 @@ var styleSheets$2 = {
1199
903
  }),
1200
904
  small: StyleSheet.create({
1201
905
  content: {
1202
- padding: "".concat(Spacing.xLarge_32, "px ").concat(Spacing.medium_16, "px")
906
+ padding: `${Spacing.xLarge_32}px ${Spacing.medium_16}px`
1203
907
  }
1204
908
  })
1205
909
  };
1206
910
 
1207
- var CloseButton = /*#__PURE__*/function (_React$Component) {
1208
- _inherits(CloseButton, _React$Component);
1209
-
1210
- var _super = _createSuper(CloseButton);
1211
-
1212
- function CloseButton() {
1213
- _classCallCheck(this, CloseButton);
1214
-
1215
- return _super.apply(this, arguments);
1216
- }
1217
-
1218
- _createClass(CloseButton, [{
1219
- key: "render",
1220
- value: function render() {
1221
- var _this$props = this.props,
1222
- light = _this$props.light,
1223
- onClick = _this$props.onClick,
1224
- style = _this$props.style,
1225
- testId = _this$props.testId;
1226
- return /*#__PURE__*/createElement(ModalContext.Consumer, null, function (_ref) {
1227
- var closeModal = _ref.closeModal;
1228
-
1229
- if (closeModal && onClick) {
1230
- throw new Error("You've specified 'onClose' on a modal when using ModalLauncher. Please specify 'onClose' on the ModalLauncher instead");
1231
- }
911
+ class CloseButton extends Component {
912
+ render() {
913
+ const {
914
+ light,
915
+ onClick,
916
+ style,
917
+ testId
918
+ } = this.props;
919
+ return /*#__PURE__*/createElement(ModalContext.Consumer, null, ({
920
+ closeModal
921
+ }) => {
922
+ if (closeModal && onClick) {
923
+ throw new Error("You've specified 'onClose' on a modal when using ModalLauncher. Please specify 'onClose' on the ModalLauncher instead");
924
+ }
1232
925
 
1233
- return /*#__PURE__*/createElement(IconButton, {
1234
- icon: icons.dismiss // TODO(mdr): Translate this string for i18n.
1235
- // TODO(kevinb): provide a way to set this label
1236
- ,
1237
- "aria-label": "Close modal",
1238
- onClick: onClick || closeModal,
1239
- kind: light ? "primary" : "tertiary",
1240
- light: light,
1241
- style: style,
1242
- testId: testId
1243
- });
926
+ return /*#__PURE__*/createElement(IconButton, {
927
+ icon: icons.dismiss // TODO(mdr): Translate this string for i18n.
928
+ // TODO(kevinb): provide a way to set this label
929
+ ,
930
+ "aria-label": "Close modal",
931
+ onClick: onClick || closeModal,
932
+ kind: light ? "primary" : "tertiary",
933
+ light: light,
934
+ style: style,
935
+ testId: testId
1244
936
  });
1245
- }
1246
- }]);
937
+ });
938
+ }
1247
939
 
1248
- return CloseButton;
1249
- }(Component);
940
+ }
1250
941
 
1251
942
  /**
1252
943
  * ModalPanel is the content container.
@@ -1268,73 +959,59 @@ var CloseButton = /*#__PURE__*/function (_React$Component) {
1268
959
  * </ModalDialog>
1269
960
  * ```
1270
961
  */
1271
- var ModalPanel = /*#__PURE__*/function (_React$Component) {
1272
- _inherits(ModalPanel, _React$Component);
1273
-
1274
- var _super = _createSuper(ModalPanel);
1275
-
1276
- function ModalPanel() {
1277
- _classCallCheck(this, ModalPanel);
962
+ class ModalPanel extends Component {
963
+ renderMainContent() {
964
+ const {
965
+ content,
966
+ footer,
967
+ scrollOverflow
968
+ } = this.props;
969
+ const mainContent = ModalContent.isClassOf(content) ? content : /*#__PURE__*/createElement(ModalContent, null, content);
970
+
971
+ if (!mainContent) {
972
+ return mainContent;
973
+ }
1278
974
 
1279
- return _super.apply(this, arguments);
975
+ return /*#__PURE__*/cloneElement(mainContent, {
976
+ // Pass the scrollOverflow and header in to the main content
977
+ scrollOverflow,
978
+ // We override the styling of the main content to help position
979
+ // it if there is a footer or close button being
980
+ // shown. We have to do this here as the ModalContent doesn't
981
+ // know about things being positioned around it.
982
+ style: [!!footer && styles$3.hasFooter, mainContent.props.style]
983
+ });
1280
984
  }
1281
985
 
1282
- _createClass(ModalPanel, [{
1283
- key: "renderMainContent",
1284
- value: function renderMainContent() {
1285
- var _this$props = this.props,
1286
- content = _this$props.content,
1287
- footer = _this$props.footer,
1288
- scrollOverflow = _this$props.scrollOverflow;
1289
- var mainContent = ModalContent.isClassOf(content) ? content : /*#__PURE__*/createElement(ModalContent, null, content);
1290
-
1291
- if (!mainContent) {
1292
- return mainContent;
1293
- }
1294
-
1295
- return cloneElement(mainContent, {
1296
- // Pass the scrollOverflow and header in to the main content
1297
- scrollOverflow: scrollOverflow,
1298
- // We override the styling of the main content to help position
1299
- // it if there is a footer or close button being
1300
- // shown. We have to do this here as the ModalContent doesn't
1301
- // know about things being positioned around it.
1302
- style: [!!footer && styles$3.hasFooter, mainContent.props.style]
1303
- });
1304
- }
1305
- }, {
1306
- key: "render",
1307
- value: function render() {
1308
- var _this$props2 = this.props,
1309
- closeButtonVisible = _this$props2.closeButtonVisible,
1310
- footer = _this$props2.footer,
1311
- header = _this$props2.header,
1312
- light = _this$props2.light,
1313
- onClose = _this$props2.onClose,
1314
- style = _this$props2.style,
1315
- testId = _this$props2.testId;
1316
- var mainContent = this.renderMainContent();
1317
- return /*#__PURE__*/createElement(View, {
1318
- style: [styles$3.wrapper, !light && styles$3.dark, style],
1319
- testId: testId && "".concat(testId, "-panel")
1320
- }, closeButtonVisible && /*#__PURE__*/createElement(CloseButton, {
1321
- light: !light,
1322
- onClick: onClose,
1323
- style: styles$3.closeButton,
1324
- testId: testId && "".concat(testId, "-close")
1325
- }), header, mainContent, !footer || ModalFooter.isClassOf(footer) ? footer : /*#__PURE__*/createElement(ModalFooter, null, footer));
1326
- }
1327
- }]);
1328
-
1329
- return ModalPanel;
1330
- }(Component);
986
+ render() {
987
+ const {
988
+ closeButtonVisible,
989
+ footer,
990
+ header,
991
+ light,
992
+ onClose,
993
+ style,
994
+ testId
995
+ } = this.props;
996
+ const mainContent = this.renderMainContent();
997
+ return /*#__PURE__*/createElement(View, {
998
+ style: [styles$3.wrapper, !light && styles$3.dark, style],
999
+ testId: testId && `${testId}-panel`
1000
+ }, closeButtonVisible && /*#__PURE__*/createElement(CloseButton, {
1001
+ light: !light,
1002
+ onClick: onClose,
1003
+ style: styles$3.closeButton,
1004
+ testId: testId && `${testId}-close`
1005
+ }), header, mainContent, !footer || ModalFooter.isClassOf(footer) ? footer : /*#__PURE__*/createElement(ModalFooter, null, footer));
1006
+ }
1331
1007
 
1332
- _defineProperty(ModalPanel, "defaultProps", {
1008
+ }
1009
+ ModalPanel.defaultProps = {
1333
1010
  closeButtonVisible: true,
1334
1011
  scrollOverflow: true,
1335
1012
  light: true
1336
- });
1337
- var styles$3 = StyleSheet.create({
1013
+ };
1014
+ const styles$3 = StyleSheet.create({
1338
1015
  wrapper: {
1339
1016
  flex: "1 1 auto",
1340
1017
  position: "relative",
@@ -1369,101 +1046,80 @@ var styles$3 = StyleSheet.create({
1369
1046
  * The ModalHeader is required, but the ModalFooter is optional.
1370
1047
  * The content of the dialog itself is fully customizable, but the left/right/top/bottom padding is fixed.
1371
1048
  */
1372
- var OnePaneDialog = /*#__PURE__*/function (_React$Component) {
1373
- _inherits(OnePaneDialog, _React$Component);
1374
-
1375
- var _super = _createSuper(OnePaneDialog);
1376
-
1377
- function OnePaneDialog() {
1378
- _classCallCheck(this, OnePaneDialog);
1379
-
1380
- return _super.apply(this, arguments);
1381
- }
1382
-
1383
- _createClass(OnePaneDialog, [{
1384
- key: "renderHeader",
1385
- value: function renderHeader(uniqueId) {
1386
- var _this$props = this.props,
1387
- title = _this$props.title,
1388
- _this$props$breadcrum = _this$props.breadcrumbs,
1389
- breadcrumbs = _this$props$breadcrum === void 0 ? undefined : _this$props$breadcrum,
1390
- _this$props$subtitle = _this$props.subtitle,
1391
- subtitle = _this$props$subtitle === void 0 ? undefined : _this$props$subtitle,
1392
- testId = _this$props.testId;
1393
-
1394
- if (breadcrumbs) {
1395
- return /*#__PURE__*/createElement(ModalHeader, {
1396
- title: title,
1397
- breadcrumbs: breadcrumbs,
1398
- titleId: uniqueId,
1399
- testId: testId && "".concat(testId, "-header")
1400
- });
1401
- } else if (subtitle) {
1402
- return /*#__PURE__*/createElement(ModalHeader, {
1403
- title: title,
1404
- subtitle: subtitle,
1405
- titleId: uniqueId,
1406
- testId: testId && "".concat(testId, "-header")
1407
- });
1408
- } else {
1409
- return /*#__PURE__*/createElement(ModalHeader, {
1410
- title: title,
1411
- titleId: uniqueId,
1412
- testId: testId && "".concat(testId, "-header")
1413
- });
1414
- }
1415
- }
1416
- }, {
1417
- key: "render",
1418
- value: function render() {
1419
- var _this = this;
1420
-
1421
- var _this$props2 = this.props,
1422
- onClose = _this$props2.onClose,
1423
- footer = _this$props2.footer,
1424
- content = _this$props2.content,
1425
- above = _this$props2.above,
1426
- below = _this$props2.below,
1427
- style = _this$props2.style,
1428
- closeButtonVisible = _this$props2.closeButtonVisible,
1429
- testId = _this$props2.testId,
1430
- titleId = _this$props2.titleId,
1431
- role = _this$props2.role;
1432
- return /*#__PURE__*/createElement(MediaLayout, {
1433
- styleSheets: styleSheets$3
1434
- }, function (_ref) {
1435
- var styles = _ref.styles;
1436
- return /*#__PURE__*/createElement(IDProvider, {
1437
- id: titleId,
1438
- scope: "modal"
1439
- }, function (uniqueId) {
1440
- return /*#__PURE__*/createElement(ModalDialog, {
1441
- style: [styles.dialog, style],
1442
- above: above,
1443
- below: below,
1444
- testId: testId,
1445
- "aria-labelledby": uniqueId,
1446
- role: role
1447
- }, /*#__PURE__*/createElement(ModalPanel, {
1448
- onClose: onClose,
1449
- header: _this.renderHeader(uniqueId),
1450
- content: content,
1451
- footer: footer,
1452
- closeButtonVisible: closeButtonVisible,
1453
- testId: testId
1454
- }));
1455
- });
1049
+ class OnePaneDialog extends Component {
1050
+ renderHeader(uniqueId) {
1051
+ const {
1052
+ title,
1053
+ breadcrumbs = undefined,
1054
+ subtitle = undefined,
1055
+ testId
1056
+ } = this.props;
1057
+
1058
+ if (breadcrumbs) {
1059
+ return /*#__PURE__*/createElement(ModalHeader, {
1060
+ title: title,
1061
+ breadcrumbs: breadcrumbs,
1062
+ titleId: uniqueId,
1063
+ testId: testId && `${testId}-header`
1064
+ });
1065
+ } else if (subtitle) {
1066
+ return /*#__PURE__*/createElement(ModalHeader, {
1067
+ title: title,
1068
+ subtitle: subtitle,
1069
+ titleId: uniqueId,
1070
+ testId: testId && `${testId}-header`
1071
+ });
1072
+ } else {
1073
+ return /*#__PURE__*/createElement(ModalHeader, {
1074
+ title: title,
1075
+ titleId: uniqueId,
1076
+ testId: testId && `${testId}-header`
1456
1077
  });
1457
1078
  }
1458
- }]);
1079
+ }
1459
1080
 
1460
- return OnePaneDialog;
1461
- }(Component);
1081
+ render() {
1082
+ const {
1083
+ onClose,
1084
+ footer,
1085
+ content,
1086
+ above,
1087
+ below,
1088
+ style,
1089
+ closeButtonVisible,
1090
+ testId,
1091
+ titleId,
1092
+ role
1093
+ } = this.props;
1094
+ return /*#__PURE__*/createElement(MediaLayout, {
1095
+ styleSheets: styleSheets$3
1096
+ }, ({
1097
+ styles
1098
+ }) => /*#__PURE__*/createElement(IDProvider, {
1099
+ id: titleId,
1100
+ scope: "modal"
1101
+ }, uniqueId => /*#__PURE__*/createElement(ModalDialog, {
1102
+ style: [styles.dialog, style],
1103
+ above: above,
1104
+ below: below,
1105
+ testId: testId,
1106
+ "aria-labelledby": uniqueId,
1107
+ role: role
1108
+ }, /*#__PURE__*/createElement(ModalPanel, {
1109
+ onClose: onClose,
1110
+ header: this.renderHeader(uniqueId),
1111
+ content: content,
1112
+ footer: footer,
1113
+ closeButtonVisible: closeButtonVisible,
1114
+ testId: testId
1115
+ }))));
1116
+ }
1462
1117
 
1463
- _defineProperty(OnePaneDialog, "defaultProps", {
1118
+ }
1119
+ OnePaneDialog.defaultProps = {
1464
1120
  closeButtonVisible: true
1465
- });
1466
- var styleSheets$3 = {
1121
+ };
1122
+ const styleSheets$3 = {
1467
1123
  small: StyleSheet.create({
1468
1124
  dialog: {
1469
1125
  width: "100%",
@@ -1490,7 +1146,7 @@ var styleSheets$3 = {
1490
1146
  */
1491
1147
 
1492
1148
  function maybeGetNextAncestorModalLauncherPortal(element) {
1493
- var candidateElement = element && element.parentElement;
1149
+ let candidateElement = element && element.parentElement;
1494
1150
 
1495
1151
  while (candidateElement && !candidateElement.hasAttribute(ModalLauncherPortalAttributeName)) {
1496
1152
  candidateElement = candidateElement.parentElement;