@dxos/react-ui 0.8.4-main.3c1ae3b → 0.8.4-main.3eb6e50203

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 (242) hide show
  1. package/dist/lib/browser/chunk-6DTBPJE4.mjs +774 -0
  2. package/dist/lib/browser/chunk-6DTBPJE4.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +3198 -66
  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 +34 -45
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node-esm/chunk-JKHQSGNU.mjs +776 -0
  9. package/dist/lib/node-esm/chunk-JKHQSGNU.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +3198 -66
  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 +34 -45
  14. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  15. package/dist/types/src/components/AnchoredOverflow/AnchoredOverflow.d.ts +7 -0
  16. package/dist/types/src/components/AnchoredOverflow/AnchoredOverflow.d.ts.map +1 -1
  17. package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
  18. package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  19. package/dist/types/src/components/Button/Button.d.ts +1 -1
  20. package/dist/types/src/components/Button/Button.d.ts.map +1 -1
  21. package/dist/types/src/components/Button/IconButton.d.ts.map +1 -1
  22. package/dist/types/src/components/Button/ToggleGroup.d.ts +4 -4
  23. package/dist/types/src/components/Button/ToggleGroup.stories.d.ts +4 -4
  24. package/dist/types/src/components/DensityProvider/DensityProvider.d.ts +1 -1
  25. package/dist/types/src/components/DensityProvider/DensityProvider.d.ts.map +1 -1
  26. package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
  27. package/dist/types/src/components/Dialog/Dialog.d.ts +23 -8
  28. package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
  29. package/dist/types/src/components/Dialog/Dialog.stories.d.ts +7 -5
  30. package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts +1 -1
  32. package/dist/types/src/components/ElevationProvider/ElevationProvider.d.ts.map +1 -1
  33. package/dist/types/src/components/Icon/Icon.d.ts +1 -1
  34. package/dist/types/src/components/Icon/Icon.d.ts.map +1 -1
  35. package/dist/types/src/components/Input/Input.d.ts +1 -1
  36. package/dist/types/src/components/Input/Input.d.ts.map +1 -1
  37. package/dist/types/src/components/Input/Input.stories.d.ts +2 -2
  38. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  39. package/dist/types/src/components/List/List.d.ts +1 -1
  40. package/dist/types/src/components/List/List.d.ts.map +1 -1
  41. package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
  42. package/dist/types/src/components/List/Treegrid.d.ts.map +1 -1
  43. package/dist/types/src/components/Main/Main.d.ts +8 -9
  44. package/dist/types/src/components/Main/Main.d.ts.map +1 -1
  45. package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
  46. package/dist/types/src/components/{Menus → Menu}/ContextMenu.d.ts +6 -6
  47. package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -0
  48. package/dist/types/src/components/Menu/ContextMenu.stories.d.ts.map +1 -0
  49. package/dist/types/src/components/{Menus → Menu}/DropdownMenu.d.ts +1 -1
  50. package/dist/types/src/components/Menu/DropdownMenu.d.ts.map +1 -0
  51. package/dist/types/src/components/Menu/DropdownMenu.stories.d.ts.map +1 -0
  52. package/dist/types/src/components/Menu/index.d.ts.map +1 -0
  53. package/dist/types/src/components/Message/Message.d.ts +1 -1
  54. package/dist/types/src/components/Message/Message.d.ts.map +1 -1
  55. package/dist/types/src/components/Message/Message.stories.d.ts +1 -1
  56. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  57. package/dist/types/src/components/Popover/Popover.d.ts +1 -1
  58. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  59. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +25 -26
  60. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  61. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +46 -8
  62. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  63. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts +2 -2
  64. package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
  65. package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +1 -1
  66. package/dist/types/src/components/Select/Select.d.ts +9 -9
  67. package/dist/types/src/components/Select/Select.d.ts.map +1 -1
  68. package/dist/types/src/components/Separator/Separator.d.ts +1 -1
  69. package/dist/types/src/components/Skeleton/Skeleton.d.ts +12 -0
  70. package/dist/types/src/components/Skeleton/Skeleton.d.ts.map +1 -0
  71. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts +17 -0
  72. package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -0
  73. package/dist/types/src/components/Skeleton/index.d.ts +2 -0
  74. package/dist/types/src/components/Skeleton/index.d.ts.map +1 -0
  75. package/dist/types/src/components/Splitter/Splitter.d.ts +26 -0
  76. package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -0
  77. package/dist/types/src/components/Splitter/Splitter.stories.d.ts +7 -0
  78. package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -0
  79. package/dist/types/src/components/Splitter/index.d.ts +2 -0
  80. package/dist/types/src/components/Splitter/index.d.ts.map +1 -0
  81. package/dist/types/src/components/Tag/Tag.d.ts +1 -1
  82. package/dist/types/src/components/Tag/Tag.d.ts.map +1 -1
  83. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +2 -2
  84. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  85. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +1 -8
  86. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
  87. package/dist/types/src/components/ThemeProvider/index.d.ts +2 -1
  88. package/dist/types/src/components/ThemeProvider/index.d.ts.map +1 -1
  89. package/dist/types/src/components/Toast/Toast.d.ts +4 -4
  90. package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
  91. package/dist/types/src/components/Toolbar/Toolbar.d.ts +13 -12
  92. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  93. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  94. package/dist/types/src/components/index.d.ts +3 -1
  95. package/dist/types/src/components/index.d.ts.map +1 -1
  96. package/dist/types/src/exemplars/generics.stories.d.ts +17 -0
  97. package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -0
  98. package/dist/types/src/exemplars/slot.stories.d.ts +14 -0
  99. package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -0
  100. package/dist/types/src/exemplars/tabster.stories.d.ts +8 -0
  101. package/dist/types/src/exemplars/tabster.stories.d.ts.map +1 -0
  102. package/dist/types/src/hooks/useDensityContext.d.ts +1 -1
  103. package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
  104. package/dist/types/src/hooks/useElevationContext.d.ts +1 -1
  105. package/dist/types/src/hooks/useElevationContext.d.ts.map +1 -1
  106. package/dist/types/src/index.d.ts +2 -1
  107. package/dist/types/src/index.d.ts.map +1 -1
  108. package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
  109. package/dist/types/src/primitives/Container/Container.d.ts +23 -0
  110. package/dist/types/src/primitives/Container/Container.d.ts.map +1 -0
  111. package/dist/types/src/primitives/Container/Container.stories.d.ts +11 -0
  112. package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -0
  113. package/dist/types/src/primitives/Container/Layout.d.ts +18 -0
  114. package/dist/types/src/primitives/Container/Layout.d.ts.map +1 -0
  115. package/dist/types/src/primitives/Container/Layout.stories.d.ts +10 -0
  116. package/dist/types/src/primitives/Container/Layout.stories.d.ts.map +1 -0
  117. package/dist/types/src/primitives/Container/index.d.ts +3 -0
  118. package/dist/types/src/primitives/Container/index.d.ts.map +1 -0
  119. package/dist/types/src/primitives/Flex/Flex.d.ts +8 -0
  120. package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -0
  121. package/dist/types/src/primitives/Flex/index.d.ts +2 -0
  122. package/dist/types/src/primitives/Flex/index.d.ts.map +1 -0
  123. package/dist/types/src/primitives/index.d.ts +3 -0
  124. package/dist/types/src/primitives/index.d.ts.map +1 -0
  125. package/dist/types/src/testing/decorators/withLayout.d.ts +3 -3
  126. package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -1
  127. package/dist/types/src/testing/decorators/withLayoutVariants.d.ts +1 -1
  128. package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -1
  129. package/dist/types/src/testing/decorators/withTheme.d.ts +3 -2
  130. package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
  131. package/dist/types/src/util/index.d.ts +1 -2
  132. package/dist/types/src/util/index.d.ts.map +1 -1
  133. package/dist/types/tsconfig.tsbuildinfo +1 -1
  134. package/package.json +37 -32
  135. package/src/components/AnchoredOverflow/AnchoredOverflow.tsx +10 -12
  136. package/src/components/Avatars/Avatar.stories.tsx +4 -4
  137. package/src/components/Avatars/Avatar.tsx +3 -10
  138. package/src/components/Avatars/AvatarGroup.stories.tsx +2 -2
  139. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +2 -2
  140. package/src/components/Breadcrumb/Breadcrumb.tsx +5 -31
  141. package/src/components/Button/Button.stories.tsx +2 -2
  142. package/src/components/Button/Button.tsx +2 -8
  143. package/src/components/Button/IconButton.stories.tsx +2 -2
  144. package/src/components/Button/IconButton.tsx +5 -2
  145. package/src/components/Button/Toggle.stories.tsx +2 -2
  146. package/src/components/Button/ToggleGroup.stories.tsx +2 -2
  147. package/src/components/Clipboard/CopyButton.tsx +3 -3
  148. package/src/components/DensityProvider/DensityProvider.tsx +1 -1
  149. package/src/components/Dialog/AlertDialog.stories.tsx +2 -2
  150. package/src/components/Dialog/AlertDialog.tsx +3 -8
  151. package/src/components/Dialog/Dialog.stories.tsx +57 -23
  152. package/src/components/Dialog/Dialog.tsx +162 -43
  153. package/src/components/ElevationProvider/ElevationProvider.tsx +1 -1
  154. package/src/components/Icon/Icon.stories.tsx +3 -3
  155. package/src/components/Icon/Icon.tsx +2 -2
  156. package/src/components/Input/Input.stories.tsx +12 -11
  157. package/src/components/Input/Input.tsx +12 -27
  158. package/src/components/Link/Link.stories.tsx +2 -2
  159. package/src/components/Link/Link.tsx +1 -1
  160. package/src/components/List/List.stories.tsx +18 -14
  161. package/src/components/List/List.tsx +8 -14
  162. package/src/components/List/Tree.stories.tsx +2 -2
  163. package/src/components/List/Treegrid.stories.tsx +2 -2
  164. package/src/components/List/Treegrid.tsx +4 -9
  165. package/src/components/Main/Main.stories.tsx +41 -20
  166. package/src/components/Main/Main.tsx +128 -71
  167. package/src/components/{Menus → Menu}/ContextMenu.stories.tsx +2 -2
  168. package/src/components/{Menus → Menu}/ContextMenu.tsx +7 -31
  169. package/src/components/{Menus → Menu}/DropdownMenu.stories.tsx +2 -2
  170. package/src/components/{Menus → Menu}/DropdownMenu.tsx +65 -63
  171. package/src/components/Message/Message.stories.tsx +3 -3
  172. package/src/components/Message/Message.tsx +32 -23
  173. package/src/components/Popover/Popover.stories.tsx +2 -2
  174. package/src/components/Popover/Popover.tsx +38 -36
  175. package/src/components/ScrollArea/ScrollArea.stories.tsx +166 -40
  176. package/src/components/ScrollArea/ScrollArea.tsx +80 -82
  177. package/src/components/ScrollArea/index.ts +1 -1
  178. package/src/components/ScrollContainer/ScrollContainer.stories.tsx +2 -2
  179. package/src/components/ScrollContainer/ScrollContainer.tsx +14 -9
  180. package/src/components/Select/Select.stories.tsx +2 -2
  181. package/src/components/Select/Select.tsx +9 -25
  182. package/src/components/Separator/Separator.tsx +1 -1
  183. package/src/components/Skeleton/Skeleton.stories.tsx +52 -0
  184. package/src/components/Skeleton/Skeleton.tsx +26 -0
  185. package/src/components/Skeleton/index.ts +5 -0
  186. package/src/components/Splitter/Splitter.stories.tsx +73 -0
  187. package/src/components/Splitter/Splitter.tsx +123 -0
  188. package/src/components/Splitter/index.ts +5 -0
  189. package/src/components/Status/Status.stories.tsx +2 -2
  190. package/src/components/Status/Status.tsx +2 -2
  191. package/src/components/Tag/Tag.stories.tsx +4 -4
  192. package/src/components/Tag/Tag.tsx +2 -7
  193. package/src/components/ThemeProvider/ThemeProvider.tsx +3 -4
  194. package/src/components/ThemeProvider/TranslationsProvider.tsx +1 -16
  195. package/src/components/ThemeProvider/index.ts +3 -3
  196. package/src/components/Toast/Toast.stories.tsx +2 -2
  197. package/src/components/Toast/Toast.tsx +6 -10
  198. package/src/components/Toolbar/Toolbar.stories.tsx +2 -2
  199. package/src/components/Toolbar/Toolbar.tsx +31 -12
  200. package/src/components/Tooltip/Tooltip.stories.tsx +2 -2
  201. package/src/components/Tooltip/Tooltip.tsx +24 -22
  202. package/src/components/index.ts +3 -1
  203. package/src/exemplars/generics.stories.tsx +44 -0
  204. package/src/exemplars/slot.stories.tsx +108 -0
  205. package/src/exemplars/tabster.stories.tsx +127 -0
  206. package/src/hooks/useDensityContext.ts +1 -1
  207. package/src/hooks/useElevationContext.ts +1 -1
  208. package/src/index.ts +2 -1
  209. package/src/playground/Controls.stories.tsx +3 -4
  210. package/src/playground/Custom.stories.tsx +2 -2
  211. package/src/playground/Typography.stories.tsx +2 -2
  212. package/src/primitives/Container/Container.stories.tsx +67 -0
  213. package/src/primitives/Container/Container.tsx +79 -0
  214. package/src/primitives/Container/Layout.stories.tsx +57 -0
  215. package/src/primitives/Container/Layout.tsx +61 -0
  216. package/src/primitives/Container/index.ts +6 -0
  217. package/src/primitives/Flex/Flex.tsx +26 -0
  218. package/src/primitives/Flex/index.ts +5 -0
  219. package/src/primitives/index.ts +6 -0
  220. package/src/testing/decorators/withLayout.tsx +22 -15
  221. package/src/testing/decorators/withLayoutVariants.tsx +2 -2
  222. package/src/testing/decorators/withTheme.tsx +21 -18
  223. package/src/util/index.ts +2 -2
  224. package/dist/lib/browser/chunk-BFCXP6YC.mjs +0 -4710
  225. package/dist/lib/browser/chunk-BFCXP6YC.mjs.map +0 -7
  226. package/dist/lib/node-esm/chunk-F4Z46DD6.mjs +0 -4712
  227. package/dist/lib/node-esm/chunk-F4Z46DD6.mjs.map +0 -7
  228. package/dist/types/src/components/Menus/ContextMenu.d.ts.map +0 -1
  229. package/dist/types/src/components/Menus/ContextMenu.stories.d.ts.map +0 -1
  230. package/dist/types/src/components/Menus/DropdownMenu.d.ts.map +0 -1
  231. package/dist/types/src/components/Menus/DropdownMenu.stories.d.ts.map +0 -1
  232. package/dist/types/src/components/Menus/index.d.ts.map +0 -1
  233. package/dist/types/src/util/ThemedClassName.d.ts +0 -5
  234. package/dist/types/src/util/ThemedClassName.d.ts.map +0 -1
  235. package/dist/types/src/util/domino.d.ts +0 -18
  236. package/dist/types/src/util/domino.d.ts.map +0 -1
  237. package/src/util/ThemedClassName.ts +0 -7
  238. package/src/util/domino.ts +0 -53
  239. /package/dist/types/src/components/{Menus → Menu}/ContextMenu.stories.d.ts +0 -0
  240. /package/dist/types/src/components/{Menus → Menu}/DropdownMenu.stories.d.ts +0 -0
  241. /package/dist/types/src/components/{Menus → Menu}/index.d.ts +0 -0
  242. /package/src/components/{Menus → Menu}/index.ts +0 -0
@@ -2,7 +2,6 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useState } from '@preact-signals/safe-react/react';
6
5
  import { createContext } from '@radix-ui/react-context';
7
6
  import React, {
8
7
  type HTMLAttributes,
@@ -13,16 +12,18 @@ import React, {
13
12
  useImperativeHandle,
14
13
  useMemo,
15
14
  useRef,
15
+ useState,
16
16
  } from 'react';
17
17
 
18
18
  // TODO(burdon): Move these deps to @dxos/dom-util.
19
19
  import { addEventListener, combine } from '@dxos/async';
20
20
  import { invariant } from '@dxos/invariant';
21
21
  import { useForwardedRef } from '@dxos/react-hooks';
22
- import { mx } from '@dxos/react-ui-theme';
22
+ import { mx } from '@dxos/ui-theme';
23
23
 
24
24
  import { type ThemedClassName } from '../../util';
25
25
  import { IconButton } from '../Button';
26
+ import { ScrollArea } from '../ScrollArea';
26
27
 
27
28
  const isBottom = (el: HTMLElement | null) => {
28
29
  return !!(el && el.scrollHeight - el.scrollTop === el.clientHeight);
@@ -138,9 +139,9 @@ const Root = forwardRef<ScrollController, RootProps>(
138
139
  )}
139
140
  />
140
141
  )}
141
- <div className={mx('flex flex-col min-bs-0 overflow-y-auto scrollbar-thin', classNames)} ref={scrollerRef}>
142
- {children}
143
- </div>
142
+ <ScrollArea.Root classNames={mx('min-bs-0', classNames)} ref={scrollerRef} thin>
143
+ <ScrollArea.Viewport>{children}</ScrollArea.Viewport>
144
+ </ScrollArea.Root>
144
145
  </div>
145
146
  </ScrollContainerProvider>
146
147
  );
@@ -153,11 +154,13 @@ Root.displayName = 'ScrollContainer.Root';
153
154
  // Viewport
154
155
  //
155
156
 
157
+ const VIEWPORT_NAME = 'ScrollContainer.Viewport';
158
+
156
159
  type ViewportProps = ThemedClassName<PropsWithChildren<Omit<HTMLAttributes<HTMLDivElement>, 'className'>>>;
157
160
 
158
161
  const Viewport = forwardRef<HTMLDivElement, ViewportProps>(({ classNames, children, ...props }, forwardedRef) => {
159
162
  const contentRef = useForwardedRef(forwardedRef);
160
- const { pinned, scrollToBottom } = useScrollContainerContext(Viewport.displayName!);
163
+ const { pinned, scrollToBottom } = useScrollContainerContext(VIEWPORT_NAME);
161
164
 
162
165
  useEffect(() => {
163
166
  if (!pinned || !contentRef.current) {
@@ -180,16 +183,18 @@ const Viewport = forwardRef<HTMLDivElement, ViewportProps>(({ classNames, childr
180
183
  );
181
184
  });
182
185
 
183
- Viewport.displayName = 'ScrollContainer.Viewport';
186
+ Viewport.displayName = VIEWPORT_NAME;
184
187
 
185
188
  //
186
189
  // ScrollDownButton
187
190
  //
188
191
 
192
+ const SCROLL_DOWN_BUTTON_NAME = 'ScrollContainer.ScrollDownButton';
193
+
189
194
  type ScrollDownButtonProps = ThemedClassName;
190
195
 
191
196
  const ScrollDownButton = ({ classNames }: ScrollDownButtonProps) => {
192
- const { pinned, scrollToBottom } = useScrollContainerContext(ScrollDownButton.displayName!);
197
+ const { pinned, scrollToBottom } = useScrollContainerContext(SCROLL_DOWN_BUTTON_NAME);
193
198
 
194
199
  return (
195
200
  <div
@@ -212,7 +217,7 @@ const ScrollDownButton = ({ classNames }: ScrollDownButtonProps) => {
212
217
  );
213
218
  };
214
219
 
215
- ScrollDownButton.displayName = 'ScrollContainer.ScrollDownButton';
220
+ ScrollDownButton.displayName = SCROLL_DOWN_BUTTON_NAME;
216
221
 
217
222
  //
218
223
  // ScrollContainer
@@ -42,9 +42,9 @@ const DefaultStory = ({ items = [] }: StoryProps) => {
42
42
  };
43
43
 
44
44
  const meta = {
45
- title: 'ui/react-ui-core/Select',
45
+ title: 'ui/react-ui-core/components/Select',
46
46
  render: DefaultStory,
47
- decorators: [withTheme, withLayoutVariants()],
47
+ decorators: [withTheme(), withLayoutVariants()],
48
48
  } satisfies Meta<typeof DefaultStory>;
49
49
 
50
50
  export default meta;
@@ -61,7 +61,7 @@ const SelectContent = forwardRef<HTMLDivElement, SelectContentProps>(
61
61
  {...props}
62
62
  data-arrow-keys='up down'
63
63
  collisionPadding={safeCollisionPadding}
64
- className={tx('select.content', 'select__content', { elevation }, classNames)}
64
+ className={tx('select.content', { elevation }, classNames)}
65
65
  position='popper'
66
66
  ref={forwardedRef}
67
67
  >
@@ -79,7 +79,7 @@ const SelectScrollUpButton = forwardRef<HTMLDivElement, SelectScrollUpButtonProp
79
79
  return (
80
80
  <SelectPrimitive.SelectScrollUpButton
81
81
  {...props}
82
- className={tx('select.scrollButton', 'select__scroll-button--up', {}, classNames)}
82
+ className={tx('select.scrollButton', {}, classNames)}
83
83
  ref={forwardedRef}
84
84
  >
85
85
  {children ?? <Icon size={3} icon='ph--caret-up--bold' />}
@@ -96,7 +96,7 @@ const SelectScrollDownButton = forwardRef<HTMLDivElement, SelectScrollDownButton
96
96
  return (
97
97
  <SelectPrimitive.SelectScrollDownButton
98
98
  {...props}
99
- className={tx('select.scrollButton', 'select__scroll-button--down', {}, classNames)}
99
+ className={tx('select.scrollButton', {}, classNames)}
100
100
  ref={forwardedRef}
101
101
  >
102
102
  {children ?? <Icon size={3} icon='ph--caret-down--bold' />}
@@ -111,11 +111,7 @@ const SelectViewport = forwardRef<HTMLDivElement, SelectViewportProps>(
111
111
  ({ classNames, children, ...props }, forwardedRef) => {
112
112
  const { tx } = useThemeContext();
113
113
  return (
114
- <SelectPrimitive.SelectViewport
115
- {...props}
116
- className={tx('select.viewport', 'select__viewport', {}, classNames)}
117
- ref={forwardedRef}
118
- >
114
+ <SelectPrimitive.SelectViewport {...props} className={tx('select.viewport', {}, classNames)} ref={forwardedRef}>
119
115
  {children}
120
116
  </SelectPrimitive.SelectViewport>
121
117
  );
@@ -126,7 +122,7 @@ type SelectItemProps = ThemedClassName<SelectPrimitive.SelectItemProps>;
126
122
 
127
123
  const SelectItem = forwardRef<HTMLDivElement, SelectItemProps>(({ classNames, ...props }, forwardedRef) => {
128
124
  const { tx } = useThemeContext();
129
- return <SelectPrimitive.Item {...props} className={tx('select.item', 'option', {}, classNames)} ref={forwardedRef} />;
125
+ return <SelectPrimitive.Item {...props} className={tx('select.item', {}, classNames)} ref={forwardedRef} />;
130
126
  });
131
127
 
132
128
  type SelectItemTextProps = SelectPrimitive.SelectItemTextProps;
@@ -141,7 +137,7 @@ const SelectItemIndicator = forwardRef<HTMLDivElement, SelectItemIndicatorProps>
141
137
  return (
142
138
  <SelectPrimitive.ItemIndicator
143
139
  {...props}
144
- className={tx('select.itemIndicator', 'option__indicator', {}, classNames)}
140
+ className={tx('select.itemIndicator', {}, classNames)}
145
141
  ref={forwardedRef}
146
142
  >
147
143
  {children}
@@ -156,7 +152,7 @@ type SelectOptionProps = SelectItemProps;
156
152
  const SelectOption = forwardRef<HTMLDivElement, SelectItemProps>(({ children, classNames, ...props }, forwardedRef) => {
157
153
  const { tx } = useThemeContext();
158
154
  return (
159
- <SelectPrimitive.Item {...props} className={tx('select.item', 'option', {}, classNames)} ref={forwardedRef}>
155
+ <SelectPrimitive.Item {...props} className={tx('select.item', {}, classNames)} ref={forwardedRef}>
160
156
  <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
161
157
  <span className='grow is-1' />
162
158
  {/* <SelectPrimitive.ItemIndicator className={tx('select.itemIndicator', 'option__indicator', {})}> */}
@@ -178,26 +174,14 @@ type SelectSeparatorProps = ThemedClassName<SelectPrimitive.SelectSeparatorProps
178
174
 
179
175
  const SelectSeparator = forwardRef<HTMLDivElement, SelectSeparatorProps>(({ classNames, ...props }, forwardedRef) => {
180
176
  const { tx } = useThemeContext();
181
- return (
182
- <SelectPrimitive.Separator
183
- {...props}
184
- className={tx('select.separator', 'select__separator', {}, classNames)}
185
- ref={forwardedRef}
186
- />
187
- );
177
+ return <SelectPrimitive.Separator {...props} className={tx('select.separator', {}, classNames)} ref={forwardedRef} />;
188
178
  });
189
179
 
190
180
  type SelectArrowProps = ThemedClassName<SelectPrimitive.SelectArrowProps>;
191
181
 
192
182
  const SelectArrow = forwardRef<SVGSVGElement, SelectArrowProps>(({ classNames, ...props }, forwardedRef) => {
193
183
  const { tx } = useThemeContext();
194
- return (
195
- <SelectPrimitive.Arrow
196
- {...props}
197
- className={tx('select.arrow', 'select__arrow', {}, classNames)}
198
- ref={forwardedRef}
199
- />
200
- );
184
+ return <SelectPrimitive.Arrow {...props} className={tx('select.arrow', {}, classNames)} ref={forwardedRef} />;
201
185
  });
202
186
 
203
187
  export const Select = {
@@ -19,7 +19,7 @@ const Separator = forwardRef<HTMLDivElement, SeparatorProps>(
19
19
  <SeparatorPrimitive
20
20
  orientation={orientation}
21
21
  {...props}
22
- className={tx('separator.root', 'separator', { orientation, subdued }, classNames)}
22
+ className={tx('separator.root', { orientation, subdued }, classNames)}
23
23
  ref={forwardedRef}
24
24
  />
25
25
  );
@@ -0,0 +1,52 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { withTheme } from '../../testing';
8
+
9
+ import { Skeleton } from './Skeleton';
10
+
11
+ export default {
12
+ title: 'ui/react-ui-core/components/Skeleton',
13
+ component: Skeleton,
14
+ decorators: [withTheme()],
15
+ parameters: {
16
+ layout: 'centered',
17
+ },
18
+ };
19
+
20
+ export const Default = {
21
+ render: () => (
22
+ <div className='flex flex-col gap-4 p-4 border border-separator rounded-sm'>
23
+ <div className='flex is-fit items-center gap-4'>
24
+ <Skeleton classNames='size-10 shrink-0 rounded-full' />
25
+ <div className='grid gap-2'>
26
+ <Skeleton classNames='bs-4 is-[150px]' />
27
+ <Skeleton classNames='bs-4 is-[100px]' />
28
+ </div>
29
+ </div>
30
+ </div>
31
+ ),
32
+ };
33
+
34
+ export const Card = {
35
+ render: () => (
36
+ <div className='flex flex-col gap-3 is-96 p-4 border border-separator rounded-sm'>
37
+ <div className='flex items-center gap-3'>
38
+ <Skeleton variant='circle' classNames='bs-12 is-12 rounded-full' />
39
+ <div className='flex flex-col gap-2 flex-1'>
40
+ <Skeleton classNames='bs-4 is-24' />
41
+ <Skeleton classNames='bs-3 is-32' />
42
+ </div>
43
+ </div>
44
+ <Skeleton classNames='bs-32 is-full rounded' />
45
+ <div className='flex flex-col gap-2'>
46
+ <Skeleton classNames='bs-3 is-full' />
47
+ <Skeleton classNames='bs-3 is-5/6' />
48
+ <Skeleton classNames='bs-3 is-4/6' />
49
+ </div>
50
+ </div>
51
+ ),
52
+ };
@@ -0,0 +1,26 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React, { type ComponentPropsWithRef, forwardRef } from 'react';
6
+
7
+ import { useThemeContext } from '../../hooks';
8
+ import { type ThemedClassName } from '../../util';
9
+
10
+ type SkeletonProps = ThemedClassName<ComponentPropsWithRef<'div'>> & {
11
+ variant?: 'default' | 'circle' | 'text';
12
+ };
13
+
14
+ /**
15
+ * A skeleton loading component that displays a placeholder while content is loading.
16
+ */
17
+ const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(
18
+ ({ classNames, variant = 'default', ...props }, forwardedRef) => {
19
+ const { tx } = useThemeContext();
20
+ return <div {...props} className={tx('skeleton.root', { variant }, classNames)} ref={forwardedRef} />;
21
+ },
22
+ );
23
+
24
+ export { Skeleton };
25
+
26
+ export type { SkeletonProps };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './Skeleton';
@@ -0,0 +1,73 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { useState } from 'react';
7
+
8
+ import { Layout } from '../../primitives';
9
+ import { withLayout, withTheme } from '../../testing';
10
+ import { ScrollArea } from '../ScrollArea';
11
+ import { Toolbar } from '../Toolbar';
12
+
13
+ import { Splitter, type SplitterRootProps } from './Splitter';
14
+
15
+ const Panel = ({ label }: { label: string }) => {
16
+ return (
17
+ <Layout.Main toolbar>
18
+ <Toolbar.Root>{label}</Toolbar.Root>
19
+ <ScrollArea.Root orientation='vertical'>
20
+ <ScrollArea.Viewport>
21
+ {Array.from({ length: 100 }).map((_, i) => (
22
+ <div key={i} className='p-1'>
23
+ {label}-{i}
24
+ </div>
25
+ ))}
26
+ </ScrollArea.Viewport>
27
+ </ScrollArea.Root>
28
+ </Layout.Main>
29
+ );
30
+ };
31
+
32
+ const DefaultStory = (props: SplitterRootProps) => {
33
+ const [mode, setMode] = useState(props.mode ?? 'both');
34
+
35
+ return (
36
+ <div className='grid grid-rows-[min-content_1fr] bs-full overflow-hidden'>
37
+ <Toolbar.Root>
38
+ <Toolbar.Button onClick={() => setMode('upper')}>A</Toolbar.Button>
39
+ <Toolbar.Button onClick={() => setMode('both')}>A + B</Toolbar.Button>
40
+ <Toolbar.Button onClick={() => setMode('lower')}>B</Toolbar.Button>
41
+ </Toolbar.Root>
42
+ <Splitter.Root mode={mode} ratio={props.ratio} classNames='divide-y divide-subduedSeparator'>
43
+ <Splitter.Panel position='upper'>
44
+ <Panel label='A' />
45
+ </Splitter.Panel>
46
+ <Splitter.Panel position='lower'>
47
+ <Panel label='B' />
48
+ </Splitter.Panel>
49
+ </Splitter.Root>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ const meta: Meta<SplitterRootProps> = {
55
+ title: 'ui/react-ui-core/components/Splitter',
56
+ component: Splitter.Root,
57
+ render: DefaultStory,
58
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
59
+ parameters: {
60
+ layout: 'fullscreen',
61
+ },
62
+ };
63
+
64
+ export default meta;
65
+
66
+ type Story = StoryObj<SplitterRootProps>;
67
+
68
+ export const Default: Story = {
69
+ args: {
70
+ mode: 'both',
71
+ ratio: 0.5,
72
+ },
73
+ };
@@ -0,0 +1,123 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { createContextScope } from '@radix-ui/react-context';
6
+ import React, { type ComponentPropsWithoutRef, forwardRef } from 'react';
7
+
8
+ import { mx } from '@dxos/ui-theme';
9
+
10
+ import { type ThemedClassName } from '../../util';
11
+
12
+ type ScopedProps<P> = P & { __scopeSplitter?: any };
13
+
14
+ // TODO(burdon): Generalize styles.
15
+ // TODO(burdon): Enalbe resize.
16
+ // TODO(burdon): Generalize horizontal/vertical and change to start/end.
17
+ type Mode = 'upper' | 'lower' | 'both';
18
+
19
+ type SplitterContextValue = {
20
+ mode: Mode;
21
+ ratio: number;
22
+ transition: number;
23
+ };
24
+
25
+ const SPLITTER_NAME = 'Splitter';
26
+
27
+ const [createSplitterContext, createSplitterScope] = createContextScope(SPLITTER_NAME);
28
+
29
+ const [SplitterProvider, useSplitterContext] = createSplitterContext<SplitterContextValue>(SPLITTER_NAME);
30
+
31
+ //
32
+ // Root
33
+ //
34
+
35
+ const ROOT_NAME = 'Splitter.Root';
36
+
37
+ type RootProps = ThemedClassName<ComponentPropsWithoutRef<'div'>> & Partial<SplitterContextValue>;
38
+
39
+ const Root = forwardRef<HTMLDivElement, ScopedProps<RootProps>>(
40
+ (
41
+ { __scopeSplitter, classNames, mode = 'upper', ratio = 0.5, transition = 250, children, ...rootProps },
42
+ forwardedRef,
43
+ ) => {
44
+ return (
45
+ <SplitterProvider scope={__scopeSplitter} mode={mode} ratio={ratio} transition={transition}>
46
+ <div
47
+ role='none'
48
+ {...rootProps}
49
+ ref={forwardedRef}
50
+ className={mx('relative bs-full overflow-hidden', classNames)}
51
+ >
52
+ {children}
53
+ </div>
54
+ </SplitterProvider>
55
+ );
56
+ },
57
+ );
58
+
59
+ Root.displayName = ROOT_NAME;
60
+
61
+ //
62
+ // Panel
63
+ //
64
+
65
+ const PANEL_NAME = 'Splitter.Panel';
66
+
67
+ interface PanelProps extends ThemedClassName<ComponentPropsWithoutRef<'div'>> {
68
+ position: 'upper' | 'lower';
69
+ }
70
+
71
+ const Panel = forwardRef<HTMLDivElement, ScopedProps<PanelProps>>(
72
+ ({ __scopeSplitter, classNames, children, position, style, ...panelProps }, forwardedRef) => {
73
+ const context = useSplitterContext(PANEL_NAME, __scopeSplitter);
74
+ const { mode, ratio, transition } = context;
75
+
76
+ // Calculate position and height based on mode and ratio.
77
+ const isUpper = position === 'upper';
78
+ const top = isUpper ? '0%' : mode === 'upper' ? '100%' : mode === 'lower' ? '0%' : `${ratio * 100}%`;
79
+
80
+ const height = isUpper
81
+ ? mode === 'upper'
82
+ ? '100%'
83
+ : mode === 'lower'
84
+ ? '0%'
85
+ : `${ratio * 100}%`
86
+ : mode === 'lower'
87
+ ? '100%'
88
+ : mode === 'upper'
89
+ ? '0%'
90
+ : `${(1 - ratio) * 100}%`;
91
+
92
+ return (
93
+ <div
94
+ {...panelProps}
95
+ ref={forwardedRef}
96
+ className={mx('absolute inset-inline-0 flex flex-col overflow-hidden', classNames)}
97
+ style={{
98
+ top,
99
+ height,
100
+ transition: `top ${transition}ms, height ${transition}ms ease-out`,
101
+ ...style,
102
+ }}
103
+ >
104
+ {children}
105
+ </div>
106
+ );
107
+ },
108
+ );
109
+
110
+ Panel.displayName = PANEL_NAME;
111
+
112
+ //
113
+ // Splitter
114
+ //
115
+
116
+ const Splitter = {
117
+ Root,
118
+ Panel,
119
+ };
120
+
121
+ export { Splitter, createSplitterScope };
122
+
123
+ export type { Mode as SplitterMode, RootProps as SplitterRootProps, PanelProps as SplitterPanelProps };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export * from './Splitter';
@@ -10,9 +10,9 @@ import { withTheme } from '../../testing';
10
10
  import { Status } from './Status';
11
11
 
12
12
  const meta = {
13
- title: 'ui/react-ui-core/Status',
13
+ title: 'ui/react-ui-core/components/Status',
14
14
  component: Status,
15
- decorators: [withTheme],
15
+ decorators: [withTheme()],
16
16
  } satisfies Meta<typeof Status>;
17
17
 
18
18
  export default meta;
@@ -20,12 +20,12 @@ const Status = forwardRef<HTMLSpanElement, StatusProps>(
20
20
  <span
21
21
  role='status'
22
22
  {...props}
23
- className={tx('status.root', 'status', { indeterminate, variant }, classNames)}
23
+ className={tx('status.root', { indeterminate, variant }, classNames)}
24
24
  ref={forwardedRef}
25
25
  >
26
26
  <span
27
27
  role='none'
28
- className={tx('status.bar', 'status__bar', { indeterminate, variant }, classNames)}
28
+ className={tx('status.bar', { indeterminate, variant }, classNames)}
29
29
  {...(!indeterminate && { style: { width: `${Math.round(progress * 100)}%` } })}
30
30
  />
31
31
  {children}
@@ -5,8 +5,8 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
 
8
- import { hues } from '@dxos/react-ui-theme';
9
- import { type ChromaticPalette, type MessageValence } from '@dxos/react-ui-types';
8
+ import { hues } from '@dxos/ui-theme';
9
+ import { type ChromaticPalette, type MessageValence } from '@dxos/ui-types';
10
10
 
11
11
  import { withTheme } from '../../testing';
12
12
 
@@ -15,7 +15,7 @@ import { Tag } from './Tag';
15
15
  const palettes = ['neutral', 'success', 'info', 'warning', 'error', ...hues] as (ChromaticPalette | MessageValence)[];
16
16
 
17
17
  const meta = {
18
- title: 'ui/react-ui-core/Tag',
18
+ title: 'ui/react-ui-core/components/Tag',
19
19
  component: Tag,
20
20
  render: () => (
21
21
  <div role='grid' className='grid grid-cols-5 gap-2 max-is-screen-md'>
@@ -26,7 +26,7 @@ const meta = {
26
26
  ))}
27
27
  </div>
28
28
  ),
29
- decorators: [withTheme],
29
+ decorators: [withTheme()],
30
30
  parameters: {
31
31
  chromatic: {
32
32
  disableSnapshot: false,
@@ -6,7 +6,7 @@ import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
7
  import React, { type ComponentPropsWithRef, forwardRef } from 'react';
8
8
 
9
- import { type ChromaticPalette, type MessageValence, type NeutralPalette } from '@dxos/react-ui-types';
9
+ import { type ChromaticPalette, type MessageValence, type NeutralPalette } from '@dxos/ui-types';
10
10
 
11
11
  import { useThemeContext } from '../../hooks';
12
12
  import { type ThemedClassName } from '../../util';
@@ -21,12 +21,7 @@ export const Tag = forwardRef<HTMLSpanElement, TagProps>(
21
21
  const { tx } = useThemeContext();
22
22
  const Root = asChild ? Slot : Primitive.span;
23
23
  return (
24
- <Root
25
- {...props}
26
- className={tx('tag.root', 'dx-tag', { palette }, classNames)}
27
- data-hue={palette}
28
- ref={forwardedRef}
29
- />
24
+ <Root {...props} className={tx('tag.root', { palette }, classNames)} data-hue={palette} ref={forwardedRef} />
30
25
  );
31
26
  },
32
27
  );
@@ -5,7 +5,7 @@
5
5
  import { createKeyborg } from 'keyborg';
6
6
  import React, { type PropsWithChildren, createContext, useEffect, useMemo } from 'react';
7
7
 
8
- import { type Density, type Elevation, type ThemeFunction } from '@dxos/react-ui-types';
8
+ import { type Density, type Elevation, type ThemeFunction, type ThemeMode } from '@dxos/ui-types';
9
9
 
10
10
  import { type SafeAreaPadding, useSafeArea } from '../../hooks';
11
11
  import { hasIosKeyboard } from '../../util';
@@ -14,14 +14,13 @@ import { ElevationProvider } from '../ElevationProvider';
14
14
 
15
15
  import { TranslationsProvider, type TranslationsProviderProps } from './TranslationsProvider';
16
16
 
17
- export type ThemeMode = 'dark' | 'light';
18
-
19
17
  export type ThemeContextValue = {
20
18
  tx: ThemeFunction<any>;
21
19
  themeMode: ThemeMode;
22
20
  hasIosKeyboard: boolean;
23
21
  safeAreaPadding?: SafeAreaPadding;
24
22
  noCache?: boolean;
23
+ platform?: 'mobile' | 'desktop';
25
24
  };
26
25
 
27
26
  /**
@@ -41,7 +40,7 @@ export const ThemeProvider = ({
41
40
  fallback = null,
42
41
  resourceExtensions,
43
42
  appNs,
44
- tx = (_path, defaultClassName, _styleProps, ..._options) => defaultClassName,
43
+ tx = (_path, _styleProps, ..._options) => undefined,
45
44
  themeMode = 'dark',
46
45
  rootDensity = 'fine',
47
46
  ...rest
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { type Locale, enUS as dtLocaleEnUs } from 'date-fns/locale';
6
- import i18Next, { type Resource, type TFunction } from 'i18next';
6
+ import i18Next, { type Resource } from 'i18next';
7
7
  import React, { type ReactNode, Suspense, createContext, useContext, useEffect, useState } from 'react';
8
8
  import { initReactI18next, useTranslation as useI18NextTranslation } from 'react-i18next';
9
9
 
@@ -11,21 +11,6 @@ const initialLng = 'en-US';
11
11
  const initialNs = 'dxos-common';
12
12
  const initialDtLocale = dtLocaleEnUs;
13
13
 
14
- // TODO(thure): `Parameters<TFunction>` causes typechecking issues because `TFunction` has so many signatures.
15
- export type Label = string | [string, { ns: string; count?: number; defaultValue?: string }];
16
-
17
- export const isLabel = (o: any): o is Label =>
18
- typeof o === 'string' ||
19
- (Array.isArray(o) &&
20
- o.length === 2 &&
21
- typeof o[0] === 'string' &&
22
- !!o[1] &&
23
- typeof o[1] === 'object' &&
24
- 'ns' in o[1] &&
25
- typeof o[1].ns === 'string');
26
-
27
- export const toLocalizedString = (label: Label, t: TFunction) => (Array.isArray(label) ? t(...label) : label);
28
-
29
14
  export const resources = {
30
15
  [initialLng]: {
31
16
  [initialNs]: {
@@ -2,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- export * from './ThemeProvider';
6
- export { type Label, isLabel, toLocalizedString, useTranslation } from './TranslationsProvider';
5
+ export { type Label, isLabel, toLocalizedString } from '@dxos/ui-types';
7
6
 
8
- // TODO(burdon): Use `@internal` with barrel exports (rather than picking individual exports?)
7
+ export * from './ThemeProvider';
8
+ export { useTranslation } from './TranslationsProvider';
@@ -45,10 +45,10 @@ const DefaultStory = ({ title, description, actionTriggers, openTrigger, closeTr
45
45
  };
46
46
 
47
47
  const meta = {
48
- title: 'ui/react-ui-core/Toast',
48
+ title: 'ui/react-ui-core/components/Toast',
49
49
  component: Toast as any,
50
50
  render: DefaultStory,
51
- decorators: [withTheme],
51
+ decorators: [withTheme()],
52
52
  } satisfies Meta<typeof DefaultStory>;
53
53
 
54
54
  export default meta;