@khanacademy/wonder-blocks-modal 4.0.39 → 4.1.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.
@@ -1,14 +1,16 @@
1
1
  import * as React from "react";
2
- import {StyleSheet} from "aphrodite";
3
- import {
4
- MediaLayout,
5
- MediaLayoutContext,
6
- MEDIA_MODAL_SPEC,
7
- } from "@khanacademy/wonder-blocks-layout";
8
2
  import {View} from "@khanacademy/wonder-blocks-core";
9
3
  import type {StyleType} from "@khanacademy/wonder-blocks-core";
10
- import type {MediaLayoutContextValue} from "@khanacademy/wonder-blocks-layout";
11
- import Spacing from "@khanacademy/wonder-blocks-spacing";
4
+
5
+ import {
6
+ ThemedStylesFn,
7
+ useScopedTheme,
8
+ useStyles,
9
+ } from "@khanacademy/wonder-blocks-theming";
10
+ import ThemeModalDialog, {
11
+ ModalDialogThemeContext,
12
+ ModalDialogThemeContract,
13
+ } from "../themes/themed-modal-dialog";
12
14
 
13
15
  type Props = {
14
16
  /**
@@ -42,7 +44,7 @@ type Props = {
42
44
  */
43
45
  testId?: string;
44
46
  /**
45
- * The ID of the content labelling this dialog, if applicable.
47
+ * The ID of the title labelling this dialog, if applicable.
46
48
  */
47
49
  "aria-labelledby"?: string;
48
50
  /**
@@ -51,10 +53,6 @@ type Props = {
51
53
  "aria-describedby"?: string;
52
54
  };
53
55
 
54
- type DefaultProps = {
55
- role: Props["role"];
56
- };
57
-
58
56
  /**
59
57
  * `ModalDialog` is a component that contains these elements:
60
58
  * - The visual dialog element itself (`<div role="dialog"/>`)
@@ -65,102 +63,104 @@ type DefaultProps = {
65
63
  * - If there is a custom Dialog implementation (e.g. `TwoPaneDialog`), the dialog element doesn’t have to have
66
64
  * the `aria-labelledby` attribute however this is recommended. It should match the `id` of the dialog title.
67
65
  */
68
- export default class ModalDialog extends React.Component<Props> {
69
- static defaultProps: DefaultProps = {
70
- role: "dialog",
71
- };
66
+ const ModalDialogCore = React.forwardRef(function ModalDialogCore(
67
+ props: Props,
68
+ ref: React.ForwardedRef<HTMLDivElement>,
69
+ ) {
70
+ const {
71
+ above,
72
+ below,
73
+ role = "dialog",
74
+ style,
75
+ children,
76
+ testId,
77
+ /* eslint-disable react/prop-types */
78
+ // the react/prop-types plugin does not like these
79
+ "aria-labelledby": ariaLabelledBy,
80
+ "aria-describedby": ariaDescribedBy,
81
+ /* eslint-enable react/prop-types */
82
+ } = props;
72
83
 
73
- render(): React.ReactNode {
74
- const {
75
- above,
76
- below,
77
- role,
78
- style,
79
- children,
80
- testId,
81
- /* eslint-disable react/prop-types */
82
- // the react/prop-types plugin does not like these
83
- "aria-labelledby": ariaLabelledBy,
84
- "aria-describedby": ariaDescribedBy,
85
- /* eslint-enable react/prop-types */
86
- } = this.props;
84
+ const {theme} = useScopedTheme(ModalDialogThemeContext);
85
+ const styles = useStyles(themedStylesFn, theme);
87
86
 
88
- const contextValue: MediaLayoutContextValue = {
89
- ssrSize: "large",
90
- mediaSpec: MEDIA_MODAL_SPEC,
91
- };
87
+ return (
88
+ <View style={[styles.wrapper, style]}>
89
+ {below && <View style={styles.below}>{below}</View>}
90
+ <View
91
+ role={role}
92
+ aria-modal="true"
93
+ aria-labelledby={ariaLabelledBy}
94
+ aria-describedby={ariaDescribedBy}
95
+ ref={ref}
96
+ style={styles.dialog}
97
+ testId={testId}
98
+ >
99
+ {children}
100
+ </View>
101
+ {above && <View style={styles.above}>{above}</View>}
102
+ </View>
103
+ );
104
+ });
92
105
 
93
- return (
94
- <MediaLayoutContext.Provider value={contextValue}>
95
- <MediaLayout styleSheets={styleSheets}>
96
- {({styles}) => (
97
- <View style={[styles.wrapper, style]}>
98
- {below && <View style={styles.below}>{below}</View>}
99
- <View
100
- role={role}
101
- aria-modal="true"
102
- aria-labelledby={ariaLabelledBy}
103
- aria-describedby={ariaDescribedBy}
104
- style={styles.dialog}
105
- testId={testId}
106
- >
107
- {children}
108
- </View>
109
- {above && <View style={styles.above}>{above}</View>}
110
- </View>
111
- )}
112
- </MediaLayout>
113
- </MediaLayoutContext.Provider>
114
- );
115
- }
116
- }
106
+ const ModalDialog = React.forwardRef(function ModalDialog(
107
+ props: Props,
108
+ ref: React.ForwardedRef<HTMLDivElement>,
109
+ ) {
110
+ return (
111
+ <ThemeModalDialog>
112
+ <ModalDialogCore {...props} ref={ref} />
113
+ </ThemeModalDialog>
114
+ );
115
+ });
117
116
 
118
- const styleSheets = {
119
- all: StyleSheet.create({
120
- wrapper: {
121
- display: "flex",
122
- flexDirection: "row",
123
- alignItems: "stretch",
124
- width: "100%",
125
- height: "100%",
126
- position: "relative",
127
- },
117
+ const small = "@media (max-width: 767px)";
128
118
 
129
- /**
130
- * Ensures the dialog container uses the container size
131
- */
132
- dialog: {
133
- width: "100%",
134
- height: "100%",
135
- borderRadius: 4,
136
- overflow: "hidden",
119
+ const themedStylesFn: ThemedStylesFn<ModalDialogThemeContract> = (theme) => ({
120
+ wrapper: {
121
+ display: "flex",
122
+ flexDirection: "row",
123
+ alignItems: "stretch",
124
+ width: "100%",
125
+ height: "100%",
126
+ position: "relative",
127
+ [small]: {
128
+ padding: theme.spacing.dialog.small,
129
+ flexDirection: "column",
137
130
  },
131
+ },
138
132
 
139
- above: {
140
- pointerEvents: "none",
141
- position: "absolute",
142
- top: 0,
143
- left: 0,
144
- bottom: 0,
145
- right: 0,
146
- zIndex: 1,
147
- },
133
+ /**
134
+ * Ensures the dialog container uses the container size
135
+ */
136
+ dialog: {
137
+ width: "100%",
138
+ height: "100%",
139
+ borderRadius: theme.border.radius,
140
+ overflow: "hidden",
141
+ },
148
142
 
149
- below: {
150
- pointerEvents: "none",
151
- position: "absolute",
152
- top: 0,
153
- left: 0,
154
- bottom: 0,
155
- right: 0,
156
- zIndex: -1,
157
- },
158
- }),
143
+ above: {
144
+ pointerEvents: "none",
145
+ position: "absolute",
146
+ top: 0,
147
+ left: 0,
148
+ bottom: 0,
149
+ right: 0,
150
+ zIndex: 1,
151
+ },
159
152
 
160
- small: StyleSheet.create({
161
- wrapper: {
162
- padding: Spacing.medium_16,
163
- flexDirection: "column",
164
- },
165
- }),
166
- } as const;
153
+ below: {
154
+ pointerEvents: "none",
155
+ position: "absolute",
156
+ top: 0,
157
+ left: 0,
158
+ bottom: 0,
159
+ right: 0,
160
+ zIndex: -1,
161
+ },
162
+ });
163
+
164
+ ModalDialog.displayName = "ModalDialog";
165
+
166
+ export default ModalDialog;
@@ -0,0 +1,14 @@
1
+ import {tokens} from "@khanacademy/wonder-blocks-theming";
2
+
3
+ const theme = {
4
+ border: {
5
+ radius: tokens.border.radius.medium_4,
6
+ },
7
+ spacing: {
8
+ dialog: {
9
+ small: tokens.spacing.medium_16,
10
+ },
11
+ },
12
+ };
13
+
14
+ export default theme;
@@ -0,0 +1,43 @@
1
+ import * as React from "react";
2
+ import {
3
+ createThemeContext,
4
+ Themes,
5
+ ThemeSwitcherContext,
6
+ } from "@khanacademy/wonder-blocks-theming";
7
+
8
+ import defaultTheme from "./default";
9
+
10
+ type Props = {
11
+ children: React.ReactNode;
12
+ };
13
+
14
+ export type ModalDialogThemeContract = typeof defaultTheme;
15
+
16
+ /**
17
+ * The themes available to the ModalDialog component.
18
+ */
19
+ const themes: Themes<ModalDialogThemeContract> = {
20
+ default: defaultTheme,
21
+ // khanmigo: khanmigoTheme,
22
+ };
23
+
24
+ /**
25
+ * The context that provides the theme to the ModalDialog component.
26
+ * This is generally consumed via the `useScopedTheme` hook.
27
+ */
28
+ export const ModalDialogThemeContext = createThemeContext(defaultTheme);
29
+
30
+ /**
31
+ * ThemeModalDialog is a component that provides a theme to the <ModalDialog/>
32
+ * component.
33
+ */
34
+ export default function ThemeModalDialog(props: Props) {
35
+ const currentTheme = React.useContext(ThemeSwitcherContext);
36
+
37
+ const theme = themes[currentTheme] || defaultTheme;
38
+ return (
39
+ <ModalDialogThemeContext.Provider value={theme}>
40
+ {props.children}
41
+ </ModalDialogThemeContext.Provider>
42
+ );
43
+ }
@@ -14,6 +14,7 @@
14
14
  {"path": "../wonder-blocks-icon-button/tsconfig-build.json"},
15
15
  {"path": "../wonder-blocks-layout/tsconfig-build.json"},
16
16
  {"path": "../wonder-blocks-spacing/tsconfig-build.json"},
17
+ {"path": "../wonder-blocks-theming/tsconfig-build.json"},
17
18
  {"path": "../wonder-blocks-timing/tsconfig-build.json"},
18
19
  {"path": "../wonder-blocks-typography/tsconfig-build.json"},
19
20
  ]