@dxos/react-ui 0.8.4-main.8360d9e660 → 0.8.4-main.8baae0fced

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 (300) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/browser/chunk-A5QCIG5R.mjs +24 -0
  4. package/dist/lib/browser/chunk-A5QCIG5R.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-EJSGYGYH.mjs → chunk-LY5XDQR5.mjs} +84 -12
  6. package/dist/lib/browser/chunk-LY5XDQR5.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +1322 -811
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/testing/index.mjs +30 -24
  11. package/dist/lib/browser/testing/index.mjs.map +3 -3
  12. package/dist/lib/browser/translations.mjs +9 -0
  13. package/dist/lib/browser/translations.mjs.map +7 -0
  14. package/dist/lib/node-esm/{chunk-B7MXDDMJ.mjs → chunk-NGKLIKP3.mjs} +84 -12
  15. package/dist/lib/node-esm/chunk-NGKLIKP3.mjs.map +7 -0
  16. package/dist/lib/node-esm/chunk-XCFLA74M.mjs +26 -0
  17. package/dist/lib/node-esm/chunk-XCFLA74M.mjs.map +7 -0
  18. package/dist/lib/node-esm/index.mjs +1322 -811
  19. package/dist/lib/node-esm/index.mjs.map +4 -4
  20. package/dist/lib/node-esm/meta.json +1 -1
  21. package/dist/lib/node-esm/testing/index.mjs +30 -24
  22. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  23. package/dist/lib/node-esm/translations.mjs +10 -0
  24. package/dist/lib/node-esm/translations.mjs.map +7 -0
  25. package/dist/types/src/components/Avatars/Avatar.d.ts +1 -1
  26. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  27. package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
  28. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  30. package/dist/types/src/components/Breadcrumb/Breadcrumb.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Button/Button.d.ts.map +1 -1
  32. package/dist/types/src/components/Button/Button.stories.d.ts +1 -1
  33. package/dist/types/src/components/Button/Button.stories.d.ts.map +1 -1
  34. package/dist/types/src/components/Button/IconButton.d.ts +1 -0
  35. package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
  36. package/dist/types/src/components/Button/IconButton.stories.d.ts +3 -0
  37. package/dist/types/src/components/Button/IconButton.stories.d.ts.map +1 -1
  38. package/dist/types/src/components/Button/Toggle.stories.d.ts.map +1 -1
  39. package/dist/types/src/components/Button/ToggleGroup.d.ts +2 -2
  40. package/dist/types/src/components/Button/ToggleGroup.stories.d.ts +2 -2
  41. package/dist/types/src/components/Button/ToggleGroup.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/Card/Card.d.ts +59 -42
  43. package/dist/types/src/components/Card/Card.d.ts.map +1 -1
  44. package/dist/types/src/components/Card/Card.stories.d.ts +2 -2
  45. package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -1
  46. package/dist/types/src/components/Carousel/Carousel.d.ts +106 -0
  47. package/dist/types/src/components/Carousel/Carousel.d.ts.map +1 -0
  48. package/dist/types/src/components/Carousel/index.d.ts +2 -0
  49. package/dist/types/src/components/Carousel/index.d.ts.map +1 -0
  50. package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts.map +1 -1
  51. package/dist/types/src/components/Clipboard/CopyButton.d.ts.map +1 -1
  52. package/dist/types/src/components/Clipboard/index.d.ts +1 -1
  53. package/dist/types/src/components/Clipboard/index.d.ts.map +1 -1
  54. package/dist/types/src/components/DensityProvider/DensityProvider.d.ts.map +1 -1
  55. package/dist/types/src/components/Dialog/AlertDialog.d.ts +34 -23
  56. package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
  57. package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts.map +1 -1
  58. package/dist/types/src/components/Dialog/Dialog.d.ts +38 -21
  59. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  60. package/dist/types/src/components/Dialog/Dialog.stories.d.ts +3 -2
  61. package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
  62. package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts.map +1 -1
  63. package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts.map +1 -1
  64. package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts.map +1 -1
  65. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts +14 -3
  66. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -1
  67. package/dist/types/src/components/ErrorFallback/ThrowError.d.ts.map +1 -1
  68. package/dist/types/src/components/Focus/Focus.d.ts +36 -0
  69. package/dist/types/src/components/Focus/Focus.d.ts.map +1 -0
  70. package/dist/types/src/components/Focus/Focus.stories.d.ts +9 -0
  71. package/dist/types/src/components/Focus/Focus.stories.d.ts.map +1 -0
  72. package/dist/types/src/components/Focus/index.d.ts +2 -0
  73. package/dist/types/src/components/Focus/index.d.ts.map +1 -0
  74. package/dist/types/src/components/Icon/Icon.d.ts +4 -0
  75. package/dist/types/src/components/Icon/Icon.d.ts.map +1 -1
  76. package/dist/types/src/components/Icon/Icon.stories.d.ts +11 -3
  77. package/dist/types/src/components/Icon/Icon.stories.d.ts.map +1 -1
  78. package/dist/types/src/components/Image/Image.d.ts +2 -1
  79. package/dist/types/src/components/Image/Image.d.ts.map +1 -1
  80. package/dist/types/src/components/Image/Image.stories.d.ts +3 -2
  81. package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -1
  82. package/dist/types/src/components/Input/Input.d.ts +12 -15
  83. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  84. package/dist/types/src/components/Input/Input.stories.d.ts +3 -3
  85. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  86. package/dist/types/src/components/Link/Link.d.ts.map +1 -1
  87. package/dist/types/src/components/Link/Link.stories.d.ts.map +1 -1
  88. package/dist/types/src/components/List/List.d.ts +5 -3
  89. package/dist/types/src/components/List/List.d.ts.map +1 -1
  90. package/dist/types/src/components/List/List.stories.d.ts +3 -1
  91. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  92. package/dist/types/src/components/List/ListDropIndicator.d.ts.map +1 -1
  93. package/dist/types/src/components/List/Tree.d.ts +2 -2
  94. package/dist/types/src/components/List/Tree.d.ts.map +1 -1
  95. package/dist/types/src/components/List/Tree.stories.d.ts.map +1 -1
  96. package/dist/types/src/components/List/TreeDropIndicator.d.ts.map +1 -1
  97. package/dist/types/src/components/List/Treegrid.d.ts +5 -9
  98. package/dist/types/src/components/List/Treegrid.d.ts.map +1 -1
  99. package/dist/types/src/components/List/Treegrid.stories.d.ts.map +1 -1
  100. package/dist/types/src/components/Main/Main.d.ts +7 -3
  101. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  102. package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
  103. package/dist/types/src/components/Main/useSwipeToDismiss.d.ts.map +1 -1
  104. package/dist/types/src/components/MediaPlayer/MediaPlayer.d.ts +46 -0
  105. package/dist/types/src/components/MediaPlayer/MediaPlayer.d.ts.map +1 -0
  106. package/dist/types/src/components/MediaPlayer/MediaPlayer.stories.d.ts +16 -0
  107. package/dist/types/src/components/MediaPlayer/MediaPlayer.stories.d.ts.map +1 -0
  108. package/dist/types/src/components/MediaPlayer/index.d.ts +2 -0
  109. package/dist/types/src/components/MediaPlayer/index.d.ts.map +1 -0
  110. package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -1
  111. package/dist/types/src/components/Menu/ContextMenu.stories.d.ts.map +1 -1
  112. package/dist/types/src/components/Menu/DropdownMenu.d.ts +13 -6
  113. package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -1
  114. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts +9 -1
  115. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -1
  116. package/dist/types/src/components/Message/Message.d.ts +1 -1
  117. package/dist/types/src/components/Message/Message.d.ts.map +1 -1
  118. package/dist/types/src/components/Message/Message.stories.d.ts +2 -2
  119. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  120. package/dist/types/src/components/Popover/Popover.d.ts +14 -3
  121. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  122. package/dist/types/src/components/Popover/Popover.stories.d.ts.map +1 -1
  123. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +12 -9
  124. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  125. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +18 -5
  126. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  127. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +42 -13
  128. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
  129. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +5 -6
  130. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
  131. package/dist/types/src/components/Select/Select.d.ts.map +1 -1
  132. package/dist/types/src/components/Select/Select.stories.d.ts +2 -2
  133. package/dist/types/src/components/Select/Select.stories.d.ts.map +1 -1
  134. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -1
  135. package/dist/types/src/components/Splitter/Splitter.d.ts +19 -17
  136. package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -1
  137. package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -1
  138. package/dist/types/src/components/Status/Status.d.ts +3 -4
  139. package/dist/types/src/components/Status/Status.d.ts.map +1 -1
  140. package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
  141. package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
  142. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +1 -1
  143. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  144. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts +1 -1
  145. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
  146. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +54 -55
  147. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
  148. package/dist/types/src/components/ThemeProvider/index.d.ts +1 -1
  149. package/dist/types/src/components/ThemeProvider/index.d.ts.map +1 -1
  150. package/dist/types/src/components/Toast/Toast.d.ts +4 -4
  151. package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
  152. package/dist/types/src/components/Toast/Toast.stories.d.ts.map +1 -1
  153. package/dist/types/src/components/Toolbar/Toolbar.d.ts +11 -15
  154. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  155. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  156. package/dist/types/src/components/Tooltip/Tooltip.d.ts +8 -8
  157. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  158. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +2 -2
  159. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  160. package/dist/types/src/components/index.d.ts +3 -0
  161. package/dist/types/src/components/index.d.ts.map +1 -1
  162. package/dist/types/src/exemplars/generics.stories.d.ts +6 -5
  163. package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -1
  164. package/dist/types/src/exemplars/slot.stories.d.ts +1 -0
  165. package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -1
  166. package/dist/types/src/exemplars/tabster.stories.d.ts.map +1 -1
  167. package/dist/types/src/exemplars/virtualizer.stories.d.ts.map +1 -1
  168. package/dist/types/src/hooks/useDensityContext.d.ts +1 -1
  169. package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
  170. package/dist/types/src/hooks/useElevationContext.d.ts.map +1 -1
  171. package/dist/types/src/hooks/useIconHref.d.ts.map +1 -1
  172. package/dist/types/src/hooks/useSafeArea.d.ts.map +1 -1
  173. package/dist/types/src/hooks/useSafeCollisionPadding.d.ts.map +1 -1
  174. package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
  175. package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
  176. package/dist/types/src/playground/Custom.stories.d.ts +1 -1
  177. package/dist/types/src/playground/Custom.stories.d.ts.map +1 -1
  178. package/dist/types/src/playground/Typography.stories.d.ts.map +1 -1
  179. package/dist/types/src/primitives/Column/Column.d.ts +21 -14
  180. package/dist/types/src/primitives/Column/Column.d.ts.map +1 -1
  181. package/dist/types/src/primitives/Column/Column.stories.d.ts +19 -0
  182. package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -1
  183. package/dist/types/src/primitives/Container/Container.d.ts +4 -5
  184. package/dist/types/src/primitives/Container/Container.d.ts.map +1 -1
  185. package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -1
  186. package/dist/types/src/primitives/Flex/Flex.d.ts +5 -7
  187. package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -1
  188. package/dist/types/src/primitives/Flex/Flex.stories.d.ts.map +1 -1
  189. package/dist/types/src/primitives/Grid/Grid.d.ts +3 -8
  190. package/dist/types/src/primitives/Grid/Grid.d.ts.map +1 -1
  191. package/dist/types/src/primitives/Grid/Grid.stories.d.ts.map +1 -1
  192. package/dist/types/src/primitives/Panel/Panel.d.ts +24 -15
  193. package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -1
  194. package/dist/types/src/primitives/Panel/Panel.stories.d.ts.map +1 -1
  195. package/dist/types/src/testing/Loading.d.ts.map +1 -1
  196. package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -1
  197. package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -1
  198. package/dist/types/src/testing/decorators/withTheme.d.ts +1 -1
  199. package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
  200. package/dist/types/src/translations.d.ts +8 -3
  201. package/dist/types/src/translations.d.ts.map +1 -1
  202. package/dist/types/src/util/usePx.d.ts.map +1 -1
  203. package/dist/types/tsconfig.tsbuildinfo +1 -1
  204. package/package.json +29 -26
  205. package/src/components/Avatars/Avatar.stories.tsx +2 -3
  206. package/src/components/Avatars/Avatar.tsx +1 -2
  207. package/src/components/Avatars/AvatarGroup.stories.tsx +0 -1
  208. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +1 -2
  209. package/src/components/Button/Button.stories.tsx +0 -1
  210. package/src/components/Button/Button.tsx +3 -11
  211. package/src/components/Button/IconButton.stories.tsx +6 -4
  212. package/src/components/Button/IconButton.tsx +3 -3
  213. package/src/components/Button/Toggle.stories.tsx +0 -1
  214. package/src/components/Button/ToggleGroup.stories.tsx +0 -1
  215. package/src/components/Card/Card.stories.tsx +15 -15
  216. package/src/components/Card/Card.tsx +190 -66
  217. package/src/components/Carousel/Carousel.tsx +379 -0
  218. package/src/components/Carousel/index.ts +5 -0
  219. package/src/components/Clipboard/CopyButton.tsx +5 -6
  220. package/src/components/Dialog/AlertDialog.stories.tsx +5 -6
  221. package/src/components/Dialog/AlertDialog.tsx +51 -93
  222. package/src/components/Dialog/Dialog.stories.tsx +64 -9
  223. package/src/components/Dialog/Dialog.tsx +66 -56
  224. package/src/components/ErrorFallback/ErrorFallback.stories.tsx +3 -8
  225. package/src/components/ErrorFallback/ErrorStack.tsx +36 -2
  226. package/src/components/Focus/AUDIT.md +43 -0
  227. package/src/components/Focus/Focus.stories.tsx +230 -0
  228. package/src/components/Focus/Focus.tsx +201 -0
  229. package/src/components/Focus/index.ts +5 -0
  230. package/src/components/Icon/Icon.stories.tsx +43 -13
  231. package/src/components/Icon/Icon.tsx +13 -3
  232. package/src/components/Image/Image.stories.tsx +3 -3
  233. package/src/components/Image/Image.tsx +31 -8
  234. package/src/components/Input/Input.stories.tsx +3 -4
  235. package/src/components/Input/Input.tsx +3 -3
  236. package/src/components/Link/Link.stories.tsx +0 -1
  237. package/src/components/Link/Link.tsx +10 -2
  238. package/src/components/List/List.stories.tsx +1 -2
  239. package/src/components/List/List.tsx +7 -6
  240. package/src/components/List/ListDropIndicator.tsx +0 -1
  241. package/src/components/List/Tree.stories.tsx +2 -3
  242. package/src/components/List/Tree.tsx +0 -1
  243. package/src/components/List/Treegrid.stories.tsx +26 -27
  244. package/src/components/List/Treegrid.tsx +14 -14
  245. package/src/components/Main/Main.stories.tsx +0 -1
  246. package/src/components/Main/Main.tsx +0 -1
  247. package/src/components/MediaPlayer/MediaPlayer.stories.tsx +50 -0
  248. package/src/components/MediaPlayer/MediaPlayer.tsx +153 -0
  249. package/src/components/MediaPlayer/index.ts +5 -0
  250. package/src/components/Menu/ContextMenu.stories.tsx +0 -1
  251. package/src/components/Menu/DropdownMenu.stories.tsx +0 -1
  252. package/src/components/Menu/DropdownMenu.tsx +3 -3
  253. package/src/components/Message/Message.stories.tsx +7 -8
  254. package/src/components/Message/Message.tsx +23 -10
  255. package/src/components/Popover/Popover.stories.tsx +4 -5
  256. package/src/components/Popover/Popover.tsx +1 -1
  257. package/src/components/ScrollArea/ScrollArea.stories.tsx +89 -30
  258. package/src/components/ScrollArea/ScrollArea.tsx +39 -23
  259. package/src/components/ScrollContainer/ScrollContainer.stories.tsx +19 -17
  260. package/src/components/ScrollContainer/ScrollContainer.tsx +199 -92
  261. package/src/components/Select/Select.stories.tsx +5 -6
  262. package/src/components/Skeleton/Skeleton.stories.tsx +0 -1
  263. package/src/components/Splitter/Splitter.stories.tsx +29 -29
  264. package/src/components/Splitter/Splitter.tsx +35 -34
  265. package/src/components/Status/Status.stories.tsx +0 -1
  266. package/src/components/Status/Status.tsx +8 -5
  267. package/src/components/Tag/Tag.stories.tsx +0 -1
  268. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +0 -1
  269. package/src/components/ThemeProvider/ThemeProvider.tsx +5 -4
  270. package/src/components/ThemeProvider/index.ts +1 -1
  271. package/src/components/Toast/Toast.stories.tsx +0 -1
  272. package/src/components/Toolbar/Toolbar.stories.tsx +0 -1
  273. package/src/components/Toolbar/Toolbar.tsx +19 -15
  274. package/src/components/Tooltip/Tooltip.stories.tsx +7 -8
  275. package/src/components/Tooltip/Tooltip.tsx +14 -13
  276. package/src/components/index.ts +3 -0
  277. package/src/exemplars/generics.stories.tsx +7 -15
  278. package/src/exemplars/slot.stories.tsx +65 -57
  279. package/src/exemplars/tabster.stories.tsx +1 -1
  280. package/src/exemplars/virtualizer.stories.tsx +4 -5
  281. package/src/hooks/useDensityContext.ts +2 -2
  282. package/src/playground/Custom.stories.tsx +6 -9
  283. package/src/primitives/Column/AUDIT.md +148 -0
  284. package/src/primitives/Column/Column.stories.tsx +122 -19
  285. package/src/primitives/Column/Column.tsx +73 -41
  286. package/src/primitives/Container/Container.stories.tsx +0 -1
  287. package/src/primitives/Container/Container.tsx +5 -8
  288. package/src/primitives/Flex/Flex.stories.tsx +0 -1
  289. package/src/primitives/Flex/Flex.tsx +10 -12
  290. package/src/primitives/Grid/Grid.stories.tsx +0 -1
  291. package/src/primitives/Grid/Grid.tsx +4 -9
  292. package/src/primitives/Panel/Panel.stories.tsx +8 -7
  293. package/src/primitives/Panel/Panel.tsx +64 -63
  294. package/src/testing/Loading.tsx +25 -4
  295. package/src/testing/decorators/withLayout.tsx +7 -17
  296. package/src/testing/decorators/withTheme.tsx +10 -7
  297. package/src/translations.ts +8 -3
  298. package/src/util/usePx.ts +1 -0
  299. package/dist/lib/browser/chunk-EJSGYGYH.mjs.map +0 -7
  300. package/dist/lib/node-esm/chunk-B7MXDDMJ.mjs.map +0 -7
@@ -0,0 +1,148 @@
1
+ # Column architecture reference
2
+
3
+ ## Background
4
+
5
+ `Column` establishes a 3-column CSS grid with left/right gutter columns and a center content
6
+ channel. Two CSS custom properties drive the system:
7
+
8
+ - `--gutter` — the gutter track width (e.g. `var(--dx-gutter-md)`); consumed by `ScrollArea.Viewport` for padding.
9
+ - `--dx-col` — the grid-column placement token; set by `Column.Root` and consumed by `withColumn` utilities.
10
+
11
+ ## Column primitives
12
+
13
+ ### Column.Root
14
+
15
+ ```css
16
+ /* column.ts — columnRoot */
17
+ dx-column grid
18
+ /* inline style */
19
+ --gutter: <gutterSize>
20
+ --dx-col: 2 / span 1
21
+ grid-template-columns: <gutter> minmax(0,1fr) <gutter>
22
+ ```
23
+
24
+ Sets the 3-column grid and both CSS variables. All `withColumn` utilities are no-ops outside this context.
25
+
26
+ ### Column.Center
27
+
28
+ ```css
29
+ /* column.ts — columnCenter */
30
+ [grid-column:var(--dx-col,auto)] min-h-0
31
+ ```
32
+
33
+ Places a single element in col 2 (the center track). Does not use subgrid — placement is explicit
34
+ on this element only, so arbitrary compound components (including `display: contents` wrappers) can
35
+ be nested safely.
36
+
37
+ ### Column.Bleed
38
+
39
+ ```css
40
+ /* column.ts — columnBleed */
41
+ col-span-full grid grid-cols-subgrid min-h-0
42
+ ```
43
+
44
+ Spans all 3 columns and propagates the subgrid. Use for `ScrollArea`, full-width dividers, and
45
+ any content that should ignore the gutters.
46
+
47
+ ### Column.Row
48
+
49
+ ```css
50
+ /* column.ts — columnRow */
51
+ col-span-3 grid grid-cols-subgrid
52
+ ```
53
+
54
+ Three-slot icon row. Children map to: `[col-1: icon/slot] [col-2: content] [col-3: icon/action]`.
55
+ Must be a direct child of `Column.Root`.
56
+
57
+ ## withColumn theme utilities
58
+
59
+ Exported from `@dxos/ui-theme`. Components import and call these in their theme functions to
60
+ participate in the Column grid without importing Column React components.
61
+
62
+ ```ts
63
+ withColumn.center();
64
+ // → '[grid-column:var(--dx-col,auto)]'
65
+
66
+ withColumn.propagate();
67
+ // → '[.dx-column_&]:col-span-full [.dx-column_&]:grid [.dx-column_&]:grid-cols-subgrid'
68
+
69
+ withColumn.consumed();
70
+ // → '[--dx-col:auto]'
71
+ ```
72
+
73
+ | Utility | Purpose | Where used |
74
+ | :------------ | :-------------------------------------------------------------------------------- | :---------------------------------------------------------------------------- |
75
+ | `center()` | Place element in col 2 via `--dx-col`. No-op outside Column or inside ScrollArea. | Dialog.Header, Dialog.ActionBar, Form.Content, Form.Actions, SearchList.Input |
76
+ | `propagate()` | Extend Column subgrid to children. No-op outside Column. | Dialog.Body, SearchList.Content |
77
+ | `consumed()` | Reset `--dx-col` after `--gutter` is consumed. | ScrollArea.Viewport |
78
+
79
+ ## CSS custom property cascade
80
+
81
+ ```text
82
+ Column.Root
83
+ sets --gutter = var(--dx-gutter-<size>)
84
+ sets --dx-col = 2 / span 1
85
+
86
+ ├─ Column.Center → grid-column: var(--dx-col) ← consumes --dx-col
87
+ ├─ Column.Bleed → col-span-full, subgrid
88
+ ├─ Column.Row → col-span-3, subgrid
89
+
90
+ └─ withColumn.center() → grid-column: var(--dx-col) ← consumes --dx-col
91
+ withColumn.propagate() → col-span-full, grid, subgrid (inside .dx-column only)
92
+
93
+ └─ ScrollArea.Root → col-span-full (inside .dx-column only)
94
+ ScrollArea.Viewport
95
+ applies pl/pr using --gutter
96
+ withColumn.consumed() → sets --dx-col: auto
97
+
98
+ └─ (nested components no longer auto-position)
99
+ ```
100
+
101
+ ## Component integration
102
+
103
+ ### Dialog
104
+
105
+ | Sub-component | withColumn applied | Effect |
106
+ | :----------------- | :---------------------------- | :---------------------------- |
107
+ | `Dialog.Content` | `Column.Root` (gutter `'sm'`) | Establishes the 3-col grid. |
108
+ | `Dialog.Header` | `withColumn.center()` | Placed in col 2. |
109
+ | `Dialog.Body` | `withColumn.propagate()` | Children inherit the subgrid. |
110
+ | `Dialog.ActionBar` | `withColumn.center()` | Placed in col 2. |
111
+
112
+ ### Form
113
+
114
+ | Sub-component | withColumn applied | Effect |
115
+ | :------------- | :-------------------- | :---------------------------------- |
116
+ | `Form.Content` | `withColumn.center()` | Placed in col 2 when inside Column. |
117
+ | `Form.Actions` | `withColumn.center()` | Placed in col 2 when inside Column. |
118
+
119
+ ### SearchList
120
+
121
+ | Sub-component | withColumn applied | Effect |
122
+ | :------------------------- | :----------------------- | :---------------------------------------------- |
123
+ | `SearchList.Content` | `withColumn.propagate()` | Extends subgrid to children when inside Column. |
124
+ | `SearchList.Input` wrapper | `withColumn.center()` | Input row placed in col 2. |
125
+
126
+ ### Card
127
+
128
+ `Card.Row` uses its own inline subgrid CSS (`col-span-3 grid grid-cols-subgrid`) and does not
129
+ participate in an outer Column grid. `Card.Root` establishes a separate 3-column grid for its
130
+ own icon-slot layout.
131
+
132
+ ## Subgrid chain integrity
133
+
134
+ Every intermediate container between `Column.Root` and a `ScrollArea.Root` must propagate the
135
+ subgrid, otherwise `ScrollArea.Root`'s `[.dx-column_&]:col-span-full` selector will not match
136
+ and the scrollbar will not extend to the gutter.
137
+
138
+ Required chain:
139
+
140
+ ```
141
+ Column.Root (.dx-column)
142
+ → withColumn.propagate() container (col-span-full, grid, grid-cols-subgrid)
143
+ → ScrollArea.Root (.dx-container, [.dx-column_&]:col-span-full)
144
+ → ScrollArea.Viewport (applies --gutter padding, resets --dx-col)
145
+ ```
146
+
147
+ If any intermediate element wraps the ScrollArea without propagating, use `Column.Bleed` or
148
+ apply `withColumn.propagate()` to that wrapper.
@@ -7,18 +7,16 @@ import React from 'react';
7
7
 
8
8
  import { Input, ScrollArea } from '../../components';
9
9
  import { withLayout, withTheme } from '../../testing';
10
- import { Flex } from '../Flex';
11
-
12
10
  import { Column } from './Column';
13
11
 
14
12
  const List = () => {
15
13
  return (
16
- <ScrollArea.Root margin role='list'>
14
+ <ScrollArea.Root centered>
17
15
  <ScrollArea.Viewport>
18
16
  {Array.from({ length: 100 }).map((_, i) => (
19
- <div key={i} role='listitem' className='p-1 hover:bg-hover-surface'>
20
- Item {i}
21
- </div>
17
+ <Input.Root key={i}>
18
+ <Input.TextInput value={`Item ${i}`} readOnly />
19
+ </Input.Root>
22
20
  ))}
23
21
  </ScrollArea.Viewport>
24
22
  </ScrollArea.Root>
@@ -27,10 +25,10 @@ const List = () => {
27
25
 
28
26
  const DefaultStory = () => {
29
27
  return (
30
- <Column.Root className='h-full overflow-hidden' gutter='md'>
31
- <Column.Segment asChild>
28
+ <Column.Root classNames='overflow-hidden' gutter='md'>
29
+ <Column.Center>
32
30
  <h1 className='p-1 bg-blue-500 text-black'>Header</h1>
33
- </Column.Segment>
31
+ </Column.Center>
34
32
 
35
33
  <Column.Row>
36
34
  <div className='p-1 bg-blue-500'>A</div>
@@ -38,26 +36,36 @@ const DefaultStory = () => {
38
36
  <div className='p-1 bg-blue-500'>C</div>
39
37
  </Column.Row>
40
38
 
41
- <Column.Segment asChild>
42
- <div className='py-2'>
39
+ <Column.Center asChild>
40
+ <div>
43
41
  <Input.Root>
44
42
  <Input.TextInput placeholder='Search' />
45
43
  </Input.Root>
46
44
  </div>
47
- </Column.Segment>
45
+ </Column.Center>
48
46
 
49
- <List />
47
+ <ScrollArea.Root orientation='vertical' padding>
48
+ <ScrollArea.Viewport>
49
+ <div className='flex flex-col gap-2'>
50
+ {Array.from({ length: 100 }).map((_, i) => (
51
+ <Input.Root key={i}>
52
+ <Input.TextInput value={`Item ${i}`} readOnly />
53
+ </Input.Root>
54
+ ))}
55
+ </div>
56
+ </ScrollArea.Viewport>
57
+ </ScrollArea.Root>
50
58
 
51
- <Column.Segment asChild>
52
- <Flex column>
59
+ <Column.Center asChild>
60
+ <div className='flex flex-col'>
53
61
  <h1 className='p-1 bg-red-500 text-black'>Section with overflow</h1>
54
62
  <pre className='p-1 text-xs text-subdued overflow-auto'>{new Error().stack}</pre>
55
- </Flex>
56
- </Column.Segment>
63
+ </div>
64
+ </Column.Center>
57
65
 
58
- <Column.Segment asChild>
66
+ <Column.Center>
59
67
  <div className='p-1 bg-green-500 text-black'>Footer</div>
60
- </Column.Segment>
68
+ </Column.Center>
61
69
  </Column.Root>
62
70
  );
63
71
  };
@@ -76,3 +84,98 @@ export default meta;
76
84
  type Story = StoryObj<typeof meta>;
77
85
 
78
86
  export const Default: Story = {};
87
+
88
+ const InputList = ({ items = 50 }: { items?: number }) => (
89
+ <div className='flex flex-col gap-2'>
90
+ {Array.from({ length: items }).map((_, index) => (
91
+ <Input.Root key={index}>
92
+ <Input.TextInput value={`Item ${index + 1}`} readOnly />
93
+ </Input.Root>
94
+ ))}
95
+ </div>
96
+ );
97
+
98
+ export const WithScrollArea = {
99
+ decorators: [withLayout({ layout: 'column' })],
100
+ render: () => (
101
+ <Column.Root classNames='overflow-hidden' gutter='md'>
102
+ <Column.Center>
103
+ <h2>Header</h2>
104
+ </Column.Center>
105
+ <ScrollArea.Root padding centered orientation='vertical'>
106
+ <ScrollArea.Viewport>
107
+ <InputList items={30} />
108
+ </ScrollArea.Viewport>
109
+ </ScrollArea.Root>
110
+ <Column.Center>
111
+ <h2>Footer</h2>
112
+ </Column.Center>
113
+ </Column.Root>
114
+ ),
115
+ };
116
+
117
+ /**
118
+ * Column.Center places a single element in the center column of the parent grid.
119
+ * Preferred for centered content — safe to nest
120
+ * compound components (Form.Root, Editor.Root, etc.) that render `display: contents`.
121
+ */
122
+ export const WithCenter: Story = {
123
+ decorators: [withLayout({ classNames: 'w-[25rem]' })],
124
+ render: () => (
125
+ <Column.Root gutter='md'>
126
+ <Column.Center>
127
+ <h2>Header (Column.Center)</h2>
128
+ </Column.Center>
129
+ <Column.Center classNames='flex flex-col'>
130
+ <p>This text is inside Column.Center. It sits in the central column between the gutters.</p>
131
+ <Input.Root>
132
+ <Input.Label>Name</Input.Label>
133
+ <Input.TextInput placeholder='Enter name' />
134
+ </Input.Root>
135
+ </Column.Center>
136
+ <Column.Center>
137
+ <h2>Footer (Column.Center)</h2>
138
+ </Column.Center>
139
+ </Column.Root>
140
+ ),
141
+ };
142
+
143
+ /**
144
+ * ScrollArea auto-bleeds inside Column.Root (via [.dx-column_&]:col-span-full).
145
+ * No Column.Bleed wrapper needed.
146
+ */
147
+ export const WithScrollAreaAutoBleed: Story = {
148
+ decorators: [withLayout({ layout: 'column', classNames: 'w-[25rem]' })],
149
+ render: () => (
150
+ <Column.Root classNames='overflow-hidden' gutter='md'>
151
+ <Column.Center>
152
+ <h2>Header (Column.Center)</h2>
153
+ </Column.Center>
154
+ <ScrollArea.Root orientation='vertical' padding thin>
155
+ <ScrollArea.Viewport>
156
+ <InputList items={30} />
157
+ </ScrollArea.Viewport>
158
+ </ScrollArea.Root>
159
+ <Column.Center>
160
+ <h2>Footer (Column.Center)</h2>
161
+ </Column.Center>
162
+ </Column.Root>
163
+ ),
164
+ };
165
+
166
+ export const Experimental = {
167
+ render: () => {
168
+ return (
169
+ <div className='grid grid-cols-[2rem_1fr_2rem]'>
170
+ <div className='col-span-full grid grid-cols-subgrid'>
171
+ <div className='bg-red-surface'>A</div>
172
+ <div className='bg-green-surface'>B</div>
173
+ <div className='bg-blue-surface'>C</div>
174
+ </div>
175
+ <div className='col-span-full grid grid-cols-subgrid col-start-2'>
176
+ <div className='bg-green-surface'>B</div>
177
+ </div>
178
+ </div>
179
+ );
180
+ },
181
+ };
@@ -4,9 +4,9 @@
4
4
 
5
5
  import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
- import React, { type CSSProperties, forwardRef } from 'react';
7
+ import React, { type CSSProperties } from 'react';
8
8
 
9
- import { composableProps } from '@dxos/ui-theme';
9
+ import { composableProps, slottable } from '@dxos/ui-theme';
10
10
  import { type SlottableProps } from '@dxos/ui-types';
11
11
 
12
12
  import { useThemeContext } from '../../hooks';
@@ -17,28 +17,35 @@ import { useThemeContext } from '../../hooks';
17
17
 
18
18
  const COLUMN_ROOT_NAME = 'Column.Root';
19
19
 
20
- type GutterSize = 'sm' | 'md' | 'lg';
20
+ type GutterSize = 'xs' | 'sm' | 'md' | 'lg';
21
21
 
22
22
  const gutterSizes: Record<GutterSize, string> = {
23
+ xs: 'var(--dx-gutter-xs)',
23
24
  sm: 'var(--dx-gutter-sm)',
24
25
  md: 'var(--dx-gutter-md)',
25
26
  lg: 'var(--dx-gutter-lg)',
26
27
  };
27
28
 
28
- type ColumnRootProps = SlottableProps<HTMLDivElement, { gutter?: GutterSize }>;
29
+ type ColumnRootProps = { gutter?: GutterSize };
29
30
 
30
31
  /**
31
- * Creates a vertical channel with left/right gutter columns.
32
- * The `--gutter` CSS variable is set for nested components (Dialog, ScrollArea, Form.Viewport, etc.).
33
- * Use `gutter='sm'` for compact layouts; `gutter='md'` (default) for whitespace layouts (Dialog); `gutter='lg'` for wider spacing.
34
- * Direct children must use Column.Row (spans all 3 cols) or Column.Segment (center col only).
32
+ * Creates a 3-column CSS grid with left/right gutter columns and a center content column.
33
+ * Sets `--gutter` and `--dx-col` CSS variables for nested components.
35
34
  *
36
- * NOTE: The theme applies a `dx-column` marker class to this element.
37
- * ScrollArea.Root detects this via `[.dx-column_&]:col-span-full` to span all 3 grid columns,
38
- * ensuring scroll content extends under the gutters rather than being confined to the center column.
39
- * The `--gutter` CSS variable is also consumed by ScrollArea's `margin` option to align scrollbar spacing.
35
+ * `--dx-col` defaults to `2 / span 1` (center column),
36
+ * enabling `withColumn` utilities to cascade the correct grid placement to slotted children.
37
+ *
38
+ * Direct children participate in the grid in one of several ways:
39
+ * - **Column.Center** — places element in the center column (col 2). Preferred for plain content.
40
+ * - **Column.Bleed** — spans all 3 columns gutter-to-gutter. Preferred for `ScrollArea` and
41
+ * other content that should ignore the gutters.
42
+ * - **Column.Row** — 3-col subgrid row (icons in gutters, content in center).
43
+ *
44
+ * Use `withColumn.center()` / `withColumn.bleed()` helpers to apply placement on slotted elements.
45
+ *
46
+ * Gutter sizes: `'sm'` for compact layouts (Dialog); `'md'` (default); `'lg'` for wider spacing.
40
47
  */
41
- const Root = forwardRef<HTMLDivElement, ColumnRootProps>(
48
+ const ColumnRoot = slottable<HTMLDivElement, ColumnRootProps>(
42
49
  ({ children, asChild, role, gutter = 'md', ...props }, forwardedRef) => {
43
50
  const { className, ...rest } = composableProps(props);
44
51
  const Comp = asChild ? Slot : Primitive.div;
@@ -51,6 +58,7 @@ const Root = forwardRef<HTMLDivElement, ColumnRootProps>(
51
58
  style={
52
59
  {
53
60
  '--gutter': gutterSize,
61
+ '--dx-col': '2 / span 1',
54
62
  gridTemplateColumns: [gutterSize, 'minmax(0,1fr)', gutterSize].join(' '),
55
63
  } as CSSProperties
56
64
  }
@@ -63,7 +71,7 @@ const Root = forwardRef<HTMLDivElement, ColumnRootProps>(
63
71
  },
64
72
  );
65
73
 
66
- Root.displayName = COLUMN_ROOT_NAME;
74
+ ColumnRoot.displayName = COLUMN_ROOT_NAME;
67
75
 
68
76
  //
69
77
  // Row
@@ -71,14 +79,14 @@ Root.displayName = COLUMN_ROOT_NAME;
71
79
 
72
80
  const COLUMN_ROW_NAME = 'Column.Row';
73
81
 
74
- type ColumnRowProps = SlottableProps<HTMLDivElement>;
82
+ type ColumnRowProps = {};
75
83
 
76
84
  /**
77
85
  * Spans all 3 columns of the parent Column.Root and uses CSS subgrid to inherit their sizing.
78
86
  * Children map to: [col-1: icon/slot] [col-2: content] [col-3: icon/action].
79
87
  * Must be a direct child of Column.Root.
80
88
  */
81
- const Row = forwardRef<HTMLDivElement, ColumnRowProps>(({ children, asChild, role, ...props }, forwardedRef) => {
89
+ const ColumnRow = slottable<HTMLDivElement, ColumnRowProps>(({ children, asChild, role, ...props }, forwardedRef) => {
82
90
  const { className, ...rest } = composableProps(props);
83
91
  const Comp = asChild ? Slot : Primitive.div;
84
92
  const { tx } = useThemeContext();
@@ -89,45 +97,69 @@ const Row = forwardRef<HTMLDivElement, ColumnRowProps>(({ children, asChild, rol
89
97
  );
90
98
  });
91
99
 
92
- Row.displayName = COLUMN_ROW_NAME;
100
+ ColumnRow.displayName = COLUMN_ROW_NAME;
93
101
 
94
102
  //
95
- // Segment
103
+ // Bleed
96
104
  //
97
105
 
98
- const COLUMN_SEGMENT_NAME = 'Column.Segment';
106
+ const COLUMN_BLEED_NAME = 'Column.Bleed';
99
107
 
100
- type ColumnSegmentProps = SlottableProps<HTMLDivElement>;
108
+ type ColumnBleedProps = SlottableProps;
101
109
 
102
110
  /**
103
- * Occupies only the center column (col-2) of the parent Column.Root grid.
104
- * Use `asChild` to merge grid positioning onto the child element, eliminating the wrapper div.
105
- * NOTE: Must not use overflow-hidden here since it will clip input focus rings.
111
+ * Spans all 3 columns of the parent Column.Root (gutter-to-gutter).
112
+ * Establishes a CSS subgrid so that grandchildren can participate in the parent column tracks.
113
+ * Use for `ScrollArea`, full-width dividers, tables, or any content that should ignore the gutters.
106
114
  */
107
- const Segment = forwardRef<HTMLDivElement, ColumnSegmentProps>(
108
- ({ children, asChild, role, ...props }, forwardedRef) => {
109
- const { className, ...rest } = composableProps(props);
110
- const Comp = asChild ? Slot : Primitive.div;
111
- const { tx } = useThemeContext();
112
- // With asChild, merge col-start-2 directly onto the child — no contents wrapper needed.
113
- return (
114
- <Comp {...rest} role={role ?? 'none'} className={tx('column.segment', {}, className)} ref={forwardedRef}>
115
- {asChild ? children : <div className='contents'>{children}</div>}
116
- </Comp>
117
- );
118
- },
119
- );
115
+ const ColumnBleed = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
116
+ const { tx } = useThemeContext();
117
+ const { className, ...rest } = composableProps(props);
118
+ const Comp = asChild ? Slot : Primitive.div;
119
+ return (
120
+ <Comp {...rest} className={tx('column.bleed', {}, className)} ref={forwardedRef}>
121
+ {children}
122
+ </Comp>
123
+ );
124
+ });
125
+
126
+ ColumnBleed.displayName = COLUMN_BLEED_NAME;
127
+
128
+ //
129
+ // Center
130
+ //
131
+
132
+ const COLUMN_CENTER_NAME = 'Column.Center';
133
+
134
+ type ColumnCenterProps = SlottableProps;
135
+
136
+ /**
137
+ * Places its element in column 2 (the center track between gutters) of the parent Column.Root.
138
+ * Does NOT use subgrid — placement is explicit on this element only, so it is safe to nest
139
+ * arbitrary compound components (including ones that render `display: contents` wrappers).
140
+ */
141
+ const ColumnCenter = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
142
+ const { tx } = useThemeContext();
143
+ const { className, ...rest } = composableProps(props);
144
+ const Comp = asChild ? Slot : Primitive.div;
145
+ return (
146
+ <Comp {...rest} className={tx('column.center', {}, className)} ref={forwardedRef}>
147
+ {children}
148
+ </Comp>
149
+ );
150
+ });
120
151
 
121
- Segment.displayName = COLUMN_SEGMENT_NAME;
152
+ ColumnCenter.displayName = COLUMN_CENTER_NAME;
122
153
 
123
154
  //
124
155
  // Column
125
156
  //
126
157
 
127
158
  export const Column = {
128
- Root,
129
- Row,
130
- Segment,
159
+ Root: ColumnRoot,
160
+ Row: ColumnRow,
161
+ Bleed: ColumnBleed,
162
+ Center: ColumnCenter,
131
163
  };
132
164
 
133
- export type { ColumnRootProps, ColumnRowProps, ColumnSegmentProps };
165
+ export type { ColumnRootProps, ColumnRowProps, ColumnBleedProps, ColumnCenterProps };
@@ -6,7 +6,6 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
 
8
8
  import { withLayout, withTheme } from '../../testing';
9
-
10
9
  import { Container } from './Container';
11
10
 
12
11
  const DefaultStory = () => (
@@ -2,17 +2,14 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- import React, { forwardRef } from 'react';
6
-
7
- import { composableProps, mx } from '@dxos/ui-theme';
8
- import { Slot } from '@radix-ui/react-slot';
9
- import { SlottableProps } from '@dxos/ui-types';
10
5
  import { Primitive } from '@radix-ui/react-primitive';
6
+ import { Slot } from '@radix-ui/react-slot';
7
+ import React from 'react';
11
8
 
12
- export type ContainerProps = SlottableProps<HTMLDivElement>;
9
+ import { composableProps, mx, slottable } from '@dxos/ui-theme';
13
10
 
14
- export const Container = forwardRef<HTMLDivElement, ContainerProps>(({ children, asChild, ...props }, forwardedRef) => {
15
- const { className, ...rest } = composableProps<HTMLDivElement>(props, { role: 'none' });
11
+ export const Container = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
12
+ const { className, ...rest } = composableProps<HTMLDivElement>(props);
16
13
  const Comp = asChild ? Slot : Primitive.div;
17
14
  return (
18
15
  <Comp {...rest} className={mx('dx-container', className)} ref={forwardedRef}>
@@ -8,7 +8,6 @@ import React from 'react';
8
8
  import { type ChromaticPalette } from '@dxos/ui-types';
9
9
 
10
10
  import { withLayout, withTheme } from '../../testing';
11
-
12
11
  import { Flex } from './Flex';
13
12
 
14
13
  const Cell = ({ label, hue }: { label: string; hue: ChromaticPalette }) => (
@@ -2,28 +2,26 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- import React, { forwardRef } from 'react';
5
+ import { Primitive } from '@radix-ui/react-primitive';
6
+ import { Slot } from '@radix-ui/react-slot';
7
+ import React from 'react';
6
8
 
7
- import { composableProps, mx } from '@dxos/ui-theme';
8
- import { type ComposableProps } from '@dxos/ui-types';
9
+ import { composableProps, mx, slottable } from '@dxos/ui-theme';
9
10
 
10
- export type FlexProps = ComposableProps<HTMLDivElement> & {
11
- column?: boolean;
12
- grow?: boolean;
13
- };
11
+ export type FlexProps = { column?: boolean; grow?: boolean };
14
12
 
15
- export const Flex = forwardRef<HTMLDivElement, FlexProps>(
16
- ({ children, role, column, grow, ...props }, forwardedRef) => {
13
+ export const Flex = slottable<HTMLDivElement, FlexProps>(
14
+ ({ children, asChild, column, grow, ...props }, forwardedRef) => {
17
15
  const { className, ...rest } = composableProps(props);
16
+ const Comp = asChild ? Slot : Primitive.div;
18
17
  return (
19
- <div
18
+ <Comp
20
19
  ref={forwardedRef}
21
20
  {...rest}
22
- role={role ?? 'none'}
23
21
  className={mx('flex', column && 'flex-col', grow && 'flex-1 overflow-hidden', className)}
24
22
  >
25
23
  {children}
26
- </div>
24
+ </Comp>
27
25
  );
28
26
  },
29
27
  );
@@ -8,7 +8,6 @@ import React from 'react';
8
8
  import { type ChromaticPalette } from '@dxos/ui-types';
9
9
 
10
10
  import { withLayout, withTheme } from '../../testing';
11
-
12
11
  import { Grid } from './Grid';
13
12
 
14
13
  const Cell = ({ label, hue }: { label: string; hue: ChromaticPalette }) => (
@@ -2,18 +2,13 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- import React, { forwardRef } from 'react';
5
+ import React from 'react';
6
6
 
7
- import { composableProps, mx } from '@dxos/ui-theme';
8
- import { type ComposableProps } from '@dxos/ui-types';
7
+ import { composable, composableProps, mx } from '@dxos/ui-theme';
9
8
 
10
- export type GridProps = ComposableProps<HTMLDivElement> & {
11
- cols?: number;
12
- rows?: number;
13
- grow?: boolean;
14
- };
9
+ export type GridProps = { cols?: number; rows?: number; grow?: boolean };
15
10
 
16
- export const Grid = forwardRef<HTMLDivElement, GridProps>(
11
+ export const Grid = composable<HTMLDivElement, GridProps>(
17
12
  ({ children, style, role, cols, rows, grow = true, ...props }, forwardedRef) => {
18
13
  const { className, ...rest } = composableProps(props);
19
14
  return (
@@ -5,14 +5,15 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
 
8
- import { Input, ScrollArea, Toolbar } from '../../components';
9
- import { withLayout, withTheme } from '../../testing';
8
+ import { composable, composableProps } from '@dxos/ui-theme';
10
9
 
10
+ import { Input, ScrollArea, ScrollAreaRootProps, Toolbar } from '../../components';
11
+ import { withLayout, withTheme } from '../../testing';
11
12
  import { Panel } from './Panel';
12
13
 
13
- const List = () => {
14
+ const List = composable<HTMLDivElement, ScrollAreaRootProps>((props, forwardedRef) => {
14
15
  return (
15
- <ScrollArea.Root margin role='list'>
16
+ <ScrollArea.Root centered {...composableProps(props, { role: 'list' })} ref={forwardedRef}>
16
17
  <ScrollArea.Viewport>
17
18
  {Array.from({ length: 100 }).map((_, i) => (
18
19
  <div key={i} role='listitem' className='p-1 hover:bg-hover-surface'>
@@ -22,7 +23,7 @@ const List = () => {
22
23
  </ScrollArea.Viewport>
23
24
  </ScrollArea.Root>
24
25
  );
25
- };
26
+ });
26
27
 
27
28
  const DefaultStory = () => {
28
29
  return (
@@ -43,8 +44,8 @@ const DefaultStory = () => {
43
44
 
44
45
  <Panel.Statusbar asChild>
45
46
  <Toolbar.Root classNames='justify-between'>
46
- <Toolbar.IconButton variant='ghost' icon='ph--house--regular' iconOnly label='Add' size={4} />
47
- <Toolbar.IconButton variant='ghost' icon='ph--alarm--regular' iconOnly label='Status' size={4} />
47
+ <Toolbar.IconButton variant='ghost' icon='ph--house--regular' iconOnly label='Add' />
48
+ <Toolbar.IconButton variant='ghost' icon='ph--alarm--regular' iconOnly label='Status' />
48
49
  </Toolbar.Root>
49
50
  </Panel.Statusbar>
50
51
  </Panel.Root>