@khanacademy/wonder-blocks-modal 4.1.0 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @khanacademy/wonder-blocks-modal
2
2
 
3
+ ## 4.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [80592e75]
8
+ - @khanacademy/wonder-blocks-theming@1.3.0
9
+ - @khanacademy/wonder-blocks-icon-button@5.1.8
10
+
11
+ ## 4.2.0
12
+
13
+ ### Minor Changes
14
+
15
+ - b7bae8f2: Add theming support to ModalPanel
16
+ - 09c61d25: Add theming support to ModalHeader and ModalFooter
17
+
3
18
  ## 4.1.0
4
19
 
5
20
  ### Minor Changes
@@ -8,16 +8,15 @@ type Props = {
8
8
  /** Optional styling to apply to the contents. */
9
9
  style?: StyleType;
10
10
  };
11
- type DefaultProps = {
12
- scrollOverflow: Props["scrollOverflow"];
13
- };
14
11
  /**
15
12
  * The Modal content included after the header
16
13
  */
17
- export default class ModalContent extends React.Component<Props> {
18
- static isClassOf(instance: any): boolean;
19
- static defaultProps: DefaultProps;
20
- static __IS_MODAL_CONTENT__: boolean;
21
- render(): React.ReactNode;
14
+ declare function ModalContent(props: Props): JSX.Element;
15
+ declare namespace ModalContent {
16
+ var __IS_MODAL_CONTENT__: boolean;
17
+ var isComponentOf: (instance: any) => boolean;
18
+ var defaultProps: {
19
+ scrollOverflow: boolean;
20
+ };
22
21
  }
23
- export {};
22
+ export default ModalContent;
@@ -19,9 +19,9 @@ type Props = {
19
19
  * </ModalFooter>
20
20
  * ```
21
21
  */
22
- export default class ModalFooter extends React.Component<Props> {
23
- static isClassOf(instance: any): boolean;
24
- static __IS_MODAL_FOOTER__: boolean;
25
- render(): React.ReactNode;
22
+ declare function ModalFooter({ children }: Props): JSX.Element;
23
+ declare namespace ModalFooter {
24
+ var __IS_MODAL_FOOTER__: boolean;
25
+ var isComponentOf: (instance: any) => boolean;
26
26
  }
27
- export {};
27
+ export default ModalFooter;
@@ -40,9 +40,6 @@ type WithBreadcrumbs = Common & {
40
40
  breadcrumbs: React.ReactElement<React.ComponentProps<typeof Breadcrumbs>>;
41
41
  };
42
42
  type Props = Common | WithSubtitle | WithBreadcrumbs;
43
- type DefaultProps = {
44
- light: Props["light"];
45
- };
46
43
  /**
47
44
  * This is a helper component that is never rendered by itself. It is always
48
45
  * pinned to the top of the dialog, is responsive using the same behavior as its
@@ -86,8 +83,10 @@ type DefaultProps = {
86
83
  * />
87
84
  * ```
88
85
  */
89
- export default class ModalHeader extends React.Component<Props> {
90
- static defaultProps: DefaultProps;
91
- render(): React.ReactNode;
86
+ declare function ModalHeader(props: Props): JSX.Element;
87
+ declare namespace ModalHeader {
88
+ var defaultProps: {
89
+ light: boolean;
90
+ };
92
91
  }
93
- export {};
92
+ export default ModalHeader;
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import { PropsFor } from "@khanacademy/wonder-blocks-core";
2
3
  import type { StyleType } from "@khanacademy/wonder-blocks-core";
3
4
  import ModalContent from "./modal-content";
4
5
  import ModalHeader from "./modal-header";
@@ -8,15 +9,15 @@ type Props = {
8
9
  * The main contents of the ModalPanel. All other parts of the panel
9
10
  * are positioned around it.
10
11
  */
11
- content: React.ReactElement<React.ComponentProps<typeof ModalContent>> | React.ReactNode;
12
+ content: React.ReactElement<PropsFor<typeof ModalContent>> | React.ReactNode;
12
13
  /**
13
14
  * The modal header to show at the top of the panel.
14
15
  */
15
- header?: React.ReactElement<React.ComponentProps<typeof ModalHeader>> | React.ReactNode;
16
+ header?: React.ReactElement<PropsFor<typeof ModalHeader>> | React.ReactNode;
16
17
  /**
17
18
  * A footer to show beneath the contents.
18
19
  */
19
- footer?: React.ReactElement<React.ComponentProps<typeof ModalFooter>> | React.ReactNode;
20
+ footer?: React.ReactElement<PropsFor<typeof ModalFooter>> | React.ReactNode;
20
21
  /**
21
22
  * When true, the close button is shown; otherwise, the close button is not shown.
22
23
  */
@@ -51,13 +52,8 @@ type Props = {
51
52
  */
52
53
  testId?: string;
53
54
  };
54
- type DefaultProps = {
55
- closeButtonVisible: Props["closeButtonVisible"];
56
- scrollOverflow: Props["scrollOverflow"];
57
- light: Props["light"];
58
- };
59
55
  /**
60
- * ModalPanel is the content container.
56
+ * ModalPanel is the content container.
61
57
  *
62
58
  * **Implementation notes:**
63
59
  *
@@ -76,9 +72,12 @@ type DefaultProps = {
76
72
  * </ModalDialog>
77
73
  * ```
78
74
  */
79
- export default class ModalPanel extends React.Component<Props> {
80
- static defaultProps: DefaultProps;
81
- renderMainContent(): React.ReactNode;
82
- render(): React.ReactNode;
75
+ declare function ModalPanel({ closeButtonVisible, scrollOverflow, light, content, footer, header, onClose, style, testId, }: Props): JSX.Element;
76
+ declare namespace ModalPanel {
77
+ var defaultProps: {
78
+ closeButtonVisible: boolean;
79
+ scrollOverflow: boolean;
80
+ light: boolean;
81
+ };
83
82
  }
84
- export {};
83
+ export default ModalPanel;
package/dist/es/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import * as React from 'react';
2
2
  import { View, IDProvider } from '@khanacademy/wonder-blocks-core';
3
- import { tokens, createThemeContext, ThemeSwitcherContext, useScopedTheme, useStyles } from '@khanacademy/wonder-blocks-theming';
3
+ import { tokens, mergeTheme, createThemeContext, ThemeSwitcherContext, useScopedTheme, useStyles } from '@khanacademy/wonder-blocks-theming';
4
4
  import { StyleSheet } from 'aphrodite';
5
5
  import Color from '@khanacademy/wonder-blocks-color';
6
6
  import Spacing from '@khanacademy/wonder-blocks-spacing';
7
- import { MediaLayout } from '@khanacademy/wonder-blocks-layout';
8
7
  import { HeadingMedium, LabelSmall } from '@khanacademy/wonder-blocks-typography';
9
8
  import * as ReactDOM from 'react-dom';
10
9
  import { withActionScheduler } from '@khanacademy/wonder-blocks-timing';
11
10
  import xIcon from '@phosphor-icons/core/regular/x.svg';
12
11
  import IconButton from '@khanacademy/wonder-blocks-icon-button';
12
+ import { MediaLayout } from '@khanacademy/wonder-blocks-layout';
13
13
 
14
14
  function _extends() {
15
15
  _extends = Object.assign ? Object.assign.bind() : function (target) {
@@ -26,26 +26,57 @@ function _extends() {
26
26
  return _extends.apply(this, arguments);
27
27
  }
28
28
 
29
- const theme = {
29
+ const theme$1 = {
30
+ color: {
31
+ bg: {
32
+ inverse: tokens.color.darkBlue
33
+ },
34
+ text: {
35
+ inverse: tokens.color.white,
36
+ secondary: tokens.color.offBlack64
37
+ },
38
+ shadow: {
39
+ default: tokens.color.offBlack16
40
+ }
41
+ },
30
42
  border: {
31
43
  radius: tokens.border.radius.medium_4
32
44
  },
33
45
  spacing: {
34
46
  dialog: {
35
47
  small: tokens.spacing.medium_16
48
+ },
49
+ panel: {
50
+ closeButton: tokens.spacing.medium_16,
51
+ footer: tokens.spacing.xLarge_32
52
+ },
53
+ header: {
54
+ xsmall: tokens.spacing.xSmall_8,
55
+ small: tokens.spacing.medium_16,
56
+ medium: tokens.spacing.large_24,
57
+ large: tokens.spacing.xLarge_32
36
58
  }
37
59
  }
38
60
  };
39
61
 
62
+ const theme = mergeTheme(theme$1, {
63
+ color: {
64
+ bg: {
65
+ inverse: tokens.color.eggplant
66
+ }
67
+ }
68
+ });
69
+
40
70
  const themes = {
41
- default: theme
71
+ default: theme$1,
72
+ khanmigo: theme
42
73
  };
43
- const ModalDialogThemeContext = createThemeContext(theme);
74
+ const ModalDialogThemeContext = createThemeContext(theme$1);
44
75
  function ThemeModalDialog(props) {
45
76
  const currentTheme = React.useContext(ThemeSwitcherContext);
46
- const theme$1 = themes[currentTheme] || theme;
77
+ const theme = themes[currentTheme] || theme$1;
47
78
  return React.createElement(ModalDialogThemeContext.Provider, {
48
- value: theme$1
79
+ value: theme
49
80
  }, props.children);
50
81
  }
51
82
 
@@ -63,7 +94,7 @@ const ModalDialogCore = React.forwardRef(function ModalDialogCore(props, ref) {
63
94
  const {
64
95
  theme
65
96
  } = useScopedTheme(ModalDialogThemeContext);
66
- const styles = useStyles(themedStylesFn, theme);
97
+ const styles = useStyles(themedStylesFn$3, theme);
67
98
  return React.createElement(View, {
68
99
  style: [styles.wrapper, style]
69
100
  }, below && React.createElement(View, {
@@ -85,8 +116,8 @@ const ModalDialog = React.forwardRef(function ModalDialog(props, ref) {
85
116
  ref: ref
86
117
  })));
87
118
  });
88
- const small = "@media (max-width: 767px)";
89
- const themedStylesFn = theme => ({
119
+ const small$2 = "@media (max-width: 767px)";
120
+ const themedStylesFn$3 = theme => ({
90
121
  wrapper: {
91
122
  display: "flex",
92
123
  flexDirection: "row",
@@ -94,7 +125,7 @@ const themedStylesFn = theme => ({
94
125
  width: "100%",
95
126
  height: "100%",
96
127
  position: "relative",
97
- [small]: {
128
+ [small$2]: {
98
129
  padding: theme.spacing.dialog.small,
99
130
  flexDirection: "column"
100
131
  }
@@ -126,21 +157,18 @@ const themedStylesFn = theme => ({
126
157
  });
127
158
  ModalDialog.displayName = "ModalDialog";
128
159
 
129
- class ModalFooter extends React.Component {
130
- static isClassOf(instance) {
131
- return instance && instance.type && instance.type.__IS_MODAL_FOOTER__;
132
- }
133
- render() {
134
- const {
135
- children
136
- } = this.props;
137
- return React.createElement(View, {
138
- style: styles$3.footer
139
- }, children);
140
- }
160
+ function ModalFooter({
161
+ children
162
+ }) {
163
+ return React.createElement(View, {
164
+ style: styles$2.footer
165
+ }, children);
141
166
  }
142
167
  ModalFooter.__IS_MODAL_FOOTER__ = true;
143
- const styles$3 = StyleSheet.create({
168
+ ModalFooter.isComponentOf = instance => {
169
+ return instance && instance.type && instance.type.__IS_MODAL_FOOTER__;
170
+ };
171
+ const styles$2 = StyleSheet.create({
144
172
  footer: {
145
173
  flex: "0 0 auto",
146
174
  boxSizing: "border-box",
@@ -157,77 +185,72 @@ const styles$3 = StyleSheet.create({
157
185
  }
158
186
  });
159
187
 
160
- class ModalHeader extends React.Component {
161
- render() {
162
- const {
163
- breadcrumbs = undefined,
164
- light,
165
- subtitle = undefined,
166
- testId,
167
- title,
168
- titleId
169
- } = this.props;
170
- if (subtitle && breadcrumbs) {
171
- throw new Error("'subtitle' and 'breadcrumbs' can't be used together");
172
- }
173
- return React.createElement(MediaLayout, {
174
- styleSheets: styleSheets$2
175
- }, ({
176
- styles
177
- }) => React.createElement(View, {
178
- style: [styles.header, !light && styles.dark],
179
- testId: testId
180
- }, breadcrumbs && React.createElement(View, {
181
- style: styles.breadcrumbs
182
- }, breadcrumbs), React.createElement(HeadingMedium, {
183
- style: styles.title,
184
- id: titleId,
185
- testId: testId && `${testId}-title`
186
- }, title), subtitle && React.createElement(LabelSmall, {
187
- style: light && styles.subtitle,
188
- testId: testId && `${testId}-subtitle`
189
- }, subtitle)));
188
+ function ModalHeader(props) {
189
+ const {
190
+ breadcrumbs = undefined,
191
+ light,
192
+ subtitle = undefined,
193
+ testId,
194
+ title,
195
+ titleId
196
+ } = props;
197
+ if (subtitle && breadcrumbs) {
198
+ throw new Error("'subtitle' and 'breadcrumbs' can't be used together");
190
199
  }
200
+ const {
201
+ theme
202
+ } = useScopedTheme(ModalDialogThemeContext);
203
+ const styles = useStyles(themedStylesFn$2, theme);
204
+ return React.createElement(View, {
205
+ style: [styles.header, !light && styles.dark],
206
+ testId: testId
207
+ }, breadcrumbs && React.createElement(View, {
208
+ style: styles.breadcrumbs
209
+ }, breadcrumbs), React.createElement(HeadingMedium, {
210
+ style: styles.title,
211
+ id: titleId,
212
+ testId: testId && `${testId}-title`
213
+ }, title), subtitle && React.createElement(LabelSmall, {
214
+ style: light && styles.subtitle,
215
+ testId: testId && `${testId}-subtitle`
216
+ }, subtitle));
191
217
  }
192
- ModalHeader.defaultProps = {
193
- light: true
194
- };
195
- const styleSheets$2 = {
196
- all: StyleSheet.create({
197
- header: {
198
- boxShadow: `0px 1px 0px ${Color.offBlack16}`,
199
- display: "flex",
200
- flexDirection: "column",
201
- minHeight: 66,
202
- padding: `${Spacing.large_24}px ${Spacing.xLarge_32}px`,
203
- position: "relative",
204
- width: "100%"
205
- },
206
- dark: {
207
- background: Color.darkBlue,
208
- color: Color.white
209
- },
210
- breadcrumbs: {
211
- color: Color.offBlack64,
212
- marginBottom: Spacing.xSmall_8
213
- },
214
- title: {
215
- paddingRight: Spacing.medium_16
216
- },
217
- subtitle: {
218
- color: Color.offBlack64,
219
- marginTop: Spacing.xSmall_8
218
+ const small$1 = "@media (max-width: 767px)";
219
+ const themedStylesFn$2 = theme => ({
220
+ header: {
221
+ boxShadow: `0px 1px 0px ${theme.color.shadow.default}`,
222
+ display: "flex",
223
+ flexDirection: "column",
224
+ minHeight: 66,
225
+ padding: `${theme.spacing.header.medium}px ${theme.spacing.header.large}px`,
226
+ position: "relative",
227
+ width: "100%",
228
+ [small$1]: {
229
+ paddingLeft: theme.spacing.header.small,
230
+ paddingRight: theme.spacing.header.small
220
231
  }
221
- }),
222
- small: StyleSheet.create({
223
- header: {
224
- paddingLeft: Spacing.medium_16,
225
- paddingRight: Spacing.medium_16
226
- },
227
- title: {
228
- paddingRight: Spacing.xLarge_32
232
+ },
233
+ dark: {
234
+ background: theme.color.bg.inverse,
235
+ color: theme.color.text.inverse
236
+ },
237
+ breadcrumbs: {
238
+ color: theme.color.text.secondary,
239
+ marginBottom: theme.spacing.header.xsmall
240
+ },
241
+ title: {
242
+ paddingRight: theme.spacing.header.small,
243
+ [small$1]: {
244
+ paddingRight: theme.spacing.header.large
229
245
  }
230
- })
246
+ },
247
+ subtitle: {
248
+ color: theme.color.text.secondary,
249
+ marginTop: theme.spacing.header.xsmall
250
+ }
251
+ });
252
+ ModalHeader.defaultProps = {
253
+ light: true
231
254
  };
232
255
 
233
256
  const FOCUSABLE_ELEMENTS$1 = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
@@ -353,14 +376,14 @@ class ModalBackdrop extends React.Component {
353
376
  [ModalLauncherPortalAttributeName]: true
354
377
  };
355
378
  return React.createElement(View, _extends({
356
- style: styles$2.modalPositioner,
379
+ style: styles$1.modalPositioner,
357
380
  onMouseDown: this.handleMouseDown,
358
381
  onMouseUp: this.handleMouseUp,
359
382
  testId: testId
360
383
  }, backdropProps), children);
361
384
  }
362
385
  }
363
- const styles$2 = StyleSheet.create({
386
+ const styles$1 = StyleSheet.create({
364
387
  modalPositioner: {
365
388
  position: "fixed",
366
389
  left: 0,
@@ -531,7 +554,7 @@ class ModalLauncher extends React.Component {
531
554
  closeModal: this.handleCloseModal
532
555
  }
533
556
  }, renderedChildren, this.state.opened && ReactDOM.createPortal(React.createElement(FocusTrap, {
534
- style: styles$1.container
557
+ style: styles.container
535
558
  }, React.createElement(ModalBackdrop, {
536
559
  initialFocusId: this.props.initialFocusId,
537
560
  testId: this.props.testId,
@@ -565,59 +588,54 @@ class ModalLauncherKeypressListener extends React.Component {
565
588
  return null;
566
589
  }
567
590
  }
568
- const styles$1 = StyleSheet.create({
591
+ const styles = StyleSheet.create({
569
592
  container: {
570
593
  zIndex: 1080
571
594
  }
572
595
  });
573
596
  var modalLauncher = withActionScheduler(ModalLauncher);
574
597
 
575
- class ModalContent extends React.Component {
576
- static isClassOf(instance) {
577
- return instance && instance.type && instance.type.__IS_MODAL_CONTENT__;
578
- }
579
- render() {
580
- const {
581
- scrollOverflow,
582
- style,
583
- children
584
- } = this.props;
585
- return React.createElement(MediaLayout, {
586
- styleSheets: styleSheets$1
587
- }, ({
588
- styles
589
- }) => React.createElement(View, {
590
- style: [styles.wrapper, scrollOverflow && styles.scrollOverflow]
591
- }, React.createElement(View, {
592
- style: [styles.content, style]
593
- }, children)));
594
- }
598
+ function ModalContent(props) {
599
+ const {
600
+ scrollOverflow,
601
+ style,
602
+ children
603
+ } = props;
604
+ const {
605
+ theme
606
+ } = useScopedTheme(ModalDialogThemeContext);
607
+ const styles = useStyles(themedStylesFn$1, theme);
608
+ return React.createElement(View, {
609
+ style: [styles.wrapper, scrollOverflow && styles.scrollOverflow]
610
+ }, React.createElement(View, {
611
+ style: [styles.content, style]
612
+ }, children));
595
613
  }
596
- ModalContent.defaultProps = {
597
- scrollOverflow: true
598
- };
599
614
  ModalContent.__IS_MODAL_CONTENT__ = true;
600
- const styleSheets$1 = {
601
- all: StyleSheet.create({
602
- wrapper: {
603
- flex: 1,
604
- display: "block"
605
- },
606
- scrollOverflow: {
607
- overflow: "auto"
608
- },
609
- content: {
610
- flex: 1,
611
- minHeight: "100%",
612
- padding: Spacing.xLarge_32,
613
- boxSizing: "border-box"
614
- }
615
- }),
616
- small: StyleSheet.create({
617
- content: {
615
+ ModalContent.isComponentOf = instance => {
616
+ return instance && instance.type && instance.type.__IS_MODAL_CONTENT__;
617
+ };
618
+ const small = "@media (max-width: 767px)";
619
+ const themedStylesFn$1 = theme => ({
620
+ wrapper: {
621
+ flex: 1,
622
+ display: "block"
623
+ },
624
+ scrollOverflow: {
625
+ overflow: "auto"
626
+ },
627
+ content: {
628
+ flex: 1,
629
+ minHeight: "100%",
630
+ padding: Spacing.xLarge_32,
631
+ boxSizing: "border-box",
632
+ [small]: {
618
633
  padding: `${Spacing.xLarge_32}px ${Spacing.medium_16}px`
619
634
  }
620
- })
635
+ }
636
+ });
637
+ ModalContent.defaultProps = {
638
+ scrollOverflow: true
621
639
  };
622
640
 
623
641
  class CloseButton extends React.Component {
@@ -647,14 +665,23 @@ class CloseButton extends React.Component {
647
665
  }
648
666
  }
649
667
 
650
- class ModalPanel extends React.Component {
651
- renderMainContent() {
652
- const {
653
- content,
654
- footer,
655
- scrollOverflow
656
- } = this.props;
657
- const mainContent = ModalContent.isClassOf(content) ? content : React.createElement(ModalContent, null, content);
668
+ function ModalPanel({
669
+ closeButtonVisible = true,
670
+ scrollOverflow = true,
671
+ light = true,
672
+ content,
673
+ footer,
674
+ header,
675
+ onClose,
676
+ style,
677
+ testId
678
+ }) {
679
+ const {
680
+ theme
681
+ } = useScopedTheme(ModalDialogThemeContext);
682
+ const styles = useStyles(themedStylesFn, theme);
683
+ const renderMainContent = React.useCallback(() => {
684
+ const mainContent = ModalContent.isComponentOf(content) ? content : React.createElement(ModalContent, null, content);
658
685
  if (!mainContent) {
659
686
  return mainContent;
660
687
  }
@@ -662,35 +689,24 @@ class ModalPanel extends React.Component {
662
689
  scrollOverflow,
663
690
  style: [!!footer && styles.hasFooter, mainContent.props.style]
664
691
  });
665
- }
666
- render() {
667
- const {
668
- closeButtonVisible,
669
- footer,
670
- header,
671
- light,
672
- onClose,
673
- style,
674
- testId
675
- } = this.props;
676
- const mainContent = this.renderMainContent();
677
- return React.createElement(View, {
678
- style: [styles.wrapper, !light && styles.dark, style],
679
- testId: testId && `${testId}-panel`
680
- }, closeButtonVisible && React.createElement(CloseButton, {
681
- light: !light,
682
- onClick: onClose,
683
- style: styles.closeButton,
684
- testId: testId && `${testId}-close`
685
- }), header, mainContent, !footer || ModalFooter.isClassOf(footer) ? footer : React.createElement(ModalFooter, null, footer));
686
- }
692
+ }, [content, footer, scrollOverflow, styles.hasFooter]);
693
+ const mainContent = renderMainContent();
694
+ return React.createElement(View, {
695
+ style: [styles.wrapper, !light && styles.dark, style],
696
+ testId: testId && `${testId}-panel`
697
+ }, closeButtonVisible && React.createElement(CloseButton, {
698
+ light: !light,
699
+ onClick: onClose,
700
+ style: styles.closeButton,
701
+ testId: testId && `${testId}-close`
702
+ }), header, mainContent, !footer || ModalFooter.isComponentOf(footer) ? footer : React.createElement(ModalFooter, null, footer));
687
703
  }
688
704
  ModalPanel.defaultProps = {
689
705
  closeButtonVisible: true,
690
706
  scrollOverflow: true,
691
707
  light: true
692
708
  };
693
- const styles = StyleSheet.create({
709
+ const themedStylesFn = theme => ({
694
710
  wrapper: {
695
711
  flex: "1 1 auto",
696
712
  position: "relative",
@@ -704,16 +720,16 @@ const styles = StyleSheet.create({
704
720
  },
705
721
  closeButton: {
706
722
  position: "absolute",
707
- right: Spacing.medium_16,
708
- top: Spacing.medium_16,
723
+ right: theme.spacing.panel.closeButton,
724
+ top: theme.spacing.panel.closeButton,
709
725
  zIndex: 1
710
726
  },
711
727
  dark: {
712
- background: Color.darkBlue,
713
- color: Color.white
728
+ background: theme.color.bg.inverse,
729
+ color: theme.color.text.inverse
714
730
  },
715
731
  hasFooter: {
716
- paddingBottom: Spacing.xLarge_32
732
+ paddingBottom: theme.spacing.panel.footer
717
733
  }
718
734
  });
719
735