@dxos/storybook-utils 0.8.3 → 0.8.4-main.2e9d522

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 (65) hide show
  1. package/dist/lib/browser/index.mjs +139 -90
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +139 -90
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/CardContainers/ExtrinsicCardContainer.d.ts +12 -0
  8. package/dist/types/src/components/CardContainers/ExtrinsicCardContainer.d.ts.map +1 -0
  9. package/dist/types/src/components/CardContainers/IntrinsicCardContainer.d.ts +9 -0
  10. package/dist/types/src/components/CardContainers/IntrinsicCardContainer.d.ts.map +1 -0
  11. package/dist/types/src/components/CardContainers/PopoverCardContainer.d.ts +5 -0
  12. package/dist/types/src/components/CardContainers/PopoverCardContainer.d.ts.map +1 -0
  13. package/dist/types/src/components/CardContainers/index.d.ts +4 -0
  14. package/dist/types/src/components/CardContainers/index.d.ts.map +1 -0
  15. package/dist/types/src/components/DocsContainer.d.ts +4 -0
  16. package/dist/types/src/components/DocsContainer.d.ts.map +1 -0
  17. package/dist/types/src/components/ThemeEditor.d.ts +5 -0
  18. package/dist/types/src/components/ThemeEditor.d.ts.map +1 -0
  19. package/dist/types/src/components/index.d.ts +3 -0
  20. package/dist/types/src/components/index.d.ts.map +1 -0
  21. package/dist/types/src/decorators/index.d.ts +1 -1
  22. package/dist/types/src/decorators/index.d.ts.map +1 -1
  23. package/dist/types/src/decorators/withLayout.d.ts +5 -4
  24. package/dist/types/src/decorators/withLayout.d.ts.map +1 -1
  25. package/dist/types/src/decorators/withTheme.d.ts +1 -2
  26. package/dist/types/src/decorators/withTheme.d.ts.map +1 -1
  27. package/dist/types/src/decorators/withThemeEditor.d.ts +6 -0
  28. package/dist/types/src/decorators/withThemeEditor.d.ts.map +1 -0
  29. package/dist/types/src/index.d.ts +1 -0
  30. package/dist/types/src/index.d.ts.map +1 -1
  31. package/dist/types/src/stories/test/Test.d.ts +6 -0
  32. package/dist/types/src/stories/test/Test.d.ts.map +1 -0
  33. package/dist/types/src/stories/test/Test.stories.d.ts +12 -0
  34. package/dist/types/src/stories/test/Test.stories.d.ts.map +1 -0
  35. package/dist/types/src/stories/test/Test.test.d.ts +2 -0
  36. package/dist/types/src/stories/test/Test.test.d.ts.map +1 -0
  37. package/dist/types/src/vitest-setup.d.ts +2 -0
  38. package/dist/types/src/vitest-setup.d.ts.map +1 -0
  39. package/dist/types/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +15 -14
  41. package/src/components/CardContainers/ExtrinsicCardContainer.tsx +72 -0
  42. package/src/components/CardContainers/IntrinsicCardContainer.tsx +48 -0
  43. package/src/components/CardContainers/PopoverCardContainer.tsx +24 -0
  44. package/src/components/CardContainers/index.ts +7 -0
  45. package/src/components/DocsContainer.tsx +18 -0
  46. package/src/components/ThemeEditor.tsx +18 -0
  47. package/src/components/index.ts +7 -0
  48. package/src/decorators/index.ts +1 -1
  49. package/src/decorators/withLayout.tsx +9 -6
  50. package/src/decorators/withTheme.tsx +9 -63
  51. package/src/decorators/withThemeEditor.tsx +28 -0
  52. package/src/index.ts +1 -0
  53. package/src/stories/test/Test.stories.tsx +62 -0
  54. package/src/stories/test/Test.test.tsx +40 -0
  55. package/src/stories/test/Test.tsx +15 -0
  56. package/src/stories/test/__snapshots__/Test.test.tsx.snap +3 -0
  57. package/src/stories/test/index.mdx +14 -0
  58. package/src/vitest-setup.ts +11 -0
  59. package/README.yml +0 -1
  60. package/dist/lib/node/index.cjs +0 -170
  61. package/dist/lib/node/index.cjs.map +0 -7
  62. package/dist/lib/node/meta.json +0 -1
  63. package/dist/types/src/decorators/withSignals.d.ts +0 -6
  64. package/dist/types/src/decorators/withSignals.d.ts.map +0 -1
  65. package/src/decorators/withSignals.tsx +0 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/storybook-utils",
3
- "version": "0.8.3",
3
+ "version": "0.8.4-main.2e9d522",
4
4
  "description": "Utilities for DXOS UI Storybooks.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -24,15 +24,14 @@
24
24
  "src"
25
25
  ],
26
26
  "dependencies": {
27
- "@storybook/manager-api": "^8.3.6",
28
- "@storybook/preview-api": "^8.3.6",
27
+ "@radix-ui/react-use-controllable-state": "^1.0.0",
29
28
  "lodash.defaultsdeep": "^4.6.1",
30
- "storybook-dark-mode": "^4.0.2",
31
- "@dxos/echo-signals": "0.8.3",
32
- "@dxos/lit-theme-editor": "0.8.3",
33
- "@dxos/lit-ui": "0.8.3",
34
- "@dxos/log": "0.8.3",
35
- "@dxos/theme-editor-addon": "0.8.3"
29
+ "storybook": "^9.0.18",
30
+ "@dxos/echo-signals": "0.8.4-main.2e9d522",
31
+ "@dxos/lit-theme-editor": "0.8.4-main.2e9d522",
32
+ "@dxos/lit-ui": "0.8.4-main.2e9d522",
33
+ "@dxos/log": "0.8.4-main.2e9d522",
34
+ "@dxos/react-ui-dnd": "0.8.4-main.2e9d522"
36
35
  },
37
36
  "devDependencies": {
38
37
  "@types/lodash.defaultsdeep": "^4.6.6",
@@ -40,14 +39,16 @@
40
39
  "@types/react-dom": "~18.2.0",
41
40
  "react": "~18.2.0",
42
41
  "react-dom": "~18.2.0",
43
- "storybook": "^8.3.6",
44
- "@dxos/react-ui": "0.8.3",
45
- "@dxos/react-ui-theme": "0.8.3"
42
+ "@dxos/react-ui": "0.8.4-main.2e9d522",
43
+ "@dxos/react-ui-theme": "0.8.4-main.2e9d522"
46
44
  },
47
45
  "peerDependencies": {
48
46
  "react": "~18.2.0",
49
47
  "react-dom": "~18.2.0",
50
- "@dxos/react-ui": "0.8.3",
51
- "@dxos/react-ui-theme": "0.8.3"
48
+ "@dxos/react-ui": "0.8.4-main.2e9d522",
49
+ "@dxos/react-ui-theme": "0.8.4-main.2e9d522"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
52
53
  }
53
54
  }
@@ -0,0 +1,72 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useControllableState } from '@radix-ui/react-use-controllable-state';
6
+ import React, { type PropsWithChildren } from 'react';
7
+
8
+ import { ResizeHandle, resizeAttributes, sizeStyle, type Size } from '@dxos/react-ui-dnd';
9
+
10
+ // Default size in rem
11
+ const DEFAULT_INLINE_SIZE = 24;
12
+ const MIN_INLINE_SIZE = 8;
13
+ const DEFAULT_BLOCK_SIZE = 24;
14
+ const MIN_BLOCK_SIZE = 8;
15
+
16
+ export type ExtrinsicCardContainerProps = PropsWithChildren<{
17
+ defaultInlineSize?: Size;
18
+ inlineSize?: Size;
19
+ defaultBlockSize?: Size;
20
+ blockSize?: Size;
21
+ onInlineSizeChange?: (size: Size, commit?: boolean) => void;
22
+ onBlockSizeChange?: (size: Size, commit?: boolean) => void;
23
+ }>;
24
+
25
+ export const ExtrinsicCardContainer = ({
26
+ children,
27
+ defaultInlineSize,
28
+ inlineSize: propInlineSize,
29
+ defaultBlockSize,
30
+ blockSize: propBlockSize,
31
+ onInlineSizeChange,
32
+ onBlockSizeChange,
33
+ }: ExtrinsicCardContainerProps) => {
34
+ const [inlineSize = DEFAULT_INLINE_SIZE, setInlineSize] = useControllableState<Size>({
35
+ prop: propInlineSize,
36
+ defaultProp: defaultInlineSize,
37
+ onChange: onInlineSizeChange,
38
+ });
39
+
40
+ const [blockSize = DEFAULT_BLOCK_SIZE, setBlockSize] = useControllableState<Size>({
41
+ prop: propBlockSize,
42
+ defaultProp: defaultBlockSize,
43
+ onChange: onBlockSizeChange,
44
+ });
45
+
46
+ return (
47
+ <div
48
+ className='grid relative border border-dashed border-subduedSeparator p-4 rounded-lg overflow-hidden contain-layout'
49
+ style={{
50
+ ...sizeStyle(inlineSize, 'horizontal'),
51
+ ...sizeStyle(blockSize, 'vertical'),
52
+ }}
53
+ {...resizeAttributes}
54
+ >
55
+ {children}
56
+ <ResizeHandle
57
+ side='inline-end'
58
+ fallbackSize={DEFAULT_INLINE_SIZE}
59
+ minSize={MIN_INLINE_SIZE}
60
+ size={inlineSize}
61
+ onSizeChange={setInlineSize}
62
+ />
63
+ <ResizeHandle
64
+ side='block-end'
65
+ fallbackSize={DEFAULT_BLOCK_SIZE}
66
+ minSize={MIN_BLOCK_SIZE}
67
+ size={blockSize}
68
+ onSizeChange={setBlockSize}
69
+ />
70
+ </div>
71
+ );
72
+ };
@@ -0,0 +1,48 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useControllableState } from '@radix-ui/react-use-controllable-state';
6
+ import React, { type PropsWithChildren } from 'react';
7
+
8
+ import { ResizeHandle, resizeAttributes, sizeStyle, type Size } from '@dxos/react-ui-dnd';
9
+
10
+ // Default size in rem
11
+ const DEFAULT_SIZE = 24;
12
+ const MIN_SIZE = 8;
13
+
14
+ export type IntrinsicCardContainerProps = PropsWithChildren<{
15
+ defaultSize?: Size;
16
+ size?: Size;
17
+ onSizeChange?: (size: Size, commit?: boolean) => void;
18
+ }>;
19
+
20
+ export const IntrinsicCardContainer = ({
21
+ children,
22
+ defaultSize,
23
+ size: propSize,
24
+ onSizeChange,
25
+ }: IntrinsicCardContainerProps) => {
26
+ const [size = DEFAULT_SIZE, setSize] = useControllableState<Size>({
27
+ prop: propSize,
28
+ defaultProp: defaultSize,
29
+ onChange: onSizeChange,
30
+ });
31
+
32
+ return (
33
+ <div
34
+ className='relative border border-dashed border-subduedSeparator p-4 rounded-lg'
35
+ style={sizeStyle(size, 'horizontal')}
36
+ {...resizeAttributes}
37
+ >
38
+ {children}
39
+ <ResizeHandle
40
+ side='inline-end'
41
+ fallbackSize={DEFAULT_SIZE}
42
+ minSize={MIN_SIZE}
43
+ size={size}
44
+ onSizeChange={setSize}
45
+ />
46
+ </div>
47
+ );
48
+ };
@@ -0,0 +1,24 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { type PropsWithChildren } from 'react';
6
+
7
+ import { Icon, Popover } from '@dxos/react-ui';
8
+
9
+ export const PopoverCardContainer = ({
10
+ children,
11
+ icon = 'ph--placeholder--regular',
12
+ }: PropsWithChildren<{ icon: string }>) => {
13
+ return (
14
+ <Popover.Root open>
15
+ <Popover.Content onOpenAutoFocus={(event) => event.preventDefault()}>
16
+ <Popover.Viewport>{children}</Popover.Viewport>
17
+ <Popover.Arrow />
18
+ </Popover.Content>
19
+ <Popover.Trigger>
20
+ <Icon icon={icon} size={5} />
21
+ </Popover.Trigger>
22
+ </Popover.Root>
23
+ );
24
+ };
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './ExtrinsicCardContainer';
6
+ export * from './IntrinsicCardContainer';
7
+ export * from './PopoverCardContainer';
@@ -0,0 +1,18 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ // TODO(wittjosiah): Not compatible with storybook 9.0.
6
+ // import { DocsContainer as BaseContainer, type DocsContainerProps } from '@storybook/blocks';
7
+ // import React, { type PropsWithChildren } from 'react';
8
+
9
+ /**
10
+ * https://storybook.js.org/docs/writing-docs/doc-blocks
11
+ */
12
+ // export const DocsContainer = ({ children, context, theme }: PropsWithChildren<DocsContainerProps>) => {
13
+ // return (
14
+ // <BaseContainer context={context} theme={theme}>
15
+ // {children}
16
+ // </BaseContainer>
17
+ // );
18
+ // };
@@ -0,0 +1,18 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React, { memo } from 'react';
6
+
7
+ import { DxThemeEditor as NaturalDxThemeEditor } from '@dxos/lit-theme-editor';
8
+ import { createComponent } from '@dxos/lit-ui/react';
9
+
10
+ import '@dxos/lit-theme-editor/dx-theme-editor.pcss';
11
+
12
+ const DxThemeEditor = createComponent({
13
+ tagName: 'dx-theme-editor',
14
+ elementClass: NaturalDxThemeEditor,
15
+ react: React,
16
+ });
17
+
18
+ export const ThemeEditor = memo(DxThemeEditor);
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ // export * from './DocsContainer';
6
+ export * from './ThemeEditor';
7
+ export * from './CardContainers';
@@ -3,5 +3,5 @@
3
3
  //
4
4
 
5
5
  export * from './withLayout';
6
- export * from './withSignals';
7
6
  export * from './withTheme';
7
+ export * from './withThemeEditor';
@@ -36,7 +36,7 @@ export type WithLayoutProps = ThemedClassName<ProviderOptions & { Container?: FC
36
36
  export const withLayout = ({
37
37
  classNames,
38
38
  fullscreen,
39
- Container = fullscreen ? FixedContainer : DefaultContainer,
39
+ Container = fullscreen ? FullscreenContainer : DefaultContainer,
40
40
  ...providedOptions
41
41
  }: WithLayoutProps = {}): Decorator => {
42
42
  // TODO(burdon): Inspect "fullscreen" parameter in context.
@@ -52,7 +52,10 @@ export const withLayout = ({
52
52
  };
53
53
  };
54
54
 
55
- export const DefaultContainer: FC<ContainerProps> = ({ children, classNames }) => {
55
+ // TODO(burdon): Use consistently.
56
+ export const layoutCentered = 'bg-deckSurface justify-center overflow-y-auto';
57
+
58
+ export const DefaultContainer = ({ children, classNames }: ContainerProps) => {
56
59
  return (
57
60
  <div role='none' className={mx(classNames)}>
58
61
  {children}
@@ -60,7 +63,7 @@ export const DefaultContainer: FC<ContainerProps> = ({ children, classNames }) =
60
63
  );
61
64
  };
62
65
 
63
- export const FixedContainer: FC<ContainerProps> = ({ children, classNames }) => {
66
+ export const FullscreenContainer = ({ children, classNames }: ContainerProps) => {
64
67
  return (
65
68
  <div role='none' className={mx('fixed inset-0 flex overflow-hidden', classNames)}>
66
69
  {children}
@@ -68,12 +71,12 @@ export const FixedContainer: FC<ContainerProps> = ({ children, classNames }) =>
68
71
  );
69
72
  };
70
73
 
71
- export const ColumnContainer: FC<ContainerProps> = ({ children, classNames = 'w-[30rem]', ...props }) => {
74
+ export const ColumnContainer = ({ children, classNames = 'w-[30rem]', ...props }: ContainerProps) => {
72
75
  return (
73
- <FixedContainer classNames='justify-center bg-modalSurface' {...props}>
76
+ <FullscreenContainer classNames='justify-center bg-modalSurface' {...props}>
74
77
  <div role='none' className={mx('flex flex-col h-full overflow-y-auto bg-baseSurface', classNames)}>
75
78
  {children}
76
79
  </div>
77
- </FixedContainer>
80
+ </FullscreenContainer>
78
81
  );
79
82
  };
@@ -2,82 +2,28 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { addons } from '@storybook/preview-api';
6
5
  import { type Decorator } from '@storybook/react';
7
- import React, { memo, useCallback, useEffect, useState } from 'react';
8
- import { DARK_MODE_EVENT_NAME } from 'storybook-dark-mode';
6
+ import React, { memo } from 'react';
9
7
 
10
- import { DxThemeEditor as NaturalDxThemeEditor } from '@dxos/lit-theme-editor';
11
- import '@dxos/lit-theme-editor/dx-theme-editor.pcss';
12
- import { createComponent } from '@dxos/lit-ui/react';
13
- import { type ThemeMode, ThemeProvider, Tooltip, Dialog, IconButton } from '@dxos/react-ui';
8
+ import { type ThemeMode, ThemeProvider, Tooltip } from '@dxos/react-ui';
14
9
  import { defaultTx } from '@dxos/react-ui-theme';
15
- import { PARAM_KEY } from '@dxos/theme-editor-addon';
16
-
17
- const DxThemeEditor = createComponent({
18
- tagName: 'dx-theme-editor',
19
- elementClass: NaturalDxThemeEditor,
20
- react: React,
21
- });
22
10
 
23
11
  /**
24
- * Changes theme based on storybook toolbar toggle.
12
+ * Adds theme decorator.
25
13
  */
26
14
  export const withTheme: Decorator = (Story, context) => {
15
+ const {
16
+ globals: { theme },
17
+ parameters: { translations },
18
+ } = context;
19
+
27
20
  // Prevent re-rendering of the story.
28
21
  const MemoizedStory = memo(Story);
29
- const [themeMode, setThemeMode] = useState<ThemeMode>('dark');
30
- const [editorOpen, setEditorOpen] = useState(false);
31
-
32
- const handleOpenChange = useCallback((nextOpen: boolean) => {
33
- setEditorOpen(nextOpen);
34
- }, []);
35
-
36
- // https://www.npmjs.com/package/storybook-dark-mode
37
- // NOTE: The `useDarkMode` hook causes the story to continually re-render.
38
- // NOTE: Changing the theme will cause the story to remount.
39
- useEffect(() => {
40
- const handleDarkModeUpdate = (darkMode: boolean) => setThemeMode(darkMode ? 'dark' : 'light');
41
- addons.getChannel().on(DARK_MODE_EVENT_NAME, handleDarkModeUpdate);
42
- return () => addons.getChannel().off(DARK_MODE_EVENT_NAME, handleDarkModeUpdate);
43
- }, []);
44
-
45
- useEffect(() => {
46
- const openEditor = () => {
47
- handleOpenChange(true);
48
- };
49
- addons.getChannel().on(PARAM_KEY, openEditor);
50
- return () => addons.getChannel().off(PARAM_KEY, openEditor);
51
- }, []);
52
22
 
53
23
  return (
54
- <ThemeProvider tx={defaultTx} themeMode={themeMode} resourceExtensions={context?.parameters?.translations} noCache>
24
+ <ThemeProvider tx={defaultTx} themeMode={theme as ThemeMode} resourceExtensions={translations} noCache>
55
25
  <Tooltip.Provider>
56
26
  <MemoizedStory />
57
- <Dialog.Root open={editorOpen} onOpenChange={handleOpenChange} modal={false}>
58
- <div
59
- role='none'
60
- className='dx-dialog__overlay bg-transparent pointer-events-none'
61
- style={{ placeContent: 'end' }}
62
- >
63
- <Dialog.Content
64
- classNames='relative box-content py-0 px-2 md:is-[35rem] md:max-is-none overflow-y-auto layout-contain pointer-events-auto'
65
- style={{ maxBlockSize: '50dvh' }}
66
- onInteractOutside={(event) => event.preventDefault()}
67
- >
68
- <Dialog.Title srOnly>Theme Editor</Dialog.Title>
69
- {editorOpen && <DxThemeEditor />}
70
- <Dialog.Close asChild>
71
- <IconButton
72
- iconOnly
73
- icon='ph--x--regular'
74
- label='Close'
75
- classNames='absolute block-start-2 inline-end-2'
76
- />
77
- </Dialog.Close>
78
- </Dialog.Content>
79
- </div>
80
- </Dialog.Root>
81
27
  </Tooltip.Provider>
82
28
  </ThemeProvider>
83
29
  );
@@ -0,0 +1,28 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Decorator } from '@storybook/react';
6
+ import React, { memo } from 'react';
7
+
8
+ import { ThemeEditor } from '../components';
9
+
10
+ /**
11
+ * Show theme editor.
12
+ */
13
+ // TODO(burdon): Ideally move to storybook-addon-theme, but this has a build issue since the addon would depend on the vite theme plugin.
14
+ export const withThemeEditor: Decorator = (Story, context) => {
15
+ // Prevent re-rendering of the story.
16
+ const MemoizedStory = memo(Story);
17
+
18
+ return (
19
+ <>
20
+ <MemoizedStory />
21
+ <div className='absolute top-4 bottom-4 right-4 z-10'>
22
+ <div className='h-full is-[35rem] overflow-auto bg-baseSurface border border-separator rounded'>
23
+ <ThemeEditor />
24
+ </div>
25
+ </div>
26
+ </>
27
+ );
28
+ };
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ import { registerSignalsRuntime } from '@dxos/echo-signals/react';
6
6
 
7
7
  export { type Meta } from '@storybook/react';
8
8
 
9
+ export * from './components';
9
10
  export * from './decorators';
10
11
  export * from './util';
11
12
 
@@ -0,0 +1,62 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
+ import React from 'react';
9
+ import { expect, fn, userEvent, within } from 'storybook/test';
10
+
11
+ import { log } from '@dxos/log';
12
+ import { withTheme } from '@dxos/storybook-utils';
13
+
14
+ import { TEST_ID, Test, type TestProps } from './Test';
15
+
16
+ /**
17
+ * Storybook sanity test.
18
+ */
19
+ const meta: Meta<TestProps> = {
20
+ title: 'devtools/storybook-utils/Test',
21
+ component: Test,
22
+ render: (args) => <Test {...{ 'data-testid': TEST_ID }} {...args} />,
23
+ decorators: [withTheme],
24
+ };
25
+
26
+ export default meta;
27
+
28
+ type Story = StoryObj<TestProps>;
29
+
30
+ export const Default: Story = {
31
+ // Interactions tab.
32
+ // https://storybook.js.org/docs/writing-stories/play-function?renderer=react#writing-stories-with-the-play-function
33
+ play: async ({ args, canvasElement }: any) => {
34
+ const canvas = within(canvasElement);
35
+ await userEvent.click(canvas.getByRole('button'));
36
+ await expect(args.onClick).toHaveBeenCalled();
37
+ await expect(canvas.getByText(args.label)).toBeInTheDocument();
38
+ },
39
+ args: {
40
+ variant: 'primary',
41
+ icon: 'ph--rocket-launch--regular',
42
+ label: 'Composer',
43
+ onClick: fn(),
44
+ },
45
+ parameters: {
46
+ docs: {
47
+ description: {
48
+ component: 'A basic button component.',
49
+ },
50
+ },
51
+ },
52
+ };
53
+
54
+ export const WithLog: Story = {
55
+ args: {
56
+ icon: 'ph--rocket-launch--regular',
57
+ label: 'Test',
58
+ onClick: () => {
59
+ log.info('Hello, world!');
60
+ },
61
+ },
62
+ };
@@ -0,0 +1,40 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { composeStories } from '@storybook/react';
6
+ import { render, screen, fireEvent } from '@testing-library/react';
7
+ import React from 'react';
8
+ import { describe, expect, it, vi } from 'vitest';
9
+
10
+ import { ThemeProvider } from '@dxos/react-ui';
11
+
12
+ import { TEST_ID, Test } from './Test';
13
+ import * as stories from './Test.stories';
14
+
15
+ const { Default } = composeStories(stories);
16
+
17
+ /**
18
+ * Vitest sanity test (should be visible in the storybook).
19
+ * https://storybook.js.org/docs/writing-tests/integrations/vitest-addon
20
+ */
21
+ // TODO(burdon): Not working.
22
+ describe('Test', () => {
23
+ it('should render', async () => {
24
+ await Default.run();
25
+ expect(screen.getByTestId(TEST_ID)).to.exist;
26
+ });
27
+
28
+ it('calls onClick when clicked', () => {
29
+ const handleClick = vi.fn();
30
+ const { container } = render(
31
+ <ThemeProvider>
32
+ <Test id='test' icon='ph--x--regular' label='Test' onClick={handleClick} />
33
+ </ThemeProvider>,
34
+ );
35
+
36
+ fireEvent.click(container.querySelector('#test')!);
37
+ expect(handleClick).toHaveBeenCalledTimes(1);
38
+ expect(screen.debug()).toMatchSnapshot();
39
+ });
40
+ });
@@ -0,0 +1,15 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { IconButton, type IconButtonProps } from '@dxos/react-ui';
8
+
9
+ export const TEST_ID = 'test';
10
+
11
+ export type TestProps = IconButtonProps;
12
+
13
+ export const Test = (props: TestProps) => {
14
+ return <IconButton size={4} {...props} />;
15
+ };
@@ -0,0 +1,3 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Test > calls onClick when clicked 1`] = `undefined`;
@@ -0,0 +1,14 @@
1
+ {/* Copyright 2023 DXOS.org */}
2
+
3
+ import { Meta, Story, Canvas } from '@storybook/addon-docs/blocks';
4
+ import * as TestStories from './Test.stories';
5
+
6
+ <Meta title='MDX/Test' of={TestStories} />
7
+
8
+ # Test
9
+
10
+ Test `MDX` for the `Test` component.
11
+
12
+ <Canvas>
13
+ <Story of={TestStories} />
14
+ </Canvas>
@@ -0,0 +1,11 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ // https://github.com/testing-library/jest-dom#with-vitest
6
+ import '@testing-library/jest-dom/vitest';
7
+
8
+ // https://github.com/jsdom/jsdom/issues/3368#issuecomment-1396749033
9
+ import ResizeObserver from 'resize-observer-polyfill';
10
+
11
+ global.ResizeObserver = ResizeObserver;
package/README.yml DELETED
@@ -1 +0,0 @@
1
- guideUrl: https://docs.dxos.org/guide/react/aurora/