@ceed/ads 1.29.1 → 1.30.0-next.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/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
- package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
- package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
- package/dist/components/SearchBar/SearchBar.d.ts +21 -0
- package/dist/components/SearchBar/index.d.ts +3 -0
- package/dist/components/data-display/Badge.md +39 -71
- package/dist/components/data-display/DataTable.md +1 -1
- package/dist/components/data-display/InfoSign.md +98 -74
- package/dist/components/data-display/Typography.md +97 -363
- package/dist/components/feedback/Dialog.md +62 -76
- package/dist/components/feedback/Modal.md +44 -259
- package/dist/components/feedback/llms.txt +0 -2
- package/dist/components/index.d.ts +2 -0
- package/dist/components/inputs/Autocomplete.md +107 -356
- package/dist/components/inputs/ButtonGroup.md +106 -115
- package/dist/components/inputs/Calendar.md +459 -98
- package/dist/components/inputs/CurrencyInput.md +5 -183
- package/dist/components/inputs/DatePicker.md +431 -108
- package/dist/components/inputs/DateRangePicker.md +492 -131
- package/dist/components/inputs/FilterMenu.md +19 -169
- package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
- package/dist/components/inputs/IconButton.md +88 -137
- package/dist/components/inputs/Input.md +0 -5
- package/dist/components/inputs/MonthPicker.md +422 -95
- package/dist/components/inputs/MonthRangePicker.md +466 -89
- package/dist/components/inputs/PercentageInput.md +16 -185
- package/dist/components/inputs/RadioButton.md +35 -163
- package/dist/components/inputs/RadioTileGroup.md +61 -150
- package/dist/components/inputs/SearchBar.md +44 -0
- package/dist/components/inputs/Select.md +326 -222
- package/dist/components/inputs/Switch.md +376 -136
- package/dist/components/inputs/Textarea.md +10 -213
- package/dist/components/inputs/Uploader/Uploader.md +66 -145
- package/dist/components/inputs/llms.txt +1 -3
- package/dist/components/navigation/Breadcrumbs.md +322 -80
- package/dist/components/navigation/Dropdown.md +221 -92
- package/dist/components/navigation/IconMenuButton.md +502 -40
- package/dist/components/navigation/InsetDrawer.md +738 -68
- package/dist/components/navigation/Link.md +298 -39
- package/dist/components/navigation/Menu.md +285 -92
- package/dist/components/navigation/MenuButton.md +448 -55
- package/dist/components/navigation/Pagination.md +338 -47
- package/dist/components/navigation/ProfileMenu.md +268 -45
- package/dist/components/navigation/Stepper.md +28 -160
- package/dist/components/navigation/Tabs.md +316 -57
- package/dist/components/surfaces/Sheet.md +334 -151
- package/dist/index.browser.js +15 -13
- package/dist/index.browser.js.map +4 -4
- package/dist/index.cjs +289 -288
- package/dist/index.d.ts +1 -1
- package/dist/index.js +426 -369
- package/dist/llms.txt +1 -8
- package/framer/index.js +1 -1
- package/package.json +16 -15
- package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
- package/dist/components/feedback/CircularProgress.md +0 -257
- package/dist/components/feedback/Skeleton.md +0 -280
- package/dist/components/inputs/FormControl.md +0 -361
- package/dist/components/inputs/RadioList.md +0 -241
- package/dist/components/inputs/Slider.md +0 -334
- package/dist/guides/ThemeProvider.md +0 -116
- package/dist/guides/llms.txt +0 -9
|
@@ -43,7 +43,9 @@ function ConfirmationDialog({ open, onClose, onConfirm }) {
|
|
|
43
43
|
<Button variant="plain" color="neutral" onClick={onClose}>
|
|
44
44
|
Cancel
|
|
45
45
|
</Button>
|
|
46
|
-
<Button onClick={onConfirm}>
|
|
46
|
+
<Button onClick={onConfirm}>
|
|
47
|
+
Confirm
|
|
48
|
+
</Button>
|
|
47
49
|
</>
|
|
48
50
|
}
|
|
49
51
|
>
|
|
@@ -92,61 +94,6 @@ Dialog Content
|
|
|
92
94
|
</DialogFrame>
|
|
93
95
|
```
|
|
94
96
|
|
|
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** meet the following requirements:
|
|
102
|
-
>
|
|
103
|
-
> - `position: 'relative'` — DialogFrame uses absolute positioning internally
|
|
104
|
-
> - Explicit `width` and `height` — `height` must be an absolute value (e.g., `300`, `'400px'`), not a relative value like `%` or `auto`
|
|
105
|
-
>
|
|
106
|
-
> DialogFrame inherits its dimensions from `ModalDialog`, which normally receives sizing from the Modal overlay. Without these constraints, the component will not render with correct dimensions.
|
|
107
|
-
|
|
108
|
-
```tsx
|
|
109
|
-
<Box sx={{
|
|
110
|
-
position: 'relative',
|
|
111
|
-
width: 480,
|
|
112
|
-
height: 300
|
|
113
|
-
}}>
|
|
114
|
-
<DialogFrame {...args} title="Standalone Dialog" actions={<>
|
|
115
|
-
<Button variant="plain" color="neutral">
|
|
116
|
-
Cancel
|
|
117
|
-
</Button>
|
|
118
|
-
<Button variant="plain">Confirm</Button>
|
|
119
|
-
</>}>
|
|
120
|
-
DialogFrame used without Modal. The parent container must provide explicit width and height.
|
|
121
|
-
</DialogFrame>
|
|
122
|
-
</Box>
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
```tsx
|
|
126
|
-
import { DialogFrame, Button, Box } from '@ceed/ads';
|
|
127
|
-
|
|
128
|
-
// Standalone usage requires explicit container dimensions
|
|
129
|
-
function EmbeddedDialog() {
|
|
130
|
-
return (
|
|
131
|
-
<Box sx={{ position: 'relative', width: 480, height: 300 }}>
|
|
132
|
-
<DialogFrame
|
|
133
|
-
title="Settings"
|
|
134
|
-
actions={
|
|
135
|
-
<>
|
|
136
|
-
<Button variant="plain" color="neutral">
|
|
137
|
-
Cancel
|
|
138
|
-
</Button>
|
|
139
|
-
<Button>Save</Button>
|
|
140
|
-
</>
|
|
141
|
-
}
|
|
142
|
-
>
|
|
143
|
-
This dialog is embedded directly in the page layout.
|
|
144
|
-
</DialogFrame>
|
|
145
|
-
</Box>
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
97
|
## When to Use
|
|
151
98
|
|
|
152
99
|
### ✅ Good Use Cases
|
|
@@ -230,11 +177,21 @@ function QuickAddDialog({ open, onClose, onSubmit }) {
|
|
|
230
177
|
<Stack gap={2}>
|
|
231
178
|
<FormControl>
|
|
232
179
|
<FormLabel>Name</FormLabel>
|
|
233
|
-
<Input
|
|
180
|
+
<Input
|
|
181
|
+
value={name}
|
|
182
|
+
onChange={(e) => setName(e.target.value)}
|
|
183
|
+
placeholder="Enter name"
|
|
184
|
+
autoFocus
|
|
185
|
+
/>
|
|
234
186
|
</FormControl>
|
|
235
187
|
<FormControl>
|
|
236
188
|
<FormLabel>Email</FormLabel>
|
|
237
|
-
<Input
|
|
189
|
+
<Input
|
|
190
|
+
type="email"
|
|
191
|
+
value={email}
|
|
192
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
193
|
+
placeholder="Enter email"
|
|
194
|
+
/>
|
|
238
195
|
</FormControl>
|
|
239
196
|
</Stack>
|
|
240
197
|
</DialogFrame>
|
|
@@ -259,11 +216,15 @@ function UnsavedChangesDialog({ open, onClose, onDiscard, onSave }) {
|
|
|
259
216
|
<Button variant="outlined" color="danger" onClick={onDiscard}>
|
|
260
217
|
Discard
|
|
261
218
|
</Button>
|
|
262
|
-
<Button onClick={onSave}>
|
|
219
|
+
<Button onClick={onSave}>
|
|
220
|
+
Save Changes
|
|
221
|
+
</Button>
|
|
263
222
|
</>
|
|
264
223
|
}
|
|
265
224
|
>
|
|
266
|
-
<Typography>
|
|
225
|
+
<Typography>
|
|
226
|
+
You have unsaved changes. Would you like to save them before leaving?
|
|
227
|
+
</Typography>
|
|
267
228
|
</DialogFrame>
|
|
268
229
|
</Modal>
|
|
269
230
|
);
|
|
@@ -276,7 +237,14 @@ function UnsavedChangesDialog({ open, onClose, onDiscard, onSave }) {
|
|
|
276
237
|
function InfoDialog({ open, onClose, title, message }) {
|
|
277
238
|
return (
|
|
278
239
|
<Modal open={open} onClose={onClose}>
|
|
279
|
-
<DialogFrame
|
|
240
|
+
<DialogFrame
|
|
241
|
+
title={title}
|
|
242
|
+
actions={
|
|
243
|
+
<Button onClick={onClose}>
|
|
244
|
+
Got it
|
|
245
|
+
</Button>
|
|
246
|
+
}
|
|
247
|
+
>
|
|
280
248
|
<Typography>{message}</Typography>
|
|
281
249
|
</DialogFrame>
|
|
282
250
|
</Modal>
|
|
@@ -333,8 +301,18 @@ function ProcessingDialog({ open, status, onClose }) {
|
|
|
333
301
|
return (
|
|
334
302
|
<Modal open={open} onClose={isProcessing ? undefined : onClose}>
|
|
335
303
|
<DialogFrame
|
|
336
|
-
title={
|
|
337
|
-
|
|
304
|
+
title={
|
|
305
|
+
isProcessing ? 'Processing...' :
|
|
306
|
+
isSuccess ? 'Success!' :
|
|
307
|
+
'Error'
|
|
308
|
+
}
|
|
309
|
+
actions={
|
|
310
|
+
!isProcessing && (
|
|
311
|
+
<Button onClick={onClose}>
|
|
312
|
+
{isSuccess ? 'Done' : 'Try Again'}
|
|
313
|
+
</Button>
|
|
314
|
+
)
|
|
315
|
+
}
|
|
338
316
|
>
|
|
339
317
|
<Box sx={{ textAlign: 'center', py: 2 }}>
|
|
340
318
|
{isProcessing && <CircularProgress />}
|
|
@@ -479,7 +457,9 @@ DialogFrame should be wrapped in Modal for proper behavior:
|
|
|
479
457
|
// Fullscreen for complex content or mobile
|
|
480
458
|
<Modal open={open} onClose={onClose}>
|
|
481
459
|
<DialogFrame fullscreen title="Edit Profile">
|
|
482
|
-
<Box sx={{ p: 2 }}>
|
|
460
|
+
<Box sx={{ p: 2 }}>
|
|
461
|
+
{/* Large form or content */}
|
|
462
|
+
</Box>
|
|
483
463
|
</DialogFrame>
|
|
484
464
|
</Modal>
|
|
485
465
|
```
|
|
@@ -520,7 +500,9 @@ DialogFrame inherits accessibility features from Modal:
|
|
|
520
500
|
|
|
521
501
|
```tsx
|
|
522
502
|
// Title provides context
|
|
523
|
-
<DialogFrame title="Confirm Deletion">
|
|
503
|
+
<DialogFrame title="Confirm Deletion">
|
|
504
|
+
{/* Content is read after title */}
|
|
505
|
+
</DialogFrame>
|
|
524
506
|
```
|
|
525
507
|
|
|
526
508
|
## Best Practices
|
|
@@ -548,7 +530,9 @@ DialogFrame inherits accessibility features from Modal:
|
|
|
548
530
|
```tsx
|
|
549
531
|
// ✅ Good: Brief, scannable content
|
|
550
532
|
<DialogFrame title="Delete Project">
|
|
551
|
-
<Typography>
|
|
533
|
+
<Typography>
|
|
534
|
+
This will permanently delete the project and all its data.
|
|
535
|
+
</Typography>
|
|
552
536
|
</DialogFrame>
|
|
553
537
|
```
|
|
554
538
|
|
|
@@ -576,7 +560,7 @@ DialogFrame inherits accessibility features from Modal:
|
|
|
576
560
|
// ❌ Bad: Dialog for simple feedback
|
|
577
561
|
<DialogFrame title="Success">
|
|
578
562
|
<Typography>Item saved!</Typography>
|
|
579
|
-
</DialogFrame
|
|
563
|
+
</DialogFrame>
|
|
580
564
|
|
|
581
565
|
// ✅ Good: Use Toast
|
|
582
566
|
showToast({ message: 'Item saved!' });
|
|
@@ -586,7 +570,9 @@ showToast({ message: 'Item saved!' });
|
|
|
586
570
|
|
|
587
571
|
```tsx
|
|
588
572
|
// ❌ Bad: Complex form in dialog
|
|
589
|
-
<DialogFrame title="Create Account">
|
|
573
|
+
<DialogFrame title="Create Account">
|
|
574
|
+
{/* 20+ form fields */}
|
|
575
|
+
</DialogFrame>
|
|
590
576
|
```
|
|
591
577
|
|
|
592
578
|
3. **Don't use vague button labels**: Be specific about actions
|
|
@@ -613,7 +599,9 @@ For dialogs with heavy content:
|
|
|
613
599
|
function HeavyDialog({ open, onClose }) {
|
|
614
600
|
return (
|
|
615
601
|
<Modal open={open} onClose={onClose}>
|
|
616
|
-
<DialogFrame title="Data Preview">
|
|
602
|
+
<DialogFrame title="Data Preview">
|
|
603
|
+
{open && <HeavyDataComponent />}
|
|
604
|
+
</DialogFrame>
|
|
617
605
|
</Modal>
|
|
618
606
|
);
|
|
619
607
|
}
|
|
@@ -637,13 +625,11 @@ const handleCancel = useCallback(() => {
|
|
|
637
625
|
Unmount dialog completely when not needed:
|
|
638
626
|
|
|
639
627
|
```tsx
|
|
640
|
-
{
|
|
641
|
-
open
|
|
642
|
-
<
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
);
|
|
646
|
-
}
|
|
628
|
+
{open && (
|
|
629
|
+
<Modal open={open} onClose={onClose}>
|
|
630
|
+
<DialogFrame>...</DialogFrame>
|
|
631
|
+
</Modal>
|
|
632
|
+
)}
|
|
647
633
|
```
|
|
648
634
|
|
|
649
635
|
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.
|
|
@@ -41,7 +41,15 @@ The Modal component is a dialog overlay that appears on top of the main content,
|
|
|
41
41
|
## Usage
|
|
42
42
|
|
|
43
43
|
```tsx
|
|
44
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
Modal,
|
|
46
|
+
ModalDialog,
|
|
47
|
+
ModalClose,
|
|
48
|
+
DialogTitle,
|
|
49
|
+
DialogContent,
|
|
50
|
+
DialogActions,
|
|
51
|
+
Button,
|
|
52
|
+
} from '@ceed/ads';
|
|
45
53
|
|
|
46
54
|
function MyComponent() {
|
|
47
55
|
const [open, setOpen] = useState(false);
|
|
@@ -53,7 +61,9 @@ function MyComponent() {
|
|
|
53
61
|
<ModalDialog>
|
|
54
62
|
<ModalClose />
|
|
55
63
|
<DialogTitle>Modal Title</DialogTitle>
|
|
56
|
-
<DialogContent>
|
|
64
|
+
<DialogContent>
|
|
65
|
+
Place your content here.
|
|
66
|
+
</DialogContent>
|
|
57
67
|
<DialogActions>
|
|
58
68
|
<Button onClick={() => setOpen(false)}>Close</Button>
|
|
59
69
|
</DialogActions>
|
|
@@ -64,28 +74,6 @@ function MyComponent() {
|
|
|
64
74
|
}
|
|
65
75
|
```
|
|
66
76
|
|
|
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/ads';
|
|
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
|
-
|
|
89
77
|
## Examples
|
|
90
78
|
|
|
91
79
|
### Basic Modal
|
|
@@ -304,166 +292,6 @@ Modals can be stacked on top of each other when necessary.
|
|
|
304
292
|
</>
|
|
305
293
|
```
|
|
306
294
|
|
|
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
|
-
</>
|
|
325
|
-
```
|
|
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** meet the following requirements:
|
|
446
|
-
>
|
|
447
|
-
> - `position: 'relative'` — ModalFrame uses absolute positioning internally
|
|
448
|
-
> - Explicit `width` and `height` — `height` must be an absolute value (e.g., `300`, `'400px'`), not a relative value like `%` or `auto`
|
|
449
|
-
>
|
|
450
|
-
> ModalFrame inherits its dimensions from `ModalDialog`, which normally receives sizing from the Modal overlay. Without these constraints, the component will not render with correct dimensions.
|
|
451
|
-
|
|
452
|
-
```tsx
|
|
453
|
-
<Box sx={{
|
|
454
|
-
position: 'relative',
|
|
455
|
-
width: 480,
|
|
456
|
-
height: 300
|
|
457
|
-
}}>
|
|
458
|
-
<ModalFrame title="Standalone ModalFrame" onClose={() => console.log('close')}>
|
|
459
|
-
<Typography>
|
|
460
|
-
ModalFrame used without Modal. The parent container must provide
|
|
461
|
-
explicit width and height.
|
|
462
|
-
</Typography>
|
|
463
|
-
</ModalFrame>
|
|
464
|
-
</Box>
|
|
465
|
-
```
|
|
466
|
-
|
|
467
295
|
## When to Use
|
|
468
296
|
|
|
469
297
|
### ✅ Good Use Cases
|
|
@@ -499,7 +327,8 @@ function DeleteConfirmation({ item, onDelete, onCancel }) {
|
|
|
499
327
|
</DialogTitle>
|
|
500
328
|
<Divider />
|
|
501
329
|
<DialogContent>
|
|
502
|
-
This action cannot be undone. All data associated with this item
|
|
330
|
+
This action cannot be undone. All data associated with this item
|
|
331
|
+
will be permanently removed.
|
|
503
332
|
</DialogContent>
|
|
504
333
|
<DialogActions>
|
|
505
334
|
<Button variant="solid" color="danger" onClick={onDelete}>
|
|
@@ -575,7 +404,8 @@ function TermsModal({ open, onAccept, onDecline }) {
|
|
|
575
404
|
<DialogTitle>Terms of Service</DialogTitle>
|
|
576
405
|
<DialogContent>
|
|
577
406
|
<Typography level="body-sm">
|
|
578
|
-
Please read and accept the following terms and conditions before
|
|
407
|
+
Please read and accept the following terms and conditions before
|
|
408
|
+
proceeding...
|
|
579
409
|
</Typography>
|
|
580
410
|
{/* Terms content */}
|
|
581
411
|
</DialogContent>
|
|
@@ -603,7 +433,11 @@ function ImagePreviewModal({ image, open, onClose }) {
|
|
|
603
433
|
<Modal open={open} onClose={onClose}>
|
|
604
434
|
<ModalDialog layout="center" sx={{ p: 0, overflow: 'hidden' }}>
|
|
605
435
|
<ModalClose sx={{ top: 8, right: 8, zIndex: 1 }} />
|
|
606
|
-
<img
|
|
436
|
+
<img
|
|
437
|
+
src={image.src}
|
|
438
|
+
alt={image.alt}
|
|
439
|
+
style={{ maxWidth: '90vw', maxHeight: '90vh', objectFit: 'contain' }}
|
|
440
|
+
/>
|
|
607
441
|
</ModalDialog>
|
|
608
442
|
</Modal>
|
|
609
443
|
);
|
|
@@ -634,69 +468,22 @@ function LoadingModal({ open, message }) {
|
|
|
634
468
|
Modal uses a composition pattern with multiple sub-components:
|
|
635
469
|
|
|
636
470
|
```tsx
|
|
637
|
-
<Modal>
|
|
638
|
-
{/*
|
|
639
|
-
|
|
640
|
-
{/*
|
|
641
|
-
<ModalClose /> {/* Close button (optional) */}
|
|
642
|
-
<DialogTitle>
|
|
643
|
-
{/* Header */}
|
|
471
|
+
<Modal> {/* Overlay and backdrop */}
|
|
472
|
+
<ModalDialog> {/* Dialog container */}
|
|
473
|
+
<ModalClose /> {/* Close button (optional) */}
|
|
474
|
+
<DialogTitle> {/* Header */}
|
|
644
475
|
Title
|
|
645
476
|
</DialogTitle>
|
|
646
|
-
<DialogContent>
|
|
647
|
-
{/* Body */}
|
|
477
|
+
<DialogContent> {/* Body */}
|
|
648
478
|
Content goes here
|
|
649
479
|
</DialogContent>
|
|
650
|
-
<DialogActions>
|
|
651
|
-
{/* Footer */}
|
|
480
|
+
<DialogActions> {/* Footer */}
|
|
652
481
|
<Button>Action</Button>
|
|
653
482
|
</DialogActions>
|
|
654
483
|
</ModalDialog>
|
|
655
484
|
</Modal>
|
|
656
485
|
```
|
|
657
486
|
|
|
658
|
-
## Component Roles
|
|
659
|
-
|
|
660
|
-
| Component | Role | When to Use |
|
|
661
|
-
| ----------------- | --------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
662
|
-
| **Modal** | Overlay backdrop, open/close state management | Always required as the outermost wrapper |
|
|
663
|
-
| **ModalDialog** | Dialog container (variant/size/layout) | When you need direct control over layout |
|
|
664
|
-
| **ModalClose** | Close (X) button in the top-right corner | When users should be able to close via a button |
|
|
665
|
-
| **ModalOverflow** | Scrollable area | When content exceeds the viewport |
|
|
666
|
-
| **ModalFrame** | Combines ModalDialog + ModalClose + DialogTitle + DialogContent | When you only need a title + close + content (no action buttons) |
|
|
667
|
-
| **DialogTitle** | Header area (styled padding) | When composing manually |
|
|
668
|
-
| **DialogContent** | Body area (styled padding) | When composing manually |
|
|
669
|
-
| **DialogActions** | Footer action button area | When confirm/cancel buttons are needed |
|
|
670
|
-
|
|
671
|
-
## Choosing the Right Component
|
|
672
|
-
|
|
673
|
-
### ModalFrame vs DialogFrame
|
|
674
|
-
|
|
675
|
-
| | ModalFrame | DialogFrame |
|
|
676
|
-
| ------------------ | ----------------------------------------------- | --------------------------------------- |
|
|
677
|
-
| Close (X) button | Built-in | None |
|
|
678
|
-
| Title decorator | `titleStartDecorator` | None |
|
|
679
|
-
| Action button area | None | `actions` prop (required) |
|
|
680
|
-
| Fullscreen | `layout="fullscreen"` | `fullscreen` prop |
|
|
681
|
-
| Best for | Information display, detail views, inline forms | Confirm/cancel dialogs, decision-making |
|
|
682
|
-
|
|
683
|
-
### Use ModalFrame when
|
|
684
|
-
|
|
685
|
-
- You need an informational modal with a close button (detail views, previews)
|
|
686
|
-
- The form's submit button lives inside the content area
|
|
687
|
-
- You need an icon next to the title
|
|
688
|
-
|
|
689
|
-
### Use DialogFrame when
|
|
690
|
-
|
|
691
|
-
- Explicit action buttons (confirm/cancel) must be pinned to the bottom
|
|
692
|
-
- User decisions are required (delete confirmation, save confirmation)
|
|
693
|
-
- Only explicit choices should be allowed without a close (X) button
|
|
694
|
-
|
|
695
|
-
### Use manual composition when
|
|
696
|
-
|
|
697
|
-
- You need a custom layout that doesn't fit the ModalFrame/DialogFrame pattern
|
|
698
|
-
- You want to use both ModalClose and DialogActions together
|
|
699
|
-
|
|
700
487
|
## Props and Customization
|
|
701
488
|
|
|
702
489
|
### Modal Props
|
|
@@ -718,17 +505,6 @@ Modal uses a composition pattern with multiple sub-components:
|
|
|
718
505
|
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Dialog size |
|
|
719
506
|
| `layout` | `'center' \| 'fullscreen'` | `'center'` | Layout mode |
|
|
720
507
|
|
|
721
|
-
### ModalFrame Props
|
|
722
|
-
|
|
723
|
-
| Prop | Type | Default | Description |
|
|
724
|
-
| --------------------- | ------------ | ------- | ------------------------------------------ |
|
|
725
|
-
| `title` | `ReactNode` | - | Title displayed in the header |
|
|
726
|
-
| `children` | `ReactNode` | - | Body content |
|
|
727
|
-
| `titleStartDecorator` | `ReactNode` | - | Icon or element displayed before the title |
|
|
728
|
-
| `onClose` | `() => void` | - | Callback when the close button is clicked |
|
|
729
|
-
|
|
730
|
-
ModalFrame accepts all ModalDialog props (`variant`, `color`, `size`, `layout`, `sx`, etc.).
|
|
731
|
-
|
|
732
508
|
### Custom Styling
|
|
733
509
|
|
|
734
510
|
```tsx
|
|
@@ -767,10 +543,17 @@ Modal components include comprehensive accessibility features:
|
|
|
767
543
|
- `aria-describedby` connects to DialogContent
|
|
768
544
|
|
|
769
545
|
```tsx
|
|
770
|
-
<Modal
|
|
546
|
+
<Modal
|
|
547
|
+
open={open}
|
|
548
|
+
onClose={onClose}
|
|
549
|
+
aria-labelledby="modal-title"
|
|
550
|
+
aria-describedby="modal-description"
|
|
551
|
+
>
|
|
771
552
|
<ModalDialog>
|
|
772
553
|
<DialogTitle id="modal-title">Accessible Title</DialogTitle>
|
|
773
|
-
<DialogContent id="modal-description">
|
|
554
|
+
<DialogContent id="modal-description">
|
|
555
|
+
This content is read by screen readers.
|
|
556
|
+
</DialogContent>
|
|
774
557
|
</ModalDialog>
|
|
775
558
|
</Modal>
|
|
776
559
|
```
|
|
@@ -799,9 +582,7 @@ Modal components include comprehensive accessibility features:
|
|
|
799
582
|
```tsx
|
|
800
583
|
// ✅ Good: Clear action buttons
|
|
801
584
|
<DialogActions>
|
|
802
|
-
<Button variant="solid" color="danger">
|
|
803
|
-
Delete
|
|
804
|
-
</Button>
|
|
585
|
+
<Button variant="solid" color="danger">Delete</Button>
|
|
805
586
|
<Button variant="plain">Cancel</Button>
|
|
806
587
|
</DialogActions>
|
|
807
588
|
```
|
|
@@ -876,11 +657,15 @@ Use `keepMounted` only when the modal needs to preserve state between openings:
|
|
|
876
657
|
Memoize modal content when it depends on complex data:
|
|
877
658
|
|
|
878
659
|
```tsx
|
|
879
|
-
const modalContent = useMemo(() =>
|
|
660
|
+
const modalContent = useMemo(() => (
|
|
661
|
+
<ComplexContent data={data} />
|
|
662
|
+
), [data]);
|
|
880
663
|
|
|
881
664
|
<Modal open={open} onClose={onClose}>
|
|
882
|
-
<ModalDialog>
|
|
883
|
-
|
|
665
|
+
<ModalDialog>
|
|
666
|
+
{modalContent}
|
|
667
|
+
</ModalDialog>
|
|
668
|
+
</Modal>
|
|
884
669
|
```
|
|
885
670
|
|
|
886
671
|
Modal is a powerful component for focused user interactions. Use it thoughtfully to maintain a smooth user experience while capturing important decisions and inputs.
|
|
@@ -49,6 +49,8 @@ export { ProfileMenu } from './ProfileMenu';
|
|
|
49
49
|
export { Radio, RadioGroup } from './Radio';
|
|
50
50
|
export { RadioTileGroup } from './RadioTileGroup';
|
|
51
51
|
export { RadioList } from './RadioList';
|
|
52
|
+
export { SearchBar } from './SearchBar';
|
|
53
|
+
export type { SearchBarOption, SearchBarProps } from './SearchBar';
|
|
52
54
|
export { Select, Option } from './Select';
|
|
53
55
|
export { Sheet } from './Sheet';
|
|
54
56
|
export { Stack } from './Stack';
|