@olympusoss/canvas 3.2.1 → 5.0.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 +75 -65
- package/package.json +11 -5
- package/src/atoms/avatar/avatar.md +185 -0
- package/src/atoms/avatar/avatar.styles.ts +48 -0
- package/src/atoms/avatar/avatar.tsx +99 -0
- package/src/atoms/badge/badge.md +237 -0
- package/src/atoms/badge/badge.styles.ts +79 -0
- package/src/atoms/badge/badge.tsx +86 -0
- package/src/atoms/breadcrumb/breadcrumb.md +233 -0
- package/src/atoms/breadcrumb/breadcrumb.styles.ts +40 -0
- package/src/atoms/breadcrumb/breadcrumb.tsx +130 -0
- package/src/atoms/button/button.android.tsx +6 -0
- package/src/atoms/button/button.ios.tsx +6 -0
- package/src/atoms/button/button.md +184 -0
- package/src/atoms/button/button.shared.tsx +79 -0
- package/src/atoms/button/button.styles.ts +152 -0
- package/src/atoms/button/button.tsx +6 -0
- package/src/atoms/button-group/button-group.android.tsx +6 -0
- package/src/atoms/button-group/button-group.ios.tsx +6 -0
- package/src/atoms/button-group/button-group.md +120 -0
- package/src/atoms/button-group/button-group.shared.tsx +398 -0
- package/src/atoms/button-group/button-group.styles.ts +483 -0
- package/src/atoms/button-group/button-group.tsx +6 -0
- package/src/atoms/checkbox/checkbox.android.tsx +6 -0
- package/src/atoms/checkbox/checkbox.ios.tsx +6 -0
- package/src/atoms/checkbox/checkbox.md +150 -0
- package/src/atoms/checkbox/checkbox.shared.tsx +103 -0
- package/src/atoms/checkbox/checkbox.styles.ts +106 -0
- package/src/atoms/checkbox/checkbox.tsx +6 -0
- package/src/atoms/combobox/combobox.android.tsx +6 -0
- package/src/atoms/combobox/combobox.ios.tsx +6 -0
- package/src/atoms/combobox/combobox.md +213 -0
- package/src/atoms/combobox/combobox.shared.tsx +160 -0
- package/src/atoms/combobox/combobox.styles.ts +270 -0
- package/src/atoms/combobox/combobox.tsx +6 -0
- package/src/atoms/divider/divider.md +140 -0
- package/src/atoms/divider/divider.styles.ts +35 -0
- package/src/atoms/divider/divider.tsx +67 -0
- package/src/atoms/dropdown/dropdown.android.tsx +6 -0
- package/src/atoms/dropdown/dropdown.ios.tsx +6 -0
- package/src/atoms/dropdown/dropdown.md +221 -0
- package/src/atoms/dropdown/dropdown.shared.tsx +190 -0
- package/src/atoms/dropdown/dropdown.styles.ts +233 -0
- package/src/atoms/dropdown/dropdown.tsx +6 -0
- package/src/atoms/icon/icon.md +131 -0
- package/src/atoms/icon/icon.styles.ts +30 -0
- package/src/atoms/icon/icon.tsx +328 -0
- package/src/atoms/index.ts +24 -0
- package/src/atoms/input/input.android.tsx +6 -0
- package/src/atoms/input/input.ios.tsx +6 -0
- package/src/atoms/input/input.md +118 -0
- package/src/atoms/input/input.shared.tsx +203 -0
- package/src/atoms/input/input.styles.ts +286 -0
- package/src/atoms/input/input.tsx +6 -0
- package/src/atoms/kbd/kbd.md +91 -0
- package/src/atoms/kbd/kbd.styles.ts +33 -0
- package/src/atoms/kbd/kbd.tsx +27 -0
- package/src/atoms/listbox/listbox.md +177 -0
- package/src/atoms/listbox/listbox.styles.ts +60 -0
- package/src/atoms/listbox/listbox.tsx +113 -0
- package/src/atoms/pagination/pagination.android.tsx +6 -0
- package/src/atoms/pagination/pagination.ios.tsx +6 -0
- package/src/atoms/pagination/pagination.md +133 -0
- package/src/atoms/pagination/pagination.shared.tsx +289 -0
- package/src/atoms/pagination/pagination.styles.ts +245 -0
- package/src/atoms/pagination/pagination.tsx +6 -0
- package/src/atoms/popover/popover.android.tsx +8 -0
- package/src/atoms/popover/popover.ios.tsx +6 -0
- package/src/atoms/popover/popover.md +87 -0
- package/src/atoms/popover/popover.shared.tsx +124 -0
- package/src/atoms/popover/popover.styles.ts +144 -0
- package/src/atoms/popover/popover.tsx +6 -0
- package/src/atoms/radio/radio.android.tsx +6 -0
- package/src/atoms/radio/radio.ios.tsx +6 -0
- package/src/atoms/radio/radio.md +173 -0
- package/src/atoms/radio/radio.shared.tsx +98 -0
- package/src/atoms/radio/radio.styles.ts +109 -0
- package/src/atoms/radio/radio.tsx +6 -0
- package/src/atoms/select/select.android.tsx +6 -0
- package/src/atoms/select/select.ios.tsx +6 -0
- package/src/atoms/select/select.md +156 -0
- package/src/atoms/select/select.shared.tsx +143 -0
- package/src/atoms/select/select.styles.ts +310 -0
- package/src/atoms/select/select.tsx +6 -0
- package/src/atoms/skeleton/skeleton.md +135 -0
- package/src/atoms/skeleton/skeleton.styles.ts +117 -0
- package/src/atoms/skeleton/skeleton.tsx +145 -0
- package/src/atoms/spinner/spinner.android.tsx +7 -0
- package/src/atoms/spinner/spinner.ios.tsx +7 -0
- package/src/atoms/spinner/spinner.md +94 -0
- package/src/atoms/spinner/spinner.shared.tsx +92 -0
- package/src/atoms/spinner/spinner.styles.tsx +115 -0
- package/src/atoms/spinner/spinner.tsx +7 -0
- package/src/atoms/switch/switch.android.tsx +6 -0
- package/src/atoms/switch/switch.ios.tsx +6 -0
- package/src/atoms/switch/switch.md +91 -0
- package/src/atoms/switch/switch.shared.tsx +97 -0
- package/src/atoms/switch/switch.styles.ts +79 -0
- package/src/atoms/switch/switch.tsx +6 -0
- package/src/atoms/textarea/textarea.android.tsx +6 -0
- package/src/atoms/textarea/textarea.ios.tsx +6 -0
- package/src/atoms/textarea/textarea.md +140 -0
- package/src/atoms/textarea/textarea.shared.tsx +74 -0
- package/src/atoms/textarea/textarea.styles.ts +116 -0
- package/src/atoms/textarea/textarea.tsx +6 -0
- package/src/atoms/tooltip/tooltip.android.tsx +6 -0
- package/src/atoms/tooltip/tooltip.ios.tsx +7 -0
- package/src/atoms/tooltip/tooltip.md +122 -0
- package/src/atoms/tooltip/tooltip.shared.tsx +113 -0
- package/src/atoms/tooltip/tooltip.styles.ts +113 -0
- package/src/atoms/tooltip/tooltip.tsx +6 -0
- package/src/atoms/typography/typography.md +330 -0
- package/src/atoms/typography/typography.styles.ts +95 -0
- package/src/atoms/typography/typography.tsx +76 -0
- package/src/index.ts +12 -2
- package/src/molecules/action-panels/action-panels.md +133 -0
- package/src/molecules/action-panels/action-panels.styles.ts +39 -0
- package/src/molecules/action-panels/action-panels.tsx +113 -0
- package/src/molecules/alert/alert.md +119 -0
- package/src/molecules/alert/alert.styles.ts +88 -0
- package/src/molecules/alert/alert.tsx +74 -0
- package/src/molecules/alert-dialog/alert-dialog.android.tsx +6 -0
- package/src/molecules/alert-dialog/alert-dialog.ios.tsx +6 -0
- package/src/molecules/alert-dialog/alert-dialog.md +177 -0
- package/src/molecules/alert-dialog/alert-dialog.shared.tsx +187 -0
- package/src/molecules/alert-dialog/alert-dialog.styles.ts +248 -0
- package/src/molecules/alert-dialog/alert-dialog.tsx +6 -0
- package/src/molecules/card/card.md +190 -0
- package/src/molecules/card/card.styles.ts +67 -0
- package/src/molecules/card/card.tsx +176 -0
- package/src/molecules/code-block/code-block.md +159 -0
- package/src/molecules/code-block/code-block.styles.ts +167 -0
- package/src/molecules/code-block/code-block.tsx +176 -0
- package/src/molecules/description-lists/description-lists.md +129 -0
- package/src/molecules/description-lists/description-lists.styles.ts +102 -0
- package/src/molecules/description-lists/description-lists.tsx +133 -0
- package/src/molecules/empty-state/empty-state.md +218 -0
- package/src/molecules/empty-state/empty-state.styles.ts +63 -0
- package/src/molecules/empty-state/empty-state.tsx +77 -0
- package/src/molecules/feeds/feeds.md +102 -0
- package/src/molecules/feeds/feeds.styles.ts +120 -0
- package/src/molecules/feeds/feeds.tsx +167 -0
- package/src/molecules/field/field.md +117 -0
- package/src/molecules/field/field.styles.ts +85 -0
- package/src/molecules/field/field.tsx +175 -0
- package/src/molecules/fieldset/fieldset.md +141 -0
- package/src/molecules/fieldset/fieldset.styles.ts +79 -0
- package/src/molecules/fieldset/fieldset.tsx +182 -0
- package/src/molecules/form/form.md +137 -0
- package/src/molecules/form/form.styles.ts +39 -0
- package/src/molecules/form/form.tsx +246 -0
- package/src/molecules/grid-lists/grid-lists.md +114 -0
- package/src/molecules/grid-lists/grid-lists.styles.ts +79 -0
- package/src/molecules/grid-lists/grid-lists.tsx +157 -0
- package/src/molecules/index.ts +16 -0
- package/src/molecules/media-objects/media-objects.md +87 -0
- package/src/molecules/media-objects/media-objects.styles.ts +94 -0
- package/src/molecules/media-objects/media-objects.tsx +128 -0
- package/src/molecules/stacked-lists/stacked-lists.md +116 -0
- package/src/molecules/stacked-lists/stacked-lists.styles.ts +111 -0
- package/src/molecules/stacked-lists/stacked-lists.tsx +195 -0
- package/src/molecules/stats/stats.md +166 -0
- package/src/molecules/stats/stats.styles.ts +91 -0
- package/src/molecules/stats/stats.tsx +88 -0
- package/src/organisms/calendar/calendar.android.tsx +6 -0
- package/src/organisms/calendar/calendar.ios.tsx +6 -0
- package/src/organisms/calendar/calendar.md +114 -0
- package/src/organisms/calendar/calendar.shared.tsx +146 -0
- package/src/organisms/calendar/calendar.styles.ts +315 -0
- package/src/organisms/calendar/calendar.tsx +6 -0
- package/src/organisms/charts/charts.md +326 -0
- package/src/organisms/charts/charts.styles.ts +135 -0
- package/src/organisms/charts/charts.tsx +124 -0
- package/src/organisms/command/command.md +117 -0
- package/src/organisms/command/command.styles.ts +179 -0
- package/src/organisms/command/command.tsx +164 -0
- package/src/organisms/data-table/data-table.md +182 -0
- package/src/organisms/data-table/data-table.styles.ts +103 -0
- package/src/organisms/data-table/data-table.tsx +105 -0
- package/src/organisms/dialog/dialog.android.tsx +6 -0
- package/src/organisms/dialog/dialog.ios.tsx +6 -0
- package/src/organisms/dialog/dialog.md +271 -0
- package/src/organisms/dialog/dialog.shared.tsx +230 -0
- package/src/organisms/dialog/dialog.styles.ts +272 -0
- package/src/organisms/dialog/dialog.tsx +6 -0
- package/src/organisms/filter-panel/filter-panel.md +116 -0
- package/src/organisms/filter-panel/filter-panel.styles.ts +83 -0
- package/src/organisms/filter-panel/filter-panel.tsx +91 -0
- package/src/organisms/index.ts +13 -0
- package/src/organisms/navbars/navbars.android.tsx +6 -0
- package/src/organisms/navbars/navbars.ios.tsx +6 -0
- package/src/organisms/navbars/navbars.md +144 -0
- package/src/organisms/navbars/navbars.shared.tsx +137 -0
- package/src/organisms/navbars/navbars.styles.ts +251 -0
- package/src/organisms/navbars/navbars.tsx +6 -0
- package/src/organisms/overlays/overlays.android.tsx +6 -0
- package/src/organisms/overlays/overlays.ios.tsx +6 -0
- package/src/organisms/overlays/overlays.md +123 -0
- package/src/organisms/overlays/overlays.shared.tsx +175 -0
- package/src/organisms/overlays/overlays.styles.ts +309 -0
- package/src/organisms/overlays/overlays.tsx +6 -0
- package/src/organisms/row-menu/row-menu.android.tsx +6 -0
- package/src/organisms/row-menu/row-menu.ios.tsx +6 -0
- package/src/organisms/row-menu/row-menu.md +102 -0
- package/src/organisms/row-menu/row-menu.shared.tsx +105 -0
- package/src/organisms/row-menu/row-menu.styles.ts +262 -0
- package/src/organisms/row-menu/row-menu.tsx +6 -0
- package/src/organisms/sidebar/sidebar.android.tsx +6 -0
- package/src/organisms/sidebar/sidebar.ios.tsx +6 -0
- package/src/organisms/sidebar/sidebar.md +188 -0
- package/src/organisms/sidebar/sidebar.shared.tsx +167 -0
- package/src/organisms/sidebar/sidebar.styles.ts +262 -0
- package/src/organisms/sidebar/sidebar.tsx +6 -0
- package/src/organisms/stepper/stepper.android.tsx +6 -0
- package/src/organisms/stepper/stepper.ios.tsx +6 -0
- package/src/organisms/stepper/stepper.md +150 -0
- package/src/organisms/stepper/stepper.shared.tsx +158 -0
- package/src/organisms/stepper/stepper.styles.ts +280 -0
- package/src/organisms/stepper/stepper.tsx +6 -0
- package/src/organisms/tabs/tabs.android.tsx +6 -0
- package/src/organisms/tabs/tabs.ios.tsx +6 -0
- package/src/organisms/tabs/tabs.md +127 -0
- package/src/organisms/tabs/tabs.shared.tsx +281 -0
- package/src/organisms/tabs/tabs.styles.ts +398 -0
- package/src/organisms/tabs/tabs.tsx +6 -0
- package/src/style/color.ts +17 -0
- package/src/style/index.ts +14 -0
- package/src/style/primitives.ts +26 -0
- package/src/style/responsive.ts +45 -0
- package/src/style/shadow.ts +21 -0
- package/src/style/theme.tsx +56 -0
- package/src/style/tokens.ts +487 -0
- package/styles/canvas.css +127 -74
- package/tsconfig.json +4 -2
- package/src/cn.ts +0 -3
- package/styles/atoms/avatar.css +0 -22
- package/styles/atoms/badge.css +0 -83
- package/styles/atoms/breadcrumb.css +0 -35
- package/styles/atoms/button-group.css +0 -23
- package/styles/atoms/button.css +0 -107
- package/styles/atoms/checkbox.css +0 -55
- package/styles/atoms/combobox.css +0 -76
- package/styles/atoms/dropdown.css +0 -54
- package/styles/atoms/icon.css +0 -8
- package/styles/atoms/input-group.css +0 -45
- package/styles/atoms/input.css +0 -56
- package/styles/atoms/kbd.css +0 -15
- package/styles/atoms/pagination.css +0 -48
- package/styles/atoms/popover.css +0 -14
- package/styles/atoms/radio.css +0 -28
- package/styles/atoms/select.css +0 -57
- package/styles/atoms/separator.css +0 -32
- package/styles/atoms/skeleton.css +0 -32
- package/styles/atoms/spinner.css +0 -26
- package/styles/atoms/switch.css +0 -45
- package/styles/atoms/textarea.css +0 -31
- package/styles/atoms/tooltip.css +0 -53
- package/styles/atoms/typography.css +0 -105
- package/styles/base.css +0 -17
- package/styles/molecules/alert.css +0 -66
- package/styles/molecules/card.css +0 -58
- package/styles/molecules/code-block.css +0 -18
- package/styles/molecules/empty-state.css +0 -17
- package/styles/molecules/field.css +0 -27
- package/styles/molecules/form.css +0 -27
- package/styles/molecules/page-header.css +0 -52
- package/styles/molecules/section-card.css +0 -49
- package/styles/molecules/stat-card.css +0 -71
- package/styles/molecules/toast.css +0 -95
- package/styles/organisms/app-shell.css +0 -46
- package/styles/organisms/calendar.css +0 -73
- package/styles/organisms/command.css +0 -95
- package/styles/organisms/data-table.css +0 -142
- package/styles/organisms/dialog.css +0 -72
- package/styles/organisms/filter-panel.css +0 -58
- package/styles/organisms/row-menu.css +0 -69
- package/styles/organisms/sheet.css +0 -70
- package/styles/organisms/sidebar.css +0 -146
- package/styles/organisms/stepper.css +0 -63
- package/styles/organisms/tabs.css +0 -40
- package/styles/organisms/topbar.css +0 -24
- package/styles/patterns/backdrops.css +0 -35
- package/styles/patterns/density.css +0 -66
- package/styles/patterns/focus.css +0 -22
- package/styles/patterns/glass.css +0 -85
- package/styles/patterns/high-contrast.css +0 -70
- package/styles/patterns/reduced-motion.css +0 -12
- package/styles/patterns/scrollbar.css +0 -10
- package/styles/reset.css +0 -89
- package/styles/tokens/colors.css +0 -108
- package/styles/tokens/motion.css +0 -33
- package/styles/tokens/radius.css +0 -10
- package/styles/tokens/shadows.css +0 -35
- package/styles/tokens/spacing.css +0 -19
- package/styles/tokens/typography.css +0 -6
- package/styles/tokens/z-index.css +0 -12
- package/styles/utilities/display.css +0 -66
- package/styles/utilities/flexbox.css +0 -240
- package/styles/utilities/gap.css +0 -288
- package/styles/utilities/grid.css +0 -138
- package/styles/utilities/position.css +0 -78
- package/styles/utilities/sizing.css +0 -138
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Dialog
|
|
2
|
+
|
|
3
|
+
A modal dialog: a centered panel over a dimmed, blurred backdrop, with a title, an optional description, a body for real content like a form, and right-aligned actions. Use it for a focused task that warrants interrupting the page; reach for the Alert Dialog for a terse yes/no confirmation.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<Dialog
|
|
9
|
+
trigger="Open dialog"
|
|
10
|
+
title="Refund payment"
|
|
11
|
+
description="The refund will be reflected in the customer's bank account within 2 to 3 business days."
|
|
12
|
+
withBody
|
|
13
|
+
confirmLabel="Confirm"
|
|
14
|
+
cancelLabel="Cancel"
|
|
15
|
+
/>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Variants
|
|
19
|
+
|
|
20
|
+
### Size - xs
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<Dialog
|
|
24
|
+
trigger="Open dialog"
|
|
25
|
+
title="Refund payment"
|
|
26
|
+
description="The refund will be reflected in the customer's bank account within 2 to 3 business days."
|
|
27
|
+
withBody
|
|
28
|
+
confirmLabel="Confirm"
|
|
29
|
+
cancelLabel="Cancel"
|
|
30
|
+
xs
|
|
31
|
+
/>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Size - sm
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<Dialog
|
|
38
|
+
trigger="Open dialog"
|
|
39
|
+
title="Refund payment"
|
|
40
|
+
description="The refund will be reflected in the customer's bank account within 2 to 3 business days."
|
|
41
|
+
withBody
|
|
42
|
+
confirmLabel="Confirm"
|
|
43
|
+
cancelLabel="Cancel"
|
|
44
|
+
small
|
|
45
|
+
/>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Size - md
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<Dialog
|
|
52
|
+
trigger="Open dialog"
|
|
53
|
+
title="Refund payment"
|
|
54
|
+
description="The refund will be reflected in the customer's bank account within 2 to 3 business days."
|
|
55
|
+
withBody
|
|
56
|
+
confirmLabel="Confirm"
|
|
57
|
+
cancelLabel="Cancel"
|
|
58
|
+
medium
|
|
59
|
+
/>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Size - xl
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<Dialog
|
|
66
|
+
trigger="Open dialog"
|
|
67
|
+
title="Refund payment"
|
|
68
|
+
description="The refund will be reflected in the customer's bank account within 2 to 3 business days."
|
|
69
|
+
withBody
|
|
70
|
+
confirmLabel="Confirm"
|
|
71
|
+
cancelLabel="Cancel"
|
|
72
|
+
large
|
|
73
|
+
/>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Size - 2xl
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<Dialog
|
|
80
|
+
trigger="Open dialog"
|
|
81
|
+
title="Refund payment"
|
|
82
|
+
description="The refund will be reflected in the customer's bank account within 2 to 3 business days."
|
|
83
|
+
withBody
|
|
84
|
+
confirmLabel="Confirm"
|
|
85
|
+
cancelLabel="Cancel"
|
|
86
|
+
wide
|
|
87
|
+
/>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Destructive action
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Dialog
|
|
94
|
+
trigger="Open dialog"
|
|
95
|
+
title="Refund payment"
|
|
96
|
+
description="The refund will be reflected in the customer's bank account within 2 to 3 business days."
|
|
97
|
+
withBody
|
|
98
|
+
confirmLabel="Refund"
|
|
99
|
+
cancelLabel="Cancel"
|
|
100
|
+
destructive
|
|
101
|
+
/>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Do & Don't
|
|
105
|
+
|
|
106
|
+
### When to use
|
|
107
|
+
|
|
108
|
+
**Do** — Use the Dialog for a focused task with real content, like a short form.
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
<Dialog open large>
|
|
112
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens["popover-foreground"] }}>Edit profile</Text>
|
|
113
|
+
<Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"], marginTop: 8 }}>Update how your name and email appear to teammates.</Text>
|
|
114
|
+
<View style={{ marginTop: 20 }}>
|
|
115
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6 }}>Name</Text>
|
|
116
|
+
<Input value="Ada Lovelace" />
|
|
117
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6, marginTop: 16 }}>Email</Text>
|
|
118
|
+
<Input value="ada@example.com" />
|
|
119
|
+
</View>
|
|
120
|
+
<View style={{ flexDirection: "row", justifyContent: "flex-end", gap: 8, marginTop: 24 }}>
|
|
121
|
+
<Button outline small>Cancel</Button>
|
|
122
|
+
<Button primary small>Save changes</Button>
|
|
123
|
+
</View>
|
|
124
|
+
</Dialog>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Don't** — A bare yes/no question does not need the roomier Dialog; that is what the Alert Dialog is for.
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
<Dialog open title="Delete file?" small destructive confirmLabel="Delete" cancelLabel="Cancel" />
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Description
|
|
134
|
+
|
|
135
|
+
**Do** — Keep the description to one supporting line; link out for the full policy.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
<Dialog open title="Refund payment" description="The refund posts to the original card in 2 to 3 business days." medium confirmLabel="Refund" cancelLabel="Cancel" />
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Don't** — A multi-sentence policy dump in the description buries the task under reading.
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
<Dialog open title="Refund payment" description="Refunds are processed through the original payment method. Depending on the bank, the amount can take 2 to 3 business days to appear. Partial refunds are supported. Once submitted a refund cannot be cancelled, and the payout for this period will be adjusted on your next statement." medium confirmLabel="Refund" cancelLabel="Cancel" />
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Body form
|
|
148
|
+
|
|
149
|
+
**Do** — Keep the body to the few fields the task needs; send long forms to a full page.
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
<Dialog open large>
|
|
153
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens["popover-foreground"] }}>Create project</Text>
|
|
154
|
+
<View style={{ marginTop: 20 }}>
|
|
155
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6 }}>Name</Text>
|
|
156
|
+
<Input placeholder="Acme website" />
|
|
157
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6, marginTop: 16 }}>Key</Text>
|
|
158
|
+
<Input placeholder="ACME" />
|
|
159
|
+
</View>
|
|
160
|
+
<View style={{ flexDirection: "row", justifyContent: "flex-end", gap: 8, marginTop: 24 }}>
|
|
161
|
+
<Button outline small>Cancel</Button>
|
|
162
|
+
<Button primary small>Create</Button>
|
|
163
|
+
</View>
|
|
164
|
+
</Dialog>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Don't** — A seven-field form crammed into a small dialog feels like a page stuffed into a popup.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<Dialog open small>
|
|
171
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens["popover-foreground"] }}>Create project</Text>
|
|
172
|
+
<View style={{ marginTop: 20 }}>
|
|
173
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6 }}>Name</Text>
|
|
174
|
+
<Input />
|
|
175
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6, marginTop: 12 }}>Key</Text>
|
|
176
|
+
<Input />
|
|
177
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6, marginTop: 12 }}>Description</Text>
|
|
178
|
+
<Input />
|
|
179
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6, marginTop: 12 }}>Lead</Text>
|
|
180
|
+
<Input />
|
|
181
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6, marginTop: 12 }}>Team</Text>
|
|
182
|
+
<Input />
|
|
183
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6, marginTop: 12 }}>Visibility</Text>
|
|
184
|
+
<Input />
|
|
185
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6, marginTop: 12 }}>Template</Text>
|
|
186
|
+
<Input />
|
|
187
|
+
</View>
|
|
188
|
+
<View style={{ flexDirection: "row", justifyContent: "flex-end", gap: 8, marginTop: 24 }}>
|
|
189
|
+
<Button outline small>Cancel</Button>
|
|
190
|
+
<Button primary small>Create</Button>
|
|
191
|
+
</View>
|
|
192
|
+
</Dialog>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Actions
|
|
196
|
+
|
|
197
|
+
**Do** — One primary plus quieter secondaries, right-aligned and labeled with their verb.
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
<Dialog open medium>
|
|
201
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens["popover-foreground"] }}>Unsaved changes</Text>
|
|
202
|
+
<Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"], marginTop: 8 }}>You have edits that are not saved.</Text>
|
|
203
|
+
<View style={{ flexDirection: "row", justifyContent: "flex-end", gap: 8, marginTop: 24 }}>
|
|
204
|
+
<Button ghost small>Discard</Button>
|
|
205
|
+
<Button outline small>Keep editing</Button>
|
|
206
|
+
<Button primary small>Save</Button>
|
|
207
|
+
</View>
|
|
208
|
+
</Dialog>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Don't** — Three look-alike primary buttons give no signal about the default, safe choice.
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
<Dialog open medium>
|
|
215
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens["popover-foreground"] }}>Unsaved changes</Text>
|
|
216
|
+
<Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"], marginTop: 8 }}>You have edits that are not saved.</Text>
|
|
217
|
+
<View style={{ flexDirection: "row", justifyContent: "flex-end", gap: 8, marginTop: 24 }}>
|
|
218
|
+
<Button primary small>Save</Button>
|
|
219
|
+
<Button primary small>Discard</Button>
|
|
220
|
+
<Button primary small>Keep editing</Button>
|
|
221
|
+
</View>
|
|
222
|
+
</Dialog>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Destructive action
|
|
226
|
+
|
|
227
|
+
**Do** — Reserve the destructive tone for the irreversible action it names.
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
<Dialog open title="Delete workspace" description="This removes all projects and cannot be undone." medium destructive confirmLabel="Delete" cancelLabel="Cancel" />
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Don't** — A red button on a routine Save trains users to ignore the colour that should mean danger.
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
<Dialog open title="Save changes" description="Update the profile with your edits." medium destructive confirmLabel="Save" cancelLabel="Cancel" />
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Size
|
|
240
|
+
|
|
241
|
+
**Do** — Size the dialog to its content: a single field belongs in xs or sm.
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
<Dialog open small>
|
|
245
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens["popover-foreground"] }}>Rename</Text>
|
|
246
|
+
<View style={{ marginTop: 20 }}>
|
|
247
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6 }}>Name</Text>
|
|
248
|
+
<Input value="Untitled" />
|
|
249
|
+
</View>
|
|
250
|
+
<View style={{ flexDirection: "row", justifyContent: "flex-end", gap: 8, marginTop: 24 }}>
|
|
251
|
+
<Button outline small>Cancel</Button>
|
|
252
|
+
<Button primary small>Save</Button>
|
|
253
|
+
</View>
|
|
254
|
+
</Dialog>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Don't** — A 2xl panel around a single field leaves a vast empty expanse beside the input.
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
<Dialog open wide>
|
|
261
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens["popover-foreground"] }}>Rename</Text>
|
|
262
|
+
<View style={{ marginTop: 20 }}>
|
|
263
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground, marginBottom: 6 }}>Name</Text>
|
|
264
|
+
<Input value="Untitled" />
|
|
265
|
+
</View>
|
|
266
|
+
<View style={{ flexDirection: "row", justifyContent: "flex-end", gap: 8, marginTop: 24 }}>
|
|
267
|
+
<Button outline small>Cancel</Button>
|
|
268
|
+
<Button primary small>Save</Button>
|
|
269
|
+
</View>
|
|
270
|
+
</Dialog>
|
|
271
|
+
```
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { useState, type ReactNode } from "react";
|
|
2
|
+
import { View, Text, Pressable, useTheme, type StyleProp, type ViewStyle } from "../../style/index.js";
|
|
3
|
+
import { Button } from "../../atoms/button/button.js";
|
|
4
|
+
import { Input } from "../../atoms/input/input.js";
|
|
5
|
+
import * as s from "./dialog.styles.js";
|
|
6
|
+
import { type Size, type DialogSkin } from "./dialog.styles.js";
|
|
7
|
+
|
|
8
|
+
// Shared Dialog shell. The structure (an optional trigger plus a modal panel
|
|
9
|
+
// centered over a dimmed backdrop, a title, an optional description, an optional
|
|
10
|
+
// data-driven Amount/Reason form, and a confirm/cancel footer), the public
|
|
11
|
+
// boolean-prop API, the size precedence, the controlled/uncontrolled open state,
|
|
12
|
+
// and the action handlers all live here once. A platform file supplies only its
|
|
13
|
+
// skin (the backdrop dimming, the card shape/fill/border/shadow, the title/body
|
|
14
|
+
// type, and the footer layout) and calls createDialog.
|
|
15
|
+
//
|
|
16
|
+
// In the docs preview the overlay is rendered INLINE: a contained dim backdrop
|
|
17
|
+
// View wraps the centered card, so it reads as a modal within the preview area
|
|
18
|
+
// rather than a full-screen portal that would cover it.
|
|
19
|
+
//
|
|
20
|
+
// Boolean-prop API: one boolean per option, grouped by axis, first-match
|
|
21
|
+
// precedence within an axis (mirrors Button's intentOf). Axes:
|
|
22
|
+
//
|
|
23
|
+
// - Confirm intent: `destructive` renders the confirm action for an irreversible
|
|
24
|
+
// action (a destructive Button on web, the `destructive` red on iOS/Android);
|
|
25
|
+
// omit for the default primary confirm.
|
|
26
|
+
// - Width (pick one): from narrowest to widest, `xs`, `small`, `medium`,
|
|
27
|
+
// `large`, `wide`; omit for the default panel width (one step wider than
|
|
28
|
+
// `medium`). First-match precedence in that order, so a narrower prop wins if
|
|
29
|
+
// more than one is set.
|
|
30
|
+
|
|
31
|
+
export interface DialogProps {
|
|
32
|
+
children?: ReactNode;
|
|
33
|
+
// Content (strings, for the children-less / data-driven case).
|
|
34
|
+
title?: string;
|
|
35
|
+
description?: string;
|
|
36
|
+
// Body: render a short form (Amount + Reason fields) inside the panel for
|
|
37
|
+
// the data-driven case.
|
|
38
|
+
withBody?: boolean;
|
|
39
|
+
// Trigger button label. When set, the dialog renders the button and opens
|
|
40
|
+
// itself on press (uncontrolled). Omit when you drive `open` yourself.
|
|
41
|
+
trigger?: string;
|
|
42
|
+
// Action labels.
|
|
43
|
+
confirmLabel?: string;
|
|
44
|
+
cancelLabel?: string;
|
|
45
|
+
// Controlled open state. Omit for uncontrolled (the trigger opens it).
|
|
46
|
+
open?: boolean;
|
|
47
|
+
// Fired when the open state changes (trigger press, confirm, cancel).
|
|
48
|
+
onOpenChange?: (open: boolean) => void;
|
|
49
|
+
// Confirm intent (default is a primary confirm).
|
|
50
|
+
destructive?: boolean;
|
|
51
|
+
// Width (pick one; default is the standard panel width). First-match
|
|
52
|
+
// precedence: xs, small, medium, large, wide.
|
|
53
|
+
xs?: boolean;
|
|
54
|
+
small?: boolean;
|
|
55
|
+
medium?: boolean;
|
|
56
|
+
large?: boolean;
|
|
57
|
+
wide?: boolean;
|
|
58
|
+
// Action handlers.
|
|
59
|
+
onConfirm?: () => void;
|
|
60
|
+
onCancel?: () => void;
|
|
61
|
+
/** Escape hatch for layout/positioning composition on the panel (mainly width). */
|
|
62
|
+
style?: StyleProp<ViewStyle>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Size precedence when more than one is passed: first match wins.
|
|
66
|
+
function sizeOf(p: DialogProps): Size {
|
|
67
|
+
if (p.xs) return "xs";
|
|
68
|
+
if (p.small) return "small";
|
|
69
|
+
if (p.medium) return "medium";
|
|
70
|
+
if (p.large) return "large";
|
|
71
|
+
if (p.wide) return "wide";
|
|
72
|
+
return "default";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Build a Dialog component from a platform skin. */
|
|
76
|
+
export function createDialog(skin: DialogSkin) {
|
|
77
|
+
return function Dialog(props: DialogProps) {
|
|
78
|
+
const {
|
|
79
|
+
children,
|
|
80
|
+
title,
|
|
81
|
+
description,
|
|
82
|
+
withBody,
|
|
83
|
+
confirmLabel = "Confirm",
|
|
84
|
+
cancelLabel = "Cancel",
|
|
85
|
+
trigger,
|
|
86
|
+
open: openProp,
|
|
87
|
+
onOpenChange,
|
|
88
|
+
destructive,
|
|
89
|
+
onConfirm,
|
|
90
|
+
onCancel,
|
|
91
|
+
style,
|
|
92
|
+
} = props;
|
|
93
|
+
const { tokens } = useTheme();
|
|
94
|
+
|
|
95
|
+
// Uncontrolled by default: the trigger opens the dialog and an action closes
|
|
96
|
+
// it; a controlled `open` prop overrides this.
|
|
97
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
98
|
+
const open = openProp ?? internalOpen;
|
|
99
|
+
const setOpen = (next: boolean) => {
|
|
100
|
+
if (openProp === undefined) setInternalOpen(next);
|
|
101
|
+
onOpenChange?.(next);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const size = sizeOf(props);
|
|
105
|
+
|
|
106
|
+
const confirm = () => {
|
|
107
|
+
onConfirm?.();
|
|
108
|
+
setOpen(false);
|
|
109
|
+
};
|
|
110
|
+
const cancel = () => {
|
|
111
|
+
onCancel?.();
|
|
112
|
+
setOpen(false);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// The confirm/cancel footer. Three platform shapes:
|
|
116
|
+
// - web (footerKind "buttons", no skin.textButton): the outline Cancel +
|
|
117
|
+
// primary/destructive Confirm Button row (verbatim Canvas look).
|
|
118
|
+
// - Android (footerKind "buttons", skin.textButton set): flat text buttons,
|
|
119
|
+
// Cancel then Confirm, brand-indigo, with a ripple.
|
|
120
|
+
// - iOS (footerKind "capsules"): a side-by-side row of capsule buttons, a
|
|
121
|
+
// gray Cancel capsule then a primary (or destructive-red-labeled) Confirm
|
|
122
|
+
// capsule, no dividers; a pressed capsule dims.
|
|
123
|
+
const footer =
|
|
124
|
+
skin.footerKind === "capsules" ? (
|
|
125
|
+
<View style={skin.footer(tokens)}>
|
|
126
|
+
{/* Cancel capsule (gray) on the left, Confirm capsule (indigo, or gray
|
|
127
|
+
with red label when destructive) on the right. */}
|
|
128
|
+
{(
|
|
129
|
+
[
|
|
130
|
+
{ label: cancelLabel, onPress: cancel, confirm: false, dangerous: false },
|
|
131
|
+
{ label: confirmLabel, onPress: confirm, confirm: true, dangerous: !!destructive },
|
|
132
|
+
] as const
|
|
133
|
+
).map((cap, i) => (
|
|
134
|
+
<Pressable
|
|
135
|
+
key={`${cap.label}-${i}`}
|
|
136
|
+
accessibilityRole="button"
|
|
137
|
+
onPress={cap.onPress}
|
|
138
|
+
style={({ pressed }) => [
|
|
139
|
+
skin.capsule != null ? skin.capsule(tokens, cap.confirm, cap.dangerous) : null,
|
|
140
|
+
skin.capsulePressedOpacity != null && pressed ? { opacity: skin.capsulePressedOpacity } : null,
|
|
141
|
+
]}
|
|
142
|
+
>
|
|
143
|
+
{skin.capsuleLabel != null ? (
|
|
144
|
+
<Text style={skin.capsuleLabel(tokens, cap.confirm, cap.dangerous)}>{cap.label}</Text>
|
|
145
|
+
) : null}
|
|
146
|
+
</Pressable>
|
|
147
|
+
))}
|
|
148
|
+
</View>
|
|
149
|
+
) : skin.textButton != null ? (
|
|
150
|
+
<View style={skin.footer(tokens)}>
|
|
151
|
+
{/* Android: flat text buttons, Cancel then Confirm. */}
|
|
152
|
+
<Pressable
|
|
153
|
+
accessibilityRole="button"
|
|
154
|
+
onPress={cancel}
|
|
155
|
+
android_ripple={skin.textButtonRipple ? skin.textButtonRipple(tokens) : undefined}
|
|
156
|
+
style={skin.textButton}
|
|
157
|
+
>
|
|
158
|
+
{skin.textButtonLabel != null ? (
|
|
159
|
+
<Text style={skin.textButtonLabel(tokens, false)}>{cancelLabel}</Text>
|
|
160
|
+
) : null}
|
|
161
|
+
</Pressable>
|
|
162
|
+
<Pressable
|
|
163
|
+
accessibilityRole="button"
|
|
164
|
+
onPress={confirm}
|
|
165
|
+
android_ripple={skin.textButtonRipple ? skin.textButtonRipple(tokens) : undefined}
|
|
166
|
+
style={skin.textButton}
|
|
167
|
+
>
|
|
168
|
+
{skin.textButtonLabel != null ? (
|
|
169
|
+
<Text style={skin.textButtonLabel(tokens, !!destructive)}>{confirmLabel}</Text>
|
|
170
|
+
) : null}
|
|
171
|
+
</Pressable>
|
|
172
|
+
</View>
|
|
173
|
+
) : (
|
|
174
|
+
<View style={skin.footer(tokens)}>
|
|
175
|
+
{/* Web: outline Cancel + primary/destructive Confirm Button row. */}
|
|
176
|
+
<Button outline small onPress={cancel}>
|
|
177
|
+
{cancelLabel}
|
|
178
|
+
</Button>
|
|
179
|
+
{destructive ? (
|
|
180
|
+
<Button destructive small onPress={confirm}>
|
|
181
|
+
{confirmLabel}
|
|
182
|
+
</Button>
|
|
183
|
+
) : (
|
|
184
|
+
<Button primary small onPress={confirm}>
|
|
185
|
+
{confirmLabel}
|
|
186
|
+
</Button>
|
|
187
|
+
)}
|
|
188
|
+
</View>
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
// Optional trigger button plus the modal. The modal is a contained dim
|
|
192
|
+
// backdrop: a centered scrim with presence in the preview (explicit
|
|
193
|
+
// minHeight) so the panel reads as a modal within the area.
|
|
194
|
+
return (
|
|
195
|
+
<View style={s.root}>
|
|
196
|
+
{trigger != null ? (
|
|
197
|
+
<Button outline small onPress={() => setOpen(true)}>
|
|
198
|
+
{trigger}
|
|
199
|
+
</Button>
|
|
200
|
+
) : null}
|
|
201
|
+
{open ? (
|
|
202
|
+
<View style={[trigger != null ? s.backdropTriggerGap : null, s.backdropLayout, skin.backdrop(tokens)]}>
|
|
203
|
+
<View style={[s.cardLayout, skin.card(tokens), s.cardWidth(size), style]}>
|
|
204
|
+
{children != null ? (
|
|
205
|
+
children
|
|
206
|
+
) : (
|
|
207
|
+
<>
|
|
208
|
+
{title != null ? <Text style={skin.title(tokens)}>{title}</Text> : null}
|
|
209
|
+
{description != null ? <Text style={skin.body(tokens)}>{description}</Text> : null}
|
|
210
|
+
{withBody ? (
|
|
211
|
+
<View style={skin.formBody}>
|
|
212
|
+
<Text style={skin.fieldLabel(tokens)}>Amount</Text>
|
|
213
|
+
<View style={skin.amountRow}>
|
|
214
|
+
<Text style={skin.currency(tokens)}>$</Text>
|
|
215
|
+
<Input value="90.00" style={skin.amountInput} />
|
|
216
|
+
</View>
|
|
217
|
+
<Text style={[skin.fieldLabel(tokens), skin.fieldLabelGap]}>Reason</Text>
|
|
218
|
+
<Input placeholder="Duplicate charge" />
|
|
219
|
+
</View>
|
|
220
|
+
) : null}
|
|
221
|
+
{footer}
|
|
222
|
+
</>
|
|
223
|
+
)}
|
|
224
|
+
</View>
|
|
225
|
+
</View>
|
|
226
|
+
) : null}
|
|
227
|
+
</View>
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
}
|