@dxos/react-ui 0.10.0 → 0.11.1

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 (354) hide show
  1. package/dist/lib/chunk-parse-stack.mjs +1566 -0
  2. package/dist/lib/chunk-parse-stack.mjs.map +1 -0
  3. package/dist/lib/index.mjs +5220 -0
  4. package/dist/lib/index.mjs.map +1 -0
  5. package/dist/lib/testing.mjs +144 -0
  6. package/dist/lib/testing.mjs.map +1 -0
  7. package/dist/lib/translations.mjs +38 -0
  8. package/dist/lib/translations.mjs.map +1 -0
  9. package/dist/types/src/components/Avatars/Avatar.d.ts +1 -6
  10. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  11. package/dist/types/src/components/Avatars/AvatarContext.d.ts +9 -0
  12. package/dist/types/src/components/Avatars/AvatarContext.d.ts.map +1 -0
  13. package/dist/types/src/components/Avatars/index.d.ts +1 -0
  14. package/dist/types/src/components/Avatars/index.d.ts.map +1 -1
  15. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts +1 -1
  16. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  17. package/dist/types/src/components/Breadcrumb/Breadcrumb.stories.d.ts.map +1 -1
  18. package/dist/types/src/components/Breadcrumb/Breadcrumb.theme.d.ts.map +1 -1
  19. package/dist/types/src/components/Button/Button.d.ts +1 -6
  20. package/dist/types/src/components/Button/Button.d.ts.map +1 -1
  21. package/dist/types/src/components/Button/ButtonGroupContext.d.ts +9 -0
  22. package/dist/types/src/components/Button/ButtonGroupContext.d.ts.map +1 -0
  23. package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
  24. package/dist/types/src/components/Button/IconButton.stories.d.ts.map +1 -1
  25. package/dist/types/src/components/Button/IconButton.theme.d.ts +1 -0
  26. package/dist/types/src/components/Button/IconButton.theme.d.ts.map +1 -1
  27. package/dist/types/src/components/Button/SystemIconButton.d.ts +1 -1
  28. package/dist/types/src/components/Button/SystemIconButton.d.ts.map +1 -1
  29. package/dist/types/src/components/Button/index.d.ts +1 -0
  30. package/dist/types/src/components/Button/index.d.ts.map +1 -1
  31. package/dist/types/src/components/Calendar/Calendar.d.ts +0 -2
  32. package/dist/types/src/components/Calendar/Calendar.d.ts.map +1 -1
  33. package/dist/types/src/components/Calendar/index.d.ts +1 -0
  34. package/dist/types/src/components/Calendar/index.d.ts.map +1 -1
  35. package/dist/types/src/components/Calendar/parse-calendar-date.d.ts +3 -0
  36. package/dist/types/src/components/Calendar/parse-calendar-date.d.ts.map +1 -0
  37. package/dist/types/src/components/Card/Card.d.ts +42 -15
  38. package/dist/types/src/components/Card/Card.d.ts.map +1 -1
  39. package/dist/types/src/components/Card/Card.theme.d.ts +0 -1
  40. package/dist/types/src/components/Card/Card.theme.d.ts.map +1 -1
  41. package/dist/types/src/components/Carousel/Carousel.d.ts +2 -4
  42. package/dist/types/src/components/Carousel/Carousel.d.ts.map +1 -1
  43. package/dist/types/src/components/Carousel/CarouselContext.d.ts +8 -0
  44. package/dist/types/src/components/Carousel/CarouselContext.d.ts.map +1 -0
  45. package/dist/types/src/components/Carousel/index.d.ts +1 -0
  46. package/dist/types/src/components/Carousel/index.d.ts.map +1 -1
  47. package/dist/types/src/components/Clipboard/ClipboardContext.d.ts +7 -0
  48. package/dist/types/src/components/Clipboard/ClipboardContext.d.ts.map +1 -0
  49. package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts +0 -6
  50. package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts.map +1 -1
  51. package/dist/types/src/components/Clipboard/index.d.ts +1 -1
  52. package/dist/types/src/components/Clipboard/index.d.ts.map +1 -1
  53. package/dist/types/src/components/Column/Column.d.ts +7 -12
  54. package/dist/types/src/components/Column/Column.d.ts.map +1 -1
  55. package/dist/types/src/components/Column/Column.stories.d.ts +2 -2
  56. package/dist/types/src/components/Column/Column.theme.d.ts +0 -1
  57. package/dist/types/src/components/Column/Column.theme.d.ts.map +1 -1
  58. package/dist/types/src/components/Column/ColumnContext.d.ts +9 -0
  59. package/dist/types/src/components/Column/ColumnContext.d.ts.map +1 -0
  60. package/dist/types/src/components/Column/index.d.ts +1 -0
  61. package/dist/types/src/components/Column/index.d.ts.map +1 -1
  62. package/dist/types/src/components/Column/withColumn.d.ts +40 -4
  63. package/dist/types/src/components/Column/withColumn.d.ts.map +1 -1
  64. package/dist/types/src/components/DatePicker/DatePicker.d.ts +0 -10
  65. package/dist/types/src/components/DatePicker/DatePicker.d.ts.map +1 -1
  66. package/dist/types/src/components/DatePicker/DatePickerContext.d.ts +13 -0
  67. package/dist/types/src/components/DatePicker/DatePickerContext.d.ts.map +1 -0
  68. package/dist/types/src/components/DatePicker/index.d.ts +1 -0
  69. package/dist/types/src/components/DatePicker/index.d.ts.map +1 -1
  70. package/dist/types/src/components/Dialog/AlertDialog.d.ts +3 -3
  71. package/dist/types/src/components/Dialog/Dialog.d.ts +3 -3
  72. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts +5 -10
  73. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -1
  74. package/dist/types/src/components/ErrorFallback/index.d.ts +1 -0
  75. package/dist/types/src/components/ErrorFallback/index.d.ts.map +1 -1
  76. package/dist/types/src/components/ErrorFallback/parse-stack.d.ts +8 -0
  77. package/dist/types/src/components/ErrorFallback/parse-stack.d.ts.map +1 -0
  78. package/dist/types/src/components/Focus/Focus.d.ts +2 -10
  79. package/dist/types/src/components/Focus/Focus.d.ts.map +1 -1
  80. package/dist/types/src/components/Focus/FocusContext.d.ts +10 -0
  81. package/dist/types/src/components/Focus/FocusContext.d.ts.map +1 -0
  82. package/dist/types/src/components/Focus/index.d.ts +1 -0
  83. package/dist/types/src/components/Focus/index.d.ts.map +1 -1
  84. package/dist/types/src/components/Input/Input.d.ts +9 -10
  85. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  86. package/dist/types/src/components/Input/Input.stories.d.ts +7 -2
  87. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  88. package/dist/types/src/components/Input/Input.theme.d.ts +13 -0
  89. package/dist/types/src/components/Input/Input.theme.d.ts.map +1 -1
  90. package/dist/types/src/components/Input/InputTriggerContext.d.ts +15 -0
  91. package/dist/types/src/components/Input/InputTriggerContext.d.ts.map +1 -0
  92. package/dist/types/src/components/Input/SegmentedInput.d.ts.map +1 -1
  93. package/dist/types/src/components/Input/index.d.ts +1 -0
  94. package/dist/types/src/components/Input/index.d.ts.map +1 -1
  95. package/dist/types/src/components/Main/Main.d.ts +2 -35
  96. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  97. package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
  98. package/dist/types/src/components/Main/Main.theme.d.ts.map +1 -1
  99. package/dist/types/src/components/Main/MainContext.d.ts +38 -0
  100. package/dist/types/src/components/Main/MainContext.d.ts.map +1 -0
  101. package/dist/types/src/components/Main/index.d.ts +1 -0
  102. package/dist/types/src/components/Main/index.d.ts.map +1 -1
  103. package/dist/types/src/components/MediaPlayer/MediaPlayer.d.ts +1 -17
  104. package/dist/types/src/components/MediaPlayer/MediaPlayer.d.ts.map +1 -1
  105. package/dist/types/src/components/MediaPlayer/index.d.ts +1 -0
  106. package/dist/types/src/components/MediaPlayer/index.d.ts.map +1 -1
  107. package/dist/types/src/components/MediaPlayer/media-kind.d.ts +18 -0
  108. package/dist/types/src/components/MediaPlayer/media-kind.d.ts.map +1 -0
  109. package/dist/types/src/components/Menu/DropdownMenu.d.ts +6 -22
  110. package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -1
  111. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts +1 -11
  112. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -1
  113. package/dist/types/src/components/Menu/DropdownMenuContext.d.ts +27 -0
  114. package/dist/types/src/components/Menu/DropdownMenuContext.d.ts.map +1 -0
  115. package/dist/types/src/components/Menu/index.d.ts +1 -0
  116. package/dist/types/src/components/Menu/index.d.ts.map +1 -1
  117. package/dist/types/src/components/Message/Message.d.ts +11 -6
  118. package/dist/types/src/components/Message/Message.d.ts.map +1 -1
  119. package/dist/types/src/components/Message/Message.stories.d.ts +4 -1
  120. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  121. package/dist/types/src/components/Message/Message.theme.d.ts.map +1 -1
  122. package/dist/types/src/components/Message/index.d.ts +1 -0
  123. package/dist/types/src/components/Message/index.d.ts.map +1 -1
  124. package/dist/types/src/components/Message/message-icons.d.ts +3 -0
  125. package/dist/types/src/components/Message/message-icons.d.ts.map +1 -0
  126. package/dist/types/src/components/Panel/Panel.d.ts +4 -4
  127. package/dist/types/src/components/Panel/Panel.stories.d.ts.map +1 -1
  128. package/dist/types/src/components/Panel/Panel.theme.d.ts +1 -1
  129. package/dist/types/src/components/Panel/Panel.theme.d.ts.map +1 -1
  130. package/dist/types/src/components/Popover/Popover.d.ts +6 -10
  131. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  132. package/dist/types/src/components/Popover/PopoverContext.d.ts +29 -0
  133. package/dist/types/src/components/Popover/PopoverContext.d.ts.map +1 -0
  134. package/dist/types/src/components/Popover/index.d.ts +1 -0
  135. package/dist/types/src/components/Popover/index.d.ts.map +1 -1
  136. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +2 -2
  137. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +2 -2
  138. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +3 -16
  139. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
  140. package/dist/types/src/components/ScrollContainer/ScrollContainerContext.d.ts +16 -0
  141. package/dist/types/src/components/ScrollContainer/ScrollContainerContext.d.ts.map +1 -0
  142. package/dist/types/src/components/ScrollContainer/index.d.ts +1 -0
  143. package/dist/types/src/components/ScrollContainer/index.d.ts.map +1 -1
  144. package/dist/types/src/components/Slider/Slider.d.ts +25 -0
  145. package/dist/types/src/components/Slider/Slider.d.ts.map +1 -0
  146. package/dist/types/src/components/Slider/Slider.stories.d.ts +29 -0
  147. package/dist/types/src/components/Slider/Slider.stories.d.ts.map +1 -0
  148. package/dist/types/src/components/Slider/Slider.test.d.ts +2 -0
  149. package/dist/types/src/components/Slider/Slider.test.d.ts.map +1 -0
  150. package/dist/types/src/components/Slider/Slider.theme.d.ts +7 -0
  151. package/dist/types/src/components/Slider/Slider.theme.d.ts.map +1 -0
  152. package/dist/types/src/components/Slider/index.d.ts +2 -0
  153. package/dist/types/src/components/Slider/index.d.ts.map +1 -0
  154. package/dist/types/src/components/Splitter/Splitter.d.ts +3 -3
  155. package/dist/types/src/components/Status/Status.d.ts.map +1 -1
  156. package/dist/types/src/components/Toolbar/Toolbar.d.ts +4 -2
  157. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  158. package/dist/types/src/components/Toolbar/Toolbar.theme.d.ts.map +1 -1
  159. package/dist/types/src/components/Tooltip/TextTooltip.d.ts.map +1 -1
  160. package/dist/types/src/components/Tooltip/Tooltip.d.ts +2 -23
  161. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  162. package/dist/types/src/components/Tooltip/TooltipContext.d.ts +35 -0
  163. package/dist/types/src/components/Tooltip/TooltipContext.d.ts.map +1 -0
  164. package/dist/types/src/components/Tooltip/index.d.ts +1 -0
  165. package/dist/types/src/components/Tooltip/index.d.ts.map +1 -1
  166. package/dist/types/src/components/index.d.ts +1 -0
  167. package/dist/types/src/components/index.d.ts.map +1 -1
  168. package/dist/types/src/exemplars/generics.stories.d.ts +1 -1
  169. package/dist/types/src/hooks/useIconHref.d.ts +8 -0
  170. package/dist/types/src/hooks/useIconHref.d.ts.map +1 -1
  171. package/dist/types/src/hooks/useThemeContext.d.ts +2 -1
  172. package/dist/types/src/hooks/useThemeContext.d.ts.map +1 -1
  173. package/dist/types/src/hooks/useThemeContext.test.d.ts +2 -0
  174. package/dist/types/src/hooks/useThemeContext.test.d.ts.map +1 -0
  175. package/dist/types/src/playground/Density.stories.d.ts +11 -0
  176. package/dist/types/src/playground/Density.stories.d.ts.map +1 -0
  177. package/dist/types/src/playground/Elevation.stories.d.ts +14 -0
  178. package/dist/types/src/playground/Elevation.stories.d.ts.map +1 -0
  179. package/dist/types/src/primitives/Container/Container.d.ts +1 -1
  180. package/dist/types/src/primitives/Container/Container.d.ts.map +1 -1
  181. package/dist/types/src/primitives/DensityProvider/DensityContext.d.ts +6 -0
  182. package/dist/types/src/primitives/DensityProvider/DensityContext.d.ts.map +1 -0
  183. package/dist/types/src/primitives/DensityProvider/DensityProvider.d.ts +10 -4
  184. package/dist/types/src/primitives/DensityProvider/DensityProvider.d.ts.map +1 -1
  185. package/dist/types/src/primitives/DensityProvider/index.d.ts +1 -0
  186. package/dist/types/src/primitives/DensityProvider/index.d.ts.map +1 -1
  187. package/dist/types/src/primitives/Flex/Flex.d.ts +1 -1
  188. package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -1
  189. package/dist/types/src/primitives/Grid/Grid.d.ts +1 -1
  190. package/dist/types/src/primitives/Grid/Grid.d.ts.map +1 -1
  191. package/dist/types/src/primitives/ThemeProvider/IconRegistry.d.ts +15 -0
  192. package/dist/types/src/primitives/ThemeProvider/IconRegistry.d.ts.map +1 -0
  193. package/dist/types/src/primitives/ThemeProvider/ThemeProvider.d.ts +1 -2
  194. package/dist/types/src/primitives/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  195. package/dist/types/src/primitives/ThemeProvider/ThemeProvider.stories.d.ts +1 -1
  196. package/dist/types/src/primitives/ThemeProvider/TranslationsContext.d.ts +112 -0
  197. package/dist/types/src/primitives/ThemeProvider/TranslationsContext.d.ts.map +1 -0
  198. package/dist/types/src/primitives/ThemeProvider/TranslationsProvider.d.ts +0 -109
  199. package/dist/types/src/primitives/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
  200. package/dist/types/src/primitives/ThemeProvider/icon-registry.d.ts +34 -0
  201. package/dist/types/src/primitives/ThemeProvider/icon-registry.d.ts.map +1 -0
  202. package/dist/types/src/primitives/ThemeProvider/index.d.ts +3 -1
  203. package/dist/types/src/primitives/ThemeProvider/index.d.ts.map +1 -1
  204. package/dist/types/src/testing/decorators/withTheme.d.ts +1 -1
  205. package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
  206. package/dist/types/src/theme/defaultTheme.d.ts.map +1 -1
  207. package/dist/types/src/theme/index.d.ts +1 -0
  208. package/dist/types/src/theme/index.d.ts.map +1 -1
  209. package/dist/types/src/util/slots.d.ts +6 -3
  210. package/dist/types/src/util/slots.d.ts.map +1 -1
  211. package/dist/types/src/util/slots.stories.d.ts +14 -0
  212. package/dist/types/src/util/slots.stories.d.ts.map +1 -0
  213. package/dist/types/tsconfig.tsbuildinfo +1 -1
  214. package/package.json +25 -27
  215. package/src/components/Avatars/Avatar.tsx +1 -11
  216. package/src/components/Avatars/AvatarContext.ts +16 -0
  217. package/src/components/Avatars/index.ts +2 -0
  218. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +27 -25
  219. package/src/components/Breadcrumb/Breadcrumb.theme.ts +7 -5
  220. package/src/components/Breadcrumb/Breadcrumb.tsx +2 -2
  221. package/src/components/Button/Button.tsx +2 -11
  222. package/src/components/Button/ButtonGroupContext.ts +17 -0
  223. package/src/components/Button/IconButton.stories.tsx +2 -3
  224. package/src/components/Button/IconButton.theme.ts +15 -2
  225. package/src/components/Button/IconButton.tsx +6 -1
  226. package/src/components/Button/SystemIconButton.tsx +23 -16
  227. package/src/components/Button/index.ts +2 -0
  228. package/src/components/Calendar/Calendar.theme.ts +5 -5
  229. package/src/components/Calendar/Calendar.tsx +1 -3
  230. package/src/components/Calendar/index.ts +2 -0
  231. package/src/components/Calendar/parse-calendar-date.ts +9 -0
  232. package/src/components/Card/Card.theme.ts +48 -38
  233. package/src/components/Card/Card.tsx +77 -16
  234. package/src/components/Carousel/Carousel.tsx +4 -11
  235. package/src/components/Carousel/CarouselContext.ts +17 -0
  236. package/src/components/Carousel/index.ts +2 -0
  237. package/src/components/Clipboard/ClipboardContext.ts +20 -0
  238. package/src/components/Clipboard/ClipboardProvider.tsx +2 -12
  239. package/src/components/Clipboard/CopyButton.tsx +1 -1
  240. package/src/components/Clipboard/index.ts +1 -1
  241. package/src/components/Column/Column.stories.tsx +2 -2
  242. package/src/components/Column/Column.theme.ts +2 -11
  243. package/src/components/Column/Column.tsx +35 -57
  244. package/src/components/Column/ColumnContext.ts +22 -0
  245. package/src/components/Column/index.ts +2 -0
  246. package/src/components/Column/withColumn.ts +41 -4
  247. package/src/components/DatePicker/DatePicker.theme.ts +2 -2
  248. package/src/components/DatePicker/DatePicker.tsx +1 -14
  249. package/src/components/DatePicker/DatePickerContext.ts +21 -0
  250. package/src/components/DatePicker/index.ts +2 -0
  251. package/src/components/ErrorFallback/ErrorStack.tsx +8 -28
  252. package/src/components/ErrorFallback/index.ts +1 -0
  253. package/src/components/ErrorFallback/parse-stack.ts +33 -0
  254. package/src/components/Focus/Focus.stories.tsx +6 -6
  255. package/src/components/Focus/Focus.tsx +2 -30
  256. package/src/components/Focus/FocusContext.ts +22 -0
  257. package/src/components/Focus/index.ts +2 -0
  258. package/src/components/Image/Image.tsx +1 -1
  259. package/src/components/Input/Input.stories.tsx +63 -48
  260. package/src/components/Input/Input.theme.ts +33 -27
  261. package/src/components/Input/Input.tsx +46 -43
  262. package/src/components/Input/InputTriggerContext.ts +45 -0
  263. package/src/components/Input/SegmentedInput.tsx +2 -1
  264. package/src/components/Input/index.ts +2 -0
  265. package/src/components/Main/Main.stories.tsx +2 -1
  266. package/src/components/Main/Main.theme.ts +10 -1
  267. package/src/components/Main/Main.tsx +1 -115
  268. package/src/components/Main/MainContext.ts +126 -0
  269. package/src/components/Main/index.ts +2 -0
  270. package/src/components/MediaPlayer/MediaPlayer.tsx +16 -47
  271. package/src/components/MediaPlayer/index.ts +2 -0
  272. package/src/components/MediaPlayer/media-kind.ts +41 -0
  273. package/src/components/Menu/DropdownMenu.tsx +27 -44
  274. package/src/components/Menu/DropdownMenuContext.ts +35 -0
  275. package/src/components/Menu/Menu.theme.ts +3 -3
  276. package/src/components/Menu/index.ts +2 -0
  277. package/src/components/Message/Message.stories.tsx +32 -15
  278. package/src/components/Message/Message.theme.ts +8 -2
  279. package/src/components/Message/Message.tsx +47 -23
  280. package/src/components/Message/index.ts +2 -0
  281. package/src/components/Message/message-icons.ts +16 -0
  282. package/src/components/Panel/Panel.stories.tsx +15 -2
  283. package/src/components/Panel/Panel.theme.ts +15 -6
  284. package/src/components/Popover/Popover.theme.ts +1 -1
  285. package/src/components/Popover/Popover.tsx +22 -37
  286. package/src/components/Popover/PopoverContext.ts +32 -0
  287. package/src/components/Popover/index.ts +2 -0
  288. package/src/components/ScrollContainer/ScrollContainer.stories.tsx +1 -1
  289. package/src/components/ScrollContainer/ScrollContainer.tsx +1 -18
  290. package/src/components/ScrollContainer/ScrollContainerContext.ts +25 -0
  291. package/src/components/ScrollContainer/index.ts +2 -0
  292. package/src/components/Select/Select.theme.ts +2 -2
  293. package/src/components/Slider/Slider.stories.tsx +107 -0
  294. package/src/components/Slider/Slider.test.tsx +105 -0
  295. package/src/components/Slider/Slider.theme.ts +38 -0
  296. package/src/components/Slider/Slider.tsx +64 -0
  297. package/src/components/Slider/index.ts +5 -0
  298. package/src/components/Status/Status.theme.ts +1 -1
  299. package/src/components/Status/Status.tsx +0 -1
  300. package/src/components/Tag/Tag.stories.tsx +1 -1
  301. package/src/components/Toolbar/Toolbar.theme.ts +14 -5
  302. package/src/components/Toolbar/Toolbar.tsx +5 -1
  303. package/src/components/Tooltip/TextTooltip.tsx +2 -1
  304. package/src/components/Tooltip/Tooltip.tsx +12 -35
  305. package/src/components/Tooltip/TooltipContext.ts +41 -0
  306. package/src/components/Tooltip/index.ts +2 -0
  307. package/src/components/index.ts +1 -0
  308. package/src/hooks/useIconHref.ts +26 -5
  309. package/src/hooks/useThemeContext.test.tsx +33 -0
  310. package/src/hooks/useThemeContext.ts +28 -3
  311. package/src/playground/Density.stories.tsx +41 -0
  312. package/src/playground/Elevation.stories.tsx +348 -0
  313. package/src/primitives/DensityProvider/DensityContext.ts +15 -0
  314. package/src/primitives/DensityProvider/DensityProvider.tsx +12 -6
  315. package/src/primitives/DensityProvider/index.ts +1 -0
  316. package/src/primitives/Flex/Flex.stories.tsx +1 -1
  317. package/src/primitives/Grid/Grid.stories.tsx +1 -1
  318. package/src/primitives/ThemeProvider/IconRegistry.tsx +42 -0
  319. package/src/primitives/ThemeProvider/ThemeProvider.tsx +16 -15
  320. package/src/primitives/ThemeProvider/TranslationsContext.ts +24 -0
  321. package/src/primitives/ThemeProvider/TranslationsProvider.tsx +4 -16
  322. package/src/primitives/ThemeProvider/icon-registry.ts +272 -0
  323. package/src/primitives/ThemeProvider/index.ts +9 -1
  324. package/src/testing/decorators/withLayout.tsx +4 -4
  325. package/src/testing/decorators/withLayoutVariants.tsx +3 -3
  326. package/src/testing/decorators/withTheme.tsx +1 -2
  327. package/src/theme/defaultTheme.ts +2 -0
  328. package/src/theme/index.ts +1 -0
  329. package/src/util/slots.stories.tsx +80 -0
  330. package/src/util/slots.ts +14 -5
  331. package/dist/lib/browser/chunk-CMHHVHX3.mjs +0 -46
  332. package/dist/lib/browser/chunk-CMHHVHX3.mjs.map +0 -7
  333. package/dist/lib/browser/chunk-GTHV4WYK.mjs +0 -1499
  334. package/dist/lib/browser/chunk-GTHV4WYK.mjs.map +0 -7
  335. package/dist/lib/browser/index.mjs +0 -5632
  336. package/dist/lib/browser/index.mjs.map +0 -7
  337. package/dist/lib/browser/meta.json +0 -1
  338. package/dist/lib/browser/testing/index.mjs +0 -133
  339. package/dist/lib/browser/testing/index.mjs.map +0 -7
  340. package/dist/lib/browser/translations.mjs +0 -9
  341. package/dist/lib/browser/translations.mjs.map +0 -7
  342. package/dist/lib/node-esm/chunk-3VSKWNCQ.mjs +0 -1501
  343. package/dist/lib/node-esm/chunk-3VSKWNCQ.mjs.map +0 -7
  344. package/dist/lib/node-esm/chunk-P4KFQGJI.mjs +0 -48
  345. package/dist/lib/node-esm/chunk-P4KFQGJI.mjs.map +0 -7
  346. package/dist/lib/node-esm/index.mjs +0 -5633
  347. package/dist/lib/node-esm/index.mjs.map +0 -7
  348. package/dist/lib/node-esm/meta.json +0 -1
  349. package/dist/lib/node-esm/testing/index.mjs +0 -134
  350. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  351. package/dist/lib/node-esm/translations.mjs +0 -10
  352. package/dist/lib/node-esm/translations.mjs.map +0 -7
  353. package/src/components/Column/AUDIT.md +0 -148
  354. package/src/components/Focus/AUDIT.md +0 -43
@@ -0,0 +1,126 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { useFocusableGroup } from '@fluentui/react-tabster';
6
+ import { createContext } from '@radix-ui/react-context';
7
+ import {
8
+ type ComponentPropsWithoutRef,
9
+ type Dispatch,
10
+ type KeyboardEvent,
11
+ type SetStateAction,
12
+ useCallback,
13
+ } from 'react';
14
+
15
+ import { log } from '@dxos/log';
16
+
17
+ export const MAIN_NAME = 'Main';
18
+
19
+ // Kept out of `Main.tsx`: react-refresh only fast-refreshes a module whose exports are all
20
+ // components, so a context and its hook exported beside them force a full page reload on every edit.
21
+
22
+ //
23
+ // Landmark
24
+ //
25
+
26
+ const landmarkAttr = 'data-main-landmark';
27
+
28
+ /**
29
+ * Facilitates moving focus between landmarks.
30
+ * Ref https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/landmark_role
31
+ */
32
+ export const useLandmarkMover = (propsOnKeyDown: ComponentPropsWithoutRef<'div'>['onKeyDown'], landmark: string) => {
33
+ const handleKeyDown = useCallback(
34
+ (event: KeyboardEvent<HTMLDivElement>) => {
35
+ const target = event.target as HTMLDivElement;
36
+ if (event.target === event.currentTarget && event.key === 'Tab' && target.hasAttribute(landmarkAttr)) {
37
+ event.preventDefault();
38
+ const landmarks = Array.from(document.querySelectorAll(`[${landmarkAttr}]:not([inert])`))
39
+ .map((el) => (el.hasAttribute(landmarkAttr) ? parseInt(el.getAttribute(landmarkAttr)!) : NaN))
40
+ .sort();
41
+ const l = landmarks.length;
42
+ const cursor = landmarks.indexOf(parseInt(target.getAttribute(landmarkAttr)!));
43
+ const nextLandmark = landmarks[(cursor + l + (event.getModifierState('Shift') ? -1 : 1)) % l];
44
+ (document.querySelector(`[${landmarkAttr}="${nextLandmark}"]`) as HTMLDivElement | null)?.focus();
45
+ }
46
+ propsOnKeyDown?.(event);
47
+ },
48
+ [propsOnKeyDown],
49
+ );
50
+
51
+ // TODO(thure): This was disconnected once before in #8818;
52
+ // if this should change again to support the browser extension, please ensure the change doesn’t break web, desktop and mobile.
53
+ const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited', ignoreDefaultKeydown: { Tab: true } });
54
+
55
+ return {
56
+ [landmarkAttr]: landmark,
57
+ tabIndex: 0,
58
+ onKeyDown: handleKeyDown,
59
+ ...focusableGroupAttrs,
60
+ };
61
+ };
62
+
63
+ //
64
+ // Context
65
+ //
66
+
67
+ // TODO(burdon): Define collapsed state.
68
+ export type SidebarState = 'expanded' | 'collapsed' | 'closed';
69
+
70
+ export type MainContextValue = {
71
+ resizing: boolean;
72
+
73
+ // Navigation
74
+ navigationSidebarState: SidebarState;
75
+ setNavigationSidebarState: Dispatch<SetStateAction<SidebarState | undefined>>;
76
+
77
+ // Complementary
78
+ complementarySidebarState: SidebarState;
79
+ setComplementarySidebarState: Dispatch<SetStateAction<SidebarState | undefined>>;
80
+ };
81
+
82
+ export const [MainProvider, useMainContext] = createContext<MainContextValue>(MAIN_NAME, {
83
+ resizing: false,
84
+
85
+ navigationSidebarState: 'closed',
86
+ setNavigationSidebarState: (_nextState) => {
87
+ log.warn('Not initialized');
88
+ },
89
+
90
+ complementarySidebarState: 'closed',
91
+ setComplementarySidebarState: (_nextState) => {
92
+ log.warn('Not initialized');
93
+ },
94
+ });
95
+
96
+ export const useSidebars = (consumerName: string) => {
97
+ const {
98
+ navigationSidebarState,
99
+ setNavigationSidebarState,
100
+
101
+ complementarySidebarState,
102
+ setComplementarySidebarState,
103
+ } = useMainContext(consumerName);
104
+
105
+ return {
106
+ navigationSidebarState,
107
+ setNavigationSidebarState,
108
+ toggleNavigationSidebar: useCallback(
109
+ () => setNavigationSidebarState(navigationSidebarState === 'expanded' ? 'closed' : 'expanded'),
110
+ [navigationSidebarState, setNavigationSidebarState],
111
+ ),
112
+ openNavigationSidebar: useCallback(() => setNavigationSidebarState('expanded'), []),
113
+ collapseNavigationSidebar: useCallback(() => setNavigationSidebarState('collapsed'), []),
114
+ closeNavigationSidebar: useCallback(() => setNavigationSidebarState('closed'), []),
115
+
116
+ complementarySidebarState,
117
+ setComplementarySidebarState,
118
+ toggleComplementarySidebar: useCallback(
119
+ () => setComplementarySidebarState(complementarySidebarState === 'expanded' ? 'closed' : 'expanded'),
120
+ [complementarySidebarState, setComplementarySidebarState],
121
+ ),
122
+ openComplementarySidebar: useCallback(() => setComplementarySidebarState('expanded'), []),
123
+ collapseComplementarySidebar: useCallback(() => setComplementarySidebarState('collapsed'), []),
124
+ closeComplementarySidebar: useCallback(() => setComplementarySidebarState('closed'), []),
125
+ };
126
+ };
@@ -2,5 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ export { useLandmarkMover, useMainContext, useSidebars } from './MainContext';
6
+
5
7
  export * from './Main';
6
8
  export * from './constants';
@@ -7,8 +7,7 @@ import React, { useState } from 'react';
7
7
  import { mx } from '@dxos/ui-theme';
8
8
 
9
9
  import { type ThemedClassName } from '../../util';
10
-
11
- export type MediaKind = 'video' | 'audio';
10
+ import { type MediaKind, detectMediaKind, isEmbedUrl } from './media-kind';
12
11
 
13
12
  export type MediaFit = 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';
14
13
 
@@ -21,42 +20,9 @@ const FIT_CLASS: Record<MediaFit, string> = {
21
20
  'scale-down': 'object-scale-down',
22
21
  };
23
22
 
24
- const VIDEO_EXTENSIONS = ['.mp4', '.webm', '.ogv', '.mov', '.m4v'];
25
- const AUDIO_EXTENSIONS = ['.mp3', '.wav', '.ogg', '.m4a', '.aac', '.flac'];
26
-
27
23
  /** iframe sandbox flags compatible with typical oEmbed-style players. */
28
24
  const DEFAULT_IFRAME_SANDBOX = 'allow-scripts allow-same-origin allow-presentation';
29
25
 
30
- /**
31
- * Best-effort detection of `video` vs `audio` from a media URL.
32
- * Inspects the pathname's extension (ignoring query/hash). Returns `undefined`
33
- * when the URL doesn't look like a recognised media file — callers should
34
- * default to 'video' or render a fallback (e.g. iframe / img).
35
- */
36
- export const detectMediaKind = (src: string): MediaKind | undefined => {
37
- // Strip query and hash, then take the last path segment's extension.
38
- const pathname = src.split(/[?#]/, 1)[0]!;
39
- const lower = pathname.toLowerCase();
40
- if (VIDEO_EXTENSIONS.some((extension) => lower.endsWith(extension))) {
41
- return 'video';
42
- }
43
- if (AUDIO_EXTENSIONS.some((extension) => lower.endsWith(extension))) {
44
- return 'audio';
45
- }
46
-
47
- return undefined;
48
- };
49
-
50
- /**
51
- * Heuristic match for URLs that should render as native `<video>` / `<audio>`
52
- * (i.e. URLs ending in a recognised media extension).
53
- *
54
- * NB: Cloudflare Stream embed URLs serve an HTML player page, **not** a media
55
- * stream, so they cannot be loaded via `<video>`. Those are detected by
56
- * {@link isCloudflareStreamEmbed} and rendered via `<iframe>` instead.
57
- */
58
- export const isEmbedUrl = (src: string): boolean => detectMediaKind(src) !== undefined;
59
-
60
26
  /**
61
27
  * Match Cloudflare Stream `/iframe` embed URLs of the form
62
28
  * `https://customer-<code>.cloudflarestream.com/<32-hex-uid>/iframe[?…]`.
@@ -105,7 +71,8 @@ export const MediaPlayer = ({
105
71
  fit = 'cover',
106
72
  }: MediaPlayerProps) => {
107
73
  const fitClass = FIT_CLASS[fit];
108
- if (isEmbedUrl(src)) {
74
+ // An explicit `kind` forces native playback even for extensionless URLs (e.g. `blob:`/`data:`).
75
+ if (kind || isEmbedUrl(src)) {
109
76
  const resolved = kind ?? detectMediaKind(src) ?? 'video';
110
77
  if (resolved === 'audio') {
111
78
  return (
@@ -123,16 +90,18 @@ export const MediaPlayer = ({
123
90
  }
124
91
 
125
92
  return (
126
- <video
127
- className={mx('max-w-full max-h-full aspect-video', fitClass, classNames)}
128
- src={src}
129
- controls={controls}
130
- autoPlay={autoPlay}
131
- loop={loop}
132
- muted={muted}
133
- crossOrigin={crossOrigin}
134
- aria-label={alt}
135
- />
93
+ <div className={mx('grid place-items-center', classNames)}>
94
+ <video
95
+ className={mx('max-w-full max-h-full aspect-video', fitClass)}
96
+ src={src}
97
+ controls={controls}
98
+ autoPlay={autoPlay}
99
+ loop={loop}
100
+ muted={muted}
101
+ crossOrigin={crossOrigin}
102
+ aria-label={alt}
103
+ />
104
+ </div>
136
105
  );
137
106
  }
138
107
 
@@ -161,7 +130,7 @@ type IframePlayerProps = ThemedClassName<{
161
130
  const IframePlayer = ({ src, alt, classNames }: IframePlayerProps) => {
162
131
  const [loaded, setLoaded] = useState(false);
163
132
  return (
164
- <div className={mx('relative bg-baseSurface', classNames)}>
133
+ <div className={mx('relative bg-base-surface', classNames)}>
165
134
  <iframe
166
135
  src={src}
167
136
  title={alt ?? 'Embedded media'}
@@ -2,4 +2,6 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
+ export { type MediaKind, detectMediaKind, isEmbedUrl } from './media-kind';
6
+
5
7
  export * from './MediaPlayer';
@@ -0,0 +1,41 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ // Kept out of `MediaPlayer.tsx`: react-refresh only fast-refreshes a module whose exports are all
6
+ // components, so a context and its hook exported beside them force a full page reload on every edit.
7
+
8
+ export type MediaKind = 'video' | 'audio';
9
+
10
+ const VIDEO_EXTENSIONS = ['.mp4', '.webm', '.ogv', '.mov', '.m4v'];
11
+ const AUDIO_EXTENSIONS = ['.mp3', '.wav', '.ogg', '.m4a', '.aac', '.flac'];
12
+
13
+ /**
14
+ * Best-effort detection of `video` vs `audio` from a media URL.
15
+ * Inspects the pathname's extension (ignoring query/hash). Returns `undefined`
16
+ * when the URL doesn't look like a recognised media file — callers should
17
+ * default to 'video' or render a fallback (e.g. iframe / img).
18
+ */
19
+ export const detectMediaKind = (src: string): MediaKind | undefined => {
20
+ // Strip query and hash, then take the last path segment's extension.
21
+ const pathname = src.split(/[?#]/, 1)[0]!;
22
+ const lower = pathname.toLowerCase();
23
+ if (VIDEO_EXTENSIONS.some((extension) => lower.endsWith(extension))) {
24
+ return 'video';
25
+ }
26
+ if (AUDIO_EXTENSIONS.some((extension) => lower.endsWith(extension))) {
27
+ return 'audio';
28
+ }
29
+
30
+ return undefined;
31
+ };
32
+
33
+ /**
34
+ * Heuristic match for URLs that should render as native `<video>` / `<audio>`
35
+ * (i.e. URLs ending in a recognised media extension).
36
+ *
37
+ * NB: Cloudflare Stream embed URLs serve an HTML player page, **not** a media
38
+ * stream, so they cannot be loaded via `<video>`. Those are detected by
39
+ * {@link isCloudflareStreamEmbed} and rendered via `<iframe>` instead.
40
+ */
41
+ export const isEmbedUrl = (src: string): boolean => detectMediaKind(src) !== undefined;
@@ -6,11 +6,8 @@
6
6
 
7
7
  import { composeEventHandlers } from '@radix-ui/primitive';
8
8
  import { composeRefs } from '@radix-ui/react-compose-refs';
9
- import { createContextScope } from '@radix-ui/react-context';
10
- import type { Scope } from '@radix-ui/react-context';
11
9
  import { useId } from '@radix-ui/react-id';
12
10
  import * as MenuPrimitive from '@radix-ui/react-menu';
13
- import { createMenuScope } from '@radix-ui/react-menu';
14
11
  import { Primitive } from '@radix-ui/react-primitive';
15
12
  import { Slot } from '@radix-ui/react-slot';
16
13
  import { useControllableState } from '@radix-ui/react-use-controllable-state';
@@ -31,6 +28,13 @@ import React, {
31
28
 
32
29
  import { useElevationContext, useSafeCollisionPadding, useThemeContext } from '../../hooks';
33
30
  import { type ThemedClassName } from '../../util';
31
+ import {
32
+ DROPDOWN_MENU_NAME,
33
+ DropdownMenuProvider,
34
+ type DropdownMenuScopedProps,
35
+ useDropdownMenuContext,
36
+ useMenuScope,
37
+ } from './DropdownMenuContext';
34
38
 
35
39
  type Direction = 'ltr' | 'rtl';
36
40
 
@@ -38,25 +42,6 @@ type Direction = 'ltr' | 'rtl';
38
42
  // DropdownMenu
39
43
  //
40
44
 
41
- const DROPDOWN_MENU_NAME = 'DropdownMenu';
42
-
43
- type ScopedProps<P> = P & { __scopeDropdownMenu?: Scope };
44
- const [createDropdownMenuContext, createDropdownMenuScope] = createContextScope(DROPDOWN_MENU_NAME, [createMenuScope]);
45
- const useMenuScope: (scope?: Scope) => any = createMenuScope();
46
-
47
- type DropdownMenuContextValue = {
48
- triggerId: string;
49
- triggerRef: RefObject<HTMLButtonElement | null>;
50
- contentId: string;
51
- open: boolean;
52
- onOpenChange(open: boolean): void;
53
- onOpenToggle(): void;
54
- modal: boolean;
55
- };
56
-
57
- const [DropdownMenuProvider, useDropdownMenuContext] =
58
- createDropdownMenuContext<DropdownMenuContextValue>(DROPDOWN_MENU_NAME);
59
-
60
45
  type DropdownMenuRootProps = PropsWithChildren<{
61
46
  dir?: Direction;
62
47
  modal?: boolean;
@@ -73,7 +58,7 @@ const DropdownMenuRoot = ({
73
58
  open: openProp,
74
59
  defaultOpen,
75
60
  onOpenChange,
76
- }: ScopedProps<DropdownMenuRootProps>) => {
61
+ }: DropdownMenuScopedProps<DropdownMenuRootProps>) => {
77
62
  const menuScope = useMenuScope(__scopeDropdownMenu);
78
63
  const triggerRef = useRef<HTMLButtonElement | null>(null);
79
64
  const [open = false, setOpen] = useControllableState({
@@ -113,7 +98,7 @@ type PrimitiveButtonProps = ComponentPropsWithoutRef<typeof Primitive.button>;
113
98
  type DropdownMenuTriggerProps = PrimitiveButtonProps;
114
99
 
115
100
  const DropdownMenuTrigger = forwardRef<DropdownMenuTriggerElement, DropdownMenuTriggerProps>(
116
- (props: ScopedProps<DropdownMenuTriggerProps>, forwardedRef) => {
101
+ (props: DropdownMenuScopedProps<DropdownMenuTriggerProps>, forwardedRef) => {
117
102
  const { __scopeDropdownMenu, disabled = false, ...triggerProps } = props;
118
103
  const context = useDropdownMenuContext(TRIGGER_NAME, __scopeDropdownMenu);
119
104
  const menuScope = useMenuScope(__scopeDropdownMenu);
@@ -177,7 +162,7 @@ type DropdownMenuVirtualTriggerProps = {
177
162
  virtualRef: RefObject<DropdownMenuTriggerElement | null>;
178
163
  };
179
164
 
180
- const DropdownMenuVirtualTrigger = (props: ScopedProps<DropdownMenuVirtualTriggerProps>) => {
165
+ const DropdownMenuVirtualTrigger = (props: DropdownMenuScopedProps<DropdownMenuVirtualTriggerProps>) => {
181
166
  const { __scopeDropdownMenu, virtualRef } = props;
182
167
  const context = useDropdownMenuContext(VIRTUAL_TRIGGER_NAME, __scopeDropdownMenu);
183
168
  const menuScope = useMenuScope(__scopeDropdownMenu);
@@ -200,7 +185,7 @@ const PORTAL_NAME = 'DropdownMenu.Portal';
200
185
  type MenuPortalProps = ComponentPropsWithoutRef<typeof MenuPrimitive.Portal>;
201
186
  type DropdownMenuPortalProps = MenuPortalProps;
202
187
 
203
- const DropdownMenuPortal: FC<DropdownMenuPortalProps> = (props: ScopedProps<DropdownMenuPortalProps>) => {
188
+ const DropdownMenuPortal: FC<DropdownMenuPortalProps> = (props: DropdownMenuScopedProps<DropdownMenuPortalProps>) => {
204
189
  const { __scopeDropdownMenu, ...portalProps } = props;
205
190
  const menuScope = useMenuScope(__scopeDropdownMenu);
206
191
  return <MenuPrimitive.Portal {...menuScope} {...portalProps} />;
@@ -239,7 +224,7 @@ type MenuContentProps = ThemedClassName<ComponentPropsWithoutRef<typeof MenuPrim
239
224
  type DropdownMenuContentProps = Omit<MenuContentProps, 'onEntryFocus'>;
240
225
 
241
226
  const DropdownMenuContent = forwardRef<DropdownMenuContentElement, DropdownMenuContentProps>(
242
- (props: ScopedProps<DropdownMenuContentProps>, forwardedRef) => {
227
+ (props: DropdownMenuScopedProps<DropdownMenuContentProps>, forwardedRef) => {
243
228
  const { __scopeDropdownMenu, classNames, collisionPadding = 8, collisionBoundary, ...contentProps } = props;
244
229
  const { tx } = useThemeContext();
245
230
  const context = useDropdownMenuContext(CONTENT_NAME, __scopeDropdownMenu);
@@ -318,7 +303,7 @@ type MenuGroupProps = ComponentPropsWithoutRef<typeof MenuPrimitive.Group>;
318
303
  type DropdownMenuGroupProps = MenuGroupProps;
319
304
 
320
305
  const DropdownMenuGroup = forwardRef<DropdownMenuGroupElement, DropdownMenuGroupProps>(
321
- (props: ScopedProps<DropdownMenuGroupProps>, forwardedRef) => {
306
+ (props: DropdownMenuScopedProps<DropdownMenuGroupProps>, forwardedRef) => {
322
307
  const { __scopeDropdownMenu, ...groupProps } = props;
323
308
  const menuScope = useMenuScope(__scopeDropdownMenu);
324
309
  return <MenuPrimitive.Group {...menuScope} {...groupProps} ref={forwardedRef} />;
@@ -338,7 +323,7 @@ type MenuLabelProps = ThemedClassName<ComponentPropsWithoutRef<typeof MenuPrimit
338
323
  type DropdownMenuLabelProps = MenuLabelProps;
339
324
 
340
325
  const DropdownMenuGroupLabel = forwardRef<DropdownMenuLabelElement, DropdownMenuLabelProps>(
341
- (props: ScopedProps<DropdownMenuLabelProps>, forwardedRef) => {
326
+ (props: DropdownMenuScopedProps<DropdownMenuLabelProps>, forwardedRef) => {
342
327
  const { __scopeDropdownMenu, classNames, ...labelProps } = props;
343
328
  const menuScope = useMenuScope(__scopeDropdownMenu);
344
329
  const { tx } = useThemeContext();
@@ -366,7 +351,7 @@ type MenuItemProps = ThemedClassName<ComponentPropsWithoutRef<typeof MenuPrimiti
366
351
  type DropdownMenuItemProps = MenuItemProps;
367
352
 
368
353
  const DropdownMenuItem = forwardRef<DropdownMenuItemElement, DropdownMenuItemProps>(
369
- (props: ScopedProps<DropdownMenuItemProps>, forwardedRef) => {
354
+ (props: DropdownMenuScopedProps<DropdownMenuItemProps>, forwardedRef) => {
370
355
  const { __scopeDropdownMenu, classNames, ...itemProps } = props;
371
356
  const menuScope = useMenuScope(__scopeDropdownMenu);
372
357
  const { tx } = useThemeContext();
@@ -394,7 +379,7 @@ type MenuCheckboxItemProps = ThemedClassName<ComponentPropsWithoutRef<typeof Men
394
379
  type DropdownMenuCheckboxItemProps = MenuCheckboxItemProps;
395
380
 
396
381
  const DropdownMenuCheckboxItem = forwardRef<DropdownMenuCheckboxItemElement, DropdownMenuCheckboxItemProps>(
397
- (props: ScopedProps<DropdownMenuCheckboxItemProps>, forwardedRef) => {
382
+ (props: DropdownMenuScopedProps<DropdownMenuCheckboxItemProps>, forwardedRef) => {
398
383
  const { __scopeDropdownMenu, classNames, ...checkboxItemProps } = props;
399
384
  const menuScope = useMenuScope(__scopeDropdownMenu);
400
385
  const { tx } = useThemeContext();
@@ -422,7 +407,7 @@ type MenuRadioGroupProps = ComponentPropsWithoutRef<typeof MenuPrimitive.RadioGr
422
407
  type DropdownMenuRadioGroupProps = MenuRadioGroupProps;
423
408
 
424
409
  const DropdownMenuRadioGroup = forwardRef<DropdownMenuRadioGroupElement, DropdownMenuRadioGroupProps>(
425
- (props: ScopedProps<DropdownMenuRadioGroupProps>, forwardedRef) => {
410
+ (props: DropdownMenuScopedProps<DropdownMenuRadioGroupProps>, forwardedRef) => {
426
411
  const { __scopeDropdownMenu, ...radioGroupProps } = props;
427
412
  const menuScope = useMenuScope(__scopeDropdownMenu);
428
413
  return <MenuPrimitive.RadioGroup {...menuScope} {...radioGroupProps} ref={forwardedRef} />;
@@ -442,7 +427,7 @@ type MenuRadioItemProps = ComponentPropsWithoutRef<typeof MenuPrimitive.RadioIte
442
427
  type DropdownMenuRadioItemProps = ThemedClassName<MenuRadioItemProps>;
443
428
 
444
429
  const DropdownMenuRadioItem = forwardRef<DropdownMenuRadioItemElement, DropdownMenuRadioItemProps>(
445
- (props: ScopedProps<DropdownMenuRadioItemProps>, forwardedRef) => {
430
+ (props: DropdownMenuScopedProps<DropdownMenuRadioItemProps>, forwardedRef) => {
446
431
  const { __scopeDropdownMenu, classNames, ...itemProps } = props;
447
432
  const menuScope = useMenuScope(__scopeDropdownMenu);
448
433
  const { tx } = useThemeContext();
@@ -470,7 +455,7 @@ type MenuItemIndicatorProps = ComponentPropsWithoutRef<typeof MenuPrimitive.Item
470
455
  type DropdownMenuItemIndicatorProps = MenuItemIndicatorProps;
471
456
 
472
457
  const DropdownMenuItemIndicator = forwardRef<DropdownMenuItemIndicatorElement, DropdownMenuItemIndicatorProps>(
473
- (props: ScopedProps<DropdownMenuItemIndicatorProps>, forwardedRef) => {
458
+ (props: DropdownMenuScopedProps<DropdownMenuItemIndicatorProps>, forwardedRef) => {
474
459
  const { __scopeDropdownMenu, ...itemIndicatorProps } = props;
475
460
  const menuScope = useMenuScope(__scopeDropdownMenu);
476
461
  return <MenuPrimitive.ItemIndicator {...menuScope} {...itemIndicatorProps} ref={forwardedRef} />;
@@ -490,7 +475,7 @@ type MenuSeparatorProps = ThemedClassName<ComponentPropsWithoutRef<typeof MenuPr
490
475
  type DropdownMenuSeparatorProps = MenuSeparatorProps;
491
476
 
492
477
  const DropdownMenuSeparator = forwardRef<DropdownMenuSeparatorElement, DropdownMenuSeparatorProps>(
493
- (props: ScopedProps<DropdownMenuSeparatorProps>, forwardedRef) => {
478
+ (props: DropdownMenuScopedProps<DropdownMenuSeparatorProps>, forwardedRef) => {
494
479
  const { __scopeDropdownMenu, classNames, ...separatorProps } = props;
495
480
  const menuScope = useMenuScope(__scopeDropdownMenu);
496
481
  const { tx } = useThemeContext();
@@ -518,7 +503,7 @@ type MenuArrowProps = ThemedClassName<ComponentPropsWithoutRef<typeof MenuPrimit
518
503
  type DropdownMenuArrowProps = MenuArrowProps;
519
504
 
520
505
  const DropdownMenuArrow = forwardRef<DropdownMenuArrowElement, DropdownMenuArrowProps>(
521
- (props: ScopedProps<DropdownMenuArrowProps>, forwardedRef) => {
506
+ (props: DropdownMenuScopedProps<DropdownMenuArrowProps>, forwardedRef) => {
522
507
  const { __scopeDropdownMenu, classNames, ...arrowProps } = props;
523
508
  const menuScope = useMenuScope(__scopeDropdownMenu);
524
509
  const { tx } = useThemeContext();
@@ -546,7 +531,7 @@ type DropdownMenuSubProps = {
546
531
  onOpenChange?(open: boolean): void;
547
532
  };
548
533
 
549
- const DropdownMenuSub: FC<DropdownMenuSubProps> = (props: ScopedProps<DropdownMenuSubProps>) => {
534
+ const DropdownMenuSub: FC<DropdownMenuSubProps> = (props: DropdownMenuScopedProps<DropdownMenuSubProps>) => {
550
535
  const { __scopeDropdownMenu, children, open: openProp, onOpenChange, defaultOpen } = props;
551
536
  const menuScope = useMenuScope(__scopeDropdownMenu);
552
537
  const [open = false, setOpen] = useControllableState({
@@ -573,7 +558,7 @@ type MenuSubTriggerProps = ComponentPropsWithoutRef<typeof MenuPrimitive.SubTrig
573
558
  type DropdownMenuSubTriggerProps = MenuSubTriggerProps;
574
559
 
575
560
  const DropdownMenuSubTrigger = forwardRef<DropdownMenuSubTriggerElement, DropdownMenuSubTriggerProps>(
576
- (props: ScopedProps<DropdownMenuSubTriggerProps>, forwardedRef) => {
561
+ (props: DropdownMenuScopedProps<DropdownMenuSubTriggerProps>, forwardedRef) => {
577
562
  const { __scopeDropdownMenu, ...subTriggerProps } = props;
578
563
  const menuScope = useMenuScope(__scopeDropdownMenu);
579
564
  return <MenuPrimitive.SubTrigger {...menuScope} {...subTriggerProps} ref={forwardedRef} />;
@@ -593,7 +578,7 @@ type MenuSubContentProps = ComponentPropsWithoutRef<typeof MenuPrimitive.SubCont
593
578
  type DropdownMenuSubContentProps = MenuSubContentProps;
594
579
 
595
580
  const DropdownMenuSubContent = forwardRef<DropdownMenuSubContentElement, DropdownMenuSubContentProps>(
596
- (props: ScopedProps<DropdownMenuSubContentProps>, forwardedRef) => {
581
+ (props: DropdownMenuScopedProps<DropdownMenuSubContentProps>, forwardedRef) => {
597
582
  const { __scopeDropdownMenu, ...subContentProps } = props;
598
583
  const menuScope = useMenuScope(__scopeDropdownMenu);
599
584
 
@@ -645,11 +630,9 @@ export const DropdownMenu = {
645
630
  SubContent: DropdownMenuSubContent,
646
631
  };
647
632
 
648
- type DropdownMenuScope = Scope;
649
-
650
- const useDropdownMenuMenuScope: (scope?: DropdownMenuScope) => any = useMenuScope;
651
-
652
- export { createDropdownMenuScope, useDropdownMenuContext, useDropdownMenuMenuScope };
633
+ // Type-only re-export (erased, so it does not affect the refresh boundary): keeps the inferred
634
+ // types of downstream composites nameable across package boundaries.
635
+ export type { DropdownMenuScopedProps } from './DropdownMenuContext';
653
636
 
654
637
  export type {
655
638
  DropdownMenuArrowProps,
@@ -0,0 +1,35 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type Scope, createContextScope } from '@radix-ui/react-context';
6
+ import { createMenuScope } from '@radix-ui/react-menu';
7
+ import { type RefObject } from 'react';
8
+
9
+ // Kept out of `DropdownMenu.tsx`: react-refresh only fast-refreshes a module whose exports are all
10
+ // components, so a context and its hook exported beside them force a full page reload on every edit.
11
+
12
+ export const DROPDOWN_MENU_NAME = 'DropdownMenu';
13
+
14
+ export type DropdownMenuScopedProps<P> = P & { __scopeDropdownMenu?: Scope };
15
+ export const [createDropdownMenuContext, createDropdownMenuScope] = createContextScope(DROPDOWN_MENU_NAME, [
16
+ createMenuScope,
17
+ ]);
18
+ export const useMenuScope: (scope?: Scope) => any = createMenuScope();
19
+
20
+ export type DropdownMenuScope = Scope;
21
+
22
+ export const useDropdownMenuMenuScope: (scope?: DropdownMenuScope) => any = useMenuScope;
23
+
24
+ export type DropdownMenuContextValue = {
25
+ triggerId: string;
26
+ triggerRef: RefObject<HTMLButtonElement | null>;
27
+ contentId: string;
28
+ open: boolean;
29
+ onOpenChange(open: boolean): void;
30
+ onOpenToggle(): void;
31
+ modal: boolean;
32
+ };
33
+
34
+ export const [DropdownMenuProvider, useDropdownMenuContext] =
35
+ createDropdownMenuContext<DropdownMenuContextValue>(DROPDOWN_MENU_NAME);
@@ -13,7 +13,7 @@ export type MenuStyleProps = Partial<{
13
13
 
14
14
  const content: ComponentFunction<MenuStyleProps> = ({ elevation }, ...etc) =>
15
15
  mx(
16
- 'dx-popover-surface w-48 rounded-sm md:w-56 border border-separator',
16
+ 'dx-popover-surface w-48 md:w-56 border border-separator rounded-sm',
17
17
  surfaceZIndex({ elevation, level: 'menu' }),
18
18
  surfaceShadow({ elevation: 'positioned' }),
19
19
  ...etc,
@@ -24,7 +24,7 @@ const viewport: ComponentFunction<MenuStyleProps> = (_props, ...etc) =>
24
24
 
25
25
  const item: ComponentFunction<MenuStyleProps> = (_props, ...etc) =>
26
26
  mx(
27
- 'flex cursor-pointer select-none items-center gap-2 rounded-xs px-2 py-2 text-sm',
27
+ 'flex cursor-pointer select-none items-center gap-2 rounded-xs min-h-(--dx-control) px-(--dx-control-pad) py-1 text-sm',
28
28
  'hover:bg-hover-surface data-[highlighted]:bg-hover-surface',
29
29
  'dx-focus-subdued',
30
30
  dataDisabled,
@@ -34,7 +34,7 @@ const item: ComponentFunction<MenuStyleProps> = (_props, ...etc) =>
34
34
  const separator: ComponentFunction<MenuStyleProps> = (_props, ...etc) => mx('my-1 mx-2 h-px bg-separator', ...etc);
35
35
 
36
36
  const groupLabel: ComponentFunction<MenuStyleProps> = (_props, ...etc) =>
37
- mx('text-description', 'select-none px-2 py-2', ...etc);
37
+ mx('text-description', 'select-none px-(--dx-control-pad) py-1', ...etc);
38
38
 
39
39
  const arrow: ComponentFunction<MenuStyleProps> = (_props, ...etc) => mx('fill-separator', ...etc);
40
40
 
@@ -3,4 +3,6 @@
3
3
  //
4
4
 
5
5
  export * from './ContextMenu';
6
+ export { createDropdownMenuScope, useDropdownMenuContext, useDropdownMenuMenuScope } from './DropdownMenuContext';
7
+
6
8
  export * from './DropdownMenu';
@@ -19,23 +19,30 @@ type StoryArgs = {
19
19
  title: string;
20
20
  body: string;
21
21
  button?: boolean;
22
+ /** Wrap the title/body in `Message.Content` so the message carries its own inset. */
23
+ padded?: boolean;
22
24
  };
23
25
 
24
- const DefaultStory = ({ valence, title, body, button }: StoryArgs) => (
25
- <div className='w-[30rem]'>
26
- <Message.Root valence={valence}>
27
- {title && <Message.Title onClose={() => console.log('close')}>{title}</Message.Title>}
28
- {body && (
29
- <Message.Content asChild classNames='gap-2'>
30
- <div>
31
- <p>{body}</p>
32
- {button && <Button>Test</Button>}
33
- </div>
34
- </Message.Content>
35
- )}
36
- </Message.Root>
37
- </div>
38
- );
26
+ const DefaultStory = ({ valence, title, body, button, padded }: StoryArgs) => {
27
+ const Wrapper = padded ? Message.Content : React.Fragment;
28
+ return (
29
+ <div className='w-[30rem]'>
30
+ <Message.Root valence={valence}>
31
+ <Wrapper>
32
+ {title && <Message.Title onClose={() => console.log('close')}>{title}</Message.Title>}
33
+ {body && (
34
+ <Message.Body asChild classNames='gap-2'>
35
+ <div>
36
+ <p>{body}</p>
37
+ {button && <Button>Test</Button>}
38
+ </div>
39
+ </Message.Body>
40
+ )}
41
+ </Wrapper>
42
+ </Message.Root>
43
+ </div>
44
+ );
45
+ };
39
46
 
40
47
  const meta = {
41
48
  title: 'ui/react-ui-core/components/Message',
@@ -101,3 +108,13 @@ export const Error: Story = {
101
108
  button: true,
102
109
  },
103
110
  };
111
+
112
+ export const Padded: Story = {
113
+ args: {
114
+ valence: 'neutral',
115
+ title: 'Padded',
116
+ body: random.lorem.paragraphs(1),
117
+ button: true,
118
+ padded: true,
119
+ },
120
+ };
@@ -14,6 +14,11 @@ const root: ComponentFunction<MessageStyleProps> = ({ valence }, etc) => {
14
14
  return mx('p-1 rounded-sm', messageValence(valence), etc);
15
15
  };
16
16
 
17
+ // Subgrid rather than a plain block so a nested `Message.Title` row still reaches the root's gutters.
18
+ const content: ComponentFunction<MessageStyleProps> = (_, etc) => {
19
+ return mx('col-span-full grid grid-cols-subgrid p-trim-md', etc);
20
+ };
21
+
17
22
  const header: ComponentFunction<MessageStyleProps> = (_, etc) => {
18
23
  return mx('items-center', etc);
19
24
  };
@@ -22,13 +27,14 @@ const title: ComponentFunction<MessageStyleProps> = (_, etc) => {
22
27
  return mx('col-start-2 overflow-hidden truncate', etc);
23
28
  };
24
29
 
25
- const content: ComponentFunction<MessageStyleProps> = (_, etc) => {
30
+ const body: ComponentFunction<MessageStyleProps> = (_, etc) => {
26
31
  return mx('col-start-2 flex flex-col first:font-medium pb-1.5', etc);
27
32
  };
28
33
 
29
34
  export const messageTheme: Theme<MessageStyleProps> = {
30
35
  root,
36
+ content,
31
37
  header,
32
38
  title,
33
- content,
39
+ body,
34
40
  };