@ceed/cds 1.22.0 → 1.22.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.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
Typography
|
|
5
|
+
The Typography component is a core component for displaying text. It is based on Joy UI Typography and provides a variety of text levels and styles. You can apply consistent typography across all text elements such as headings, body text, and labels.
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
8
|
<Typography children="Typography" />
|
|
@@ -16,15 +16,15 @@ Typography 컴포넌트는 텍스트를 표시하기 위한 핵심 컴포넌트
|
|
|
16
16
|
## Usage
|
|
17
17
|
|
|
18
18
|
```tsx
|
|
19
|
-
import { Typography } from '@ceed/
|
|
19
|
+
import { Typography } from '@ceed/ads';
|
|
20
20
|
|
|
21
21
|
function MyComponent() {
|
|
22
22
|
return (
|
|
23
23
|
<div>
|
|
24
|
-
<Typography level="h1"
|
|
25
|
-
<Typography level="body-md"
|
|
24
|
+
<Typography level="h1">Main Heading</Typography>
|
|
25
|
+
<Typography level="body-md">This is body text.</Typography>
|
|
26
26
|
<Typography level="body-sm" color="neutral">
|
|
27
|
-
|
|
27
|
+
This is supporting description text.
|
|
28
28
|
</Typography>
|
|
29
29
|
</div>
|
|
30
30
|
);
|
|
@@ -35,18 +35,18 @@ function MyComponent() {
|
|
|
35
35
|
|
|
36
36
|
### Headings
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
Levels for headings. Use them to clearly define page structure.
|
|
39
39
|
|
|
40
40
|
```tsx
|
|
41
|
-
<Typography level="h1">H1 -
|
|
42
|
-
<Typography level="h2">H2 -
|
|
43
|
-
<Typography level="h3">H3 -
|
|
44
|
-
<Typography level="h4">H4 -
|
|
41
|
+
<Typography level="h1">H1 - Main page heading</Typography>
|
|
42
|
+
<Typography level="h2">H2 - Section heading</Typography>
|
|
43
|
+
<Typography level="h3">H3 - Subsection heading</Typography>
|
|
44
|
+
<Typography level="h4">H4 - Detailed heading</Typography>
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
### Titles
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Used for important titles or emphasized text.
|
|
50
50
|
|
|
51
51
|
```tsx
|
|
52
52
|
<Typography level="title-lg">Large Title</Typography>
|
|
@@ -56,13 +56,13 @@ function MyComponent() {
|
|
|
56
56
|
|
|
57
57
|
### Body Text
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Levels for body text. Use these for most readable content.
|
|
60
60
|
|
|
61
61
|
```tsx
|
|
62
|
-
<Typography level="body-lg"
|
|
63
|
-
<Typography level="body-md"
|
|
64
|
-
<Typography level="body-sm"
|
|
65
|
-
<Typography level="body-xs"
|
|
62
|
+
<Typography level="body-lg">Large body text</Typography>
|
|
63
|
+
<Typography level="body-md">Regular body text</Typography>
|
|
64
|
+
<Typography level="body-sm">Small body text</Typography>
|
|
65
|
+
<Typography level="body-xs">Extra small text</Typography>
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
## Common Use Cases
|
|
@@ -74,22 +74,22 @@ function ArticlePage() {
|
|
|
74
74
|
return (
|
|
75
75
|
<article>
|
|
76
76
|
<Typography level="h1" sx={{ mb: 2 }}>
|
|
77
|
-
|
|
77
|
+
Article Title
|
|
78
78
|
</Typography>
|
|
79
79
|
|
|
80
80
|
<Typography level="body-sm" color="neutral" sx={{ mb: 3 }}>
|
|
81
|
-
|
|
81
|
+
January 15, 2024 · Written by John Doe
|
|
82
82
|
</Typography>
|
|
83
83
|
|
|
84
84
|
<Typography level="body-md" sx={{ mb: 2 }}>
|
|
85
|
-
|
|
85
|
+
The main content of the article goes here. This text uses a readable size and line spacing.
|
|
86
86
|
</Typography>
|
|
87
87
|
|
|
88
88
|
<Typography level="h2" sx={{ mt: 4, mb: 2 }}>
|
|
89
|
-
|
|
89
|
+
Section Title
|
|
90
90
|
</Typography>
|
|
91
91
|
|
|
92
|
-
<Typography level="body-md"
|
|
92
|
+
<Typography level="body-md">The section content continues here.</Typography>
|
|
93
93
|
</article>
|
|
94
94
|
);
|
|
95
95
|
}
|
|
@@ -101,15 +101,15 @@ function ArticlePage() {
|
|
|
101
101
|
<Card>
|
|
102
102
|
<CardContent>
|
|
103
103
|
<Typography level="title-md" sx={{ mb: 1 }}>
|
|
104
|
-
|
|
104
|
+
Product Name
|
|
105
105
|
</Typography>
|
|
106
106
|
|
|
107
107
|
<Typography level="body-sm" color="neutral" sx={{ mb: 2 }}>
|
|
108
|
-
|
|
108
|
+
Category: Electronics
|
|
109
109
|
</Typography>
|
|
110
110
|
|
|
111
111
|
<Typography level="body-md" sx={{ mb: 2 }}>
|
|
112
|
-
|
|
112
|
+
A detailed description of the product goes here.
|
|
113
113
|
</Typography>
|
|
114
114
|
|
|
115
115
|
<Typography level="title-lg" color="primary">
|
|
@@ -125,21 +125,21 @@ function ArticlePage() {
|
|
|
125
125
|
<Stack spacing={2}>
|
|
126
126
|
<FormControl>
|
|
127
127
|
<Typography level="title-sm" component="label">
|
|
128
|
-
|
|
128
|
+
Username
|
|
129
129
|
</Typography>
|
|
130
|
-
<Input placeholder="
|
|
130
|
+
<Input placeholder="Enter your name" />
|
|
131
131
|
<Typography level="body-xs" color="neutral">
|
|
132
|
-
|
|
132
|
+
Please enter your real name.
|
|
133
133
|
</Typography>
|
|
134
134
|
</FormControl>
|
|
135
135
|
|
|
136
136
|
<FormControl error>
|
|
137
137
|
<Typography level="title-sm" component="label">
|
|
138
|
-
|
|
138
|
+
Email Address
|
|
139
139
|
</Typography>
|
|
140
140
|
<Input placeholder="email@example.com" />
|
|
141
141
|
<Typography level="body-xs" color="danger">
|
|
142
|
-
|
|
142
|
+
The email format is invalid.
|
|
143
143
|
</Typography>
|
|
144
144
|
</FormControl>
|
|
145
145
|
</Stack>
|
|
@@ -150,16 +150,16 @@ function ArticlePage() {
|
|
|
150
150
|
```tsx
|
|
151
151
|
<Stack spacing={2}>
|
|
152
152
|
<Box>
|
|
153
|
-
<Typography level="body-md"
|
|
153
|
+
<Typography level="body-md">Server Status:</Typography>
|
|
154
154
|
<Typography level="body-md" color="success">
|
|
155
|
-
|
|
155
|
+
Operating Normally
|
|
156
156
|
</Typography>
|
|
157
157
|
</Box>
|
|
158
158
|
|
|
159
159
|
<Box>
|
|
160
|
-
<Typography level="body-md"
|
|
160
|
+
<Typography level="body-md">Last Updated:</Typography>
|
|
161
161
|
<Typography level="body-sm" color="neutral">
|
|
162
|
-
2
|
|
162
|
+
2 minutes ago
|
|
163
163
|
</Typography>
|
|
164
164
|
</Box>
|
|
165
165
|
</Stack>
|
|
@@ -169,7 +169,7 @@ function ArticlePage() {
|
|
|
169
169
|
|
|
170
170
|
```tsx
|
|
171
171
|
<Stack spacing={1}>
|
|
172
|
-
<Typography level="title-md"
|
|
172
|
+
<Typography level="title-md">Todo List</Typography>
|
|
173
173
|
|
|
174
174
|
{todoItems.map((item) => (
|
|
175
175
|
<Box key={item.id} sx={{ pl: 2 }}>
|
|
@@ -192,39 +192,39 @@ function ArticlePage() {
|
|
|
192
192
|
|
|
193
193
|
## Colors
|
|
194
194
|
|
|
195
|
-
Typography
|
|
195
|
+
Typography supports various colors:
|
|
196
196
|
|
|
197
197
|
```tsx
|
|
198
198
|
<Stack spacing={1}>
|
|
199
|
-
<Typography color="primary">Primary
|
|
200
|
-
<Typography color="neutral">Neutral
|
|
201
|
-
<Typography color="danger">Danger
|
|
202
|
-
<Typography color="success">Success
|
|
203
|
-
<Typography color="warning">Warning
|
|
199
|
+
<Typography color="primary">Primary color</Typography>
|
|
200
|
+
<Typography color="neutral">Neutral color</Typography>
|
|
201
|
+
<Typography color="danger">Danger color</Typography>
|
|
202
|
+
<Typography color="success">Success color</Typography>
|
|
203
|
+
<Typography color="warning">Warning color</Typography>
|
|
204
204
|
</Stack>
|
|
205
205
|
```
|
|
206
206
|
|
|
207
207
|
## Component Prop
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
You can render it as a different HTML element or React component:
|
|
210
210
|
|
|
211
211
|
```tsx
|
|
212
212
|
<Typography level="h1" component="h2">
|
|
213
|
-
|
|
213
|
+
h1 style rendered as an h2 tag
|
|
214
214
|
</Typography>
|
|
215
215
|
|
|
216
216
|
<Typography level="body-md" component="span">
|
|
217
|
-
|
|
217
|
+
Inline text
|
|
218
218
|
</Typography>
|
|
219
219
|
|
|
220
220
|
<Typography level="title-md" component={Link} href="/page">
|
|
221
|
-
|
|
221
|
+
Rendered as a Link component
|
|
222
222
|
</Typography>
|
|
223
223
|
```
|
|
224
224
|
|
|
225
225
|
## Responsive Typography
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
You can use responsive levels:
|
|
228
228
|
|
|
229
229
|
```tsx
|
|
230
230
|
<Typography
|
|
@@ -233,36 +233,36 @@ Typography는 다양한 색상을 지원합니다:
|
|
|
233
233
|
fontSize: { xs: '1.5rem', sm: '2rem', md: '2.5rem' },
|
|
234
234
|
}}
|
|
235
235
|
>
|
|
236
|
-
|
|
236
|
+
Responsive Heading
|
|
237
237
|
</Typography>
|
|
238
238
|
```
|
|
239
239
|
|
|
240
240
|
## Best Practices
|
|
241
241
|
|
|
242
|
-
1.
|
|
242
|
+
1. **Semantic Structure**: Use heading levels in order to create a clear document structure.
|
|
243
243
|
|
|
244
244
|
```tsx
|
|
245
|
-
// ✅
|
|
246
|
-
<Typography level="h1"
|
|
247
|
-
<Typography level="h2"
|
|
248
|
-
<Typography level="h3"
|
|
249
|
-
|
|
250
|
-
// ❌
|
|
251
|
-
<Typography level="h1"
|
|
252
|
-
<Typography level="h3"
|
|
245
|
+
// ✅ Correct order
|
|
246
|
+
<Typography level="h1">Main heading</Typography>
|
|
247
|
+
<Typography level="h2">Section heading</Typography>
|
|
248
|
+
<Typography level="h3">Subsection</Typography>
|
|
249
|
+
|
|
250
|
+
// ❌ Incorrect order
|
|
251
|
+
<Typography level="h1">Main heading</Typography>
|
|
252
|
+
<Typography level="h3">Section heading</Typography>
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
-
2.
|
|
255
|
+
2. **Consistency**: Use the same level for text serving the same purpose.
|
|
256
256
|
|
|
257
|
-
3.
|
|
257
|
+
3. **Readability**: Provide proper line spacing and paragraph separation for body text.
|
|
258
258
|
|
|
259
|
-
4.
|
|
259
|
+
4. **Color Contrast**: Maintain sufficient color contrast to ensure accessibility.
|
|
260
260
|
|
|
261
261
|
## Accessibility
|
|
262
262
|
|
|
263
|
-
-
|
|
264
|
-
-
|
|
265
|
-
-
|
|
266
|
-
-
|
|
263
|
+
- Use appropriate semantic HTML tags
|
|
264
|
+
- Support screen readers
|
|
265
|
+
- Ensure keyboard navigation (when used as a link or button)
|
|
266
|
+
- Maintain sufficient color contrast
|
|
267
267
|
|
|
268
|
-
Typography
|
|
268
|
+
Typography plays a key role in effectively conveying information and creating visual hierarchy in user interfaces. By choosing appropriate levels and styles, you can create content that is easy to read and accessible.
|
|
@@ -4,8 +4,25 @@
|
|
|
4
4
|
|
|
5
5
|
The Modal component is a dialog overlay that appears on top of the main content, demanding user attention and interaction. Built on Joy UI's Modal, it is used for displaying critical information, capturing user input, or requiring confirmation before proceeding. Modals block interaction with the underlying page until dismissed, making them ideal for important actions that require focused attention.
|
|
6
6
|
|
|
7
|
-
```
|
|
8
|
-
|
|
7
|
+
```tsx
|
|
8
|
+
<>
|
|
9
|
+
<Button onClick={() => setOpen(true)}>Open Modal</Button>
|
|
10
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
11
|
+
<ModalDialog>
|
|
12
|
+
<ModalClose />
|
|
13
|
+
<DialogTitle>Modal Title</DialogTitle>
|
|
14
|
+
<DialogContent>This is the modal content. You can place any content here.</DialogContent>
|
|
15
|
+
<DialogActions>
|
|
16
|
+
<Button variant="solid" onClick={() => setOpen(false)}>
|
|
17
|
+
Confirm
|
|
18
|
+
</Button>
|
|
19
|
+
<Button variant="plain" color="neutral" onClick={() => setOpen(false)}>
|
|
20
|
+
Cancel
|
|
21
|
+
</Button>
|
|
22
|
+
</DialogActions>
|
|
23
|
+
</ModalDialog>
|
|
24
|
+
</Modal>
|
|
25
|
+
</>
|
|
9
26
|
```
|
|
10
27
|
|
|
11
28
|
| Field | Description | Default |
|
|
@@ -24,15 +41,7 @@ The Modal component is a dialog overlay that appears on top of the main content,
|
|
|
24
41
|
## Usage
|
|
25
42
|
|
|
26
43
|
```tsx
|
|
27
|
-
import {
|
|
28
|
-
Modal,
|
|
29
|
-
ModalDialog,
|
|
30
|
-
ModalClose,
|
|
31
|
-
DialogTitle,
|
|
32
|
-
DialogContent,
|
|
33
|
-
DialogActions,
|
|
34
|
-
Button,
|
|
35
|
-
} from '@ceed/cds';
|
|
44
|
+
import { Modal, ModalDialog, ModalClose, DialogTitle, DialogContent, DialogActions, Button } from '@ceed/cds';
|
|
36
45
|
|
|
37
46
|
function MyComponent() {
|
|
38
47
|
const [open, setOpen] = useState(false);
|
|
@@ -44,9 +53,7 @@ function MyComponent() {
|
|
|
44
53
|
<ModalDialog>
|
|
45
54
|
<ModalClose />
|
|
46
55
|
<DialogTitle>Modal Title</DialogTitle>
|
|
47
|
-
<DialogContent>
|
|
48
|
-
Place your content here.
|
|
49
|
-
</DialogContent>
|
|
56
|
+
<DialogContent>Place your content here.</DialogContent>
|
|
50
57
|
<DialogActions>
|
|
51
58
|
<Button onClick={() => setOpen(false)}>Close</Button>
|
|
52
59
|
</DialogActions>
|
|
@@ -57,6 +64,28 @@ function MyComponent() {
|
|
|
57
64
|
}
|
|
58
65
|
```
|
|
59
66
|
|
|
67
|
+
### ModalFrame Usage
|
|
68
|
+
|
|
69
|
+
`ModalFrame` is a convenience component that combines `ModalDialog` + `ModalClose` + `DialogTitle` + `DialogContent` into a single composable unit.
|
|
70
|
+
It provides a concise way to build modals with a title, close button, and content area.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { Modal, ModalFrame } from '@ceed/cds';
|
|
74
|
+
|
|
75
|
+
function DetailModal({ open, onClose }) {
|
|
76
|
+
return (
|
|
77
|
+
<Modal open={open} onClose={onClose}>
|
|
78
|
+
<ModalFrame title="Detail" onClose={onClose}>
|
|
79
|
+
Content goes here.
|
|
80
|
+
</ModalFrame>
|
|
81
|
+
</Modal>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> **Note**: Connect the same handler to both `Modal`'s `onClose` and `ModalFrame`'s `onClose`.
|
|
87
|
+
> `Modal` handles backdrop click and ESC key, while `ModalFrame` handles the X button click.
|
|
88
|
+
|
|
60
89
|
## Examples
|
|
61
90
|
|
|
62
91
|
### Basic Modal
|
|
@@ -64,29 +93,32 @@ function MyComponent() {
|
|
|
64
93
|
The basic modal with a simple Sheet for custom layouts.
|
|
65
94
|
|
|
66
95
|
```tsx
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
</
|
|
96
|
+
<>
|
|
97
|
+
<Button onClick={() => setOpen(true)}>Open Basic Modal</Button>
|
|
98
|
+
<Modal aria-labelledby="modal-title" aria-describedby="modal-desc" open={open} onClose={() => setOpen(false)} sx={{
|
|
99
|
+
display: 'flex',
|
|
100
|
+
justifyContent: 'center',
|
|
101
|
+
alignItems: 'center'
|
|
102
|
+
}}>
|
|
103
|
+
<Sheet variant="outlined" sx={{
|
|
104
|
+
maxWidth: 500,
|
|
105
|
+
borderRadius: 'md',
|
|
106
|
+
p: 3,
|
|
107
|
+
boxShadow: 'lg'
|
|
108
|
+
}}>
|
|
109
|
+
<ModalClose variant="plain" sx={{
|
|
110
|
+
m: 1
|
|
111
|
+
}} />
|
|
112
|
+
<Typography component="h2" id="modal-title" level="h4" textColor="inherit" fontWeight="lg" mb={2}>
|
|
113
|
+
This is the modal title
|
|
114
|
+
</Typography>
|
|
115
|
+
<Typography id="modal-desc" textColor="text.tertiary">
|
|
116
|
+
Make sure to use <code>aria-labelledby</code> on the modal dialog with an optional{' '}
|
|
117
|
+
<code>aria-describedby</code> attribute.
|
|
118
|
+
</Typography>
|
|
88
119
|
</Sheet>
|
|
89
120
|
</Modal>
|
|
121
|
+
</>
|
|
90
122
|
```
|
|
91
123
|
|
|
92
124
|
### Modal Dialog
|
|
@@ -94,29 +126,34 @@ The basic modal with a simple Sheet for custom layouts.
|
|
|
94
126
|
Use ModalDialog for structured dialogs with title, content, and actions.
|
|
95
127
|
|
|
96
128
|
```tsx
|
|
97
|
-
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
</
|
|
129
|
+
<>
|
|
130
|
+
<Button onClick={() => setOpen(true)}>Open Form Modal</Button>
|
|
131
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
132
|
+
<ModalDialog>
|
|
133
|
+
<ModalClose />
|
|
134
|
+
<DialogTitle>Create new project</DialogTitle>
|
|
135
|
+
<DialogContent>
|
|
136
|
+
Fill in the information of the project.
|
|
137
|
+
<form onSubmit={(event: React.FormEvent<HTMLFormElement>) => {
|
|
138
|
+
event.preventDefault();
|
|
139
|
+
setOpen(false);
|
|
140
|
+
}}>
|
|
141
|
+
<Stack spacing={4}>
|
|
142
|
+
<FormControl>
|
|
143
|
+
<FormLabel>Name</FormLabel>
|
|
144
|
+
<Input required />
|
|
145
|
+
</FormControl>
|
|
146
|
+
<FormControl>
|
|
147
|
+
<FormLabel>Description</FormLabel>
|
|
148
|
+
<Input required />
|
|
149
|
+
</FormControl>
|
|
150
|
+
<Button type="submit">Submit</Button>
|
|
151
|
+
</Stack>
|
|
152
|
+
</form>
|
|
153
|
+
</DialogContent>
|
|
154
|
+
</ModalDialog>
|
|
119
155
|
</Modal>
|
|
156
|
+
</>
|
|
120
157
|
```
|
|
121
158
|
|
|
122
159
|
### Variants
|
|
@@ -126,49 +163,61 @@ Modal dialogs support different visual variants.
|
|
|
126
163
|
#### Plain Variant
|
|
127
164
|
|
|
128
165
|
```tsx
|
|
129
|
-
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
166
|
+
<>
|
|
167
|
+
<Button onClick={() => setOpen(true)}>Plain Variant</Button>
|
|
168
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
169
|
+
<ModalDialog variant="plain">
|
|
170
|
+
<ModalClose />
|
|
171
|
+
<DialogTitle>Modal Dialog</DialogTitle>
|
|
172
|
+
<DialogContent>This is a `plain` modal dialog.</DialogContent>
|
|
173
|
+
</ModalDialog>
|
|
174
|
+
</Modal>
|
|
175
|
+
</>
|
|
136
176
|
```
|
|
137
177
|
|
|
138
178
|
#### Outlined Variant
|
|
139
179
|
|
|
140
180
|
```tsx
|
|
141
|
-
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
181
|
+
<>
|
|
182
|
+
<Button onClick={() => setOpen(true)}>Outlined Variant</Button>
|
|
183
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
184
|
+
<ModalDialog variant="outlined">
|
|
185
|
+
<ModalClose />
|
|
186
|
+
<DialogTitle>Modal Dialog</DialogTitle>
|
|
187
|
+
<DialogContent>This is an `outlined` modal dialog.</DialogContent>
|
|
188
|
+
</ModalDialog>
|
|
189
|
+
</Modal>
|
|
190
|
+
</>
|
|
148
191
|
```
|
|
149
192
|
|
|
150
193
|
#### Soft Variant
|
|
151
194
|
|
|
152
195
|
```tsx
|
|
153
|
-
|
|
154
|
-
<
|
|
155
|
-
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
196
|
+
<>
|
|
197
|
+
<Button onClick={() => setOpen(true)}>Soft Variant</Button>
|
|
198
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
199
|
+
<ModalDialog variant="soft">
|
|
200
|
+
<ModalClose />
|
|
201
|
+
<DialogTitle>Modal Dialog</DialogTitle>
|
|
202
|
+
<DialogContent>This is a `soft` modal dialog.</DialogContent>
|
|
203
|
+
</ModalDialog>
|
|
204
|
+
</Modal>
|
|
205
|
+
</>
|
|
160
206
|
```
|
|
161
207
|
|
|
162
208
|
#### Solid Variant
|
|
163
209
|
|
|
164
210
|
```tsx
|
|
165
|
-
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
211
|
+
<>
|
|
212
|
+
<Button onClick={() => setOpen(true)}>Solid Variant</Button>
|
|
213
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
214
|
+
<ModalDialog variant="solid">
|
|
215
|
+
<ModalClose />
|
|
216
|
+
<DialogTitle>Modal Dialog</DialogTitle>
|
|
217
|
+
<DialogContent>This is a `solid` modal dialog.</DialogContent>
|
|
218
|
+
</ModalDialog>
|
|
219
|
+
</Modal>
|
|
220
|
+
</>
|
|
172
221
|
```
|
|
173
222
|
|
|
174
223
|
### Alert Dialog
|
|
@@ -176,24 +225,29 @@ Modal dialogs support different visual variants.
|
|
|
176
225
|
For critical confirmations that require explicit user decision.
|
|
177
226
|
|
|
178
227
|
```tsx
|
|
179
|
-
|
|
180
|
-
<
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
228
|
+
<>
|
|
229
|
+
<Button color="danger" onClick={() => setOpen(true)}>
|
|
230
|
+
Delete Item
|
|
231
|
+
</Button>
|
|
232
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
233
|
+
<ModalDialog variant="outlined" role="alertdialog">
|
|
234
|
+
<DialogTitle>
|
|
235
|
+
<WarningRoundedIcon />
|
|
236
|
+
Confirmation
|
|
237
|
+
</DialogTitle>
|
|
238
|
+
<Divider />
|
|
239
|
+
<DialogContent>Are you sure you want to discard all of your notes?</DialogContent>
|
|
240
|
+
<DialogActions>
|
|
241
|
+
<Button variant="solid" color="danger" onClick={() => setOpen(false)}>
|
|
242
|
+
Discard notes
|
|
243
|
+
</Button>
|
|
244
|
+
<Button variant="plain" color="neutral" onClick={() => setOpen(false)}>
|
|
245
|
+
Cancel
|
|
246
|
+
</Button>
|
|
247
|
+
</DialogActions>
|
|
248
|
+
</ModalDialog>
|
|
249
|
+
</Modal>
|
|
250
|
+
</>
|
|
197
251
|
```
|
|
198
252
|
|
|
199
253
|
### Layouts
|
|
@@ -202,16 +256,207 @@ For critical confirmations that require explicit user decision.
|
|
|
202
256
|
|
|
203
257
|
For complex content that requires maximum screen space.
|
|
204
258
|
|
|
205
|
-
```
|
|
206
|
-
|
|
259
|
+
```tsx
|
|
260
|
+
<>
|
|
261
|
+
<Button onClick={() => setOpen(true)}>Open Fullscreen Modal</Button>
|
|
262
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
263
|
+
<ModalDialog layout="fullscreen">
|
|
264
|
+
<ModalClose />
|
|
265
|
+
<DialogTitle>Fullscreen Modal</DialogTitle>
|
|
266
|
+
<DialogContent>This modal takes up the entire screen.</DialogContent>
|
|
267
|
+
<DialogActions>
|
|
268
|
+
<Button variant="solid" onClick={() => setOpen(false)}>
|
|
269
|
+
Save
|
|
270
|
+
</Button>
|
|
271
|
+
</DialogActions>
|
|
272
|
+
</ModalDialog>
|
|
273
|
+
</Modal>
|
|
274
|
+
</>
|
|
207
275
|
```
|
|
208
276
|
|
|
209
277
|
### Nested Modals
|
|
210
278
|
|
|
211
279
|
Modals can be stacked on top of each other when necessary.
|
|
212
280
|
|
|
281
|
+
```tsx
|
|
282
|
+
<>
|
|
283
|
+
<Button onClick={() => setFirstOpen(true)}>Open First Modal</Button>
|
|
284
|
+
<Modal open={firstOpen} onClose={() => setFirstOpen(false)}>
|
|
285
|
+
<ModalDialog>
|
|
286
|
+
<ModalClose />
|
|
287
|
+
<DialogTitle>First Modal</DialogTitle>
|
|
288
|
+
<DialogContent>This is the first modal. Click the button below to open a nested modal.</DialogContent>
|
|
289
|
+
<DialogActions>
|
|
290
|
+
<Button onClick={() => setSecondOpen(true)}>Open Nested Modal</Button>
|
|
291
|
+
</DialogActions>
|
|
292
|
+
</ModalDialog>
|
|
293
|
+
</Modal>
|
|
294
|
+
<Modal open={secondOpen} onClose={() => setSecondOpen(false)}>
|
|
295
|
+
<ModalDialog>
|
|
296
|
+
<ModalClose />
|
|
297
|
+
<DialogTitle>Nested Modal</DialogTitle>
|
|
298
|
+
<DialogContent>This is a nested modal on top of the first one.</DialogContent>
|
|
299
|
+
<DialogActions>
|
|
300
|
+
<Button onClick={() => setSecondOpen(false)}>Close</Button>
|
|
301
|
+
</DialogActions>
|
|
302
|
+
</ModalDialog>
|
|
303
|
+
</Modal>
|
|
304
|
+
</>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### ModalFrame
|
|
308
|
+
|
|
309
|
+
ModalFrame is a convenience component that automatically provides a title, close button, and content area.
|
|
310
|
+
|
|
311
|
+
#### ModalFrame Playground
|
|
312
|
+
|
|
313
|
+
```tsx
|
|
314
|
+
<>
|
|
315
|
+
<Button onClick={() => setOpen(true)}>Open ModalFrame</Button>
|
|
316
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
317
|
+
<ModalFrame title="ModalFrame Title" onClose={() => setOpen(false)}>
|
|
318
|
+
<Typography>
|
|
319
|
+
ModalFrame automatically composes ModalDialog, ModalClose, DialogTitle, and DialogContent. You only need
|
|
320
|
+
to provide a title, onClose handler, and children.
|
|
321
|
+
</Typography>
|
|
322
|
+
</ModalFrame>
|
|
323
|
+
</Modal>
|
|
324
|
+
</>
|
|
213
325
|
```
|
|
214
|
-
|
|
326
|
+
|
|
327
|
+
#### titleStartDecorator
|
|
328
|
+
|
|
329
|
+
Display an icon or decorative element before the title.
|
|
330
|
+
|
|
331
|
+
```tsx
|
|
332
|
+
<>
|
|
333
|
+
<Button onClick={() => setOpen(true)}>With Decorator</Button>
|
|
334
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
335
|
+
<ModalFrame title="Details" titleStartDecorator={<InfoOutlinedIcon />} onClose={() => setOpen(false)}>
|
|
336
|
+
<Typography>
|
|
337
|
+
Use the <code>titleStartDecorator</code> prop to display an icon or element before the title.
|
|
338
|
+
</Typography>
|
|
339
|
+
</ModalFrame>
|
|
340
|
+
</Modal>
|
|
341
|
+
</>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
#### Form Content
|
|
345
|
+
|
|
346
|
+
An inline form pattern where the submit button lives inside the content area.
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
<>
|
|
350
|
+
<Button onClick={() => setOpen(true)}>Form in ModalFrame</Button>
|
|
351
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
352
|
+
<ModalFrame title="Create Project" onClose={() => setOpen(false)}>
|
|
353
|
+
<form onSubmit={(event: React.FormEvent<HTMLFormElement>) => {
|
|
354
|
+
event.preventDefault();
|
|
355
|
+
setOpen(false);
|
|
356
|
+
}}>
|
|
357
|
+
<Stack spacing={2}>
|
|
358
|
+
<FormControl>
|
|
359
|
+
<FormLabel>Name</FormLabel>
|
|
360
|
+
<Input required />
|
|
361
|
+
</FormControl>
|
|
362
|
+
<FormControl>
|
|
363
|
+
<FormLabel>Description</FormLabel>
|
|
364
|
+
<Input required />
|
|
365
|
+
</FormControl>
|
|
366
|
+
<Button type="submit">Submit</Button>
|
|
367
|
+
</Stack>
|
|
368
|
+
</form>
|
|
369
|
+
</ModalFrame>
|
|
370
|
+
</Modal>
|
|
371
|
+
</>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### Sizes
|
|
375
|
+
|
|
376
|
+
Compare sm / md / lg sizes side by side.
|
|
377
|
+
|
|
378
|
+
```tsx
|
|
379
|
+
<Stack direction="row" spacing={2}>
|
|
380
|
+
<Button size="sm" onClick={() => setOpenSm(true)}>
|
|
381
|
+
Small
|
|
382
|
+
</Button>
|
|
383
|
+
<Button size="md" onClick={() => setOpenMd(true)}>
|
|
384
|
+
Medium
|
|
385
|
+
</Button>
|
|
386
|
+
<Button size="lg" onClick={() => setOpenLg(true)}>
|
|
387
|
+
Large
|
|
388
|
+
</Button>
|
|
389
|
+
<Modal open={openSm} onClose={() => setOpenSm(false)}>
|
|
390
|
+
<ModalFrame title="Small ModalFrame" size="sm" onClose={() => setOpenSm(false)}>
|
|
391
|
+
<Typography>This is a small ModalFrame.</Typography>
|
|
392
|
+
</ModalFrame>
|
|
393
|
+
</Modal>
|
|
394
|
+
<Modal open={openMd} onClose={() => setOpenMd(false)}>
|
|
395
|
+
<ModalFrame title="Medium ModalFrame" size="md" onClose={() => setOpenMd(false)}>
|
|
396
|
+
<Typography>This is a medium ModalFrame.</Typography>
|
|
397
|
+
</ModalFrame>
|
|
398
|
+
</Modal>
|
|
399
|
+
<Modal open={openLg} onClose={() => setOpenLg(false)}>
|
|
400
|
+
<ModalFrame title="Large ModalFrame" size="lg" onClose={() => setOpenLg(false)}>
|
|
401
|
+
<Typography>This is a large ModalFrame.</Typography>
|
|
402
|
+
</ModalFrame>
|
|
403
|
+
</Modal>
|
|
404
|
+
</Stack>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### Custom Content
|
|
408
|
+
|
|
409
|
+
A layout example suited for displaying detailed information.
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
<>
|
|
413
|
+
<Button onClick={() => setOpen(true)}>Custom Content</Button>
|
|
414
|
+
<Modal open={open} onClose={() => setOpen(false)}>
|
|
415
|
+
<ModalFrame title="Order Details" onClose={() => setOpen(false)}>
|
|
416
|
+
<Stack spacing={2}>
|
|
417
|
+
<Box>
|
|
418
|
+
<Typography level="title-sm">Order ID</Typography>
|
|
419
|
+
<Typography level="body-sm">ORD-2024-00123</Typography>
|
|
420
|
+
</Box>
|
|
421
|
+
<Divider />
|
|
422
|
+
<Box>
|
|
423
|
+
<Typography level="title-sm">Customer</Typography>
|
|
424
|
+
<Typography level="body-sm">John Doe</Typography>
|
|
425
|
+
</Box>
|
|
426
|
+
<Divider />
|
|
427
|
+
<Box>
|
|
428
|
+
<Typography level="title-sm">Status</Typography>
|
|
429
|
+
<Typography level="body-sm" color="success">
|
|
430
|
+
Completed
|
|
431
|
+
</Typography>
|
|
432
|
+
</Box>
|
|
433
|
+
</Stack>
|
|
434
|
+
</ModalFrame>
|
|
435
|
+
</Modal>
|
|
436
|
+
</>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### Standalone
|
|
440
|
+
|
|
441
|
+
ModalFrame can be used without a Modal wrapper for embedding dialog-style layouts directly within a page.
|
|
442
|
+
|
|
443
|
+
> ⚠️ **Important** ⚠️
|
|
444
|
+
>
|
|
445
|
+
> When using ModalFrame without Modal, the parent container **must** provide explicit `width` and `height` values.
|
|
446
|
+
> ModalFrame inherits its dimensions from `ModalDialog`, which normally receives sizing from the Modal overlay.
|
|
447
|
+
> Without these constraints, the component will not render with correct dimensions.
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
<Box sx={{
|
|
451
|
+
width: 480,
|
|
452
|
+
height: 300
|
|
453
|
+
}}>
|
|
454
|
+
<ModalFrame title="Standalone ModalFrame" onClose={() => console.log('close')}>
|
|
455
|
+
<Typography>
|
|
456
|
+
ModalFrame used without Modal. The parent container must provide explicit width and height.
|
|
457
|
+
</Typography>
|
|
458
|
+
</ModalFrame>
|
|
459
|
+
</Box>
|
|
215
460
|
```
|
|
216
461
|
|
|
217
462
|
## When to Use
|
|
@@ -249,8 +494,7 @@ function DeleteConfirmation({ item, onDelete, onCancel }) {
|
|
|
249
494
|
</DialogTitle>
|
|
250
495
|
<Divider />
|
|
251
496
|
<DialogContent>
|
|
252
|
-
This action cannot be undone. All data associated with this item
|
|
253
|
-
will be permanently removed.
|
|
497
|
+
This action cannot be undone. All data associated with this item will be permanently removed.
|
|
254
498
|
</DialogContent>
|
|
255
499
|
<DialogActions>
|
|
256
500
|
<Button variant="solid" color="danger" onClick={onDelete}>
|
|
@@ -326,8 +570,7 @@ function TermsModal({ open, onAccept, onDecline }) {
|
|
|
326
570
|
<DialogTitle>Terms of Service</DialogTitle>
|
|
327
571
|
<DialogContent>
|
|
328
572
|
<Typography level="body-sm">
|
|
329
|
-
Please read and accept the following terms and conditions before
|
|
330
|
-
proceeding...
|
|
573
|
+
Please read and accept the following terms and conditions before proceeding...
|
|
331
574
|
</Typography>
|
|
332
575
|
{/* Terms content */}
|
|
333
576
|
</DialogContent>
|
|
@@ -355,11 +598,7 @@ function ImagePreviewModal({ image, open, onClose }) {
|
|
|
355
598
|
<Modal open={open} onClose={onClose}>
|
|
356
599
|
<ModalDialog layout="center" sx={{ p: 0, overflow: 'hidden' }}>
|
|
357
600
|
<ModalClose sx={{ top: 8, right: 8, zIndex: 1 }} />
|
|
358
|
-
<img
|
|
359
|
-
src={image.src}
|
|
360
|
-
alt={image.alt}
|
|
361
|
-
style={{ maxWidth: '90vw', maxHeight: '90vh', objectFit: 'contain' }}
|
|
362
|
-
/>
|
|
601
|
+
<img src={image.src} alt={image.alt} style={{ maxWidth: '90vw', maxHeight: '90vh', objectFit: 'contain' }} />
|
|
363
602
|
</ModalDialog>
|
|
364
603
|
</Modal>
|
|
365
604
|
);
|
|
@@ -390,22 +629,69 @@ function LoadingModal({ open, message }) {
|
|
|
390
629
|
Modal uses a composition pattern with multiple sub-components:
|
|
391
630
|
|
|
392
631
|
```tsx
|
|
393
|
-
<Modal>
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
632
|
+
<Modal>
|
|
633
|
+
{/* Overlay and backdrop */}
|
|
634
|
+
<ModalDialog>
|
|
635
|
+
{/* Dialog container */}
|
|
636
|
+
<ModalClose /> {/* Close button (optional) */}
|
|
637
|
+
<DialogTitle>
|
|
638
|
+
{/* Header */}
|
|
397
639
|
Title
|
|
398
640
|
</DialogTitle>
|
|
399
|
-
<DialogContent>
|
|
641
|
+
<DialogContent>
|
|
642
|
+
{/* Body */}
|
|
400
643
|
Content goes here
|
|
401
644
|
</DialogContent>
|
|
402
|
-
<DialogActions>
|
|
645
|
+
<DialogActions>
|
|
646
|
+
{/* Footer */}
|
|
403
647
|
<Button>Action</Button>
|
|
404
648
|
</DialogActions>
|
|
405
649
|
</ModalDialog>
|
|
406
650
|
</Modal>
|
|
407
651
|
```
|
|
408
652
|
|
|
653
|
+
## Component Roles
|
|
654
|
+
|
|
655
|
+
| Component | Role | When to Use |
|
|
656
|
+
| ----------------- | --------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
657
|
+
| **Modal** | Overlay backdrop, open/close state management | Always required as the outermost wrapper |
|
|
658
|
+
| **ModalDialog** | Dialog container (variant/size/layout) | When you need direct control over layout |
|
|
659
|
+
| **ModalClose** | Close (X) button in the top-right corner | When users should be able to close via a button |
|
|
660
|
+
| **ModalOverflow** | Scrollable area | When content exceeds the viewport |
|
|
661
|
+
| **ModalFrame** | Combines ModalDialog + ModalClose + DialogTitle + DialogContent | When you only need a title + close + content (no action buttons) |
|
|
662
|
+
| **DialogTitle** | Header area (styled padding) | When composing manually |
|
|
663
|
+
| **DialogContent** | Body area (styled padding) | When composing manually |
|
|
664
|
+
| **DialogActions** | Footer action button area | When confirm/cancel buttons are needed |
|
|
665
|
+
|
|
666
|
+
## Choosing the Right Component
|
|
667
|
+
|
|
668
|
+
### ModalFrame vs DialogFrame
|
|
669
|
+
|
|
670
|
+
| | ModalFrame | DialogFrame |
|
|
671
|
+
| ------------------ | ----------------------------------------------- | --------------------------------------- |
|
|
672
|
+
| Close (X) button | Built-in | None |
|
|
673
|
+
| Title decorator | `titleStartDecorator` | None |
|
|
674
|
+
| Action button area | None | `actions` prop (required) |
|
|
675
|
+
| Fullscreen | `layout="fullscreen"` | `fullscreen` prop |
|
|
676
|
+
| Best for | Information display, detail views, inline forms | Confirm/cancel dialogs, decision-making |
|
|
677
|
+
|
|
678
|
+
### Use ModalFrame when
|
|
679
|
+
|
|
680
|
+
- You need an informational modal with a close button (detail views, previews)
|
|
681
|
+
- The form's submit button lives inside the content area
|
|
682
|
+
- You need an icon next to the title
|
|
683
|
+
|
|
684
|
+
### Use DialogFrame when
|
|
685
|
+
|
|
686
|
+
- Explicit action buttons (confirm/cancel) must be pinned to the bottom
|
|
687
|
+
- User decisions are required (delete confirmation, save confirmation)
|
|
688
|
+
- Only explicit choices should be allowed without a close (X) button
|
|
689
|
+
|
|
690
|
+
### Use manual composition when
|
|
691
|
+
|
|
692
|
+
- You need a custom layout that doesn't fit the ModalFrame/DialogFrame pattern
|
|
693
|
+
- You want to use both ModalClose and DialogActions together
|
|
694
|
+
|
|
409
695
|
## Props and Customization
|
|
410
696
|
|
|
411
697
|
### Modal Props
|
|
@@ -427,6 +713,17 @@ Modal uses a composition pattern with multiple sub-components:
|
|
|
427
713
|
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Dialog size |
|
|
428
714
|
| `layout` | `'center' \| 'fullscreen'` | `'center'` | Layout mode |
|
|
429
715
|
|
|
716
|
+
### ModalFrame Props
|
|
717
|
+
|
|
718
|
+
| Prop | Type | Default | Description |
|
|
719
|
+
| --------------------- | ------------ | ------- | ------------------------------------------ |
|
|
720
|
+
| `title` | `ReactNode` | - | Title displayed in the header |
|
|
721
|
+
| `children` | `ReactNode` | - | Body content |
|
|
722
|
+
| `titleStartDecorator` | `ReactNode` | - | Icon or element displayed before the title |
|
|
723
|
+
| `onClose` | `() => void` | - | Callback when the close button is clicked |
|
|
724
|
+
|
|
725
|
+
ModalFrame accepts all ModalDialog props (`variant`, `color`, `size`, `layout`, `sx`, etc.).
|
|
726
|
+
|
|
430
727
|
### Custom Styling
|
|
431
728
|
|
|
432
729
|
```tsx
|
|
@@ -465,17 +762,10 @@ Modal components include comprehensive accessibility features:
|
|
|
465
762
|
- `aria-describedby` connects to DialogContent
|
|
466
763
|
|
|
467
764
|
```tsx
|
|
468
|
-
<Modal
|
|
469
|
-
open={open}
|
|
470
|
-
onClose={onClose}
|
|
471
|
-
aria-labelledby="modal-title"
|
|
472
|
-
aria-describedby="modal-description"
|
|
473
|
-
>
|
|
765
|
+
<Modal open={open} onClose={onClose} aria-labelledby="modal-title" aria-describedby="modal-description">
|
|
474
766
|
<ModalDialog>
|
|
475
767
|
<DialogTitle id="modal-title">Accessible Title</DialogTitle>
|
|
476
|
-
<DialogContent id="modal-description">
|
|
477
|
-
This content is read by screen readers.
|
|
478
|
-
</DialogContent>
|
|
768
|
+
<DialogContent id="modal-description">This content is read by screen readers.</DialogContent>
|
|
479
769
|
</ModalDialog>
|
|
480
770
|
</Modal>
|
|
481
771
|
```
|
|
@@ -504,7 +794,9 @@ Modal components include comprehensive accessibility features:
|
|
|
504
794
|
```tsx
|
|
505
795
|
// ✅ Good: Clear action buttons
|
|
506
796
|
<DialogActions>
|
|
507
|
-
<Button variant="solid" color="danger">
|
|
797
|
+
<Button variant="solid" color="danger">
|
|
798
|
+
Delete
|
|
799
|
+
</Button>
|
|
508
800
|
<Button variant="plain">Cancel</Button>
|
|
509
801
|
</DialogActions>
|
|
510
802
|
```
|
|
@@ -579,15 +871,11 @@ Use `keepMounted` only when the modal needs to preserve state between openings:
|
|
|
579
871
|
Memoize modal content when it depends on complex data:
|
|
580
872
|
|
|
581
873
|
```tsx
|
|
582
|
-
const modalContent = useMemo(() =>
|
|
583
|
-
<ComplexContent data={data} />
|
|
584
|
-
), [data]);
|
|
874
|
+
const modalContent = useMemo(() => <ComplexContent data={data} />, [data]);
|
|
585
875
|
|
|
586
876
|
<Modal open={open} onClose={onClose}>
|
|
587
|
-
<ModalDialog>
|
|
588
|
-
|
|
589
|
-
</ModalDialog>
|
|
590
|
-
</Modal>
|
|
877
|
+
<ModalDialog>{modalContent}</ModalDialog>
|
|
878
|
+
</Modal>;
|
|
591
879
|
```
|
|
592
880
|
|
|
593
881
|
Modal is a powerful component for focused user interactions. Use it thoughtfully to maintain a smooth user experience while capturing important decisions and inputs.
|