@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
@@ -4,17 +4,19 @@
4
4
 
5
5
  import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
+ import DOMPurify from 'dompurify';
7
8
  import React, {
8
9
  CSSProperties,
9
- type HTMLAttributes,
10
+ MouseEventHandler,
10
11
  type PropsWithChildren,
11
12
  createContext,
12
13
  forwardRef,
13
14
  useContext,
15
+ useMemo,
14
16
  } from 'react';
15
17
 
16
- import { composableProps, largeIconSize, mx } from '@dxos/ui-theme';
17
- import { type Density, type SlottableProps } from '@dxos/ui-types';
18
+ import { composable, composableProps, iconSize, mx, slottable } from '@dxos/ui-theme';
19
+ import { type Density } from '@dxos/ui-types';
18
20
 
19
21
  import { useThemeContext } from '../../hooks';
20
22
  import { Column } from '../../primitives';
@@ -35,6 +37,8 @@ import {
35
37
  // Context
36
38
  //
37
39
 
40
+ const CARD_NAME = 'Card';
41
+
38
42
  type CardContextValue = {
39
43
  menuItems?: CardMenuItem<any>[];
40
44
  };
@@ -46,84 +50,115 @@ const CardContext = createContext<CardContextValue>({});
46
50
  // Root
47
51
  //
48
52
 
49
- type CardRootProps = SlottableProps<
50
- HTMLDivElement,
51
- {
52
- id?: string;
53
- border?: boolean;
54
- fullWidth?: boolean;
55
- density?: Density;
56
- }
57
- >;
53
+ const CARD_ROOT_NAME = 'Card.Root';
54
+
55
+ type CardRootProps = {
56
+ id?: string;
57
+ border?: boolean;
58
+ fullWidth?: boolean;
59
+ density?: Density;
60
+ style?: CSSProperties;
61
+ tabIndex?: number;
62
+ onClick?: MouseEventHandler<HTMLDivElement>;
63
+ 'data-selected'?: boolean;
64
+ 'data-testid'?: string;
65
+ };
58
66
 
59
- const CardRoot = forwardRef<HTMLDivElement, CardRootProps>(
60
- ({ children, id, asChild, role, border = true, fullWidth, density, ...props }, forwardedRef) => {
67
+ /**
68
+ * `Card.Root` does not support `asChild`. The Column grid is the root element
69
+ * (one `<div>` carrying both the `dx-card` and `dx-column-root` classes
70
+ * instead of the previous outer-card + inner-column pair), so caller-provided
71
+ * HTML attributes — `onClick`, `tabIndex`, `style`, `data-*`, `grid-template-rows`
72
+ * overrides via `classNames` — land directly on the grid container.
73
+ * Slot-parents (`Focus.Item asChild`, `Mosaic.Tile asChild`, etc.) continue to
74
+ * work because `composable()` preserves the COMPOSABLE marker that slottable parents
75
+ * check before warning, and Radix `Slot` merges the parent's props onto the inner
76
+ * `<div>` exactly the way `slottable`'s `Slot`/`Primitive.div` branch did.
77
+ */
78
+ const CardRoot = composable<HTMLDivElement, CardRootProps>(
79
+ ({ children, id, role, border = true, fullWidth, density, ...props }, forwardedRef) => {
61
80
  const { className, ...rest } = composableProps(props);
62
- const Comp = asChild ? Slot : Primitive.div;
63
81
  const { tx } = useThemeContext();
64
82
 
65
83
  return (
66
- <Comp
67
- {...rest}
68
- {...(id && { 'data-object-id': id })}
84
+ <Column.Root
85
+ asChild
86
+ gutter={density === 'coarse' ? 'lg' : 'md'}
87
+ classNames={tx('card.root', { border, fullWidth }, className)}
69
88
  role={role ?? 'group'}
70
- className={tx('card.root', { border, fullWidth }, className)}
71
- ref={forwardedRef}
72
89
  >
73
- <Column.Root gutter={density === 'coarse' ? 'lg' : 'md'}>{children}</Column.Root>
74
- </Comp>
90
+ <div {...rest} {...(id && { 'data-object-id': id })} ref={forwardedRef}>
91
+ {children}
92
+ </div>
93
+ </Column.Root>
75
94
  );
76
95
  },
77
96
  );
78
97
 
98
+ CardRoot.displayName = CARD_ROOT_NAME;
99
+
79
100
  //
80
101
  // Toolbar
81
102
  //
82
103
 
104
+ const CARD_TOOLBAR_NAME = 'Card.Toolbar';
105
+
83
106
  type CardToolbarProps = ToolbarRootProps;
84
107
 
85
- const CardToolbar = forwardRef<HTMLDivElement, CardToolbarProps>(({ children, classNames, ...props }, forwardedRef) => {
108
+ const CardToolbar = composable<HTMLDivElement, CardToolbarProps>(({ children, classNames, ...props }, forwardedRef) => {
86
109
  const { tx } = useThemeContext();
87
110
 
88
111
  return (
89
- <Toolbar.Root {...props} style={largeIconSize} classNames={[tx('card.toolbar', {}), classNames]} ref={forwardedRef}>
112
+ <Toolbar.Root {...props} style={iconSize(5)} classNames={[tx('card.toolbar', {}), classNames]} ref={forwardedRef}>
90
113
  {children}
91
114
  </Toolbar.Root>
92
115
  );
93
116
  });
94
117
 
118
+ CardToolbar.displayName = CARD_TOOLBAR_NAME;
119
+
95
120
  //
96
121
  // DragHandle
97
122
  //
98
123
 
124
+ const CARD_DRAG_HANDLE_NAME = 'Card.DragHandle';
125
+
99
126
  type CardDragHandleProps = ToolbarDragHandleProps;
100
127
 
101
128
  const CardDragHandle = forwardRef<HTMLButtonElement, CardDragHandleProps>((props, forwardedRef) => {
102
129
  return (
103
- <CardIconBlock>
104
- <Toolbar.DragHandle {...props} testId='card-drag-handle' ref={forwardedRef} />
130
+ <CardIconBlock padding>
131
+ <Toolbar.DragHandle {...props} ref={forwardedRef} />
105
132
  </CardIconBlock>
106
133
  );
107
134
  });
108
135
 
136
+ CardDragHandle.displayName = CARD_DRAG_HANDLE_NAME;
137
+
109
138
  //
110
139
  // CloseIconButton
111
140
  //
112
141
 
142
+ const CARD_CLOSE_ICON_BUTTON_NAME = 'Card.CloseIconButton';
143
+
113
144
  type CloseIconButtonProps = ToolbarCloseIconButtonProps;
114
145
 
115
146
  const CloseIconButton = forwardRef<HTMLButtonElement, CloseIconButtonProps>((props, forwardedRef) => {
116
147
  return (
117
- <CardIconBlock>
148
+ <CardIconBlock padding>
118
149
  <Toolbar.CloseIconButton {...props} ref={forwardedRef} />
119
150
  </CardIconBlock>
120
151
  );
121
152
  });
122
153
 
154
+ CloseIconButton.displayName = CARD_CLOSE_ICON_BUTTON_NAME;
155
+
123
156
  //
124
157
  // Menu
125
158
  //
126
159
 
160
+ const CARD_MENU_NAME = 'Card.Menu';
161
+
127
162
  type CardMenuItem<T extends any | void = void> = ToolbarMenuItem<T>;
128
163
 
129
164
  type CardMenuProps<T extends any | void = void> = ToolbarMenuProps<T>;
@@ -133,16 +168,20 @@ const CardMenu = <T extends any | void = void>({ context, items, ...props }: Car
133
168
  const combinedItems = [...(items ?? []), ...((menuItems as CardMenuItem<T>[]) ?? [])];
134
169
 
135
170
  return (
136
- <CardIconBlock>
171
+ <CardIconBlock padding>
137
172
  <Toolbar.Menu {...props} context={context} items={combinedItems} />
138
173
  </CardIconBlock>
139
174
  );
140
175
  };
141
176
 
177
+ (CardMenu as any).displayName = CARD_MENU_NAME;
178
+
142
179
  //
143
180
  // Icon
144
181
  //
145
182
 
183
+ const CARD_ICON_NAME = 'Card.Icon';
184
+
146
185
  const CardIcon = (props: IconProps) => {
147
186
  return (
148
187
  <CardIconBlock>
@@ -151,101 +190,126 @@ const CardIcon = (props: IconProps) => {
151
190
  );
152
191
  };
153
192
 
193
+ (CardIcon as any).displayName = CARD_ICON_NAME;
194
+
154
195
  //
155
196
  // IconBlock
156
197
  //
157
198
 
158
- const CardIconBlock = forwardRef<HTMLDivElement, ThemedClassName<PropsWithChildren>>(
159
- ({ classNames, children, ...props }, forwardedRef) => {
199
+ const CARD_ICON_BLOCK_NAME = 'Card.IconBlock';
200
+
201
+ const CardIconBlock = forwardRef<HTMLDivElement, ThemedClassName<PropsWithChildren<{ padding?: boolean }>>>(
202
+ ({ classNames, children, padding, ...props }, forwardedRef) => {
160
203
  const { tx } = useThemeContext();
204
+
161
205
  return (
162
- <div {...props} role='none' className={tx('card.icon-block', {}, classNames)} ref={forwardedRef}>
206
+ <div {...props} className={tx('card.icon-block', { padding }, classNames)} ref={forwardedRef}>
163
207
  {children}
164
208
  </div>
165
209
  );
166
210
  },
167
211
  );
168
212
 
213
+ CardIconBlock.displayName = CARD_ICON_BLOCK_NAME;
214
+
169
215
  //
170
216
  // Title
171
217
  //
172
218
 
173
- type CardTitleProps = SlottableProps<HTMLDivElement>;
219
+ const CARD_TITLE_NAME = 'Card.Title';
174
220
 
175
- const CardTitle = forwardRef<HTMLDivElement, CardTitleProps>(({ children, asChild, role, ...props }, forwardedRef) => {
176
- const { className, ...rest } = composableProps(props);
177
- const Comp = asChild ? Slot : Primitive.div;
221
+ const CardTitle = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
178
222
  const { tx } = useThemeContext();
223
+ const { className, ...rest } = composableProps(props, { role: 'heading' });
224
+ const Comp = asChild ? Slot : Primitive.div;
179
225
 
180
226
  return (
181
- <Comp {...rest} role={role ?? 'heading'} className={tx('card.title', {}, className)} ref={forwardedRef}>
227
+ <Comp {...rest} className={tx('card.title', {}, className)} ref={forwardedRef}>
182
228
  {children}
183
229
  </Comp>
184
230
  );
185
231
  });
186
232
 
233
+ CardTitle.displayName = CARD_TITLE_NAME;
234
+
187
235
  //
188
236
  // Content
189
237
  //
190
238
 
191
- type CardContentProps = SlottableProps<HTMLDivElement>;
239
+ const CARD_CONTENT_NAME = 'Card.Content';
192
240
 
193
- const CardContent = forwardRef<HTMLDivElement, CardContentProps>(({ children, role, ...props }, forwardedRef) => {
241
+ const CardContent = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
242
+ const { className, ...rest } = composableProps(props);
243
+ const Comp = asChild ? Slot : Primitive.div;
194
244
  const { tx } = useThemeContext();
195
245
 
196
246
  return (
197
- <div {...props} role={role ?? 'none'} className={tx('card.content', {})} ref={forwardedRef}>
247
+ <Comp {...rest} className={tx('card.content', {}, className)} ref={forwardedRef}>
198
248
  {children}
199
- </div>
249
+ </Comp>
200
250
  );
201
251
  });
202
252
 
253
+ CardContent.displayName = CARD_CONTENT_NAME;
254
+
203
255
  //
204
256
  // Row
205
257
  //
206
258
 
207
- type CardRowProps = SlottableProps<HTMLDivElement, { icon?: string }>;
259
+ const CARD_ROW_NAME = 'Card.Row';
260
+
261
+ type CardRowProps = { icon?: string; fullWidth?: boolean };
208
262
 
209
- const CardRow = forwardRef<HTMLDivElement, CardRowProps>(({ children, role, icon, ...props }, forwardedRef) => {
263
+ // TODO(burdon): fullWidth should mean no columns.
264
+ const CardRow = slottable<HTMLDivElement, CardRowProps>(({ children, asChild, icon, ...props }, forwardedRef) => {
210
265
  const { className, ...rest } = composableProps(props);
266
+ const Comp = asChild ? Slot : Primitive.div;
267
+ const { tx } = useThemeContext();
268
+
211
269
  return (
212
- <Column.Row {...rest} role={role ?? 'none'} classNames={className} ref={forwardedRef}>
213
- {(icon && <CardIcon classNames='text-subdued' icon={icon} />) || <div />}
270
+ <Comp {...rest} className={tx('card.row', {}, className)} ref={forwardedRef}>
271
+ {(icon && <CardIcon classNames='text-subdued' icon={icon} size={4} />) || <div />}
214
272
  {children}
215
- <div />
216
- </Column.Row>
273
+ </Comp>
217
274
  );
218
275
  });
219
276
 
277
+ CardRow.displayName = CARD_ROW_NAME;
278
+
220
279
  //
221
280
  // Section
222
281
  //
223
282
 
224
- type CardSectionProps = SlottableProps<HTMLDivElement>;
283
+ const CARD_SECTION_NAME = 'Card.Section';
225
284
 
226
- const CardSection = forwardRef<HTMLDivElement, CardSectionProps>(
227
- ({ children, asChild, role, ...props }, forwardedRef) => {
228
- const { className, ...rest } = composableProps(props);
229
- const Comp = asChild ? Slot : Primitive.div;
285
+ /**
286
+ * @deprecated Merge with Card.Row fullWidth
287
+ */
288
+ const CardSection = slottable<HTMLDivElement>(({ children, asChild, role, ...props }, forwardedRef) => {
289
+ const { className, ...rest } = composableProps(props);
290
+ const Comp = asChild ? Slot : Primitive.div;
230
291
 
231
- return (
232
- <Comp {...rest} role={role ?? 'none'} className={mx('col-span-full', className)} ref={forwardedRef}>
233
- {children}
234
- </Comp>
235
- );
236
- },
237
- );
292
+ return (
293
+ <Comp {...rest} role={role ?? 'none'} className={mx('col-span-full', className)} ref={forwardedRef}>
294
+ {children}
295
+ </Comp>
296
+ );
297
+ });
298
+
299
+ CardSection.displayName = CARD_SECTION_NAME;
238
300
 
239
301
  //
240
302
  // Heading
241
303
  //
242
304
 
243
- type CardHeadingProps = SlottableProps<HTMLDivElement, { variant?: 'default' | 'subtitle' }>;
305
+ const CARD_HEADING_NAME = 'Card.Heading';
306
+
307
+ type CardHeadingProps = { variant?: 'default' | 'subtitle' };
244
308
 
245
309
  /**
246
310
  * @deprecated Use typography.
247
311
  */
248
- const CardHeading = forwardRef<HTMLDivElement, CardHeadingProps>(
312
+ const CardHeading = slottable<HTMLDivElement, CardHeadingProps>(
249
313
  ({ children, asChild, role, variant = 'default', ...props }, forwardedRef) => {
250
314
  const { className, ...rest } = composableProps(props);
251
315
  const Comp = asChild ? Slot : Primitive.div;
@@ -264,13 +328,17 @@ const CardHeading = forwardRef<HTMLDivElement, CardHeadingProps>(
264
328
  },
265
329
  );
266
330
 
331
+ CardHeading.displayName = CARD_HEADING_NAME;
332
+
267
333
  //
268
334
  // Text
269
335
  //
270
336
 
271
- type CardTextProps = SlottableProps<HTMLDivElement, { truncate?: boolean; variant?: 'default' | 'description' }>;
337
+ const CARD_TEXT_NAME = 'Card.Text';
272
338
 
273
- const CardText = forwardRef<HTMLDivElement, CardTextProps>(
339
+ type CardTextProps = { truncate?: boolean; variant?: 'default' | 'description' };
340
+
341
+ const CardText = slottable<HTMLDivElement, CardTextProps>(
274
342
  ({ children, asChild, role, truncate, variant = 'default', ...props }, forwardedRef) => {
275
343
  const { className, ...rest } = composableProps(props);
276
344
  const Comp = asChild ? Slot : Primitive.div;
@@ -284,24 +352,69 @@ const CardText = forwardRef<HTMLDivElement, CardTextProps>(
284
352
  },
285
353
  );
286
354
 
355
+ CardText.displayName = CARD_TEXT_NAME;
356
+
357
+ //
358
+ // Html
359
+ //
360
+
361
+ const CARD_HTML_NAME = 'Card.Html';
362
+
363
+ type CardHtmlProps = { html: string; variant?: 'default' | 'description' };
364
+
365
+ /**
366
+ * Renders sanitized HTML content inside a card text slot.
367
+ * Uses DOMPurify to prevent XSS from untrusted markup (e.g. RSS feed content).
368
+ */
369
+ const CardHtml = ({ html, variant = 'default', ...props }: CardHtmlProps & ThemedClassName<object>) => {
370
+ const { tx } = useThemeContext();
371
+ const sanitized = useMemo(() => DOMPurify.sanitize(html), [html]);
372
+
373
+ return (
374
+ <div
375
+ {...props}
376
+ className={tx('card.text', { variant })}
377
+ // eslint-disable-next-line react/no-danger
378
+ dangerouslySetInnerHTML={{ __html: sanitized }}
379
+ />
380
+ );
381
+ };
382
+
383
+ (CardHtml as any).displayName = CARD_HTML_NAME;
384
+
287
385
  //
288
386
  // Poster
289
387
  //
290
388
 
389
+ const CARD_POSTER_NAME = 'Card.Poster';
390
+
291
391
  type CardPosterProps = ThemedClassName<
292
392
  {
293
393
  alt: string;
294
394
  aspect?: 'video' | 'auto';
395
+ /**
396
+ * How the image fills the poster box. `'contain'` (default) preserves
397
+ * aspect ratio and may letterbox; `'cover'` fills the box edge-to-edge,
398
+ * cropping as needed. Forwarded to the underlying `Image`'s
399
+ * `object-fit`.
400
+ */
401
+ fit?: 'contain' | 'cover';
295
402
  } & Partial<{ image: string; icon: string }>
296
403
  >;
297
404
 
298
405
  const CardPoster = (props: CardPosterProps) => {
299
406
  const { tx } = useThemeContext();
300
407
  const aspect = props.aspect === 'auto' ? 'aspect-auto' : 'aspect-video';
408
+
301
409
  if (props.image) {
302
410
  return (
303
- <div role='none' className='col-span-full mb-1'>
304
- <Image classNames={[tx('card.poster', {}), aspect, props.classNames]} src={props.image} alt={props.alt} />
411
+ <div className='col-span-full'>
412
+ <Image
413
+ classNames={[tx('card.poster', {}), aspect, props.classNames]}
414
+ src={props.image}
415
+ alt={props.alt}
416
+ fit={props.fit}
417
+ />
305
418
  </div>
306
419
  );
307
420
  }
@@ -315,27 +428,35 @@ const CardPoster = (props: CardPosterProps) => {
315
428
  }
316
429
  };
317
430
 
431
+ (CardPoster as any).displayName = CARD_POSTER_NAME;
432
+
318
433
  //
319
434
  // Action
320
435
  //
321
436
 
437
+ const CARD_ACTION_NAME = 'Card.Action';
438
+
322
439
  type CardActionProps = { icon?: string; label: string; actionIcon?: string; onClick?: () => void };
323
440
 
324
441
  const CardAction = ({ icon, actionIcon = 'ph--arrow-right--regular', label, onClick }: CardActionProps) => {
325
442
  const { tx } = useThemeContext();
326
443
  return (
327
444
  <Button variant='ghost' classNames={tx('card.action', {})} onClick={onClick}>
328
- {icon ? <CardIcon classNames='text-subdued' icon={icon} /> : <div />}
445
+ {icon ? <CardIcon classNames='text-subdued' icon={icon} size={4} /> : <div />}
329
446
  <span className={tx('card.action-label', {}, !actionIcon ? 'col-span-2' : undefined)}>{label}</span>
330
- {actionIcon && <CardIcon icon={actionIcon} />}
447
+ {actionIcon && <CardIcon icon={actionIcon} size={4} />}
331
448
  </Button>
332
449
  );
333
450
  };
334
451
 
452
+ (CardAction as any).displayName = CARD_ACTION_NAME;
453
+
335
454
  //
336
455
  // Link
337
456
  //
338
457
 
458
+ const CARD_LINK_NAME = 'Card.Link';
459
+
339
460
  type CardLinkProps = { label: string; href: string };
340
461
 
341
462
  const CardLink = ({ label, href }: CardLinkProps) => {
@@ -349,6 +470,8 @@ const CardLink = ({ label, href }: CardLinkProps) => {
349
470
  );
350
471
  };
351
472
 
473
+ (CardLink as any).displayName = CARD_LINK_NAME;
474
+
352
475
  //
353
476
  // Card
354
477
  //
@@ -375,6 +498,7 @@ export const Card = {
375
498
  Section: CardSection,
376
499
  Heading: CardHeading,
377
500
  Text: CardText,
501
+ Html: CardHtml,
378
502
  Poster: CardPoster,
379
503
  Action: CardAction,
380
504
  Link: CardLink,