@khanacademy/wonder-blocks-modal 2.1.42 → 2.2.0

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/index.js CHANGED
@@ -82,7 +82,7 @@ module.exports =
82
82
  /******/
83
83
  /******/
84
84
  /******/ // Load entry module and return exports
85
- /******/ return __webpack_require__(__webpack_require__.s = 11);
85
+ /******/ return __webpack_require__(__webpack_require__.s = 25);
86
86
  /******/ })
87
87
  /************************************************************************/
88
88
  /******/ ([
@@ -129,82 +129,232 @@ module.exports = require("react-dom");
129
129
 
130
130
  /***/ }),
131
131
  /* 7 */
132
- /***/ (function(module, exports) {
132
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
133
133
 
134
- module.exports = require("@khanacademy/wonder-blocks-typography");
134
+ "use strict";
135
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ModalHeader; });
136
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
137
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
138
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
139
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
140
+ /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
141
+ /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__);
142
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2);
143
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__);
144
+ /* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5);
145
+ /* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_4__);
146
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(1);
147
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5__);
148
+ /* harmony import */ var _khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(13);
149
+ /* harmony import */ var _khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_6__);
135
150
 
136
- /***/ }),
137
- /* 8 */
138
- /***/ (function(module, exports) {
139
151
 
140
- function _extends() {
141
- module.exports = _extends = Object.assign || function (target) {
142
- for (var i = 1; i < arguments.length; i++) {
143
- var source = arguments[i];
144
152
 
145
- for (var key in source) {
146
- if (Object.prototype.hasOwnProperty.call(source, key)) {
147
- target[key] = source[key];
148
- }
149
- }
150
- }
151
153
 
152
- return target;
153
- };
154
154
 
155
- module.exports["default"] = module.exports, module.exports.__esModule = true;
156
- return _extends.apply(this, arguments);
157
- }
158
155
 
159
- module.exports = _extends;
160
- module.exports["default"] = module.exports, module.exports.__esModule = true;
161
156
 
162
- /***/ }),
163
- /* 9 */
164
- /***/ (function(module, exports) {
165
157
 
166
- module.exports = require("@khanacademy/wonder-blocks-icon");
158
+ /**
159
+ * This is a helper component that is never rendered by itself. It is always
160
+ * pinned to the top of the dialog, is responsive using the same behavior as its
161
+ * parent dialog, and has the following properties:
162
+ * - title
163
+ * - breadcrumb OR subtitle, but not both.
164
+ *
165
+ * **Accessibility notes:**
166
+ *
167
+ * - By default (e.g. using [OnePaneDialog](/#onepanedialog)), `titleId` is
168
+ * populated automatically by the parent container.
169
+ * - If there is a custom Dialog implementation (e.g. `TwoPaneDialog`), the
170
+ * ModalHeader doesn’t have to have the `titleId` prop however this is
171
+ * recommended. It should match the `aria-labelledby` prop of the
172
+ * [ModalDialog](/#modaldialog) component. If you want to see an example of
173
+ * how to generate this ID, check [IDProvider](/#idprovider).
174
+ *
175
+ * **Implementation notes:**
176
+ *
177
+ * If you are creating a custom Dialog, make sure to follow these guidelines:
178
+ * - Make sure to include it as part of [ModalPanel](/#modalpanel) by using the
179
+ * `header` prop.
180
+ * - Add a title (required).
181
+ * - Optionally add a subtitle or breadcrumbs.
182
+ * - We encourage you to add `titleId` (see Accessibility notes).
183
+ * - If the `ModalPanel` has a dark background, make sure to set `light` to
184
+ * `false`.
185
+ * - If you need to create e2e tests, make sure to pass a `testId` prop and
186
+ * add a sufix to scope the testId to this component: e.g.
187
+ * `some-random-id-ModalHeader`. This scope will also be passed to the title
188
+ * and subtitle elements: e.g. `some-random-id-ModalHeader-title`.
189
+ *
190
+ * Example:
191
+ *
192
+ * ```js
193
+ * <ModalHeader
194
+ * title="Sidebar using ModalHeader"
195
+ * subtitle="subtitle"
196
+ * titleId="uniqueTitleId"
197
+ * light={false}
198
+ * />
199
+ * ```
200
+ */
201
+ class ModalHeader extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
202
+ render() {
203
+ const {
204
+ breadcrumbs = undefined,
205
+ light,
206
+ subtitle = undefined,
207
+ testId,
208
+ title,
209
+ titleId
210
+ } = this.props;
167
211
 
168
- /***/ }),
169
- /* 10 */
170
- /***/ (function(module, exports) {
212
+ if (subtitle && breadcrumbs) {
213
+ throw new Error("'subtitle' and 'breadcrumbs' can't be used together");
214
+ }
171
215
 
172
- module.exports = require("@khanacademy/wonder-blocks-icon-button");
216
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_4__["MediaLayout"], {
217
+ styleSheets: styleSheets
218
+ }, ({
219
+ styles
220
+ }) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
221
+ style: [styles.header, !light && styles.dark],
222
+ testId: testId
223
+ }, breadcrumbs && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
224
+ style: styles.breadcrumbs
225
+ }, breadcrumbs), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_6__["HeadingMedium"], {
226
+ style: styles.title,
227
+ id: titleId,
228
+ testId: testId && `${testId}-title`
229
+ }, title), subtitle && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_6__["LabelSmall"], {
230
+ style: light && styles.subtitle,
231
+ testId: testId && `${testId}-subtitle`
232
+ }, subtitle)));
233
+ }
234
+
235
+ }
236
+ ModalHeader.defaultProps = {
237
+ light: true
238
+ };
239
+ const styleSheets = {
240
+ all: aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
241
+ header: {
242
+ boxShadow: `0px 1px 0px ${_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack16}`,
243
+ display: "flex",
244
+ flexDirection: "column",
245
+ minHeight: 66,
246
+ padding: `${_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default.a.large_24}px ${_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default.a.xLarge_32}px`,
247
+ position: "relative",
248
+ width: "100%"
249
+ },
250
+ dark: {
251
+ background: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.darkBlue,
252
+ color: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.white
253
+ },
254
+ breadcrumbs: {
255
+ color: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack64,
256
+ marginBottom: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default.a.xSmall_8
257
+ },
258
+ title: {
259
+ // Prevent title from overlapping the close button
260
+ paddingRight: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default.a.medium_16
261
+ },
262
+ subtitle: {
263
+ color: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack64,
264
+ marginTop: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default.a.xSmall_8
265
+ }
266
+ }),
267
+ small: aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
268
+ header: {
269
+ paddingLeft: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default.a.medium_16,
270
+ paddingRight: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default.a.medium_16
271
+ },
272
+ title: {
273
+ paddingRight: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_5___default.a.xLarge_32
274
+ }
275
+ })
276
+ };
173
277
 
174
278
  /***/ }),
175
- /* 11 */
279
+ /* 8 */
176
280
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
177
281
 
178
282
  "use strict";
179
- // ESM COMPAT FLAG
180
- __webpack_require__.r(__webpack_exports__);
283
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ModalFooter; });
284
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
285
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
286
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
287
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
288
+ /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
289
+ /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__);
290
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2);
291
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__);
292
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
293
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__);
294
+
295
+
181
296
 
182
- // EXPORTS
183
- __webpack_require__.d(__webpack_exports__, "ModalHeader", function() { return /* reexport */ modal_header_ModalHeader; });
184
- __webpack_require__.d(__webpack_exports__, "ModalFooter", function() { return /* reexport */ modal_footer_ModalFooter; });
185
- __webpack_require__.d(__webpack_exports__, "ModalDialog", function() { return /* reexport */ modal_dialog_ModalDialog; });
186
- __webpack_require__.d(__webpack_exports__, "ModalPanel", function() { return /* reexport */ modal_panel_ModalPanel; });
187
- __webpack_require__.d(__webpack_exports__, "ModalLauncher", function() { return /* reexport */ modal_launcher_ModalLauncher; });
188
- __webpack_require__.d(__webpack_exports__, "OnePaneDialog", function() { return /* reexport */ one_pane_dialog_OnePaneDialog; });
189
- __webpack_require__.d(__webpack_exports__, "maybeGetPortalMountedModalHostElement", function() { return /* reexport */ maybeGetPortalMountedModalHostElement; });
190
297
 
191
- // EXTERNAL MODULE: external "react"
192
- var external_react_ = __webpack_require__(0);
193
298
 
194
- // EXTERNAL MODULE: external "aphrodite"
195
- var external_aphrodite_ = __webpack_require__(3);
196
299
 
197
- // EXTERNAL MODULE: external "@khanacademy/wonder-blocks-layout"
198
- var wonder_blocks_layout_ = __webpack_require__(5);
300
+ /**
301
+ * Modal footer included after the content.
302
+ *
303
+ * **Implementation notes**:
304
+ *
305
+ * If you are creating a custom Dialog, make sure to follow these guidelines:
306
+ * - Make sure to include it as part of [ModalPanel](/#modalpanel) by using the `footer` prop.
307
+ * - The footer is completely flexible. Meaning the developer needs to add its own custom layout to match design specs.
308
+ */
309
+ class ModalFooter extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
310
+ static isClassOf(instance) {
311
+ return instance && instance.type && instance.type.__IS_MODAL_FOOTER__;
312
+ }
313
+
314
+ render() {
315
+ const {
316
+ children
317
+ } = this.props;
318
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
319
+ style: styles.footer
320
+ }, children);
321
+ }
199
322
 
200
- // EXTERNAL MODULE: external "@khanacademy/wonder-blocks-core"
201
- var wonder_blocks_core_ = __webpack_require__(2);
323
+ }
324
+ ModalFooter.__IS_MODAL_FOOTER__ = true;
325
+ const styles = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
326
+ footer: {
327
+ flex: "0 0 auto",
328
+ boxSizing: "border-box",
329
+ minHeight: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xxxLarge_64,
330
+ paddingLeft: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16,
331
+ paddingRight: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16,
332
+ paddingTop: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xSmall_8,
333
+ paddingBottom: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xSmall_8,
334
+ display: "flex",
335
+ flexDirection: "row",
336
+ alignItems: "center",
337
+ justifyContent: "flex-end",
338
+ boxShadow: `0px -1px 0px ${_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack16}`
339
+ }
340
+ });
202
341
 
203
- // EXTERNAL MODULE: external "@khanacademy/wonder-blocks-spacing"
204
- var wonder_blocks_spacing_ = __webpack_require__(1);
205
- var wonder_blocks_spacing_default = /*#__PURE__*/__webpack_require__.n(wonder_blocks_spacing_);
342
+ /***/ }),
343
+ /* 9 */
344
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
206
345
 
207
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/modal-dialog.js
346
+ "use strict";
347
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ModalDialog; });
348
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
349
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
350
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
351
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
352
+ /* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
353
+ /* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__);
354
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2);
355
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__);
356
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
357
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__);
208
358
 
209
359
 
210
360
 
@@ -221,7 +371,7 @@ var wonder_blocks_spacing_default = /*#__PURE__*/__webpack_require__.n(wonder_bl
221
371
  * - If there is a custom Dialog implementation (e.g. `TwoPaneDialog`), the dialog element doesn’t have to have
222
372
  * the `aria-labelledby` attribute however this is recommended. It should match the `id` of the dialog title.
223
373
  */
224
- class modal_dialog_ModalDialog extends external_react_["Component"] {
374
+ class ModalDialog extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
225
375
  render() {
226
376
  const {
227
377
  above,
@@ -234,35 +384,35 @@ class modal_dialog_ModalDialog extends external_react_["Component"] {
234
384
  } = this.props;
235
385
  const contextValue = {
236
386
  ssrSize: "large",
237
- mediaSpec: wonder_blocks_layout_["MEDIA_MODAL_SPEC"]
387
+ mediaSpec: _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__["MEDIA_MODAL_SPEC"]
238
388
  };
239
- return /*#__PURE__*/external_react_["createElement"](wonder_blocks_layout_["MediaLayoutContext"].Provider, {
389
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__["MediaLayoutContext"].Provider, {
240
390
  value: contextValue
241
- }, /*#__PURE__*/external_react_["createElement"](wonder_blocks_layout_["MediaLayout"], {
391
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__["MediaLayout"], {
242
392
  styleSheets: styleSheets
243
393
  }, ({
244
394
  styles
245
- }) => /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
395
+ }) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
246
396
  style: [styles.wrapper, style]
247
- }, below && /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
397
+ }, below && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
248
398
  style: styles.below
249
- }, below), /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
399
+ }, below), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
250
400
  role: role,
251
401
  "aria-modal": "true",
252
402
  "aria-labelledby": ariaLabelledBy,
253
403
  style: styles.dialog,
254
404
  testId: testId
255
- }, children), above && /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
405
+ }, children), above && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
256
406
  style: styles.above
257
407
  }, above))));
258
408
  }
259
409
 
260
410
  }
261
- modal_dialog_ModalDialog.defaultProps = {
411
+ ModalDialog.defaultProps = {
262
412
  role: "dialog"
263
413
  };
264
414
  const styleSheets = {
265
- all: external_aphrodite_["StyleSheet"].create({
415
+ all: aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
266
416
  wrapper: {
267
417
  display: "flex",
268
418
  flexDirection: "row",
@@ -300,18 +450,38 @@ const styleSheets = {
300
450
  zIndex: -1
301
451
  }
302
452
  }),
303
- small: external_aphrodite_["StyleSheet"].create({
453
+ small: aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
304
454
  wrapper: {
305
- padding: wonder_blocks_spacing_default.a.medium_16,
455
+ padding: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16,
306
456
  flexDirection: "column"
307
457
  }
308
458
  })
309
459
  };
310
- // EXTERNAL MODULE: external "@khanacademy/wonder-blocks-color"
311
- var wonder_blocks_color_ = __webpack_require__(4);
312
- var wonder_blocks_color_default = /*#__PURE__*/__webpack_require__.n(wonder_blocks_color_);
313
460
 
314
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/modal-footer.js
461
+ /***/ }),
462
+ /* 10 */
463
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
464
+
465
+ "use strict";
466
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ModalPanel; });
467
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
468
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
469
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
470
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
471
+ /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
472
+ /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__);
473
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2);
474
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__);
475
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
476
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__);
477
+ /* harmony import */ var _modal_content_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(14);
478
+ /* harmony import */ var _modal_header_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7);
479
+ /* harmony import */ var _modal_footer_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(8);
480
+ /* harmony import */ var _close_button_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(22);
481
+
482
+
483
+
484
+
315
485
 
316
486
 
317
487
 
@@ -319,52 +489,153 @@ var wonder_blocks_color_default = /*#__PURE__*/__webpack_require__.n(wonder_bloc
319
489
 
320
490
 
321
491
  /**
322
- * Modal footer included after the content.
492
+ * ModalPanel is the content container.
323
493
  *
324
- * **Implementation notes**:
494
+ * **Implementation notes:**
325
495
  *
326
496
  * If you are creating a custom Dialog, make sure to follow these guidelines:
327
- * - Make sure to include it as part of [ModalPanel](/#modalpanel) by using the `footer` prop.
328
- * - The footer is completely flexible. Meaning the developer needs to add its own custom layout to match design specs.
497
+ * - Make sure to add this component inside the [ModalDialog](/#modaldialog).
498
+ * - If needed, you can also add a [ModalHeader](/#modalheader) using the
499
+ * `header` prop. Same goes for [ModalFooter](/#modalfooter).
500
+ * - If you need to create e2e tests, make sure to pass a `testId` prop. This
501
+ * will be passed down to this component using a sufix: e.g.
502
+ * `some-random-id-ModalPanel`. This scope will be propagated to the
503
+ * CloseButton element as well: e.g. `some-random-id-CloseButton`.
504
+ *
505
+ * ```js
506
+ * <ModalDialog>
507
+ * <ModalPanel content={"custom content goes here"} />
508
+ * </ModalDialog>
509
+ * ```
329
510
  */
330
- class modal_footer_ModalFooter extends external_react_["Component"] {
331
- static isClassOf(instance) {
332
- return instance && instance.type && instance.type.__IS_MODAL_FOOTER__;
511
+ class ModalPanel extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
512
+ renderMainContent() {
513
+ const {
514
+ content,
515
+ footer,
516
+ scrollOverflow
517
+ } = this.props;
518
+ const mainContent = _modal_content_js__WEBPACK_IMPORTED_MODULE_5__[/* default */ "a"].isClassOf(content) ? content : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_content_js__WEBPACK_IMPORTED_MODULE_5__[/* default */ "a"], null, content);
519
+
520
+ if (!mainContent) {
521
+ return mainContent;
522
+ }
523
+
524
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["cloneElement"](mainContent, {
525
+ // Pass the scrollOverflow and header in to the main content
526
+ scrollOverflow,
527
+ // We override the styling of the main content to help position
528
+ // it if there is a footer or close button being
529
+ // shown. We have to do this here as the ModalContent doesn't
530
+ // know about things being positioned around it.
531
+ style: [!!footer && styles.hasFooter, mainContent.props.style]
532
+ });
333
533
  }
334
534
 
335
535
  render() {
336
536
  const {
337
- children
537
+ closeButtonVisible,
538
+ footer,
539
+ header,
540
+ light,
541
+ onClose,
542
+ style,
543
+ testId
338
544
  } = this.props;
339
- return /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
340
- style: modal_footer_styles.footer
341
- }, children);
545
+ const mainContent = this.renderMainContent();
546
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
547
+ style: [styles.wrapper, !light && styles.dark, style],
548
+ testId: testId && `${testId}-panel`
549
+ }, closeButtonVisible && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_close_button_js__WEBPACK_IMPORTED_MODULE_8__[/* default */ "a"], {
550
+ light: !light,
551
+ onClick: onClose,
552
+ style: styles.closeButton,
553
+ testId: testId && `${testId}-close`
554
+ }), header, mainContent, !footer || _modal_footer_js__WEBPACK_IMPORTED_MODULE_7__[/* default */ "a"].isClassOf(footer) ? footer : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_footer_js__WEBPACK_IMPORTED_MODULE_7__[/* default */ "a"], null, footer));
342
555
  }
343
556
 
344
557
  }
345
- modal_footer_ModalFooter.__IS_MODAL_FOOTER__ = true;
346
- const modal_footer_styles = external_aphrodite_["StyleSheet"].create({
347
- footer: {
348
- flex: "0 0 auto",
349
- boxSizing: "border-box",
350
- minHeight: wonder_blocks_spacing_default.a.xxxLarge_64,
351
- paddingLeft: wonder_blocks_spacing_default.a.medium_16,
352
- paddingRight: wonder_blocks_spacing_default.a.medium_16,
353
- paddingTop: wonder_blocks_spacing_default.a.xSmall_8,
354
- paddingBottom: wonder_blocks_spacing_default.a.xSmall_8,
558
+ ModalPanel.defaultProps = {
559
+ closeButtonVisible: true,
560
+ scrollOverflow: true,
561
+ light: true
562
+ };
563
+ const styles = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
564
+ wrapper: {
565
+ flex: "1 1 auto",
566
+ position: "relative",
355
567
  display: "flex",
356
- flexDirection: "row",
357
- alignItems: "center",
358
- justifyContent: "flex-end",
359
- boxShadow: `0px -1px 0px ${wonder_blocks_color_default.a.offBlack16}`
568
+ flexDirection: "column",
569
+ background: "white",
570
+ boxSizing: "border-box",
571
+ overflow: "hidden",
572
+ height: "100%",
573
+ width: "100%"
574
+ },
575
+ closeButton: {
576
+ position: "absolute",
577
+ right: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16,
578
+ top: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16,
579
+ // This is to allow the button to be tab-ordered before the modal
580
+ // content but still be above the header and content.
581
+ zIndex: 1
582
+ },
583
+ dark: {
584
+ background: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.darkBlue,
585
+ color: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.white
586
+ },
587
+ hasFooter: {
588
+ paddingBottom: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xLarge_32
360
589
  }
361
590
  });
362
- // EXTERNAL MODULE: external "@khanacademy/wonder-blocks-typography"
363
- var wonder_blocks_typography_ = __webpack_require__(7);
364
-
365
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/modal-header.js
366
591
 
592
+ /***/ }),
593
+ /* 11 */
594
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
367
595
 
596
+ "use strict";
597
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ModalLauncherPortalAttributeName; });
598
+ /**
599
+ * The attribute used to identify a modal launcher portal.
600
+ */
601
+ const ModalLauncherPortalAttributeName = "data-modal-launcher-portal";
602
+
603
+
604
+ /***/ }),
605
+ /* 12 */
606
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
607
+
608
+ "use strict";
609
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
610
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
611
+
612
+ const defaultContext = {
613
+ closeModal: undefined
614
+ };
615
+ /* harmony default export */ __webpack_exports__["a"] = (/*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createContext"](defaultContext));
616
+
617
+ /***/ }),
618
+ /* 13 */
619
+ /***/ (function(module, exports) {
620
+
621
+ module.exports = require("@khanacademy/wonder-blocks-typography");
622
+
623
+ /***/ }),
624
+ /* 14 */
625
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
626
+
627
+ "use strict";
628
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ModalContent; });
629
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
630
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
631
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
632
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
633
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
634
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__);
635
+ /* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5);
636
+ /* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3__);
637
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
638
+ /* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__);
368
639
 
369
640
 
370
641
 
@@ -372,132 +643,441 @@ var wonder_blocks_typography_ = __webpack_require__(7);
372
643
 
373
644
 
374
645
  /**
375
- * This is a helper component that is never rendered by itself. It is always
376
- * pinned to the top of the dialog, is responsive using the same behavior as its
377
- * parent dialog, and has the following properties:
378
- * - title
379
- * - breadcrumb OR subtitle, but not both.
380
- *
381
- * **Accessibility notes:**
382
- *
383
- * - By default (e.g. using [OnePaneDialog](/#onepanedialog)), `titleId` is
384
- * populated automatically by the parent container.
385
- * - If there is a custom Dialog implementation (e.g. `TwoPaneDialog`), the
386
- * ModalHeader doesn’t have to have the `titleId` prop however this is
387
- * recommended. It should match the `aria-labelledby` prop of the
388
- * [ModalDialog](/#modaldialog) component. If you want to see an example of
389
- * how to generate this ID, check [IDProvider](/#idprovider).
390
- *
391
- * **Implementation notes:**
392
- *
393
- * If you are creating a custom Dialog, make sure to follow these guidelines:
394
- * - Make sure to include it as part of [ModalPanel](/#modalpanel) by using the
395
- * `header` prop.
396
- * - Add a title (required).
397
- * - Optionally add a subtitle or breadcrumbs.
398
- * - We encourage you to add `titleId` (see Accessibility notes).
399
- * - If the `ModalPanel` has a dark background, make sure to set `light` to
400
- * `false`.
401
- * - If you need to create e2e tests, make sure to pass a `testId` prop and
402
- * add a sufix to scope the testId to this component: e.g.
403
- * `some-random-id-ModalHeader`. This scope will also be passed to the title
404
- * and subtitle elements: e.g. `some-random-id-ModalHeader-title`.
646
+ * The Modal content included after the header
647
+ */
648
+ class ModalContent extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
649
+ static isClassOf(instance) {
650
+ return instance && instance.type && instance.type.__IS_MODAL_CONTENT__;
651
+ }
652
+
653
+ render() {
654
+ const {
655
+ scrollOverflow,
656
+ style,
657
+ children
658
+ } = this.props;
659
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3__["MediaLayout"], {
660
+ styleSheets: styleSheets
661
+ }, ({
662
+ styles
663
+ }) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__["View"], {
664
+ style: [styles.wrapper, scrollOverflow && styles.scrollOverflow]
665
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__["View"], {
666
+ style: [styles.content, style]
667
+ }, children)));
668
+ }
669
+
670
+ }
671
+ ModalContent.defaultProps = {
672
+ scrollOverflow: true
673
+ };
674
+ ModalContent.__IS_MODAL_CONTENT__ = true;
675
+ const styleSheets = {
676
+ all: aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
677
+ wrapper: {
678
+ flex: 1,
679
+ // This helps to ensure that the paddingBottom is preserved when
680
+ // the contents start to overflow, this goes away on display: flex
681
+ display: "block"
682
+ },
683
+ scrollOverflow: {
684
+ overflow: "auto"
685
+ },
686
+ content: {
687
+ flex: 1,
688
+ minHeight: "100%",
689
+ padding: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xLarge_32,
690
+ boxSizing: "border-box"
691
+ }
692
+ }),
693
+ small: aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
694
+ content: {
695
+ padding: `${_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xLarge_32}px ${_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16}px`
696
+ }
697
+ })
698
+ };
699
+
700
+ /***/ }),
701
+ /* 15 */
702
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
703
+
704
+ "use strict";
705
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ModalLauncher; });
706
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
707
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
708
+ /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
709
+ /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
710
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
711
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_2__);
712
+ /* harmony import */ var _focus_trap_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(18);
713
+ /* harmony import */ var _modal_backdrop_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(19);
714
+ /* harmony import */ var _scroll_disabler_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(21);
715
+ /* harmony import */ var _modal_context_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(12);
716
+
717
+
718
+
719
+
720
+
721
+
722
+
723
+
724
+ /**
725
+ * This component enables you to launch a modal, covering the screen.
405
726
  *
406
- * Example:
727
+ * Children have access to `openModal` function via the function-as-children
728
+ * pattern, so one common use case is for this component to wrap a button:
407
729
  *
408
730
  * ```js
409
- * <ModalHeader
410
- * title="Sidebar using ModalHeader"
411
- * subtitle="subtitle"
412
- * titleId="uniqueTitleId"
413
- * light={false}
414
- * />
731
+ * <ModalLauncher modal={<TwoColumnModal ... />}>
732
+ * {({openModal}) => <button onClick={openModal}>Learn more</button>}
733
+ * </ModalLauncher>
415
734
  * ```
735
+ *
736
+ * The actual modal itself is constructed separately, using a layout component
737
+ * like OnePaneDialog and is provided via
738
+ * the `modal` prop.
416
739
  */
417
- class modal_header_ModalHeader extends external_react_["Component"] {
740
+ class ModalLauncher extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
741
+ constructor(...args) {
742
+ super(...args);
743
+ this.state = {
744
+ opened: false
745
+ };
746
+
747
+ this._saveLastElementFocused = () => {
748
+ // keep a reference of the element that triggers the modal
749
+ this.lastElementFocusedOutsideModal = document.activeElement;
750
+ };
751
+
752
+ this._openModal = () => {
753
+ this._saveLastElementFocused();
754
+
755
+ this.setState({
756
+ opened: true
757
+ });
758
+ };
759
+
760
+ this.handleCloseModal = () => {
761
+ this.setState({
762
+ opened: false
763
+ }, () => {
764
+ this.props.onClose && this.props.onClose();
765
+
766
+ if (this.lastElementFocusedOutsideModal != null) {
767
+ // return focus to the element that triggered the modal
768
+ this.lastElementFocusedOutsideModal.focus();
769
+ }
770
+ });
771
+ };
772
+ }
773
+
774
+ static getDerivedStateFromProps(props, state) {
775
+ if (typeof props.opened === "boolean" && props.children) {
776
+ // eslint-disable-next-line no-console
777
+ console.warn("'children' and 'opened' can't be used together");
778
+ }
779
+
780
+ if (typeof props.opened === "boolean" && !props.onClose) {
781
+ // eslint-disable-next-line no-console
782
+ console.warn("'onClose' should be used with 'opened'");
783
+ }
784
+
785
+ if (typeof props.opened !== "boolean" && !props.children) {
786
+ // eslint-disable-next-line no-console
787
+ console.warn("either 'children' or 'opened' must be set");
788
+ }
789
+
790
+ return {
791
+ opened: typeof props.opened === "boolean" ? props.opened : state.opened
792
+ };
793
+ }
794
+
795
+ componentDidUpdate(prevProps) {
796
+ // ensures the element is stored only when the modal is opened
797
+ if (!prevProps.opened && this.props.opened) {
798
+ this._saveLastElementFocused();
799
+ }
800
+ }
801
+
802
+ _renderModal() {
803
+ if (typeof this.props.modal === "function") {
804
+ return this.props.modal({
805
+ closeModal: this.handleCloseModal
806
+ });
807
+ } else {
808
+ return this.props.modal;
809
+ }
810
+ }
811
+
812
+ render() {
813
+ const renderedChildren = this.props.children ? this.props.children({
814
+ openModal: this._openModal
815
+ }) : null;
816
+ const {
817
+ body
818
+ } = document;
819
+
820
+ if (!body) {
821
+ return null;
822
+ }
823
+
824
+ return (
825
+ /*#__PURE__*/
826
+ // This flow check is valid, it's the babel plugin which is broken,
827
+ // see modal-context.js for details.
828
+ // $FlowFixMe
829
+ react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_context_js__WEBPACK_IMPORTED_MODULE_6__[/* default */ "a"].Provider, {
830
+ value: {
831
+ closeModal: this.handleCloseModal
832
+ }
833
+ }, renderedChildren, this.state.opened && /*#__PURE__*/react_dom__WEBPACK_IMPORTED_MODULE_1__["createPortal"](
834
+ /*#__PURE__*/
835
+
836
+ /* We need the container View that FocusTrap creates to be at the
837
+ correct z-index so that it'll be above the global nav in webapp. */
838
+ react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_focus_trap_js__WEBPACK_IMPORTED_MODULE_3__[/* default */ "a"], {
839
+ style: styles.container
840
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_backdrop_js__WEBPACK_IMPORTED_MODULE_4__[/* default */ "a"], {
841
+ initialFocusId: this.props.initialFocusId,
842
+ testId: this.props.testId,
843
+ onCloseModal: this.props.backdropDismissEnabled ? this.handleCloseModal : () => {}
844
+ }, this._renderModal())), body), this.state.opened && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](ModalLauncherKeypressListener, {
845
+ onClose: this.handleCloseModal
846
+ }), this.state.opened && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_scroll_disabler_js__WEBPACK_IMPORTED_MODULE_5__[/* default */ "a"], null))
847
+ );
848
+ }
849
+
850
+ }
851
+ /** A component that, when mounted, calls `onClose` when Escape is pressed. */
852
+
853
+ ModalLauncher.defaultProps = {
854
+ backdropDismissEnabled: true
855
+ };
856
+
857
+ class ModalLauncherKeypressListener extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
858
+ constructor(...args) {
859
+ super(...args);
860
+
861
+ this._handleKeyup = e => {
862
+ // We check the key as that's keyboard layout agnostic and also avoids
863
+ // the minefield of deprecated number type properties like keyCode and
864
+ // which, with the replacement code, which uses a string instead.
865
+ if (e.key === "Escape") {
866
+ // Stop the event going any further.
867
+ // For cancellation events, like the Escape key, we generally should
868
+ // air on the side of caution and only allow it to cancel one thing.
869
+ // So, it's polite for us to stop propagation of the event.
870
+ // Otherwise, we end up with UX where one Escape key press
871
+ // unexpectedly cancels multiple things.
872
+ e.preventDefault();
873
+ e.stopPropagation();
874
+ this.props.onClose();
875
+ }
876
+ };
877
+ }
878
+
879
+ componentDidMount() {
880
+ window.addEventListener("keyup", this._handleKeyup);
881
+ }
882
+
883
+ componentWillUnmount() {
884
+ window.removeEventListener("keyup", this._handleKeyup);
885
+ }
886
+
418
887
  render() {
888
+ return null;
889
+ }
890
+
891
+ }
892
+
893
+ const styles = aphrodite__WEBPACK_IMPORTED_MODULE_2__["StyleSheet"].create({
894
+ container: {
895
+ // This z-index is copied from the Khan Academy webapp.
896
+ //
897
+ // TODO(mdr): Should we keep this in a constants file somewhere? Or
898
+ // not hardcode it at all, and provide it to Wonder Blocks via
899
+ // configuration?
900
+ zIndex: 1080
901
+ }
902
+ });
903
+
904
+ /***/ }),
905
+ /* 16 */
906
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
907
+
908
+ "use strict";
909
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return OnePaneDialog; });
910
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
911
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
912
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
913
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
914
+ /* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
915
+ /* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__);
916
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2);
917
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__);
918
+ /* harmony import */ var _modal_dialog_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
919
+ /* harmony import */ var _modal_panel_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(10);
920
+ /* harmony import */ var _modal_header_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7);
921
+
922
+
923
+
924
+
925
+
926
+
927
+
928
+
929
+ /**
930
+ * This is the standard layout for most straightforward modal experiences.
931
+ *
932
+ * The ModalHeader is required, but the ModalFooter is optional.
933
+ * The content of the dialog itself is fully customizable, but the left/right/top/bottom padding is fixed.
934
+ */
935
+ class OnePaneDialog extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
936
+ renderHeader(uniqueId) {
419
937
  const {
938
+ title,
420
939
  breadcrumbs = undefined,
421
- light,
422
940
  subtitle = undefined,
423
- testId,
424
- title,
425
- titleId
941
+ testId
426
942
  } = this.props;
427
943
 
428
- if (subtitle && breadcrumbs) {
429
- throw new Error("'subtitle' and 'breadcrumbs' can't be used together");
944
+ if (breadcrumbs) {
945
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_header_js__WEBPACK_IMPORTED_MODULE_6__[/* default */ "a"], {
946
+ title: title,
947
+ breadcrumbs: breadcrumbs,
948
+ titleId: uniqueId,
949
+ testId: testId && `${testId}-header`
950
+ });
951
+ } else if (subtitle) {
952
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_header_js__WEBPACK_IMPORTED_MODULE_6__[/* default */ "a"], {
953
+ title: title,
954
+ subtitle: subtitle,
955
+ titleId: uniqueId,
956
+ testId: testId && `${testId}-header`
957
+ });
958
+ } else {
959
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_header_js__WEBPACK_IMPORTED_MODULE_6__[/* default */ "a"], {
960
+ title: title,
961
+ titleId: uniqueId,
962
+ testId: testId && `${testId}-header`
963
+ });
430
964
  }
965
+ }
431
966
 
432
- return /*#__PURE__*/external_react_["createElement"](wonder_blocks_layout_["MediaLayout"], {
433
- styleSheets: modal_header_styleSheets
967
+ render() {
968
+ const {
969
+ onClose,
970
+ footer,
971
+ content,
972
+ above,
973
+ below,
974
+ style,
975
+ closeButtonVisible,
976
+ testId,
977
+ titleId,
978
+ role
979
+ } = this.props;
980
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__["MediaLayout"], {
981
+ styleSheets: styleSheets
434
982
  }, ({
435
983
  styles
436
- }) => /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
437
- style: [styles.header, !light && styles.dark],
438
- testId: testId
439
- }, breadcrumbs && /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
440
- style: styles.breadcrumbs
441
- }, breadcrumbs), /*#__PURE__*/external_react_["createElement"](wonder_blocks_typography_["HeadingMedium"], {
442
- style: styles.title,
984
+ }) => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["IDProvider"], {
443
985
  id: titleId,
444
- testId: testId && `${testId}-title`
445
- }, title), subtitle && /*#__PURE__*/external_react_["createElement"](wonder_blocks_typography_["LabelSmall"], {
446
- style: light && styles.subtitle,
447
- testId: testId && `${testId}-subtitle`
448
- }, subtitle)));
986
+ scope: "modal"
987
+ }, uniqueId => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_dialog_js__WEBPACK_IMPORTED_MODULE_4__[/* default */ "a"], {
988
+ style: [styles.dialog, style],
989
+ above: above,
990
+ below: below,
991
+ testId: testId,
992
+ "aria-labelledby": uniqueId,
993
+ role: role
994
+ }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_panel_js__WEBPACK_IMPORTED_MODULE_5__[/* default */ "a"], {
995
+ onClose: onClose,
996
+ header: this.renderHeader(uniqueId),
997
+ content: content,
998
+ footer: footer,
999
+ closeButtonVisible: closeButtonVisible,
1000
+ testId: testId
1001
+ }))));
449
1002
  }
450
1003
 
451
1004
  }
452
- modal_header_ModalHeader.defaultProps = {
453
- light: true
1005
+ OnePaneDialog.defaultProps = {
1006
+ closeButtonVisible: true
454
1007
  };
455
- const modal_header_styleSheets = {
456
- all: external_aphrodite_["StyleSheet"].create({
457
- header: {
458
- boxShadow: `0px 1px 0px ${wonder_blocks_color_default.a.offBlack16}`,
459
- display: "flex",
460
- flexDirection: "column",
461
- minHeight: 66,
462
- padding: `${wonder_blocks_spacing_default.a.large_24}px ${wonder_blocks_spacing_default.a.xLarge_32}px`,
463
- position: "relative",
464
- width: "100%"
465
- },
466
- dark: {
467
- background: wonder_blocks_color_default.a.darkBlue,
468
- color: wonder_blocks_color_default.a.white
469
- },
470
- breadcrumbs: {
471
- color: wonder_blocks_color_default.a.offBlack64,
472
- marginBottom: wonder_blocks_spacing_default.a.xSmall_8
473
- },
474
- title: {
475
- // Prevent title from overlapping the close button
476
- paddingRight: wonder_blocks_spacing_default.a.medium_16
477
- },
478
- subtitle: {
479
- color: wonder_blocks_color_default.a.offBlack64,
480
- marginTop: wonder_blocks_spacing_default.a.xSmall_8
1008
+ const styleSheets = {
1009
+ small: aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
1010
+ dialog: {
1011
+ width: "100%",
1012
+ height: "100%",
1013
+ overflow: "hidden"
481
1014
  }
482
1015
  }),
483
- small: external_aphrodite_["StyleSheet"].create({
484
- header: {
485
- paddingLeft: wonder_blocks_spacing_default.a.medium_16,
486
- paddingRight: wonder_blocks_spacing_default.a.medium_16
487
- },
488
- title: {
489
- paddingRight: wonder_blocks_spacing_default.a.xLarge_32
1016
+ mdOrLarger: aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
1017
+ dialog: {
1018
+ width: "93.75%",
1019
+ maxWidth: 576,
1020
+ height: "81.25%",
1021
+ maxHeight: 624
490
1022
  }
491
1023
  })
492
1024
  };
493
- // EXTERNAL MODULE: external "react-dom"
494
- var external_react_dom_ = __webpack_require__(6);
495
1025
 
496
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/focus-trap.js
1026
+ /***/ }),
1027
+ /* 17 */
1028
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1029
+
1030
+ "use strict";
1031
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return maybeGetPortalMountedModalHostElement; });
1032
+ /* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(11);
1033
+
1034
+ /**
1035
+ * From a given element, finds its next ancestor that is a modal launcher portal
1036
+ * element.
1037
+ * @param {?(Element | Text)} element The element whose ancestors are to be
1038
+ * walked.
1039
+ * @returns {?Element} The nearest parent modal launcher portal.
1040
+ */
1041
+
1042
+ function maybeGetNextAncestorModalLauncherPortal(element) {
1043
+ let candidateElement = element && element.parentElement;
1044
+
1045
+ while (candidateElement && !candidateElement.hasAttribute(_constants_js__WEBPACK_IMPORTED_MODULE_0__[/* ModalLauncherPortalAttributeName */ "a"])) {
1046
+ candidateElement = candidateElement.parentElement;
1047
+ }
1048
+
1049
+ return candidateElement;
1050
+ }
1051
+ /**
1052
+ * From a given element, finds the next modal host that has been mounted in
1053
+ * a modal portal.
1054
+ * @param {?(Element | Text)} element The element whose ancestors are to be
1055
+ * walked.
1056
+ * @returns {?Element} The next portal-mounted modal host element.
1057
+ * TODO(kevinb): look into getting rid of this
1058
+ */
1059
+
1060
+
1061
+ function maybeGetPortalMountedModalHostElement(element) {
1062
+ return maybeGetNextAncestorModalLauncherPortal(element);
1063
+ }
1064
+
1065
+ /***/ }),
1066
+ /* 18 */
1067
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1068
+
1069
+ "use strict";
1070
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return FocusTrap; });
1071
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
1072
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
1073
+ /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
1074
+ /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
1075
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
1076
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__);
497
1077
 
498
1078
 
499
1079
 
500
- class focus_trap_FocusTrap extends external_react_["Component"] {
1080
+ class FocusTrap extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
501
1081
  /** The most recent node _inside this component_ to receive focus. */
502
1082
 
503
1083
  /**
@@ -517,7 +1097,7 @@ class focus_trap_FocusTrap extends external_react_["Component"] {
517
1097
  return;
518
1098
  }
519
1099
 
520
- const modalRoot = external_react_dom_["findDOMNode"](node);
1100
+ const modalRoot = react_dom__WEBPACK_IMPORTED_MODULE_1__["findDOMNode"](node);
521
1101
 
522
1102
  if (!modalRoot) {
523
1103
  throw new Error("Assertion error: modal root should exist after mount");
@@ -646,15 +1226,15 @@ class focus_trap_FocusTrap extends external_react_["Component"] {
646
1226
  const {
647
1227
  style
648
1228
  } = this.props;
649
- return /*#__PURE__*/external_react_["createElement"](external_react_["Fragment"], null, /*#__PURE__*/external_react_["createElement"]("div", {
1229
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](react__WEBPACK_IMPORTED_MODULE_0__["Fragment"], null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("div", {
650
1230
  tabIndex: "0",
651
1231
  style: {
652
1232
  position: "fixed"
653
1233
  }
654
- }), /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
1234
+ }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__["View"], {
655
1235
  style: style,
656
1236
  ref: this.getModalRoot
657
- }, this.props.children), /*#__PURE__*/external_react_["createElement"]("div", {
1237
+ }, this.props.children), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("div", {
658
1238
  tabIndex: "0",
659
1239
  style: {
660
1240
  position: "fixed"
@@ -663,17 +1243,27 @@ class focus_trap_FocusTrap extends external_react_["Component"] {
663
1243
  }
664
1244
 
665
1245
  }
666
- // EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/extends.js
667
- var helpers_extends = __webpack_require__(8);
668
- var extends_default = /*#__PURE__*/__webpack_require__.n(helpers_extends);
669
1246
 
670
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/util/constants.js
671
- /**
672
- * The attribute used to identify a modal launcher portal.
673
- */
674
- const ModalLauncherPortalAttributeName = "data-modal-launcher-portal";
1247
+ /***/ }),
1248
+ /* 19 */
1249
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1250
+
1251
+ "use strict";
1252
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ModalBackdrop; });
1253
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
1254
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
1255
+ /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
1256
+ /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
1257
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
1258
+ /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_2__);
1259
+ /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
1260
+ /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_3__);
1261
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(2);
1262
+ /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_4__);
1263
+ /* harmony import */ var _util_constants_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(11);
1264
+ /* harmony import */ var _util_find_focusable_nodes_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(20);
1265
+ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
675
1266
 
676
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/modal-backdrop.js
677
1267
 
678
1268
 
679
1269
 
@@ -682,11 +1272,6 @@ const ModalLauncherPortalAttributeName = "data-modal-launcher-portal";
682
1272
 
683
1273
 
684
1274
 
685
- /**
686
- * List of elements that can be focused
687
- * @see https://www.w3.org/TR/html5/editing.html#can-be-focused
688
- */
689
- const FOCUSABLE_ELEMENTS = 'a[href], details, input, textarea, select, button:not([aria-label^="Close"])';
690
1275
  /**
691
1276
  * A private component used by ModalLauncher. This is the fixed-position
692
1277
  * container element that gets mounted outside the DOM. It overlays the modal
@@ -697,22 +1282,29 @@ const FOCUSABLE_ELEMENTS = 'a[href], details, input, textarea, select, button:no
697
1282
  * and adding an `onClose` prop that will call `onCloseModal`. If an
698
1283
  * `onClose` prop is already provided, the two are merged.
699
1284
  */
700
-
701
- class modal_backdrop_ModalBackdrop extends external_react_["Component"] {
1285
+ class ModalBackdrop extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
702
1286
  constructor(...args) {
703
1287
  super(...args);
1288
+ this._mousePressedOutside = false;
1289
+
1290
+ this.handleMouseDown = e => {
1291
+ // Confirm that it is the backdrop that is being clicked, not the child
1292
+ this._mousePressedOutside = e.target === e.currentTarget;
1293
+ };
704
1294
 
705
- this.handleClick = e => {
706
- // Was the lowest-level click target (`e.target`) the positioner element
707
- // (`e.currentTarget`)?
708
- if (e.target === e.currentTarget) {
1295
+ this.handleMouseUp = e => {
1296
+ // Confirm that it is the backdrop that is being clicked, not the child
1297
+ // and that the mouse was pressed in the backdrop first.
1298
+ if (e.target === e.currentTarget && this._mousePressedOutside) {
709
1299
  this.props.onCloseModal();
710
1300
  }
1301
+
1302
+ this._mousePressedOutside = false;
711
1303
  };
712
1304
  }
713
1305
 
714
1306
  componentDidMount() {
715
- const node = external_react_dom_["findDOMNode"](this);
1307
+ const node = react_dom__WEBPACK_IMPORTED_MODULE_1__["findDOMNode"](this);
716
1308
 
717
1309
  if (!node) {
718
1310
  return;
@@ -728,11 +1320,10 @@ class modal_backdrop_ModalBackdrop extends external_react_["Component"] {
728
1320
  firstFocusableElement.focus();
729
1321
  }, 0);
730
1322
  }
1323
+
731
1324
  /**
732
1325
  * Returns an element specified by the user
733
1326
  */
734
-
735
-
736
1327
  _getInitialFocusElement(node) {
737
1328
  const {
738
1329
  initialFocusId
@@ -742,7 +1333,7 @@ class modal_backdrop_ModalBackdrop extends external_react_["Component"] {
742
1333
  return null;
743
1334
  }
744
1335
 
745
- return external_react_dom_["findDOMNode"](node.querySelector(`#${initialFocusId}`));
1336
+ return react_dom__WEBPACK_IMPORTED_MODULE_1__["findDOMNode"](node.querySelector(`#${initialFocusId}`));
746
1337
  }
747
1338
  /**
748
1339
  * Returns the first focusable element found inside the Dialog
@@ -751,7 +1342,7 @@ class modal_backdrop_ModalBackdrop extends external_react_["Component"] {
751
1342
 
752
1343
  _getFirstFocusableElement(node) {
753
1344
  // get a collection of elements that can be focused
754
- const focusableElements = node.querySelectorAll(FOCUSABLE_ELEMENTS);
1345
+ const focusableElements = Object(_util_find_focusable_nodes_js__WEBPACK_IMPORTED_MODULE_6__[/* findFocusableNodes */ "a"])(node);
755
1346
 
756
1347
  if (!focusableElements) {
757
1348
  return null;
@@ -768,7 +1359,7 @@ class modal_backdrop_ModalBackdrop extends external_react_["Component"] {
768
1359
  _getDialogElement(node) {
769
1360
  // If no focusable elements are found,
770
1361
  // the dialog content element itself will receive focus.
771
- const dialogElement = external_react_dom_["findDOMNode"](node.querySelector('[role="dialog"]')); // add tabIndex to make the Dialog focusable
1362
+ const dialogElement = react_dom__WEBPACK_IMPORTED_MODULE_1__["findDOMNode"](node.querySelector('[role="dialog"]')); // add tabIndex to make the Dialog focusable
772
1363
 
773
1364
  dialogElement.tabIndex = -1;
774
1365
  return dialogElement;
@@ -786,17 +1377,18 @@ class modal_backdrop_ModalBackdrop extends external_react_["Component"] {
786
1377
  testId
787
1378
  } = this.props;
788
1379
  const backdropProps = {
789
- [ModalLauncherPortalAttributeName]: true
1380
+ [_util_constants_js__WEBPACK_IMPORTED_MODULE_5__[/* ModalLauncherPortalAttributeName */ "a"]]: true
790
1381
  };
791
- return /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], extends_default()({
792
- style: modal_backdrop_styles.modalPositioner,
793
- onClick: this.handleClick,
1382
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_4__["View"], _extends({
1383
+ style: styles.modalPositioner,
1384
+ onMouseDown: this.handleMouseDown,
1385
+ onMouseUp: this.handleMouseUp,
794
1386
  testId: testId
795
1387
  }, backdropProps), children);
796
1388
  }
797
1389
 
798
1390
  }
799
- const modal_backdrop_styles = external_aphrodite_["StyleSheet"].create({
1391
+ const styles = aphrodite__WEBPACK_IMPORTED_MODULE_2__["StyleSheet"].create({
800
1392
  modalPositioner: {
801
1393
  position: "fixed",
802
1394
  left: 0,
@@ -814,10 +1406,32 @@ const modal_backdrop_styles = external_aphrodite_["StyleSheet"].create({
814
1406
  // turns out to be necessary. That sounds hard to do; punting for
815
1407
  // now!
816
1408
  overflow: "auto",
817
- background: wonder_blocks_color_default.a.offBlack64
1409
+ background: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_3___default.a.offBlack64
818
1410
  }
819
1411
  });
820
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/scroll-disabler.js
1412
+
1413
+ /***/ }),
1414
+ /* 20 */
1415
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1416
+
1417
+ "use strict";
1418
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return findFocusableNodes; });
1419
+ /**
1420
+ * List of elements that can be focused
1421
+ * @see https://www.w3.org/TR/html5/editing.html#can-be-focused
1422
+ */
1423
+ const FOCUSABLE_ELEMENTS = 'a[href], details, input, textarea, select, button:not([aria-label^="Close"])';
1424
+ function findFocusableNodes(root) {
1425
+ return Array.from(root.querySelectorAll(FOCUSABLE_ELEMENTS));
1426
+ }
1427
+
1428
+ /***/ }),
1429
+ /* 21 */
1430
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1431
+
1432
+ "use strict";
1433
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
1434
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
821
1435
  /**
822
1436
  * A UI-less component that lets `ModalLauncher` disable page scroll.
823
1437
  *
@@ -839,9 +1453,9 @@ const needsHackyMobileSafariScrollDisabler = (() => {
839
1453
  return userAgent.indexOf("iPad") > -1 || userAgent.indexOf("iPhone") > -1;
840
1454
  })();
841
1455
 
842
- class scroll_disabler_ScrollDisabler extends external_react_["Component"] {
1456
+ class ScrollDisabler extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
843
1457
  componentDidMount() {
844
- if (scroll_disabler_ScrollDisabler.numModalsOpened === 0) {
1458
+ if (ScrollDisabler.numModalsOpened === 0) {
845
1459
  const body = document.body;
846
1460
 
847
1461
  if (!body) {
@@ -850,14 +1464,14 @@ class scroll_disabler_ScrollDisabler extends external_react_["Component"] {
850
1464
  // opened.
851
1465
 
852
1466
 
853
- scroll_disabler_ScrollDisabler.oldOverflow = body.style.overflow;
854
- scroll_disabler_ScrollDisabler.oldScrollY = window.scrollY; // We need to grab all of the original style properties before we
1467
+ ScrollDisabler.oldOverflow = body.style.overflow;
1468
+ ScrollDisabler.oldScrollY = window.scrollY; // We need to grab all of the original style properties before we
855
1469
  // modified any of them.
856
1470
 
857
1471
  if (needsHackyMobileSafariScrollDisabler) {
858
- scroll_disabler_ScrollDisabler.oldPosition = body.style.position;
859
- scroll_disabler_ScrollDisabler.oldWidth = body.style.width;
860
- scroll_disabler_ScrollDisabler.oldTop = body.style.top;
1472
+ ScrollDisabler.oldPosition = body.style.position;
1473
+ ScrollDisabler.oldWidth = body.style.width;
1474
+ ScrollDisabler.oldTop = body.style.top;
861
1475
  }
862
1476
 
863
1477
  body.style.overflow = "hidden"; // On mobile Safari, overflow: hidden is not enough, position:
@@ -867,17 +1481,17 @@ class scroll_disabler_ScrollDisabler extends external_react_["Component"] {
867
1481
  if (needsHackyMobileSafariScrollDisabler) {
868
1482
  body.style.position = "fixed";
869
1483
  body.style.width = "100%";
870
- body.style.top = `${-scroll_disabler_ScrollDisabler.oldScrollY}px`;
1484
+ body.style.top = `${-ScrollDisabler.oldScrollY}px`;
871
1485
  }
872
1486
  }
873
1487
 
874
- scroll_disabler_ScrollDisabler.numModalsOpened++;
1488
+ ScrollDisabler.numModalsOpened++;
875
1489
  }
876
1490
 
877
1491
  componentWillUnmount() {
878
- scroll_disabler_ScrollDisabler.numModalsOpened--;
1492
+ ScrollDisabler.numModalsOpened--;
879
1493
 
880
- if (scroll_disabler_ScrollDisabler.numModalsOpened === 0) {
1494
+ if (ScrollDisabler.numModalsOpened === 0) {
881
1495
  const body = document.body;
882
1496
 
883
1497
  if (!body) {
@@ -885,296 +1499,47 @@ class scroll_disabler_ScrollDisabler extends external_react_["Component"] {
885
1499
  } // Reset all values on the closing of the final modal.
886
1500
 
887
1501
 
888
- body.style.overflow = scroll_disabler_ScrollDisabler.oldOverflow;
1502
+ body.style.overflow = ScrollDisabler.oldOverflow;
889
1503
 
890
1504
  if (needsHackyMobileSafariScrollDisabler) {
891
- body.style.position = scroll_disabler_ScrollDisabler.oldPosition;
892
- body.style.width = scroll_disabler_ScrollDisabler.oldWidth;
893
- body.style.top = scroll_disabler_ScrollDisabler.oldTop;
894
- }
895
-
896
- if (typeof window !== "undefined" && window.scrollTo) {
897
- window.scrollTo(0, scroll_disabler_ScrollDisabler.oldScrollY);
898
- }
899
- }
900
- }
901
-
902
- render() {
903
- return null;
904
- }
905
-
906
- }
907
-
908
- scroll_disabler_ScrollDisabler.numModalsOpened = 0;
909
- /* harmony default export */ var scroll_disabler = (scroll_disabler_ScrollDisabler);
910
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/modal-context.js
911
-
912
- const defaultContext = {
913
- closeModal: undefined
914
- };
915
- /* harmony default export */ var modal_context = (/*#__PURE__*/external_react_["createContext"](defaultContext));
916
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/modal-launcher.js
917
-
918
-
919
-
920
-
921
-
922
-
923
-
924
-
925
- /**
926
- * This component enables you to launch a modal, covering the screen.
927
- *
928
- * Children have access to `openModal` function via the function-as-children
929
- * pattern, so one common use case is for this component to wrap a button:
930
- *
931
- * ```js
932
- * <ModalLauncher modal={<TwoColumnModal ... />}>
933
- * {({openModal}) => <button onClick={openModal}>Learn more</button>}
934
- * </ModalLauncher>
935
- * ```
936
- *
937
- * The actual modal itself is constructed separately, using a layout component
938
- * like OnePaneDialog and is provided via
939
- * the `modal` prop.
940
- */
941
- class modal_launcher_ModalLauncher extends external_react_["Component"] {
942
- constructor(...args) {
943
- super(...args);
944
- this.state = {
945
- opened: false
946
- };
947
-
948
- this._saveLastElementFocused = () => {
949
- // keep a reference of the element that triggers the modal
950
- this.lastElementFocusedOutsideModal = document.activeElement;
951
- };
952
-
953
- this._openModal = () => {
954
- this._saveLastElementFocused();
955
-
956
- this.setState({
957
- opened: true
958
- });
959
- };
960
-
961
- this.handleCloseModal = () => {
962
- this.setState({
963
- opened: false
964
- }, () => {
965
- this.props.onClose && this.props.onClose();
966
-
967
- if (this.lastElementFocusedOutsideModal != null) {
968
- // return focus to the element that triggered the modal
969
- this.lastElementFocusedOutsideModal.focus();
970
- }
971
- });
972
- };
973
- }
974
-
975
- static getDerivedStateFromProps(props, state) {
976
- if (typeof props.opened === "boolean" && props.children) {
977
- // eslint-disable-next-line no-console
978
- console.warn("'children' and 'opened' can't be used together");
979
- }
980
-
981
- if (typeof props.opened === "boolean" && !props.onClose) {
982
- // eslint-disable-next-line no-console
983
- console.warn("'onClose' should be used with 'opened'");
984
- }
985
-
986
- if (typeof props.opened !== "boolean" && !props.children) {
987
- // eslint-disable-next-line no-console
988
- console.warn("either 'children' or 'opened' must be set");
989
- }
990
-
991
- return {
992
- opened: typeof props.opened === "boolean" ? props.opened : state.opened
993
- };
994
- }
995
-
996
- componentDidUpdate(prevProps) {
997
- // ensures the element is stored only when the modal is opened
998
- if (!prevProps.opened && this.props.opened) {
999
- this._saveLastElementFocused();
1000
- }
1001
- }
1002
-
1003
- _renderModal() {
1004
- if (typeof this.props.modal === "function") {
1005
- return this.props.modal({
1006
- closeModal: this.handleCloseModal
1007
- });
1008
- } else {
1009
- return this.props.modal;
1010
- }
1011
- }
1012
-
1013
- render() {
1014
- const renderedChildren = this.props.children ? this.props.children({
1015
- openModal: this._openModal
1016
- }) : null;
1017
- const {
1018
- body
1019
- } = document;
1020
-
1021
- if (!body) {
1022
- return null;
1023
- }
1024
-
1025
- return (
1026
- /*#__PURE__*/
1027
- // This flow check is valid, it's the babel plugin which is broken,
1028
- // see modal-context.js for details.
1029
- // $FlowFixMe
1030
- external_react_["createElement"](modal_context.Provider, {
1031
- value: {
1032
- closeModal: this.handleCloseModal
1033
- }
1034
- }, renderedChildren, this.state.opened && /*#__PURE__*/external_react_dom_["createPortal"](
1035
- /*#__PURE__*/
1036
-
1037
- /* We need the container View that FocusTrap creates to be at the
1038
- correct z-index so that it'll be above the global nav in webapp. */
1039
- external_react_["createElement"](focus_trap_FocusTrap, {
1040
- style: modal_launcher_styles.container
1041
- }, /*#__PURE__*/external_react_["createElement"](modal_backdrop_ModalBackdrop, {
1042
- initialFocusId: this.props.initialFocusId,
1043
- testId: this.props.testId,
1044
- onCloseModal: this.props.backdropDismissEnabled ? this.handleCloseModal : () => {}
1045
- }, this._renderModal())), body), this.state.opened && /*#__PURE__*/external_react_["createElement"](modal_launcher_ModalLauncherKeypressListener, {
1046
- onClose: this.handleCloseModal
1047
- }), this.state.opened && /*#__PURE__*/external_react_["createElement"](scroll_disabler, null))
1048
- );
1049
- }
1050
-
1051
- }
1052
- /** A component that, when mounted, calls `onClose` when Escape is pressed. */
1053
-
1054
- modal_launcher_ModalLauncher.defaultProps = {
1055
- backdropDismissEnabled: true
1056
- };
1057
-
1058
- class modal_launcher_ModalLauncherKeypressListener extends external_react_["Component"] {
1059
- constructor(...args) {
1060
- super(...args);
1061
-
1062
- this._handleKeyup = e => {
1063
- // We check the key as that's keyboard layout agnostic and also avoids
1064
- // the minefield of deprecated number type properties like keyCode and
1065
- // which, with the replacement code, which uses a string instead.
1066
- if (e.key === "Escape") {
1067
- // Stop the event going any further.
1068
- // For cancellation events, like the Escape key, we generally should
1069
- // air on the side of caution and only allow it to cancel one thing.
1070
- // So, it's polite for us to stop propagation of the event.
1071
- // Otherwise, we end up with UX where one Escape key press
1072
- // unexpectedly cancels multiple things.
1073
- e.preventDefault();
1074
- e.stopPropagation();
1075
- this.props.onClose();
1505
+ body.style.position = ScrollDisabler.oldPosition;
1506
+ body.style.width = ScrollDisabler.oldWidth;
1507
+ body.style.top = ScrollDisabler.oldTop;
1076
1508
  }
1077
- };
1078
- }
1079
-
1080
- componentDidMount() {
1081
- window.addEventListener("keyup", this._handleKeyup);
1082
- }
1083
-
1084
- componentWillUnmount() {
1085
- window.removeEventListener("keyup", this._handleKeyup);
1086
- }
1087
-
1088
- render() {
1089
- return null;
1090
- }
1091
-
1092
- }
1093
-
1094
- const modal_launcher_styles = external_aphrodite_["StyleSheet"].create({
1095
- container: {
1096
- // This z-index is copied from the Khan Academy webapp.
1097
- //
1098
- // TODO(mdr): Should we keep this in a constants file somewhere? Or
1099
- // not hardcode it at all, and provide it to Wonder Blocks via
1100
- // configuration?
1101
- zIndex: 1080
1102
- }
1103
- });
1104
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/modal-content.js
1105
-
1106
-
1107
-
1108
-
1109
-
1110
1509
 
1111
- /**
1112
- * The Modal content included after the header
1113
- */
1114
- class modal_content_ModalContent extends external_react_["Component"] {
1115
- static isClassOf(instance) {
1116
- return instance && instance.type && instance.type.__IS_MODAL_CONTENT__;
1510
+ if (typeof window !== "undefined" && window.scrollTo) {
1511
+ window.scrollTo(0, ScrollDisabler.oldScrollY);
1512
+ }
1513
+ }
1117
1514
  }
1118
1515
 
1119
1516
  render() {
1120
- const {
1121
- scrollOverflow,
1122
- style,
1123
- children
1124
- } = this.props;
1125
- return /*#__PURE__*/external_react_["createElement"](wonder_blocks_layout_["MediaLayout"], {
1126
- styleSheets: modal_content_styleSheets
1127
- }, ({
1128
- styles
1129
- }) => /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
1130
- style: [styles.wrapper, scrollOverflow && styles.scrollOverflow]
1131
- }, /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
1132
- style: [styles.content, style]
1133
- }, children)));
1517
+ return null;
1134
1518
  }
1135
1519
 
1136
1520
  }
1137
- modal_content_ModalContent.defaultProps = {
1138
- scrollOverflow: true
1139
- };
1140
- modal_content_ModalContent.__IS_MODAL_CONTENT__ = true;
1141
- const modal_content_styleSheets = {
1142
- all: external_aphrodite_["StyleSheet"].create({
1143
- wrapper: {
1144
- flex: 1,
1145
- // This helps to ensure that the paddingBottom is preserved when
1146
- // the contents start to overflow, this goes away on display: flex
1147
- display: "block"
1148
- },
1149
- scrollOverflow: {
1150
- overflow: "auto"
1151
- },
1152
- content: {
1153
- flex: 1,
1154
- minHeight: "100%",
1155
- padding: wonder_blocks_spacing_default.a.xLarge_32,
1156
- boxSizing: "border-box"
1157
- }
1158
- }),
1159
- small: external_aphrodite_["StyleSheet"].create({
1160
- content: {
1161
- padding: `${wonder_blocks_spacing_default.a.xLarge_32}px ${wonder_blocks_spacing_default.a.medium_16}px`
1162
- }
1163
- })
1164
- };
1165
- // EXTERNAL MODULE: external "@khanacademy/wonder-blocks-icon"
1166
- var wonder_blocks_icon_ = __webpack_require__(9);
1167
1521
 
1168
- // EXTERNAL MODULE: external "@khanacademy/wonder-blocks-icon-button"
1169
- var wonder_blocks_icon_button_ = __webpack_require__(10);
1170
- var wonder_blocks_icon_button_default = /*#__PURE__*/__webpack_require__.n(wonder_blocks_icon_button_);
1522
+ ScrollDisabler.numModalsOpened = 0;
1523
+ /* harmony default export */ __webpack_exports__["a"] = (ScrollDisabler);
1171
1524
 
1172
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/close-button.js
1525
+ /***/ }),
1526
+ /* 22 */
1527
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1528
+
1529
+ "use strict";
1530
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return CloseButton; });
1531
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
1532
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
1533
+ /* harmony import */ var _khanacademy_wonder_blocks_icon__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(23);
1534
+ /* harmony import */ var _khanacademy_wonder_blocks_icon__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_icon__WEBPACK_IMPORTED_MODULE_1__);
1535
+ /* harmony import */ var _khanacademy_wonder_blocks_icon_button__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(24);
1536
+ /* harmony import */ var _khanacademy_wonder_blocks_icon_button__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_icon_button__WEBPACK_IMPORTED_MODULE_2__);
1537
+ /* harmony import */ var _modal_context_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12);
1173
1538
 
1174
1539
 
1175
1540
 
1176
1541
 
1177
- class close_button_CloseButton extends external_react_["Component"] {
1542
+ class CloseButton extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
1178
1543
  render() {
1179
1544
  const {
1180
1545
  light,
@@ -1182,15 +1547,15 @@ class close_button_CloseButton extends external_react_["Component"] {
1182
1547
  style,
1183
1548
  testId
1184
1549
  } = this.props;
1185
- return /*#__PURE__*/external_react_["createElement"](modal_context.Consumer, null, ({
1550
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_context_js__WEBPACK_IMPORTED_MODULE_3__[/* default */ "a"].Consumer, null, ({
1186
1551
  closeModal
1187
1552
  }) => {
1188
1553
  if (closeModal && onClick) {
1189
1554
  throw new Error("You've specified 'onClose' on a modal when using ModalLauncher. Please specify 'onClose' on the ModalLauncher instead");
1190
1555
  }
1191
1556
 
1192
- return /*#__PURE__*/external_react_["createElement"](wonder_blocks_icon_button_default.a, {
1193
- icon: wonder_blocks_icon_["icons"].dismiss // TODO(mdr): Translate this string for i18n.
1557
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_icon_button__WEBPACK_IMPORTED_MODULE_2___default.a, {
1558
+ icon: _khanacademy_wonder_blocks_icon__WEBPACK_IMPORTED_MODULE_1__["icons"].dismiss // TODO(mdr): Translate this string for i18n.
1194
1559
  // TODO(kevinb): provide a way to set this label
1195
1560
  ,
1196
1561
  "aria-label": "Close modal",
@@ -1204,255 +1569,46 @@ class close_button_CloseButton extends external_react_["Component"] {
1204
1569
  }
1205
1570
 
1206
1571
  }
1207
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/modal-panel.js
1208
-
1209
-
1210
-
1211
-
1212
-
1213
-
1214
-
1215
-
1216
-
1217
-
1218
- /**
1219
- * ModalPanel is the content container.
1220
- *
1221
- * **Implementation notes:**
1222
- *
1223
- * If you are creating a custom Dialog, make sure to follow these guidelines:
1224
- * - Make sure to add this component inside the [ModalDialog](/#modaldialog).
1225
- * - If needed, you can also add a [ModalHeader](/#modalheader) using the
1226
- * `header` prop. Same goes for [ModalFooter](/#modalfooter).
1227
- * - If you need to create e2e tests, make sure to pass a `testId` prop. This
1228
- * will be passed down to this component using a sufix: e.g.
1229
- * `some-random-id-ModalPanel`. This scope will be propagated to the
1230
- * CloseButton element as well: e.g. `some-random-id-CloseButton`.
1231
- *
1232
- * ```js
1233
- * <ModalDialog>
1234
- * <ModalPanel content={"custom content goes here"} />
1235
- * </ModalDialog>
1236
- * ```
1237
- */
1238
- class modal_panel_ModalPanel extends external_react_["Component"] {
1239
- renderMainContent() {
1240
- const {
1241
- content,
1242
- footer,
1243
- scrollOverflow
1244
- } = this.props;
1245
- const mainContent = modal_content_ModalContent.isClassOf(content) ? content : /*#__PURE__*/external_react_["createElement"](modal_content_ModalContent, null, content);
1246
-
1247
- if (!mainContent) {
1248
- return mainContent;
1249
- }
1250
-
1251
- return /*#__PURE__*/external_react_["cloneElement"](mainContent, {
1252
- // Pass the scrollOverflow and header in to the main content
1253
- scrollOverflow,
1254
- // We override the styling of the main content to help position
1255
- // it if there is a footer or close button being
1256
- // shown. We have to do this here as the ModalContent doesn't
1257
- // know about things being positioned around it.
1258
- style: [!!footer && modal_panel_styles.hasFooter, mainContent.props.style]
1259
- });
1260
- }
1261
-
1262
- render() {
1263
- const {
1264
- closeButtonVisible,
1265
- footer,
1266
- header,
1267
- light,
1268
- onClose,
1269
- style,
1270
- testId
1271
- } = this.props;
1272
- const mainContent = this.renderMainContent();
1273
- return /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["View"], {
1274
- style: [modal_panel_styles.wrapper, !light && modal_panel_styles.dark, style],
1275
- testId: testId && `${testId}-panel`
1276
- }, closeButtonVisible && /*#__PURE__*/external_react_["createElement"](close_button_CloseButton, {
1277
- light: !light,
1278
- onClick: onClose,
1279
- style: modal_panel_styles.closeButton,
1280
- testId: testId && `${testId}-close`
1281
- }), header, mainContent, !footer || modal_footer_ModalFooter.isClassOf(footer) ? footer : /*#__PURE__*/external_react_["createElement"](modal_footer_ModalFooter, null, footer));
1282
- }
1283
-
1284
- }
1285
- modal_panel_ModalPanel.defaultProps = {
1286
- closeButtonVisible: true,
1287
- scrollOverflow: true,
1288
- light: true
1289
- };
1290
- const modal_panel_styles = external_aphrodite_["StyleSheet"].create({
1291
- wrapper: {
1292
- flex: "1 1 auto",
1293
- position: "relative",
1294
- display: "flex",
1295
- flexDirection: "column",
1296
- background: "white",
1297
- boxSizing: "border-box",
1298
- overflow: "hidden",
1299
- height: "100%",
1300
- width: "100%"
1301
- },
1302
- closeButton: {
1303
- position: "absolute",
1304
- right: wonder_blocks_spacing_default.a.medium_16,
1305
- top: wonder_blocks_spacing_default.a.medium_16,
1306
- // This is to allow the button to be tab-ordered before the modal
1307
- // content but still be above the header and content.
1308
- zIndex: 1
1309
- },
1310
- dark: {
1311
- background: wonder_blocks_color_default.a.darkBlue,
1312
- color: wonder_blocks_color_default.a.white
1313
- },
1314
- hasFooter: {
1315
- paddingBottom: wonder_blocks_spacing_default.a.xLarge_32
1316
- }
1317
- });
1318
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/components/one-pane-dialog.js
1319
-
1320
-
1321
-
1322
-
1323
1572
 
1573
+ /***/ }),
1574
+ /* 23 */
1575
+ /***/ (function(module, exports) {
1324
1576
 
1577
+ module.exports = require("@khanacademy/wonder-blocks-icon");
1325
1578
 
1579
+ /***/ }),
1580
+ /* 24 */
1581
+ /***/ (function(module, exports) {
1326
1582
 
1327
- /**
1328
- * This is the standard layout for most straightforward modal experiences.
1329
- *
1330
- * The ModalHeader is required, but the ModalFooter is optional.
1331
- * The content of the dialog itself is fully customizable, but the left/right/top/bottom padding is fixed.
1332
- */
1333
- class one_pane_dialog_OnePaneDialog extends external_react_["Component"] {
1334
- renderHeader(uniqueId) {
1335
- const {
1336
- title,
1337
- breadcrumbs = undefined,
1338
- subtitle = undefined,
1339
- testId
1340
- } = this.props;
1583
+ module.exports = require("@khanacademy/wonder-blocks-icon-button");
1341
1584
 
1342
- if (breadcrumbs) {
1343
- return /*#__PURE__*/external_react_["createElement"](modal_header_ModalHeader, {
1344
- title: title,
1345
- breadcrumbs: breadcrumbs,
1346
- titleId: uniqueId,
1347
- testId: testId && `${testId}-header`
1348
- });
1349
- } else if (subtitle) {
1350
- return /*#__PURE__*/external_react_["createElement"](modal_header_ModalHeader, {
1351
- title: title,
1352
- subtitle: subtitle,
1353
- titleId: uniqueId,
1354
- testId: testId && `${testId}-header`
1355
- });
1356
- } else {
1357
- return /*#__PURE__*/external_react_["createElement"](modal_header_ModalHeader, {
1358
- title: title,
1359
- titleId: uniqueId,
1360
- testId: testId && `${testId}-header`
1361
- });
1362
- }
1363
- }
1585
+ /***/ }),
1586
+ /* 25 */
1587
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1364
1588
 
1365
- render() {
1366
- const {
1367
- onClose,
1368
- footer,
1369
- content,
1370
- above,
1371
- below,
1372
- style,
1373
- closeButtonVisible,
1374
- testId,
1375
- titleId,
1376
- role
1377
- } = this.props;
1378
- return /*#__PURE__*/external_react_["createElement"](wonder_blocks_layout_["MediaLayout"], {
1379
- styleSheets: one_pane_dialog_styleSheets
1380
- }, ({
1381
- styles
1382
- }) => /*#__PURE__*/external_react_["createElement"](wonder_blocks_core_["IDProvider"], {
1383
- id: titleId,
1384
- scope: "modal"
1385
- }, uniqueId => /*#__PURE__*/external_react_["createElement"](modal_dialog_ModalDialog, {
1386
- style: [styles.dialog, style],
1387
- above: above,
1388
- below: below,
1389
- testId: testId,
1390
- "aria-labelledby": uniqueId,
1391
- role: role
1392
- }, /*#__PURE__*/external_react_["createElement"](modal_panel_ModalPanel, {
1393
- onClose: onClose,
1394
- header: this.renderHeader(uniqueId),
1395
- content: content,
1396
- footer: footer,
1397
- closeButtonVisible: closeButtonVisible,
1398
- testId: testId
1399
- }))));
1400
- }
1589
+ "use strict";
1590
+ __webpack_require__.r(__webpack_exports__);
1591
+ /* harmony import */ var _components_modal_dialog_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9);
1592
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ModalDialog", function() { return _components_modal_dialog_js__WEBPACK_IMPORTED_MODULE_0__["a"]; });
1401
1593
 
1402
- }
1403
- one_pane_dialog_OnePaneDialog.defaultProps = {
1404
- closeButtonVisible: true
1405
- };
1406
- const one_pane_dialog_styleSheets = {
1407
- small: external_aphrodite_["StyleSheet"].create({
1408
- dialog: {
1409
- width: "100%",
1410
- height: "100%",
1411
- overflow: "hidden"
1412
- }
1413
- }),
1414
- mdOrLarger: external_aphrodite_["StyleSheet"].create({
1415
- dialog: {
1416
- width: "93.75%",
1417
- maxWidth: 576,
1418
- height: "81.25%",
1419
- maxHeight: 624
1420
- }
1421
- })
1422
- };
1423
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/util/maybe-get-portal-mounted-modal-host-element.js
1594
+ /* harmony import */ var _components_modal_footer_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
1595
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ModalFooter", function() { return _components_modal_footer_js__WEBPACK_IMPORTED_MODULE_1__["a"]; });
1424
1596
 
1425
- /**
1426
- * From a given element, finds its next ancestor that is a modal launcher portal
1427
- * element.
1428
- * @param {?(Element | Text)} element The element whose ancestors are to be
1429
- * walked.
1430
- * @returns {?Element} The nearest parent modal launcher portal.
1431
- */
1597
+ /* harmony import */ var _components_modal_header_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7);
1598
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ModalHeader", function() { return _components_modal_header_js__WEBPACK_IMPORTED_MODULE_2__["a"]; });
1432
1599
 
1433
- function maybeGetNextAncestorModalLauncherPortal(element) {
1434
- let candidateElement = element && element.parentElement;
1600
+ /* harmony import */ var _components_modal_launcher_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(15);
1601
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ModalLauncher", function() { return _components_modal_launcher_js__WEBPACK_IMPORTED_MODULE_3__["a"]; });
1435
1602
 
1436
- while (candidateElement && !candidateElement.hasAttribute(ModalLauncherPortalAttributeName)) {
1437
- candidateElement = candidateElement.parentElement;
1438
- }
1603
+ /* harmony import */ var _components_modal_panel_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(10);
1604
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ModalPanel", function() { return _components_modal_panel_js__WEBPACK_IMPORTED_MODULE_4__["a"]; });
1439
1605
 
1440
- return candidateElement;
1441
- }
1442
- /**
1443
- * From a given element, finds the next modal host that has been mounted in
1444
- * a modal portal.
1445
- * @param {?(Element | Text)} element The element whose ancestors are to be
1446
- * walked.
1447
- * @returns {?Element} The next portal-mounted modal host element.
1448
- * TODO(kevinb): look into getting rid of this
1449
- */
1606
+ /* harmony import */ var _components_one_pane_dialog_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(16);
1607
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "OnePaneDialog", function() { return _components_one_pane_dialog_js__WEBPACK_IMPORTED_MODULE_5__["a"]; });
1450
1608
 
1609
+ /* harmony import */ var _util_maybe_get_portal_mounted_modal_host_element_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(17);
1610
+ /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "maybeGetPortalMountedModalHostElement", function() { return _util_maybe_get_portal_mounted_modal_host_element_js__WEBPACK_IMPORTED_MODULE_6__["a"]; });
1451
1611
 
1452
- function maybeGetPortalMountedModalHostElement(element) {
1453
- return maybeGetNextAncestorModalLauncherPortal(element);
1454
- }
1455
- // CONCATENATED MODULE: ./packages/wonder-blocks-modal/src/index.js
1456
1612
 
1457
1613
 
1458
1614