torch-glare 2.5.5 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/bin/index.js +9 -24
- package/dist/bin/index.js.map +1 -1
- package/dist/src/commands/add.d.ts +2 -2
- package/dist/src/commands/add.d.ts.map +1 -1
- package/dist/src/commands/add.js +4 -70
- package/dist/src/commands/add.js.map +1 -1
- package/dist/src/commands/hook.d.ts +5 -4
- package/dist/src/commands/hook.d.ts.map +1 -1
- package/dist/src/commands/hook.js +7 -75
- package/dist/src/commands/hook.js.map +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/layout.d.ts +5 -4
- package/dist/src/commands/layout.d.ts.map +1 -1
- package/dist/src/commands/layout.js +7 -75
- package/dist/src/commands/layout.js.map +1 -1
- package/dist/src/commands/provider.d.ts +5 -4
- package/dist/src/commands/provider.d.ts.map +1 -1
- package/dist/src/commands/provider.js +7 -75
- package/dist/src/commands/provider.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +78 -43
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/commands/utils.d.ts +5 -4
- package/dist/src/commands/utils.d.ts.map +1 -1
- package/dist/src/commands/utils.js +7 -80
- package/dist/src/commands/utils.js.map +1 -1
- package/dist/src/shared/addFromRegistry.d.ts +16 -0
- package/dist/src/shared/addFromRegistry.d.ts.map +1 -0
- package/dist/src/shared/addFromRegistry.js +88 -0
- package/dist/src/shared/addFromRegistry.js.map +1 -0
- package/dist/src/shared/getInstallCommand.d.ts.map +1 -1
- package/dist/src/shared/getInstallCommand.js +5 -0
- package/dist/src/shared/getInstallCommand.js.map +1 -1
- package/dist/src/shared/installDependencies.d.ts +0 -10
- package/dist/src/shared/installDependencies.d.ts.map +1 -1
- package/dist/src/shared/installDependencies.js +0 -17
- package/dist/src/shared/installDependencies.js.map +1 -1
- package/dist/src/shared/installFromPlan.d.ts +7 -5
- package/dist/src/shared/installFromPlan.d.ts.map +1 -1
- package/dist/src/shared/installFromPlan.js +103 -36
- package/dist/src/shared/installFromPlan.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +12 -3
- package/dist/src/shared/loadRegistry.d.ts.map +1 -1
- package/dist/src/shared/loadRegistry.js +19 -20
- package/dist/src/shared/loadRegistry.js.map +1 -1
- package/dist/src/shared/registryClient.d.ts +19 -0
- package/dist/src/shared/registryClient.d.ts.map +1 -0
- package/dist/src/shared/registryClient.js +128 -0
- package/dist/src/shared/registryClient.js.map +1 -0
- package/dist/src/shared/resolveEntry.d.ts +10 -7
- package/dist/src/shared/resolveEntry.d.ts.map +1 -1
- package/dist/src/shared/resolveEntry.js +18 -13
- package/dist/src/shared/resolveEntry.js.map +1 -1
- package/dist/src/shared/suggestOtherCommand.d.ts +7 -1
- package/dist/src/shared/suggestOtherCommand.d.ts.map +1 -1
- package/dist/src/shared/suggestOtherCommand.js +29 -23
- package/dist/src/shared/suggestOtherCommand.js.map +1 -1
- package/dist/src/types/main.d.ts +31 -2
- package/dist/src/types/main.d.ts.map +1 -1
- package/package.json +6 -11
- package/apps/lib/components/ActionButton.tsx +0 -93
- package/apps/lib/components/ActionsGroup.tsx +0 -27
- package/apps/lib/components/AlertDialog.tsx +0 -204
- package/apps/lib/components/Avatar.tsx +0 -46
- package/apps/lib/components/Badge.tsx +0 -250
- package/apps/lib/components/BadgeField.tsx +0 -338
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -317
- package/apps/lib/components/ButtonGroup.tsx +0 -190
- package/apps/lib/components/Calendar.tsx +0 -115
- package/apps/lib/components/Card.tsx +0 -95
- package/apps/lib/components/Checkbox.tsx +0 -42
- package/apps/lib/components/ColorPicker.tsx +0 -441
- package/apps/lib/components/ConclusionHeader.tsx +0 -148
- package/apps/lib/components/ContextMenu.tsx +0 -571
- package/apps/lib/components/CountBadge.tsx +0 -52
- package/apps/lib/components/DataTable.tsx +0 -213
- package/apps/lib/components/DataViews/badge.ts +0 -49
- package/apps/lib/components/DataViews/cell.tsx +0 -324
- package/apps/lib/components/DataViews/context.ts +0 -144
- package/apps/lib/components/DataViews/data-views.tsx +0 -383
- package/apps/lib/components/DataViews/filters/children.tsx +0 -98
- package/apps/lib/components/DataViews/filters/custom.tsx +0 -34
- package/apps/lib/components/DataViews/filters/filters.tsx +0 -157
- package/apps/lib/components/DataViews/filters/index.ts +0 -4
- package/apps/lib/components/DataViews/filters/labelled.tsx +0 -20
- package/apps/lib/components/DataViews/filters/presets.tsx +0 -65
- package/apps/lib/components/DataViews/filters/sync.tsx +0 -35
- package/apps/lib/components/DataViews/filters/values.ts +0 -173
- package/apps/lib/components/DataViews/header.tsx +0 -220
- package/apps/lib/components/DataViews/hooks/index.ts +0 -5
- package/apps/lib/components/DataViews/hooks/useActiveRow.ts +0 -22
- package/apps/lib/components/DataViews/hooks/useControllable.ts +0 -52
- package/apps/lib/components/DataViews/index.ts +0 -84
- package/apps/lib/components/DataViews/panel/columns.tsx +0 -153
- package/apps/lib/components/DataViews/panel/controls.tsx +0 -106
- package/apps/lib/components/DataViews/panel/index.ts +0 -3
- package/apps/lib/components/DataViews/panel/panel.tsx +0 -164
- package/apps/lib/components/DataViews/panel/saved-views.tsx +0 -67
- package/apps/lib/components/DataViews/panel/section.tsx +0 -81
- package/apps/lib/components/DataViews/panel/sort.tsx +0 -42
- package/apps/lib/components/DataViews/panel/tab.tsx +0 -31
- package/apps/lib/components/DataViews/slots.ts +0 -63
- package/apps/lib/components/DataViews/states.tsx +0 -38
- package/apps/lib/components/DataViews/types.ts +0 -510
- package/apps/lib/components/DataViews/views/board-view.tsx +0 -381
- package/apps/lib/components/DataViews/views/card-rows.tsx +0 -36
- package/apps/lib/components/DataViews/views/inbox-view.tsx +0 -260
- package/apps/lib/components/DataViews/views/pane-views.tsx +0 -196
- package/apps/lib/components/DataViews/views/table-view.tsx +0 -493
- package/apps/lib/components/DataViews/views/tree-view.tsx +0 -367
- package/apps/lib/components/DatePicker.tsx +0 -232
- package/apps/lib/components/Dialog.tsx +0 -116
- package/apps/lib/components/Divider.tsx +0 -28
- package/apps/lib/components/Drawer.tsx +0 -420
- package/apps/lib/components/DropdownMenu.tsx +0 -540
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -73
- package/apps/lib/components/FormBuilder/field-kind.ts +0 -28
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +0 -60
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +0 -59
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +0 -11
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +0 -32
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +0 -74
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +0 -163
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +0 -39
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +0 -132
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +0 -109
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +0 -91
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +0 -157
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +0 -67
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +0 -41
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +0 -336
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +0 -213
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +0 -43
- package/apps/lib/components/FormBuilder/fields/countries.ts +0 -303
- package/apps/lib/components/FormBuilder/fields/index.ts +0 -25
- package/apps/lib/components/FormBuilder/form-builder.tsx +0 -198
- package/apps/lib/components/FormBuilder/index.ts +0 -31
- package/apps/lib/components/FormBuilder/numberFormat.ts +0 -16
- package/apps/lib/components/FormBuilder/submit.tsx +0 -47
- package/apps/lib/components/FormBuilder/types.ts +0 -311
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -128
- package/apps/lib/components/FormRenderer/detail.tsx +0 -207
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -297
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -15
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -339
- package/apps/lib/components/FormRenderer/types.ts +0 -78
- package/apps/lib/components/FormSummary.tsx +0 -282
- package/apps/lib/components/HeaderBar.tsx +0 -117
- package/apps/lib/components/ImageAttachment.tsx +0 -209
- package/apps/lib/components/InnerLabelField.tsx +0 -154
- package/apps/lib/components/Input.tsx +0 -224
- package/apps/lib/components/InputField.tsx +0 -147
- package/apps/lib/components/InputOTP.tsx +0 -84
- package/apps/lib/components/Label.tsx +0 -129
- package/apps/lib/components/LabelField.tsx +0 -76
- package/apps/lib/components/LabeledCheckBox.tsx +0 -51
- package/apps/lib/components/LabeledRadio.tsx +0 -51
- package/apps/lib/components/LinkButton.tsx +0 -94
- package/apps/lib/components/LoginButton.tsx +0 -51
- package/apps/lib/components/PasswordLevel.tsx +0 -58
- package/apps/lib/components/Popover.tsx +0 -312
- package/apps/lib/components/ProfileMenu.tsx +0 -85
- package/apps/lib/components/Radio.tsx +0 -59
- package/apps/lib/components/RadioCard.tsx +0 -50
- package/apps/lib/components/ScrollArea.tsx +0 -54
- package/apps/lib/components/SearchField.tsx +0 -62
- package/apps/lib/components/SearchableSelect.tsx +0 -318
- package/apps/lib/components/SearchableTable.tsx +0 -344
- package/apps/lib/components/SearchableTree.tsx +0 -485
- package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
- package/apps/lib/components/SectionBlock.tsx +0 -147
- package/apps/lib/components/Select.tsx +0 -347
- package/apps/lib/components/SimpleSelect.tsx +0 -225
- package/apps/lib/components/Skeleton.tsx +0 -12
- package/apps/lib/components/SlideDatePicker.tsx +0 -253
- package/apps/lib/components/SpinLoading.tsx +0 -174
- package/apps/lib/components/Stepper.tsx +0 -480
- package/apps/lib/components/Switch.tsx +0 -82
- package/apps/lib/components/TabFormItem.tsx +0 -153
- package/apps/lib/components/TabSwitch.tsx +0 -172
- package/apps/lib/components/Table.tsx +0 -610
- package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
- package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
- package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
- package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
- package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
- package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
- package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
- package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
- package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
- package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
- package/apps/lib/components/TextEditor/index.ts +0 -7
- package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
- package/apps/lib/components/Textarea.tsx +0 -117
- package/apps/lib/components/Timeline.tsx +0 -263
- package/apps/lib/components/Toast.tsx +0 -87
- package/apps/lib/components/Toggle.tsx +0 -125
- package/apps/lib/components/ToggleButton.tsx +0 -140
- package/apps/lib/components/Tooltip.tsx +0 -116
- package/apps/lib/components/TransparentLabel.tsx +0 -71
- package/apps/lib/components/TreeDropDown.tsx +0 -115
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
- package/apps/lib/components/TreeFolder/icons.tsx +0 -60
- package/apps/lib/components/TreeFolder/index.ts +0 -24
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
- package/apps/lib/components/TreeFolder/types.ts +0 -77
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
- package/apps/lib/hooks/useActiveTreeItem.ts +0 -58
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
- package/apps/lib/hooks/useIsMobile.ts +0 -21
- package/apps/lib/hooks/useResize.ts +0 -67
- package/apps/lib/hooks/useTagSelection.ts +0 -214
- package/apps/lib/layouts/CNLayout.tsx +0 -372
- package/apps/lib/layouts/DataViewCard.tsx +0 -62
- package/apps/lib/layouts/FieldSection.tsx +0 -91
- package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
- package/apps/lib/providers/ThemeProvider.tsx +0 -84
- package/apps/lib/registry.json +0 -1201
- package/apps/lib/tsconfig.json +0 -9
- package/apps/lib/tsconfig.tsbuildinfo +0 -1
- package/apps/lib/utils/cn.ts +0 -6
- package/apps/lib/utils/color.ts +0 -175
- package/apps/lib/utils/dataViews/path.ts +0 -67
- package/apps/lib/utils/dataViews/query.ts +0 -73
- package/apps/lib/utils/dataViews/types.ts +0 -187
- package/apps/lib/utils/dateFormat.ts +0 -108
- package/apps/lib/utils/resize.ts +0 -31
- package/apps/lib/utils/types.ts +0 -16
- package/docs/BLOCKS.md +0 -129
- package/docs/CHANGELOG-1.1.16.md +0 -108
- package/docs/Cover.png +0 -0
- package/docs/README.md +0 -215
- package/docs/components/action-button.md +0 -638
- package/docs/components/actions-group.md +0 -708
- package/docs/components/alert-dialog.md +0 -920
- package/docs/components/avatar.md +0 -709
- package/docs/components/badge-field.md +0 -712
- package/docs/components/badge.md +0 -301
- package/docs/components/breadcrumb.md +0 -930
- package/docs/components/button-group.md +0 -650
- package/docs/components/button.md +0 -639
- package/docs/components/calendar.md +0 -555
- package/docs/components/card.md +0 -622
- package/docs/components/chart-block-tool.md +0 -129
- package/docs/components/checkbox.md +0 -699
- package/docs/components/cn-layout.md +0 -854
- package/docs/components/color-picker.md +0 -101
- package/docs/components/conclusion-header.md +0 -80
- package/docs/components/context-menu.md +0 -483
- package/docs/components/count-badge.md +0 -560
- package/docs/components/data-table.md +0 -854
- package/docs/components/data-views/backend-response.md +0 -324
- package/docs/components/data-views/examples/a11y-rtl.md +0 -250
- package/docs/components/data-views/examples/api-orders-route.md +0 -130
- package/docs/components/data-views/examples/fields.md +0 -362
- package/docs/components/data-views/examples/filters.md +0 -307
- package/docs/components/data-views/examples/inbox-routing.md +0 -218
- package/docs/components/data-views/examples/index.md +0 -29
- package/docs/components/data-views/examples/overview.md +0 -244
- package/docs/components/data-views/examples/panel.md +0 -212
- package/docs/components/data-views/examples/scale.md +0 -231
- package/docs/components/data-views/examples/server-side.md +0 -210
- package/docs/components/data-views/examples/state.md +0 -250
- package/docs/components/data-views/examples/tree-custom.md +0 -388
- package/docs/components/data-views/examples/view-registry.md +0 -313
- package/docs/components/data-views/examples/views.md +0 -534
- package/docs/components/data-views/guide.md +0 -405
- package/docs/components/data-views/index.md +0 -1495
- package/docs/components/data-views/migration.md +0 -79
- package/docs/components/date-picker.md +0 -857
- package/docs/components/dialog.md +0 -929
- package/docs/components/divider.md +0 -766
- package/docs/components/drawer.md +0 -654
- package/docs/components/dropdown-menu.md +0 -668
- package/docs/components/field-hint.md +0 -898
- package/docs/components/field-section.md +0 -781
- package/docs/components/form-builder.md +0 -276
- package/docs/components/form-renderer.md +0 -326
- package/docs/components/form-summary.md +0 -138
- package/docs/components/form.md +0 -785
- package/docs/components/header-bar.md +0 -188
- package/docs/components/image-attachment.md +0 -906
- package/docs/components/inner-label-field.md +0 -819
- package/docs/components/input-field.md +0 -623
- package/docs/components/input-otp.md +0 -756
- package/docs/components/input.md +0 -634
- package/docs/components/label-field.md +0 -770
- package/docs/components/label.md +0 -761
- package/docs/components/labeled-check-box.md +0 -642
- package/docs/components/labeled-radio.md +0 -796
- package/docs/components/link-button.md +0 -685
- package/docs/components/login-button.md +0 -872
- package/docs/components/password-level.md +0 -803
- package/docs/components/popover.md +0 -649
- package/docs/components/profile-menu.md +0 -656
- package/docs/components/radio-card.md +0 -801
- package/docs/components/radio.md +0 -735
- package/docs/components/scroll-area.md +0 -691
- package/docs/components/search-field.md +0 -702
- package/docs/components/searchable-select.md +0 -368
- package/docs/components/searchable-table.md +0 -438
- package/docs/components/searchable-tree-dialog.md +0 -190
- package/docs/components/searchable-tree.md +0 -200
- package/docs/components/section-block.md +0 -477
- package/docs/components/select.md +0 -709
- package/docs/components/simple-select.md +0 -741
- package/docs/components/skeleton.md +0 -706
- package/docs/components/slide-date-picker.md +0 -837
- package/docs/components/spin-loading.md +0 -696
- package/docs/components/stepper.md +0 -316
- package/docs/components/switch.md +0 -770
- package/docs/components/tab-form-item.md +0 -773
- package/docs/components/tab-switch.md +0 -170
- package/docs/components/table-dnd-wrapper.md +0 -107
- package/docs/components/table.md +0 -1088
- package/docs/components/text-editor.md +0 -735
- package/docs/components/textarea.md +0 -681
- package/docs/components/timeline.md +0 -254
- package/docs/components/toast.md +0 -773
- package/docs/components/toggle-button.md +0 -643
- package/docs/components/toggle.md +0 -882
- package/docs/components/tooltip.md +0 -513
- package/docs/components/transparent-label.md +0 -721
- package/docs/components/tree-drop-down.md +0 -740
- package/docs/components/tree-folder.md +0 -110
- package/docs/components/tree-sub-layout.md +0 -707
- package/docs/explanation/architecture.md +0 -54
- package/docs/explanation/design-system.md +0 -52
- package/docs/how-to/form-and-list-recipes.md +0 -386
- package/docs/how-to/forms-with-form-builder.md +0 -472
- package/docs/how-to/guides.md +0 -1027
- package/docs/migration/changelog.md +0 -54
- package/docs/migration/form-builder-2.5.2.md +0 -113
- package/docs/reference/cli.md +0 -112
- package/docs/reference/components.md +0 -572
- package/docs/reference/hooks.md +0 -1500
- package/docs/reference/providers.md +0 -866
- package/docs/reference/tailwind-plugins.md +0 -942
- package/docs/reference/theme.md +0 -85
- package/docs/reference/types.md +0 -1016
- package/docs/reference/utilities.md +0 -704
- package/docs/tutorials/building-first-form.md +0 -846
- package/docs/tutorials/component-composition.md +0 -882
- package/docs/tutorials/getting-started.md +0 -302
- package/docs/tutorials/theming-basics.md +0 -785
|
@@ -1,929 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Dialog
|
|
3
|
-
description: Modal dialog component with overlay backdrop for displaying content above the main page
|
|
4
|
-
group: Overlays & Dialogs
|
|
5
|
-
keywords: [dialog, modal, overlay, popup, radix-ui, compound-component]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Dialog
|
|
9
|
-
|
|
10
|
-
> A modal dialog component built on Radix UI that displays content in a centered overlay above the main page content. Features smooth animations, backdrop overlay, and keyboard/focus management.
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
15
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npx torch-glare@latest init
|
|
19
|
-
npx torch-glare@latest add Dialog
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`add` also copies any components, hooks, and utilities that `Dialog` depends on.
|
|
23
|
-
|
|
24
|
-
## Import
|
|
25
|
-
|
|
26
|
-
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
27
|
-
|
|
28
|
-
```tsx
|
|
29
|
-
import { Dialog } from "@/components/Dialog";
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Quick Examples
|
|
33
|
-
|
|
34
|
-
### Basic Usage
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/Dialog";
|
|
38
|
-
import { Button } from "@/components/Button";
|
|
39
|
-
|
|
40
|
-
function Example() {
|
|
41
|
-
return (
|
|
42
|
-
<Dialog>
|
|
43
|
-
<DialogTrigger asChild>
|
|
44
|
-
<Button>Open Dialog</Button>
|
|
45
|
-
</DialogTrigger>
|
|
46
|
-
<DialogContent>
|
|
47
|
-
<DialogHeader>
|
|
48
|
-
<DialogTitle>Welcome</DialogTitle>
|
|
49
|
-
<DialogDescription>
|
|
50
|
-
This is a basic dialog example.
|
|
51
|
-
</DialogDescription>
|
|
52
|
-
</DialogHeader>
|
|
53
|
-
</DialogContent>
|
|
54
|
-
</Dialog>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### With Header and Footer
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose } from "@/components/Dialog";
|
|
63
|
-
import { Button } from "@/components/Button";
|
|
64
|
-
|
|
65
|
-
function FormDialog() {
|
|
66
|
-
return (
|
|
67
|
-
<Dialog>
|
|
68
|
-
<DialogTrigger asChild>
|
|
69
|
-
<Button>Edit Profile</Button>
|
|
70
|
-
</DialogTrigger>
|
|
71
|
-
<DialogContent>
|
|
72
|
-
<DialogHeader>
|
|
73
|
-
<DialogTitle>Edit Profile</DialogTitle>
|
|
74
|
-
<DialogDescription>
|
|
75
|
-
Make changes to your profile here.
|
|
76
|
-
</DialogDescription>
|
|
77
|
-
</DialogHeader>
|
|
78
|
-
|
|
79
|
-
{/* Form content */}
|
|
80
|
-
<div className="space-y-4 p-4">
|
|
81
|
-
<input type="text" placeholder="Name" className="w-full p-2 border rounded" />
|
|
82
|
-
<input type="email" placeholder="Email" className="w-full p-2 border rounded" />
|
|
83
|
-
</div>
|
|
84
|
-
|
|
85
|
-
<DialogFooter>
|
|
86
|
-
<DialogClose asChild>
|
|
87
|
-
<Button variant="BluSecStyle">Cancel</Button>
|
|
88
|
-
</DialogClose>
|
|
89
|
-
<Button variant="PrimeStyle">Save Changes</Button>
|
|
90
|
-
</DialogFooter>
|
|
91
|
-
</DialogContent>
|
|
92
|
-
</Dialog>
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Controlled State
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
import { Dialog, DialogTrigger, DialogContent, DialogTitle } from "@/components/Dialog";
|
|
101
|
-
import { useState } from 'react'
|
|
102
|
-
|
|
103
|
-
function ControlledDialog() {
|
|
104
|
-
const [open, setOpen] = useState(false)
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
108
|
-
<DialogTrigger asChild>
|
|
109
|
-
<button>Open</button>
|
|
110
|
-
</DialogTrigger>
|
|
111
|
-
<DialogContent>
|
|
112
|
-
<DialogTitle>Controlled Dialog</DialogTitle>
|
|
113
|
-
<p>This dialog's state is controlled externally.</p>
|
|
114
|
-
<button onClick={() => setOpen(false)}>Close</button>
|
|
115
|
-
</DialogContent>
|
|
116
|
-
</Dialog>
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### With Custom Close Button
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
import { Dialog, DialogTrigger, DialogContent, DialogTitle, DialogCloseButton } from "@/components/Dialog";
|
|
125
|
-
import { ActionButton } from "@/components/ActionButton";
|
|
126
|
-
|
|
127
|
-
function CustomCloseDialog() {
|
|
128
|
-
return (
|
|
129
|
-
<Dialog>
|
|
130
|
-
<DialogTrigger asChild>
|
|
131
|
-
<button>Open</button>
|
|
132
|
-
</DialogTrigger>
|
|
133
|
-
<DialogContent className="relative p-6">
|
|
134
|
-
<DialogCloseButton className="absolute top-4 right-4">
|
|
135
|
-
<ActionButton size="XS" aria-label="Close dialog">
|
|
136
|
-
<i className="ri-close-line" />
|
|
137
|
-
</ActionButton>
|
|
138
|
-
</DialogCloseButton>
|
|
139
|
-
|
|
140
|
-
<DialogTitle>Dialog with Custom Close</DialogTitle>
|
|
141
|
-
<p>Click the X button to close.</p>
|
|
142
|
-
</DialogContent>
|
|
143
|
-
</Dialog>
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Confirmation Dialog
|
|
149
|
-
|
|
150
|
-
```typescript
|
|
151
|
-
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose } from "@/components/Dialog";
|
|
152
|
-
import { Button } from "@/components/Button";
|
|
153
|
-
|
|
154
|
-
function ConfirmationDialog({ onConfirm }: { onConfirm: () => void }) {
|
|
155
|
-
return (
|
|
156
|
-
<Dialog>
|
|
157
|
-
<DialogTrigger asChild>
|
|
158
|
-
<Button variant="RedSecStyle">Delete Account</Button>
|
|
159
|
-
</DialogTrigger>
|
|
160
|
-
<DialogContent>
|
|
161
|
-
<DialogHeader>
|
|
162
|
-
<DialogTitle>Are you absolutely sure?</DialogTitle>
|
|
163
|
-
<DialogDescription>
|
|
164
|
-
This action cannot be undone. This will permanently delete your
|
|
165
|
-
account and remove your data from our servers.
|
|
166
|
-
</DialogDescription>
|
|
167
|
-
</DialogHeader>
|
|
168
|
-
|
|
169
|
-
<DialogFooter>
|
|
170
|
-
<DialogClose asChild>
|
|
171
|
-
<Button variant="BluSecStyle">Cancel</Button>
|
|
172
|
-
</DialogClose>
|
|
173
|
-
<DialogClose asChild>
|
|
174
|
-
<Button variant="RedSecStyle" onClick={onConfirm}>
|
|
175
|
-
Delete Account
|
|
176
|
-
</Button>
|
|
177
|
-
</DialogClose>
|
|
178
|
-
</DialogFooter>
|
|
179
|
-
</DialogContent>
|
|
180
|
-
</Dialog>
|
|
181
|
-
)
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### Nested Form Dialog
|
|
186
|
-
|
|
187
|
-
```typescript
|
|
188
|
-
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription } from "@/components/Dialog";
|
|
189
|
-
import { Button } from "@/components/Button";
|
|
190
|
-
import { Input } from "@/components/Input";
|
|
191
|
-
import { useForm } from 'react-hook-form'
|
|
192
|
-
|
|
193
|
-
interface FormData {
|
|
194
|
-
username: string
|
|
195
|
-
email: string
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function FormDialog() {
|
|
199
|
-
const { register, handleSubmit } = useForm<FormData>()
|
|
200
|
-
|
|
201
|
-
const onSubmit = (data: FormData) => {
|
|
202
|
-
console.log(data)
|
|
203
|
-
// Close dialog after submission
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return (
|
|
207
|
-
<Dialog>
|
|
208
|
-
<DialogTrigger asChild>
|
|
209
|
-
<Button>Sign Up</Button>
|
|
210
|
-
</DialogTrigger>
|
|
211
|
-
<DialogContent>
|
|
212
|
-
<form onSubmit={handleSubmit(onSubmit)}>
|
|
213
|
-
<DialogHeader>
|
|
214
|
-
<DialogTitle>Create Account</DialogTitle>
|
|
215
|
-
<DialogDescription>
|
|
216
|
-
Fill in your details to create a new account.
|
|
217
|
-
</DialogDescription>
|
|
218
|
-
</DialogHeader>
|
|
219
|
-
|
|
220
|
-
<div className="space-y-4 p-4">
|
|
221
|
-
<Input {...register('username')} placeholder="Username" />
|
|
222
|
-
<Input {...register('email')} type="email" placeholder="Email" />
|
|
223
|
-
</div>
|
|
224
|
-
|
|
225
|
-
<DialogFooter>
|
|
226
|
-
<Button type="submit">Create Account</Button>
|
|
227
|
-
</DialogFooter>
|
|
228
|
-
</form>
|
|
229
|
-
</DialogContent>
|
|
230
|
-
</Dialog>
|
|
231
|
-
)
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Content-Heavy Dialog
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/Dialog";
|
|
239
|
-
import { Button } from "@/components/Button";
|
|
240
|
-
import { ScrollArea } from "@/components/ScrollArea";
|
|
241
|
-
|
|
242
|
-
function ContentDialog() {
|
|
243
|
-
return (
|
|
244
|
-
<Dialog>
|
|
245
|
-
<DialogTrigger asChild>
|
|
246
|
-
<Button>Terms & Conditions</Button>
|
|
247
|
-
</DialogTrigger>
|
|
248
|
-
<DialogContent className="max-w-2xl">
|
|
249
|
-
<DialogHeader>
|
|
250
|
-
<DialogTitle>Terms and Conditions</DialogTitle>
|
|
251
|
-
<DialogDescription>
|
|
252
|
-
Please read our terms carefully.
|
|
253
|
-
</DialogDescription>
|
|
254
|
-
</DialogHeader>
|
|
255
|
-
|
|
256
|
-
<ScrollArea className="h-96 p-4">
|
|
257
|
-
<div className="space-y-4">
|
|
258
|
-
<h3 className="font-semibold">1. Acceptance of Terms</h3>
|
|
259
|
-
<p>By accessing our service, you agree to these terms...</p>
|
|
260
|
-
{/* More content */}
|
|
261
|
-
</div>
|
|
262
|
-
</ScrollArea>
|
|
263
|
-
|
|
264
|
-
<DialogFooter>
|
|
265
|
-
<Button>I Agree</Button>
|
|
266
|
-
</DialogFooter>
|
|
267
|
-
</DialogContent>
|
|
268
|
-
</Dialog>
|
|
269
|
-
)
|
|
270
|
-
}
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### Multi-Step Dialog
|
|
274
|
-
|
|
275
|
-
```typescript
|
|
276
|
-
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle } from "@/components/Dialog";
|
|
277
|
-
import { Button } from "@/components/Button";
|
|
278
|
-
import { useState } from 'react'
|
|
279
|
-
|
|
280
|
-
function MultiStepDialog() {
|
|
281
|
-
const [step, setStep] = useState(1)
|
|
282
|
-
|
|
283
|
-
return (
|
|
284
|
-
<Dialog>
|
|
285
|
-
<DialogTrigger asChild>
|
|
286
|
-
<Button>Start Wizard</Button>
|
|
287
|
-
</DialogTrigger>
|
|
288
|
-
<DialogContent>
|
|
289
|
-
<DialogHeader>
|
|
290
|
-
<DialogTitle>Setup Wizard - Step {step}/3</DialogTitle>
|
|
291
|
-
</DialogHeader>
|
|
292
|
-
|
|
293
|
-
<div className="p-4">
|
|
294
|
-
{step === 1 && <div>Step 1: Basic Information</div>}
|
|
295
|
-
{step === 2 && <div>Step 2: Preferences</div>}
|
|
296
|
-
{step === 3 && <div>Step 3: Confirmation</div>}
|
|
297
|
-
</div>
|
|
298
|
-
|
|
299
|
-
<DialogFooter>
|
|
300
|
-
{step > 1 && (
|
|
301
|
-
<Button variant="BluSecStyle" onClick={() => setStep(step - 1)}>
|
|
302
|
-
Back
|
|
303
|
-
</Button>
|
|
304
|
-
)}
|
|
305
|
-
{step < 3 ? (
|
|
306
|
-
<Button onClick={() => setStep(step + 1)}>Next</Button>
|
|
307
|
-
) : (
|
|
308
|
-
<Button>Finish</Button>
|
|
309
|
-
)}
|
|
310
|
-
</DialogFooter>
|
|
311
|
-
</DialogContent>
|
|
312
|
-
</Dialog>
|
|
313
|
-
)
|
|
314
|
-
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### Image Preview Dialog
|
|
318
|
-
|
|
319
|
-
```typescript
|
|
320
|
-
import { Dialog, DialogTrigger, DialogContent } from "@/components/Dialog";
|
|
321
|
-
|
|
322
|
-
function ImageDialog({ src, alt }: { src: string; alt: string }) {
|
|
323
|
-
return (
|
|
324
|
-
<Dialog>
|
|
325
|
-
<DialogTrigger asChild>
|
|
326
|
-
<img
|
|
327
|
-
src={src}
|
|
328
|
-
alt={alt}
|
|
329
|
-
className="w-32 h-32 object-cover cursor-pointer hover:opacity-80"
|
|
330
|
-
/>
|
|
331
|
-
</DialogTrigger>
|
|
332
|
-
<DialogContent className="max-w-4xl bg-transparent border-none shadow-none">
|
|
333
|
-
<img src={src} alt={alt} className="w-full h-auto" />
|
|
334
|
-
</DialogContent>
|
|
335
|
-
</Dialog>
|
|
336
|
-
)
|
|
337
|
-
}
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### Loading State Dialog
|
|
341
|
-
|
|
342
|
-
```typescript
|
|
343
|
-
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle } from "@/components/Dialog";
|
|
344
|
-
import { Button } from "@/components/Button";
|
|
345
|
-
import { SpinLoading } from "@/components/SpinLoading";
|
|
346
|
-
import { useState } from 'react'
|
|
347
|
-
|
|
348
|
-
function LoadingDialog() {
|
|
349
|
-
const [loading, setLoading] = useState(false)
|
|
350
|
-
|
|
351
|
-
const handleAction = async () => {
|
|
352
|
-
setLoading(true)
|
|
353
|
-
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
354
|
-
setLoading(false)
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
return (
|
|
358
|
-
<Dialog>
|
|
359
|
-
<DialogTrigger asChild>
|
|
360
|
-
<Button>Process Data</Button>
|
|
361
|
-
</DialogTrigger>
|
|
362
|
-
<DialogContent>
|
|
363
|
-
<DialogHeader>
|
|
364
|
-
<DialogTitle>Processing...</DialogTitle>
|
|
365
|
-
</DialogHeader>
|
|
366
|
-
|
|
367
|
-
{loading ? (
|
|
368
|
-
<div className="flex items-center justify-center p-8">
|
|
369
|
-
<SpinLoading size="L" />
|
|
370
|
-
</div>
|
|
371
|
-
) : (
|
|
372
|
-
<div className="p-4">
|
|
373
|
-
<p>Click below to start processing.</p>
|
|
374
|
-
<Button onClick={handleAction} className="mt-4">
|
|
375
|
-
Start
|
|
376
|
-
</Button>
|
|
377
|
-
</div>
|
|
378
|
-
)}
|
|
379
|
-
</DialogContent>
|
|
380
|
-
</Dialog>
|
|
381
|
-
)
|
|
382
|
-
}
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
## API Reference
|
|
386
|
-
|
|
387
|
-
### Dialog (Root)
|
|
388
|
-
|
|
389
|
-
| Prop | Type | Default | Description |
|
|
390
|
-
|------|------|---------|-------------|
|
|
391
|
-
| `open` | `boolean` | - | Controlled open state |
|
|
392
|
-
| `onOpenChange` | `(open: boolean) => void` | - | Callback when open state changes |
|
|
393
|
-
| `defaultOpen` | `boolean` | `false` | Uncontrolled default open state |
|
|
394
|
-
| `modal` | `boolean` | `true` | Whether to render as modal (trap focus) |
|
|
395
|
-
|
|
396
|
-
### DialogTrigger
|
|
397
|
-
|
|
398
|
-
| Prop | Type | Default | Description |
|
|
399
|
-
|------|------|---------|-------------|
|
|
400
|
-
| `asChild` | `boolean` | `false` | Render trigger as child element |
|
|
401
|
-
|
|
402
|
-
### DialogContent
|
|
403
|
-
|
|
404
|
-
| Prop | Type | Default | Description |
|
|
405
|
-
|------|------|---------|-------------|
|
|
406
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
407
|
-
| `onEscapeKeyDown` | `(event) => void` | - | Callback when Escape is pressed |
|
|
408
|
-
| `onPointerDownOutside` | `(event) => void` | - | Callback when clicking outside |
|
|
409
|
-
| `onInteractOutside` | `(event) => void` | - | Callback for any outside interaction |
|
|
410
|
-
|
|
411
|
-
### DialogHeader, DialogFooter
|
|
412
|
-
|
|
413
|
-
| Prop | Type | Default | Description |
|
|
414
|
-
|------|------|---------|-------------|
|
|
415
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
416
|
-
|
|
417
|
-
### DialogTitle
|
|
418
|
-
|
|
419
|
-
| Prop | Type | Default | Description |
|
|
420
|
-
|------|------|---------|-------------|
|
|
421
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
422
|
-
| `asChild` | `boolean` | `false` | Render as child element |
|
|
423
|
-
|
|
424
|
-
### DialogDescription
|
|
425
|
-
|
|
426
|
-
| Prop | Type | Default | Description |
|
|
427
|
-
|------|------|---------|-------------|
|
|
428
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
429
|
-
| `asChild` | `boolean` | `false` | Render as child element |
|
|
430
|
-
|
|
431
|
-
### DialogClose
|
|
432
|
-
|
|
433
|
-
| Prop | Type | Default | Description |
|
|
434
|
-
|------|------|---------|-------------|
|
|
435
|
-
| `asChild` | `boolean` | `false` | Render close button as child |
|
|
436
|
-
|
|
437
|
-
### DialogCloseButton
|
|
438
|
-
|
|
439
|
-
| Prop | Type | Default | Description |
|
|
440
|
-
|------|------|---------|-------------|
|
|
441
|
-
| `className` | `string` | - | Additional CSS classes for close button |
|
|
442
|
-
|
|
443
|
-
## TypeScript
|
|
444
|
-
|
|
445
|
-
### Full Type Definitions
|
|
446
|
-
|
|
447
|
-
```typescript
|
|
448
|
-
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
|
449
|
-
|
|
450
|
-
// Root component
|
|
451
|
-
interface DialogProps {
|
|
452
|
-
open?: boolean
|
|
453
|
-
onOpenChange?: (open: boolean) => void
|
|
454
|
-
defaultOpen?: boolean
|
|
455
|
-
modal?: boolean
|
|
456
|
-
children: React.ReactNode
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export const Dialog: React.FC<DialogProps>
|
|
460
|
-
|
|
461
|
-
// Compound components
|
|
462
|
-
export const DialogTrigger: React.ForwardRefExoticComponent<
|
|
463
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>
|
|
464
|
-
>
|
|
465
|
-
|
|
466
|
-
export const DialogContent: React.ForwardRefExoticComponent<
|
|
467
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
|
468
|
-
>
|
|
469
|
-
|
|
470
|
-
export const DialogHeader: React.FC<React.HTMLAttributes<HTMLDivElement>>
|
|
471
|
-
export const DialogFooter: React.FC<React.HTMLAttributes<HTMLDivElement>>
|
|
472
|
-
export const DialogTitle: React.ForwardRefExoticComponent<
|
|
473
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
474
|
-
>
|
|
475
|
-
export const DialogDescription: React.ForwardRefExoticComponent<
|
|
476
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
477
|
-
>
|
|
478
|
-
export const DialogClose: React.ForwardRefExoticComponent<
|
|
479
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>
|
|
480
|
-
>
|
|
481
|
-
export const DialogCloseButton: React.ForwardRefExoticComponent<
|
|
482
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>
|
|
483
|
-
>
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
## Known Limitations & Frontend Patterns
|
|
487
|
-
|
|
488
|
-
### Every Dialog subcomponent ships without panel/typography defaults
|
|
489
|
-
|
|
490
|
-
`DialogContent`, `DialogHeader`, `DialogFooter`, `DialogTitle`, and `DialogDescription` all ship without surfaces, padding, rounded corners, or theme-correct typography. The official "bare" example renders an invisible/transparent panel, and the shipped `DialogTitle` defaults to `text-content-system-global-primary` (a light-on-dark token) which renders white-on-white on the correct light surface.
|
|
491
|
-
|
|
492
|
-
**Critical token corrections** (the previous override was wrong):
|
|
493
|
-
|
|
494
|
-
- The right surface is `bg-background-presentation-body-primary` — NOT `bg-background-presentation-form-base` (form-base is for input field surfaces) and NOT `bg-background-system-action-secondary` (that's a brand-dark inverted action surface).
|
|
495
|
-
- The right title token is `text-content-presentation-global-primary` — NOT `text-content-system-global-primary`.
|
|
496
|
-
- The right description token is `text-content-presentation-global-secondary` — NOT the shipped triple-stack `"text-sm text-muted-foreground text-content-system-global-primary"`.
|
|
497
|
-
|
|
498
|
-
**Production-tested override** — patch `Dialog.tsx` once after `npx torch-glare add Dialog`, then every consumer renders correctly with bare components:
|
|
499
|
-
|
|
500
|
-
```tsx
|
|
501
|
-
"use client";
|
|
502
|
-
|
|
503
|
-
import * as React from "react";
|
|
504
|
-
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
505
|
-
import { cn } from "@/utils/cn";
|
|
506
|
-
|
|
507
|
-
const Dialog = DialogPrimitive.Root;
|
|
508
|
-
const DialogTrigger = DialogPrimitive.Trigger;
|
|
509
|
-
const DialogPortal = DialogPrimitive.Portal;
|
|
510
|
-
|
|
511
|
-
const DialogOverlay = React.forwardRef<
|
|
512
|
-
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
|
513
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
|
514
|
-
>(({ className, ...props }, ref) => (
|
|
515
|
-
<DialogPrimitive.Overlay
|
|
516
|
-
ref={ref}
|
|
517
|
-
className={cn(
|
|
518
|
-
"fixed inset-0 z-50 bg-black/60",
|
|
519
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
520
|
-
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
521
|
-
className,
|
|
522
|
-
)}
|
|
523
|
-
{...props}
|
|
524
|
-
/>
|
|
525
|
-
));
|
|
526
|
-
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
527
|
-
|
|
528
|
-
const DialogContent = React.forwardRef<
|
|
529
|
-
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
530
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
|
531
|
-
>(({ className, children, ...props }, ref) => (
|
|
532
|
-
<DialogPortal>
|
|
533
|
-
<DialogOverlay />
|
|
534
|
-
<DialogPrimitive.Content
|
|
535
|
-
ref={ref}
|
|
536
|
-
className={cn(
|
|
537
|
-
"fixed left-[50%] top-[50%] z-50 translate-x-[-50%] translate-y-[-50%]",
|
|
538
|
-
"flex flex-col items-stretch justify-start",
|
|
539
|
-
"w-[92vw] sm:max-w-lg",
|
|
540
|
-
"bg-background-presentation-body-primary",
|
|
541
|
-
"border border-border-presentation-global-primary",
|
|
542
|
-
"rounded-xl shadow-lg",
|
|
543
|
-
"p-0 gap-0 overflow-hidden",
|
|
544
|
-
"max-h-[90vh]",
|
|
545
|
-
"duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
546
|
-
className,
|
|
547
|
-
)}
|
|
548
|
-
{...props}
|
|
549
|
-
>
|
|
550
|
-
{children}
|
|
551
|
-
</DialogPrimitive.Content>
|
|
552
|
-
</DialogPortal>
|
|
553
|
-
));
|
|
554
|
-
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
555
|
-
|
|
556
|
-
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
557
|
-
<div
|
|
558
|
-
className={cn("flex flex-col space-y-1.5 text-left px-6 pt-5 pb-4", className)}
|
|
559
|
-
{...props}
|
|
560
|
-
/>
|
|
561
|
-
);
|
|
562
|
-
DialogHeader.displayName = "DialogHeader";
|
|
563
|
-
|
|
564
|
-
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
565
|
-
<div
|
|
566
|
-
className={cn("flex flex-row justify-end gap-2 px-6 py-4", className)}
|
|
567
|
-
{...props}
|
|
568
|
-
/>
|
|
569
|
-
);
|
|
570
|
-
DialogFooter.displayName = "DialogFooter";
|
|
571
|
-
|
|
572
|
-
const DialogTitle = React.forwardRef<
|
|
573
|
-
React.ElementRef<typeof DialogPrimitive.Title>,
|
|
574
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
575
|
-
>(({ className, ...props }, ref) => (
|
|
576
|
-
<DialogPrimitive.Title
|
|
577
|
-
ref={ref}
|
|
578
|
-
className={cn(
|
|
579
|
-
"typography-headers-small-semibold text-content-presentation-global-primary",
|
|
580
|
-
className,
|
|
581
|
-
)}
|
|
582
|
-
{...props}
|
|
583
|
-
/>
|
|
584
|
-
));
|
|
585
|
-
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
586
|
-
|
|
587
|
-
const DialogDescription = React.forwardRef<
|
|
588
|
-
React.ElementRef<typeof DialogPrimitive.Description>,
|
|
589
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
590
|
-
>(({ className, ...props }, ref) => (
|
|
591
|
-
<DialogPrimitive.Description
|
|
592
|
-
ref={ref}
|
|
593
|
-
className={cn(
|
|
594
|
-
"typography-body-small-regular text-content-presentation-global-secondary",
|
|
595
|
-
className,
|
|
596
|
-
)}
|
|
597
|
-
{...props}
|
|
598
|
-
/>
|
|
599
|
-
));
|
|
600
|
-
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
601
|
-
|
|
602
|
-
export {
|
|
603
|
-
Dialog,
|
|
604
|
-
DialogTrigger,
|
|
605
|
-
DialogPortal,
|
|
606
|
-
DialogOverlay,
|
|
607
|
-
DialogContent,
|
|
608
|
-
DialogHeader,
|
|
609
|
-
DialogFooter,
|
|
610
|
-
DialogTitle,
|
|
611
|
-
DialogDescription,
|
|
612
|
-
};
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
Critical default decisions, and why:
|
|
616
|
-
|
|
617
|
-
- **`bg-background-presentation-body-primary`** for the panel surface — it's the body-surface token that pairs correctly with `text-content-presentation-global-primary` across all themes. `form-base` and `action-secondary` are wrong choices that the previous version of this doc recommended.
|
|
618
|
-
- **`p-0 gap-0 overflow-hidden`** on `DialogContent` — padding is delegated to `DialogHeader`/`DialogFooter` (and the form body). Keeping the content padding-free lets header/footer touch the rounded corners cleanly.
|
|
619
|
-
- **`DialogHeader` → `flex flex-col space-y-1.5 ... px-6 pt-5 pb-4`** — column layout (NOT `flex justify-between` like the shipped default) so title and description stack with a tight 6 px gap. Padding lives here, not on the content.
|
|
620
|
-
- **`DialogFooter` → `flex flex-row justify-end gap-2 px-6 py-4`** — horizontal on all viewports (NOT `flex-col-reverse sm:flex-row` like the shipped default). The shipped vertical-on-mobile pattern looks broken on narrow phones too.
|
|
621
|
-
- **`w-[92vw] sm:max-w-lg`** — 92 % of viewport on mobile, 512 px max from `sm` up. Override per-dialog with `className="sm:max-w-110"` (440 px) or `sm:max-w-2xl` (672 px) for wider forms.
|
|
622
|
-
|
|
623
|
-
### Form body lives outside the form-padded `DialogFooter`
|
|
624
|
-
|
|
625
|
-
Place the `<form>` between `DialogHeader` and `DialogFooter`, with the footer as a **sibling outside the form** so its padding doesn't compound with the form body's padding. Use `type="button"` + `onClick={handleSubmit(onSubmit)}` on the submit button rather than `type="submit"`:
|
|
626
|
-
|
|
627
|
-
```tsx
|
|
628
|
-
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
629
|
-
<DialogContent className="sm:max-w-110">
|
|
630
|
-
<DialogHeader>
|
|
631
|
-
<DialogTitle>Create Folder</DialogTitle>
|
|
632
|
-
<DialogDescription>Add a new folder.</DialogDescription>
|
|
633
|
-
</DialogHeader>
|
|
634
|
-
|
|
635
|
-
<form className="flex flex-col gap-4 px-6 py-5">
|
|
636
|
-
<LabelField
|
|
637
|
-
label="Folder Name"
|
|
638
|
-
requiredLabel="*"
|
|
639
|
-
{...register("name")}
|
|
640
|
-
className="w-full *:w-full"
|
|
641
|
-
/>
|
|
642
|
-
</form>
|
|
643
|
-
|
|
644
|
-
<DialogFooter>
|
|
645
|
-
<Button type="button" variant="BorderStyle" size="M" onClick={() => onOpenChange(false)}>
|
|
646
|
-
Cancel
|
|
647
|
-
</Button>
|
|
648
|
-
<Button type="button" variant="PrimeStyle" size="M" onClick={handleSubmit(onSubmit)}>
|
|
649
|
-
Create
|
|
650
|
-
</Button>
|
|
651
|
-
</DialogFooter>
|
|
652
|
-
</DialogContent>
|
|
653
|
-
</Dialog>
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
The `px-6 py-5` body padding matches the header/footer's horizontal `px-6` rhythm so the columns line up vertically across the panel.
|
|
657
|
-
|
|
658
|
-
### `DialogTitle` with icon
|
|
659
|
-
|
|
660
|
-
Plain `<DialogTitle>Create Account</DialogTitle>` is fine, but you can pass JSX with an icon for instant entity recognition:
|
|
661
|
-
|
|
662
|
-
```tsx
|
|
663
|
-
<DialogHeader>
|
|
664
|
-
<DialogTitle>
|
|
665
|
-
<div className="flex items-center gap-2">
|
|
666
|
-
<i className="ri-bank-line text-content-presentation-state-information" />
|
|
667
|
-
<span>Create Account</span>
|
|
668
|
-
</div>
|
|
669
|
-
</DialogTitle>
|
|
670
|
-
</DialogHeader>
|
|
671
|
-
```
|
|
672
|
-
|
|
673
|
-
Pick an icon that matches the entity (`ri-bank-line` for accounts, `ri-calendar-line` for fiscal periods, `ri-receipt-line` for vouchers, etc.).
|
|
674
|
-
|
|
675
|
-
## Common Patterns
|
|
676
|
-
|
|
677
|
-
### Alert/Confirmation Pattern
|
|
678
|
-
|
|
679
|
-
```typescript
|
|
680
|
-
import { Dialog, DialogContent, DialogTitle, DialogDescription } from "@/components/Dialog";
|
|
681
|
-
import { Button } from "@/components/Button";
|
|
682
|
-
|
|
683
|
-
function useConfirmDialog() {
|
|
684
|
-
const [open, setOpen] = useState(false)
|
|
685
|
-
const [resolver, setResolver] = useState<((value: boolean) => void) | null>(null)
|
|
686
|
-
|
|
687
|
-
const confirm = () => new Promise<boolean>((resolve) => {
|
|
688
|
-
setOpen(true)
|
|
689
|
-
setResolver(() => resolve)
|
|
690
|
-
})
|
|
691
|
-
|
|
692
|
-
const handleConfirm = (value: boolean) => {
|
|
693
|
-
resolver?.(value)
|
|
694
|
-
setOpen(false)
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
const ConfirmDialog = (
|
|
698
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
699
|
-
<DialogContent>
|
|
700
|
-
<DialogTitle>Confirm Action</DialogTitle>
|
|
701
|
-
<DialogDescription>
|
|
702
|
-
Are you sure you want to proceed?
|
|
703
|
-
</DialogDescription>
|
|
704
|
-
<div className="flex gap-2 mt-4">
|
|
705
|
-
<Button onClick={() => handleConfirm(false)}>Cancel</Button>
|
|
706
|
-
<Button onClick={() => handleConfirm(true)}>Confirm</Button>
|
|
707
|
-
</div>
|
|
708
|
-
</DialogContent>
|
|
709
|
-
</Dialog>
|
|
710
|
-
)
|
|
711
|
-
|
|
712
|
-
return { confirm, ConfirmDialog }
|
|
713
|
-
}
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
### Preventing Close on Outside Click
|
|
717
|
-
|
|
718
|
-
```typescript
|
|
719
|
-
<DialogContent
|
|
720
|
-
onInteractOutside={(e) => {
|
|
721
|
-
e.preventDefault()
|
|
722
|
-
}}
|
|
723
|
-
>
|
|
724
|
-
{/* Content that shouldn't be dismissed */}
|
|
725
|
-
</DialogContent>
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
## Testing
|
|
729
|
-
|
|
730
|
-
### Unit Test Example
|
|
731
|
-
|
|
732
|
-
```typescript
|
|
733
|
-
import { render, screen, fireEvent } from '@testing-library/react'
|
|
734
|
-
import { Dialog, DialogTrigger, DialogContent, DialogTitle } from "@/components/Dialog";
|
|
735
|
-
|
|
736
|
-
describe('Dialog', () => {
|
|
737
|
-
it('opens when trigger is clicked', () => {
|
|
738
|
-
render(
|
|
739
|
-
<Dialog>
|
|
740
|
-
<DialogTrigger>Open</DialogTrigger>
|
|
741
|
-
<DialogContent>
|
|
742
|
-
<DialogTitle>Test Dialog</DialogTitle>
|
|
743
|
-
</DialogContent>
|
|
744
|
-
</Dialog>
|
|
745
|
-
)
|
|
746
|
-
|
|
747
|
-
fireEvent.click(screen.getByText('Open'))
|
|
748
|
-
expect(screen.getByText('Test Dialog')).toBeInTheDocument()
|
|
749
|
-
})
|
|
750
|
-
|
|
751
|
-
it('closes when Escape is pressed', () => {
|
|
752
|
-
render(
|
|
753
|
-
<Dialog defaultOpen>
|
|
754
|
-
<DialogContent>
|
|
755
|
-
<DialogTitle>Test</DialogTitle>
|
|
756
|
-
</DialogContent>
|
|
757
|
-
</Dialog>
|
|
758
|
-
)
|
|
759
|
-
|
|
760
|
-
fireEvent.keyDown(document, { key: 'Escape' })
|
|
761
|
-
expect(screen.queryByText('Test')).not.toBeInTheDocument()
|
|
762
|
-
})
|
|
763
|
-
|
|
764
|
-
it('calls onOpenChange callback', () => {
|
|
765
|
-
const handleChange = jest.fn()
|
|
766
|
-
|
|
767
|
-
render(
|
|
768
|
-
<Dialog onOpenChange={handleChange}>
|
|
769
|
-
<DialogTrigger>Open</DialogTrigger>
|
|
770
|
-
<DialogContent>Content</DialogContent>
|
|
771
|
-
</Dialog>
|
|
772
|
-
)
|
|
773
|
-
|
|
774
|
-
fireEvent.click(screen.getByText('Open'))
|
|
775
|
-
expect(handleChange).toHaveBeenCalledWith(true)
|
|
776
|
-
})
|
|
777
|
-
})
|
|
778
|
-
```
|
|
779
|
-
|
|
780
|
-
## Accessibility
|
|
781
|
-
|
|
782
|
-
- **Keyboard Support**:
|
|
783
|
-
- Escape: Close dialog
|
|
784
|
-
- Tab: Navigate through focusable elements
|
|
785
|
-
- Shift+Tab: Navigate backwards
|
|
786
|
-
- **ARIA Attributes**:
|
|
787
|
-
- `role="dialog"` automatically applied
|
|
788
|
-
- `aria-modal="true"` when modal
|
|
789
|
-
- `aria-labelledby` links to title
|
|
790
|
-
- `aria-describedby` links to description
|
|
791
|
-
- **Focus Management**:
|
|
792
|
-
- Focus trapped within dialog when open
|
|
793
|
-
- Focus returned to trigger on close
|
|
794
|
-
- First focusable element focused on open
|
|
795
|
-
- **Screen Readers**: Dialog announced with title and description
|
|
796
|
-
|
|
797
|
-
### Best Practices for Accessibility
|
|
798
|
-
|
|
799
|
-
```typescript
|
|
800
|
-
// Always provide a title
|
|
801
|
-
<DialogContent>
|
|
802
|
-
<DialogTitle>Dialog Title</DialogTitle> {/* Required */}
|
|
803
|
-
<DialogDescription>Description</DialogDescription> {/* Recommended */}
|
|
804
|
-
</DialogContent>
|
|
805
|
-
|
|
806
|
-
// Use semantic buttons
|
|
807
|
-
<DialogClose asChild>
|
|
808
|
-
<Button aria-label="Close dialog">Close</Button>
|
|
809
|
-
</DialogClose>
|
|
810
|
-
```
|
|
811
|
-
|
|
812
|
-
## Performance
|
|
813
|
-
|
|
814
|
-
| Metric | Value |
|
|
815
|
-
|--------|-------|
|
|
816
|
-
| Bundle size (minified) | ~8kb |
|
|
817
|
-
| Bundle size (gzipped) | ~3kb |
|
|
818
|
-
| Dependencies | @radix-ui/react-dialog (~12kb) |
|
|
819
|
-
| First render | <10ms |
|
|
820
|
-
| Animation duration | 200ms |
|
|
821
|
-
| Tree-shakeable | ✅ |
|
|
822
|
-
|
|
823
|
-
### Performance Tips
|
|
824
|
-
|
|
825
|
-
1. **Lazy load dialog content**: Don't render until opened
|
|
826
|
-
```typescript
|
|
827
|
-
{open && <DialogContent>{/* Heavy content */}</DialogContent>}
|
|
828
|
-
```
|
|
829
|
-
|
|
830
|
-
2. **Use asChild prop**: Avoid extra wrapper elements
|
|
831
|
-
```typescript
|
|
832
|
-
<DialogTrigger asChild>
|
|
833
|
-
<Button>Open</Button>
|
|
834
|
-
</DialogTrigger>
|
|
835
|
-
```
|
|
836
|
-
|
|
837
|
-
## Migration from Other Modals
|
|
838
|
-
|
|
839
|
-
### From Material-UI Dialog
|
|
840
|
-
|
|
841
|
-
```diff
|
|
842
|
-
- import { Dialog, DialogTitle, DialogContent } from '@mui/material'
|
|
843
|
-
+ import { Dialog, DialogTrigger, DialogContent, DialogTitle } from "@/components/Dialog";
|
|
844
|
-
|
|
845
|
-
- <Dialog open={open} onClose={() => setOpen(false)}>
|
|
846
|
-
- <DialogTitle>Title</DialogTitle>
|
|
847
|
-
- <DialogContent>Content</DialogContent>
|
|
848
|
-
- </Dialog>
|
|
849
|
-
|
|
850
|
-
+ <Dialog open={open} onOpenChange={setOpen}>
|
|
851
|
-
+ <DialogContent>
|
|
852
|
-
+ <DialogTitle>Title</DialogTitle>
|
|
853
|
-
+ <div>Content</div>
|
|
854
|
-
+ </DialogContent>
|
|
855
|
-
+ </Dialog>
|
|
856
|
-
```
|
|
857
|
-
|
|
858
|
-
### From Headless UI Dialog
|
|
859
|
-
|
|
860
|
-
```diff
|
|
861
|
-
- import { Dialog } from '@headlessui/react'
|
|
862
|
-
+ import { Dialog, DialogContent, DialogTitle } from "@/components/Dialog";
|
|
863
|
-
|
|
864
|
-
- <Dialog open={open} onClose={setOpen}>
|
|
865
|
-
- <Dialog.Panel>
|
|
866
|
-
- <Dialog.Title>Title</Dialog.Title>
|
|
867
|
-
- Content
|
|
868
|
-
- </Dialog.Panel>
|
|
869
|
-
- </Dialog>
|
|
870
|
-
|
|
871
|
-
+ <Dialog open={open} onOpenChange={setOpen}>
|
|
872
|
-
+ <DialogContent>
|
|
873
|
-
+ <DialogTitle>Title</DialogTitle>
|
|
874
|
-
+ Content
|
|
875
|
-
+ </DialogContent>
|
|
876
|
-
+ </Dialog>
|
|
877
|
-
```
|
|
878
|
-
|
|
879
|
-
## Best Practices
|
|
880
|
-
|
|
881
|
-
1. **Always provide DialogTitle**: Required for accessibility
|
|
882
|
-
```typescript
|
|
883
|
-
<DialogContent>
|
|
884
|
-
<DialogTitle>Required Title</DialogTitle>
|
|
885
|
-
</DialogContent>
|
|
886
|
-
```
|
|
887
|
-
|
|
888
|
-
2. **Use controlled state for complex interactions**
|
|
889
|
-
```typescript
|
|
890
|
-
const [open, setOpen] = useState(false)
|
|
891
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
892
|
-
```
|
|
893
|
-
|
|
894
|
-
3. **Wrap trigger with asChild**: Avoid unnecessary wrappers
|
|
895
|
-
```typescript
|
|
896
|
-
<DialogTrigger asChild>
|
|
897
|
-
<Button>Open</Button>
|
|
898
|
-
</DialogTrigger>
|
|
899
|
-
```
|
|
900
|
-
|
|
901
|
-
4. **Don't nest dialogs**: Use separate dialogs or switch content
|
|
902
|
-
```typescript
|
|
903
|
-
// Avoid: <Dialog><Dialog></Dialog></Dialog>
|
|
904
|
-
// Use: Multiple root-level dialogs with state management
|
|
905
|
-
```
|
|
906
|
-
|
|
907
|
-
5. **Handle loading states**: Show feedback during async operations
|
|
908
|
-
```typescript
|
|
909
|
-
{loading ? <SpinLoading /> : <FormContent />}
|
|
910
|
-
```
|
|
911
|
-
|
|
912
|
-
6. **Provide clear close affordances**: Include close button and cancel option
|
|
913
|
-
```typescript
|
|
914
|
-
<DialogCloseButton>
|
|
915
|
-
<ActionButton aria-label="Close">×</ActionButton>
|
|
916
|
-
</DialogCloseButton>
|
|
917
|
-
```
|
|
918
|
-
|
|
919
|
-
7. **Keep content concise**: Long content should use ScrollArea
|
|
920
|
-
```typescript
|
|
921
|
-
<ScrollArea className="max-h-96">{longContent}</ScrollArea>
|
|
922
|
-
```
|
|
923
|
-
|
|
924
|
-
## Related Components
|
|
925
|
-
|
|
926
|
-
- [AlertDialog](./alert-dialog.md) - Dialog variant for confirmation/alerts
|
|
927
|
-
- [Drawer](./drawer.md) - Bottom sheet alternative to dialog
|
|
928
|
-
- [Popover](./popover.md) - Non-modal overlay for contextual content
|
|
929
|
-
- [Tooltip](./tooltip.md) - Small overlay for hints
|