@ceed/ads 1.22.0 → 1.23.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" />
|
|
@@ -21,10 +21,10 @@ import { Typography } from '@ceed/ads';
|
|
|
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,24 +74,24 @@ 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
|
-
|
|
86
|
-
|
|
85
|
+
The main content of the article goes here. This text uses a readable size
|
|
86
|
+
and line spacing.
|
|
87
87
|
</Typography>
|
|
88
88
|
|
|
89
89
|
<Typography level="h2" sx={{ mt: 4, mb: 2 }}>
|
|
90
|
-
|
|
90
|
+
Section Title
|
|
91
91
|
</Typography>
|
|
92
92
|
|
|
93
93
|
<Typography level="body-md">
|
|
94
|
-
|
|
94
|
+
The section content continues here.
|
|
95
95
|
</Typography>
|
|
96
96
|
</article>
|
|
97
97
|
);
|
|
@@ -104,15 +104,15 @@ function ArticlePage() {
|
|
|
104
104
|
<Card>
|
|
105
105
|
<CardContent>
|
|
106
106
|
<Typography level="title-md" sx={{ mb: 1 }}>
|
|
107
|
-
|
|
107
|
+
Product Name
|
|
108
108
|
</Typography>
|
|
109
109
|
|
|
110
110
|
<Typography level="body-sm" color="neutral" sx={{ mb: 2 }}>
|
|
111
|
-
|
|
111
|
+
Category: Electronics
|
|
112
112
|
</Typography>
|
|
113
113
|
|
|
114
114
|
<Typography level="body-md" sx={{ mb: 2 }}>
|
|
115
|
-
|
|
115
|
+
A detailed description of the product goes here.
|
|
116
116
|
</Typography>
|
|
117
117
|
|
|
118
118
|
<Typography level="title-lg" color="primary">
|
|
@@ -128,21 +128,21 @@ function ArticlePage() {
|
|
|
128
128
|
<Stack spacing={2}>
|
|
129
129
|
<FormControl>
|
|
130
130
|
<Typography level="title-sm" component="label">
|
|
131
|
-
|
|
131
|
+
Username
|
|
132
132
|
</Typography>
|
|
133
|
-
<Input placeholder="
|
|
133
|
+
<Input placeholder="Enter your name" />
|
|
134
134
|
<Typography level="body-xs" color="neutral">
|
|
135
|
-
|
|
135
|
+
Please enter your real name.
|
|
136
136
|
</Typography>
|
|
137
137
|
</FormControl>
|
|
138
138
|
|
|
139
139
|
<FormControl error>
|
|
140
140
|
<Typography level="title-sm" component="label">
|
|
141
|
-
|
|
141
|
+
Email Address
|
|
142
142
|
</Typography>
|
|
143
143
|
<Input placeholder="email@example.com" />
|
|
144
144
|
<Typography level="body-xs" color="danger">
|
|
145
|
-
|
|
145
|
+
The email format is invalid.
|
|
146
146
|
</Typography>
|
|
147
147
|
</FormControl>
|
|
148
148
|
</Stack>
|
|
@@ -153,16 +153,16 @@ function ArticlePage() {
|
|
|
153
153
|
```tsx
|
|
154
154
|
<Stack spacing={2}>
|
|
155
155
|
<Box>
|
|
156
|
-
<Typography level="body-md"
|
|
156
|
+
<Typography level="body-md">Server Status:</Typography>
|
|
157
157
|
<Typography level="body-md" color="success">
|
|
158
|
-
|
|
158
|
+
Operating Normally
|
|
159
159
|
</Typography>
|
|
160
160
|
</Box>
|
|
161
161
|
|
|
162
162
|
<Box>
|
|
163
|
-
<Typography level="body-md"
|
|
163
|
+
<Typography level="body-md">Last Updated:</Typography>
|
|
164
164
|
<Typography level="body-sm" color="neutral">
|
|
165
|
-
2
|
|
165
|
+
2 minutes ago
|
|
166
166
|
</Typography>
|
|
167
167
|
</Box>
|
|
168
168
|
</Stack>
|
|
@@ -172,7 +172,7 @@ function ArticlePage() {
|
|
|
172
172
|
|
|
173
173
|
```tsx
|
|
174
174
|
<Stack spacing={1}>
|
|
175
|
-
<Typography level="title-md"
|
|
175
|
+
<Typography level="title-md">Todo List</Typography>
|
|
176
176
|
|
|
177
177
|
{todoItems.map((item) => (
|
|
178
178
|
<Box key={item.id} sx={{ pl: 2 }}>
|
|
@@ -195,39 +195,39 @@ function ArticlePage() {
|
|
|
195
195
|
|
|
196
196
|
## Colors
|
|
197
197
|
|
|
198
|
-
Typography
|
|
198
|
+
Typography supports various colors:
|
|
199
199
|
|
|
200
200
|
```tsx
|
|
201
201
|
<Stack spacing={1}>
|
|
202
|
-
<Typography color="primary">Primary
|
|
203
|
-
<Typography color="neutral">Neutral
|
|
204
|
-
<Typography color="danger">Danger
|
|
205
|
-
<Typography color="success">Success
|
|
206
|
-
<Typography color="warning">Warning
|
|
202
|
+
<Typography color="primary">Primary color</Typography>
|
|
203
|
+
<Typography color="neutral">Neutral color</Typography>
|
|
204
|
+
<Typography color="danger">Danger color</Typography>
|
|
205
|
+
<Typography color="success">Success color</Typography>
|
|
206
|
+
<Typography color="warning">Warning color</Typography>
|
|
207
207
|
</Stack>
|
|
208
208
|
```
|
|
209
209
|
|
|
210
210
|
## Component Prop
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
You can render it as a different HTML element or React component:
|
|
213
213
|
|
|
214
214
|
```tsx
|
|
215
215
|
<Typography level="h1" component="h2">
|
|
216
|
-
|
|
216
|
+
h1 style rendered as an h2 tag
|
|
217
217
|
</Typography>
|
|
218
218
|
|
|
219
219
|
<Typography level="body-md" component="span">
|
|
220
|
-
|
|
220
|
+
Inline text
|
|
221
221
|
</Typography>
|
|
222
222
|
|
|
223
223
|
<Typography level="title-md" component={Link} href="/page">
|
|
224
|
-
|
|
224
|
+
Rendered as a Link component
|
|
225
225
|
</Typography>
|
|
226
226
|
```
|
|
227
227
|
|
|
228
228
|
## Responsive Typography
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
You can use responsive levels:
|
|
231
231
|
|
|
232
232
|
```tsx
|
|
233
233
|
<Typography
|
|
@@ -236,36 +236,36 @@ Typography는 다양한 색상을 지원합니다:
|
|
|
236
236
|
fontSize: { xs: '1.5rem', sm: '2rem', md: '2.5rem' }
|
|
237
237
|
}}
|
|
238
238
|
>
|
|
239
|
-
|
|
239
|
+
Responsive Heading
|
|
240
240
|
</Typography>
|
|
241
241
|
```
|
|
242
242
|
|
|
243
243
|
## Best Practices
|
|
244
244
|
|
|
245
|
-
1.
|
|
245
|
+
1. **Semantic Structure**: Use heading levels in order to create a clear document structure.
|
|
246
246
|
|
|
247
247
|
```tsx
|
|
248
|
-
// ✅
|
|
249
|
-
<Typography level="h1"
|
|
250
|
-
<Typography level="h2"
|
|
251
|
-
<Typography level="h3"
|
|
252
|
-
|
|
253
|
-
// ❌
|
|
254
|
-
<Typography level="h1"
|
|
255
|
-
<Typography level="h3"
|
|
248
|
+
// ✅ Correct order
|
|
249
|
+
<Typography level="h1">Main heading</Typography>
|
|
250
|
+
<Typography level="h2">Section heading</Typography>
|
|
251
|
+
<Typography level="h3">Subsection</Typography>
|
|
252
|
+
|
|
253
|
+
// ❌ Incorrect order
|
|
254
|
+
<Typography level="h1">Main heading</Typography>
|
|
255
|
+
<Typography level="h3">Section heading</Typography>
|
|
256
256
|
```
|
|
257
257
|
|
|
258
|
-
2.
|
|
258
|
+
2. **Consistency**: Use the same level for text serving the same purpose.
|
|
259
259
|
|
|
260
|
-
3.
|
|
260
|
+
3. **Readability**: Provide proper line spacing and paragraph separation for body text.
|
|
261
261
|
|
|
262
|
-
4.
|
|
262
|
+
4. **Color Contrast**: Maintain sufficient color contrast to ensure accessibility.
|
|
263
263
|
|
|
264
264
|
## Accessibility
|
|
265
265
|
|
|
266
|
-
-
|
|
267
|
-
-
|
|
268
|
-
-
|
|
269
|
-
-
|
|
266
|
+
- Use appropriate semantic HTML tags
|
|
267
|
+
- Support screen readers
|
|
268
|
+
- Ensure keyboard navigation (when used as a link or button)
|
|
269
|
+
- Maintain sufficient color contrast
|
|
270
270
|
|
|
271
|
-
Typography
|
|
271
|
+
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.
|
|
@@ -43,9 +43,7 @@ function ConfirmationDialog({ open, onClose, onConfirm }) {
|
|
|
43
43
|
<Button variant="plain" color="neutral" onClick={onClose}>
|
|
44
44
|
Cancel
|
|
45
45
|
</Button>
|
|
46
|
-
<Button onClick={onConfirm}>
|
|
47
|
-
Confirm
|
|
48
|
-
</Button>
|
|
46
|
+
<Button onClick={onConfirm}>Confirm</Button>
|
|
49
47
|
</>
|
|
50
48
|
}
|
|
51
49
|
>
|
|
@@ -94,6 +92,57 @@ Dialog Content
|
|
|
94
92
|
</DialogFrame>
|
|
95
93
|
```
|
|
96
94
|
|
|
95
|
+
### Standalone Usage
|
|
96
|
+
|
|
97
|
+
DialogFrame can be used without a Modal wrapper for embedding dialog-style layouts directly within a page.
|
|
98
|
+
|
|
99
|
+
> ⚠️ **Important** ⚠️
|
|
100
|
+
>
|
|
101
|
+
> When using DialogFrame without Modal, the parent container **must** provide explicit `width` and `height` values.
|
|
102
|
+
> DialogFrame inherits its dimensions from `ModalDialog`, which normally receives sizing from the Modal overlay.
|
|
103
|
+
> Without these constraints, the component will not render with correct dimensions.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
<Box sx={{
|
|
107
|
+
width: 480,
|
|
108
|
+
height: 300
|
|
109
|
+
}}>
|
|
110
|
+
<DialogFrame {...args} title="Standalone Dialog" actions={<>
|
|
111
|
+
<Button variant="plain" color="neutral">
|
|
112
|
+
Cancel
|
|
113
|
+
</Button>
|
|
114
|
+
<Button variant="plain">Confirm</Button>
|
|
115
|
+
</>}>
|
|
116
|
+
DialogFrame used without Modal. The parent container must provide explicit width and height.
|
|
117
|
+
</DialogFrame>
|
|
118
|
+
</Box>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { DialogFrame, Button, Box } from '@ceed/ads';
|
|
123
|
+
|
|
124
|
+
// Standalone usage requires explicit container dimensions
|
|
125
|
+
function EmbeddedDialog() {
|
|
126
|
+
return (
|
|
127
|
+
<Box sx={{ width: 480, height: 300 }}>
|
|
128
|
+
<DialogFrame
|
|
129
|
+
title="Settings"
|
|
130
|
+
actions={
|
|
131
|
+
<>
|
|
132
|
+
<Button variant="plain" color="neutral">
|
|
133
|
+
Cancel
|
|
134
|
+
</Button>
|
|
135
|
+
<Button>Save</Button>
|
|
136
|
+
</>
|
|
137
|
+
}
|
|
138
|
+
>
|
|
139
|
+
This dialog is embedded directly in the page layout.
|
|
140
|
+
</DialogFrame>
|
|
141
|
+
</Box>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
97
146
|
## When to Use
|
|
98
147
|
|
|
99
148
|
### ✅ Good Use Cases
|
|
@@ -177,21 +226,11 @@ function QuickAddDialog({ open, onClose, onSubmit }) {
|
|
|
177
226
|
<Stack gap={2}>
|
|
178
227
|
<FormControl>
|
|
179
228
|
<FormLabel>Name</FormLabel>
|
|
180
|
-
<Input
|
|
181
|
-
value={name}
|
|
182
|
-
onChange={(e) => setName(e.target.value)}
|
|
183
|
-
placeholder="Enter name"
|
|
184
|
-
autoFocus
|
|
185
|
-
/>
|
|
229
|
+
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder="Enter name" autoFocus />
|
|
186
230
|
</FormControl>
|
|
187
231
|
<FormControl>
|
|
188
232
|
<FormLabel>Email</FormLabel>
|
|
189
|
-
<Input
|
|
190
|
-
type="email"
|
|
191
|
-
value={email}
|
|
192
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
193
|
-
placeholder="Enter email"
|
|
194
|
-
/>
|
|
233
|
+
<Input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Enter email" />
|
|
195
234
|
</FormControl>
|
|
196
235
|
</Stack>
|
|
197
236
|
</DialogFrame>
|
|
@@ -216,15 +255,11 @@ function UnsavedChangesDialog({ open, onClose, onDiscard, onSave }) {
|
|
|
216
255
|
<Button variant="outlined" color="danger" onClick={onDiscard}>
|
|
217
256
|
Discard
|
|
218
257
|
</Button>
|
|
219
|
-
<Button onClick={onSave}>
|
|
220
|
-
Save Changes
|
|
221
|
-
</Button>
|
|
258
|
+
<Button onClick={onSave}>Save Changes</Button>
|
|
222
259
|
</>
|
|
223
260
|
}
|
|
224
261
|
>
|
|
225
|
-
<Typography>
|
|
226
|
-
You have unsaved changes. Would you like to save them before leaving?
|
|
227
|
-
</Typography>
|
|
262
|
+
<Typography>You have unsaved changes. Would you like to save them before leaving?</Typography>
|
|
228
263
|
</DialogFrame>
|
|
229
264
|
</Modal>
|
|
230
265
|
);
|
|
@@ -237,14 +272,7 @@ function UnsavedChangesDialog({ open, onClose, onDiscard, onSave }) {
|
|
|
237
272
|
function InfoDialog({ open, onClose, title, message }) {
|
|
238
273
|
return (
|
|
239
274
|
<Modal open={open} onClose={onClose}>
|
|
240
|
-
<DialogFrame
|
|
241
|
-
title={title}
|
|
242
|
-
actions={
|
|
243
|
-
<Button onClick={onClose}>
|
|
244
|
-
Got it
|
|
245
|
-
</Button>
|
|
246
|
-
}
|
|
247
|
-
>
|
|
275
|
+
<DialogFrame title={title} actions={<Button onClick={onClose}>Got it</Button>}>
|
|
248
276
|
<Typography>{message}</Typography>
|
|
249
277
|
</DialogFrame>
|
|
250
278
|
</Modal>
|
|
@@ -301,18 +329,8 @@ function ProcessingDialog({ open, status, onClose }) {
|
|
|
301
329
|
return (
|
|
302
330
|
<Modal open={open} onClose={isProcessing ? undefined : onClose}>
|
|
303
331
|
<DialogFrame
|
|
304
|
-
title={
|
|
305
|
-
|
|
306
|
-
isSuccess ? 'Success!' :
|
|
307
|
-
'Error'
|
|
308
|
-
}
|
|
309
|
-
actions={
|
|
310
|
-
!isProcessing && (
|
|
311
|
-
<Button onClick={onClose}>
|
|
312
|
-
{isSuccess ? 'Done' : 'Try Again'}
|
|
313
|
-
</Button>
|
|
314
|
-
)
|
|
315
|
-
}
|
|
332
|
+
title={isProcessing ? 'Processing...' : isSuccess ? 'Success!' : 'Error'}
|
|
333
|
+
actions={!isProcessing && <Button onClick={onClose}>{isSuccess ? 'Done' : 'Try Again'}</Button>}
|
|
316
334
|
>
|
|
317
335
|
<Box sx={{ textAlign: 'center', py: 2 }}>
|
|
318
336
|
{isProcessing && <CircularProgress />}
|
|
@@ -457,9 +475,7 @@ DialogFrame should be wrapped in Modal for proper behavior:
|
|
|
457
475
|
// Fullscreen for complex content or mobile
|
|
458
476
|
<Modal open={open} onClose={onClose}>
|
|
459
477
|
<DialogFrame fullscreen title="Edit Profile">
|
|
460
|
-
<Box sx={{ p: 2 }}>
|
|
461
|
-
{/* Large form or content */}
|
|
462
|
-
</Box>
|
|
478
|
+
<Box sx={{ p: 2 }}>{/* Large form or content */}</Box>
|
|
463
479
|
</DialogFrame>
|
|
464
480
|
</Modal>
|
|
465
481
|
```
|
|
@@ -500,9 +516,7 @@ DialogFrame inherits accessibility features from Modal:
|
|
|
500
516
|
|
|
501
517
|
```tsx
|
|
502
518
|
// Title provides context
|
|
503
|
-
<DialogFrame title="Confirm Deletion">
|
|
504
|
-
{/* Content is read after title */}
|
|
505
|
-
</DialogFrame>
|
|
519
|
+
<DialogFrame title="Confirm Deletion">{/* Content is read after title */}</DialogFrame>
|
|
506
520
|
```
|
|
507
521
|
|
|
508
522
|
## Best Practices
|
|
@@ -530,9 +544,7 @@ DialogFrame inherits accessibility features from Modal:
|
|
|
530
544
|
```tsx
|
|
531
545
|
// ✅ Good: Brief, scannable content
|
|
532
546
|
<DialogFrame title="Delete Project">
|
|
533
|
-
<Typography>
|
|
534
|
-
This will permanently delete the project and all its data.
|
|
535
|
-
</Typography>
|
|
547
|
+
<Typography>This will permanently delete the project and all its data.</Typography>
|
|
536
548
|
</DialogFrame>
|
|
537
549
|
```
|
|
538
550
|
|
|
@@ -560,7 +572,7 @@ DialogFrame inherits accessibility features from Modal:
|
|
|
560
572
|
// ❌ Bad: Dialog for simple feedback
|
|
561
573
|
<DialogFrame title="Success">
|
|
562
574
|
<Typography>Item saved!</Typography>
|
|
563
|
-
</DialogFrame
|
|
575
|
+
</DialogFrame>;
|
|
564
576
|
|
|
565
577
|
// ✅ Good: Use Toast
|
|
566
578
|
showToast({ message: 'Item saved!' });
|
|
@@ -570,9 +582,7 @@ showToast({ message: 'Item saved!' });
|
|
|
570
582
|
|
|
571
583
|
```tsx
|
|
572
584
|
// ❌ Bad: Complex form in dialog
|
|
573
|
-
<DialogFrame title="Create Account">
|
|
574
|
-
{/* 20+ form fields */}
|
|
575
|
-
</DialogFrame>
|
|
585
|
+
<DialogFrame title="Create Account">{/* 20+ form fields */}</DialogFrame>
|
|
576
586
|
```
|
|
577
587
|
|
|
578
588
|
3. **Don't use vague button labels**: Be specific about actions
|
|
@@ -599,9 +609,7 @@ For dialogs with heavy content:
|
|
|
599
609
|
function HeavyDialog({ open, onClose }) {
|
|
600
610
|
return (
|
|
601
611
|
<Modal open={open} onClose={onClose}>
|
|
602
|
-
<DialogFrame title="Data Preview">
|
|
603
|
-
{open && <HeavyDataComponent />}
|
|
604
|
-
</DialogFrame>
|
|
612
|
+
<DialogFrame title="Data Preview">{open && <HeavyDataComponent />}</DialogFrame>
|
|
605
613
|
</Modal>
|
|
606
614
|
);
|
|
607
615
|
}
|
|
@@ -625,11 +633,13 @@ const handleCancel = useCallback(() => {
|
|
|
625
633
|
Unmount dialog completely when not needed:
|
|
626
634
|
|
|
627
635
|
```tsx
|
|
628
|
-
{
|
|
629
|
-
|
|
630
|
-
<
|
|
631
|
-
|
|
632
|
-
|
|
636
|
+
{
|
|
637
|
+
open && (
|
|
638
|
+
<Modal open={open} onClose={onClose}>
|
|
639
|
+
<DialogFrame>...</DialogFrame>
|
|
640
|
+
</Modal>
|
|
641
|
+
);
|
|
642
|
+
}
|
|
633
643
|
```
|
|
634
644
|
|
|
635
645
|
DialogFrame provides a consistent structure for dialog content. Combine it with Modal for proper overlay behavior, keep content concise and actionable, and always provide clear options for users to proceed or cancel.
|