@khanacademy/wonder-blocks-modal 2.3.4 → 2.3.6
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 +16 -0
- package/dist/es/index.js +18 -69
- package/dist/index.js +180 -164
- package/package.json +5 -5
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +209 -209
- package/src/components/__docs__/modal-dialog.stories.js +308 -0
- package/src/components/__docs__/modal-footer.stories.js +337 -0
- package/src/components/__docs__/modal-header.argtypes.js +76 -0
- package/src/components/__docs__/modal-header.stories.js +294 -0
- package/src/components/__docs__/modal-launcher.argtypes.js +78 -0
- package/src/components/__docs__/modal-launcher.stories.js +512 -0
- package/src/components/__docs__/modal-panel.stories.js +414 -0
- package/src/components/__docs__/one-pane-dialog.argtypes.js +102 -0
- package/src/components/__docs__/one-pane-dialog.stories.js +582 -0
- package/src/components/__tests__/focus-trap.test.js +101 -0
- package/src/components/focus-trap.js +47 -98
- package/src/components/modal-footer.js +8 -0
- package/src/components/one-pane-dialog.js +26 -1
- package/src/components/one-pane-dialog.stories.js +0 -248
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import {StyleSheet} from "aphrodite";
|
|
4
|
+
|
|
5
|
+
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
+
import Color from "@khanacademy/wonder-blocks-color";
|
|
7
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
8
|
+
import {Strut} from "@khanacademy/wonder-blocks-layout";
|
|
9
|
+
import {
|
|
10
|
+
ModalLauncher,
|
|
11
|
+
ModalDialog,
|
|
12
|
+
ModalPanel,
|
|
13
|
+
} from "@khanacademy/wonder-blocks-modal";
|
|
14
|
+
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
15
|
+
import {Body, Title} from "@khanacademy/wonder-blocks-typography";
|
|
16
|
+
|
|
17
|
+
import type {StoryComponentType} from "@storybook/react";
|
|
18
|
+
|
|
19
|
+
import ComponentInfo from "../../../../../.storybook/components/component-info.js";
|
|
20
|
+
import {name, version} from "../../../package.json";
|
|
21
|
+
|
|
22
|
+
const customViewports = {
|
|
23
|
+
phone: {
|
|
24
|
+
name: "phone",
|
|
25
|
+
styles: {
|
|
26
|
+
width: "320px",
|
|
27
|
+
height: "568px",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
tablet: {
|
|
31
|
+
name: "tablet",
|
|
32
|
+
styles: {
|
|
33
|
+
width: "640px",
|
|
34
|
+
height: "960px",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
desktop: {
|
|
38
|
+
name: "desktop",
|
|
39
|
+
styles: {
|
|
40
|
+
width: "1024px",
|
|
41
|
+
height: "768px",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default {
|
|
47
|
+
title: "Modal/Building Blocks/ModalDialog",
|
|
48
|
+
component: ModalDialog,
|
|
49
|
+
decorators: [
|
|
50
|
+
(Story: any): React.Element<typeof View> => (
|
|
51
|
+
<View style={styles.example}>
|
|
52
|
+
<Story />
|
|
53
|
+
</View>
|
|
54
|
+
),
|
|
55
|
+
],
|
|
56
|
+
parameters: {
|
|
57
|
+
componentSubtitle: ((
|
|
58
|
+
<ComponentInfo name={name} version={version} />
|
|
59
|
+
): any),
|
|
60
|
+
docs: {
|
|
61
|
+
description: {
|
|
62
|
+
component: null,
|
|
63
|
+
},
|
|
64
|
+
source: {
|
|
65
|
+
// See https://github.com/storybookjs/storybook/issues/12596
|
|
66
|
+
excludeDecorators: true,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
viewport: {
|
|
70
|
+
viewports: customViewports,
|
|
71
|
+
defaultViewport: "desktop",
|
|
72
|
+
},
|
|
73
|
+
chromatic: {
|
|
74
|
+
viewports: [320, 640, 1024],
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
// Make the following props null in the control panel
|
|
78
|
+
// because setting an object for a React node is
|
|
79
|
+
// not practical to do manually.
|
|
80
|
+
argTypes: {
|
|
81
|
+
children: {
|
|
82
|
+
control: {type: null},
|
|
83
|
+
},
|
|
84
|
+
above: {
|
|
85
|
+
control: {type: null},
|
|
86
|
+
},
|
|
87
|
+
below: {
|
|
88
|
+
control: {type: null},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const Default: StoryComponentType = (args) => (
|
|
94
|
+
<View style={styles.previewSizer}>
|
|
95
|
+
<View style={styles.modalPositioner}>
|
|
96
|
+
<ModalDialog aria-labelledby="modal-title-0" {...args}>
|
|
97
|
+
<ModalPanel
|
|
98
|
+
content={
|
|
99
|
+
<>
|
|
100
|
+
<Title id="modal-title-0">Modal Title</Title>
|
|
101
|
+
<Strut size={Spacing.large_24} />
|
|
102
|
+
<Body>Here is some text in the modal.</Body>
|
|
103
|
+
</>
|
|
104
|
+
}
|
|
105
|
+
/>
|
|
106
|
+
</ModalDialog>
|
|
107
|
+
</View>
|
|
108
|
+
</View>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
Default.args = {
|
|
112
|
+
style: {
|
|
113
|
+
maxWidth: 500,
|
|
114
|
+
maxHeight: 500,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const Simple: StoryComponentType = () => (
|
|
119
|
+
<View style={styles.previewSizer}>
|
|
120
|
+
<View style={styles.modalPositioner}>
|
|
121
|
+
<ModalDialog
|
|
122
|
+
aria-labelledby="modal-title-1"
|
|
123
|
+
style={styles.squareDialog}
|
|
124
|
+
>
|
|
125
|
+
<ModalPanel
|
|
126
|
+
content={
|
|
127
|
+
<>
|
|
128
|
+
<Title id="modal-title-1">Modal Title</Title>
|
|
129
|
+
<Strut size={Spacing.large_24} />
|
|
130
|
+
<Body>Here is some text in the modal.</Body>
|
|
131
|
+
</>
|
|
132
|
+
}
|
|
133
|
+
/>
|
|
134
|
+
</ModalDialog>
|
|
135
|
+
</View>
|
|
136
|
+
</View>
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
Simple.parameters = {
|
|
140
|
+
docs: {
|
|
141
|
+
storyDescription: `This is a basic \`<ModalDialog>\` that wraps a
|
|
142
|
+
\`<ModalPanel>\` element. The \`<ModalDialog>\` is just a a wrapper
|
|
143
|
+
for the visual components of the overall modal. It sets
|
|
144
|
+
the modal's role to \`"dialog"\`. If it did not have another
|
|
145
|
+
element as a child here (a \`<ModalPanel>\` in this case),
|
|
146
|
+
nothing would be visible. If the \`<ModalDialog>\` were not given
|
|
147
|
+
a \`maxHeight\` or \`maxWidth\` style, it would take up the
|
|
148
|
+
entire viewport. To demonstrate the difference between
|
|
149
|
+
the \`<ModalDialog>\` and the \`<ModalPanel>\` elements, the panel
|
|
150
|
+
has been given a smaller height and width than \`<ModalDialog>\`,
|
|
151
|
+
and \`<ModalDialog>\` has been given a dark blue background.`,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export const WithAboveAndBelow: StoryComponentType = () => {
|
|
156
|
+
const aboveStyle = {
|
|
157
|
+
background: "url(./modal-above.png)",
|
|
158
|
+
width: 874,
|
|
159
|
+
height: 551,
|
|
160
|
+
position: "absolute",
|
|
161
|
+
top: 40,
|
|
162
|
+
left: -140,
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const belowStyle = {
|
|
166
|
+
background: "url(./modal-below.png)",
|
|
167
|
+
width: 868,
|
|
168
|
+
height: 521,
|
|
169
|
+
position: "absolute",
|
|
170
|
+
top: -100,
|
|
171
|
+
left: -300,
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<View style={styles.previewSizer}>
|
|
176
|
+
<View style={styles.modalPositioner}>
|
|
177
|
+
<ModalDialog
|
|
178
|
+
aria-labelledby="modal-title-2"
|
|
179
|
+
style={styles.squareDialog}
|
|
180
|
+
above={<View style={aboveStyle} />}
|
|
181
|
+
below={<View style={belowStyle} />}
|
|
182
|
+
>
|
|
183
|
+
<ModalPanel
|
|
184
|
+
content={
|
|
185
|
+
<>
|
|
186
|
+
<Title id="modal-title-2">Modal Title</Title>
|
|
187
|
+
<Strut size={Spacing.large_24} />
|
|
188
|
+
<Body>Here is some text in the modal.</Body>
|
|
189
|
+
</>
|
|
190
|
+
}
|
|
191
|
+
/>
|
|
192
|
+
</ModalDialog>
|
|
193
|
+
</View>
|
|
194
|
+
</View>
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
WithAboveAndBelow.parameters = {
|
|
199
|
+
docs: {
|
|
200
|
+
storyDescription: `The \`above\` and \`below\` props work the same
|
|
201
|
+
for \`<ModalDialog>\` as they do for \`<OnePaneDialog>\`.
|
|
202
|
+
The element passed into the \`above\` prop is rendered in front
|
|
203
|
+
of the modal. The element passed into the \`below\` prop is
|
|
204
|
+
rendered behind the modal. In this example, a \`<View>\` element
|
|
205
|
+
with a background image of a person and an orange blob is passed
|
|
206
|
+
into the \`below\` prop. A \`<View>\` element with a background
|
|
207
|
+
image of an arc and a blue semicircle is passed into the \`above\`
|
|
208
|
+
prop. This results in the person's head and the orange blob
|
|
209
|
+
peeking out from behind the modal, and the arc and semicircle
|
|
210
|
+
going over the front of the modal.`,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
export const WithLauncher: StoryComponentType = () => {
|
|
215
|
+
type MyModalProps = {|
|
|
216
|
+
closeModal: () => void,
|
|
217
|
+
|};
|
|
218
|
+
|
|
219
|
+
const MyModal = ({
|
|
220
|
+
closeModal,
|
|
221
|
+
}: MyModalProps): React.Element<typeof ModalDialog> => (
|
|
222
|
+
<ModalDialog
|
|
223
|
+
aria-labelledby="modal-title-3"
|
|
224
|
+
style={styles.squareDialog}
|
|
225
|
+
>
|
|
226
|
+
<ModalPanel
|
|
227
|
+
content={
|
|
228
|
+
<>
|
|
229
|
+
<Title id="modal-title-3">Modal Title</Title>
|
|
230
|
+
<Strut size={Spacing.large_24} />
|
|
231
|
+
<Body>Here is some text in the modal.</Body>
|
|
232
|
+
</>
|
|
233
|
+
}
|
|
234
|
+
/>
|
|
235
|
+
</ModalDialog>
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<ModalLauncher modal={MyModal}>
|
|
240
|
+
{({openModal}) => (
|
|
241
|
+
<Button onClick={openModal}>Click me to open the modal</Button>
|
|
242
|
+
)}
|
|
243
|
+
</ModalLauncher>
|
|
244
|
+
);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
WithLauncher.parameters = {
|
|
248
|
+
chromatic: {
|
|
249
|
+
// Don't take screenshots of this story since it would only show a
|
|
250
|
+
// button and not the actual modal.
|
|
251
|
+
disableSnapshot: true,
|
|
252
|
+
},
|
|
253
|
+
docs: {
|
|
254
|
+
storyDescription: `A modal can be launched using a launcher. Here,
|
|
255
|
+
the launcher is a \`<Button>\` element whose \`onClick\` function
|
|
256
|
+
opens the modal. The modal passed into the \`modal\` prop of
|
|
257
|
+
the \`<ModalLauncher>\` element is a \`<ModalDialog>\` element.
|
|
258
|
+
To turn an element into a launcher, wrap the element in a
|
|
259
|
+
\`<ModalLauncher>\` element.`,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const styles = StyleSheet.create({
|
|
264
|
+
example: {
|
|
265
|
+
alignItems: "center",
|
|
266
|
+
justifyContent: "center",
|
|
267
|
+
},
|
|
268
|
+
modalPositioner: {
|
|
269
|
+
// Checkerboard background
|
|
270
|
+
backgroundImage:
|
|
271
|
+
"linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(-45deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(-45deg, transparent 75%, #ccc 75%)",
|
|
272
|
+
backgroundSize: "20px 20px",
|
|
273
|
+
backgroundPosition: "0 0, 0 10px, 10px -10px, -10px 0px",
|
|
274
|
+
|
|
275
|
+
flexDirection: "row",
|
|
276
|
+
alignItems: "center",
|
|
277
|
+
justifyContent: "center",
|
|
278
|
+
|
|
279
|
+
position: "absolute",
|
|
280
|
+
left: 0,
|
|
281
|
+
right: 0,
|
|
282
|
+
top: 0,
|
|
283
|
+
bottom: 0,
|
|
284
|
+
},
|
|
285
|
+
previewSizer: {
|
|
286
|
+
minHeight: 600,
|
|
287
|
+
width: "100%",
|
|
288
|
+
},
|
|
289
|
+
row: {
|
|
290
|
+
flexDirection: "row",
|
|
291
|
+
justifyContent: "flex-end",
|
|
292
|
+
},
|
|
293
|
+
footer: {
|
|
294
|
+
alignItems: "center",
|
|
295
|
+
flexDirection: "row",
|
|
296
|
+
justifyContent: "space-between",
|
|
297
|
+
width: "100%",
|
|
298
|
+
},
|
|
299
|
+
squareDialog: {
|
|
300
|
+
maxHeight: 500,
|
|
301
|
+
maxWidth: 500,
|
|
302
|
+
backgroundColor: Color.darkBlue,
|
|
303
|
+
},
|
|
304
|
+
smallSquarePanel: {
|
|
305
|
+
maxHeight: 400,
|
|
306
|
+
maxWidth: 400,
|
|
307
|
+
},
|
|
308
|
+
});
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import {StyleSheet} from "aphrodite";
|
|
4
|
+
|
|
5
|
+
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
7
|
+
import {Strut} from "@khanacademy/wonder-blocks-layout";
|
|
8
|
+
import {
|
|
9
|
+
ModalDialog,
|
|
10
|
+
ModalPanel,
|
|
11
|
+
ModalFooter,
|
|
12
|
+
} from "@khanacademy/wonder-blocks-modal";
|
|
13
|
+
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
14
|
+
import {Body, LabelLarge, Title} from "@khanacademy/wonder-blocks-typography";
|
|
15
|
+
|
|
16
|
+
import type {StoryComponentType} from "@storybook/react";
|
|
17
|
+
|
|
18
|
+
import ComponentInfo from "../../../../../.storybook/components/component-info.js";
|
|
19
|
+
import {name, version} from "../../../package.json";
|
|
20
|
+
|
|
21
|
+
const customViewports = {
|
|
22
|
+
phone: {
|
|
23
|
+
name: "phone",
|
|
24
|
+
styles: {
|
|
25
|
+
width: "320px",
|
|
26
|
+
height: "568px",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
tablet: {
|
|
30
|
+
name: "tablet",
|
|
31
|
+
styles: {
|
|
32
|
+
width: "640px",
|
|
33
|
+
height: "960px",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
desktop: {
|
|
37
|
+
name: "desktop",
|
|
38
|
+
styles: {
|
|
39
|
+
width: "1024px",
|
|
40
|
+
height: "768px",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const longBody = (
|
|
46
|
+
<>
|
|
47
|
+
<Body>
|
|
48
|
+
{`Let's make this body content long in order
|
|
49
|
+
to test scroll overflow.`}
|
|
50
|
+
</Body>
|
|
51
|
+
<br />
|
|
52
|
+
<Body>
|
|
53
|
+
{`Lorem ipsum dolor sit amet, consectetur
|
|
54
|
+
adipiscing elit, sed do eiusmod tempor incididunt
|
|
55
|
+
ut labore et dolore magna aliqua. Ut enim ad minim
|
|
56
|
+
veniam, quis nostrud exercitation ullamco laboris
|
|
57
|
+
nisi ut aliquip ex ea commodo consequat. Duis aute
|
|
58
|
+
irure dolor in reprehenderit in voluptate velit
|
|
59
|
+
esse cillum dolore eu fugiat nulla pariatur.
|
|
60
|
+
Excepteur sint occaecat cupidatat non proident,
|
|
61
|
+
sunt in culpa qui officia deserunt mollit anim id
|
|
62
|
+
est.`}
|
|
63
|
+
</Body>
|
|
64
|
+
<br />
|
|
65
|
+
<Body>
|
|
66
|
+
{`Lorem ipsum dolor sit amet, consectetur
|
|
67
|
+
adipiscing elit, sed do eiusmod tempor incididunt
|
|
68
|
+
ut labore et dolore magna aliqua. Ut enim ad minim
|
|
69
|
+
veniam, quis nostrud exercitation ullamco laboris
|
|
70
|
+
nisi ut aliquip ex ea commodo consequat. Duis aute
|
|
71
|
+
irure dolor in reprehenderit in voluptate velit
|
|
72
|
+
esse cillum dolore eu fugiat nulla pariatur.
|
|
73
|
+
Excepteur sint occaecat cupidatat non proident,
|
|
74
|
+
sunt in culpa qui officia deserunt mollit anim id
|
|
75
|
+
est.`}
|
|
76
|
+
</Body>
|
|
77
|
+
<br />
|
|
78
|
+
<Body>
|
|
79
|
+
{`Lorem ipsum dolor sit amet, consectetur
|
|
80
|
+
adipiscing elit, sed do eiusmod tempor incididunt
|
|
81
|
+
ut labore et dolore magna aliqua. Ut enim ad minim
|
|
82
|
+
veniam, quis nostrud exercitation ullamco laboris
|
|
83
|
+
nisi ut aliquip ex ea commodo consequat. Duis aute
|
|
84
|
+
irure dolor in reprehenderit in voluptate velit
|
|
85
|
+
esse cillum dolore eu fugiat nulla pariatur.
|
|
86
|
+
Excepteur sint occaecat cupidatat non proident,
|
|
87
|
+
sunt in culpa qui officia deserunt mollit anim id
|
|
88
|
+
est.`}
|
|
89
|
+
</Body>
|
|
90
|
+
</>
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
export default {
|
|
94
|
+
title: "Modal/Building Blocks/ModalFooter",
|
|
95
|
+
component: ModalFooter,
|
|
96
|
+
decorators: [
|
|
97
|
+
(Story: StoryComponentType): React.Element<typeof View> => (
|
|
98
|
+
<View style={styles.previewSizer}>
|
|
99
|
+
<View style={styles.modalPositioner}>
|
|
100
|
+
<Story />
|
|
101
|
+
</View>
|
|
102
|
+
</View>
|
|
103
|
+
),
|
|
104
|
+
],
|
|
105
|
+
parameters: {
|
|
106
|
+
componentSubtitle: ((
|
|
107
|
+
<ComponentInfo name={name} version={version} />
|
|
108
|
+
): any),
|
|
109
|
+
docs: {
|
|
110
|
+
description: {
|
|
111
|
+
component: null,
|
|
112
|
+
},
|
|
113
|
+
source: {
|
|
114
|
+
// See https://github.com/storybookjs/storybook/issues/12596
|
|
115
|
+
excludeDecorators: true,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
viewport: {
|
|
119
|
+
viewports: customViewports,
|
|
120
|
+
defaultViewport: "desktop",
|
|
121
|
+
},
|
|
122
|
+
chromatic: {
|
|
123
|
+
viewports: [320, 640, 1024],
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
argTypes: {
|
|
127
|
+
children: {
|
|
128
|
+
control: {type: null},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const Default: StoryComponentType = (args) => (
|
|
134
|
+
<ModalDialog aria-labelledby={"modal-id-0"} style={styles.dialog}>
|
|
135
|
+
<ModalPanel
|
|
136
|
+
content={
|
|
137
|
+
<>
|
|
138
|
+
<Title id="modal-id-0">Modal Title</Title>
|
|
139
|
+
<Strut size={Spacing.large_24} />
|
|
140
|
+
{longBody}
|
|
141
|
+
</>
|
|
142
|
+
}
|
|
143
|
+
footer={<ModalFooter {...args} />}
|
|
144
|
+
/>
|
|
145
|
+
</ModalDialog>
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
export const Simple: StoryComponentType = () => (
|
|
149
|
+
<ModalDialog aria-labelledby={"modal-id-1"} style={styles.dialog}>
|
|
150
|
+
<ModalPanel
|
|
151
|
+
content={
|
|
152
|
+
<>
|
|
153
|
+
<Title id="modal-id-1">Modal Title</Title>
|
|
154
|
+
<Strut size={Spacing.large_24} />
|
|
155
|
+
{longBody}
|
|
156
|
+
</>
|
|
157
|
+
}
|
|
158
|
+
footer={
|
|
159
|
+
<ModalFooter>
|
|
160
|
+
<View />
|
|
161
|
+
</ModalFooter>
|
|
162
|
+
}
|
|
163
|
+
/>
|
|
164
|
+
</ModalDialog>
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
Simple.parameters = {
|
|
168
|
+
docs: {
|
|
169
|
+
storyDescription: `This is a basic footer. It contains an empty
|
|
170
|
+
\`<View>\`, so it is completely blank.`,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const WithButton: StoryComponentType = () => (
|
|
175
|
+
<ModalDialog aria-labelledby={"modal-id-2"} style={styles.dialog}>
|
|
176
|
+
<ModalPanel
|
|
177
|
+
content={
|
|
178
|
+
<>
|
|
179
|
+
<Title id="modal-id-2">Modal Title</Title>
|
|
180
|
+
<Strut size={Spacing.large_24} />
|
|
181
|
+
{longBody}
|
|
182
|
+
</>
|
|
183
|
+
}
|
|
184
|
+
footer={
|
|
185
|
+
<ModalFooter>
|
|
186
|
+
<Button onClick={() => {}}>Submit</Button>
|
|
187
|
+
</ModalFooter>
|
|
188
|
+
}
|
|
189
|
+
/>
|
|
190
|
+
</ModalDialog>
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
WithButton.parameters = {
|
|
194
|
+
docs: {
|
|
195
|
+
storyDescription: `This is a \`<ModalFooter>\` with a \`<Button>\`
|
|
196
|
+
as a child. No additional styling is needed, as the footer
|
|
197
|
+
already has the style \`{justifyContent: "flex-end"}\`.`,
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export const WithThreeActions: StoryComponentType = () => {
|
|
202
|
+
const mobile = "@media (max-width: 1023px)";
|
|
203
|
+
const desktop = "@media (min-width: 1024px)";
|
|
204
|
+
|
|
205
|
+
const buttonStyle = {
|
|
206
|
+
[desktop]: {
|
|
207
|
+
marginRight: Spacing.medium_16,
|
|
208
|
+
},
|
|
209
|
+
[mobile]: {
|
|
210
|
+
marginBottom: Spacing.medium_16,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const containerStyle = {
|
|
215
|
+
[desktop]: {
|
|
216
|
+
flexDirection: "row",
|
|
217
|
+
justifyContent: "flex-end",
|
|
218
|
+
},
|
|
219
|
+
[mobile]: {
|
|
220
|
+
flexDirection: "column-reverse",
|
|
221
|
+
width: "100%",
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<ModalDialog aria-labelledby={"modal-id-3"} style={styles.dialog}>
|
|
227
|
+
<ModalPanel
|
|
228
|
+
content={
|
|
229
|
+
<>
|
|
230
|
+
<Title id="modal-id-3">Modal Title</Title>
|
|
231
|
+
<Strut size={Spacing.large_24} />
|
|
232
|
+
{longBody}
|
|
233
|
+
</>
|
|
234
|
+
}
|
|
235
|
+
footer={
|
|
236
|
+
<ModalFooter>
|
|
237
|
+
<View style={containerStyle}>
|
|
238
|
+
<Button style={buttonStyle} kind="tertiary">
|
|
239
|
+
Tertiary action
|
|
240
|
+
</Button>
|
|
241
|
+
<Button style={buttonStyle} kind="tertiary">
|
|
242
|
+
Secondary action
|
|
243
|
+
</Button>
|
|
244
|
+
<Button style={buttonStyle}>Primary action</Button>
|
|
245
|
+
</View>
|
|
246
|
+
</ModalFooter>
|
|
247
|
+
}
|
|
248
|
+
/>
|
|
249
|
+
</ModalDialog>
|
|
250
|
+
);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
WithThreeActions.parameters = {
|
|
254
|
+
docs: {
|
|
255
|
+
storyDescription: `This is an example of a footer with multiple
|
|
256
|
+
actions. It's fully responsive, so the buttons are in a
|
|
257
|
+
column layout when the window is small.`,
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
export const WithMultipleActions: StoryComponentType = () => {
|
|
262
|
+
const footerStyle = {
|
|
263
|
+
alignItems: "center",
|
|
264
|
+
flexDirection: "row",
|
|
265
|
+
justifyContent: "space-between",
|
|
266
|
+
width: "100%",
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const rowStyle = {
|
|
270
|
+
flexDirection: "row",
|
|
271
|
+
justifyContent: "flex-end",
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
<ModalDialog aria-labelledby={"modal-id-4"} style={styles.dialog}>
|
|
276
|
+
<ModalPanel
|
|
277
|
+
content={
|
|
278
|
+
<>
|
|
279
|
+
<Title id="modal-id-4">Modal Title</Title>
|
|
280
|
+
<Strut size={Spacing.large_24} />
|
|
281
|
+
{longBody}
|
|
282
|
+
</>
|
|
283
|
+
}
|
|
284
|
+
footer={
|
|
285
|
+
<ModalFooter>
|
|
286
|
+
<View style={footerStyle}>
|
|
287
|
+
<LabelLarge>Step 1 of 4</LabelLarge>
|
|
288
|
+
<View style={rowStyle}>
|
|
289
|
+
<Button kind="tertiary">Previous</Button>
|
|
290
|
+
<Strut size={16} />
|
|
291
|
+
<Button kind="primary">Next</Button>
|
|
292
|
+
</View>
|
|
293
|
+
</View>
|
|
294
|
+
</ModalFooter>
|
|
295
|
+
}
|
|
296
|
+
/>
|
|
297
|
+
</ModalDialog>
|
|
298
|
+
);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
WithMultipleActions.parameters = {
|
|
302
|
+
docs: {
|
|
303
|
+
storyDescription: `This is an example of a footer that indicates
|
|
304
|
+
multiple steps in a flow.`,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const styles = StyleSheet.create({
|
|
309
|
+
dialog: {
|
|
310
|
+
maxWidth: 600,
|
|
311
|
+
maxHeight: 500,
|
|
312
|
+
},
|
|
313
|
+
modalPositioner: {
|
|
314
|
+
// Checkerboard background
|
|
315
|
+
backgroundImage:
|
|
316
|
+
"linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(-45deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(-45deg, transparent 75%, #ccc 75%)",
|
|
317
|
+
backgroundSize: "20px 20px",
|
|
318
|
+
backgroundPosition: "0 0, 0 10px, 10px -10px, -10px 0px",
|
|
319
|
+
|
|
320
|
+
flexDirection: "row",
|
|
321
|
+
alignItems: "center",
|
|
322
|
+
justifyContent: "center",
|
|
323
|
+
|
|
324
|
+
position: "absolute",
|
|
325
|
+
left: 0,
|
|
326
|
+
right: 0,
|
|
327
|
+
top: 0,
|
|
328
|
+
bottom: 0,
|
|
329
|
+
},
|
|
330
|
+
previewSizer: {
|
|
331
|
+
height: 600,
|
|
332
|
+
},
|
|
333
|
+
example: {
|
|
334
|
+
alignItems: "center",
|
|
335
|
+
justifyContent: "center",
|
|
336
|
+
},
|
|
337
|
+
});
|