@dxos/react-ui 0.8.4-main.f9ba587 → 0.8.4-main.fcfe5033a5

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 (475) hide show
  1. package/dist/lib/browser/chunk-OCVRIJCH.mjs +848 -0
  2. package/dist/lib/browser/chunk-OCVRIJCH.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +4115 -61
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +112 -61
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/chunk-QUD5P3RU.mjs +850 -0
  9. package/dist/lib/node-esm/chunk-QUD5P3RU.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +4115 -61
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +112 -61
  14. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  15. package/dist/types/src/components/Avatars/Avatar.d.ts +2 -2
  16. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  17. package/dist/types/src/components/Avatars/Avatar.stories.d.ts +5 -31
  18. package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
  19. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts +5 -11
  20. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
  21. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts +1 -1
  22. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  23. package/dist/types/src/components/Breadcrumb/Breadcrumb.stories.d.ts +8 -20
  24. package/dist/types/src/components/Breadcrumb/Breadcrumb.stories.d.ts.map +1 -1
  25. package/dist/types/src/components/{Buttons → Button}/Button.d.ts +4 -4
  26. package/dist/types/src/components/Button/Button.d.ts.map +1 -0
  27. package/dist/types/src/components/Button/Button.stories.d.ts +17 -0
  28. package/dist/types/src/components/Button/Button.stories.d.ts.map +1 -0
  29. package/dist/types/src/components/{Buttons → Button}/IconButton.d.ts +4 -4
  30. package/dist/types/src/components/Button/IconButton.d.ts.map +1 -0
  31. package/dist/types/src/components/Button/IconButton.stories.d.ts +16 -0
  32. package/dist/types/src/components/Button/IconButton.stories.d.ts.map +1 -0
  33. package/dist/types/src/components/{Buttons → Button}/Toggle.d.ts +2 -2
  34. package/dist/types/src/components/Button/Toggle.d.ts.map +1 -0
  35. package/dist/types/src/components/Button/Toggle.stories.d.ts +16 -0
  36. package/dist/types/src/components/Button/Toggle.stories.d.ts.map +1 -0
  37. package/dist/types/src/components/Button/ToggleGroup.d.ts +27 -0
  38. package/dist/types/src/components/Button/ToggleGroup.d.ts.map +1 -0
  39. package/dist/types/src/components/Button/ToggleGroup.stories.d.ts +27 -0
  40. package/dist/types/src/components/Button/ToggleGroup.stories.d.ts.map +1 -0
  41. package/dist/types/src/components/Button/index.d.ts.map +1 -0
  42. package/dist/types/src/components/Card/Card.d.ts +120 -0
  43. package/dist/types/src/components/Card/Card.d.ts.map +1 -0
  44. package/dist/types/src/components/Card/Card.stories.d.ts +21 -0
  45. package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -0
  46. package/dist/types/src/components/Card/index.d.ts +2 -0
  47. package/dist/types/src/components/Card/index.d.ts.map +1 -0
  48. package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts.map +1 -1
  49. package/dist/types/src/components/Clipboard/CopyButton.d.ts +1 -1
  50. package/dist/types/src/components/Clipboard/CopyButton.d.ts.map +1 -1
  51. package/dist/types/src/components/Clipboard/index.d.ts +10 -1
  52. package/dist/types/src/components/Clipboard/index.d.ts.map +1 -1
  53. package/dist/types/src/components/DensityProvider/DensityProvider.d.ts +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 +51 -0
  56. package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -0
  57. package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts +11 -0
  58. package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts.map +1 -0
  59. package/dist/types/src/components/Dialog/Dialog.d.ts +64 -0
  60. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -0
  61. package/dist/types/src/components/Dialog/Dialog.stories.d.ts +25 -0
  62. package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -0
  63. package/dist/types/src/components/Dialog/index.d.ts.map +1 -0
  64. package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts +1 -1
  65. package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts.map +1 -1
  66. package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts +11 -0
  67. package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts.map +1 -0
  68. package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts +7 -0
  69. package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts.map +1 -0
  70. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts +19 -0
  71. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -0
  72. package/dist/types/src/components/ErrorFallback/ThrowError.d.ts +9 -0
  73. package/dist/types/src/components/ErrorFallback/ThrowError.d.ts.map +1 -0
  74. package/dist/types/src/components/ErrorFallback/index.d.ts +5 -0
  75. package/dist/types/src/components/ErrorFallback/index.d.ts.map +1 -0
  76. package/dist/types/src/components/Focus/Focus.d.ts +36 -0
  77. package/dist/types/src/components/Focus/Focus.d.ts.map +1 -0
  78. package/dist/types/src/components/Focus/Focus.stories.d.ts +9 -0
  79. package/dist/types/src/components/Focus/Focus.stories.d.ts.map +1 -0
  80. package/dist/types/src/components/Focus/index.d.ts +2 -0
  81. package/dist/types/src/components/Focus/index.d.ts.map +1 -0
  82. package/dist/types/src/components/Icon/Icon.d.ts +5 -2
  83. package/dist/types/src/components/Icon/Icon.d.ts.map +1 -1
  84. package/dist/types/src/components/Icon/Icon.stories.d.ts +25 -0
  85. package/dist/types/src/components/Icon/Icon.stories.d.ts.map +1 -0
  86. package/dist/types/src/components/Image/Image.d.ts +14 -0
  87. package/dist/types/src/components/Image/Image.d.ts.map +1 -0
  88. package/dist/types/src/components/Image/Image.stories.d.ts +33 -0
  89. package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -0
  90. package/dist/types/src/components/Image/index.d.ts +2 -0
  91. package/dist/types/src/components/Image/index.d.ts.map +1 -0
  92. package/dist/types/src/components/Input/Input.d.ts +8 -10
  93. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  94. package/dist/types/src/components/Input/Input.stories.d.ts +17 -18
  95. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  96. package/dist/types/src/components/Link/Link.stories.d.ts +8 -8
  97. package/dist/types/src/components/Link/Link.stories.d.ts.map +1 -1
  98. package/dist/types/src/components/{Lists → List}/List.d.ts +8 -6
  99. package/dist/types/src/components/List/List.d.ts.map +1 -0
  100. package/dist/types/src/components/List/List.stories.d.ts +16 -0
  101. package/dist/types/src/components/List/List.stories.d.ts.map +1 -0
  102. package/dist/types/src/components/List/ListDropIndicator.d.ts.map +1 -0
  103. package/dist/types/src/components/{Lists → List}/Tree.d.ts +1 -1
  104. package/dist/types/src/components/List/Tree.d.ts.map +1 -0
  105. package/dist/types/src/components/List/Tree.stories.d.ts +15 -0
  106. package/dist/types/src/components/List/Tree.stories.d.ts.map +1 -0
  107. package/dist/types/src/components/List/TreeDropIndicator.d.ts.map +1 -0
  108. package/dist/types/src/components/{Lists → List}/Treegrid.d.ts +6 -10
  109. package/dist/types/src/components/List/Treegrid.d.ts.map +1 -0
  110. package/dist/types/src/components/List/Treegrid.stories.d.ts +12 -0
  111. package/dist/types/src/components/List/Treegrid.stories.d.ts.map +1 -0
  112. package/dist/types/src/components/List/index.d.ts.map +1 -0
  113. package/dist/types/src/components/Main/Main.d.ts +18 -28
  114. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  115. package/dist/types/src/components/Main/Main.stories.d.ts +6 -10
  116. package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
  117. package/dist/types/src/components/{Menus → Menu}/ContextMenu.d.ts +6 -6
  118. package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -0
  119. package/dist/types/src/components/Menu/ContextMenu.stories.d.ts +12 -0
  120. package/dist/types/src/components/Menu/ContextMenu.stories.d.ts.map +1 -0
  121. package/dist/types/src/components/Menu/DropdownMenu.d.ts +113 -0
  122. package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -0
  123. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts +28 -0
  124. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -0
  125. package/dist/types/src/components/Menu/index.d.ts.map +1 -0
  126. package/dist/types/src/components/Message/Message.d.ts +1 -1
  127. package/dist/types/src/components/Message/Message.d.ts.map +1 -1
  128. package/dist/types/src/components/Message/Message.stories.d.ts +12 -22
  129. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  130. package/dist/types/src/components/Popover/Popover.d.ts +34 -25
  131. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  132. package/dist/types/src/components/Popover/Popover.stories.d.ts +6 -34
  133. package/dist/types/src/components/Popover/Popover.stories.d.ts.map +1 -1
  134. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +27 -27
  135. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  136. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +50 -27
  137. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  138. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +60 -0
  139. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -0
  140. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +23 -0
  141. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -0
  142. package/dist/types/src/components/ScrollContainer/index.d.ts +2 -0
  143. package/dist/types/src/components/ScrollContainer/index.d.ts.map +1 -0
  144. package/dist/types/src/components/Select/Select.d.ts +10 -10
  145. package/dist/types/src/components/Select/Select.d.ts.map +1 -1
  146. package/dist/types/src/components/Select/Select.stories.d.ts +6 -11
  147. package/dist/types/src/components/Select/Select.stories.d.ts.map +1 -1
  148. package/dist/types/src/components/Separator/Separator.d.ts +4 -4
  149. package/dist/types/src/components/Separator/Separator.d.ts.map +1 -1
  150. package/dist/types/src/components/Skeleton/Skeleton.d.ts +12 -0
  151. package/dist/types/src/components/Skeleton/Skeleton.d.ts.map +1 -0
  152. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts +17 -0
  153. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -0
  154. package/dist/types/src/components/Skeleton/index.d.ts +2 -0
  155. package/dist/types/src/components/Skeleton/index.d.ts.map +1 -0
  156. package/dist/types/src/components/Splitter/Splitter.d.ts +34 -0
  157. package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -0
  158. package/dist/types/src/components/Splitter/Splitter.stories.d.ts +7 -0
  159. package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -0
  160. package/dist/types/src/components/Splitter/index.d.ts +2 -0
  161. package/dist/types/src/components/Splitter/index.d.ts.map +1 -0
  162. package/dist/types/src/components/Status/Status.d.ts +3 -4
  163. package/dist/types/src/components/Status/Status.d.ts.map +1 -1
  164. package/dist/types/src/components/Status/Status.stories.d.ts +6 -10
  165. package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
  166. package/dist/types/src/components/Tag/Tag.d.ts +1 -1
  167. package/dist/types/src/components/Tag/Tag.d.ts.map +1 -1
  168. package/dist/types/src/components/Tag/Tag.stories.d.ts +8 -13
  169. package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
  170. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +4 -4
  171. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  172. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts +12 -0
  173. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -0
  174. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +1 -8
  175. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
  176. package/dist/types/src/components/ThemeProvider/index.d.ts +2 -1
  177. package/dist/types/src/components/ThemeProvider/index.d.ts.map +1 -1
  178. package/dist/types/src/components/Toast/Toast.d.ts +19 -19
  179. package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
  180. package/dist/types/src/components/Toast/Toast.stories.d.ts +6 -44
  181. package/dist/types/src/components/Toast/Toast.stories.d.ts.map +1 -1
  182. package/dist/types/src/components/Toolbar/Toolbar.d.ts +40 -22
  183. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  184. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +6 -50
  185. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  186. package/dist/types/src/components/Tooltip/Tooltip.d.ts +10 -12
  187. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  188. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +10 -63
  189. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  190. package/dist/types/src/components/index.d.ts +14 -8
  191. package/dist/types/src/components/index.d.ts.map +1 -1
  192. package/dist/types/src/exemplars/generics.stories.d.ts +19 -0
  193. package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -0
  194. package/dist/types/src/exemplars/slot.stories.d.ts +15 -0
  195. package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -0
  196. package/dist/types/src/exemplars/tabster.stories.d.ts +8 -0
  197. package/dist/types/src/exemplars/tabster.stories.d.ts.map +1 -0
  198. package/dist/types/src/exemplars/virtualizer.stories.d.ts +11 -0
  199. package/dist/types/src/exemplars/virtualizer.stories.d.ts.map +1 -0
  200. package/dist/types/src/hooks/index.d.ts +1 -0
  201. package/dist/types/src/hooks/index.d.ts.map +1 -1
  202. package/dist/types/src/hooks/useDensityContext.d.ts +2 -2
  203. package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
  204. package/dist/types/src/hooks/useElevationContext.d.ts +1 -1
  205. package/dist/types/src/hooks/useElevationContext.d.ts.map +1 -1
  206. package/dist/types/src/hooks/useSafeArea.d.ts.map +1 -1
  207. package/dist/types/src/hooks/useVisualViewport.d.ts +2 -2
  208. package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
  209. package/dist/types/src/index.d.ts +2 -1
  210. package/dist/types/src/index.d.ts.map +1 -1
  211. package/dist/types/src/playground/Controls.stories.d.ts +5 -9
  212. package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
  213. package/dist/types/src/playground/Custom.stories.d.ts +12 -4
  214. package/dist/types/src/playground/Custom.stories.d.ts.map +1 -1
  215. package/dist/types/src/playground/Typography.stories.d.ts +5 -11
  216. package/dist/types/src/playground/Typography.stories.d.ts.map +1 -1
  217. package/dist/types/src/primitives/Column/Column.d.ts +33 -0
  218. package/dist/types/src/primitives/Column/Column.d.ts.map +1 -0
  219. package/dist/types/src/primitives/Column/Column.stories.d.ts +25 -0
  220. package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -0
  221. package/dist/types/src/primitives/Column/index.d.ts +2 -0
  222. package/dist/types/src/primitives/Column/index.d.ts.map +1 -0
  223. package/dist/types/src/primitives/Container/Container.d.ts +7 -0
  224. package/dist/types/src/primitives/Container/Container.d.ts.map +1 -0
  225. package/dist/types/src/primitives/Container/Container.stories.d.ts +6 -0
  226. package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -0
  227. package/dist/types/src/primitives/Container/index.d.ts +2 -0
  228. package/dist/types/src/primitives/Container/index.d.ts.map +1 -0
  229. package/dist/types/src/primitives/Flex/Flex.d.ts +11 -0
  230. package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -0
  231. package/dist/types/src/primitives/Flex/Flex.stories.d.ts +8 -0
  232. package/dist/types/src/primitives/Flex/Flex.stories.d.ts.map +1 -0
  233. package/dist/types/src/primitives/Flex/index.d.ts +2 -0
  234. package/dist/types/src/primitives/Flex/index.d.ts.map +1 -0
  235. package/dist/types/src/primitives/Grid/Grid.d.ts +10 -0
  236. package/dist/types/src/primitives/Grid/Grid.d.ts.map +1 -0
  237. package/dist/types/src/primitives/Grid/Grid.stories.d.ts +8 -0
  238. package/dist/types/src/primitives/Grid/Grid.stories.d.ts.map +1 -0
  239. package/dist/types/src/primitives/Grid/index.d.ts +2 -0
  240. package/dist/types/src/primitives/Grid/index.d.ts.map +1 -0
  241. package/dist/types/src/primitives/Panel/Panel.d.ts +35 -0
  242. package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -0
  243. package/dist/types/src/primitives/Panel/Panel.stories.d.ts +6 -0
  244. package/dist/types/src/primitives/Panel/Panel.stories.d.ts.map +1 -0
  245. package/dist/types/src/primitives/Panel/index.d.ts +2 -0
  246. package/dist/types/src/primitives/Panel/index.d.ts.map +1 -0
  247. package/dist/types/src/primitives/index.d.ts +6 -0
  248. package/dist/types/src/primitives/index.d.ts.map +1 -0
  249. package/dist/types/src/testing/Loading.d.ts +9 -0
  250. package/dist/types/src/testing/Loading.d.ts.map +1 -0
  251. package/dist/types/src/testing/decorators/index.d.ts +2 -1
  252. package/dist/types/src/testing/decorators/index.d.ts.map +1 -1
  253. package/dist/types/src/testing/decorators/withLayout.d.ts +15 -0
  254. package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -0
  255. package/dist/types/src/testing/decorators/withLayoutVariants.d.ts +12 -0
  256. package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -0
  257. package/dist/types/src/testing/decorators/withTheme.d.ts +5 -1
  258. package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
  259. package/dist/types/src/testing/index.d.ts +1 -0
  260. package/dist/types/src/testing/index.d.ts.map +1 -1
  261. package/dist/types/src/translations.d.ts +11 -0
  262. package/dist/types/src/translations.d.ts.map +1 -0
  263. package/dist/types/src/util/index.d.ts +2 -1
  264. package/dist/types/src/util/index.d.ts.map +1 -1
  265. package/dist/types/src/util/usePx.d.ts +8 -0
  266. package/dist/types/src/util/usePx.d.ts.map +1 -0
  267. package/dist/types/tsconfig.tsbuildinfo +1 -1
  268. package/package.json +45 -32
  269. package/src/components/Avatars/Avatar.stories.tsx +23 -16
  270. package/src/components/Avatars/Avatar.tsx +10 -18
  271. package/src/components/Avatars/AvatarGroup.stories.tsx +11 -8
  272. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +19 -15
  273. package/src/components/Breadcrumb/Breadcrumb.tsx +14 -40
  274. package/src/components/{Buttons → Button}/Button.stories.tsx +11 -13
  275. package/src/components/{Buttons → Button}/Button.tsx +12 -26
  276. package/src/components/{Buttons → Button}/IconButton.stories.tsx +18 -13
  277. package/src/components/{Buttons → Button}/IconButton.tsx +21 -16
  278. package/src/components/Button/Toggle.stories.tsx +36 -0
  279. package/src/components/{Buttons → Button}/Toggle.tsx +4 -4
  280. package/src/components/{Buttons → Button}/ToggleGroup.stories.tsx +14 -12
  281. package/src/components/Button/ToggleGroup.tsx +50 -0
  282. package/src/components/Card/Card.stories.tsx +151 -0
  283. package/src/components/Card/Card.tsx +493 -0
  284. package/src/components/Card/index.ts +5 -0
  285. package/src/components/Clipboard/ClipboardProvider.tsx +1 -1
  286. package/src/components/Clipboard/CopyButton.tsx +9 -9
  287. package/src/components/DensityProvider/DensityProvider.tsx +2 -2
  288. package/src/components/Dialog/AlertDialog.stories.tsx +68 -0
  289. package/src/components/Dialog/AlertDialog.tsx +213 -0
  290. package/src/components/Dialog/Dialog.stories.tsx +177 -0
  291. package/src/components/Dialog/Dialog.tsx +285 -0
  292. package/src/components/ElevationProvider/ElevationProvider.tsx +2 -2
  293. package/src/components/ErrorFallback/ErrorFallback.stories.tsx +45 -0
  294. package/src/components/ErrorFallback/ErrorFallback.tsx +70 -0
  295. package/src/components/ErrorFallback/ErrorStack.tsx +114 -0
  296. package/src/components/ErrorFallback/ThrowError.tsx +37 -0
  297. package/src/components/ErrorFallback/index.ts +9 -0
  298. package/src/components/Focus/AUDIT.md +43 -0
  299. package/src/components/Focus/Focus.stories.tsx +230 -0
  300. package/src/components/Focus/Focus.tsx +201 -0
  301. package/src/components/Focus/index.ts +5 -0
  302. package/src/components/Icon/Icon.stories.tsx +143 -0
  303. package/src/components/Icon/Icon.tsx +6 -2
  304. package/src/components/Image/Image.stories.tsx +86 -0
  305. package/src/components/Image/Image.tsx +223 -0
  306. package/src/components/Image/index.ts +5 -0
  307. package/src/components/Input/Input.stories.tsx +27 -49
  308. package/src/components/Input/Input.tsx +51 -87
  309. package/src/components/Link/Link.stories.tsx +11 -8
  310. package/src/components/Link/Link.tsx +2 -2
  311. package/src/components/{Lists → List}/List.stories.tsx +45 -47
  312. package/src/components/{Lists → List}/List.tsx +30 -35
  313. package/src/components/{Lists → List}/ListDropIndicator.tsx +7 -7
  314. package/src/components/{Lists → List}/Tree.stories.tsx +15 -13
  315. package/src/components/{Lists → List}/Tree.tsx +3 -3
  316. package/src/components/{Lists → List}/TreeDropIndicator.tsx +7 -7
  317. package/src/components/{Lists → List}/Treegrid.stories.tsx +39 -34
  318. package/src/components/List/Treegrid.tsx +188 -0
  319. package/src/components/Main/Main.stories.tsx +52 -27
  320. package/src/components/Main/Main.tsx +176 -105
  321. package/src/components/{Menus → Menu}/ContextMenu.stories.tsx +12 -10
  322. package/src/components/{Menus → Menu}/ContextMenu.tsx +10 -33
  323. package/src/components/{Menus → Menu}/DropdownMenu.stories.tsx +13 -11
  324. package/src/components/{Menus → Menu}/DropdownMenu.tsx +157 -120
  325. package/src/components/Message/Message.stories.tsx +36 -18
  326. package/src/components/Message/Message.tsx +43 -34
  327. package/src/components/Popover/Popover.stories.tsx +18 -16
  328. package/src/components/Popover/Popover.tsx +124 -102
  329. package/src/components/ScrollArea/ScrollArea.stories.tsx +224 -32
  330. package/src/components/ScrollArea/ScrollArea.tsx +97 -79
  331. package/src/components/ScrollArea/index.ts +1 -1
  332. package/src/components/ScrollContainer/ScrollContainer.stories.tsx +91 -0
  333. package/src/components/ScrollContainer/ScrollContainer.tsx +347 -0
  334. package/src/components/ScrollContainer/index.ts +5 -0
  335. package/src/components/Select/Select.stories.tsx +19 -17
  336. package/src/components/Select/Select.tsx +16 -32
  337. package/src/components/Separator/Separator.tsx +5 -8
  338. package/src/components/Skeleton/Skeleton.stories.tsx +51 -0
  339. package/src/components/Skeleton/Skeleton.tsx +26 -0
  340. package/src/components/Skeleton/index.ts +5 -0
  341. package/src/components/Splitter/Splitter.stories.tsx +83 -0
  342. package/src/components/Splitter/Splitter.tsx +127 -0
  343. package/src/components/Splitter/index.ts +5 -0
  344. package/src/components/Status/Status.stories.tsx +29 -23
  345. package/src/components/Status/Status.tsx +10 -7
  346. package/src/components/Tag/Tag.stories.tsx +16 -13
  347. package/src/components/Tag/Tag.tsx +3 -8
  348. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +31 -0
  349. package/src/components/ThemeProvider/ThemeProvider.tsx +12 -11
  350. package/src/components/ThemeProvider/TranslationsProvider.tsx +3 -18
  351. package/src/components/ThemeProvider/index.ts +3 -3
  352. package/src/components/Toast/Toast.stories.tsx +13 -11
  353. package/src/components/Toast/Toast.tsx +23 -42
  354. package/src/components/Toolbar/Toolbar.stories.tsx +22 -21
  355. package/src/components/Toolbar/Toolbar.tsx +187 -13
  356. package/src/components/Tooltip/Tooltip.stories.tsx +35 -30
  357. package/src/components/Tooltip/Tooltip.tsx +44 -41
  358. package/src/components/index.ts +15 -9
  359. package/src/exemplars/generics.stories.tsx +41 -0
  360. package/src/exemplars/slot.stories.tsx +117 -0
  361. package/src/exemplars/tabster.stories.tsx +127 -0
  362. package/src/exemplars/virtualizer.stories.tsx +137 -0
  363. package/src/hooks/index.ts +1 -0
  364. package/src/hooks/useDensityContext.ts +3 -3
  365. package/src/hooks/useElevationContext.ts +1 -1
  366. package/src/hooks/useSafeArea.ts +3 -2
  367. package/src/hooks/useSafeCollisionPadding.ts +1 -1
  368. package/src/hooks/useVisualViewport.ts +4 -4
  369. package/src/index.ts +2 -1
  370. package/src/playground/Controls.stories.tsx +20 -24
  371. package/src/playground/Custom.stories.tsx +20 -34
  372. package/src/playground/Typography.stories.tsx +11 -9
  373. package/src/primitives/Column/AUDIT.md +148 -0
  374. package/src/primitives/Column/Column.stories.tsx +181 -0
  375. package/src/primitives/Column/Column.tsx +165 -0
  376. package/src/primitives/Column/index.ts +5 -0
  377. package/src/primitives/Container/Container.stories.tsx +29 -0
  378. package/src/primitives/Container/Container.tsx +19 -0
  379. package/src/primitives/Container/index.ts +5 -0
  380. package/src/primitives/Flex/Flex.stories.tsx +57 -0
  381. package/src/primitives/Flex/Flex.tsx +27 -0
  382. package/src/primitives/Flex/index.ts +5 -0
  383. package/src/primitives/Grid/Grid.stories.tsx +56 -0
  384. package/src/primitives/Grid/Grid.tsx +30 -0
  385. package/src/primitives/Grid/index.ts +5 -0
  386. package/src/primitives/Panel/Panel.stories.tsx +68 -0
  387. package/src/primitives/Panel/Panel.tsx +120 -0
  388. package/src/primitives/Panel/index.ts +5 -0
  389. package/src/primitives/index.ts +9 -0
  390. package/src/testing/Loading.tsx +47 -0
  391. package/src/testing/decorators/index.ts +2 -1
  392. package/src/testing/decorators/withLayout.tsx +77 -0
  393. package/src/testing/decorators/withLayoutVariants.tsx +48 -0
  394. package/src/testing/decorators/withTheme.tsx +37 -0
  395. package/src/testing/index.ts +2 -0
  396. package/src/translations.ts +19 -0
  397. package/src/util/index.ts +3 -1
  398. package/src/util/usePx.ts +62 -0
  399. package/dist/lib/browser/chunk-T6YPS45E.mjs +0 -4376
  400. package/dist/lib/browser/chunk-T6YPS45E.mjs.map +0 -7
  401. package/dist/lib/node-esm/chunk-TYVQJ4KW.mjs +0 -4378
  402. package/dist/lib/node-esm/chunk-TYVQJ4KW.mjs.map +0 -7
  403. package/dist/types/src/components/AnchoredOverflow/AnchoredOverflow.d.ts +0 -15
  404. package/dist/types/src/components/AnchoredOverflow/AnchoredOverflow.d.ts.map +0 -1
  405. package/dist/types/src/components/AnchoredOverflow/index.d.ts +0 -2
  406. package/dist/types/src/components/AnchoredOverflow/index.d.ts.map +0 -1
  407. package/dist/types/src/components/Buttons/Button.d.ts.map +0 -1
  408. package/dist/types/src/components/Buttons/Button.stories.d.ts +0 -12
  409. package/dist/types/src/components/Buttons/Button.stories.d.ts.map +0 -1
  410. package/dist/types/src/components/Buttons/IconButton.d.ts.map +0 -1
  411. package/dist/types/src/components/Buttons/IconButton.stories.d.ts +0 -22
  412. package/dist/types/src/components/Buttons/IconButton.stories.d.ts.map +0 -1
  413. package/dist/types/src/components/Buttons/Toggle.d.ts.map +0 -1
  414. package/dist/types/src/components/Buttons/Toggle.stories.d.ts +0 -19
  415. package/dist/types/src/components/Buttons/Toggle.stories.d.ts.map +0 -1
  416. package/dist/types/src/components/Buttons/ToggleGroup.d.ts +0 -28
  417. package/dist/types/src/components/Buttons/ToggleGroup.d.ts.map +0 -1
  418. package/dist/types/src/components/Buttons/ToggleGroup.stories.d.ts +0 -39
  419. package/dist/types/src/components/Buttons/ToggleGroup.stories.d.ts.map +0 -1
  420. package/dist/types/src/components/Buttons/index.d.ts.map +0 -1
  421. package/dist/types/src/components/Dialogs/AlertDialog.d.ts +0 -31
  422. package/dist/types/src/components/Dialogs/AlertDialog.d.ts.map +0 -1
  423. package/dist/types/src/components/Dialogs/AlertDialog.stories.d.ts +0 -43
  424. package/dist/types/src/components/Dialogs/AlertDialog.stories.d.ts.map +0 -1
  425. package/dist/types/src/components/Dialogs/Dialog.d.ts +0 -31
  426. package/dist/types/src/components/Dialogs/Dialog.d.ts.map +0 -1
  427. package/dist/types/src/components/Dialogs/Dialog.stories.d.ts +0 -48
  428. package/dist/types/src/components/Dialogs/Dialog.stories.d.ts.map +0 -1
  429. package/dist/types/src/components/Dialogs/index.d.ts.map +0 -1
  430. package/dist/types/src/components/Lists/List.d.ts.map +0 -1
  431. package/dist/types/src/components/Lists/List.stories.d.ts +0 -37
  432. package/dist/types/src/components/Lists/List.stories.d.ts.map +0 -1
  433. package/dist/types/src/components/Lists/ListDropIndicator.d.ts.map +0 -1
  434. package/dist/types/src/components/Lists/Tree.d.ts.map +0 -1
  435. package/dist/types/src/components/Lists/Tree.stories.d.ts +0 -41
  436. package/dist/types/src/components/Lists/Tree.stories.d.ts.map +0 -1
  437. package/dist/types/src/components/Lists/TreeDropIndicator.d.ts.map +0 -1
  438. package/dist/types/src/components/Lists/Treegrid.d.ts.map +0 -1
  439. package/dist/types/src/components/Lists/Treegrid.stories.d.ts +0 -10
  440. package/dist/types/src/components/Lists/Treegrid.stories.d.ts.map +0 -1
  441. package/dist/types/src/components/Lists/index.d.ts.map +0 -1
  442. package/dist/types/src/components/Menus/ContextMenu.d.ts.map +0 -1
  443. package/dist/types/src/components/Menus/ContextMenu.stories.d.ts +0 -50
  444. package/dist/types/src/components/Menus/ContextMenu.stories.d.ts.map +0 -1
  445. package/dist/types/src/components/Menus/DropdownMenu.d.ts +0 -112
  446. package/dist/types/src/components/Menus/DropdownMenu.d.ts.map +0 -1
  447. package/dist/types/src/components/Menus/DropdownMenu.stories.d.ts +0 -50
  448. package/dist/types/src/components/Menus/DropdownMenu.stories.d.ts.map +0 -1
  449. package/dist/types/src/components/Menus/index.d.ts.map +0 -1
  450. package/dist/types/src/testing/decorators/withSurfaceVariantsLayout.d.ts +0 -12
  451. package/dist/types/src/testing/decorators/withSurfaceVariantsLayout.d.ts.map +0 -1
  452. package/dist/types/src/util/ThemedClassName.d.ts +0 -5
  453. package/dist/types/src/util/ThemedClassName.d.ts.map +0 -1
  454. package/src/components/AnchoredOverflow/AnchoredOverflow.tsx +0 -59
  455. package/src/components/AnchoredOverflow/index.ts +0 -5
  456. package/src/components/Buttons/Toggle.stories.tsx +0 -33
  457. package/src/components/Buttons/ToggleGroup.tsx +0 -41
  458. package/src/components/Dialogs/AlertDialog.stories.tsx +0 -66
  459. package/src/components/Dialogs/AlertDialog.tsx +0 -172
  460. package/src/components/Dialogs/Dialog.stories.tsx +0 -65
  461. package/src/components/Dialogs/Dialog.tsx +0 -159
  462. package/src/components/Lists/Treegrid.tsx +0 -152
  463. package/src/testing/decorators/withSurfaceVariantsLayout.tsx +0 -51
  464. package/src/testing/decorators/withTheme.ts +0 -22
  465. package/src/util/ThemedClassName.ts +0 -7
  466. /package/dist/types/src/components/{Buttons → Button}/index.d.ts +0 -0
  467. /package/dist/types/src/components/{Dialogs → Dialog}/index.d.ts +0 -0
  468. /package/dist/types/src/components/{Lists → List}/ListDropIndicator.d.ts +0 -0
  469. /package/dist/types/src/components/{Lists → List}/TreeDropIndicator.d.ts +0 -0
  470. /package/dist/types/src/components/{Lists → List}/index.d.ts +0 -0
  471. /package/dist/types/src/components/{Menus → Menu}/index.d.ts +0 -0
  472. /package/src/components/{Buttons → Button}/index.ts +0 -0
  473. /package/src/components/{Dialogs → Dialog}/index.ts +0 -0
  474. /package/src/components/{Lists → List}/index.ts +0 -0
  475. /package/src/components/{Menus → Menu}/index.ts +0 -0
@@ -0,0 +1,45 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React from 'react';
7
+
8
+ import { ErrorBoundary } from '@dxos/react-error-boundary';
9
+
10
+ import { withLayout, withTheme } from '../../testing';
11
+ import { ErrorFallback } from './ErrorFallback';
12
+ import { ThrowError } from './ThrowError';
13
+
14
+ const DefaultStory = () => {
15
+ return (
16
+ <ErrorBoundary name='story' FallbackComponent={ErrorFallback}>
17
+ <ThrowError />
18
+ </ErrorBoundary>
19
+ );
20
+ };
21
+
22
+ const meta: Meta = {
23
+ title: 'ui/react-ui-core/components/ErrorFallback',
24
+ component: ErrorFallback,
25
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
26
+ parameters: {
27
+ layout: 'fullscreen',
28
+ },
29
+ };
30
+
31
+ export default meta;
32
+
33
+ type Story = StoryObj<typeof meta>;
34
+
35
+ export const Default: Story = {
36
+ render: DefaultStory,
37
+ play: async () => {
38
+ // This story intentionally renders an ErrorBoundary fallback; clear the smoke-test error flag.
39
+ (window as any).__ERROR_BOUNDARY_ERRORS__ = [];
40
+ },
41
+ };
42
+
43
+ export const StringError: Story = {
44
+ render: () => <ErrorFallback error='This is a string error message' data={{ context: 'story' }} />,
45
+ };
@@ -0,0 +1,70 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import React, { type PropsWithChildren } from 'react';
6
+ import { type FallbackProps } from 'react-error-boundary';
7
+
8
+ import { safeStringify } from '@dxos/util';
9
+
10
+ import { ErrorStack } from './ErrorStack';
11
+
12
+ export type ErrorFallbackProps = PropsWithChildren<Pick<FallbackProps, 'error'> & { title?: string; data?: any }>;
13
+
14
+ /**
15
+ * Themed fallback component for `ErrorBoundary`.
16
+ */
17
+ export const ErrorFallback = ({ children, error, title, data }: ErrorFallbackProps) => {
18
+ const isDev = process.env.NODE_ENV === 'development';
19
+ const message = error instanceof Error ? error.message : String(error);
20
+
21
+ return (
22
+ <div role='alert' data-testid='error-boundary-fallback' className='flex flex-col p-4 gap-4 overflow-auto'>
23
+ <h1 className='text-lg text-info-text'>{title ?? 'Runtime Error'}</h1>
24
+ <p>{message}</p>
25
+
26
+ {isDev && error instanceof Error && (
27
+ <Section
28
+ title='Stack'
29
+ onClick={() => {
30
+ const text = error instanceof Error ? (error.stack ?? error.message) : String(error);
31
+ void navigator.clipboard.writeText(text);
32
+ }}
33
+ >
34
+ <ErrorStack error={error} />
35
+ </Section>
36
+ )}
37
+
38
+ {data && (
39
+ <Section
40
+ title='Data'
41
+ onClick={() => {
42
+ void navigator.clipboard.writeText(JSON.stringify(data, undefined, 2));
43
+ }}
44
+ >
45
+ <pre className='overflow-x-auto text-xs'>{safeStringify(data, undefined, 2)}</pre>
46
+ </Section>
47
+ )}
48
+
49
+ {children}
50
+ </div>
51
+ );
52
+ };
53
+
54
+ const Section = ({ children, title, onClick }: PropsWithChildren<{ title?: string; onClick?: () => void }>) => {
55
+ return (
56
+ <div className='flex flex-col gap-1'>
57
+ {onClick && (
58
+ <button
59
+ type='button'
60
+ onClick={onClick}
61
+ className='flex items-center gap-1 text-xs text-subdued hover:text-primary-500 transition-colors'
62
+ title={`Copy ${title}`}
63
+ >
64
+ <h2 className='text-xs uppercase text-subdued'>{title}</h2>
65
+ </button>
66
+ )}
67
+ {children}
68
+ </div>
69
+ );
70
+ };
@@ -0,0 +1,114 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import ErrorStackParser from 'error-stack-parser';
6
+ import React from 'react';
7
+
8
+ import { mx } from '@dxos/ui-theme';
9
+
10
+ type LocalFrame = { href: string; fileName: string };
11
+
12
+ export type ParsedStackFrame = ReturnType<typeof ErrorStackParser.parse>[number];
13
+
14
+ export type ErrorStackProps = {
15
+ /** When set, these frames are shown instead of parsing `error`. */
16
+ frames?: ParsedStackFrame[];
17
+ /** Used when `frames` is omitted. */
18
+ error?: Error;
19
+ };
20
+
21
+ /**
22
+ * Parses `captureOwnerStack()` output (React dev) into frames for {@link ErrorStack}.
23
+ * Prefixes a synthetic Error line when needed so `error-stack-parser` can read V8-style stacks.
24
+ */
25
+ export const parseCaptureOwnerStack = (stack: string | null): ParsedStackFrame[] | null => {
26
+ if (stack == null || stack.length === 0) {
27
+ return null;
28
+ }
29
+ const err = new Error();
30
+ err.stack = stack;
31
+ try {
32
+ return ErrorStackParser.parse(err);
33
+ } catch {
34
+ err.stack = `Error\n${stack}`;
35
+ try {
36
+ return ErrorStackParser.parse(err);
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+ };
42
+
43
+ /**
44
+ * Renders a parsed error stack trace with tree connector symbols and clickable vscode:// links for local frames.
45
+ */
46
+ export const ErrorStack = ({ error, frames: framesProp }: ErrorStackProps) => {
47
+ const frames = framesProp ?? (error ? ErrorStackParser.parse(error) : []);
48
+ if (frames.length === 0) {
49
+ return null;
50
+ }
51
+
52
+ return (
53
+ <div className='font-mono text-sm'>
54
+ {frames.map((frame, i) => {
55
+ const isLast = i === frames.length - 1;
56
+ const local = frame.fileName
57
+ ? parseLocalFrame(frame.fileName, frame.lineNumber, frame.columnNumber)
58
+ : undefined;
59
+ const name = frame.functionName ?? '<anonymous>';
60
+ return (
61
+ <div
62
+ key={i}
63
+ className={mx(
64
+ 'grid grid-cols-[16px_1fr_auto_auto] items-stretch gap-x-2',
65
+ local && 'cursor-pointer hover:bg-hover-surface',
66
+ )}
67
+ >
68
+ {/* Tree connector: vertical line full-height + horizontal branch at midpoint */}
69
+ <div className='relative'>
70
+ <div
71
+ className={mx(
72
+ 'absolute left-1/2 -translate-x-1/2 w-px bg-neutral-500',
73
+ isLast ? 'top-0 h-1/2' : 'inset-y-0',
74
+ )}
75
+ />
76
+ <div className='absolute top-1/2 -translate-y-1/2 left-1/2 right-0 h-px bg-neutral-500' />
77
+ </div>
78
+ {local ? (
79
+ <a href={local.href} className='truncate self-center'>
80
+ {name}
81
+ </a>
82
+ ) : (
83
+ <span className='text-subdued truncate self-center'>{name}</span>
84
+ )}
85
+ <span className='text-xs text-subdued truncate self-center'>{local?.fileName ?? ''}</span>
86
+ <span className='text-xs text-subdued text-right self-center'>
87
+ {local ? `${frame.lineNumber}:${frame.columnNumber}` : ''}
88
+ </span>
89
+ </div>
90
+ );
91
+ })}
92
+ </div>
93
+ );
94
+ };
95
+
96
+ /**
97
+ * Parses a Vite `/@fs/` URL into a `vscode://` deep link and short filename.
98
+ * Returns undefined if the URL cannot be resolved to a local file.
99
+ */
100
+ const parseLocalFrame = (fileUrl: string, line?: number, col?: number): LocalFrame | undefined => {
101
+ try {
102
+ const { pathname } = new URL(fileUrl);
103
+ if (!pathname.startsWith('/@fs/')) {
104
+ return undefined;
105
+ }
106
+ const localPath = pathname.slice(4); // /@fs/Users/... → /Users/...
107
+ return {
108
+ href: `vscode://file/${localPath}:${line ?? 1}:${col ?? 1}`,
109
+ fileName: pathname.split('/').pop() ?? localPath,
110
+ };
111
+ } catch {
112
+ return undefined;
113
+ }
114
+ };
@@ -0,0 +1,37 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { useEffect, useState } from 'react';
6
+
7
+ export type ThrowErrorProps = {
8
+ error?: () => Error;
9
+ delay?: number;
10
+ };
11
+
12
+ /**
13
+ * Use this to debug the error boundary.
14
+ */
15
+ export const ThrowError = ({ delay = 1_000, ...props }: ThrowErrorProps) => {
16
+ const [error, setError] = useState<Error>();
17
+ useEffect(() => {
18
+ if (delay < 0) {
19
+ return;
20
+ }
21
+
22
+ const t = setTimeout(() => {
23
+ setError(generator({ delay, ...props }));
24
+ }, delay);
25
+ return () => clearTimeout(t);
26
+ }, [delay, generator]);
27
+
28
+ if (error) {
29
+ throw error;
30
+ }
31
+
32
+ return null;
33
+ };
34
+
35
+ const generator = ({ error, delay }: ThrowErrorProps) => {
36
+ return error?.() ?? new Error(`Error generated after ${delay}ms`);
37
+ };
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { ErrorBoundary, type ErrorBoundaryProps, type FallbackProps } from '@dxos/react-error-boundary';
6
+
7
+ export * from './ErrorFallback';
8
+ export * from './ErrorStack';
9
+ export * from './ThrowError';
@@ -0,0 +1,43 @@
1
+ # Focus
2
+
3
+ ## Problem
4
+
5
+ Grid cells use `overflow-hidden` which clips outward CSS `ring` (box-shadow) and `outline` styles.
6
+ Using `border` for focus indicators creates doubled lines at grid cell boundaries.
7
+ Inset `box-shadow` alone is obscured by child elements with backgrounds (e.g., toolbar headers).
8
+
9
+ ## Solution
10
+
11
+ Uses a `::after` pseudo-element overlay with `ring-inset` to paint the focus ring above all child content.
12
+ The pseudo-element is absolutely positioned, `pointer-events-none`, and inherits `border-radius`.
13
+
14
+ - **Default**: ring is transparent (invisible until focused).
15
+ - **`border` prop**: shows a CSS `border-separator` when unfocused (e.g., for grid cell edges).
16
+ - **Focus/active/error states**: ring color changes to the appropriate indicator color.
17
+
18
+ Both `Focus.Group` and `Focus.Item` support the `border` prop.
19
+
20
+ ## Why `::after` overlay
21
+
22
+ | Approach | Clipped? | Obscured by children? | Notes |
23
+ | ------------------------ | -------- | --------------------- | --------------------------------------------------------------------- |
24
+ | `ring` (outward) | Yes | N/A | Extends outside bounds, clipped by parent `overflow-hidden`. |
25
+ | `ring-inset` | No | Yes | Inset box-shadow is part of background layer; children paint over it. |
26
+ | `::after` + `ring-inset` | No | No | Pseudo-element paints above children. Requires `position: relative`. |
27
+
28
+ ## Relationship to `dx-focus-ring-inset-over-all`
29
+
30
+ The CSS class `dx-focus-ring-inset-over-all` (in `focus-ring.css`) uses the same `::after` technique
31
+ but only reacts to `:focus-visible`. `Focus.Group/Item` additionally support programmatic states
32
+ via `data-focus-state` (`active`, `error`).
33
+
34
+ ## Clean-up
35
+
36
+ - [ ] Unify: extend `dx-focus-ring-inset-over-all` to support `data-focus-state` attributes,
37
+ then have `Focus.Group/Item` use the CSS class instead of inline Tailwind utilities.
38
+ Consumers: Plank, StackItem, Tabs, AttentionProvider, main sidebar.
39
+
40
+ ## Audit
41
+
42
+ - [ ] Create a list of all container components (outside of `react-ui`) that directly use `overflow-hidden`;
43
+ Consider containers to be components that have `children` and expand (e.g., `grid`, `grow`, `h-full`, `w-full`).
@@ -0,0 +1,230 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { type PropsWithChildren, useState } from 'react';
7
+
8
+ import { mx } from '@dxos/ui-theme';
9
+
10
+ import { withLayout, withTheme } from '../../testing';
11
+ import { type ThemedClassName } from '../../util';
12
+ import { Focus } from './Focus';
13
+
14
+ type Item = { id: string; label: string };
15
+
16
+ const ITEMS: Item[] = [
17
+ { id: '1', label: 'Item 1' },
18
+ { id: '2', label: 'Item 2' },
19
+ { id: '3', label: 'Item 3' },
20
+ { id: '4', label: 'Item 4' },
21
+ { id: '5', label: 'Item 5' },
22
+ ];
23
+
24
+ const itemClassName = 'flex items-center gap-3 px-3 py-2 aria-current:bg-neutral-75 dark:aria-current:bg-neutral-800';
25
+
26
+ const Container = ({ classNames, children }: ThemedClassName<PropsWithChildren>) => {
27
+ return (
28
+ <div className='dx-container grid grid-cols-[1fr_2fr_1fr]'>
29
+ <div className='border-e border-separator' />
30
+ <div className='dx-expander grid grid-rows-[1fr_2fr_1fr]'>
31
+ <div className='border-b border-separator' />
32
+ <div className={mx('h-full flex flex-col gap-2', classNames)}>{children}</div>
33
+ <div className='border-t border-separator' />
34
+ </div>
35
+ <div className='border-s border-separator' />
36
+ </div>
37
+ );
38
+ };
39
+
40
+ const Text = ({ children }: PropsWithChildren) => {
41
+ return <p className='p-1 text-sm text-subdued'>{children}</p>;
42
+ };
43
+
44
+ //
45
+ // Default (vertical list)
46
+ //
47
+
48
+ const DefaultStory = () => {
49
+ const [current, setCurrent] = useState<string | undefined>('1');
50
+
51
+ return (
52
+ <Container>
53
+ <Text>Tab into the group, then use arrow keys to navigate. Press Enter to select.</Text>
54
+ <Focus.Group classNames='h-full'>
55
+ {ITEMS.map((item) => (
56
+ <Focus.Item
57
+ key={item.id}
58
+ current={current === item.id}
59
+ onCurrentChange={() => setCurrent(item.id)}
60
+ className={itemClassName}
61
+ >
62
+ <span className='size-2 bg-primary-500 opacity-0 aria-[current]:opacity-100' />
63
+ <span>{item.label}</span>
64
+ </Focus.Item>
65
+ ))}
66
+ </Focus.Group>
67
+ <Text>Selected: {current ?? 'none'}</Text>
68
+ </Container>
69
+ );
70
+ };
71
+
72
+ //
73
+ // Horizontal group
74
+ //
75
+
76
+ const HorizontalStory = () => {
77
+ const [current, setCurrent] = useState<string | undefined>();
78
+
79
+ return (
80
+ <Container>
81
+ <Text>Horizontal arrow-key navigation between cards.</Text>
82
+ <Focus.Group classNames='h-full flex flex-row gap-2 items-center justify-center' orientation='horizontal'>
83
+ {ITEMS.map((item) => (
84
+ <Focus.Item
85
+ key={item.id}
86
+ current={current === item.id}
87
+ onCurrentChange={() => setCurrent(item.id)}
88
+ className='flex flex-col items-center justify-center w-20 h-20 border border-separator aria-current:border-primary-500 aria-current:bg-primary-50 dark:aria-current:bg-primary-900/20 cursor-pointer'
89
+ >
90
+ <span className='text-xs mt-1'>{item.label}</span>
91
+ </Focus.Item>
92
+ ))}
93
+ </Focus.Group>
94
+ <Text>Selected: {current ?? 'none'}</Text>
95
+ </Container>
96
+ );
97
+ };
98
+
99
+ //
100
+ // Grid (demonstrates border prop and overflow-hidden clipping)
101
+ //
102
+
103
+ const GridCell = ({ border, items }: { border?: boolean; items: Item[] }) => {
104
+ const [current, setCurrent] = useState<string | undefined>();
105
+ return (
106
+ <div className='overflow-hidden bg-base-surface'>
107
+ <Focus.Group classNames='h-full' border={border}>
108
+ {items.map((item) => (
109
+ <Focus.Item
110
+ key={item.id}
111
+ current={current === item.id}
112
+ onCurrentChange={() => setCurrent(item.id)}
113
+ className={itemClassName}
114
+ >
115
+ <span>{item.label}</span>
116
+ </Focus.Item>
117
+ ))}
118
+ </Focus.Group>
119
+ </div>
120
+ );
121
+ };
122
+
123
+ const GridStory = () => {
124
+ return (
125
+ <div className='p-8 space-y-8'>
126
+ <Text>Tab between groups to compare. Each cell has overflow-hidden.</Text>
127
+
128
+ {/* Default vs border. */}
129
+ <div className='grid grid-cols-2 gap-4'>
130
+ <div className='space-y-2'>
131
+ <p className='text-xs font-mono text-subdued'>Default (invisible until focused)</p>
132
+ <div className='h-48'>
133
+ <GridCell items={ITEMS} />
134
+ </div>
135
+ </div>
136
+ <div className='space-y-2'>
137
+ <p className='text-xs font-mono text-subdued'>border (always visible)</p>
138
+ <div className='h-48'>
139
+ <GridCell border items={ITEMS} />
140
+ </div>
141
+ </div>
142
+ </div>
143
+
144
+ {/* Tight grid — border. */}
145
+ <p className='text-xs font-mono text-subdued'>Tight grid — border</p>
146
+ <div className='grid grid-cols-3'>
147
+ {[0, 1, 2].map((col) => (
148
+ <div key={col} className='overflow-hidden'>
149
+ <GridCell border items={ITEMS.slice(0, 3)} />
150
+ </div>
151
+ ))}
152
+ </div>
153
+
154
+ {/* Tight grid — default. */}
155
+ <p className='text-xs font-mono text-subdued'>Tight grid — default</p>
156
+ <div className='grid grid-cols-3'>
157
+ {[0, 1, 2].map((col) => (
158
+ <div key={col} className='overflow-hidden'>
159
+ <GridCell items={ITEMS.slice(0, 3)} />
160
+ </div>
161
+ ))}
162
+ </div>
163
+
164
+ {/* Item-level border. */}
165
+ <p className='text-xs font-mono text-subdued'>Item-level border</p>
166
+ <div className='h-48 overflow-hidden'>
167
+ <Focus.Group classNames='h-full'>
168
+ {ITEMS.slice(0, 3).map((item) => (
169
+ <Focus.Item key={item.id} border className={itemClassName}>
170
+ <span>{item.label}</span>
171
+ </Focus.Item>
172
+ ))}
173
+ </Focus.Group>
174
+ </div>
175
+
176
+ {/* Error state. */}
177
+ <p className='text-xs font-mono text-subdued'>Error state</p>
178
+ <div className='h-48 overflow-hidden'>
179
+ <Focus.Group classNames='h-full' data-focus-state='error'>
180
+ {ITEMS.slice(0, 3).map((item) => (
181
+ <Focus.Item key={item.id} className={itemClassName}>
182
+ <span>{item.label}</span>
183
+ </Focus.Item>
184
+ ))}
185
+ </Focus.Group>
186
+ </div>
187
+ </div>
188
+ );
189
+ };
190
+
191
+ //
192
+ // asChild (slot) usage
193
+ //
194
+
195
+ const AsChildStory = () => {
196
+ const [current, setCurrent] = useState<string | undefined>();
197
+
198
+ return (
199
+ <Container>
200
+ <Text>Focus.Item rendered as a custom element via asChild.</Text>
201
+ <Focus.Group classNames='h-full'>
202
+ {ITEMS.slice(0, 3).map((item) => (
203
+ <Focus.Item key={item.id} asChild current={current === item.id} onCurrentChange={() => setCurrent(item.id)}>
204
+ <button className='flex w-full items-center gap-3 px-3 py-2 text-left hover:bg-neutral-75 dark:hover:bg-neutral-800 aria-current:bg-primary-50 dark:aria-current:bg-primary-900/20 aria-current:text-primary-600'>
205
+ <span>{item.label}</span>
206
+ </button>
207
+ </Focus.Item>
208
+ ))}
209
+ </Focus.Group>
210
+ </Container>
211
+ );
212
+ };
213
+
214
+ //
215
+ // Meta
216
+ //
217
+
218
+ const meta: Meta = {
219
+ title: 'ui/react-ui-core/components/Focus',
220
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
221
+ };
222
+
223
+ export default meta;
224
+
225
+ type Story = StoryObj<typeof meta>;
226
+
227
+ export const Default: Story = { render: DefaultStory };
228
+ export const Horizontal: Story = { render: HorizontalStory };
229
+ export const Grid: Story = { render: GridStory };
230
+ export const AsChild: Story = { render: AsChildStory };