@cdx-ui/components 0.2.2 → 0.2.4

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 (373) hide show
  1. package/AGENTS.md +24 -0
  2. package/README.md +6 -2
  3. package/coverage.svg +1 -1
  4. package/docs/components/accordion/content.md +538 -0
  5. package/docs/components/alert/content.md +203 -0
  6. package/docs/components/alert-dialog/content.md +319 -0
  7. package/docs/components/avatar/content.md +368 -0
  8. package/docs/components/avatar/design.md +202 -0
  9. package/docs/components/badge/content.md +235 -0
  10. package/docs/components/bottom-sheet/content.md +351 -0
  11. package/docs/components/bottom-sheet/design.md +249 -0
  12. package/docs/components/breadcrumbs/content.md +169 -0
  13. package/docs/components/button/content.md +398 -0
  14. package/docs/components/button/design.md +258 -0
  15. package/docs/components/calendar/content.md +137 -0
  16. package/docs/components/card/content.md +283 -0
  17. package/docs/components/carousel/content.md +416 -0
  18. package/docs/components/checkbox/content.md +236 -0
  19. package/docs/components/checkbox/design.md +214 -0
  20. package/docs/components/chip/content.md +439 -0
  21. package/docs/components/chip/design.md +418 -0
  22. package/docs/components/color-area/content.md +86 -0
  23. package/docs/components/color-field/content.md +134 -0
  24. package/docs/components/color-picker/content.md +208 -0
  25. package/docs/components/color-slider/content.md +120 -0
  26. package/docs/components/color-swatch/content.md +64 -0
  27. package/docs/components/color-swatch-picker/content.md +126 -0
  28. package/docs/components/content.md +97 -0
  29. package/docs/components/currency-input/content.md +205 -0
  30. package/docs/components/data-grid/content.md +522 -0
  31. package/docs/components/date-field/content.md +147 -0
  32. package/docs/components/date-picker/content.md +360 -0
  33. package/docs/components/date-range-picker/content.md +301 -0
  34. package/docs/components/date-time-field/content.md +157 -0
  35. package/docs/components/date-time-list/content.md +105 -0
  36. package/docs/components/date-time-picker/content.md +272 -0
  37. package/docs/components/dialog/content.md +436 -0
  38. package/docs/components/dialog/design.md +192 -0
  39. package/docs/components/divider/content.md +112 -0
  40. package/docs/components/drawer/content.md +436 -0
  41. package/docs/components/field/content.md +277 -0
  42. package/docs/components/form/content.md +62 -0
  43. package/docs/components/full-screen-dialog/content.md +881 -0
  44. package/docs/components/heading/content.md +55 -0
  45. package/docs/components/icon/content.md +190 -0
  46. package/docs/components/icon-button/content.md +200 -0
  47. package/docs/components/icon-button/design.md +165 -0
  48. package/docs/components/image/content.md +104 -0
  49. package/docs/components/input/content.md +281 -0
  50. package/docs/components/input/design.md +389 -0
  51. package/docs/components/insurance-disclosure/content.md +103 -0
  52. package/docs/components/link/content.md +180 -0
  53. package/docs/components/link/design.md +160 -0
  54. package/docs/components/list-item/content.md +695 -0
  55. package/docs/components/menu/content.md +1247 -0
  56. package/docs/components/month-calendar/content.md +84 -0
  57. package/docs/components/month-picker/content.md +273 -0
  58. package/docs/components/otp-input/content.md +327 -0
  59. package/docs/components/progress-bar/content.md +87 -0
  60. package/docs/components/progress-circle/content.md +176 -0
  61. package/docs/components/progress-segmented/content.md +119 -0
  62. package/docs/components/quick-action-button/content.md +154 -0
  63. package/docs/components/quick-action-button/design.md +170 -0
  64. package/docs/components/radio/content.md +224 -0
  65. package/docs/components/range-calendar/content.md +123 -0
  66. package/docs/components/reorderable-list/content.md +309 -0
  67. package/docs/components/scoped-theme/content.md +47 -0
  68. package/docs/components/scroll-shadow/content.md +686 -0
  69. package/docs/components/select/content.md +400 -0
  70. package/docs/components/select/design.md +301 -0
  71. package/docs/components/skeleton/content.md +103 -0
  72. package/docs/components/slider/content.md +423 -0
  73. package/docs/components/stack/content.md +161 -0
  74. package/docs/components/switch/content.md +150 -0
  75. package/docs/components/switch/design.md +208 -0
  76. package/docs/components/table/content.md +548 -0
  77. package/docs/components/table-pagination/content.md +177 -0
  78. package/docs/components/tabs/content.md +292 -0
  79. package/docs/components/text/content.md +142 -0
  80. package/docs/components/textarea/content.md +222 -0
  81. package/docs/components/tile/content.md +703 -0
  82. package/docs/components/toast/content.md +456 -0
  83. package/docs/components/toggle-button/content.md +505 -0
  84. package/docs/components/tooltip/content.md +350 -0
  85. package/docs/components/virtualized-list/content.md +250 -0
  86. package/docs/foundations/content.md +9 -0
  87. package/docs/foundations/expressions/icons/content.md +19 -0
  88. package/docs/foundations/styles/tokens/all-tokens/content.md +192 -0
  89. package/docs/foundations/styles/tokens/what-are-tokens/content.md +33 -0
  90. package/docs/foundations/styles/tokens/what-are-tokens/design.md +33 -0
  91. package/docs/getting-started/content.md +4 -0
  92. package/docs/getting-started/designers/content.md +13 -0
  93. package/docs/getting-started/designers/design.md +13 -0
  94. package/docs/getting-started/developers/accessibility/content.md +31 -0
  95. package/docs/getting-started/developers/content.md +612 -0
  96. package/docs/getting-started/developers/styling/content.md +193 -0
  97. package/docs/llms.txt +193 -0
  98. package/docs/patterns/account-management/content.md +75 -0
  99. package/docs/patterns/authentication/content.md +52 -0
  100. package/docs/patterns/content.md +10 -0
  101. package/docs/patterns/dashboard/content.md +39 -0
  102. package/docs/patterns/empty-states/content.md +31 -0
  103. package/docs/patterns/forms/content.md +109 -0
  104. package/docs/patterns/onboarding/content.md +69 -0
  105. package/docs/patterns/payments/content.md +35 -0
  106. package/docs/patterns/settings/content.md +72 -0
  107. package/docs/resources/content.md +9 -0
  108. package/docs/resources/figma-libraries/content.md +42 -0
  109. package/docs/resources/release-notes/0.0.1-beta.118/content.md +27 -0
  110. package/docs/resources/release-notes/0.0.1-beta.122/content.md +21 -0
  111. package/docs/resources/release-notes/0.0.1-beta.124/content.md +16 -0
  112. package/docs/resources/release-notes/0.0.1-beta.126/content.md +10 -0
  113. package/docs/resources/release-notes/0.0.1-beta.127/content.md +14 -0
  114. package/docs/resources/release-notes/0.0.1-beta.128/content.md +9 -0
  115. package/docs/resources/release-notes/0.0.1-beta.129/content.md +18 -0
  116. package/docs/resources/release-notes/0.0.1-beta.130/content.md +18 -0
  117. package/docs/resources/release-notes/0.0.1-beta.133/content.md +7 -0
  118. package/docs/resources/release-notes/0.0.1-beta.134/content.md +17 -0
  119. package/docs/resources/release-notes/0.0.1-beta.136/content.md +7 -0
  120. package/docs/resources/release-notes/0.0.1-beta.137/content.md +10 -0
  121. package/docs/resources/release-notes/0.0.1-beta.138/content.md +7 -0
  122. package/docs/resources/release-notes/0.0.1-beta.139/content.md +13 -0
  123. package/docs/resources/release-notes/0.0.1-beta.140/content.md +26 -0
  124. package/docs/resources/release-notes/0.0.1-beta.141/content.md +63 -0
  125. package/docs/resources/release-notes/0.0.1-beta.142/content.md +7 -0
  126. package/docs/resources/release-notes/0.0.1-beta.143/content.md +12 -0
  127. package/docs/resources/release-notes/0.0.1-beta.144/content.md +7 -0
  128. package/docs/resources/release-notes/0.0.1-beta.145/content.md +7 -0
  129. package/docs/resources/release-notes/0.0.1-beta.147/content.md +10 -0
  130. package/docs/resources/release-notes/0.0.1-beta.149/content.md +10 -0
  131. package/docs/resources/release-notes/0.0.1-beta.150/content.md +13 -0
  132. package/docs/resources/release-notes/0.0.1-beta.152/content.md +7 -0
  133. package/docs/resources/release-notes/0.0.1-beta.154/content.md +15 -0
  134. package/docs/resources/release-notes/0.0.1-beta.156/content.md +7 -0
  135. package/docs/resources/release-notes/0.0.1-beta.158/content.md +9 -0
  136. package/docs/resources/release-notes/0.0.1-beta.159/content.md +11 -0
  137. package/docs/resources/release-notes/0.0.1-beta.160/content.md +7 -0
  138. package/docs/resources/release-notes/0.0.1-beta.161/content.md +7 -0
  139. package/docs/resources/release-notes/0.0.1-beta.163/content.md +7 -0
  140. package/docs/resources/release-notes/0.0.1-beta.164/content.md +9 -0
  141. package/docs/resources/release-notes/0.0.1-beta.166/content.md +17 -0
  142. package/docs/resources/release-notes/0.0.1-beta.167/content.md +7 -0
  143. package/docs/resources/release-notes/0.0.1-beta.168/content.md +7 -0
  144. package/docs/resources/release-notes/0.0.1-beta.169/content.md +7 -0
  145. package/docs/resources/release-notes/0.0.1-beta.171/content.md +16 -0
  146. package/docs/resources/release-notes/0.0.1-beta.172/content.md +24 -0
  147. package/docs/resources/release-notes/0.0.1-beta.173/content.md +15 -0
  148. package/docs/resources/release-notes/0.0.1-beta.174/content.md +7 -0
  149. package/docs/resources/release-notes/0.0.1-beta.176/content.md +32 -0
  150. package/docs/resources/release-notes/0.0.1-beta.179/content.md +11 -0
  151. package/docs/resources/release-notes/0.0.1-beta.182/content.md +13 -0
  152. package/docs/resources/release-notes/0.0.1-beta.185/content.md +7 -0
  153. package/docs/resources/release-notes/0.0.1-beta.187/content.md +27 -0
  154. package/docs/resources/release-notes/0.1.1/content.md +23 -0
  155. package/docs/resources/release-notes/0.1.2/content.md +7 -0
  156. package/docs/resources/release-notes/0.1.4/content.md +19 -0
  157. package/docs/resources/release-notes/0.1.5/content.md +7 -0
  158. package/docs/resources/release-notes/0.1.6/content.md +7 -0
  159. package/docs/resources/release-notes/0.2.0/content.md +31 -0
  160. package/docs/resources/release-notes/0.2.1/content.md +17 -0
  161. package/docs/resources/release-notes/0.2.2/content.md +11 -0
  162. package/docs/resources/release-notes/0.2.3/content.md +15 -0
  163. package/docs/resources/release-notes/content.md +64 -0
  164. package/lib/commonjs/components/Checkbox/index.js.map +1 -1
  165. package/lib/commonjs/components/DateTimeList/index.js +11 -26
  166. package/lib/commonjs/components/DateTimeList/index.js.map +1 -1
  167. package/lib/commonjs/components/DateTimeList/styles.js +2 -12
  168. package/lib/commonjs/components/DateTimeList/styles.js.map +1 -1
  169. package/lib/commonjs/components/Heading/index.js.map +1 -1
  170. package/lib/commonjs/components/Icon/index.js.map +1 -1
  171. package/lib/commonjs/components/ListItem/index.js +170 -9
  172. package/lib/commonjs/components/ListItem/index.js.map +1 -1
  173. package/lib/commonjs/components/ListItem/styles.js +38 -2
  174. package/lib/commonjs/components/ListItem/styles.js.map +1 -1
  175. package/lib/commonjs/components/Menu/index.js +11 -5
  176. package/lib/commonjs/components/Menu/index.js.map +1 -1
  177. package/lib/commonjs/components/RangeCalendar/index.js.map +1 -1
  178. package/lib/commonjs/components/ReorderableList/ReorderableListShared.js +91 -0
  179. package/lib/commonjs/components/ReorderableList/ReorderableListShared.js.map +1 -0
  180. package/lib/commonjs/components/ReorderableList/index.js +135 -0
  181. package/lib/commonjs/components/ReorderableList/index.js.map +1 -0
  182. package/lib/commonjs/components/ReorderableList/index.web.js +233 -0
  183. package/lib/commonjs/components/ReorderableList/index.web.js.map +1 -0
  184. package/lib/commonjs/components/ReorderableList/labels.js +47 -0
  185. package/lib/commonjs/components/ReorderableList/labels.js.map +1 -0
  186. package/lib/commonjs/components/ReorderableList/reorderItems.js +16 -0
  187. package/lib/commonjs/components/ReorderableList/reorderItems.js.map +1 -0
  188. package/lib/commonjs/components/ReorderableList/rowContext.js +42 -0
  189. package/lib/commonjs/components/ReorderableList/rowContext.js.map +1 -0
  190. package/lib/commonjs/components/ReorderableList/types.js +6 -0
  191. package/lib/commonjs/components/ReorderableList/types.js.map +1 -0
  192. package/lib/commonjs/components/ReorderableList/useReorder.js +131 -0
  193. package/lib/commonjs/components/ReorderableList/useReorder.js.map +1 -0
  194. package/lib/commonjs/components/ReorderableList/webDnd.js +64 -0
  195. package/lib/commonjs/components/ReorderableList/webDnd.js.map +1 -0
  196. package/lib/commonjs/components/ScopedTheme/index.js.map +1 -1
  197. package/lib/commonjs/components/ScrollShadow/gradient.js +29 -0
  198. package/lib/commonjs/components/ScrollShadow/gradient.js.map +1 -0
  199. package/lib/commonjs/components/ScrollShadow/index.js +171 -44
  200. package/lib/commonjs/components/ScrollShadow/index.js.map +1 -1
  201. package/lib/commonjs/components/ScrollShadow/styles.js +58 -14
  202. package/lib/commonjs/components/ScrollShadow/styles.js.map +1 -1
  203. package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js +63 -0
  204. package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
  205. package/lib/commonjs/components/ScrollShadow/useScrollShadow.js +48 -8
  206. package/lib/commonjs/components/ScrollShadow/useScrollShadow.js.map +1 -1
  207. package/lib/commonjs/components/Skeleton/index.js.map +1 -1
  208. package/lib/commonjs/components/TablePagination/index.js.map +1 -1
  209. package/lib/commonjs/components/Tabs/index.js +16 -23
  210. package/lib/commonjs/components/Tabs/index.js.map +1 -1
  211. package/lib/commonjs/components/Tabs/styles.js +1 -10
  212. package/lib/commonjs/components/Tabs/styles.js.map +1 -1
  213. package/lib/commonjs/components/Text/index.js.map +1 -1
  214. package/lib/commonjs/components/Tile/styles.js +1 -1
  215. package/lib/commonjs/components/Tile/styles.js.map +1 -1
  216. package/lib/commonjs/components/index.js.map +1 -1
  217. package/lib/commonjs/figma/ListItem.SectionHeader.figma.js +20 -5
  218. package/lib/commonjs/figma/ListItem.SectionHeader.figma.js.map +1 -1
  219. package/lib/commonjs/reorderable-list.js +17 -0
  220. package/lib/commonjs/reorderable-list.js.map +1 -0
  221. package/lib/module/components/Checkbox/index.js.map +1 -1
  222. package/lib/module/components/DateTimeList/index.js +12 -27
  223. package/lib/module/components/DateTimeList/index.js.map +1 -1
  224. package/lib/module/components/DateTimeList/styles.js +1 -11
  225. package/lib/module/components/DateTimeList/styles.js.map +1 -1
  226. package/lib/module/components/Heading/index.js.map +1 -1
  227. package/lib/module/components/Icon/index.js.map +1 -1
  228. package/lib/module/components/ListItem/index.js +163 -14
  229. package/lib/module/components/ListItem/index.js.map +1 -1
  230. package/lib/module/components/ListItem/styles.js +37 -1
  231. package/lib/module/components/ListItem/styles.js.map +1 -1
  232. package/lib/module/components/Menu/index.js +11 -5
  233. package/lib/module/components/Menu/index.js.map +1 -1
  234. package/lib/module/components/RangeCalendar/index.js.map +1 -1
  235. package/lib/module/components/ReorderableList/ReorderableListShared.js +86 -0
  236. package/lib/module/components/ReorderableList/ReorderableListShared.js.map +1 -0
  237. package/lib/module/components/ReorderableList/index.js +130 -0
  238. package/lib/module/components/ReorderableList/index.js.map +1 -0
  239. package/lib/module/components/ReorderableList/index.web.js +229 -0
  240. package/lib/module/components/ReorderableList/index.web.js.map +1 -0
  241. package/lib/module/components/ReorderableList/labels.js +41 -0
  242. package/lib/module/components/ReorderableList/labels.js.map +1 -0
  243. package/lib/module/components/ReorderableList/reorderItems.js +12 -0
  244. package/lib/module/components/ReorderableList/reorderItems.js.map +1 -0
  245. package/lib/module/components/ReorderableList/rowContext.js +38 -0
  246. package/lib/module/components/ReorderableList/rowContext.js.map +1 -0
  247. package/lib/module/components/ReorderableList/types.js +4 -0
  248. package/lib/module/components/ReorderableList/types.js.map +1 -0
  249. package/lib/module/components/ReorderableList/useReorder.js +123 -0
  250. package/lib/module/components/ReorderableList/useReorder.js.map +1 -0
  251. package/lib/module/components/ReorderableList/webDnd.js +59 -0
  252. package/lib/module/components/ReorderableList/webDnd.js.map +1 -0
  253. package/lib/module/components/ScopedTheme/index.js.map +1 -1
  254. package/lib/module/components/ScrollShadow/gradient.js +24 -0
  255. package/lib/module/components/ScrollShadow/gradient.js.map +1 -0
  256. package/lib/module/components/ScrollShadow/index.js +170 -48
  257. package/lib/module/components/ScrollShadow/index.js.map +1 -1
  258. package/lib/module/components/ScrollShadow/styles.js +57 -13
  259. package/lib/module/components/ScrollShadow/styles.js.map +1 -1
  260. package/lib/module/components/ScrollShadow/useComposedScrollHandler.js +57 -0
  261. package/lib/module/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
  262. package/lib/module/components/ScrollShadow/useScrollShadow.js +46 -8
  263. package/lib/module/components/ScrollShadow/useScrollShadow.js.map +1 -1
  264. package/lib/module/components/Skeleton/index.js.map +1 -1
  265. package/lib/module/components/TablePagination/index.js.map +1 -1
  266. package/lib/module/components/Tabs/index.js +17 -24
  267. package/lib/module/components/Tabs/index.js.map +1 -1
  268. package/lib/module/components/Tabs/styles.js +0 -9
  269. package/lib/module/components/Tabs/styles.js.map +1 -1
  270. package/lib/module/components/Text/index.js.map +1 -1
  271. package/lib/module/components/Tile/styles.js +1 -1
  272. package/lib/module/components/Tile/styles.js.map +1 -1
  273. package/lib/module/components/index.js.map +1 -1
  274. package/lib/module/figma/ListItem.SectionHeader.figma.js +20 -5
  275. package/lib/module/figma/ListItem.SectionHeader.figma.js.map +1 -1
  276. package/lib/module/reorderable-list.js +4 -0
  277. package/lib/module/reorderable-list.js.map +1 -0
  278. package/lib/typescript/components/Checkbox/index.d.ts +22 -0
  279. package/lib/typescript/components/Checkbox/index.d.ts.map +1 -1
  280. package/lib/typescript/components/DateTimeList/index.d.ts.map +1 -1
  281. package/lib/typescript/components/DateTimeList/styles.d.ts +1 -4
  282. package/lib/typescript/components/DateTimeList/styles.d.ts.map +1 -1
  283. package/lib/typescript/components/Heading/index.d.ts +20 -2
  284. package/lib/typescript/components/Heading/index.d.ts.map +1 -1
  285. package/lib/typescript/components/Icon/index.d.ts +2 -0
  286. package/lib/typescript/components/Icon/index.d.ts.map +1 -1
  287. package/lib/typescript/components/ListItem/index.d.ts +28 -5
  288. package/lib/typescript/components/ListItem/index.d.ts.map +1 -1
  289. package/lib/typescript/components/ListItem/styles.d.ts +6 -1
  290. package/lib/typescript/components/ListItem/styles.d.ts.map +1 -1
  291. package/lib/typescript/components/Menu/index.d.ts +116 -4
  292. package/lib/typescript/components/Menu/index.d.ts.map +1 -1
  293. package/lib/typescript/components/RangeCalendar/index.d.ts +2 -0
  294. package/lib/typescript/components/RangeCalendar/index.d.ts.map +1 -1
  295. package/lib/typescript/components/ReorderableList/ReorderableListShared.d.ts +31 -0
  296. package/lib/typescript/components/ReorderableList/ReorderableListShared.d.ts.map +1 -0
  297. package/lib/typescript/components/ReorderableList/index.d.ts +8 -0
  298. package/lib/typescript/components/ReorderableList/index.d.ts.map +1 -0
  299. package/lib/typescript/components/ReorderableList/index.web.d.ts +8 -0
  300. package/lib/typescript/components/ReorderableList/index.web.d.ts.map +1 -0
  301. package/lib/typescript/components/ReorderableList/labels.d.ts +16 -0
  302. package/lib/typescript/components/ReorderableList/labels.d.ts.map +1 -0
  303. package/lib/typescript/components/ReorderableList/reorderItems.d.ts +3 -0
  304. package/lib/typescript/components/ReorderableList/reorderItems.d.ts.map +1 -0
  305. package/lib/typescript/components/ReorderableList/rowContext.d.ts +57 -0
  306. package/lib/typescript/components/ReorderableList/rowContext.d.ts.map +1 -0
  307. package/lib/typescript/components/ReorderableList/types.d.ts +75 -0
  308. package/lib/typescript/components/ReorderableList/types.d.ts.map +1 -0
  309. package/lib/typescript/components/ReorderableList/useReorder.d.ts +31 -0
  310. package/lib/typescript/components/ReorderableList/useReorder.d.ts.map +1 -0
  311. package/lib/typescript/components/ReorderableList/webDnd.d.ts +27 -0
  312. package/lib/typescript/components/ReorderableList/webDnd.d.ts.map +1 -0
  313. package/lib/typescript/components/ScopedTheme/index.d.ts +6 -1
  314. package/lib/typescript/components/ScopedTheme/index.d.ts.map +1 -1
  315. package/lib/typescript/components/ScrollShadow/gradient.d.ts +7 -0
  316. package/lib/typescript/components/ScrollShadow/gradient.d.ts.map +1 -0
  317. package/lib/typescript/components/ScrollShadow/index.d.ts +57 -15
  318. package/lib/typescript/components/ScrollShadow/index.d.ts.map +1 -1
  319. package/lib/typescript/components/ScrollShadow/styles.d.ts +8 -2
  320. package/lib/typescript/components/ScrollShadow/styles.d.ts.map +1 -1
  321. package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts +13 -0
  322. package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts.map +1 -0
  323. package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts +15 -2
  324. package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts.map +1 -1
  325. package/lib/typescript/components/Skeleton/index.d.ts +3 -0
  326. package/lib/typescript/components/Skeleton/index.d.ts.map +1 -1
  327. package/lib/typescript/components/TablePagination/index.d.ts +54 -0
  328. package/lib/typescript/components/TablePagination/index.d.ts.map +1 -1
  329. package/lib/typescript/components/Tabs/index.d.ts.map +1 -1
  330. package/lib/typescript/components/Tabs/styles.d.ts +0 -7
  331. package/lib/typescript/components/Tabs/styles.d.ts.map +1 -1
  332. package/lib/typescript/components/Text/index.d.ts +12 -2
  333. package/lib/typescript/components/Text/index.d.ts.map +1 -1
  334. package/lib/typescript/components/Tile/styles.d.ts.map +1 -1
  335. package/lib/typescript/components/ToggleButton/styles.d.ts +1 -1
  336. package/lib/typescript/components/index.d.ts +1 -0
  337. package/lib/typescript/components/index.d.ts.map +1 -1
  338. package/lib/typescript/figma/ListItem.SectionHeader.figma.d.ts.map +1 -1
  339. package/lib/typescript/reorderable-list.d.ts +2 -0
  340. package/lib/typescript/reorderable-list.d.ts.map +1 -0
  341. package/package.json +37 -8
  342. package/src/components/Checkbox/index.tsx +22 -0
  343. package/src/components/DateTimeList/index.tsx +13 -26
  344. package/src/components/DateTimeList/styles.ts +1 -10
  345. package/src/components/Heading/index.tsx +10 -1
  346. package/src/components/Icon/index.tsx +2 -0
  347. package/src/components/ListItem/index.tsx +232 -15
  348. package/src/components/ListItem/styles.ts +41 -0
  349. package/src/components/Menu/index.tsx +128 -12
  350. package/src/components/RangeCalendar/index.tsx +2 -0
  351. package/src/components/ReorderableList/ReorderableListShared.tsx +113 -0
  352. package/src/components/ReorderableList/index.tsx +162 -0
  353. package/src/components/ReorderableList/index.web.tsx +254 -0
  354. package/src/components/ReorderableList/labels.ts +52 -0
  355. package/src/components/ReorderableList/reorderItems.ts +16 -0
  356. package/src/components/ReorderableList/rowContext.tsx +72 -0
  357. package/src/components/ReorderableList/types.ts +80 -0
  358. package/src/components/ReorderableList/useReorder.ts +159 -0
  359. package/src/components/ReorderableList/webDnd.ts +60 -0
  360. package/src/components/ScopedTheme/index.tsx +6 -1
  361. package/src/components/ScrollShadow/gradient.ts +48 -0
  362. package/src/components/ScrollShadow/index.tsx +300 -69
  363. package/src/components/ScrollShadow/styles.ts +45 -28
  364. package/src/components/ScrollShadow/useComposedScrollHandler.ts +58 -0
  365. package/src/components/ScrollShadow/useScrollShadow.ts +72 -10
  366. package/src/components/Skeleton/index.tsx +3 -0
  367. package/src/components/TablePagination/index.tsx +54 -0
  368. package/src/components/Tabs/index.tsx +25 -35
  369. package/src/components/Tabs/styles.ts +0 -9
  370. package/src/components/Text/index.tsx +6 -1
  371. package/src/components/Tile/styles.ts +4 -1
  372. package/src/components/index.ts +5 -0
  373. package/src/reorderable-list.ts +1 -0
@@ -0,0 +1,881 @@
1
+ # Full Screen Dialog (https://design.candescent.com/docs/components/full-screen-dialog)
2
+
3
+ Resources: [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/overlays-fullscreendialog--default)
4
+
5
+ A compound modal that presents a task as a full page. It shares the dialog's open state, focus trapping, and dismissal, and adds a back / title / close header. Bottom sheets, menus, selects, and picker popovers opened from it appear on top.
6
+
7
+ ```tsx
8
+ import { Button, FullScreenDialog } from '@cdx-ui/components';
9
+ ```
10
+
11
+ > [!NOTE]
12
+ >
13
+ > **Portal host**
14
+ >
15
+ > `ForgeDesignProvider` mounts the shared portal host automatically. If you do not use the
16
+ > provider, mount one `PortalHost` from `@cdx-ui/primitives` near your app root. On web, to keep
17
+ > the dialog inside an embedded surface such as a device preview, wrap that surface in
18
+ > `PortalProvider` and give its `PortalHost` a `container` element inside it; the fixed overlay
19
+ > stays inside only when an ancestor of the container sets a `transform`.
20
+
21
+ ## Basic
22
+
23
+ Put a `ScrollView` inside `FullScreenDialog.Content` so the body scrolls under a fixed header. The header's close button closes the dialog unless you pass `onClose`. The popup always covers the viewport; on wide screens, add `w-full max-w-md self-center` to the header and content to keep the page at a phone reading width.
24
+
25
+ ```tsx
26
+ import { useState } from 'react';
27
+ import { Box, Button, FullScreenDialog, ScrollView, Text } from '@cdx-ui/components';
28
+
29
+ const details = [
30
+ { label: 'From', value: 'Everyday Checking •••• 4642' },
31
+ { label: 'To', value: 'High-yield Savings •••• 5541' },
32
+ { label: 'Amount', value: '$250.00' },
33
+ { label: 'Frequency', value: 'Monthly on the 1st' },
34
+ ];
35
+
36
+ export default function FullScreenDialogBasicDemo() {
37
+ const [open, setOpen] = useState(false);
38
+
39
+ return (
40
+ <FullScreenDialog isOpen={open} onOpenChange={setOpen}>
41
+ <FullScreenDialog.Trigger asChild>
42
+ <Button>
43
+ <Button.Label>View transfer</Button.Label>
44
+ </Button>
45
+ </FullScreenDialog.Trigger>
46
+ <FullScreenDialog.Popup>
47
+ <FullScreenDialog.Header
48
+ title="Scheduled transfer"
49
+ className="w-full max-w-md self-center"
50
+ />
51
+ <FullScreenDialog.Content className="w-full max-w-md self-center">
52
+ <ScrollView className="flex-1" contentContainerClassName="gap-4 p-4">
53
+ {details.map((detail) => (
54
+ <Box key={detail.label} className="gap-1">
55
+ <Text color="secondary" size="sm">
56
+ {detail.label}
57
+ </Text>
58
+ <Text>{detail.value}</Text>
59
+ </Box>
60
+ ))}
61
+ <Button onPress={() => setOpen(false)}>
62
+ <Button.Label>Done</Button.Label>
63
+ </Button>
64
+ </ScrollView>
65
+ </FullScreenDialog.Content>
66
+ </FullScreenDialog.Popup>
67
+ </FullScreenDialog>
68
+ );
69
+ }
70
+ ```
71
+
72
+ ## With footer
73
+
74
+ `FullScreenDialog.Content` is a flex column, so actions placed after the `ScrollView` stay pinned above the bottom safe area while the body scrolls. Use `subtitle` for secondary context under the title, such as the payee.
75
+
76
+ ```tsx
77
+ import { useState } from 'react';
78
+ import {
79
+ Avatar,
80
+ Box,
81
+ Button,
82
+ Chip,
83
+ Divider,
84
+ FullScreenDialog,
85
+ Heading,
86
+ ListItem,
87
+ ScrollView,
88
+ Text,
89
+ } from '@cdx-ui/components';
90
+
91
+ const details = [
92
+ { label: 'From', value: 'Everyday Checking •••• 4642' },
93
+ { label: 'Deliver by', value: 'Friday, October 9' },
94
+ { label: 'Frequency', value: 'Monthly on the 9th' },
95
+ { label: 'Memo', value: 'Account 0193 — October' },
96
+ ];
97
+
98
+ export default function FullScreenDialogWithFooterDemo() {
99
+ const [open, setOpen] = useState(false);
100
+
101
+ return (
102
+ <FullScreenDialog isOpen={open} onOpenChange={setOpen}>
103
+ <FullScreenDialog.Trigger asChild>
104
+ <Button>
105
+ <Button.Label>Review payment</Button.Label>
106
+ </Button>
107
+ </FullScreenDialog.Trigger>
108
+ <FullScreenDialog.Popup>
109
+ <FullScreenDialog.Header
110
+ title="Review payment"
111
+ subtitle="Springfield Electric"
112
+ className="w-full max-w-md self-center"
113
+ />
114
+ <FullScreenDialog.Content className="w-full max-w-md self-center">
115
+ <ScrollView className="flex-1" contentContainerClassName="gap-6 p-4">
116
+ <Box className="items-center gap-3 py-4">
117
+ <Avatar size="2xl" color="brand" accessibilityLabel="Springfield Electric">
118
+ <Avatar.Text>Springfield Electric</Avatar.Text>
119
+ </Avatar>
120
+ <Heading size="xl">$84.12</Heading>
121
+ <Chip color="warning" size="small">
122
+ <Chip.Label>Scheduled</Chip.Label>
123
+ </Chip>
124
+ </Box>
125
+ <Box>
126
+ {details.map((detail, index) => (
127
+ <ListItem key={detail.label} showSeparator={index < details.length - 1}>
128
+ <ListItem.Content>
129
+ <ListItem.Description>{detail.label}</ListItem.Description>
130
+ <ListItem.Title>{detail.value}</ListItem.Title>
131
+ </ListItem.Content>
132
+ </ListItem>
133
+ ))}
134
+ </Box>
135
+ <Text color="secondary" size="sm">
136
+ Payments scheduled after 8 PM ET are processed the next business day. You can cancel
137
+ this payment until it starts processing.
138
+ </Text>
139
+ </ScrollView>
140
+ <Divider />
141
+ <Box className="gap-3 p-4">
142
+ <Button onPress={() => setOpen(false)}>
143
+ <Button.Label>Pay $84.12</Button.Label>
144
+ </Button>
145
+ <Button variant="ghost" onPress={() => setOpen(false)}>
146
+ <Button.Label>Edit payment</Button.Label>
147
+ </Button>
148
+ </Box>
149
+ </FullScreenDialog.Content>
150
+ </FullScreenDialog.Popup>
151
+ </FullScreenDialog>
152
+ );
153
+ }
154
+ ```
155
+
156
+ ## Custom triggers
157
+
158
+ Use `asChild` to open the dialog from any pressable, such as a list item or a quick action button. A dialog can have more than one trigger. To open it from a menu item, control `isOpen` and set it from the item's `onPress`.
159
+
160
+ ```tsx
161
+ import { useState } from 'react';
162
+ import {
163
+ Box,
164
+ Button,
165
+ Card,
166
+ Chip,
167
+ FullScreenDialog,
168
+ Heading,
169
+ IconButton,
170
+ ListItem,
171
+ Menu,
172
+ QuickActionButton,
173
+ ScrollView,
174
+ Text,
175
+ } from '@cdx-ui/components';
176
+ import {
177
+ ChevronRight,
178
+ ContentCopy,
179
+ Download,
180
+ Info,
181
+ MoreHoriz,
182
+ Payments,
183
+ Send,
184
+ } from '@cdx-ui/icons';
185
+
186
+ const details = [
187
+ { label: 'Account number', value: '•••• •••• 4642', copyable: true },
188
+ { label: 'Routing number', value: '011000015', copyable: true },
189
+ { label: 'Interest rate', value: '0.01% APY', copyable: false },
190
+ { label: 'Opened', value: 'March 12, 2019', copyable: false },
191
+ ];
192
+
193
+ export default function FullScreenDialogCustomTriggersDemo() {
194
+ const [open, setOpen] = useState(false);
195
+
196
+ return (
197
+ <FullScreenDialog isOpen={open} onOpenChange={setOpen} className="w-full max-w-md gap-4">
198
+ <Card fullBleed>
199
+ <Card.Header>
200
+ <Heading size="sm">Everyday Checking</Heading>
201
+ <Menu placement="bottom-end">
202
+ <Menu.Trigger asChild>
203
+ <IconButton
204
+ as={MoreHoriz}
205
+ variant="ghost"
206
+ size="small"
207
+ accessibilityLabel="Everyday Checking actions"
208
+ />
209
+ </Menu.Trigger>
210
+ <Menu.Popup>
211
+ <Menu.Content accessibilityLabel="Everyday Checking actions">
212
+ <Menu.Item onPress={() => setOpen(true)}>
213
+ <Menu.ItemLabel>Account details</Menu.ItemLabel>
214
+ </Menu.Item>
215
+ <Menu.Item onPress={() => undefined}>
216
+ <Menu.ItemLabel>Manage alerts</Menu.ItemLabel>
217
+ </Menu.Item>
218
+ </Menu.Content>
219
+ </Menu.Popup>
220
+ </Menu>
221
+ </Card.Header>
222
+ <Card.Content>
223
+ <FullScreenDialog.Trigger asChild>
224
+ <ListItem showSeparator={false} accessibilityHint="Opens account details">
225
+ <ListItem.Content>
226
+ <ListItem.Description>Available balance</ListItem.Description>
227
+ <ListItem.Title>$2,418.07</ListItem.Title>
228
+ </ListItem.Content>
229
+ <ListItem.TrailingSlot>
230
+ <ChevronRight size={20} />
231
+ </ListItem.TrailingSlot>
232
+ </ListItem>
233
+ </FullScreenDialog.Trigger>
234
+ </Card.Content>
235
+ </Card>
236
+
237
+ <Box className="flex-row justify-center gap-4">
238
+ <QuickActionButton>
239
+ <QuickActionButton.Icon as={Send} />
240
+ <QuickActionButton.Label>Transfer</QuickActionButton.Label>
241
+ </QuickActionButton>
242
+ <QuickActionButton>
243
+ <QuickActionButton.Icon as={Payments} />
244
+ <QuickActionButton.Label>Pay</QuickActionButton.Label>
245
+ </QuickActionButton>
246
+ <FullScreenDialog.Trigger asChild>
247
+ <QuickActionButton>
248
+ <QuickActionButton.Icon as={Info} />
249
+ <QuickActionButton.Label>Details</QuickActionButton.Label>
250
+ </QuickActionButton>
251
+ </FullScreenDialog.Trigger>
252
+ </Box>
253
+
254
+ <FullScreenDialog.Popup>
255
+ <FullScreenDialog.Header
256
+ title="Account details"
257
+ subtitle="Everyday Checking •••• 4642"
258
+ className="w-full max-w-md self-center"
259
+ />
260
+ <FullScreenDialog.Content className="w-full max-w-md self-center">
261
+ <ScrollView className="flex-1" contentContainerClassName="gap-6 p-4">
262
+ <Box className="items-center gap-2 py-4">
263
+ <Text color="secondary" size="sm">
264
+ Available balance
265
+ </Text>
266
+ <Heading size="xl">$2,418.07</Heading>
267
+ <Chip color="success" size="small">
268
+ <Chip.Label>Active</Chip.Label>
269
+ </Chip>
270
+ </Box>
271
+ <Box>
272
+ {details.map((detail, index) => (
273
+ <ListItem key={detail.label} showSeparator={index < details.length - 1}>
274
+ <ListItem.Content>
275
+ <ListItem.Description>{detail.label}</ListItem.Description>
276
+ <ListItem.Title>{detail.value}</ListItem.Title>
277
+ </ListItem.Content>
278
+ {detail.copyable ? (
279
+ <ListItem.TrailingSlot>
280
+ <IconButton
281
+ as={ContentCopy}
282
+ variant="ghost"
283
+ size="small"
284
+ accessibilityLabel={`Copy ${detail.label.toLowerCase()}`}
285
+ onPress={() => undefined}
286
+ />
287
+ </ListItem.TrailingSlot>
288
+ ) : null}
289
+ </ListItem>
290
+ ))}
291
+ </Box>
292
+ <Button variant="outline">
293
+ <Button.Icon as={Download} position="leading" />
294
+ <Button.Label>Download statements</Button.Label>
295
+ </Button>
296
+ </ScrollView>
297
+ </FullScreenDialog.Content>
298
+ </FullScreenDialog.Popup>
299
+ </FullScreenDialog>
300
+ );
301
+ }
302
+ ```
303
+
304
+ ## Header content
305
+
306
+ Pass `children` to `FullScreenDialog.Header` to replace the title, for example with a search field. The back and close buttons stay in place. Without a title, the popup has no accessible name, so set `aria-label` on `FullScreenDialog.Popup`.
307
+
308
+ ```tsx
309
+ import { useState } from 'react';
310
+ import {
311
+ Avatar,
312
+ Box,
313
+ FullScreenDialog,
314
+ Input,
315
+ ListItem,
316
+ ScrollView,
317
+ Text,
318
+ } from '@cdx-ui/components';
319
+ import { Check, ChevronRight, Search } from '@cdx-ui/icons';
320
+
321
+ const payees = [
322
+ { id: 'electric', name: 'Springfield Electric', detail: 'Account •••• 0193' },
323
+ { id: 'water', name: 'Shelbyville Water', detail: 'Account •••• 7720' },
324
+ { id: 'mortgage', name: 'Evergreen Mortgage', detail: 'Loan •••• 4410' },
325
+ { id: 'internet', name: 'Lakeside Fiber', detail: 'Account •••• 3358' },
326
+ { id: 'insurance', name: 'Harbor Auto Insurance', detail: 'Policy •••• 9021' },
327
+ { id: 'phone', name: 'Northwind Wireless', detail: 'Account •••• 6634' },
328
+ ];
329
+
330
+ export default function FullScreenDialogHeaderContentDemo() {
331
+ const [open, setOpen] = useState(false);
332
+ const [query, setQuery] = useState('');
333
+ const [payeeId, setPayeeId] = useState('electric');
334
+ const payee = payees.find((item) => item.id === payeeId);
335
+ const matches = payees.filter((item) =>
336
+ item.name.toLowerCase().includes(query.trim().toLowerCase()),
337
+ );
338
+
339
+ const handleOpenChange = (next: boolean) => {
340
+ if (next) setQuery('');
341
+ setOpen(next);
342
+ };
343
+
344
+ return (
345
+ <FullScreenDialog isOpen={open} onOpenChange={handleOpenChange} className="w-full max-w-md">
346
+ <Text color="secondary" size="sm">
347
+ Pay to
348
+ </Text>
349
+ <FullScreenDialog.Trigger asChild>
350
+ <ListItem showSeparator={false} accessibilityHint="Opens a searchable list of payees">
351
+ <ListItem.LeadingSlot>
352
+ <Avatar size="lg" color="brand" accessibilityLabel={payee?.name ?? 'Payee'}>
353
+ <Avatar.Text>{payee?.name ?? ''}</Avatar.Text>
354
+ </Avatar>
355
+ </ListItem.LeadingSlot>
356
+ <ListItem.Content>
357
+ <ListItem.Title>{payee?.name ?? 'Choose a payee'}</ListItem.Title>
358
+ <ListItem.Description>{payee?.detail}</ListItem.Description>
359
+ </ListItem.Content>
360
+ <ListItem.TrailingSlot>
361
+ <ChevronRight size={20} />
362
+ </ListItem.TrailingSlot>
363
+ </ListItem>
364
+ </FullScreenDialog.Trigger>
365
+
366
+ <FullScreenDialog.Popup aria-label="Choose a payee">
367
+ <FullScreenDialog.Header
368
+ closeAccessibilityLabel="Cancel"
369
+ className="w-full max-w-md self-center"
370
+ >
371
+ <Box className="px-2">
372
+ <Input variant="outline">
373
+ <Input.Slot>
374
+ <Input.Icon as={Search} />
375
+ </Input.Slot>
376
+ <Input.Field
377
+ accessibilityLabel="Search payees"
378
+ placeholder="Search payees"
379
+ value={query}
380
+ onChangeText={setQuery}
381
+ autoCorrect={false}
382
+ returnKeyType="search"
383
+ />
384
+ </Input>
385
+ </Box>
386
+ </FullScreenDialog.Header>
387
+ <FullScreenDialog.Content className="w-full max-w-md self-center">
388
+ <ScrollView
389
+ className="flex-1"
390
+ contentContainerClassName="p-4"
391
+ keyboardShouldPersistTaps="handled"
392
+ keyboardDismissMode="on-drag"
393
+ >
394
+ {matches.map((item, index) => (
395
+ <ListItem
396
+ key={item.id}
397
+ showSeparator={index < matches.length - 1}
398
+ accessibilityState={{ selected: item.id === payeeId }}
399
+ onPress={() => {
400
+ setPayeeId(item.id);
401
+ setOpen(false);
402
+ }}
403
+ >
404
+ <ListItem.LeadingSlot>
405
+ <Avatar size="lg" accessibilityLabel={item.name}>
406
+ <Avatar.Text>{item.name}</Avatar.Text>
407
+ </Avatar>
408
+ </ListItem.LeadingSlot>
409
+ <ListItem.Content>
410
+ <ListItem.Title>{item.name}</ListItem.Title>
411
+ <ListItem.Description>{item.detail}</ListItem.Description>
412
+ </ListItem.Content>
413
+ {item.id === payeeId ? (
414
+ <ListItem.TrailingSlot>
415
+ <Check size={20} />
416
+ </ListItem.TrailingSlot>
417
+ ) : null}
418
+ </ListItem>
419
+ ))}
420
+ {matches.length === 0 ? (
421
+ <Box className="items-center gap-1 py-8">
422
+ <Text>No payees found</Text>
423
+ <Text color="secondary" size="sm">
424
+ Try a different name, or add a new payee.
425
+ </Text>
426
+ </Box>
427
+ ) : null}
428
+ </ScrollView>
429
+ </FullScreenDialog.Content>
430
+ </FullScreenDialog.Popup>
431
+ </FullScreenDialog>
432
+ );
433
+ }
434
+ ```
435
+
436
+ ## Multi-step flow
437
+
438
+ Keep the step index in your own state and render the current step. Set `onBack` on the header only after the first step: it shows the back button and also handles Android system back, so both go back one step. Steps that unmount lose their local state, so keep form values above the steps. A `ProgressSegmented` placed before the `ScrollView` stays fixed under the header.
439
+
440
+ ```tsx
441
+ import { useState } from 'react';
442
+ import {
443
+ Box,
444
+ Button,
445
+ Field,
446
+ FullScreenDialog,
447
+ Input,
448
+ ListItem,
449
+ ProgressSegmented,
450
+ ScrollView,
451
+ Text,
452
+ } from '@cdx-ui/components';
453
+
454
+ const steps = ['Choose account', 'Enter amount', 'Review transfer'];
455
+
456
+ const accounts = [
457
+ { id: 'checking', name: 'Everyday Checking •••• 4642', balance: '$2,418.07' },
458
+ { id: 'savings', name: 'High-yield Savings •••• 5541', balance: '$16,163.04' },
459
+ { id: 'money-market', name: 'Money Market •••• 2323', balance: '$55,847.23' },
460
+ ];
461
+
462
+ export default function FullScreenDialogMultiStepDemo() {
463
+ const [open, setOpen] = useState(false);
464
+ const [step, setStep] = useState(0);
465
+ const [accountId, setAccountId] = useState<string | undefined>();
466
+ const [amount, setAmount] = useState('');
467
+ const account = accounts.find((item) => item.id === accountId);
468
+
469
+ const handleOpenChange = (next: boolean) => {
470
+ if (next) setStep(0);
471
+ setOpen(next);
472
+ };
473
+
474
+ return (
475
+ <FullScreenDialog isOpen={open} onOpenChange={handleOpenChange}>
476
+ <FullScreenDialog.Trigger asChild>
477
+ <Button>
478
+ <Button.Label>Start transfer</Button.Label>
479
+ </Button>
480
+ </FullScreenDialog.Trigger>
481
+ <FullScreenDialog.Popup>
482
+ <FullScreenDialog.Header
483
+ title={steps[step]}
484
+ subtitle={`Step ${step + 1} of ${steps.length}`}
485
+ onBack={step > 0 ? () => setStep((current) => current - 1) : undefined}
486
+ className="w-full max-w-md self-center"
487
+ />
488
+ <FullScreenDialog.Content className="w-full max-w-md self-center">
489
+ <Box className="px-4 pt-2">
490
+ <ProgressSegmented
491
+ step={step + 1}
492
+ segments={steps.length}
493
+ accessibilityLabel="Transfer progress"
494
+ />
495
+ </Box>
496
+ <ScrollView
497
+ className="flex-1"
498
+ contentContainerClassName="gap-4 p-4"
499
+ automaticallyAdjustKeyboardInsets
500
+ keyboardShouldPersistTaps="handled"
501
+ >
502
+ {step === 0 ? (
503
+ <Box>
504
+ {accounts.map((item, index) => (
505
+ <ListItem
506
+ key={item.id}
507
+ showSeparator={index < accounts.length - 1}
508
+ onPress={() => {
509
+ setAccountId(item.id);
510
+ setStep(1);
511
+ }}
512
+ >
513
+ <ListItem.Content>
514
+ <ListItem.Title>{item.name}</ListItem.Title>
515
+ <ListItem.Description>{`Available: ${item.balance}`}</ListItem.Description>
516
+ </ListItem.Content>
517
+ </ListItem>
518
+ ))}
519
+ </Box>
520
+ ) : null}
521
+ {step === 1 ? (
522
+ <>
523
+ <Field>
524
+ <Field.Label>Amount</Field.Label>
525
+ <Input variant="outline">
526
+ <Input.Field
527
+ placeholder="$0.00"
528
+ keyboardType="decimal-pad"
529
+ value={amount}
530
+ onChangeText={setAmount}
531
+ />
532
+ </Input>
533
+ </Field>
534
+ <Button onPress={() => setStep(2)} isDisabled={amount === ''}>
535
+ <Button.Label>Continue</Button.Label>
536
+ </Button>
537
+ </>
538
+ ) : null}
539
+ {step === 2 ? (
540
+ <>
541
+ <Box className="gap-1">
542
+ <Text color="secondary" size="sm">
543
+ From
544
+ </Text>
545
+ <Text>{account?.name ?? '—'}</Text>
546
+ </Box>
547
+ <Box className="gap-1">
548
+ <Text color="secondary" size="sm">
549
+ Amount
550
+ </Text>
551
+ <Text>{`$${amount}`}</Text>
552
+ </Box>
553
+ <Button onPress={() => setOpen(false)}>
554
+ <Button.Label>Submit transfer</Button.Label>
555
+ </Button>
556
+ </>
557
+ ) : null}
558
+ </ScrollView>
559
+ </FullScreenDialog.Content>
560
+ </FullScreenDialog.Popup>
561
+ </FullScreenDialog>
562
+ );
563
+ }
564
+ ```
565
+
566
+ ## Discard confirmation
567
+
568
+ Control the dialog and intercept `onOpenChange(false)`, which fires for the close button, Escape, and Android back when the header has no `onBack`. When there are unsaved changes, open an `AlertDialog` instead of closing. Escape on the alert dialog is consumed by the alert dialog, so the full-screen dialog beneath stays open.
569
+
570
+ ```tsx
571
+ import { useState } from 'react';
572
+ import {
573
+ AlertDialog,
574
+ Button,
575
+ Field,
576
+ FullScreenDialog,
577
+ Input,
578
+ ScrollView,
579
+ Text,
580
+ } from '@cdx-ui/components';
581
+
582
+ export default function FullScreenDialogDiscardConfirmationDemo() {
583
+ const [open, setOpen] = useState(false);
584
+ const [confirmOpen, setConfirmOpen] = useState(false);
585
+ const [savedNickname, setSavedNickname] = useState('Everyday Checking');
586
+ const [nickname, setNickname] = useState(savedNickname);
587
+ const isDirty = nickname !== savedNickname;
588
+
589
+ const handleOpenChange = (next: boolean) => {
590
+ if (next) {
591
+ setNickname(savedNickname);
592
+ setOpen(true);
593
+ } else if (isDirty) {
594
+ setConfirmOpen(true);
595
+ } else {
596
+ setOpen(false);
597
+ }
598
+ };
599
+
600
+ return (
601
+ <>
602
+ <FullScreenDialog isOpen={open} onOpenChange={handleOpenChange}>
603
+ <FullScreenDialog.Trigger asChild>
604
+ <Button variant="outline">
605
+ <Button.Label>Rename account</Button.Label>
606
+ </Button>
607
+ </FullScreenDialog.Trigger>
608
+ <FullScreenDialog.Popup>
609
+ <FullScreenDialog.Header title="Rename account" className="w-full max-w-md self-center" />
610
+ <FullScreenDialog.Content className="w-full max-w-md self-center">
611
+ <ScrollView
612
+ className="flex-1"
613
+ contentContainerClassName="gap-4 p-4"
614
+ automaticallyAdjustKeyboardInsets
615
+ keyboardShouldPersistTaps="handled"
616
+ >
617
+ <Field>
618
+ <Field.Label>Account nickname</Field.Label>
619
+ <Input variant="outline">
620
+ <Input.Field value={nickname} onChangeText={setNickname} />
621
+ </Input>
622
+ </Field>
623
+ <Text color="secondary" size="sm">
624
+ {isDirty ? 'Unsaved changes' : 'No changes'}
625
+ </Text>
626
+ <Button
627
+ isDisabled={!isDirty}
628
+ onPress={() => {
629
+ setSavedNickname(nickname);
630
+ setOpen(false);
631
+ }}
632
+ >
633
+ <Button.Label>Save</Button.Label>
634
+ </Button>
635
+ </ScrollView>
636
+ </FullScreenDialog.Content>
637
+ </FullScreenDialog.Popup>
638
+ </FullScreenDialog>
639
+
640
+ <AlertDialog isOpen={confirmOpen} onOpenChange={setConfirmOpen}>
641
+ <AlertDialog.Popup>
642
+ <AlertDialog.Header>
643
+ <AlertDialog.Title severity="warning">Discard changes?</AlertDialog.Title>
644
+ </AlertDialog.Header>
645
+ <AlertDialog.Content>
646
+ <AlertDialog.Text>Your new account nickname won&apos;t be saved.</AlertDialog.Text>
647
+ </AlertDialog.Content>
648
+ <AlertDialog.Footer>
649
+ <AlertDialog.Cancel>Keep editing</AlertDialog.Cancel>
650
+ <AlertDialog.Action
651
+ color="danger"
652
+ onPress={() => {
653
+ setConfirmOpen(false);
654
+ setOpen(false);
655
+ }}
656
+ >
657
+ Discard
658
+ </AlertDialog.Action>
659
+ </AlertDialog.Footer>
660
+ </AlertDialog.Popup>
661
+ </AlertDialog>
662
+ </>
663
+ );
664
+ }
665
+ ```
666
+
667
+ ## With a bottom sheet
668
+
669
+ Declare the `BottomSheet.Modal` inside `FullScreenDialog.Popup`, which provides its own sheet host, so the sheet presents above the dialog. Android back and Escape close the sheet before the dialog.
670
+
671
+ ```tsx
672
+ import { useState } from 'react';
673
+ import {
674
+ BottomSheet,
675
+ Box,
676
+ Button,
677
+ FullScreenDialog,
678
+ ListItem,
679
+ ScrollView,
680
+ Text,
681
+ useBottomSheet,
682
+ } from '@cdx-ui/components';
683
+ import { Check, ChevronRight } from '@cdx-ui/icons';
684
+
685
+ const accounts = [
686
+ { id: 'checking', name: 'Everyday Checking •••• 4642', balance: '$2,418.07' },
687
+ { id: 'savings', name: 'High-yield Savings •••• 5541', balance: '$16,163.04' },
688
+ { id: 'money-market', name: 'Money Market •••• 2323', balance: '$55,847.23' },
689
+ ];
690
+
691
+ export default function FullScreenDialogBottomSheetDemo() {
692
+ const [open, setOpen] = useState(false);
693
+ const [fromId, setFromId] = useState('checking');
694
+ const { ref, present, dismiss } = useBottomSheet();
695
+ const from = accounts.find((account) => account.id === fromId);
696
+
697
+ return (
698
+ <FullScreenDialog isOpen={open} onOpenChange={setOpen}>
699
+ <FullScreenDialog.Trigger asChild>
700
+ <Button>
701
+ <Button.Label>Edit transfer</Button.Label>
702
+ </Button>
703
+ </FullScreenDialog.Trigger>
704
+ <FullScreenDialog.Popup>
705
+ <FullScreenDialog.Header title="Edit transfer" className="w-full max-w-md self-center" />
706
+ <FullScreenDialog.Content className="w-full max-w-md self-center">
707
+ <ScrollView className="flex-1" contentContainerClassName="gap-4 p-4">
708
+ <Box>
709
+ <ListItem onPress={present} accessibilityHint="Opens a list of accounts">
710
+ <ListItem.Content>
711
+ <ListItem.Description>From</ListItem.Description>
712
+ <ListItem.Title>{from?.name ?? 'Choose an account'}</ListItem.Title>
713
+ </ListItem.Content>
714
+ <ListItem.TrailingSlot>
715
+ <ChevronRight size={20} />
716
+ </ListItem.TrailingSlot>
717
+ </ListItem>
718
+ <ListItem showSeparator={false}>
719
+ <ListItem.Content>
720
+ <ListItem.Description>To</ListItem.Description>
721
+ <ListItem.Title>Rent account •••• 8810</ListItem.Title>
722
+ </ListItem.Content>
723
+ </ListItem>
724
+ </Box>
725
+ <Text color="secondary" size="sm">
726
+ The account sheet is declared inside the popup, so it presents above the dialog.
727
+ </Text>
728
+ <Button onPress={() => setOpen(false)}>
729
+ <Button.Label>Save changes</Button.Label>
730
+ </Button>
731
+ </ScrollView>
732
+ </FullScreenDialog.Content>
733
+
734
+ <BottomSheet.Modal ref={ref}>
735
+ <BottomSheet.View>
736
+ <BottomSheet.Header title="Transfer from" onClose={dismiss} />
737
+ <BottomSheet.Content>
738
+ {accounts.map((account, index) => (
739
+ <ListItem
740
+ key={account.id}
741
+ showSeparator={index < accounts.length - 1}
742
+ accessibilityState={{ selected: account.id === fromId }}
743
+ onPress={() => {
744
+ setFromId(account.id);
745
+ dismiss();
746
+ }}
747
+ >
748
+ <ListItem.Content>
749
+ <ListItem.Title>{account.name}</ListItem.Title>
750
+ <ListItem.Description>{`Available: ${account.balance}`}</ListItem.Description>
751
+ </ListItem.Content>
752
+ {account.id === fromId ? (
753
+ <ListItem.TrailingSlot>
754
+ <Check size={20} />
755
+ </ListItem.TrailingSlot>
756
+ ) : null}
757
+ </ListItem>
758
+ ))}
759
+ </BottomSheet.Content>
760
+ </BottomSheet.View>
761
+ </BottomSheet.Modal>
762
+ </FullScreenDialog.Popup>
763
+ </FullScreenDialog>
764
+ );
765
+ }
766
+ ```
767
+
768
+ ## API
769
+
770
+ ### FullScreenDialog
771
+
772
+ Controls open state and Escape dismissal. There is no backdrop to press, so `closeOnBackdropPress` is not available, and there is no `size`.
773
+
774
+ | Prop | Type | Default | Description |
775
+ | --- | --- | --- | --- |
776
+ | `className?` | `string` | — | Classes for the root wrapper around the trigger. |
777
+ | `children` | `ReactNode` | — | `FullScreenDialog.Trigger` and `FullScreenDialog.Popup`. |
778
+ | `onOpenChange?` | `((open: boolean) => void)` | — | Called with the next open state. Fires `false` for the header close button, Escape, and Android back while the header has no `onBack`. |
779
+ | `defaultOpen?` | `boolean` | `false` | Initial open state when uncontrolled. |
780
+ | `closeOnEscKey?` | `boolean` | `true` | Close when Escape is pressed. Web only. Escape never steps back; Android back is routed by the header's `onBack` independently of this prop. |
781
+ | `isOpen?` | `boolean` | — | Controlled open state. Use `defaultOpen` for the uncontrolled variant. |
782
+ | `animation?` | `'disable-all'` | — | Pass `'disable-all'` to turn off the popup's enter and exit motion. |
783
+
784
+ Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props), except `children` and `role`.
785
+
786
+ ## Sub-components
787
+
788
+ ### FullScreenDialog.Trigger
789
+
790
+ Opens the dialog when pressed. Use `asChild` to merge trigger behavior onto a `Button` or another pressable element.
791
+
792
+ | Prop | Type | Default | Description |
793
+ | --- | --- | --- | --- |
794
+ | `className?` | `string` | — | Classes for the trigger. |
795
+ | `children?` | `ReactNode` | — | Content that opens the dialog when pressed. |
796
+ | `asChild?` | `boolean` | — | Render the single child as the trigger instead of a `Pressable`. |
797
+
798
+ Inherits all [`PressableProps`](https://reactnative.dev/docs/pressable#props).
799
+
800
+ ### FullScreenDialog.Popup
801
+
802
+ The page surface. It covers the viewport with the primary surface color and has no backdrop, corner radius, swipe-to-dismiss, or keyboard-avoiding layer. Bottom sheets declared inside it present above it.
803
+
804
+ | Prop | Type | Default | Description |
805
+ | --- | --- | --- | --- |
806
+ | `className?` | `string` | — | Classes for the page surface, merged after the defaults. |
807
+ | `children?` | `ReactNode` | — | `FullScreenDialog.Header` and `FullScreenDialog.Content`. Bottom sheets declared here present above the page. |
808
+
809
+ Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
810
+
811
+ | Attribute | Value | Description |
812
+ | ------------ | -------------------------------- | ---------------------------------------------- |
813
+ | `data-state` | `entering` \| `open` \| `closed` | Web only. Drives the enter and exit transition |
814
+
815
+ ### FullScreenDialog.Header
816
+
817
+ Back / title / close row that clears the top safe-area inset. It takes the same props as [`BottomSheet.Header`](https://design.candescent.com/docs/components/bottom-sheet/content.md), except that the close button closes the dialog by default. The back button appears only while `onBack` is set. An unused back or close position keeps its space so the title stays centered, but it is not rendered as a button.
818
+
819
+ | Prop | Type | Default | Description |
820
+ | --- | --- | --- | --- |
821
+ | `title?` | `string` | — | Title text. Labels the dialog. Ignored when `children` is set. |
822
+ | `subtitle?` | `string` | — | Secondary line under the title. Has no effect without `title`, or when `children` is set. |
823
+ | `children?` | `ReactNode` | — | Custom header content. Replaces `title` and `subtitle`. The consumer then owns the dialog's accessible name and focus on step change: focus doesn't move to the header. |
824
+ | `className?` | `string` | — | Classes for the header region, which includes the top safe-area padding. |
825
+ | `onClose?` | `(() => void)` | `Closes the dialog (`onOpenChange(false)`).` | Called by the close button. |
826
+ | `closeAccessibilityLabel?` | `string` | `Close` | Accessible name for the close button. |
827
+ | `onBack?` | `(() => void)` | — | Shows the back button when set. Android system back calls it too, instead of closing the dialog. Escape on web always closes. |
828
+ | `backAccessibilityLabel?` | `string` | `Go back` | Accessible name for the back button. |
829
+
830
+ ### FullScreenDialog.Content
831
+
832
+ Flex region under the header that clears the bottom safe-area inset. It does not scroll by itself; put a `ScrollView` inside it.
833
+
834
+ | Prop | Type | Default | Description |
835
+ | --- | --- | --- | --- |
836
+ | `className?` | `string` | — | Classes for the content region, merged after the defaults. |
837
+ | `children?` | `ReactNode` | — | Page body. Usually a `ScrollView`. |
838
+ | `asChild?` | `boolean` | — | Render the single child as the content region instead of a `View`. |
839
+
840
+ Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
841
+
842
+ ## Anatomy
843
+
844
+ | `data-slot` | Element |
845
+ | ---------------------------- | -------------------------------------------------- |
846
+ | `full-screen-dialog` | Root wrapper around the trigger |
847
+ | `full-screen-dialog-trigger` | Trigger |
848
+ | `full-screen-dialog-popup` | Page surface with `role="dialog"` |
849
+ | `full-screen-dialog-header` | Header region, including the top safe-area padding |
850
+ | `full-screen-dialog-content` | Body region under the header |
851
+
852
+ ## Accessibility
853
+
854
+ - The popup receives `role="dialog"`, `aria-modal`, and `aria-labelledby` pointing at the header title.
855
+ - Focus moves into the popup, remains trapped while open, and returns to the trigger after close.
856
+ - When the header `title` changes, or `onBack` switches between set and unset, focus moves to the header title on web and screen-reader focus moves there on native, so the new step is announced. This does not happen when the dialog first opens.
857
+ - When you pass custom `children` to `FullScreenDialog.Header`, the title is not rendered, so you own the dialog's accessible name and moving focus on a step change. Set `aria-label` on `FullScreenDialog.Popup` to name the dialog.
858
+ - Android system back calls the header's `onBack` while it is set, and the dialog stays open. Without `onBack`, it closes the dialog.
859
+ - Escape closes the dialog on web when `closeOnEscKey` is enabled. It never steps back, even while `onBack` is set.
860
+ - Android back and Escape go to the topmost overlay first. A presented bottom sheet, or a dialog or select opened from the full-screen dialog, handles them before the full-screen dialog does.
861
+ - The back and close buttons default to the accessible names "Go back" and "Close".
862
+
863
+ ## Constraints
864
+
865
+ - A shared `PortalHost` must be mounted once near the app root. `ForgeDesignProvider` includes one.
866
+ - Declare every `BottomSheet.Modal` you open from the dialog inside `FullScreenDialog.Popup`. The popup provides its own sheet host. A sheet declared outside the popup, for example as a sibling of `FullScreenDialog`, presents through the root host and stays beneath the dialog.
867
+ - Sheets opened from the dialog need a `GestureHandlerRootView` at the app root, wrapping `ForgeDesignProvider`. This is the same requirement as any other `BottomSheet`.
868
+ - Launching a full-screen dialog from a React Navigation native modal screen (`modal`, `formSheet`, `fullScreenModal`) is not supported in this version. On iOS the dialog renders underneath the presenting screen.
869
+ - There is no built-in keyboard avoidance. Make a `ScrollView` inside `FullScreenDialog.Content` the scroll container, and set `automaticallyAdjustKeyboardInsets` and `keyboardShouldPersistTaps="handled"` on it, as the multi-step and discard demos do. `automaticallyAdjustKeyboardInsets` applies on iOS. On Android, confirm the behavior on a device; it varies with edge-to-edge configuration. Do not wrap the dialog in a `KeyboardAvoidingView`.
870
+ - The dialog holds no step state and adds no browser history entry. It is a modal, not a navigator screen, so it does not get the iOS edge-swipe back gesture.
871
+ - Pass `animation="disable-all"` on `FullScreenDialog` to turn off the enter and exit motion. Reduced-motion settings are respected on every platform.
872
+
873
+ ## When to use
874
+
875
+ | Component | Use for |
876
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
877
+ | `FullScreenDialog` | A task that needs the whole screen, such as editing a transfer or a multi-step setup, and returns to the same place when done |
878
+ | `Dialog` | A short confirmation or a small form on a centered card |
879
+ | `Drawer` | Filters, settings, or navigation on a panel attached to an edge of the viewport |
880
+ | `BottomSheet` | A secondary task at partial height that keeps the page behind it in view |
881
+ | A navigator screen | A page that needs its own URL or deep link, or a place in the navigation history |