@dxos/react-ui 0.8.4-main.40e3dcdf1b → 0.8.4-main.422d1c7879

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 (250) hide show
  1. package/dist/lib/browser/{chunk-2FKSMWNY.mjs → chunk-OCVRIJCH.mjs} +79 -5
  2. package/dist/lib/browser/chunk-OCVRIJCH.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +905 -700
  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 +30 -18
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node-esm/{chunk-ZNBLTSHI.mjs → chunk-QUD5P3RU.mjs} +79 -5
  9. package/dist/lib/node-esm/chunk-QUD5P3RU.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +905 -700
  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 +30 -18
  14. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  15. package/dist/types/src/components/Avatars/Avatar.d.ts +1 -1
  16. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  17. package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
  18. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
  19. package/dist/types/src/components/Breadcrumb/Breadcrumb.stories.d.ts.map +1 -1
  20. package/dist/types/src/components/Button/Button.d.ts +2 -2
  21. package/dist/types/src/components/Button/Button.d.ts.map +1 -1
  22. package/dist/types/src/components/Button/Button.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
  24. package/dist/types/src/components/Button/IconButton.stories.d.ts +3 -0
  25. package/dist/types/src/components/Button/IconButton.stories.d.ts.map +1 -1
  26. package/dist/types/src/components/Button/Toggle.d.ts +2 -2
  27. package/dist/types/src/components/Button/Toggle.d.ts.map +1 -1
  28. package/dist/types/src/components/Button/Toggle.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Button/ToggleGroup.d.ts +6 -6
  30. package/dist/types/src/components/Button/ToggleGroup.d.ts.map +1 -1
  31. package/dist/types/src/components/Button/ToggleGroup.stories.d.ts.map +1 -1
  32. package/dist/types/src/components/Card/Card.d.ts +69 -49
  33. package/dist/types/src/components/Card/Card.d.ts.map +1 -1
  34. package/dist/types/src/components/Card/Card.stories.d.ts +2 -2
  35. package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -1
  36. package/dist/types/src/components/Clipboard/CopyButton.d.ts.map +1 -1
  37. package/dist/types/src/components/Clipboard/index.d.ts +10 -1
  38. package/dist/types/src/components/Clipboard/index.d.ts.map +1 -1
  39. package/dist/types/src/components/Dialog/AlertDialog.d.ts +39 -28
  40. package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
  41. package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/Dialog/Dialog.d.ts +44 -27
  43. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  44. package/dist/types/src/components/Dialog/Dialog.stories.d.ts +3 -2
  45. package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
  46. package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts +14 -3
  48. package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -1
  49. package/dist/types/src/components/Focus/Focus.d.ts +36 -0
  50. package/dist/types/src/components/Focus/Focus.d.ts.map +1 -0
  51. package/dist/types/src/components/Focus/Focus.stories.d.ts +9 -0
  52. package/dist/types/src/components/Focus/Focus.stories.d.ts.map +1 -0
  53. package/dist/types/src/components/Focus/index.d.ts +2 -0
  54. package/dist/types/src/components/Focus/index.d.ts.map +1 -0
  55. package/dist/types/src/components/Icon/Icon.d.ts +3 -0
  56. package/dist/types/src/components/Icon/Icon.d.ts.map +1 -1
  57. package/dist/types/src/components/Icon/Icon.stories.d.ts +11 -3
  58. package/dist/types/src/components/Icon/Icon.stories.d.ts.map +1 -1
  59. package/dist/types/src/components/Image/Image.d.ts +2 -1
  60. package/dist/types/src/components/Image/Image.d.ts.map +1 -1
  61. package/dist/types/src/components/Image/Image.stories.d.ts +2 -1
  62. package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -1
  63. package/dist/types/src/components/Input/Input.d.ts +2 -2
  64. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  65. package/dist/types/src/components/Input/Input.stories.d.ts +3 -3
  66. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  67. package/dist/types/src/components/Link/Link.stories.d.ts.map +1 -1
  68. package/dist/types/src/components/List/List.d.ts +5 -3
  69. package/dist/types/src/components/List/List.d.ts.map +1 -1
  70. package/dist/types/src/components/List/List.stories.d.ts +3 -1
  71. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  72. package/dist/types/src/components/List/Tree.d.ts.map +1 -1
  73. package/dist/types/src/components/List/Tree.stories.d.ts.map +1 -1
  74. package/dist/types/src/components/List/Treegrid.d.ts +5 -9
  75. package/dist/types/src/components/List/Treegrid.d.ts.map +1 -1
  76. package/dist/types/src/components/List/Treegrid.stories.d.ts.map +1 -1
  77. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  78. package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
  79. package/dist/types/src/components/Menu/ContextMenu.stories.d.ts.map +1 -1
  80. package/dist/types/src/components/Menu/DropdownMenu.d.ts +51 -50
  81. package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -1
  82. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts +14 -1
  83. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -1
  84. package/dist/types/src/components/Message/Message.d.ts.map +1 -1
  85. package/dist/types/src/components/Message/Message.stories.d.ts +2 -2
  86. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  87. package/dist/types/src/components/Popover/Popover.d.ts +31 -23
  88. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  89. package/dist/types/src/components/Popover/Popover.stories.d.ts.map +1 -1
  90. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +12 -9
  91. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  92. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +18 -5
  93. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  94. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +34 -13
  95. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
  96. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +5 -6
  97. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
  98. package/dist/types/src/components/Select/Select.stories.d.ts +2 -2
  99. package/dist/types/src/components/Select/Select.stories.d.ts.map +1 -1
  100. package/dist/types/src/components/Separator/Separator.d.ts +3 -3
  101. package/dist/types/src/components/Separator/Separator.d.ts.map +1 -1
  102. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -1
  103. package/dist/types/src/components/Splitter/Splitter.d.ts +19 -17
  104. package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -1
  105. package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -1
  106. package/dist/types/src/components/Status/Status.d.ts +3 -4
  107. package/dist/types/src/components/Status/Status.d.ts.map +1 -1
  108. package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
  109. package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
  110. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +1 -1
  111. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  112. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts +1 -1
  113. package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -1
  114. package/dist/types/src/components/Toast/Toast.d.ts +15 -15
  115. package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
  116. package/dist/types/src/components/Toast/Toast.stories.d.ts.map +1 -1
  117. package/dist/types/src/components/Toolbar/Toolbar.d.ts +8 -16
  118. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  119. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  120. package/dist/types/src/components/Tooltip/Tooltip.d.ts +9 -9
  121. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  122. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +2 -2
  123. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  124. package/dist/types/src/components/index.d.ts +1 -0
  125. package/dist/types/src/components/index.d.ts.map +1 -1
  126. package/dist/types/src/exemplars/generics.stories.d.ts +6 -5
  127. package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -1
  128. package/dist/types/src/exemplars/slot.stories.d.ts +1 -0
  129. package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -1
  130. package/dist/types/src/hooks/index.d.ts +1 -0
  131. package/dist/types/src/hooks/index.d.ts.map +1 -1
  132. package/dist/types/src/hooks/useDensityContext.d.ts +1 -1
  133. package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
  134. package/dist/types/src/playground/Custom.stories.d.ts.map +1 -1
  135. package/dist/types/src/primitives/Column/Column.d.ts +21 -14
  136. package/dist/types/src/primitives/Column/Column.d.ts.map +1 -1
  137. package/dist/types/src/primitives/Column/Column.stories.d.ts +19 -0
  138. package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -1
  139. package/dist/types/src/primitives/Container/Container.d.ts +4 -5
  140. package/dist/types/src/primitives/Container/Container.d.ts.map +1 -1
  141. package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -1
  142. package/dist/types/src/primitives/Flex/Flex.d.ts +5 -7
  143. package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -1
  144. package/dist/types/src/primitives/Flex/Flex.stories.d.ts.map +1 -1
  145. package/dist/types/src/primitives/Grid/Grid.d.ts +3 -8
  146. package/dist/types/src/primitives/Grid/Grid.d.ts.map +1 -1
  147. package/dist/types/src/primitives/Grid/Grid.stories.d.ts.map +1 -1
  148. package/dist/types/src/primitives/Panel/Panel.d.ts +24 -15
  149. package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -1
  150. package/dist/types/src/primitives/Panel/Panel.stories.d.ts.map +1 -1
  151. package/dist/types/src/testing/Loading.d.ts.map +1 -1
  152. package/dist/types/src/testing/decorators/withTheme.d.ts +1 -1
  153. package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
  154. package/dist/types/src/translations.d.ts +3 -3
  155. package/dist/types/src/util/usePx.d.ts.map +1 -1
  156. package/dist/types/tsconfig.tsbuildinfo +1 -1
  157. package/package.json +18 -24
  158. package/src/components/Avatars/Avatar.stories.tsx +2 -3
  159. package/src/components/Avatars/Avatar.tsx +1 -2
  160. package/src/components/Avatars/AvatarGroup.stories.tsx +0 -1
  161. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +1 -2
  162. package/src/components/Button/Button.stories.tsx +0 -1
  163. package/src/components/Button/Button.tsx +5 -13
  164. package/src/components/Button/IconButton.stories.tsx +6 -4
  165. package/src/components/Button/IconButton.tsx +1 -3
  166. package/src/components/Button/Toggle.stories.tsx +0 -1
  167. package/src/components/Button/Toggle.tsx +4 -4
  168. package/src/components/Button/ToggleGroup.stories.tsx +0 -1
  169. package/src/components/Button/ToggleGroup.tsx +12 -16
  170. package/src/components/Card/Card.stories.tsx +12 -12
  171. package/src/components/Card/Card.tsx +266 -108
  172. package/src/components/Clipboard/CopyButton.tsx +3 -4
  173. package/src/components/Dialog/AlertDialog.stories.tsx +5 -6
  174. package/src/components/Dialog/AlertDialog.tsx +67 -126
  175. package/src/components/Dialog/Dialog.stories.tsx +64 -9
  176. package/src/components/Dialog/Dialog.tsx +84 -88
  177. package/src/components/ErrorFallback/ErrorFallback.stories.tsx +3 -8
  178. package/src/components/ErrorFallback/ErrorStack.tsx +36 -2
  179. package/src/components/Focus/AUDIT.md +43 -0
  180. package/src/components/Focus/Focus.stories.tsx +230 -0
  181. package/src/components/Focus/Focus.tsx +201 -0
  182. package/src/components/Focus/index.ts +5 -0
  183. package/src/components/Icon/Icon.stories.tsx +43 -13
  184. package/src/components/Icon/Icon.tsx +5 -1
  185. package/src/components/Image/Image.stories.tsx +3 -3
  186. package/src/components/Image/Image.tsx +16 -3
  187. package/src/components/Input/Input.stories.tsx +3 -4
  188. package/src/components/Input/Input.tsx +7 -7
  189. package/src/components/Link/Link.stories.tsx +0 -1
  190. package/src/components/List/List.stories.tsx +0 -1
  191. package/src/components/List/List.tsx +6 -5
  192. package/src/components/List/Tree.stories.tsx +1 -2
  193. package/src/components/List/Tree.tsx +0 -1
  194. package/src/components/List/Treegrid.stories.tsx +26 -27
  195. package/src/components/List/Treegrid.tsx +14 -14
  196. package/src/components/Main/Main.stories.tsx +0 -1
  197. package/src/components/Main/Main.tsx +1 -2
  198. package/src/components/Menu/ContextMenu.stories.tsx +0 -1
  199. package/src/components/Menu/DropdownMenu.stories.tsx +0 -1
  200. package/src/components/Menu/DropdownMenu.tsx +48 -42
  201. package/src/components/Message/Message.stories.tsx +6 -7
  202. package/src/components/Message/Message.tsx +1 -5
  203. package/src/components/Popover/Popover.stories.tsx +4 -5
  204. package/src/components/Popover/Popover.tsx +42 -42
  205. package/src/components/ScrollArea/ScrollArea.stories.tsx +93 -30
  206. package/src/components/ScrollArea/ScrollArea.tsx +39 -23
  207. package/src/components/ScrollContainer/ScrollContainer.stories.tsx +20 -18
  208. package/src/components/ScrollContainer/ScrollContainer.tsx +200 -91
  209. package/src/components/Select/Select.stories.tsx +5 -6
  210. package/src/components/Separator/Separator.tsx +4 -7
  211. package/src/components/Skeleton/Skeleton.stories.tsx +0 -1
  212. package/src/components/Splitter/Splitter.stories.tsx +29 -29
  213. package/src/components/Splitter/Splitter.tsx +35 -34
  214. package/src/components/Status/Status.stories.tsx +0 -1
  215. package/src/components/Status/Status.tsx +8 -5
  216. package/src/components/Tag/Tag.stories.tsx +0 -1
  217. package/src/components/ThemeProvider/ThemeProvider.stories.tsx +0 -1
  218. package/src/components/ThemeProvider/ThemeProvider.tsx +5 -4
  219. package/src/components/Toast/Toast.stories.tsx +0 -1
  220. package/src/components/Toast/Toast.tsx +16 -31
  221. package/src/components/Toolbar/Toolbar.stories.tsx +0 -1
  222. package/src/components/Toolbar/Toolbar.tsx +19 -34
  223. package/src/components/Tooltip/Tooltip.stories.tsx +6 -7
  224. package/src/components/Tooltip/Tooltip.tsx +15 -16
  225. package/src/components/index.ts +1 -0
  226. package/src/exemplars/generics.stories.tsx +7 -15
  227. package/src/exemplars/slot.stories.tsx +67 -57
  228. package/src/exemplars/tabster.stories.tsx +1 -1
  229. package/src/exemplars/virtualizer.stories.tsx +4 -4
  230. package/src/hooks/index.ts +1 -0
  231. package/src/hooks/useDensityContext.ts +2 -2
  232. package/src/playground/Custom.stories.tsx +6 -9
  233. package/src/primitives/Column/AUDIT.md +148 -0
  234. package/src/primitives/Column/Column.stories.tsx +122 -19
  235. package/src/primitives/Column/Column.tsx +73 -42
  236. package/src/primitives/Container/Container.stories.tsx +0 -1
  237. package/src/primitives/Container/Container.tsx +5 -8
  238. package/src/primitives/Flex/Flex.stories.tsx +0 -1
  239. package/src/primitives/Flex/Flex.tsx +10 -12
  240. package/src/primitives/Grid/Grid.stories.tsx +0 -1
  241. package/src/primitives/Grid/Grid.tsx +4 -9
  242. package/src/primitives/Panel/Panel.stories.tsx +9 -8
  243. package/src/primitives/Panel/Panel.tsx +64 -63
  244. package/src/testing/Loading.tsx +25 -4
  245. package/src/testing/decorators/withLayout.tsx +6 -6
  246. package/src/testing/decorators/withTheme.tsx +10 -7
  247. package/src/translations.ts +3 -3
  248. package/src/util/usePx.ts +1 -0
  249. package/dist/lib/browser/chunk-2FKSMWNY.mjs.map +0 -7
  250. package/dist/lib/node-esm/chunk-ZNBLTSHI.mjs.map +0 -7
@@ -5,22 +5,21 @@
5
5
  import { createContextScope } from '@radix-ui/react-context';
6
6
  import { Primitive } from '@radix-ui/react-primitive';
7
7
  import { Slot } from '@radix-ui/react-slot';
8
- import React, { forwardRef } from 'react';
8
+ import React from 'react';
9
9
 
10
- import { composableProps } from '@dxos/ui-theme';
11
- import { type SlottableProps } from '@dxos/ui-types';
10
+ import { composableProps, slottable } from '@dxos/ui-theme';
12
11
 
13
12
  import { useThemeContext } from '../../hooks';
13
+ import { ThemedClassName } from '../../util';
14
14
 
15
15
  type ScopedProps<P> = P & { __scopeSplitter?: any };
16
16
 
17
- // TODO(burdon): Enable resize.
18
17
  // TODO(burdon): Generalize horizontal/vertical and change to start/end.
19
- type Mode = 'upper' | 'lower' | 'both';
18
+ type Mode = 'top' | 'bottom' | 'split';
20
19
 
21
20
  type SplitterContextValue = {
22
21
  mode: Mode;
23
- ratio: number;
22
+ ratio?: number;
24
23
  transition: number;
25
24
  };
26
25
 
@@ -36,16 +35,20 @@ const [SplitterProvider, useSplitterContext] = createSplitterContext<SplitterCon
36
35
 
37
36
  const ROOT_NAME = 'Splitter.Root';
38
37
 
39
- type RootProps = SlottableProps<HTMLDivElement, Partial<SplitterContextValue>>;
38
+ type RootOwnProps = Partial<SplitterContextValue>;
40
39
 
41
- const Root = forwardRef<HTMLDivElement, ScopedProps<RootProps>>(
42
- ({ __scopeSplitter, asChild, mode = 'upper', ratio = 0.5, transition = 250, children, ...props }, forwardedRef) => {
43
- const { className, ...rest } = composableProps(props);
44
- const Comp = asChild ? Slot : Primitive.div;
40
+ type RootProps = RootOwnProps;
41
+
42
+ const Root = slottable<HTMLDivElement, RootOwnProps>(
43
+ ({ asChild, mode = 'top', ratio = 0.5, transition = 250, children, ...props }, forwardedRef) => {
45
44
  const { tx } = useThemeContext();
45
+ const { __scopeSplitter, ...rest } = props as ScopedProps<typeof props>;
46
+ const { className, ...restProps } = composableProps(rest);
47
+ const Comp = asChild ? Slot : Primitive.div;
48
+
46
49
  return (
47
50
  <SplitterProvider scope={__scopeSplitter} mode={mode} ratio={ratio} transition={transition}>
48
- <Comp role='none' {...rest} ref={forwardedRef} className={tx('splitter.root', {}, className)}>
51
+ <Comp {...restProps} ref={forwardedRef} className={tx('splitter.root', {}, className)}>
49
52
  {children}
50
53
  </Comp>
51
54
  </SplitterProvider>
@@ -61,44 +64,42 @@ Root.displayName = ROOT_NAME;
61
64
 
62
65
  const PANEL_NAME = 'Splitter.Panel';
63
66
 
64
- type PanelProps = SlottableProps<
65
- HTMLDivElement,
66
- {
67
- position: 'upper' | 'lower';
68
- }
69
- >;
67
+ type PanelOwnProps = ThemedClassName<{
68
+ position: 'top' | 'bottom';
69
+ }>;
70
70
 
71
- const Panel = forwardRef<HTMLDivElement, ScopedProps<PanelProps>>(
72
- ({ __scopeSplitter, asChild, children, position, style, ...props }, forwardedRef) => {
73
- const { className, ...rest } = composableProps(props);
74
- const Comp = asChild ? Slot : Primitive.div;
75
- const { mode, ratio, transition } = useSplitterContext(PANEL_NAME, __scopeSplitter);
71
+ type PanelProps = PanelOwnProps;
72
+
73
+ const Panel = slottable<HTMLDivElement, PanelOwnProps>(
74
+ ({ classNames, asChild, children, position, style, ...props }, forwardedRef) => {
76
75
  const { tx } = useThemeContext();
76
+ const { __scopeSplitter, ...rest } = props as ScopedProps<typeof props>;
77
+ const Comp = asChild ? Slot : Primitive.div;
78
+ const { mode, ratio = 0.5, transition } = useSplitterContext(PANEL_NAME, __scopeSplitter);
79
+ const { className, ...restProps } = composableProps(rest);
77
80
 
78
81
  // Calculate position and height based on mode and ratio.
79
- const isUpper = position === 'upper';
80
- const top = isUpper ? '0%' : mode === 'upper' ? '100%' : mode === 'lower' ? '0%' : `${ratio * 100}%`;
81
-
82
- const height = isUpper
83
- ? mode === 'upper'
82
+ const isTopPanel = position === 'top';
83
+ const topOffset = isTopPanel ? '0%' : mode === 'top' ? '100%' : mode === 'bottom' ? '0%' : `${ratio * 100}%`;
84
+ const height = isTopPanel
85
+ ? mode === 'top'
84
86
  ? '100%'
85
- : mode === 'lower'
87
+ : mode === 'bottom'
86
88
  ? '0%'
87
89
  : `${ratio * 100}%`
88
- : mode === 'lower'
90
+ : mode === 'bottom'
89
91
  ? '100%'
90
- : mode === 'upper'
92
+ : mode === 'top'
91
93
  ? '0%'
92
94
  : `${(1 - ratio) * 100}%`;
93
95
 
94
96
  return (
95
97
  <Comp
96
- role='none'
97
- {...rest}
98
+ {...restProps}
98
99
  ref={forwardedRef}
99
100
  className={tx('splitter.panel', {}, className)}
100
101
  style={{
101
- top,
102
+ top: topOffset,
102
103
  height,
103
104
  transition: `top ${transition}ms, height ${transition}ms ease-out`,
104
105
  ...style,
@@ -6,7 +6,6 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
 
8
8
  import { withTheme } from '../../testing';
9
-
10
9
  import { Status } from './Status';
11
10
 
12
11
  const meta = {
@@ -4,14 +4,17 @@
4
4
 
5
5
  import React, { type ComponentPropsWithRef, forwardRef } from 'react';
6
6
 
7
+ import { type StatusStyleProps } from '@dxos/ui-theme';
8
+
7
9
  import { useThemeContext } from '../../hooks';
8
10
  import { type ThemedClassName } from '../../util';
9
11
 
10
- type StatusProps = ThemedClassName<ComponentPropsWithRef<'span'>> & {
11
- indeterminate?: boolean;
12
- variant?: 'default' | 'main-bottom';
13
- progress?: number;
14
- };
12
+ type StatusProps = ThemedClassName<
13
+ ComponentPropsWithRef<'span'> &
14
+ StatusStyleProps & {
15
+ progress?: number;
16
+ }
17
+ >;
15
18
 
16
19
  const Status = forwardRef<HTMLSpanElement, StatusProps>(
17
20
  ({ classNames, children, progress = 0, indeterminate, variant, ...props }, forwardedRef) => {
@@ -9,7 +9,6 @@ import { hues } from '@dxos/ui-theme';
9
9
  import { type ChromaticPalette, type MessageValence } from '@dxos/ui-types';
10
10
 
11
11
  import { withLayout, withTheme } from '../../testing';
12
-
13
12
  import { Tag } from './Tag';
14
13
 
15
14
  const palettes = ['neutral', 'success', 'info', 'warning', 'error', ...hues] as (ChromaticPalette | MessageValence)[];
@@ -7,7 +7,6 @@ import React from 'react';
7
7
 
8
8
  import { useThemeContext } from '../../hooks';
9
9
  import { withLayout, withTheme } from '../../testing';
10
-
11
10
  import { ThemeProvider } from './ThemeProvider';
12
11
 
13
12
  const meta = {
@@ -11,7 +11,6 @@ import { type SafeAreaPadding, useSafeArea } from '../../hooks';
11
11
  import { hasIosKeyboard } from '../../util';
12
12
  import { DensityProvider } from '../DensityProvider';
13
13
  import { ElevationProvider } from '../ElevationProvider';
14
-
15
14
  import { TranslationsProvider, type TranslationsProviderProps } from './TranslationsProvider';
16
15
 
17
16
  export type ThemeContextValue = {
@@ -43,7 +42,8 @@ export const ThemeProvider = ({
43
42
  tx = (_path, _styleProps, ..._options) => undefined,
44
43
  themeMode = 'dark',
45
44
  rootDensity = 'fine',
46
- ...rest
45
+ noCache,
46
+ platform,
47
47
  }: ThemeProviderProps) => {
48
48
  useEffect(() => {
49
49
  if (document.defaultView) {
@@ -54,9 +54,10 @@ export const ThemeProvider = ({
54
54
  }, []);
55
55
 
56
56
  const safeAreaPadding = useSafeArea();
57
+ // Destructure all props explicitly so useMemo deps are stable primitives, not a new `rest` object every render.
57
58
  const contextValue = useMemo(
58
- () => ({ tx, themeMode, hasIosKeyboard: hasIosKeyboard(), safeAreaPadding, ...rest }),
59
- [tx, themeMode, safeAreaPadding, rest],
59
+ () => ({ tx, themeMode, hasIosKeyboard: hasIosKeyboard(), safeAreaPadding, noCache, platform }),
60
+ [tx, themeMode, safeAreaPadding, noCache, platform],
60
61
  );
61
62
 
62
63
  return (
@@ -7,7 +7,6 @@ import React, { type ReactNode, useState } from 'react';
7
7
 
8
8
  import { withTheme } from '../../testing';
9
9
  import { Button } from '../Button';
10
-
11
10
  import { Toast } from './Toast';
12
11
 
13
12
  type ActionTriggerProps = { altText: string; trigger: ReactNode };
@@ -4,47 +4,32 @@
4
4
 
5
5
  import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
- import {
8
- ToastAction as ToastActionPrimitive,
9
- type ToastActionProps as ToastActionPrimitiveProps,
10
- ToastClose as ToastClosePrimitive,
11
- type ToastCloseProps as ToastClosePrimitiveProps,
12
- ToastDescription as ToastDescriptionPrimitive,
13
- type ToastDescriptionProps as ToastDescriptionPrimitiveProps,
14
- ToastProvider as ToastProviderPrimitive,
15
- type ToastProviderProps as ToastProviderPrimitiveProps,
16
- Root as ToastRootPrimitive,
17
- type ToastProps as ToastRootPrimitiveProps,
18
- ToastTitle as ToastTitlePrimitive,
19
- type ToastTitleProps as ToastTitlePrimitiveProps,
20
- ToastViewport as ToastViewportPrimitive,
21
- type ToastViewportProps as ToastViewportPrimitiveProps,
22
- } from '@radix-ui/react-toast';
7
+ import * as ToastPrimitive from '@radix-ui/react-toast';
23
8
  import React, { type ComponentPropsWithRef, type FunctionComponent, forwardRef } from 'react';
24
9
 
25
10
  import { useThemeContext } from '../../hooks';
26
11
  import { type ThemedClassName } from '../../util';
27
12
  import { ElevationProvider } from '../ElevationProvider';
28
13
 
29
- type ToastProviderProps = ToastProviderPrimitiveProps;
14
+ type ToastProviderProps = ToastPrimitive.ToastProviderProps;
30
15
 
31
- const ToastProvider: FunctionComponent<ToastProviderProps> = ToastProviderPrimitive;
16
+ const ToastProvider: FunctionComponent<ToastProviderProps> = ToastPrimitive.Provider;
32
17
 
33
- type ToastViewportProps = ThemedClassName<ToastViewportPrimitiveProps>;
18
+ type ToastViewportProps = ThemedClassName<ToastPrimitive.ToastViewportProps>;
34
19
 
35
20
  const ToastViewport = forwardRef<HTMLOListElement, ToastViewportProps>(({ classNames, ...props }, forwardedRef) => {
36
21
  const { tx } = useThemeContext();
37
- return <ToastViewportPrimitive className={tx('toast.viewport', {}, classNames)} ref={forwardedRef} />;
22
+ return <ToastPrimitive.Viewport {...props} className={tx('toast.viewport', {}, classNames)} ref={forwardedRef} />;
38
23
  });
39
24
 
40
- type ToastRootProps = ThemedClassName<ToastRootPrimitiveProps>;
25
+ type ToastRootProps = ThemedClassName<ToastPrimitive.ToastProps>;
41
26
 
42
27
  const ToastRoot = forwardRef<HTMLLIElement, ToastRootProps>(({ classNames, children, ...props }, forwardedRef) => {
43
28
  const { tx } = useThemeContext();
44
29
  return (
45
- <ToastRootPrimitive {...props} className={tx('toast.root', {}, classNames)} ref={forwardedRef}>
30
+ <ToastPrimitive.Root {...props} className={tx('toast.root', {}, classNames)} ref={forwardedRef}>
46
31
  <ElevationProvider elevation='toast'>{children}</ElevationProvider>
47
- </ToastRootPrimitive>
32
+ </ToastPrimitive.Root>
48
33
  );
49
34
  });
50
35
 
@@ -56,22 +41,22 @@ const ToastBody = forwardRef<HTMLDivElement, ToastBodyProps>(({ asChild, classNa
56
41
  return <Comp {...props} className={tx('toast.body', {}, classNames)} ref={forwardedRef} />;
57
42
  });
58
43
 
59
- type ToastTitleProps = ThemedClassName<ToastTitlePrimitiveProps>;
44
+ type ToastTitleProps = ThemedClassName<ToastPrimitive.ToastTitleProps>;
60
45
 
61
46
  const ToastTitle = forwardRef<HTMLHeadingElement, ToastTitleProps>(
62
47
  ({ asChild, classNames, ...props }, forwardedRef) => {
63
48
  const { tx } = useThemeContext();
64
- const Comp = asChild ? Slot : ToastTitlePrimitive;
49
+ const Comp = asChild ? Slot : ToastPrimitive.Title;
65
50
  return <Comp {...props} className={tx('toast.title', {}, classNames)} ref={forwardedRef} />;
66
51
  },
67
52
  );
68
53
 
69
- type ToastDescriptionProps = ThemedClassName<ToastDescriptionPrimitiveProps>;
54
+ type ToastDescriptionProps = ThemedClassName<ToastPrimitive.ToastDescriptionProps>;
70
55
 
71
56
  const ToastDescription = forwardRef<HTMLParagraphElement, ToastDescriptionProps>(
72
57
  ({ asChild, classNames, ...props }, forwardedRef) => {
73
58
  const { tx } = useThemeContext();
74
- const Comp = asChild ? Slot : ToastDescriptionPrimitive;
59
+ const Comp = asChild ? Slot : ToastPrimitive.Description;
75
60
  return <Comp {...props} className={tx('toast.description', {}, classNames)} ref={forwardedRef} />;
76
61
  },
77
62
  );
@@ -86,13 +71,13 @@ const ToastActions = forwardRef<HTMLDivElement, ToastActionsProps>(
86
71
  },
87
72
  );
88
73
 
89
- type ToastActionProps = ToastActionPrimitiveProps;
74
+ type ToastActionProps = ToastPrimitive.ToastActionProps;
90
75
 
91
- const ToastAction: FunctionComponent<ToastActionProps> = ToastActionPrimitive;
76
+ const ToastAction: FunctionComponent<ToastActionProps> = ToastPrimitive.Action;
92
77
 
93
- type ToastCloseProps = ToastClosePrimitiveProps;
78
+ type ToastCloseProps = ToastPrimitive.ToastCloseProps;
94
79
 
95
- const ToastClose: FunctionComponent<ToastCloseProps> = ToastClosePrimitive;
80
+ const ToastClose: FunctionComponent<ToastCloseProps> = ToastPrimitive.Close;
96
81
 
97
82
  export const Toast = {
98
83
  Provider: ToastProvider,
@@ -9,7 +9,6 @@ import { withTheme } from '../../testing';
9
9
  import { Toggle } from '../Button';
10
10
  import { Icon } from '../Icon';
11
11
  import { Select } from '../Select';
12
-
13
12
  import { Toolbar } from './Toolbar';
14
13
 
15
14
  type StorybookToolbarProps = {};
@@ -6,15 +6,14 @@ import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
7
  import type { ToggleGroupItemProps as ToggleGroupItemPrimitiveProps } from '@radix-ui/react-toggle-group';
8
8
  import * as ToolbarPrimitive from '@radix-ui/react-toolbar';
9
- import React, { Fragment, forwardRef } from 'react';
9
+ import React, { forwardRef } from 'react';
10
10
  import { useTranslation } from 'react-i18next';
11
11
 
12
- import { composableProps, type ToolbarStyleProps } from '@dxos/ui-theme';
12
+ import { composable, composableProps, slottable, type ToolbarStyleProps } from '@dxos/ui-theme';
13
13
  import { type SlottableProps } from '@dxos/ui-types';
14
14
 
15
15
  import { useThemeContext } from '../../hooks';
16
16
  import { translationKey } from '../../translations';
17
- import { type ThemedClassName } from '../../util';
18
17
  import {
19
18
  Button,
20
19
  ButtonGroup,
@@ -34,38 +33,24 @@ import { Separator, type SeparatorProps } from '../Separator';
34
33
  // Root
35
34
  //
36
35
 
37
- type ToolbarRootProps = ThemedClassName<
38
- ToolbarPrimitive.ToolbarProps &
39
- ToolbarStyleProps & {
40
- textBlockWidth?: boolean;
41
- }
42
- >;
43
-
44
- // TODO(burdon): Implement asChild property.
45
- const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
46
- (
47
- { children, density, disabled, layoutManaged, textBlockWidth: textBlockWidthProp, orientation, ...props },
48
- forwardedRef,
49
- ) => {
50
- const { className, dir: _, ...rest } = composableProps(props);
36
+ type ToolbarRootProps = ToolbarPrimitive.ToolbarProps & ToolbarStyleProps;
37
+
38
+ const ToolbarRoot = composable<HTMLDivElement, ToolbarRootProps>(
39
+ ({ children, density, disabled, layoutManaged, orientation, ...props }, forwardedRef) => {
40
+ const { className, role, ...rest } = composableProps(props);
51
41
  const { tx } = useThemeContext();
52
- const InnerRoot = textBlockWidthProp ? 'div' : Fragment;
53
- const innerRootProps = textBlockWidthProp
54
- ? {
55
- role: 'none',
56
- className: tx('toolbar.inner', { layoutManaged }, className),
57
- }
58
- : {};
59
42
 
60
43
  return (
61
44
  <ToolbarPrimitive.Root
62
45
  {...rest}
46
+ // Only pass role when explicitly set; radix provides role="toolbar" by default.
47
+ {...(role !== 'none' && { role })}
63
48
  orientation={orientation}
64
49
  data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}
65
50
  className={tx('toolbar.root', { density, disabled, layoutManaged }, className)}
66
51
  ref={forwardedRef}
67
52
  >
68
- <InnerRoot {...innerRootProps}>{children}</InnerRoot>
53
+ {children}
69
54
  </ToolbarPrimitive.Root>
70
55
  );
71
56
  },
@@ -75,9 +60,9 @@ const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
75
60
  // Text
76
61
  //
77
62
 
78
- type ToolbarTextProps = SlottableProps<HTMLDivElement>;
63
+ type ToolbarTextProps = SlottableProps;
79
64
 
80
- const ToolbarText = forwardRef<HTMLDivElement, ToolbarTextProps>(({ children, asChild, ...props }, forwardedRef) => {
65
+ const ToolbarText = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {
81
66
  const { className, ...rest } = composableProps(props);
82
67
  const Comp = asChild ? Slot : Primitive.div;
83
68
  const { tx } = useThemeContext();
@@ -205,7 +190,7 @@ const ToolbarSeparator = forwardRef<HTMLDivElement, ToolbarSeparatorProps>(
205
190
  ({ variant = 'gap', ...props }, forwardedRef) => {
206
191
  return variant === 'line' ? (
207
192
  <ToolbarPrimitive.Separator asChild>
208
- <Separator {...props} ref={forwardedRef} />
193
+ <Separator orientation='vertical' {...props} ref={forwardedRef} />
209
194
  </ToolbarPrimitive.Separator>
210
195
  ) : (
211
196
  <ToolbarPrimitive.Separator className='grow' ref={forwardedRef} />
@@ -225,13 +210,13 @@ const ToolbarDragHandle = forwardRef<HTMLButtonElement, ToolbarDragHandleProps>(
225
210
  return (
226
211
  <ToolbarIconButton
227
212
  data-testid={testId}
213
+ tabIndex={-1}
228
214
  noTooltip
229
215
  iconOnly
230
216
  icon='ph--dots-six-vertical--regular'
231
217
  variant='ghost'
232
- label={label ?? t('toolbar drag handle label')}
233
- classNames='cursor-pointer'
234
- size={5}
218
+ label={label ?? t('toolbar-drag-handle.label')}
219
+ classNames='dx-focus-ring-none cursor-pointer'
235
220
  disabled={!forwardedRef}
236
221
  ref={forwardedRef}
237
222
  />
@@ -248,14 +233,14 @@ type ToolbarCloseIconButtonProps = { onClick?: () => void; label?: string };
248
233
  const ToolbarCloseIconButton = forwardRef<HTMLButtonElement, ToolbarCloseIconButtonProps>(
249
234
  ({ onClick, label }, forwardedRef) => {
250
235
  const { t } = useTranslation(translationKey);
236
+
251
237
  return (
252
238
  <ToolbarIconButton
253
239
  iconOnly
254
240
  icon='ph--x--regular'
255
241
  variant='ghost'
256
- label={label ?? t('toolbar close label')}
242
+ label={label ?? t('toolbar-close.label')}
257
243
  classNames='cursor-pointer'
258
- size={5}
259
244
  onClick={onClick}
260
245
  ref={forwardedRef}
261
246
  />
@@ -288,7 +273,7 @@ const ToolbarMenu = <T extends any | void = void>({ context, items }: ToolbarMen
288
273
  iconOnly
289
274
  variant='ghost'
290
275
  icon='ph--dots-three-vertical--regular'
291
- label={t('toolbar menu label')}
276
+ label={t('toolbar-menu.label')}
292
277
  />
293
278
  </DropdownMenu.Trigger>
294
279
  {(items?.length ?? 0) > 0 && (
@@ -5,19 +5,18 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
 
8
- import { faker } from '@dxos/random';
8
+ import { random } from '@dxos/random';
9
9
 
10
10
  import { withTheme } from '../../testing';
11
11
  import { Button } from '../Button';
12
-
13
12
  import { Tooltip } from './Tooltip';
14
13
 
15
- type StoryProps = {
14
+ type DefaultStoryProps = {
16
15
  tooltips: { label: string; content: string }[];
17
16
  defaultOpen?: boolean;
18
17
  };
19
18
 
20
- const DefaultStory = ({ tooltips, defaultOpen }: StoryProps) => {
19
+ const DefaultStory = ({ tooltips, defaultOpen }: DefaultStoryProps) => {
21
20
  return (
22
21
  <Tooltip.Provider defaultOpen={defaultOpen}>
23
22
  <div role='none' className='w-32'>
@@ -74,10 +73,10 @@ export const DefaultOpen: Story = {
74
73
  export const StressTest: Story = {
75
74
  args: {
76
75
  defaultOpen: true,
77
- tooltips: faker.helpers.multiple(
76
+ tooltips: random.helpers.multiple(
78
77
  () => ({
79
- label: faker.lorem.words(2),
80
- content: faker.lorem.words(5),
78
+ label: random.lorem.words(2),
79
+ content: random.lorem.words(5),
81
80
  }),
82
81
  { count: 32 },
83
82
  ),
@@ -22,9 +22,8 @@ import { useControllableState } from '@radix-ui/react-use-controllable-state';
22
22
  import * as VisuallyHiddenPrimitive from '@radix-ui/react-visually-hidden';
23
23
  import React, {
24
24
  type ComponentPropsWithoutRef,
25
- type ElementRef,
25
+ type ComponentRef,
26
26
  type FC,
27
- type MutableRefObject,
28
27
  type ReactNode,
29
28
  type RefObject,
30
29
  type SyntheticEvent,
@@ -61,13 +60,13 @@ type TooltipContextValue = {
61
60
  onOpen(): void;
62
61
  onClose(): void;
63
62
  onPointerInTransitChange(inTransit: boolean): void;
64
- isPointerInTransitRef: MutableRefObject<boolean>;
63
+ isPointerInTransitRef: RefObject<boolean>;
65
64
  disableHoverableContent: boolean;
66
65
  };
67
66
 
68
67
  const [TooltipContextProvider, useTooltipContext] = createTooltipContext<TooltipContextValue>(TOOLTIP_NAME);
69
68
 
70
- interface TooltipProviderProps {
69
+ type TooltipProviderProps = {
71
70
  children?: ReactNode;
72
71
  open?: boolean;
73
72
  defaultOpen?: boolean;
@@ -88,7 +87,7 @@ interface TooltipProviderProps {
88
87
  * @defaultValue 300
89
88
  */
90
89
  skipDelayDuration?: number;
91
- }
90
+ };
92
91
 
93
92
  const TooltipProvider: FC<TooltipProviderProps> = (props: TooltipScopedProps<TooltipProviderProps>) => {
94
93
  const {
@@ -247,7 +246,7 @@ const TooltipVirtualTrigger = ({
247
246
 
248
247
  const TRIGGER_NAME = 'TooltipTrigger';
249
248
 
250
- type TooltipTriggerElement = ElementRef<typeof Primitive.button>;
249
+ type TooltipTriggerElement = ComponentRef<typeof Primitive.button>;
251
250
  type PrimitiveButtonProps = ComponentPropsWithoutRef<typeof Primitive.button>;
252
251
  type TooltipTriggerProps = PrimitiveButtonProps &
253
252
  Pick<TooltipProps, 'delayDuration'> & {
@@ -335,7 +334,7 @@ const [PortalProvider, usePortalContext] = createTooltipContext<PortalContextVal
335
334
  });
336
335
 
337
336
  type PortalProps = ComponentPropsWithoutRef<typeof PortalPrimitive>;
338
- interface TooltipPortalProps {
337
+ type TooltipPortalProps = {
339
338
  children?: ReactNode;
340
339
  /**
341
340
  * Specify a container element to portal the content into.
@@ -346,7 +345,7 @@ interface TooltipPortalProps {
346
345
  * controlling animation with React animation libraries.
347
346
  */
348
347
  forceMount?: true;
349
- }
348
+ };
350
349
 
351
350
  const TooltipPortal: FC<TooltipPortalProps> = (props: TooltipScopedProps<TooltipPortalProps>) => {
352
351
  const { __scopeTooltip, forceMount, children, container } = props;
@@ -371,13 +370,13 @@ TooltipPortal.displayName = PORTAL_NAME;
371
370
  const CONTENT_NAME = 'TooltipContent';
372
371
 
373
372
  type TooltipContentElement = TooltipContentImplElement;
374
- interface TooltipContentProps extends TooltipContentImplProps {
373
+ type TooltipContentProps = TooltipContentImplProps & {
375
374
  /**
376
375
  * Used to force mounting when more control is needed. Useful when
377
376
  * controlling animation with React animation libraries.
378
377
  */
379
378
  forceMount?: true;
380
- }
379
+ };
381
380
 
382
381
  const TooltipContent = forwardRef<TooltipContentElement, TooltipContentProps>(
383
382
  (props: TooltipScopedProps<TooltipContentProps>, forwardedRef) => {
@@ -401,7 +400,7 @@ type Point = { x: number; y: number };
401
400
  type Polygon = Point[];
402
401
 
403
402
  type TooltipContentHoverableElement = TooltipContentImplElement;
404
- interface TooltipContentHoverableProps extends TooltipContentImplProps {}
403
+ type TooltipContentHoverableProps = TooltipContentImplProps;
405
404
 
406
405
  const TooltipContentHoverable = forwardRef<TooltipContentHoverableElement, TooltipContentHoverableProps>(
407
406
  (props: TooltipScopedProps<TooltipContentHoverableProps>, forwardedRef) => {
@@ -480,10 +479,10 @@ const [VisuallyHiddenContentContextProvider, useVisuallyHiddenContentContext] =
480
479
  isInside: false,
481
480
  });
482
481
 
483
- type TooltipContentImplElement = ElementRef<typeof PopperPrimitive.Content>;
482
+ type TooltipContentImplElement = ComponentRef<typeof PopperPrimitive.Content>;
484
483
  type DismissableLayerProps = ComponentPropsWithoutRef<typeof DismissableLayer>;
485
484
  type PopperContentProps = ComponentPropsWithoutRef<typeof PopperPrimitive.Content>;
486
- interface TooltipContentImplProps extends Omit<PopperContentProps, 'onPlaced'> {
485
+ type TooltipContentImplProps = Omit<PopperContentProps, 'onPlaced'> & {
487
486
  /**
488
487
  * A more descriptive label for accessibility purpose
489
488
  */
@@ -499,7 +498,7 @@ interface TooltipContentImplProps extends Omit<PopperContentProps, 'onPlaced'> {
499
498
  * Can be prevented.
500
499
  */
501
500
  onPointerDownOutside?: DismissableLayerProps['onPointerDownOutside'];
502
- }
501
+ };
503
502
 
504
503
  const TooltipContentImpl = forwardRef<TooltipContentImplElement, TooltipContentImplProps>(
505
504
  (props: TooltipScopedProps<TooltipContentImplProps>, forwardedRef) => {
@@ -581,9 +580,9 @@ TooltipContent.displayName = CONTENT_NAME;
581
580
 
582
581
  const ARROW_NAME = 'TooltipArrow';
583
582
 
584
- type TooltipArrowElement = ElementRef<typeof PopperPrimitive.Arrow>;
583
+ type TooltipArrowElement = ComponentRef<typeof PopperPrimitive.Arrow>;
585
584
  type PopperArrowProps = ComponentPropsWithoutRef<typeof PopperPrimitive.Arrow>;
586
- interface TooltipArrowProps extends PopperArrowProps {}
585
+ type TooltipArrowProps = PopperArrowProps;
587
586
 
588
587
  const TooltipArrow = forwardRef<TooltipArrowElement, TooltipArrowProps>(
589
588
  (props: TooltipScopedProps<TooltipArrowProps>, forwardedRef) => {
@@ -13,6 +13,7 @@ export * from './Card';
13
13
  export * from './Clipboard';
14
14
  export * from './Dialog';
15
15
  export * from './ErrorFallback';
16
+ export * from './Focus';
16
17
  export * from './Icon';
17
18
  export * from './Image';
18
19
  export * from './Input';
@@ -3,13 +3,16 @@
3
3
  //
4
4
 
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
- import React, { type ReactElement, type Ref, forwardRef } from 'react';
6
+ import React from 'react';
7
7
 
8
- import { type SlottableProps } from '@dxos/ui-types';
8
+ import { slottable } from '@dxos/ui-theme';
9
9
 
10
10
  import { withTheme } from '../testing';
11
11
 
12
- const ComponentInner = forwardRef<HTMLDivElement, ComponentProps>(({ children, ...props }, forwardedRef) => {
12
+ /**
13
+ * Generic component pattern using the slottable factory.
14
+ */
15
+ const Component = slottable<HTMLDivElement>(({ children, ...props }, forwardedRef) => {
13
16
  return (
14
17
  <div {...props} ref={forwardedRef}>
15
18
  {children}
@@ -17,21 +20,10 @@ const ComponentInner = forwardRef<HTMLDivElement, ComponentProps>(({ children, .
17
20
  );
18
21
  });
19
22
 
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
23
  const meta = {
32
24
  title: 'ui/react-ui-core/exemplars/generics',
33
25
  component: Component,
34
- render: (props) => <Component<HTMLDivElement> {...props} />,
26
+ render: (props) => <Component {...props} />,
35
27
  decorators: [withTheme()],
36
28
  parameters: {
37
29
  layout: 'centered',