@khanacademy/wonder-blocks-modal 4.1.0 → 4.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
@@ -8,12 +8,12 @@ var wonderBlocksTheming = require('@khanacademy/wonder-blocks-theming');
8
8
  var aphrodite = require('aphrodite');
9
9
  var Color = require('@khanacademy/wonder-blocks-color');
10
10
  var Spacing = require('@khanacademy/wonder-blocks-spacing');
11
- var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
12
11
  var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
13
12
  var ReactDOM = require('react-dom');
14
13
  var wonderBlocksTiming = require('@khanacademy/wonder-blocks-timing');
15
14
  var xIcon = require('@phosphor-icons/core/regular/x.svg');
16
15
  var IconButton = require('@khanacademy/wonder-blocks-icon-button');
16
+ var wonderBlocksLayout = require('@khanacademy/wonder-blocks-layout');
17
17
 
18
18
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
19
19
 
@@ -57,26 +57,57 @@ function _extends() {
57
57
  return _extends.apply(this, arguments);
58
58
  }
59
59
 
60
- const theme = {
60
+ const theme$1 = {
61
+ color: {
62
+ bg: {
63
+ inverse: wonderBlocksTheming.tokens.color.darkBlue
64
+ },
65
+ text: {
66
+ inverse: wonderBlocksTheming.tokens.color.white,
67
+ secondary: wonderBlocksTheming.tokens.color.offBlack64
68
+ },
69
+ shadow: {
70
+ default: wonderBlocksTheming.tokens.color.offBlack16
71
+ }
72
+ },
61
73
  border: {
62
74
  radius: wonderBlocksTheming.tokens.border.radius.medium_4
63
75
  },
64
76
  spacing: {
65
77
  dialog: {
66
78
  small: wonderBlocksTheming.tokens.spacing.medium_16
79
+ },
80
+ panel: {
81
+ closeButton: wonderBlocksTheming.tokens.spacing.medium_16,
82
+ footer: wonderBlocksTheming.tokens.spacing.xLarge_32
83
+ },
84
+ header: {
85
+ xsmall: wonderBlocksTheming.tokens.spacing.xSmall_8,
86
+ small: wonderBlocksTheming.tokens.spacing.medium_16,
87
+ medium: wonderBlocksTheming.tokens.spacing.large_24,
88
+ large: wonderBlocksTheming.tokens.spacing.xLarge_32
67
89
  }
68
90
  }
69
91
  };
70
92
 
93
+ const theme = wonderBlocksTheming.mergeTheme(theme$1, {
94
+ color: {
95
+ bg: {
96
+ inverse: wonderBlocksTheming.tokens.color.eggplant
97
+ }
98
+ }
99
+ });
100
+
71
101
  const themes = {
72
- default: theme
102
+ default: theme$1,
103
+ khanmigo: theme
73
104
  };
74
- const ModalDialogThemeContext = wonderBlocksTheming.createThemeContext(theme);
105
+ const ModalDialogThemeContext = wonderBlocksTheming.createThemeContext(theme$1);
75
106
  function ThemeModalDialog(props) {
76
107
  const currentTheme = React__namespace.useContext(wonderBlocksTheming.ThemeSwitcherContext);
77
- const theme$1 = themes[currentTheme] || theme;
108
+ const theme = themes[currentTheme] || theme$1;
78
109
  return React__namespace.createElement(ModalDialogThemeContext.Provider, {
79
- value: theme$1
110
+ value: theme
80
111
  }, props.children);
81
112
  }
82
113
 
@@ -94,7 +125,7 @@ const ModalDialogCore = React__namespace.forwardRef(function ModalDialogCore(pro
94
125
  const {
95
126
  theme
96
127
  } = wonderBlocksTheming.useScopedTheme(ModalDialogThemeContext);
97
- const styles = wonderBlocksTheming.useStyles(themedStylesFn, theme);
128
+ const styles = wonderBlocksTheming.useStyles(themedStylesFn$3, theme);
98
129
  return React__namespace.createElement(wonderBlocksCore.View, {
99
130
  style: [styles.wrapper, style]
100
131
  }, below && React__namespace.createElement(wonderBlocksCore.View, {
@@ -116,8 +147,8 @@ const ModalDialog = React__namespace.forwardRef(function ModalDialog(props, ref)
116
147
  ref: ref
117
148
  })));
118
149
  });
119
- const small = "@media (max-width: 767px)";
120
- const themedStylesFn = theme => ({
150
+ const small$2 = "@media (max-width: 767px)";
151
+ const themedStylesFn$3 = theme => ({
121
152
  wrapper: {
122
153
  display: "flex",
123
154
  flexDirection: "row",
@@ -125,7 +156,7 @@ const themedStylesFn = theme => ({
125
156
  width: "100%",
126
157
  height: "100%",
127
158
  position: "relative",
128
- [small]: {
159
+ [small$2]: {
129
160
  padding: theme.spacing.dialog.small,
130
161
  flexDirection: "column"
131
162
  }
@@ -157,21 +188,18 @@ const themedStylesFn = theme => ({
157
188
  });
158
189
  ModalDialog.displayName = "ModalDialog";
159
190
 
160
- class ModalFooter extends React__namespace.Component {
161
- static isClassOf(instance) {
162
- return instance && instance.type && instance.type.__IS_MODAL_FOOTER__;
163
- }
164
- render() {
165
- const {
166
- children
167
- } = this.props;
168
- return React__namespace.createElement(wonderBlocksCore.View, {
169
- style: styles$3.footer
170
- }, children);
171
- }
191
+ function ModalFooter({
192
+ children
193
+ }) {
194
+ return React__namespace.createElement(wonderBlocksCore.View, {
195
+ style: styles$2.footer
196
+ }, children);
172
197
  }
173
198
  ModalFooter.__IS_MODAL_FOOTER__ = true;
174
- const styles$3 = aphrodite.StyleSheet.create({
199
+ ModalFooter.isComponentOf = instance => {
200
+ return instance && instance.type && instance.type.__IS_MODAL_FOOTER__;
201
+ };
202
+ const styles$2 = aphrodite.StyleSheet.create({
175
203
  footer: {
176
204
  flex: "0 0 auto",
177
205
  boxSizing: "border-box",
@@ -188,77 +216,72 @@ const styles$3 = aphrodite.StyleSheet.create({
188
216
  }
189
217
  });
190
218
 
191
- class ModalHeader extends React__namespace.Component {
192
- render() {
193
- const {
194
- breadcrumbs = undefined,
195
- light,
196
- subtitle = undefined,
197
- testId,
198
- title,
199
- titleId
200
- } = this.props;
201
- if (subtitle && breadcrumbs) {
202
- throw new Error("'subtitle' and 'breadcrumbs' can't be used together");
203
- }
204
- return React__namespace.createElement(wonderBlocksLayout.MediaLayout, {
205
- styleSheets: styleSheets$2
206
- }, ({
207
- styles
208
- }) => React__namespace.createElement(wonderBlocksCore.View, {
209
- style: [styles.header, !light && styles.dark],
210
- testId: testId
211
- }, breadcrumbs && React__namespace.createElement(wonderBlocksCore.View, {
212
- style: styles.breadcrumbs
213
- }, breadcrumbs), React__namespace.createElement(wonderBlocksTypography.HeadingMedium, {
214
- style: styles.title,
215
- id: titleId,
216
- testId: testId && `${testId}-title`
217
- }, title), subtitle && React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
218
- style: light && styles.subtitle,
219
- testId: testId && `${testId}-subtitle`
220
- }, subtitle)));
219
+ function ModalHeader(props) {
220
+ const {
221
+ breadcrumbs = undefined,
222
+ light,
223
+ subtitle = undefined,
224
+ testId,
225
+ title,
226
+ titleId
227
+ } = props;
228
+ if (subtitle && breadcrumbs) {
229
+ throw new Error("'subtitle' and 'breadcrumbs' can't be used together");
221
230
  }
231
+ const {
232
+ theme
233
+ } = wonderBlocksTheming.useScopedTheme(ModalDialogThemeContext);
234
+ const styles = wonderBlocksTheming.useStyles(themedStylesFn$2, theme);
235
+ return React__namespace.createElement(wonderBlocksCore.View, {
236
+ style: [styles.header, !light && styles.dark],
237
+ testId: testId
238
+ }, breadcrumbs && React__namespace.createElement(wonderBlocksCore.View, {
239
+ style: styles.breadcrumbs
240
+ }, breadcrumbs), React__namespace.createElement(wonderBlocksTypography.HeadingMedium, {
241
+ style: styles.title,
242
+ id: titleId,
243
+ testId: testId && `${testId}-title`
244
+ }, title), subtitle && React__namespace.createElement(wonderBlocksTypography.LabelSmall, {
245
+ style: light && styles.subtitle,
246
+ testId: testId && `${testId}-subtitle`
247
+ }, subtitle));
222
248
  }
223
- ModalHeader.defaultProps = {
224
- light: true
225
- };
226
- const styleSheets$2 = {
227
- all: aphrodite.StyleSheet.create({
228
- header: {
229
- boxShadow: `0px 1px 0px ${Color__default["default"].offBlack16}`,
230
- display: "flex",
231
- flexDirection: "column",
232
- minHeight: 66,
233
- padding: `${Spacing__default["default"].large_24}px ${Spacing__default["default"].xLarge_32}px`,
234
- position: "relative",
235
- width: "100%"
236
- },
237
- dark: {
238
- background: Color__default["default"].darkBlue,
239
- color: Color__default["default"].white
240
- },
241
- breadcrumbs: {
242
- color: Color__default["default"].offBlack64,
243
- marginBottom: Spacing__default["default"].xSmall_8
244
- },
245
- title: {
246
- paddingRight: Spacing__default["default"].medium_16
247
- },
248
- subtitle: {
249
- color: Color__default["default"].offBlack64,
250
- marginTop: Spacing__default["default"].xSmall_8
249
+ const small$1 = "@media (max-width: 767px)";
250
+ const themedStylesFn$2 = theme => ({
251
+ header: {
252
+ boxShadow: `0px 1px 0px ${theme.color.shadow.default}`,
253
+ display: "flex",
254
+ flexDirection: "column",
255
+ minHeight: 66,
256
+ padding: `${theme.spacing.header.medium}px ${theme.spacing.header.large}px`,
257
+ position: "relative",
258
+ width: "100%",
259
+ [small$1]: {
260
+ paddingLeft: theme.spacing.header.small,
261
+ paddingRight: theme.spacing.header.small
251
262
  }
252
- }),
253
- small: aphrodite.StyleSheet.create({
254
- header: {
255
- paddingLeft: Spacing__default["default"].medium_16,
256
- paddingRight: Spacing__default["default"].medium_16
257
- },
258
- title: {
259
- paddingRight: Spacing__default["default"].xLarge_32
263
+ },
264
+ dark: {
265
+ background: theme.color.bg.inverse,
266
+ color: theme.color.text.inverse
267
+ },
268
+ breadcrumbs: {
269
+ color: theme.color.text.secondary,
270
+ marginBottom: theme.spacing.header.xsmall
271
+ },
272
+ title: {
273
+ paddingRight: theme.spacing.header.small,
274
+ [small$1]: {
275
+ paddingRight: theme.spacing.header.large
260
276
  }
261
- })
277
+ },
278
+ subtitle: {
279
+ color: theme.color.text.secondary,
280
+ marginTop: theme.spacing.header.xsmall
281
+ }
282
+ });
283
+ ModalHeader.defaultProps = {
284
+ light: true
262
285
  };
263
286
 
264
287
  const FOCUSABLE_ELEMENTS$1 = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
@@ -384,14 +407,14 @@ class ModalBackdrop extends React__namespace.Component {
384
407
  [ModalLauncherPortalAttributeName]: true
385
408
  };
386
409
  return React__namespace.createElement(wonderBlocksCore.View, _extends({
387
- style: styles$2.modalPositioner,
410
+ style: styles$1.modalPositioner,
388
411
  onMouseDown: this.handleMouseDown,
389
412
  onMouseUp: this.handleMouseUp,
390
413
  testId: testId
391
414
  }, backdropProps), children);
392
415
  }
393
416
  }
394
- const styles$2 = aphrodite.StyleSheet.create({
417
+ const styles$1 = aphrodite.StyleSheet.create({
395
418
  modalPositioner: {
396
419
  position: "fixed",
397
420
  left: 0,
@@ -562,7 +585,7 @@ class ModalLauncher extends React__namespace.Component {
562
585
  closeModal: this.handleCloseModal
563
586
  }
564
587
  }, renderedChildren, this.state.opened && ReactDOM__namespace.createPortal(React__namespace.createElement(FocusTrap, {
565
- style: styles$1.container
588
+ style: styles.container
566
589
  }, React__namespace.createElement(ModalBackdrop, {
567
590
  initialFocusId: this.props.initialFocusId,
568
591
  testId: this.props.testId,
@@ -596,59 +619,54 @@ class ModalLauncherKeypressListener extends React__namespace.Component {
596
619
  return null;
597
620
  }
598
621
  }
599
- const styles$1 = aphrodite.StyleSheet.create({
622
+ const styles = aphrodite.StyleSheet.create({
600
623
  container: {
601
624
  zIndex: 1080
602
625
  }
603
626
  });
604
627
  var modalLauncher = wonderBlocksTiming.withActionScheduler(ModalLauncher);
605
628
 
606
- class ModalContent extends React__namespace.Component {
607
- static isClassOf(instance) {
608
- return instance && instance.type && instance.type.__IS_MODAL_CONTENT__;
609
- }
610
- render() {
611
- const {
612
- scrollOverflow,
613
- style,
614
- children
615
- } = this.props;
616
- return React__namespace.createElement(wonderBlocksLayout.MediaLayout, {
617
- styleSheets: styleSheets$1
618
- }, ({
619
- styles
620
- }) => React__namespace.createElement(wonderBlocksCore.View, {
621
- style: [styles.wrapper, scrollOverflow && styles.scrollOverflow]
622
- }, React__namespace.createElement(wonderBlocksCore.View, {
623
- style: [styles.content, style]
624
- }, children)));
625
- }
629
+ function ModalContent(props) {
630
+ const {
631
+ scrollOverflow,
632
+ style,
633
+ children
634
+ } = props;
635
+ const {
636
+ theme
637
+ } = wonderBlocksTheming.useScopedTheme(ModalDialogThemeContext);
638
+ const styles = wonderBlocksTheming.useStyles(themedStylesFn$1, theme);
639
+ return React__namespace.createElement(wonderBlocksCore.View, {
640
+ style: [styles.wrapper, scrollOverflow && styles.scrollOverflow]
641
+ }, React__namespace.createElement(wonderBlocksCore.View, {
642
+ style: [styles.content, style]
643
+ }, children));
626
644
  }
627
- ModalContent.defaultProps = {
628
- scrollOverflow: true
629
- };
630
645
  ModalContent.__IS_MODAL_CONTENT__ = true;
631
- const styleSheets$1 = {
632
- all: aphrodite.StyleSheet.create({
633
- wrapper: {
634
- flex: 1,
635
- display: "block"
636
- },
637
- scrollOverflow: {
638
- overflow: "auto"
639
- },
640
- content: {
641
- flex: 1,
642
- minHeight: "100%",
643
- padding: Spacing__default["default"].xLarge_32,
644
- boxSizing: "border-box"
645
- }
646
- }),
647
- small: aphrodite.StyleSheet.create({
648
- content: {
646
+ ModalContent.isComponentOf = instance => {
647
+ return instance && instance.type && instance.type.__IS_MODAL_CONTENT__;
648
+ };
649
+ const small = "@media (max-width: 767px)";
650
+ const themedStylesFn$1 = theme => ({
651
+ wrapper: {
652
+ flex: 1,
653
+ display: "block"
654
+ },
655
+ scrollOverflow: {
656
+ overflow: "auto"
657
+ },
658
+ content: {
659
+ flex: 1,
660
+ minHeight: "100%",
661
+ padding: Spacing__default["default"].xLarge_32,
662
+ boxSizing: "border-box",
663
+ [small]: {
649
664
  padding: `${Spacing__default["default"].xLarge_32}px ${Spacing__default["default"].medium_16}px`
650
665
  }
651
- })
666
+ }
667
+ });
668
+ ModalContent.defaultProps = {
669
+ scrollOverflow: true
652
670
  };
653
671
 
654
672
  class CloseButton extends React__namespace.Component {
@@ -678,14 +696,23 @@ class CloseButton extends React__namespace.Component {
678
696
  }
679
697
  }
680
698
 
681
- class ModalPanel extends React__namespace.Component {
682
- renderMainContent() {
683
- const {
684
- content,
685
- footer,
686
- scrollOverflow
687
- } = this.props;
688
- const mainContent = ModalContent.isClassOf(content) ? content : React__namespace.createElement(ModalContent, null, content);
699
+ function ModalPanel({
700
+ closeButtonVisible = true,
701
+ scrollOverflow = true,
702
+ light = true,
703
+ content,
704
+ footer,
705
+ header,
706
+ onClose,
707
+ style,
708
+ testId
709
+ }) {
710
+ const {
711
+ theme
712
+ } = wonderBlocksTheming.useScopedTheme(ModalDialogThemeContext);
713
+ const styles = wonderBlocksTheming.useStyles(themedStylesFn, theme);
714
+ const renderMainContent = React__namespace.useCallback(() => {
715
+ const mainContent = ModalContent.isComponentOf(content) ? content : React__namespace.createElement(ModalContent, null, content);
689
716
  if (!mainContent) {
690
717
  return mainContent;
691
718
  }
@@ -693,35 +720,24 @@ class ModalPanel extends React__namespace.Component {
693
720
  scrollOverflow,
694
721
  style: [!!footer && styles.hasFooter, mainContent.props.style]
695
722
  });
696
- }
697
- render() {
698
- const {
699
- closeButtonVisible,
700
- footer,
701
- header,
702
- light,
703
- onClose,
704
- style,
705
- testId
706
- } = this.props;
707
- const mainContent = this.renderMainContent();
708
- return React__namespace.createElement(wonderBlocksCore.View, {
709
- style: [styles.wrapper, !light && styles.dark, style],
710
- testId: testId && `${testId}-panel`
711
- }, closeButtonVisible && React__namespace.createElement(CloseButton, {
712
- light: !light,
713
- onClick: onClose,
714
- style: styles.closeButton,
715
- testId: testId && `${testId}-close`
716
- }), header, mainContent, !footer || ModalFooter.isClassOf(footer) ? footer : React__namespace.createElement(ModalFooter, null, footer));
717
- }
723
+ }, [content, footer, scrollOverflow, styles.hasFooter]);
724
+ const mainContent = renderMainContent();
725
+ return React__namespace.createElement(wonderBlocksCore.View, {
726
+ style: [styles.wrapper, !light && styles.dark, style],
727
+ testId: testId && `${testId}-panel`
728
+ }, closeButtonVisible && React__namespace.createElement(CloseButton, {
729
+ light: !light,
730
+ onClick: onClose,
731
+ style: styles.closeButton,
732
+ testId: testId && `${testId}-close`
733
+ }), header, mainContent, !footer || ModalFooter.isComponentOf(footer) ? footer : React__namespace.createElement(ModalFooter, null, footer));
718
734
  }
719
735
  ModalPanel.defaultProps = {
720
736
  closeButtonVisible: true,
721
737
  scrollOverflow: true,
722
738
  light: true
723
739
  };
724
- const styles = aphrodite.StyleSheet.create({
740
+ const themedStylesFn = theme => ({
725
741
  wrapper: {
726
742
  flex: "1 1 auto",
727
743
  position: "relative",
@@ -735,16 +751,16 @@ const styles = aphrodite.StyleSheet.create({
735
751
  },
736
752
  closeButton: {
737
753
  position: "absolute",
738
- right: Spacing__default["default"].medium_16,
739
- top: Spacing__default["default"].medium_16,
754
+ right: theme.spacing.panel.closeButton,
755
+ top: theme.spacing.panel.closeButton,
740
756
  zIndex: 1
741
757
  },
742
758
  dark: {
743
- background: Color__default["default"].darkBlue,
744
- color: Color__default["default"].white
759
+ background: theme.color.bg.inverse,
760
+ color: theme.color.text.inverse
745
761
  },
746
762
  hasFooter: {
747
- paddingBottom: Spacing__default["default"].xLarge_32
763
+ paddingBottom: theme.spacing.panel.footer
748
764
  }
749
765
  });
750
766
 
@@ -1,4 +1,16 @@
1
1
  declare const theme: {
2
+ color: {
3
+ bg: {
4
+ inverse: string;
5
+ };
6
+ text: {
7
+ inverse: string;
8
+ secondary: string;
9
+ };
10
+ shadow: {
11
+ default: string;
12
+ };
13
+ };
2
14
  border: {
3
15
  radius: number;
4
16
  };
@@ -6,6 +18,16 @@ declare const theme: {
6
18
  dialog: {
7
19
  small: 16;
8
20
  };
21
+ panel: {
22
+ closeButton: 16;
23
+ footer: 32;
24
+ };
25
+ header: {
26
+ xsmall: 8;
27
+ small: 16;
28
+ medium: 24;
29
+ large: 32;
30
+ };
9
31
  };
10
32
  };
11
33
  export default theme;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The overrides for the Khanmigo theme.
3
+ */
4
+ declare const theme: {
5
+ color: {
6
+ bg: {
7
+ inverse: string;
8
+ };
9
+ text: {
10
+ inverse: string;
11
+ secondary: string;
12
+ };
13
+ shadow: {
14
+ default: string;
15
+ };
16
+ };
17
+ border: {
18
+ radius: number;
19
+ };
20
+ spacing: {
21
+ dialog: {
22
+ small: 16;
23
+ };
24
+ panel: {
25
+ closeButton: 16;
26
+ footer: 32;
27
+ };
28
+ header: {
29
+ xsmall: 8;
30
+ small: 16;
31
+ medium: 24;
32
+ large: 32;
33
+ };
34
+ };
35
+ };
36
+ export default theme;
@@ -9,6 +9,18 @@ export type ModalDialogThemeContract = typeof defaultTheme;
9
9
  * This is generally consumed via the `useScopedTheme` hook.
10
10
  */
11
11
  export declare const ModalDialogThemeContext: React.Context<{
12
+ color: {
13
+ bg: {
14
+ inverse: string;
15
+ };
16
+ text: {
17
+ inverse: string;
18
+ secondary: string;
19
+ };
20
+ shadow: {
21
+ default: string;
22
+ };
23
+ };
12
24
  border: {
13
25
  radius: number;
14
26
  };
@@ -16,6 +28,16 @@ export declare const ModalDialogThemeContext: React.Context<{
16
28
  dialog: {
17
29
  small: 16;
18
30
  };
31
+ panel: {
32
+ closeButton: 16;
33
+ footer: 32;
34
+ };
35
+ header: {
36
+ xsmall: 8;
37
+ small: 16;
38
+ medium: 24;
39
+ large: 32;
40
+ };
19
41
  };
20
42
  }>;
21
43
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-modal",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "design": "v2",
5
5
  "publishConfig": {
6
6
  "access": "public"