@dxos/react-ui 0.8.4-main.c85a9c8dae → 0.8.4-main.d05673bc65

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 (62) hide show
  1. package/dist/lib/browser/index.mjs +590 -603
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/testing/index.mjs +18 -0
  5. package/dist/lib/browser/testing/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/index.mjs +590 -603
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/lib/node-esm/testing/index.mjs +18 -0
  10. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  11. package/dist/types/src/components/Card/Card.d.ts +15 -29
  12. package/dist/types/src/components/Card/Card.d.ts.map +1 -1
  13. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +4 -6
  14. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  15. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +5 -7
  16. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/Splitter/Splitter.d.ts +7 -11
  18. package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -1
  19. package/dist/types/src/components/Toolbar/Toolbar.d.ts +1 -3
  20. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  21. package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -1
  22. package/dist/types/src/primitives/Column/Column.d.ts +6 -12
  23. package/dist/types/src/primitives/Column/Column.d.ts.map +1 -1
  24. package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -1
  25. package/dist/types/src/primitives/Container/Container.d.ts +8 -0
  26. package/dist/types/src/primitives/Container/Container.d.ts.map +1 -0
  27. package/dist/types/src/primitives/Container/Container.stories.d.ts +6 -0
  28. package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -0
  29. package/dist/types/src/primitives/Container/index.d.ts +2 -0
  30. package/dist/types/src/primitives/Container/index.d.ts.map +1 -0
  31. package/dist/types/src/primitives/Flex/Flex.d.ts +9 -4
  32. package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -1
  33. package/dist/types/src/primitives/Grid/Grid.d.ts +10 -4
  34. package/dist/types/src/primitives/Grid/Grid.d.ts.map +1 -1
  35. package/dist/types/src/primitives/Panel/Panel.d.ts +6 -14
  36. package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -1
  37. package/dist/types/src/primitives/index.d.ts +1 -0
  38. package/dist/types/src/primitives/index.d.ts.map +1 -1
  39. package/dist/types/src/testing/Loading.d.ts +9 -0
  40. package/dist/types/src/testing/Loading.d.ts.map +1 -0
  41. package/dist/types/src/testing/index.d.ts +1 -0
  42. package/dist/types/src/testing/index.d.ts.map +1 -1
  43. package/dist/types/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +16 -16
  45. package/src/components/Card/Card.tsx +49 -54
  46. package/src/components/List/List.stories.tsx +2 -2
  47. package/src/components/List/TreeDropIndicator.tsx +1 -1
  48. package/src/components/ScrollArea/ScrollArea.tsx +6 -6
  49. package/src/components/Splitter/Splitter.tsx +17 -29
  50. package/src/components/Toolbar/Toolbar.tsx +18 -17
  51. package/src/exemplars/slot.stories.tsx +11 -23
  52. package/src/primitives/Column/Column.stories.tsx +6 -0
  53. package/src/primitives/Column/Column.tsx +26 -48
  54. package/src/primitives/Container/Container.stories.tsx +30 -0
  55. package/src/primitives/Container/Container.tsx +22 -0
  56. package/src/primitives/Container/index.ts +5 -0
  57. package/src/primitives/Flex/Flex.tsx +21 -19
  58. package/src/primitives/Grid/Grid.tsx +27 -35
  59. package/src/primitives/Panel/Panel.tsx +54 -72
  60. package/src/primitives/index.ts +1 -0
  61. package/src/testing/Loading.tsx +26 -0
  62. package/src/testing/index.ts +2 -0
@@ -6,6 +6,7 @@ import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
7
  import React, { type CSSProperties, forwardRef } from 'react';
8
8
 
9
+ import { composableProps } from '@dxos/ui-theme';
9
10
  import { type SlottableProps } from '@dxos/ui-types';
10
11
 
11
12
  import { useThemeContext } from '../../hooks';
@@ -25,7 +26,7 @@ const gutterSizes: Record<GutterSize, string> = {
25
26
  rail: 'var(--dx-rail-item)',
26
27
  };
27
28
 
28
- type ColumnRootProps = SlottableProps<HTMLDivElement> & { gutter?: GutterSize };
29
+ type ColumnRootProps = SlottableProps<HTMLDivElement, { gutter?: GutterSize }>;
29
30
 
30
31
  /**
31
32
  * Creates a vertical channel with left/right gutter columns.
@@ -39,13 +40,14 @@ type ColumnRootProps = SlottableProps<HTMLDivElement> & { gutter?: GutterSize };
39
40
  * The `--gutter` CSS variable is also consumed by ScrollArea's `margin` option to align scrollbar spacing.
40
41
  */
41
42
  const Root = forwardRef<HTMLDivElement, ColumnRootProps>(
42
- ({ classNames, className, asChild, role, children, gutter = 'md', ...props }, forwardedRef) => {
43
+ ({ children, asChild, role, gutter = 'md', ...props }, forwardedRef) => {
44
+ const { className, ...rest } = composableProps(props);
45
+ const Comp = asChild ? Slot : Primitive.div;
43
46
  const { tx } = useThemeContext();
44
- const Component = asChild ? Slot : Primitive.div;
45
47
  const gutterSize = gutterSizes[gutter];
46
48
  return (
47
- <Component
48
- {...props}
49
+ <Comp
50
+ {...rest}
49
51
  role={role ?? 'none'}
50
52
  style={
51
53
  {
@@ -53,11 +55,11 @@ const Root = forwardRef<HTMLDivElement, ColumnRootProps>(
53
55
  gridTemplateColumns: [gutterSize, 'minmax(0,1fr)', gutterSize].join(' '),
54
56
  } as CSSProperties
55
57
  }
56
- className={tx('column.root', { gutter }, [className, classNames])}
58
+ className={tx('column.root', { gutter }, className)}
57
59
  ref={forwardedRef}
58
60
  >
59
61
  {children}
60
- </Component>
62
+ </Comp>
61
63
  );
62
64
  },
63
65
  );
@@ -77,22 +79,16 @@ type ColumnRowProps = SlottableProps<HTMLDivElement>;
77
79
  * Children map to: [col-1: icon/slot] [col-2: content] [col-3: icon/action].
78
80
  * Must be a direct child of Column.Root.
79
81
  */
80
- const Row = forwardRef<HTMLDivElement, ColumnRowProps>(
81
- ({ classNames, className, asChild, role, children, ...props }, forwardedRef) => {
82
- const { tx } = useThemeContext();
83
- const Component = asChild ? Slot : Primitive.div;
84
- return (
85
- <Component
86
- {...props}
87
- className={tx('column.row', {}, [className, classNames])}
88
- role={role ?? 'none'}
89
- ref={forwardedRef}
90
- >
91
- {children}
92
- </Component>
93
- );
94
- },
95
- );
82
+ const Row = forwardRef<HTMLDivElement, ColumnRowProps>(({ children, asChild, role, ...props }, forwardedRef) => {
83
+ const { className, ...rest } = composableProps(props);
84
+ const Comp = asChild ? Slot : Primitive.div;
85
+ const { tx } = useThemeContext();
86
+ return (
87
+ <Comp {...rest} role={role ?? 'none'} className={tx('column.row', {}, className)} ref={forwardedRef}>
88
+ {children}
89
+ </Comp>
90
+ );
91
+ });
96
92
 
97
93
  Row.displayName = COLUMN_ROW_NAME;
98
94
 
@@ -110,33 +106,15 @@ type ColumnSegmentProps = SlottableProps<HTMLDivElement>;
110
106
  * NOTE: Must not use overflow-hidden here since it will clip input focus rings.
111
107
  */
112
108
  const Segment = forwardRef<HTMLDivElement, ColumnSegmentProps>(
113
- ({ classNames, className, asChild, role, children, ...props }, forwardedRef) => {
109
+ ({ children, asChild, role, ...props }, forwardedRef) => {
110
+ const { className, ...rest } = composableProps(props);
111
+ const Comp = asChild ? Slot : Primitive.div;
114
112
  const { tx } = useThemeContext();
115
- const Component = asChild ? Slot : Primitive.div;
116
-
117
- if (asChild) {
118
- // With asChild, merge col-start-2 directly onto the child — no contents wrapper needed.
119
- return (
120
- <Component
121
- {...props}
122
- role={role ?? 'none'}
123
- className={tx('column.segment', {}, [className, classNames])}
124
- ref={forwardedRef}
125
- >
126
- {children}
127
- </Component>
128
- );
129
- }
130
-
113
+ // With asChild, merge col-start-2 directly onto the child — no contents wrapper needed.
131
114
  return (
132
- <Component
133
- {...props}
134
- className={tx('column.segment', {}, [className, classNames])}
135
- role={role}
136
- ref={forwardedRef}
137
- >
138
- <div className='contents'>{children}</div>
139
- </Component>
115
+ <Comp {...rest} role={role ?? 'none'} className={tx('column.segment', {}, className)} ref={forwardedRef}>
116
+ {asChild ? children : <div className='contents'>{children}</div>}
117
+ </Comp>
140
118
  );
141
119
  },
142
120
  );
@@ -0,0 +1,30 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React from 'react';
7
+
8
+ import { withLayout, withTheme } from '../../testing';
9
+
10
+ import { Container } from './Container';
11
+
12
+ const DefaultStory = () => (
13
+ <Container asChild>
14
+ <div className='grid place-items-center border border-red-500'>Hello</div>
15
+ </Container>
16
+ );
17
+
18
+ const meta: Meta = {
19
+ title: 'ui/react-ui-core/primitives/Container',
20
+ component: Container,
21
+ render: DefaultStory,
22
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
23
+ parameters: { layout: 'fullscreen' },
24
+ };
25
+
26
+ export default meta;
27
+
28
+ type Story = StoryObj<typeof meta>;
29
+
30
+ export const Default: Story = {};
@@ -0,0 +1,22 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import React, { forwardRef } from 'react';
6
+
7
+ import { composableProps, mx } from '@dxos/ui-theme';
8
+ import { Slot } from '@radix-ui/react-slot';
9
+ import { SlottableProps } from '@dxos/ui-types';
10
+ import { Primitive } from '@radix-ui/react-primitive';
11
+
12
+ export type ContainerProps = SlottableProps<HTMLDivElement>;
13
+
14
+ export const Container = forwardRef<HTMLDivElement, ContainerProps>(({ children, asChild, ...props }, forwardedRef) => {
15
+ const { className, ...rest } = composableProps<HTMLDivElement>(props, { role: 'none' });
16
+ const Comp = asChild ? Slot : Primitive.div;
17
+ return (
18
+ <Comp {...rest} className={mx('dx-container', className)} ref={forwardedRef}>
19
+ {children}
20
+ </Comp>
21
+ );
22
+ });
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export * from './Container';
@@ -2,26 +2,28 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- import React, { type HTMLAttributes } from 'react';
5
+ import React, { forwardRef } from 'react';
6
6
 
7
- import { mx } from '@dxos/ui-theme';
7
+ import { composableProps, mx } from '@dxos/ui-theme';
8
8
  import { type ComposableProps } from '@dxos/ui-types';
9
9
 
10
- export type FlexProps = ComposableProps<
11
- HTMLAttributes<HTMLDivElement> & {
12
- column?: boolean;
13
- grow?: boolean;
14
- }
15
- >;
16
-
17
- export const Flex = ({ children, classNames, className, role, column, grow, ...props }: FlexProps) => {
18
- return (
19
- <div
20
- {...props}
21
- role={role ?? 'none'}
22
- className={mx('flex', column && 'flex-col', grow && 'flex-1 overflow-hidden', className, classNames)}
23
- >
24
- {children}
25
- </div>
26
- );
10
+ export type FlexProps = ComposableProps<HTMLDivElement> & {
11
+ column?: boolean;
12
+ grow?: boolean;
27
13
  };
14
+
15
+ export const Flex = forwardRef<HTMLDivElement, FlexProps>(
16
+ ({ children, role, column, grow, ...props }, forwardedRef) => {
17
+ const { className, ...rest } = composableProps(props);
18
+ return (
19
+ <div
20
+ ref={forwardedRef}
21
+ {...rest}
22
+ role={role ?? 'none'}
23
+ className={mx('flex', column && 'flex-col', grow && 'flex-1 overflow-hidden', className)}
24
+ >
25
+ {children}
26
+ </div>
27
+ );
28
+ },
29
+ );
@@ -2,42 +2,34 @@
2
2
  // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- import React, { type HTMLAttributes } from 'react';
5
+ import React, { forwardRef } from 'react';
6
6
 
7
- import { mx } from '@dxos/ui-theme';
7
+ import { composableProps, mx } from '@dxos/ui-theme';
8
8
  import { type ComposableProps } from '@dxos/ui-types';
9
9
 
10
- export type GridProps = ComposableProps<
11
- HTMLAttributes<HTMLDivElement> & {
12
- cols?: number;
13
- rows?: number;
14
- grow?: boolean;
15
- }
16
- >;
17
-
18
- export const Grid = ({
19
- children,
20
- classNames,
21
- className,
22
- style,
23
- role,
24
- cols,
25
- rows,
26
- grow = true,
27
- ...props
28
- }: GridProps) => {
29
- return (
30
- <div
31
- {...props}
32
- role={role ?? 'none'}
33
- style={{
34
- gridTemplateColumns: cols ? `repeat(${cols}, 1fr)` : undefined,
35
- gridTemplateRows: rows ? `repeat(${rows}, 1fr)` : undefined,
36
- ...style,
37
- }}
38
- className={mx('grid overflow-hidden', grow && 'dx-container', className, classNames)}
39
- >
40
- {children}
41
- </div>
42
- );
10
+ export type GridProps = ComposableProps<HTMLDivElement> & {
11
+ cols?: number;
12
+ rows?: number;
13
+ grow?: boolean;
43
14
  };
15
+
16
+ export const Grid = forwardRef<HTMLDivElement, GridProps>(
17
+ ({ children, style, role, cols, rows, grow = true, ...props }, forwardedRef) => {
18
+ const { className, ...rest } = composableProps(props);
19
+ return (
20
+ <div
21
+ ref={forwardedRef}
22
+ {...rest}
23
+ role={role ?? 'none'}
24
+ className={mx('grid overflow-hidden', grow && 'dx-container', className)}
25
+ style={{
26
+ gridTemplateColumns: cols ? `repeat(${cols}, 1fr)` : undefined,
27
+ gridTemplateRows: rows ? `repeat(${rows}, 1fr)` : undefined,
28
+ ...style,
29
+ }}
30
+ >
31
+ {children}
32
+ </div>
33
+ );
34
+ },
35
+ );
@@ -6,6 +6,7 @@ import { Primitive } from '@radix-ui/react-primitive';
6
6
  import { Slot } from '@radix-ui/react-slot';
7
7
  import React, { forwardRef } from 'react';
8
8
 
9
+ import { composableProps } from '@dxos/ui-theme';
9
10
  import { type SlottableProps } from '@dxos/ui-types';
10
11
 
11
12
  import { useThemeContext } from '../../hooks';
@@ -17,29 +18,28 @@ import { useThemeContext } from '../../hooks';
17
18
  const GRID_TEMPLATE_ROWS = 'auto 1fr auto';
18
19
  const GRID_TEMPLATE_AREAS = '"toolbar" "content" "statusbar"';
19
20
 
20
- type PanelRootProps = SlottableProps<HTMLDivElement>;
21
-
22
- const Root = forwardRef<HTMLDivElement, PanelRootProps>(
23
- ({ classNames, className, asChild, children, role, ...props }, forwardedRef) => {
24
- const { tx } = useThemeContext();
25
- const Comp = asChild ? Slot : Primitive.div;
26
- return (
27
- <Comp
28
- ref={forwardedRef}
29
- role={role ?? 'none'}
30
- {...props}
31
- style={{
32
- gridTemplateRows: GRID_TEMPLATE_ROWS,
33
- gridTemplateAreas: GRID_TEMPLATE_AREAS,
34
- ...props.style,
35
- }}
36
- className={tx('panel.root', {}, [className, classNames])}
37
- >
38
- {children}
39
- </Comp>
40
- );
41
- },
42
- );
21
+ type RootProps = SlottableProps<HTMLDivElement>;
22
+
23
+ const Root = forwardRef<HTMLDivElement, RootProps>(({ children, asChild, role, style, ...props }, forwardedRef) => {
24
+ const { className, ...rest } = composableProps(props);
25
+ const Comp = asChild ? Slot : Primitive.div;
26
+ const { tx } = useThemeContext();
27
+ return (
28
+ <Comp
29
+ {...rest}
30
+ role={role ?? 'none'}
31
+ style={{
32
+ gridTemplateRows: GRID_TEMPLATE_ROWS,
33
+ gridTemplateAreas: GRID_TEMPLATE_AREAS,
34
+ ...style,
35
+ }}
36
+ className={tx('panel.root', {}, className)}
37
+ ref={forwardedRef}
38
+ >
39
+ {children}
40
+ </Comp>
41
+ );
42
+ });
43
43
 
44
44
  Root.displayName = 'Panel.Root';
45
45
 
@@ -49,22 +49,16 @@ Root.displayName = 'Panel.Root';
49
49
 
50
50
  type ToolbarProps = SlottableProps<HTMLDivElement>;
51
51
 
52
- const Toolbar = forwardRef<HTMLDivElement, ToolbarProps>(
53
- ({ classNames, className, asChild, children, ...props }, forwardedRef) => {
54
- const { tx } = useThemeContext();
55
- const Comp = asChild ? Slot : Primitive.div;
56
- return (
57
- <Comp
58
- ref={forwardedRef}
59
- data-slot='toolbar'
60
- {...props}
61
- className={tx('panel.toolbar', {}, [className, classNames])}
62
- >
63
- {children}
64
- </Comp>
65
- );
66
- },
67
- );
52
+ const Toolbar = forwardRef<HTMLDivElement, ToolbarProps>(({ children, asChild, ...props }, forwardedRef) => {
53
+ const { className, ...rest } = composableProps(props);
54
+ const Comp = asChild ? Slot : Primitive.div;
55
+ const { tx } = useThemeContext();
56
+ return (
57
+ <Comp {...rest} data-slot='toolbar' className={tx('panel.toolbar', {}, className)} ref={forwardedRef}>
58
+ {children}
59
+ </Comp>
60
+ );
61
+ });
68
62
 
69
63
  Toolbar.displayName = 'Panel.Toolbar';
70
64
 
@@ -74,22 +68,16 @@ Toolbar.displayName = 'Panel.Toolbar';
74
68
 
75
69
  type ContentProps = SlottableProps<HTMLDivElement>;
76
70
 
77
- const Content = forwardRef<HTMLDivElement, ContentProps>(
78
- ({ classNames, className, asChild, children, ...props }, forwardedRef) => {
79
- const { tx } = useThemeContext();
80
- const Comp = asChild ? Slot : Primitive.div;
81
- return (
82
- <Comp
83
- ref={forwardedRef}
84
- data-slot='content'
85
- {...props}
86
- className={tx('panel.content', {}, [className, classNames])}
87
- >
88
- {children}
89
- </Comp>
90
- );
91
- },
92
- );
71
+ const Content = forwardRef<HTMLDivElement, ContentProps>(({ children, asChild, ...props }, forwardedRef) => {
72
+ const { className, ...rest } = composableProps(props);
73
+ const Comp = asChild ? Slot : Primitive.div;
74
+ const { tx } = useThemeContext();
75
+ return (
76
+ <Comp {...rest} data-slot='content' className={tx('panel.content', {}, className)} ref={forwardedRef}>
77
+ {children}
78
+ </Comp>
79
+ );
80
+ });
93
81
 
94
82
  Content.displayName = 'Panel.Content';
95
83
 
@@ -99,22 +87,16 @@ Content.displayName = 'Panel.Content';
99
87
 
100
88
  type StatusbarProps = SlottableProps<HTMLDivElement>;
101
89
 
102
- const Statusbar = forwardRef<HTMLDivElement, StatusbarProps>(
103
- ({ classNames, className, asChild, children, ...props }, forwardedRef) => {
104
- const { tx } = useThemeContext();
105
- const Comp = asChild ? Slot : Primitive.div;
106
- return (
107
- <Comp
108
- ref={forwardedRef}
109
- data-slot='statusbar'
110
- {...props}
111
- className={tx('panel.statusbar', {}, [className, classNames])}
112
- >
113
- {children}
114
- </Comp>
115
- );
116
- },
117
- );
90
+ const Statusbar = forwardRef<HTMLDivElement, StatusbarProps>(({ children, asChild, ...props }, forwardedRef) => {
91
+ const { className, ...rest } = composableProps(props);
92
+ const Comp = asChild ? Slot : Primitive.div;
93
+ const { tx } = useThemeContext();
94
+ return (
95
+ <Comp {...rest} data-slot='statusbar' className={tx('panel.statusbar', {}, className)} ref={forwardedRef}>
96
+ {children}
97
+ </Comp>
98
+ );
99
+ });
118
100
 
119
101
  Statusbar.displayName = 'Panel.Statusbar';
120
102
 
@@ -130,7 +112,7 @@ export const Panel = {
130
112
  };
131
113
 
132
114
  export type {
133
- PanelRootProps,
115
+ RootProps as PanelRootProps,
134
116
  ToolbarProps as PanelToolbarProps,
135
117
  ContentProps as PanelContentProps,
136
118
  StatusbarProps as PanelStatusbarProps,
@@ -3,6 +3,7 @@
3
3
  //
4
4
 
5
5
  export * from './Column';
6
+ export * from './Container';
6
7
  export * from './Flex';
7
8
  export * from './Grid';
8
9
  export * from './Panel';
@@ -0,0 +1,26 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { mx } from '@dxos/ui-theme';
6
+ import { safeStringify } from '@dxos/util';
7
+ import React, { useEffect, useState } from 'react';
8
+
9
+ export type LoadingProps = { data?: any };
10
+
11
+ /**
12
+ * Storybook loading component.
13
+ */
14
+ export const Loading = ({ data }: LoadingProps) => {
15
+ const [visible, setVisible] = useState(false);
16
+ useEffect(() => {
17
+ const t = setTimeout(() => setVisible(true), 500);
18
+ return () => clearTimeout(t);
19
+ }, []);
20
+ return (
21
+ <div className={mx('flex flex-col opacity-0 transition delay-1000 duration-1000', visible && 'opacity-100')}>
22
+ <h2 className='uppercase'>Loading</h2>
23
+ <pre>{safeStringify(data, undefined, 2)}</pre>
24
+ </div>
25
+ );
26
+ };
@@ -3,3 +3,5 @@
3
3
  //
4
4
 
5
5
  export * from './decorators';
6
+
7
+ export * from './Loading';