@dxos/react-ui 0.8.4-main.69d29f4 → 0.8.4-main.6fa680abb7

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 (271) hide show
  1. package/dist/lib/browser/{chunk-CEKVHJ27.mjs → chunk-2FKSMWNY.mjs} +117 -117
  2. package/dist/lib/browser/chunk-2FKSMWNY.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +2804 -1957
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +56 -32
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/{chunk-2NHEX4AD.mjs → chunk-ZNBLTSHI.mjs} +117 -117
  9. package/dist/lib/node-esm/chunk-ZNBLTSHI.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +2804 -1957
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +56 -32
  14. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  15. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  16. package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  18. package/dist/types/src/components/Button/Button.d.ts.map +1 -1
  19. package/dist/types/src/components/Card/Card.d.ts +107 -0
  20. package/dist/types/src/components/Card/Card.d.ts.map +1 -0
  21. package/dist/types/src/components/Card/Card.stories.d.ts +21 -0
  22. package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -0
  23. package/dist/types/src/components/Card/index.d.ts +2 -0
  24. package/dist/types/src/components/Card/index.d.ts.map +1 -0
  25. package/dist/types/src/components/Dialog/AlertDialog.d.ts +12 -3
  26. package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
  27. package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts.map +1 -1
  28. package/dist/types/src/components/Dialog/Dialog.d.ts +11 -4
  29. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  30. package/dist/types/src/components/Dialog/Dialog.stories.d.ts +3 -6
  31. package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
  32. package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts +11 -0
  33. package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts.map +1 -0
  34. package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts +7 -0
  35. package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts.map +1 -0
  36. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts +8 -0
  37. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -0
  38. package/dist/types/src/components/ErrorFallback/ThrowError.d.ts +9 -0
  39. package/dist/types/src/components/ErrorFallback/ThrowError.d.ts.map +1 -0
  40. package/dist/types/src/components/ErrorFallback/index.d.ts +5 -0
  41. package/dist/types/src/components/ErrorFallback/index.d.ts.map +1 -0
  42. package/dist/types/src/components/Image/Image.d.ts +14 -0
  43. package/dist/types/src/components/Image/Image.d.ts.map +1 -0
  44. package/dist/types/src/components/Image/Image.stories.d.ts +33 -0
  45. package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -0
  46. package/dist/types/src/components/Image/index.d.ts +2 -0
  47. package/dist/types/src/components/Image/index.d.ts.map +1 -0
  48. package/dist/types/src/components/Input/Input.d.ts +2 -5
  49. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  50. package/dist/types/src/components/Input/Input.stories.d.ts +7 -7
  51. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/List/List.d.ts.map +1 -1
  53. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  54. package/dist/types/src/components/List/Treegrid.d.ts.map +1 -1
  55. package/dist/types/src/components/Main/Main.d.ts +9 -10
  56. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  57. package/dist/types/src/components/Main/Main.stories.d.ts +0 -3
  58. package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
  59. package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -1
  60. package/dist/types/src/components/Message/Message.d.ts.map +1 -1
  61. package/dist/types/src/components/Message/Message.stories.d.ts +2 -3
  62. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  63. package/dist/types/src/components/Popover/Popover.d.ts +1 -0
  64. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  65. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +21 -26
  66. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  67. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +41 -9
  68. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  69. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
  70. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +6 -1
  71. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
  72. package/dist/types/src/components/Select/Select.d.ts.map +1 -1
  73. package/dist/types/src/components/Skeleton/Skeleton.d.ts +12 -0
  74. package/dist/types/src/components/Skeleton/Skeleton.d.ts.map +1 -0
  75. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts +17 -0
  76. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -0
  77. package/dist/types/src/components/Skeleton/index.d.ts +2 -0
  78. package/dist/types/src/components/Skeleton/index.d.ts.map +1 -0
  79. package/dist/types/src/components/Splitter/Splitter.d.ts +32 -0
  80. package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -0
  81. package/dist/types/src/components/Splitter/Splitter.stories.d.ts +7 -0
  82. package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -0
  83. package/dist/types/src/components/Splitter/index.d.ts +2 -0
  84. package/dist/types/src/components/Splitter/index.d.ts.map +1 -0
  85. package/dist/types/src/components/Status/Status.stories.d.ts +4 -2
  86. package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
  87. package/dist/types/src/components/Tag/Tag.d.ts.map +1 -1
  88. package/dist/types/src/components/Tag/Tag.stories.d.ts +0 -5
  89. package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
  90. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +1 -0
  91. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  92. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts +12 -0
  93. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -0
  94. package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
  95. package/dist/types/src/components/Toolbar/Toolbar.d.ts +33 -7
  96. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  97. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  98. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  99. package/dist/types/src/components/index.d.ts +8 -4
  100. package/dist/types/src/components/index.d.ts.map +1 -1
  101. package/dist/types/src/exemplars/generics.stories.d.ts +18 -0
  102. package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -0
  103. package/dist/types/src/exemplars/slot.stories.d.ts +14 -0
  104. package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -0
  105. package/dist/types/src/exemplars/tabster.stories.d.ts +8 -0
  106. package/dist/types/src/exemplars/tabster.stories.d.ts.map +1 -0
  107. package/dist/types/src/exemplars/virtualizer.stories.d.ts +11 -0
  108. package/dist/types/src/exemplars/virtualizer.stories.d.ts.map +1 -0
  109. package/dist/types/src/index.d.ts +1 -0
  110. package/dist/types/src/index.d.ts.map +1 -1
  111. package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
  112. package/dist/types/src/primitives/Column/Column.d.ts +26 -0
  113. package/dist/types/src/primitives/Column/Column.d.ts.map +1 -0
  114. package/dist/types/src/primitives/Column/Column.stories.d.ts +6 -0
  115. package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -0
  116. package/dist/types/src/primitives/Column/index.d.ts +2 -0
  117. package/dist/types/src/primitives/Column/index.d.ts.map +1 -0
  118. package/dist/types/src/primitives/Container/Container.d.ts +8 -0
  119. package/dist/types/src/primitives/Container/Container.d.ts.map +1 -0
  120. package/dist/types/src/primitives/Container/Container.stories.d.ts +6 -0
  121. package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -0
  122. package/dist/types/src/primitives/Container/index.d.ts +2 -0
  123. package/dist/types/src/primitives/Container/index.d.ts.map +1 -0
  124. package/dist/types/src/primitives/Flex/Flex.d.ts +13 -0
  125. package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -0
  126. package/dist/types/src/primitives/Flex/Flex.stories.d.ts +8 -0
  127. package/dist/types/src/primitives/Flex/Flex.stories.d.ts.map +1 -0
  128. package/dist/types/src/primitives/Flex/index.d.ts +2 -0
  129. package/dist/types/src/primitives/Flex/index.d.ts.map +1 -0
  130. package/dist/types/src/primitives/Grid/Grid.d.ts +15 -0
  131. package/dist/types/src/primitives/Grid/Grid.d.ts.map +1 -0
  132. package/dist/types/src/primitives/Grid/Grid.stories.d.ts +8 -0
  133. package/dist/types/src/primitives/Grid/Grid.stories.d.ts.map +1 -0
  134. package/dist/types/src/primitives/Grid/index.d.ts +2 -0
  135. package/dist/types/src/primitives/Grid/index.d.ts.map +1 -0
  136. package/dist/types/src/primitives/Panel/Panel.d.ts +26 -0
  137. package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -0
  138. package/dist/types/src/primitives/Panel/Panel.stories.d.ts +6 -0
  139. package/dist/types/src/primitives/Panel/Panel.stories.d.ts.map +1 -0
  140. package/dist/types/src/primitives/Panel/index.d.ts +2 -0
  141. package/dist/types/src/primitives/Panel/index.d.ts.map +1 -0
  142. package/dist/types/src/primitives/index.d.ts +6 -0
  143. package/dist/types/src/primitives/index.d.ts.map +1 -0
  144. package/dist/types/src/testing/Loading.d.ts +9 -0
  145. package/dist/types/src/testing/Loading.d.ts.map +1 -0
  146. package/dist/types/src/testing/decorators/withLayout.d.ts +1 -1
  147. package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -1
  148. package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -1
  149. package/dist/types/src/testing/decorators/withTheme.d.ts +3 -2
  150. package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
  151. package/dist/types/src/testing/index.d.ts +1 -0
  152. package/dist/types/src/testing/index.d.ts.map +1 -1
  153. package/dist/types/src/translations.d.ts +11 -0
  154. package/dist/types/src/translations.d.ts.map +1 -0
  155. package/dist/types/tsconfig.tsbuildinfo +1 -1
  156. package/package.json +25 -21
  157. package/src/components/Avatars/Avatar.stories.tsx +5 -6
  158. package/src/components/Avatars/Avatar.tsx +5 -12
  159. package/src/components/Avatars/AvatarGroup.stories.tsx +2 -2
  160. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +3 -3
  161. package/src/components/Breadcrumb/Breadcrumb.tsx +11 -37
  162. package/src/components/Button/Button.stories.tsx +3 -3
  163. package/src/components/Button/Button.tsx +6 -12
  164. package/src/components/Button/IconButton.stories.tsx +4 -4
  165. package/src/components/Button/IconButton.tsx +1 -1
  166. package/src/components/Button/Toggle.stories.tsx +2 -2
  167. package/src/components/Button/ToggleGroup.stories.tsx +2 -2
  168. package/src/components/Card/Card.stories.tsx +151 -0
  169. package/src/components/Card/Card.tsx +347 -0
  170. package/src/components/Card/index.ts +5 -0
  171. package/src/components/Clipboard/CopyButton.tsx +3 -3
  172. package/src/components/Dialog/AlertDialog.stories.tsx +15 -15
  173. package/src/components/Dialog/AlertDialog.tsx +116 -16
  174. package/src/components/Dialog/Dialog.stories.tsx +40 -15
  175. package/src/components/Dialog/Dialog.tsx +75 -45
  176. package/src/components/ErrorFallback/ErrorFallback.stories.tsx +50 -0
  177. package/src/components/ErrorFallback/ErrorFallback.tsx +70 -0
  178. package/src/components/ErrorFallback/ErrorStack.tsx +80 -0
  179. package/src/components/ErrorFallback/ThrowError.tsx +37 -0
  180. package/src/components/ErrorFallback/index.ts +9 -0
  181. package/src/components/Icon/Icon.stories.tsx +2 -2
  182. package/src/components/Icon/Icon.tsx +1 -1
  183. package/src/components/Image/Image.stories.tsx +86 -0
  184. package/src/components/Image/Image.tsx +223 -0
  185. package/src/components/Image/index.ts +5 -0
  186. package/src/components/Input/Input.stories.tsx +20 -39
  187. package/src/components/Input/Input.tsx +20 -65
  188. package/src/components/Link/Link.stories.tsx +2 -2
  189. package/src/components/Link/Link.tsx +2 -2
  190. package/src/components/List/List.stories.tsx +15 -22
  191. package/src/components/List/List.tsx +11 -16
  192. package/src/components/List/ListDropIndicator.tsx +7 -7
  193. package/src/components/List/Tree.stories.tsx +4 -4
  194. package/src/components/List/TreeDropIndicator.tsx +6 -6
  195. package/src/components/List/Treegrid.stories.tsx +3 -3
  196. package/src/components/List/Treegrid.tsx +10 -15
  197. package/src/components/Main/Main.stories.tsx +41 -23
  198. package/src/components/Main/Main.tsx +138 -81
  199. package/src/components/Menu/ContextMenu.stories.tsx +2 -2
  200. package/src/components/Menu/ContextMenu.tsx +9 -33
  201. package/src/components/Menu/DropdownMenu.stories.tsx +2 -2
  202. package/src/components/Menu/DropdownMenu.tsx +10 -10
  203. package/src/components/Message/Message.stories.tsx +25 -10
  204. package/src/components/Message/Message.tsx +17 -29
  205. package/src/components/Popover/Popover.stories.tsx +4 -4
  206. package/src/components/Popover/Popover.tsx +23 -20
  207. package/src/components/ScrollArea/ScrollArea.stories.tsx +152 -76
  208. package/src/components/ScrollArea/ScrollArea.tsx +72 -116
  209. package/src/components/ScrollArea/index.ts +1 -1
  210. package/src/components/ScrollContainer/ScrollContainer.stories.tsx +41 -22
  211. package/src/components/ScrollContainer/ScrollContainer.tsx +18 -13
  212. package/src/components/Select/Select.stories.tsx +2 -2
  213. package/src/components/Select/Select.tsx +11 -27
  214. package/src/components/Separator/Separator.tsx +1 -1
  215. package/src/components/Skeleton/Skeleton.stories.tsx +52 -0
  216. package/src/components/Skeleton/Skeleton.tsx +26 -0
  217. package/src/components/Skeleton/index.ts +5 -0
  218. package/src/components/Splitter/Splitter.stories.tsx +83 -0
  219. package/src/components/Splitter/Splitter.tsx +126 -0
  220. package/src/components/Splitter/index.ts +5 -0
  221. package/src/components/Status/Status.stories.tsx +21 -17
  222. package/src/components/Status/Status.tsx +2 -2
  223. package/src/components/Tag/Tag.stories.tsx +4 -9
  224. package/src/components/Tag/Tag.tsx +2 -7
  225. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +32 -0
  226. package/src/components/ThemeProvider/ThemeProvider.tsx +4 -3
  227. package/src/components/Toast/Toast.stories.tsx +2 -2
  228. package/src/components/Toast/Toast.tsx +10 -14
  229. package/src/components/Toolbar/Toolbar.stories.tsx +2 -2
  230. package/src/components/Toolbar/Toolbar.tsx +174 -12
  231. package/src/components/Tooltip/Tooltip.stories.tsx +15 -13
  232. package/src/components/Tooltip/Tooltip.tsx +3 -2
  233. package/src/components/index.ts +9 -5
  234. package/src/exemplars/generics.stories.tsx +49 -0
  235. package/src/exemplars/slot.stories.tsx +107 -0
  236. package/src/exemplars/tabster.stories.tsx +127 -0
  237. package/src/exemplars/virtualizer.stories.tsx +137 -0
  238. package/src/index.ts +1 -0
  239. package/src/playground/Controls.stories.tsx +3 -10
  240. package/src/playground/Custom.stories.tsx +10 -10
  241. package/src/playground/Typography.stories.tsx +3 -3
  242. package/src/primitives/Column/Column.stories.tsx +78 -0
  243. package/src/primitives/Column/Column.tsx +134 -0
  244. package/src/primitives/Column/index.ts +5 -0
  245. package/src/primitives/Container/Container.stories.tsx +30 -0
  246. package/src/primitives/Container/Container.tsx +22 -0
  247. package/src/primitives/Container/index.ts +5 -0
  248. package/src/primitives/Flex/Flex.stories.tsx +58 -0
  249. package/src/primitives/Flex/Flex.tsx +29 -0
  250. package/src/primitives/Flex/index.ts +5 -0
  251. package/src/primitives/Grid/Grid.stories.tsx +57 -0
  252. package/src/primitives/Grid/Grid.tsx +35 -0
  253. package/src/primitives/Grid/index.ts +5 -0
  254. package/src/primitives/Panel/Panel.stories.tsx +67 -0
  255. package/src/primitives/Panel/Panel.tsx +119 -0
  256. package/src/primitives/Panel/index.ts +5 -0
  257. package/src/primitives/index.ts +9 -0
  258. package/src/testing/Loading.tsx +26 -0
  259. package/src/testing/decorators/withLayout.tsx +21 -7
  260. package/src/testing/decorators/withLayoutVariants.tsx +18 -21
  261. package/src/testing/decorators/withTheme.tsx +19 -17
  262. package/src/testing/index.ts +2 -0
  263. package/src/translations.ts +19 -0
  264. package/dist/lib/browser/chunk-CEKVHJ27.mjs.map +0 -7
  265. package/dist/lib/node-esm/chunk-2NHEX4AD.mjs.map +0 -7
  266. package/dist/types/src/components/AnchoredOverflow/AnchoredOverflow.d.ts +0 -15
  267. package/dist/types/src/components/AnchoredOverflow/AnchoredOverflow.d.ts.map +0 -1
  268. package/dist/types/src/components/AnchoredOverflow/index.d.ts +0 -2
  269. package/dist/types/src/components/AnchoredOverflow/index.d.ts.map +0 -1
  270. package/src/components/AnchoredOverflow/AnchoredOverflow.tsx +0 -59
  271. package/src/components/AnchoredOverflow/index.ts +0 -5
@@ -2,11 +2,18 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { Primitive } from '@radix-ui/react-primitive';
6
+ import { Slot } from '@radix-ui/react-slot';
5
7
  import type { ToggleGroupItemProps as ToggleGroupItemPrimitiveProps } from '@radix-ui/react-toggle-group';
6
8
  import * as ToolbarPrimitive from '@radix-ui/react-toolbar';
7
9
  import React, { Fragment, forwardRef } from 'react';
10
+ import { useTranslation } from 'react-i18next';
11
+
12
+ import { composableProps, type ToolbarStyleProps } from '@dxos/ui-theme';
13
+ import { type SlottableProps } from '@dxos/ui-types';
8
14
 
9
15
  import { useThemeContext } from '../../hooks';
16
+ import { translationKey } from '../../translations';
10
17
  import { type ThemedClassName } from '../../util';
11
18
  import {
12
19
  Button,
@@ -20,33 +27,42 @@ import {
20
27
  type ToggleProps,
21
28
  } from '../Button';
22
29
  import { Link, type LinkProps } from '../Link';
30
+ import { DropdownMenu } from '../Menu';
23
31
  import { Separator, type SeparatorProps } from '../Separator';
24
32
 
33
+ //
34
+ // Root
35
+ //
36
+
25
37
  type ToolbarRootProps = ThemedClassName<
26
- ToolbarPrimitive.ToolbarProps & {
27
- disabled?: boolean;
28
- layoutManaged?: boolean; // TODO(burdon): Replace with Toolbar.Content to allow inner layout management?
29
- textBlockWidth?: boolean;
30
- }
38
+ ToolbarPrimitive.ToolbarProps &
39
+ ToolbarStyleProps & {
40
+ textBlockWidth?: boolean;
41
+ }
31
42
  >;
32
43
 
33
- // TODO(burdon): Implement asChild.
44
+ // TODO(burdon): Implement asChild property.
34
45
  const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
35
- ({ classNames, children, disabled, layoutManaged, textBlockWidth: textBlockWidthProp, ...props }, forwardedRef) => {
46
+ (
47
+ { children, density, disabled, layoutManaged, textBlockWidth: textBlockWidthProp, orientation, ...props },
48
+ forwardedRef,
49
+ ) => {
50
+ const { className, dir: _, ...rest } = composableProps(props);
36
51
  const { tx } = useThemeContext();
37
52
  const InnerRoot = textBlockWidthProp ? 'div' : Fragment;
38
53
  const innerRootProps = textBlockWidthProp
39
54
  ? {
40
55
  role: 'none',
41
- className: tx('toolbar.inner', 'toolbar', { layoutManaged }, classNames),
56
+ className: tx('toolbar.inner', { layoutManaged }, className),
42
57
  }
43
58
  : {};
44
59
 
45
60
  return (
46
61
  <ToolbarPrimitive.Root
47
- {...props}
48
- data-arrow-keys={props.orientation === 'vertical' ? 'up down' : 'left right'}
49
- className={tx('toolbar.root', 'toolbar', { layoutManaged, disabled }, classNames)}
62
+ {...rest}
63
+ orientation={orientation}
64
+ data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}
65
+ className={tx('toolbar.root', { density, disabled, layoutManaged }, className)}
50
66
  ref={forwardedRef}
51
67
  >
52
68
  <InnerRoot {...innerRootProps}>{children}</InnerRoot>
@@ -55,6 +71,27 @@ const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
55
71
  },
56
72
  );
57
73
 
74
+ //
75
+ // Text
76
+ //
77
+
78
+ type ToolbarTextProps = SlottableProps<HTMLDivElement>;
79
+
80
+ const ToolbarText = forwardRef<HTMLDivElement, ToolbarTextProps>(({ children, asChild, ...props }, forwardedRef) => {
81
+ const { className, ...rest } = composableProps(props);
82
+ const Comp = asChild ? Slot : Primitive.div;
83
+ const { tx } = useThemeContext();
84
+ return (
85
+ <Comp {...rest} className={tx('toolbar.text', {}, className)} ref={forwardedRef}>
86
+ {children}
87
+ </Comp>
88
+ );
89
+ });
90
+
91
+ //
92
+ // Button
93
+ //
94
+
58
95
  type ToolbarButtonProps = ButtonProps;
59
96
 
60
97
  const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>((props, forwardedRef) => {
@@ -65,6 +102,10 @@ const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>((props,
65
102
  );
66
103
  });
67
104
 
105
+ //
106
+ // IconButton
107
+ //
108
+
68
109
  type ToolbarIconButtonProps = IconButtonProps;
69
110
 
70
111
  const ToolbarIconButton = forwardRef<HTMLButtonElement, ToolbarIconButtonProps>((props, forwardedRef) => {
@@ -85,6 +126,10 @@ const ToolbarToggle = forwardRef<HTMLButtonElement, ToolbarToggleProps>((props,
85
126
  );
86
127
  });
87
128
 
129
+ //
130
+ // Link
131
+ //
132
+
88
133
  type ToolbarLinkProps = LinkProps;
89
134
 
90
135
  const ToolbarLink = forwardRef<HTMLAnchorElement, ToolbarLinkProps>((props, forwardedRef) => {
@@ -101,6 +146,10 @@ type ToolbarToggleGroupProps = (
101
146
  ) &
102
147
  ButtonGroupProps;
103
148
 
149
+ //
150
+ // ToggleGroup
151
+ //
152
+
104
153
  const ToolbarToggleGroup = forwardRef<HTMLDivElement, ToolbarToggleGroupProps>(
105
154
  ({ classNames, children, elevation, ...props }, forwardedRef) => {
106
155
  return (
@@ -146,10 +195,14 @@ const ToolbarToggleGroupIconItem = forwardRef<HTMLButtonElement, ToolbarToggleGr
146
195
  },
147
196
  );
148
197
 
198
+ //
199
+ // Separator
200
+ //
201
+
149
202
  type ToolbarSeparatorProps = SeparatorProps & { variant?: 'gap' | 'line' };
150
203
 
151
204
  const ToolbarSeparator = forwardRef<HTMLDivElement, ToolbarSeparatorProps>(
152
- ({ variant = 'line', ...props }, forwardedRef) => {
205
+ ({ variant = 'gap', ...props }, forwardedRef) => {
153
206
  return variant === 'line' ? (
154
207
  <ToolbarPrimitive.Separator asChild>
155
208
  <Separator {...props} ref={forwardedRef} />
@@ -160,8 +213,109 @@ const ToolbarSeparator = forwardRef<HTMLDivElement, ToolbarSeparatorProps>(
160
213
  },
161
214
  );
162
215
 
216
+ //
217
+ // DragHandle
218
+ //
219
+
220
+ type ToolbarDragHandleProps = { testId?: string; label?: string };
221
+
222
+ const ToolbarDragHandle = forwardRef<HTMLButtonElement, ToolbarDragHandleProps>(
223
+ ({ testId = 'drag-handle', label }, forwardedRef) => {
224
+ const { t } = useTranslation(translationKey);
225
+ return (
226
+ <ToolbarIconButton
227
+ data-testid={testId}
228
+ noTooltip
229
+ iconOnly
230
+ icon='ph--dots-six-vertical--regular'
231
+ variant='ghost'
232
+ label={label ?? t('toolbar drag handle label')}
233
+ classNames='cursor-pointer'
234
+ size={5}
235
+ disabled={!forwardedRef}
236
+ ref={forwardedRef}
237
+ />
238
+ );
239
+ },
240
+ );
241
+
242
+ //
243
+ // CloseIconButton
244
+ //
245
+
246
+ type ToolbarCloseIconButtonProps = { onClick?: () => void; label?: string };
247
+
248
+ const ToolbarCloseIconButton = forwardRef<HTMLButtonElement, ToolbarCloseIconButtonProps>(
249
+ ({ onClick, label }, forwardedRef) => {
250
+ const { t } = useTranslation(translationKey);
251
+ return (
252
+ <ToolbarIconButton
253
+ iconOnly
254
+ icon='ph--x--regular'
255
+ variant='ghost'
256
+ label={label ?? t('toolbar close label')}
257
+ classNames='cursor-pointer'
258
+ size={5}
259
+ onClick={onClick}
260
+ ref={forwardedRef}
261
+ />
262
+ );
263
+ },
264
+ );
265
+
266
+ //
267
+ // Menu
268
+ //
269
+
270
+ type ToolbarMenuItem<T extends any | void = void> = {
271
+ label: string;
272
+ onClick: (context: T) => void;
273
+ };
274
+
275
+ type ToolbarMenuProps<T extends any | void = void> = {
276
+ context?: T;
277
+ items?: ToolbarMenuItem<T>[];
278
+ };
279
+
280
+ // TODO(burdon): Make slottable.
281
+ const ToolbarMenu = <T extends any | void = void>({ context, items }: ToolbarMenuProps<T>) => {
282
+ const { t } = useTranslation(translationKey);
283
+
284
+ return (
285
+ <DropdownMenu.Root>
286
+ <DropdownMenu.Trigger disabled={!items?.length} asChild>
287
+ <ToolbarIconButton
288
+ iconOnly
289
+ variant='ghost'
290
+ icon='ph--dots-three-vertical--regular'
291
+ label={t('toolbar menu label')}
292
+ />
293
+ </DropdownMenu.Trigger>
294
+ {(items?.length ?? 0) > 0 && (
295
+ <DropdownMenu.Portal>
296
+ <DropdownMenu.Content>
297
+ <DropdownMenu.Viewport>
298
+ {items?.map(({ label, onClick: onSelect }, index) => (
299
+ <DropdownMenu.Item key={index} onSelect={() => onSelect(context as T)}>
300
+ {label}
301
+ </DropdownMenu.Item>
302
+ ))}
303
+ </DropdownMenu.Viewport>
304
+ <DropdownMenu.Arrow />
305
+ </DropdownMenu.Content>
306
+ </DropdownMenu.Portal>
307
+ )}
308
+ </DropdownMenu.Root>
309
+ );
310
+ };
311
+
312
+ //
313
+ // Toolbar
314
+ //
315
+
163
316
  export const Toolbar = {
164
317
  Root: ToolbarRoot,
318
+ Text: ToolbarText,
165
319
  Button: ToolbarButton,
166
320
  IconButton: ToolbarIconButton,
167
321
  Link: ToolbarLink,
@@ -170,10 +324,14 @@ export const Toolbar = {
170
324
  ToggleGroupItem: ToolbarToggleGroupItem,
171
325
  ToggleGroupIconItem: ToolbarToggleGroupIconItem,
172
326
  Separator: ToolbarSeparator,
327
+ DragHandle: ToolbarDragHandle,
328
+ CloseIconButton: ToolbarCloseIconButton,
329
+ Menu: ToolbarMenu,
173
330
  };
174
331
 
175
332
  export type {
176
333
  ToolbarRootProps,
334
+ ToolbarTextProps,
177
335
  ToolbarButtonProps,
178
336
  ToolbarIconButtonProps,
179
337
  ToolbarLinkProps,
@@ -182,4 +340,8 @@ export type {
182
340
  ToolbarToggleGroupItemProps,
183
341
  ToolbarToggleGroupIconItemProps,
184
342
  ToolbarSeparatorProps,
343
+ ToolbarDragHandleProps,
344
+ ToolbarCloseIconButtonProps,
345
+ ToolbarMenuItem,
346
+ ToolbarMenuProps,
185
347
  };
@@ -17,23 +17,25 @@ type StoryProps = {
17
17
  defaultOpen?: boolean;
18
18
  };
19
19
 
20
- const DefaultStory = ({ tooltips, defaultOpen }: StoryProps) => (
21
- <Tooltip.Provider defaultOpen={defaultOpen}>
22
- <div role='none' className='is-32'>
23
- {tooltips.map(({ label, content }, i) => (
24
- <Tooltip.Trigger asChild key={i} content={content} side='right'>
25
- <Button classNames='block is-full'>{label}</Button>
26
- </Tooltip.Trigger>
27
- ))}
28
- </div>
29
- </Tooltip.Provider>
30
- );
20
+ const DefaultStory = ({ tooltips, defaultOpen }: StoryProps) => {
21
+ return (
22
+ <Tooltip.Provider defaultOpen={defaultOpen}>
23
+ <div role='none' className='w-32'>
24
+ {tooltips.map(({ label, content }, i) => (
25
+ <Tooltip.Trigger asChild key={i} content={content} side='right'>
26
+ <Button classNames='block w-full'>{label}</Button>
27
+ </Tooltip.Trigger>
28
+ ))}
29
+ </div>
30
+ </Tooltip.Provider>
31
+ );
32
+ };
31
33
 
32
34
  const meta = {
33
- title: 'ui/react-ui-core/Tooltip',
35
+ title: 'ui/react-ui-core/components/Tooltip',
34
36
  component: Tooltip as any,
35
37
  render: DefaultStory,
36
- decorators: [withTheme],
38
+ decorators: [withTheme()],
37
39
  } satisfies Meta<typeof DefaultStory>;
38
40
 
39
41
  export default meta;
@@ -3,6 +3,7 @@
3
3
  //
4
4
 
5
5
  // This is based upon `@radix-ui/react-tooltip` fetched 17 March 2025 at https://github.com/radix-ui/primitives at commit 6e75e11.
6
+ // TODO(burdon): Replace with https://ui.shadcn.com/docs/components/radix/tooltip
6
7
 
7
8
  import { composeEventHandlers } from '@radix-ui/primitive';
8
9
  import { useComposedRefs } from '@radix-ui/react-compose-refs';
@@ -215,9 +216,9 @@ const TooltipProvider: FC<TooltipProviderProps> = (props: TooltipScopedProps<Too
215
216
  isPointerInTransitRef.current = inTransit;
216
217
  }, [])}
217
218
  >
218
- <TooltipContent side={side} className={tx('tooltip.content', 'tooltip', { elevation })}>
219
+ <TooltipContent side={side} className={tx('tooltip.content', { elevation })}>
219
220
  {content}
220
- <TooltipArrow className={tx('tooltip.arrow', 'tooltip__arrow')} />
221
+ <TooltipArrow className={tx('tooltip.arrow')} />
221
222
  </TooltipContent>
222
223
  <TooltipVirtualTrigger virtualRef={triggerRef as RefObject<HTMLButtonElement>} />
223
224
  {children}
@@ -2,13 +2,19 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- export * from './AnchoredOverflow';
5
+ export * from './DensityProvider';
6
+ export * from './ElevationProvider';
7
+ export * from './ThemeProvider';
8
+
6
9
  export * from './Avatars';
7
10
  export * from './Breadcrumb';
8
11
  export * from './Button';
12
+ export * from './Card';
9
13
  export * from './Clipboard';
10
14
  export * from './Dialog';
15
+ export * from './ErrorFallback';
11
16
  export * from './Icon';
17
+ export * from './Image';
12
18
  export * from './Input';
13
19
  export * from './Link';
14
20
  export * from './List';
@@ -21,11 +27,9 @@ export * from './ScrollArea';
21
27
  export * from './ScrollContainer';
22
28
  export * from './Select';
23
29
  export * from './Separator';
30
+ export * from './Skeleton';
31
+ export * from './Splitter';
24
32
  export * from './Tag';
25
33
  export * from './Toast';
26
34
  export * from './Toolbar';
27
35
  export * from './Tooltip';
28
-
29
- export * from './DensityProvider';
30
- export * from './ElevationProvider';
31
- export * from './ThemeProvider';
@@ -0,0 +1,49 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { type ReactElement, type Ref, forwardRef } from 'react';
7
+
8
+ import { type SlottableProps } from '@dxos/ui-types';
9
+
10
+ import { withTheme } from '../testing';
11
+
12
+ const ComponentInner = forwardRef<HTMLDivElement, ComponentProps>(({ children, ...props }, forwardedRef) => {
13
+ return (
14
+ <div {...props} ref={forwardedRef}>
15
+ {children}
16
+ </div>
17
+ );
18
+ });
19
+
20
+ ComponentInner.displayName = 'Component';
21
+
22
+ /**
23
+ * Generic component pattern.
24
+ */
25
+ type ComponentProps<P extends HTMLElement = any> = SlottableProps<P>;
26
+
27
+ const Component = ComponentInner as <P extends HTMLElement>(
28
+ props: SlottableProps<P> & { ref?: Ref<P> },
29
+ ) => ReactElement;
30
+
31
+ const meta = {
32
+ title: 'ui/react-ui-core/exemplars/generics',
33
+ component: Component,
34
+ render: (props) => <Component<HTMLDivElement> {...props} />,
35
+ decorators: [withTheme()],
36
+ parameters: {
37
+ layout: 'centered',
38
+ },
39
+ } satisfies Meta;
40
+
41
+ export default meta;
42
+
43
+ type Story = StoryObj<typeof meta>;
44
+
45
+ export const Default: Story = {
46
+ args: {
47
+ children: 'Hello',
48
+ },
49
+ };
@@ -0,0 +1,107 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Primitive } from '@radix-ui/react-primitive';
6
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
7
+ import React, { HTMLAttributes, type PropsWithChildren, forwardRef } from 'react';
8
+
9
+ import { composableProps } from '@dxos/ui-theme';
10
+ import { type ComposableProps, type SlottableProps, type ThemedClassName } from '@dxos/ui-types';
11
+
12
+ import { withTheme } from '../testing';
13
+ import { Slot } from '@radix-ui/react-slot';
14
+
15
+ /**
16
+ * Composition
17
+ *
18
+ * All Radix primitive parts that render a DOM element accept an asChild prop.
19
+ * When asChild is set to true, Radix will not render a default DOM element, instead cloning the part's child and passing it the props and behavior required to make it functional.
20
+ * https://www.radix-ui.com/primitives/docs/guides/composition
21
+ */
22
+
23
+ const Outer = forwardRef<HTMLDivElement, SlottableProps<HTMLDivElement>>(
24
+ ({ children, asChild, ...props }, forwardedRef) => {
25
+ const Comp = asChild ? Slot : Primitive.div;
26
+ return (
27
+ <Comp {...composableProps<HTMLDivElement>(props, { role: 'none' })} ref={forwardedRef}>
28
+ {children}
29
+ </Comp>
30
+ );
31
+ },
32
+ );
33
+
34
+ const Middle = forwardRef<HTMLDivElement, SlottableProps<HTMLDivElement>>(
35
+ ({ children, asChild, ...props }, forwardedRef) => {
36
+ const Comp = asChild ? Slot : Primitive.div;
37
+ return (
38
+ <Comp {...composableProps<HTMLDivElement>(props, { role: 'none' })} ref={forwardedRef}>
39
+ {children}
40
+ </Comp>
41
+ );
42
+ },
43
+ );
44
+
45
+ const Leaf = forwardRef<HTMLButtonElement, ComposableProps<HTMLButtonElement>>(
46
+ ({ children, ...props }, forwardedRef) => {
47
+ return (
48
+ <button {...composableProps<HTMLButtonElement>(props, { role: 'none' })} ref={forwardedRef}>
49
+ {children}
50
+ </button>
51
+ );
52
+ },
53
+ );
54
+
55
+ const TestSingle = (props: ThemedClassName<{ role?: string }>) => {
56
+ return (
57
+ <Outer asChild {...composableProps<HTMLDivElement>(props, { role: 'none' })}>
58
+ <Leaf>Single asChild (non-compliant — see console)</Leaf>
59
+ </Outer>
60
+ );
61
+ };
62
+
63
+ const TestNested = (props: ThemedClassName<{ role?: string }>) => {
64
+ return (
65
+ <Outer asChild {...composableProps<HTMLDivElement>(props, { role: 'none' })}>
66
+ <Middle asChild>
67
+ <Leaf>Nested asChild</Leaf>
68
+ </Middle>
69
+ </Outer>
70
+ );
71
+ };
72
+
73
+ const TestInner = (props: ThemedClassName<{ role?: string }>) => {
74
+ return (
75
+ <Outer asChild {...composableProps<HTMLDivElement>(props, { role: 'none' })}>
76
+ <Middle asChild>
77
+ <Leaf>
78
+ <div role='none'>Leaf</div>
79
+ </Leaf>
80
+ </Middle>
81
+ </Outer>
82
+ );
83
+ };
84
+
85
+ const meta = {
86
+ title: 'ui/react-ui-core/exemplars/slot',
87
+ decorators: [withTheme()],
88
+ parameters: {
89
+ layout: 'centered',
90
+ },
91
+ } satisfies Meta;
92
+
93
+ export default meta;
94
+
95
+ type Story = StoryObj<typeof meta>;
96
+
97
+ export const Single: Story = {
98
+ render: () => <TestSingle role='listitem' classNames='border-red-500' />,
99
+ };
100
+
101
+ export const Nested: Story = {
102
+ render: () => <TestNested role='listitem' classNames='border-green-500' />,
103
+ };
104
+
105
+ export const Inner: Story = {
106
+ render: () => <TestInner role='listitem' classNames='border-blue-500' />,
107
+ };
@@ -0,0 +1,127 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import {
6
+ useArrowNavigationGroup,
7
+ useFocusFinders,
8
+ useFocusableGroup,
9
+ useMergedTabsterAttributes_unstable,
10
+ } from '@fluentui/react-tabster';
11
+ import { type Decorator, type Meta, type StoryObj } from '@storybook/react-vite';
12
+ import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
13
+ import { createTabster, disposeTabster } from 'tabster';
14
+
15
+ import { Input, ScrollArea } from '@dxos/react-ui';
16
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
17
+ import { mx } from '@dxos/ui-theme';
18
+
19
+ // TODO(burdon): Factor out styles (incl. tabster debugging).
20
+ // TODO(burdon): Implement horizontal movement between columns when column is selected.
21
+ // TODO(burdon): Prevent tab out of app.
22
+
23
+ const border =
24
+ 'rounded-xs outline-hidden border border-subdued-separator focus:border-primary-500 focus-within:border-rose-500';
25
+
26
+ const Board = forwardRef<HTMLDivElement, { columns: string[][] }>(({ columns }, ref) => {
27
+ const arrowNavigationAttrs = useArrowNavigationGroup({ axis: 'horizontal', memorizeCurrent: true, tabbable: true });
28
+
29
+ return (
30
+ <div ref={ref} tabIndex={0} {...arrowNavigationAttrs} className='flex h-full w-full overflow-hidden'>
31
+ <div className={mx('flex h-full overflow-x-auto p-4 gap-4')}>
32
+ {columns.map((column) => (
33
+ <Column key={column[0]} items={column} />
34
+ ))}
35
+ </div>
36
+ </div>
37
+ );
38
+ });
39
+
40
+ const Column = forwardRef<HTMLDivElement, { items: string[] }>(({ items }, ref) => {
41
+ const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
42
+ const arrowNavigationAttrs = useArrowNavigationGroup({ axis: 'vertical', memorizeCurrent: true });
43
+ const tabsterAttrs = useMergedTabsterAttributes_unstable(focusableGroupAttrs, arrowNavigationAttrs);
44
+
45
+ return (
46
+ <ScrollArea.Root tabIndex={0} orientation='vertical' classNames={mx('w-[25rem]', border)}>
47
+ <ScrollArea.Viewport {...tabsterAttrs} classNames='p-4 gap-4' ref={ref}>
48
+ {items.map((item) => (
49
+ <Item key={item} value={item} />
50
+ ))}
51
+ </ScrollArea.Viewport>
52
+ </ScrollArea.Root>
53
+ );
54
+ });
55
+
56
+ const Item = forwardRef<HTMLDivElement, { value: string }>(({ value }, ref) => {
57
+ const focusableGroupAttrs = useFocusableGroup();
58
+
59
+ return (
60
+ <div
61
+ ref={ref}
62
+ tabIndex={0}
63
+ {...focusableGroupAttrs}
64
+ className={mx('flex shrink-0 w-full gap-4 p-4 items-center', border)}
65
+ >
66
+ <Input.Root>
67
+ <Input.Checkbox />
68
+ </Input.Root>
69
+ <Input.Root>
70
+ <Input.TextInput defaultValue={value} />
71
+ </Input.Root>
72
+ </div>
73
+ );
74
+ });
75
+
76
+ const DefaultStory = () => {
77
+ const columns = useMemo(() => {
78
+ return [['A1', 'A2', 'A3'], ['B1'], ['C1', 'C2', 'C3', 'C4', 'C5', 'C6'], ['D1', 'D2']];
79
+ }, []);
80
+
81
+ const ref = useRef<HTMLDivElement>(null);
82
+ const { findFirstFocusable } = useFocusFinders();
83
+ useEffect(() => {
84
+ if (ref.current) {
85
+ findFirstFocusable(ref.current)?.focus();
86
+ }
87
+ }, []);
88
+
89
+ return <Board columns={columns} ref={ref} />;
90
+ };
91
+
92
+ // TODO(burdon): This doesn't seem to be necessary or recongized; memoization doesn't work.
93
+ const withTabster: Decorator = (Story) => {
94
+ useEffect(() => {
95
+ const tabster = createTabster(window, {
96
+ autoRoot: {},
97
+ // TODO(burdon): Not called.
98
+ // checkUncontrolledCompletely: (el) => {
99
+ // console.log(el);
100
+ // return true;
101
+ // },
102
+ });
103
+
104
+ return () => {
105
+ disposeTabster(tabster);
106
+ };
107
+ }, []);
108
+
109
+ return <Story />;
110
+ };
111
+
112
+ const meta: Meta<typeof DefaultStory> = {
113
+ title: 'ui/react-ui-core/exemplars/tabster',
114
+ component: DefaultStory,
115
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withTabster],
116
+ parameters: {
117
+ layout: 'fullscreen',
118
+ },
119
+ };
120
+
121
+ export default meta;
122
+
123
+ type Story = StoryObj<typeof meta>;
124
+
125
+ export const Default: Story = {
126
+ args: {},
127
+ };