@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.
Files changed (302) hide show
  1. package/README.md +75 -65
  2. package/package.json +11 -5
  3. package/src/atoms/avatar/avatar.md +185 -0
  4. package/src/atoms/avatar/avatar.styles.ts +48 -0
  5. package/src/atoms/avatar/avatar.tsx +99 -0
  6. package/src/atoms/badge/badge.md +237 -0
  7. package/src/atoms/badge/badge.styles.ts +79 -0
  8. package/src/atoms/badge/badge.tsx +86 -0
  9. package/src/atoms/breadcrumb/breadcrumb.md +233 -0
  10. package/src/atoms/breadcrumb/breadcrumb.styles.ts +40 -0
  11. package/src/atoms/breadcrumb/breadcrumb.tsx +130 -0
  12. package/src/atoms/button/button.android.tsx +6 -0
  13. package/src/atoms/button/button.ios.tsx +6 -0
  14. package/src/atoms/button/button.md +184 -0
  15. package/src/atoms/button/button.shared.tsx +79 -0
  16. package/src/atoms/button/button.styles.ts +152 -0
  17. package/src/atoms/button/button.tsx +6 -0
  18. package/src/atoms/button-group/button-group.android.tsx +6 -0
  19. package/src/atoms/button-group/button-group.ios.tsx +6 -0
  20. package/src/atoms/button-group/button-group.md +120 -0
  21. package/src/atoms/button-group/button-group.shared.tsx +398 -0
  22. package/src/atoms/button-group/button-group.styles.ts +483 -0
  23. package/src/atoms/button-group/button-group.tsx +6 -0
  24. package/src/atoms/checkbox/checkbox.android.tsx +6 -0
  25. package/src/atoms/checkbox/checkbox.ios.tsx +6 -0
  26. package/src/atoms/checkbox/checkbox.md +150 -0
  27. package/src/atoms/checkbox/checkbox.shared.tsx +103 -0
  28. package/src/atoms/checkbox/checkbox.styles.ts +106 -0
  29. package/src/atoms/checkbox/checkbox.tsx +6 -0
  30. package/src/atoms/combobox/combobox.android.tsx +6 -0
  31. package/src/atoms/combobox/combobox.ios.tsx +6 -0
  32. package/src/atoms/combobox/combobox.md +213 -0
  33. package/src/atoms/combobox/combobox.shared.tsx +160 -0
  34. package/src/atoms/combobox/combobox.styles.ts +270 -0
  35. package/src/atoms/combobox/combobox.tsx +6 -0
  36. package/src/atoms/divider/divider.md +140 -0
  37. package/src/atoms/divider/divider.styles.ts +35 -0
  38. package/src/atoms/divider/divider.tsx +67 -0
  39. package/src/atoms/dropdown/dropdown.android.tsx +6 -0
  40. package/src/atoms/dropdown/dropdown.ios.tsx +6 -0
  41. package/src/atoms/dropdown/dropdown.md +221 -0
  42. package/src/atoms/dropdown/dropdown.shared.tsx +190 -0
  43. package/src/atoms/dropdown/dropdown.styles.ts +233 -0
  44. package/src/atoms/dropdown/dropdown.tsx +6 -0
  45. package/src/atoms/icon/icon.md +131 -0
  46. package/src/atoms/icon/icon.styles.ts +30 -0
  47. package/src/atoms/icon/icon.tsx +328 -0
  48. package/src/atoms/index.ts +24 -0
  49. package/src/atoms/input/input.android.tsx +6 -0
  50. package/src/atoms/input/input.ios.tsx +6 -0
  51. package/src/atoms/input/input.md +118 -0
  52. package/src/atoms/input/input.shared.tsx +203 -0
  53. package/src/atoms/input/input.styles.ts +286 -0
  54. package/src/atoms/input/input.tsx +6 -0
  55. package/src/atoms/kbd/kbd.md +91 -0
  56. package/src/atoms/kbd/kbd.styles.ts +33 -0
  57. package/src/atoms/kbd/kbd.tsx +27 -0
  58. package/src/atoms/listbox/listbox.md +177 -0
  59. package/src/atoms/listbox/listbox.styles.ts +60 -0
  60. package/src/atoms/listbox/listbox.tsx +113 -0
  61. package/src/atoms/pagination/pagination.android.tsx +6 -0
  62. package/src/atoms/pagination/pagination.ios.tsx +6 -0
  63. package/src/atoms/pagination/pagination.md +133 -0
  64. package/src/atoms/pagination/pagination.shared.tsx +289 -0
  65. package/src/atoms/pagination/pagination.styles.ts +245 -0
  66. package/src/atoms/pagination/pagination.tsx +6 -0
  67. package/src/atoms/popover/popover.android.tsx +8 -0
  68. package/src/atoms/popover/popover.ios.tsx +6 -0
  69. package/src/atoms/popover/popover.md +87 -0
  70. package/src/atoms/popover/popover.shared.tsx +124 -0
  71. package/src/atoms/popover/popover.styles.ts +144 -0
  72. package/src/atoms/popover/popover.tsx +6 -0
  73. package/src/atoms/radio/radio.android.tsx +6 -0
  74. package/src/atoms/radio/radio.ios.tsx +6 -0
  75. package/src/atoms/radio/radio.md +173 -0
  76. package/src/atoms/radio/radio.shared.tsx +98 -0
  77. package/src/atoms/radio/radio.styles.ts +109 -0
  78. package/src/atoms/radio/radio.tsx +6 -0
  79. package/src/atoms/select/select.android.tsx +6 -0
  80. package/src/atoms/select/select.ios.tsx +6 -0
  81. package/src/atoms/select/select.md +156 -0
  82. package/src/atoms/select/select.shared.tsx +143 -0
  83. package/src/atoms/select/select.styles.ts +310 -0
  84. package/src/atoms/select/select.tsx +6 -0
  85. package/src/atoms/skeleton/skeleton.md +135 -0
  86. package/src/atoms/skeleton/skeleton.styles.ts +117 -0
  87. package/src/atoms/skeleton/skeleton.tsx +145 -0
  88. package/src/atoms/spinner/spinner.android.tsx +7 -0
  89. package/src/atoms/spinner/spinner.ios.tsx +7 -0
  90. package/src/atoms/spinner/spinner.md +94 -0
  91. package/src/atoms/spinner/spinner.shared.tsx +92 -0
  92. package/src/atoms/spinner/spinner.styles.tsx +115 -0
  93. package/src/atoms/spinner/spinner.tsx +7 -0
  94. package/src/atoms/switch/switch.android.tsx +6 -0
  95. package/src/atoms/switch/switch.ios.tsx +6 -0
  96. package/src/atoms/switch/switch.md +91 -0
  97. package/src/atoms/switch/switch.shared.tsx +97 -0
  98. package/src/atoms/switch/switch.styles.ts +79 -0
  99. package/src/atoms/switch/switch.tsx +6 -0
  100. package/src/atoms/textarea/textarea.android.tsx +6 -0
  101. package/src/atoms/textarea/textarea.ios.tsx +6 -0
  102. package/src/atoms/textarea/textarea.md +140 -0
  103. package/src/atoms/textarea/textarea.shared.tsx +74 -0
  104. package/src/atoms/textarea/textarea.styles.ts +116 -0
  105. package/src/atoms/textarea/textarea.tsx +6 -0
  106. package/src/atoms/tooltip/tooltip.android.tsx +6 -0
  107. package/src/atoms/tooltip/tooltip.ios.tsx +7 -0
  108. package/src/atoms/tooltip/tooltip.md +122 -0
  109. package/src/atoms/tooltip/tooltip.shared.tsx +113 -0
  110. package/src/atoms/tooltip/tooltip.styles.ts +113 -0
  111. package/src/atoms/tooltip/tooltip.tsx +6 -0
  112. package/src/atoms/typography/typography.md +330 -0
  113. package/src/atoms/typography/typography.styles.ts +95 -0
  114. package/src/atoms/typography/typography.tsx +76 -0
  115. package/src/index.ts +12 -2
  116. package/src/molecules/action-panels/action-panels.md +133 -0
  117. package/src/molecules/action-panels/action-panels.styles.ts +39 -0
  118. package/src/molecules/action-panels/action-panels.tsx +113 -0
  119. package/src/molecules/alert/alert.md +119 -0
  120. package/src/molecules/alert/alert.styles.ts +88 -0
  121. package/src/molecules/alert/alert.tsx +74 -0
  122. package/src/molecules/alert-dialog/alert-dialog.android.tsx +6 -0
  123. package/src/molecules/alert-dialog/alert-dialog.ios.tsx +6 -0
  124. package/src/molecules/alert-dialog/alert-dialog.md +177 -0
  125. package/src/molecules/alert-dialog/alert-dialog.shared.tsx +187 -0
  126. package/src/molecules/alert-dialog/alert-dialog.styles.ts +248 -0
  127. package/src/molecules/alert-dialog/alert-dialog.tsx +6 -0
  128. package/src/molecules/card/card.md +190 -0
  129. package/src/molecules/card/card.styles.ts +67 -0
  130. package/src/molecules/card/card.tsx +176 -0
  131. package/src/molecules/code-block/code-block.md +159 -0
  132. package/src/molecules/code-block/code-block.styles.ts +167 -0
  133. package/src/molecules/code-block/code-block.tsx +176 -0
  134. package/src/molecules/description-lists/description-lists.md +129 -0
  135. package/src/molecules/description-lists/description-lists.styles.ts +102 -0
  136. package/src/molecules/description-lists/description-lists.tsx +133 -0
  137. package/src/molecules/empty-state/empty-state.md +218 -0
  138. package/src/molecules/empty-state/empty-state.styles.ts +63 -0
  139. package/src/molecules/empty-state/empty-state.tsx +77 -0
  140. package/src/molecules/feeds/feeds.md +102 -0
  141. package/src/molecules/feeds/feeds.styles.ts +120 -0
  142. package/src/molecules/feeds/feeds.tsx +167 -0
  143. package/src/molecules/field/field.md +117 -0
  144. package/src/molecules/field/field.styles.ts +85 -0
  145. package/src/molecules/field/field.tsx +175 -0
  146. package/src/molecules/fieldset/fieldset.md +141 -0
  147. package/src/molecules/fieldset/fieldset.styles.ts +79 -0
  148. package/src/molecules/fieldset/fieldset.tsx +182 -0
  149. package/src/molecules/form/form.md +137 -0
  150. package/src/molecules/form/form.styles.ts +39 -0
  151. package/src/molecules/form/form.tsx +246 -0
  152. package/src/molecules/grid-lists/grid-lists.md +114 -0
  153. package/src/molecules/grid-lists/grid-lists.styles.ts +79 -0
  154. package/src/molecules/grid-lists/grid-lists.tsx +157 -0
  155. package/src/molecules/index.ts +16 -0
  156. package/src/molecules/media-objects/media-objects.md +87 -0
  157. package/src/molecules/media-objects/media-objects.styles.ts +94 -0
  158. package/src/molecules/media-objects/media-objects.tsx +128 -0
  159. package/src/molecules/stacked-lists/stacked-lists.md +116 -0
  160. package/src/molecules/stacked-lists/stacked-lists.styles.ts +111 -0
  161. package/src/molecules/stacked-lists/stacked-lists.tsx +195 -0
  162. package/src/molecules/stats/stats.md +166 -0
  163. package/src/molecules/stats/stats.styles.ts +91 -0
  164. package/src/molecules/stats/stats.tsx +88 -0
  165. package/src/organisms/calendar/calendar.android.tsx +6 -0
  166. package/src/organisms/calendar/calendar.ios.tsx +6 -0
  167. package/src/organisms/calendar/calendar.md +114 -0
  168. package/src/organisms/calendar/calendar.shared.tsx +146 -0
  169. package/src/organisms/calendar/calendar.styles.ts +315 -0
  170. package/src/organisms/calendar/calendar.tsx +6 -0
  171. package/src/organisms/charts/charts.md +326 -0
  172. package/src/organisms/charts/charts.styles.ts +135 -0
  173. package/src/organisms/charts/charts.tsx +124 -0
  174. package/src/organisms/command/command.md +117 -0
  175. package/src/organisms/command/command.styles.ts +179 -0
  176. package/src/organisms/command/command.tsx +164 -0
  177. package/src/organisms/data-table/data-table.md +182 -0
  178. package/src/organisms/data-table/data-table.styles.ts +103 -0
  179. package/src/organisms/data-table/data-table.tsx +105 -0
  180. package/src/organisms/dialog/dialog.android.tsx +6 -0
  181. package/src/organisms/dialog/dialog.ios.tsx +6 -0
  182. package/src/organisms/dialog/dialog.md +271 -0
  183. package/src/organisms/dialog/dialog.shared.tsx +230 -0
  184. package/src/organisms/dialog/dialog.styles.ts +272 -0
  185. package/src/organisms/dialog/dialog.tsx +6 -0
  186. package/src/organisms/filter-panel/filter-panel.md +116 -0
  187. package/src/organisms/filter-panel/filter-panel.styles.ts +83 -0
  188. package/src/organisms/filter-panel/filter-panel.tsx +91 -0
  189. package/src/organisms/index.ts +13 -0
  190. package/src/organisms/navbars/navbars.android.tsx +6 -0
  191. package/src/organisms/navbars/navbars.ios.tsx +6 -0
  192. package/src/organisms/navbars/navbars.md +144 -0
  193. package/src/organisms/navbars/navbars.shared.tsx +137 -0
  194. package/src/organisms/navbars/navbars.styles.ts +251 -0
  195. package/src/organisms/navbars/navbars.tsx +6 -0
  196. package/src/organisms/overlays/overlays.android.tsx +6 -0
  197. package/src/organisms/overlays/overlays.ios.tsx +6 -0
  198. package/src/organisms/overlays/overlays.md +123 -0
  199. package/src/organisms/overlays/overlays.shared.tsx +175 -0
  200. package/src/organisms/overlays/overlays.styles.ts +309 -0
  201. package/src/organisms/overlays/overlays.tsx +6 -0
  202. package/src/organisms/row-menu/row-menu.android.tsx +6 -0
  203. package/src/organisms/row-menu/row-menu.ios.tsx +6 -0
  204. package/src/organisms/row-menu/row-menu.md +102 -0
  205. package/src/organisms/row-menu/row-menu.shared.tsx +105 -0
  206. package/src/organisms/row-menu/row-menu.styles.ts +262 -0
  207. package/src/organisms/row-menu/row-menu.tsx +6 -0
  208. package/src/organisms/sidebar/sidebar.android.tsx +6 -0
  209. package/src/organisms/sidebar/sidebar.ios.tsx +6 -0
  210. package/src/organisms/sidebar/sidebar.md +188 -0
  211. package/src/organisms/sidebar/sidebar.shared.tsx +167 -0
  212. package/src/organisms/sidebar/sidebar.styles.ts +262 -0
  213. package/src/organisms/sidebar/sidebar.tsx +6 -0
  214. package/src/organisms/stepper/stepper.android.tsx +6 -0
  215. package/src/organisms/stepper/stepper.ios.tsx +6 -0
  216. package/src/organisms/stepper/stepper.md +150 -0
  217. package/src/organisms/stepper/stepper.shared.tsx +158 -0
  218. package/src/organisms/stepper/stepper.styles.ts +280 -0
  219. package/src/organisms/stepper/stepper.tsx +6 -0
  220. package/src/organisms/tabs/tabs.android.tsx +6 -0
  221. package/src/organisms/tabs/tabs.ios.tsx +6 -0
  222. package/src/organisms/tabs/tabs.md +127 -0
  223. package/src/organisms/tabs/tabs.shared.tsx +281 -0
  224. package/src/organisms/tabs/tabs.styles.ts +398 -0
  225. package/src/organisms/tabs/tabs.tsx +6 -0
  226. package/src/style/color.ts +17 -0
  227. package/src/style/index.ts +14 -0
  228. package/src/style/primitives.ts +26 -0
  229. package/src/style/responsive.ts +45 -0
  230. package/src/style/shadow.ts +21 -0
  231. package/src/style/theme.tsx +56 -0
  232. package/src/style/tokens.ts +487 -0
  233. package/styles/canvas.css +127 -74
  234. package/tsconfig.json +4 -2
  235. package/src/cn.ts +0 -3
  236. package/styles/atoms/avatar.css +0 -22
  237. package/styles/atoms/badge.css +0 -83
  238. package/styles/atoms/breadcrumb.css +0 -35
  239. package/styles/atoms/button-group.css +0 -23
  240. package/styles/atoms/button.css +0 -107
  241. package/styles/atoms/checkbox.css +0 -55
  242. package/styles/atoms/combobox.css +0 -76
  243. package/styles/atoms/dropdown.css +0 -54
  244. package/styles/atoms/icon.css +0 -8
  245. package/styles/atoms/input-group.css +0 -45
  246. package/styles/atoms/input.css +0 -56
  247. package/styles/atoms/kbd.css +0 -15
  248. package/styles/atoms/pagination.css +0 -48
  249. package/styles/atoms/popover.css +0 -14
  250. package/styles/atoms/radio.css +0 -28
  251. package/styles/atoms/select.css +0 -57
  252. package/styles/atoms/separator.css +0 -32
  253. package/styles/atoms/skeleton.css +0 -32
  254. package/styles/atoms/spinner.css +0 -26
  255. package/styles/atoms/switch.css +0 -45
  256. package/styles/atoms/textarea.css +0 -31
  257. package/styles/atoms/tooltip.css +0 -53
  258. package/styles/atoms/typography.css +0 -105
  259. package/styles/base.css +0 -17
  260. package/styles/molecules/alert.css +0 -66
  261. package/styles/molecules/card.css +0 -58
  262. package/styles/molecules/code-block.css +0 -18
  263. package/styles/molecules/empty-state.css +0 -17
  264. package/styles/molecules/field.css +0 -27
  265. package/styles/molecules/form.css +0 -27
  266. package/styles/molecules/page-header.css +0 -52
  267. package/styles/molecules/section-card.css +0 -49
  268. package/styles/molecules/stat-card.css +0 -71
  269. package/styles/molecules/toast.css +0 -95
  270. package/styles/organisms/app-shell.css +0 -46
  271. package/styles/organisms/calendar.css +0 -73
  272. package/styles/organisms/command.css +0 -95
  273. package/styles/organisms/data-table.css +0 -142
  274. package/styles/organisms/dialog.css +0 -72
  275. package/styles/organisms/filter-panel.css +0 -58
  276. package/styles/organisms/row-menu.css +0 -69
  277. package/styles/organisms/sheet.css +0 -70
  278. package/styles/organisms/sidebar.css +0 -146
  279. package/styles/organisms/stepper.css +0 -63
  280. package/styles/organisms/tabs.css +0 -40
  281. package/styles/organisms/topbar.css +0 -24
  282. package/styles/patterns/backdrops.css +0 -35
  283. package/styles/patterns/density.css +0 -66
  284. package/styles/patterns/focus.css +0 -22
  285. package/styles/patterns/glass.css +0 -85
  286. package/styles/patterns/high-contrast.css +0 -70
  287. package/styles/patterns/reduced-motion.css +0 -12
  288. package/styles/patterns/scrollbar.css +0 -10
  289. package/styles/reset.css +0 -89
  290. package/styles/tokens/colors.css +0 -108
  291. package/styles/tokens/motion.css +0 -33
  292. package/styles/tokens/radius.css +0 -10
  293. package/styles/tokens/shadows.css +0 -35
  294. package/styles/tokens/spacing.css +0 -19
  295. package/styles/tokens/typography.css +0 -6
  296. package/styles/tokens/z-index.css +0 -12
  297. package/styles/utilities/display.css +0 -66
  298. package/styles/utilities/flexbox.css +0 -240
  299. package/styles/utilities/gap.css +0 -288
  300. package/styles/utilities/grid.css +0 -138
  301. package/styles/utilities/position.css +0 -78
  302. 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
+ }