@dxos/react-ui 0.8.2-main.f081794 → 0.8.2-main.fbd8ed0

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 (112) hide show
  1. package/dist/lib/browser/index.mjs +1606 -1073
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +1941 -1406
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +1606 -1073
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/Avatars/Avatar.stories.d.ts +2 -2
  11. package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
  12. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts +0 -1
  13. package/dist/types/src/components/Avatars/AvatarGroup.stories.d.ts.map +1 -1
  14. package/dist/types/src/components/Buttons/Button.stories.d.ts +10 -44
  15. package/dist/types/src/components/Buttons/Button.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/Buttons/IconButton.d.ts +4 -5
  17. package/dist/types/src/components/Buttons/IconButton.d.ts.map +1 -1
  18. package/dist/types/src/components/Buttons/IconButton.stories.d.ts +7 -6
  19. package/dist/types/src/components/Buttons/IconButton.stories.d.ts.map +1 -1
  20. package/dist/types/src/components/Buttons/Toggle.stories.d.ts.map +1 -1
  21. package/dist/types/src/components/Buttons/ToggleGroup.stories.d.ts +1 -4
  22. package/dist/types/src/components/Buttons/ToggleGroup.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/Clipboard/ClipboardProvider.d.ts.map +1 -1
  24. package/dist/types/src/components/Clipboard/CopyButton.d.ts +2 -1
  25. package/dist/types/src/components/Clipboard/CopyButton.d.ts.map +1 -1
  26. package/dist/types/src/components/Clipboard/index.d.ts +2 -2
  27. package/dist/types/src/components/DensityProvider/DensityProvider.d.ts.map +1 -1
  28. package/dist/types/src/components/Dialogs/AlertDialog.stories.d.ts +2 -2
  29. package/dist/types/src/components/Dialogs/AlertDialog.stories.d.ts.map +1 -1
  30. package/dist/types/src/components/Dialogs/Dialog.d.ts +2 -2
  31. package/dist/types/src/components/Dialogs/Dialog.d.ts.map +1 -1
  32. package/dist/types/src/components/Dialogs/Dialog.stories.d.ts +2 -2
  33. package/dist/types/src/components/Dialogs/Dialog.stories.d.ts.map +1 -1
  34. package/dist/types/src/components/ElevationProvider/ElevationProvider.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 +33 -159
  38. package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
  39. package/dist/types/src/components/Lists/ListDropIndicator.d.ts.map +1 -1
  40. package/dist/types/src/components/Lists/Tree.stories.d.ts.map +1 -1
  41. package/dist/types/src/components/Lists/TreeDropIndicator.d.ts.map +1 -1
  42. package/dist/types/src/components/Lists/Treegrid.stories.d.ts +1 -1
  43. package/dist/types/src/components/Lists/Treegrid.stories.d.ts.map +1 -1
  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/Main/useSwipeToDismiss.d.ts.map +1 -1
  47. package/dist/types/src/components/Message/Message.stories.d.ts +2 -2
  48. package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
  49. package/dist/types/src/components/Popover/Popover.d.ts +15 -6
  50. package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
  51. package/dist/types/src/components/Popover/Popover.stories.d.ts +5 -1
  52. package/dist/types/src/components/Popover/Popover.stories.d.ts.map +1 -1
  53. package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  54. package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
  55. package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
  57. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +1 -1
  58. package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
  59. package/dist/types/src/components/Toast/Toast.stories.d.ts +2 -2
  60. package/dist/types/src/components/Toast/Toast.stories.d.ts.map +1 -1
  61. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  62. package/dist/types/src/components/Tooltip/Tooltip.d.ts +94 -20
  63. package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
  64. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts +41 -17
  65. package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
  66. package/dist/types/src/components/index.d.ts +1 -1
  67. package/dist/types/src/components/index.d.ts.map +1 -1
  68. package/dist/types/src/hooks/useDensityContext.d.ts.map +1 -1
  69. package/dist/types/src/hooks/useElevationContext.d.ts.map +1 -1
  70. package/dist/types/src/hooks/useIconHref.d.ts.map +1 -1
  71. package/dist/types/src/hooks/useSafeCollisionPadding.d.ts.map +1 -1
  72. package/dist/types/src/hooks/useVisualViewport.d.ts.map +1 -1
  73. package/dist/types/src/playground/Controls.stories.d.ts +1 -1
  74. package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
  75. package/dist/types/src/playground/Custom.stories.d.ts +8 -0
  76. package/dist/types/src/playground/Custom.stories.d.ts.map +1 -0
  77. package/dist/types/src/testing/decorators/withVariants.d.ts.map +1 -1
  78. package/dist/types/tsconfig.tsbuildinfo +1 -1
  79. package/package.json +14 -13
  80. package/src/components/Avatars/Avatar.stories.tsx +27 -27
  81. package/src/components/Avatars/Avatar.tsx +1 -1
  82. package/src/components/Avatars/AvatarGroup.stories.tsx +4 -5
  83. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +2 -2
  84. package/src/components/Buttons/Button.stories.tsx +19 -14
  85. package/src/components/Buttons/IconButton.stories.tsx +9 -10
  86. package/src/components/Buttons/IconButton.tsx +8 -33
  87. package/src/components/Buttons/Toggle.stories.tsx +2 -2
  88. package/src/components/Buttons/ToggleGroup.stories.tsx +3 -7
  89. package/src/components/Clipboard/CopyButton.tsx +22 -24
  90. package/src/components/Dialogs/AlertDialog.stories.tsx +4 -11
  91. package/src/components/Dialogs/Dialog.stories.tsx +3 -3
  92. package/src/components/Dialogs/Dialog.tsx +7 -4
  93. package/src/components/Input/Input.stories.tsx +67 -56
  94. package/src/components/Input/Input.tsx +1 -0
  95. package/src/components/Lists/Tree.stories.tsx +2 -2
  96. package/src/components/Lists/Treegrid.stories.tsx +12 -12
  97. package/src/components/Main/Main.stories.tsx +2 -2
  98. package/src/components/Menus/ContextMenu.stories.tsx +2 -2
  99. package/src/components/Menus/DropdownMenu.stories.tsx +2 -2
  100. package/src/components/Message/Message.stories.tsx +3 -3
  101. package/src/components/Popover/Popover.stories.tsx +2 -2
  102. package/src/components/Popover/Popover.tsx +8 -4
  103. package/src/components/ScrollArea/ScrollArea.stories.tsx +2 -2
  104. package/src/components/ScrollArea/ScrollArea.tsx +3 -0
  105. package/src/components/Toast/Toast.stories.tsx +15 -10
  106. package/src/components/Toolbar/Toolbar.stories.tsx +2 -2
  107. package/src/components/Tooltip/Tooltip.stories.tsx +43 -18
  108. package/src/components/Tooltip/Tooltip.tsx +748 -58
  109. package/src/components/index.ts +1 -1
  110. package/src/playground/Controls.stories.tsx +2 -2
  111. package/src/playground/Custom.stories.tsx +137 -0
  112. package/src/playground/Typography.stories.tsx +2 -2
@@ -5,6 +5,7 @@
5
5
  import '@dxos-theme';
6
6
 
7
7
  import { CaretLeft, CaretRight } from '@phosphor-icons/react';
8
+ import { type StoryObj, type Meta } from '@storybook/react';
8
9
  import React from 'react';
9
10
 
10
11
  import { Button, ButtonGroup, type ButtonProps } from './Button';
@@ -31,32 +32,36 @@ const DefaultStory = ({ children, ...args }: Omit<ButtonProps, 'ref'>) => {
31
32
  );
32
33
  };
33
34
 
34
- const defaults = { children: 'Test' };
35
+ const meta: Meta<typeof Button> = {
36
+ title: 'ui/react-ui-core/Button',
37
+ component: Button,
38
+ render: DefaultStory,
39
+ decorators: [withVariants(), withTheme],
40
+ parameters: { chromatic: { disableSnapshot: false } },
41
+ };
42
+
43
+ export default meta;
44
+
45
+ type Story = StoryObj<typeof meta>;
35
46
 
36
- export const Default = {
47
+ const defaults: Story['args'] = { children: 'Test' };
48
+
49
+ export const Default: Story = {
37
50
  args: { ...defaults, variant: 'default' },
38
51
  };
39
52
 
40
- export const Primary = {
53
+ export const Primary: Story = {
41
54
  args: { ...defaults, variant: 'primary' },
42
55
  };
43
56
 
44
- export const Destructive = {
57
+ export const Destructive: Story = {
45
58
  args: { ...defaults, variant: 'destructive' },
46
59
  };
47
60
 
48
- export const Outline = {
61
+ export const Outline: Story = {
49
62
  args: { ...defaults, variant: 'outline' },
50
63
  };
51
64
 
52
- export const Ghost = {
65
+ export const Ghost: Story = {
53
66
  args: { ...defaults, variant: 'ghost' },
54
67
  };
55
-
56
- export default {
57
- title: 'ui/react-ui-core/Button',
58
- component: Button,
59
- decorators: [withVariants(), withTheme],
60
- render: DefaultStory,
61
- parameters: { chromatic: { disableSnapshot: false } },
62
- };
@@ -6,22 +6,18 @@ import '@dxos-theme';
6
6
 
7
7
  import React from 'react';
8
8
 
9
- import { IconButton } from './IconButton';
9
+ import { IconButton, type IconButtonProps } from './IconButton';
10
10
  import { withTheme } from '../../testing';
11
11
  import { Tooltip } from '../Tooltip';
12
12
 
13
- type StorybookIconButtonProps = {
14
- iconOnly?: boolean;
15
- };
16
-
17
- const StorybookIconButton = (props: StorybookIconButtonProps) => {
13
+ const DefaultStory = (props: IconButtonProps) => {
18
14
  return (
19
15
  <Tooltip.Provider>
20
16
  <div className='mbe-4'>
21
- <IconButton label='Bold' icon='ph--text-b--bold' {...props} />
17
+ <IconButton {...props} />
22
18
  </div>
23
19
  <div className='mbe-4'>
24
- <IconButton iconOnly label='Bold' icon='ph--text-b--bold' {...props} />
20
+ <IconButton iconOnly {...props} />
25
21
  </div>
26
22
  </Tooltip.Provider>
27
23
  );
@@ -30,11 +26,14 @@ const StorybookIconButton = (props: StorybookIconButtonProps) => {
30
26
  export default {
31
27
  title: 'ui/react-ui-core/IconButton',
32
28
  component: IconButton,
33
- render: StorybookIconButton,
29
+ render: DefaultStory,
34
30
  decorators: [withTheme],
35
31
  parameters: { chromatic: { disableSnapshot: false } },
36
32
  };
37
33
 
38
34
  export const Default = {
39
- args: {},
35
+ args: {
36
+ label: 'Bold',
37
+ icon: 'ph--text-b--regular',
38
+ },
40
39
  };
@@ -2,60 +2,35 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { forwardRef, type ReactNode, type MutableRefObject, useState } from 'react';
5
+ import React, { forwardRef, type MutableRefObject } from 'react';
6
6
 
7
7
  import { Button, type ButtonProps } from './Button';
8
8
  import { useThemeContext } from '../../hooks';
9
9
  import { type ThemedClassName } from '../../util';
10
10
  import { Icon, type IconProps } from '../Icon';
11
- import { Tooltip, type TooltipContentProps } from '../Tooltip';
11
+ import { Tooltip, type TooltipSide } from '../Tooltip';
12
12
 
13
13
  type IconButtonProps = Omit<ButtonProps, 'children'> &
14
14
  Pick<IconProps, 'icon' | 'size'> & {
15
- label: NonNullable<ReactNode>;
15
+ label: string;
16
16
  iconOnly?: boolean;
17
17
  noTooltip?: boolean;
18
18
  caretDown?: boolean;
19
- // TODO(burdon): Create slots abstraction?
20
19
  iconClassNames?: ThemedClassName<any>['classNames'];
21
20
  tooltipPortal?: boolean;
22
- tooltipZIndex?: string;
23
- tooltipSide?: TooltipContentProps['side'];
21
+ tooltipSide?: TooltipSide;
24
22
  suppressNextTooltip?: MutableRefObject<boolean>;
25
23
  };
26
24
 
27
25
  const IconOnlyButton = forwardRef<HTMLButtonElement, IconButtonProps>(
28
- (
29
- { noTooltip, tooltipPortal = true, tooltipZIndex: zIndex, tooltipSide, suppressNextTooltip, ...props },
30
- forwardedRef,
31
- ) => {
32
- const [triggerTooltipOpen, setTriggerTooltipOpen] = useState(false);
26
+ ({ noTooltip, tooltipPortal = true, tooltipSide, suppressNextTooltip, ...props }, forwardedRef) => {
33
27
  if (noTooltip) {
34
28
  return <LabelledIconButton {...props} ref={forwardedRef} />;
35
29
  }
36
- const content = (
37
- <Tooltip.Content {...(zIndex && { style: { zIndex } })} side={tooltipSide}>
38
- {props.label}
39
- <Tooltip.Arrow />
40
- </Tooltip.Content>
41
- );
42
30
  return (
43
- <Tooltip.Root
44
- open={triggerTooltipOpen}
45
- onOpenChange={(nextOpen) => {
46
- if (suppressNextTooltip?.current) {
47
- setTriggerTooltipOpen(false);
48
- suppressNextTooltip.current = false;
49
- } else {
50
- setTriggerTooltipOpen(nextOpen);
51
- }
52
- }}
53
- >
54
- <Tooltip.Trigger asChild>
55
- <LabelledIconButton {...props} ref={forwardedRef} />
56
- </Tooltip.Trigger>
57
- {tooltipPortal ? <Tooltip.Portal>{content}</Tooltip.Portal> : content}
58
- </Tooltip.Root>
31
+ <Tooltip.Trigger asChild content={props.label} side={tooltipSide} suppressNextTooltip={suppressNextTooltip}>
32
+ <LabelledIconButton {...props} ref={forwardedRef} />
33
+ </Tooltip.Trigger>
59
34
  );
60
35
  },
61
36
  );
@@ -12,7 +12,7 @@ import { withTheme } from '../../testing';
12
12
 
13
13
  type StorybookToggleProps = {};
14
14
 
15
- const StorybookToggle = (props: StorybookToggleProps) => {
15
+ const DefaultStory = (props: StorybookToggleProps) => {
16
16
  return (
17
17
  <Toggle {...props}>
18
18
  <TextB />
@@ -23,7 +23,7 @@ const StorybookToggle = (props: StorybookToggleProps) => {
23
23
  export default {
24
24
  title: 'ui/react-ui-core/Toggle',
25
25
  component: Toggle,
26
- render: StorybookToggle,
26
+ render: DefaultStory,
27
27
  decorators: [withTheme],
28
28
  parameters: { chromatic: { disableSnapshot: false } },
29
29
  };
@@ -10,12 +10,8 @@ import React from 'react';
10
10
  import { ToggleGroup, ToggleGroupItem, type ToggleGroupProps } from './ToggleGroup';
11
11
  import { withTheme } from '../../testing';
12
12
 
13
- type StorybookToggleGroupProps = {
14
- type: ToggleGroupProps['type'];
15
- };
16
-
17
- // TODO(burdon): ToggleGroup.Item.
18
- const StorybookToggleGroup = (props: StorybookToggleGroupProps) => {
13
+ // TODO(burdon): Create Radix-style Root, Item, etc?
14
+ const DefaultStory = (props: ToggleGroupProps) => {
19
15
  return (
20
16
  <ToggleGroup {...props}>
21
17
  <ToggleGroupItem value='textb'>
@@ -31,7 +27,7 @@ const StorybookToggleGroup = (props: StorybookToggleGroupProps) => {
31
27
  export default {
32
28
  title: 'ui/react-ui-core/ToggleGroup',
33
29
  component: ToggleGroup,
34
- render: StorybookToggleGroup,
30
+ render: DefaultStory,
35
31
  decorators: [withTheme],
36
32
  parameters: { chromatic: { disableSnapshot: false } },
37
33
  };
@@ -3,15 +3,15 @@
3
3
  //
4
4
 
5
5
  import { type IconProps } from '@phosphor-icons/react';
6
- import React, { useState } from 'react';
6
+ import React from 'react';
7
7
 
8
8
  import { mx } from '@dxos/react-ui-theme';
9
9
 
10
10
  import { useClipboard } from './ClipboardProvider';
11
- import { Button, type ButtonProps } from '../Buttons';
11
+ import { Button, type ButtonProps, IconButton } from '../Buttons';
12
12
  import { Icon } from '../Icon';
13
13
  import { useTranslation } from '../ThemeProvider';
14
- import { Tooltip } from '../Tooltip';
14
+ import { type TooltipScopedProps, useTooltipContext } from '../Tooltip';
15
15
 
16
16
  export type CopyButtonProps = ButtonProps & {
17
17
  value: string;
@@ -48,31 +48,29 @@ type CopyButtonIconOnlyProps = CopyButtonProps & {
48
48
  label?: string;
49
49
  };
50
50
 
51
- export const CopyButtonIconOnly = ({ value, classNames, iconProps, variant, ...props }: CopyButtonIconOnlyProps) => {
51
+ export const CopyButtonIconOnly = ({
52
+ __scopeTooltip,
53
+ value,
54
+ classNames,
55
+ iconProps,
56
+ variant,
57
+ ...props
58
+ }: TooltipScopedProps<CopyButtonIconOnlyProps>) => {
52
59
  const { t } = useTranslation('os');
53
60
  const { textValue, setTextValue } = useClipboard();
54
61
  const isCopied = textValue === value;
55
62
  const label = isCopied ? t('copy success label') : props.label ?? t('copy label');
56
- const [open, setOpen] = useState(false);
63
+ const { onOpen } = useTooltipContext('CopyButton', __scopeTooltip);
57
64
  return (
58
- <Tooltip.Root delayDuration={1500} open={open} onOpenChange={setOpen}>
59
- <Tooltip.Portal>
60
- <Tooltip.Content side='bottom' sideOffset={12}>
61
- <span>{label}</span>
62
- <Tooltip.Arrow />
63
- </Tooltip.Content>
64
- </Tooltip.Portal>
65
- <Tooltip.Trigger
66
- aria-label={label}
67
- {...props}
68
- onClick={() => setTextValue(value).then(() => setOpen(true))}
69
- data-testid='copy-invitation'
70
- asChild
71
- >
72
- <Button variant={variant} classNames={['inline-flex flex-col justify-center', classNames]}>
73
- <Icon icon='ph--copy--regular' size={5 as any} {...iconProps} />
74
- </Button>
75
- </Tooltip.Trigger>
76
- </Tooltip.Root>
65
+ <IconButton
66
+ iconOnly
67
+ label={label!}
68
+ icon='ph--copy--regular'
69
+ size={5}
70
+ variant={variant}
71
+ classNames={['inline-flex flex-col justify-center', classNames]}
72
+ onClick={() => setTextValue(value).then(onOpen)}
73
+ data-testid='copy-invitation'
74
+ />
77
75
  );
78
76
  };
@@ -11,23 +11,16 @@ import { withTheme } from '../../testing';
11
11
  import { Button } from '../Buttons';
12
12
  import { Toolbar } from '../Toolbar';
13
13
 
14
- type StorybookAlertDialogProps = Partial<{
14
+ type DefaultStoryProps = Partial<{
15
15
  title: string;
16
16
  description: string;
17
17
  body: string;
18
- cancelTrigger: string; // TODO(burdon): Why trigger?
18
+ cancelTrigger: string;
19
19
  actionTrigger: string;
20
20
  openTrigger: string;
21
21
  }>;
22
22
 
23
- const StorybookAlertDialog = ({
24
- title,
25
- openTrigger,
26
- description,
27
- body,
28
- cancelTrigger,
29
- actionTrigger,
30
- }: StorybookAlertDialogProps) => {
23
+ const DefaultStory = ({ title, openTrigger, description, body, cancelTrigger, actionTrigger }: DefaultStoryProps) => {
31
24
  return (
32
25
  <AlertDialog.Root defaultOpen>
33
26
  <AlertDialog.Trigger asChild>
@@ -56,7 +49,7 @@ const StorybookAlertDialog = ({
56
49
  export default {
57
50
  title: 'ui/react-ui-core/AlertDialog',
58
51
  component: AlertDialog,
59
- render: StorybookAlertDialog,
52
+ render: DefaultStory,
60
53
  decorators: [withTheme],
61
54
  parameters: { chromatic: { disableSnapshot: false } },
62
55
  };
@@ -10,7 +10,7 @@ import { Dialog } from './Dialog';
10
10
  import { withTheme } from '../../testing';
11
11
  import { Button } from '../Buttons';
12
12
 
13
- type StorybookDialogProps = Partial<{
13
+ type DefaultStoryProps = Partial<{
14
14
  title: string;
15
15
  description: string;
16
16
  body: string;
@@ -19,7 +19,7 @@ type StorybookDialogProps = Partial<{
19
19
  blockAlign: 'center' | 'start';
20
20
  }>;
21
21
 
22
- const StorybookDialog = ({ title, openTrigger, description, body, closeTrigger, blockAlign }: StorybookDialogProps) => {
22
+ const DefaultStory = ({ title, openTrigger, description, body, closeTrigger, blockAlign }: DefaultStoryProps) => {
23
23
  return (
24
24
  <Dialog.Root defaultOpen>
25
25
  <Dialog.Trigger asChild>
@@ -42,7 +42,7 @@ const StorybookDialog = ({ title, openTrigger, description, body, closeTrigger,
42
42
  export default {
43
43
  title: 'ui/react-ui-core/Dialog',
44
44
  component: Dialog,
45
- render: StorybookDialog,
45
+ render: DefaultStory,
46
46
  decorators: [withTheme],
47
47
  parameters: { chromatic: { disableSnapshot: false } },
48
48
  };
@@ -81,11 +81,12 @@ const DialogClose: FunctionComponent<DialogCloseProps> = DialogClosePrimitive;
81
81
  type OverlayLayoutContextValue = { inOverlayLayout?: boolean };
82
82
  const DIALOG_OVERLAY_NAME = 'DialogOverlay';
83
83
  const DIALOG_CONTENT_NAME = 'DialogContent';
84
- const [OverlayLayoutProvider, useOverlayLayoutContext] = createContext<OverlayLayoutContextValue>(DIALOG_OVERLAY_NAME, {
85
- inOverlayLayout: false,
86
- });
84
+ const [OverlayLayoutProvider, useOverlayLayoutContext] = createContext<OverlayLayoutContextValue>(
85
+ DIALOG_OVERLAY_NAME,
86
+ {},
87
+ );
87
88
 
88
- type DialogOverlayProps = ThemedClassName<DialogOverlayPrimitiveProps> & { blockAlign?: 'center' | 'start' | 'end' };
89
+ type DialogOverlayProps = ThemedClassName<DialogOverlayPrimitiveProps & { blockAlign?: 'center' | 'start' | 'end' }>;
89
90
 
90
91
  const DialogOverlay: ForwardRefExoticComponent<DialogOverlayProps> = forwardRef<HTMLDivElement, DialogOverlayProps>(
91
92
  ({ classNames, children, blockAlign, ...props }, forwardedRef) => {
@@ -115,6 +116,8 @@ const DialogContent: ForwardRefExoticComponent<DialogContentProps> = forwardRef<
115
116
 
116
117
  return (
117
118
  <DialogContentPrimitive
119
+ // NOTE: Radix warning unless set to undefined.
120
+ // https://www.radix-ui.com/primitives/docs/components/dialog#description
118
121
  aria-describedby={undefined}
119
122
  {...props}
120
123
  className={tx(
@@ -4,28 +4,44 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
+ import { type StoryObj, type Meta } from '@storybook/react';
7
8
  import React from 'react';
8
9
 
9
10
  import { baseSurface, modalSurface, groupSurface, mx, surfaceShadow } from '@dxos/react-ui-theme';
10
11
  import { type MessageValence } from '@dxos/react-ui-types';
11
12
 
12
- import { Input } from './Input';
13
+ import {
14
+ type CheckboxProps,
15
+ Input,
16
+ type PinInputProps,
17
+ type SwitchProps,
18
+ type TextInputProps,
19
+ type TextAreaProps,
20
+ } from './Input';
13
21
  import { withTheme } from '../../testing';
14
22
 
15
- type StoryInputProps = Partial<{
23
+ type VariantMap = {
24
+ text: TextInputProps;
25
+ pin: PinInputProps;
26
+ textarea: TextAreaProps;
27
+ checkbox: CheckboxProps;
28
+ switch: SwitchProps;
29
+ };
30
+
31
+ type Variant = { [K in keyof VariantMap]: { type: K } & VariantMap[K] }[keyof VariantMap];
32
+
33
+ type BaseProps = Partial<{
34
+ kind: keyof VariantMap;
16
35
  label: string;
17
- placeholder: string;
18
- disabled: boolean;
19
- description: string;
20
36
  labelVisuallyHidden: boolean;
37
+ description: string;
21
38
  descriptionVisuallyHidden: boolean;
22
- type: 'default' | 'pin' | 'textarea' | 'checkbox' | 'switch';
23
- validationMessage: string;
24
39
  validationValence: MessageValence;
40
+ validationMessage: string;
25
41
  }>;
26
42
 
27
- const StoryInputContent = ({
28
- type = 'default',
43
+ const Wrapper = ({
44
+ kind,
29
45
  label,
30
46
  description,
31
47
  labelVisuallyHidden,
@@ -33,15 +49,17 @@ const StoryInputContent = ({
33
49
  validationValence,
34
50
  validationMessage,
35
51
  ...props
36
- }: StoryInputProps) => {
52
+ }: BaseProps) => {
37
53
  return (
38
54
  <Input.Root {...{ validationValence }}>
39
55
  <Input.Label srOnly={labelVisuallyHidden}>{label}</Input.Label>
40
- {type === 'pin' && <Input.PinInput {...props} />}
41
- {type === 'textarea' && <Input.TextArea {...props} />}
42
- {type === 'checkbox' && <Input.Checkbox {...props} />}
43
- {type === 'switch' && <Input.Switch {...props} />}
44
- {type === 'default' && <Input.TextInput {...props} />}
56
+
57
+ {kind === 'text' && <Input.TextInput {...props} />}
58
+ {kind === 'pin' && <Input.PinInput {...props} />}
59
+ {kind === 'textarea' && <Input.TextArea {...props} />}
60
+ {kind === 'checkbox' && <Input.Checkbox {...props} />}
61
+ {kind === 'switch' && <Input.Switch {...props} />}
62
+
45
63
  <Input.DescriptionAndValidation srOnly={descriptionVisuallyHidden}>
46
64
  {validationMessage && (
47
65
  <>
@@ -54,47 +72,37 @@ const StoryInputContent = ({
54
72
  );
55
73
  };
56
74
 
57
- const StoryInput = (props: StoryInputProps) => {
58
- // TODO(thure): Implement
75
+ const DefaultStory = (props: BaseProps) => {
59
76
  return (
60
77
  <div className='space-b-4'>
61
78
  <div className={mx(baseSurface, 'p-4')}>
62
- <StoryInputContent {...props} />
79
+ <Wrapper {...props} />
63
80
  </div>
64
81
  <div className={mx(groupSurface, 'p-4 rounded-lg', surfaceShadow({ elevation: 'positioned' }))}>
65
- <StoryInputContent {...props} />
82
+ <Wrapper {...props} />
66
83
  </div>
67
84
  <div className={mx(modalSurface, 'p-4 rounded-lg', surfaceShadow({ elevation: 'dialog' }))}>
68
- <StoryInputContent {...props} />
85
+ <Wrapper {...props} />
69
86
  </div>
70
87
  </div>
71
88
  );
72
89
  };
73
90
 
74
- export default {
91
+ const meta: Meta<BaseProps> = {
75
92
  title: 'ui/react-ui-core/Input',
76
- component: Input,
77
- render: StoryInput,
78
- // TODO(thure): Refactor.
79
- argTypes: {
80
- label: { control: 'text' },
81
- description: { control: 'text' },
82
- validationMessage: { control: 'text' },
83
- validationValence: {
84
- control: 'select',
85
- options: ['success', 'info', 'warning', 'error'],
86
- },
87
- type: {
88
- control: 'select',
89
- options: ['default', 'textarea', 'pin'],
90
- },
91
- },
93
+ component: Input.Root,
94
+ render: DefaultStory,
92
95
  decorators: [withTheme],
93
96
  parameters: { chromatic: { disableSnapshot: false } },
94
97
  };
95
98
 
96
- export const Default = {
99
+ export default meta;
100
+
101
+ type Story = StoryObj<BaseProps & Variant>;
102
+
103
+ export const Default: Story = {
97
104
  args: {
105
+ kind: 'text',
98
106
  label: 'Hello',
99
107
  placeholder: 'This is an input',
100
108
  disabled: false,
@@ -103,12 +111,12 @@ export const Default = {
103
111
  descriptionVisuallyHidden: false,
104
112
  validationMessage: '',
105
113
  validationValence: undefined,
106
- length: 6,
107
114
  },
108
115
  };
109
116
 
110
- export const DensityFine = {
117
+ export const DensityFine: Story = {
111
118
  args: {
119
+ kind: 'text',
112
120
  label: 'This is an Input with a density value of ‘fine’',
113
121
  placeholder: 'This is a density:fine input',
114
122
  disabled: false,
@@ -117,13 +125,13 @@ export const DensityFine = {
117
125
  descriptionVisuallyHidden: false,
118
126
  validationMessage: '',
119
127
  validationValence: undefined,
120
- length: 6,
121
128
  density: 'fine',
122
129
  },
123
130
  };
124
131
 
125
- export const Subdued = {
132
+ export const Subdued: Story = {
126
133
  args: {
134
+ kind: 'text',
127
135
  label: 'Hello',
128
136
  placeholder: 'This is a subdued input',
129
137
  disabled: false,
@@ -132,37 +140,40 @@ export const Subdued = {
132
140
  descriptionVisuallyHidden: false,
133
141
  validationMessage: '',
134
142
  validationValence: undefined,
135
- length: 6,
136
143
  variant: 'subdued',
137
144
  },
138
145
  };
139
146
 
140
- export const Disabled = {
147
+ export const Disabled: Story = {
141
148
  args: {
149
+ kind: 'text',
142
150
  label: 'Disabled',
143
151
  placeholder: 'This is a disabled input',
144
152
  disabled: true,
145
153
  },
146
154
  };
147
155
 
148
- export const LabelVisuallyHidden = {
156
+ export const LabelVisuallyHidden: Story = {
149
157
  args: {
158
+ kind: 'text',
150
159
  label: 'The label is for screen readers',
151
160
  labelVisuallyHidden: true,
152
161
  placeholder: 'The label for this input exists but is only read by screen readers',
153
162
  },
154
163
  };
155
164
 
156
- export const InputWithDescription = {
165
+ export const InputWithDescription: Story = {
157
166
  args: {
167
+ kind: 'text',
158
168
  label: 'Described input',
159
169
  placeholder: 'This input has an accessible description',
160
170
  description: 'This helper text is accessibly associated with the input.',
161
171
  },
162
172
  };
163
173
 
164
- export const InputWithErrorAndDescription = {
174
+ export const InputWithErrorAndDescription: Story = {
165
175
  args: {
176
+ kind: 'text',
166
177
  label: 'Described invalid input',
167
178
  placeholder: 'This input has both an accessible description and a validation error',
168
179
  description: 'This description is identified separately in the accessibility tree.',
@@ -171,8 +182,9 @@ export const InputWithErrorAndDescription = {
171
182
  },
172
183
  };
173
184
 
174
- export const InputWithValidationAndDescription = {
185
+ export const InputWithValidationAndDescription: Story = {
175
186
  args: {
187
+ kind: 'text',
176
188
  label: 'Described input with validation message',
177
189
  placeholder: 'This input is styled to express a validation valence',
178
190
  description: 'This description is extra.',
@@ -181,39 +193,38 @@ export const InputWithValidationAndDescription = {
181
193
  },
182
194
  };
183
195
 
184
- export const TextArea = {
196
+ export const TextArea: Story = {
185
197
  args: {
198
+ kind: 'textarea',
186
199
  label: 'This input is a text area input',
187
- type: 'textarea',
188
200
  description: 'Type a long paragraph',
189
201
  placeholder: 'Lorem ipsum dolor sit amet',
190
202
  },
191
203
  };
192
204
 
193
- export const PinInput = {
205
+ export const PinInput: Story = {
194
206
  args: {
207
+ kind: 'pin',
195
208
  label: 'This input is a PIN-style input',
196
- type: 'pin',
197
209
  length: 6,
198
210
  description: 'Type in secret you received',
199
211
  placeholder: '••••••',
200
212
  },
201
213
  };
202
214
 
203
- export const Checkbox = {
215
+ export const Checkbox: Story = {
204
216
  args: {
217
+ kind: 'checkbox',
205
218
  label: 'This is a checkbox',
206
- type: 'checkbox',
207
219
  description: 'It’s checked, indeterminate, or unchecked',
208
220
  size: 5,
209
- weight: 'bold',
210
221
  },
211
222
  };
212
223
 
213
224
  export const Switch = {
214
225
  args: {
226
+ kind: 'switch',
215
227
  label: 'This is a switch',
216
- type: 'switch',
217
228
  description: 'It’s either off... or on.',
218
229
  },
219
230
  };
@@ -342,6 +342,7 @@ export const Input = {
342
342
  export type {
343
343
  InputVariant,
344
344
  InputRootProps,
345
+ InputSharedProps,
345
346
  PinInputProps,
346
347
  TextInputProps,
347
348
  TextAreaProps,
@@ -51,14 +51,14 @@ const StorybookTreeItem = ({ data, prefix }: StorybookTreeItemProps) => {
51
51
  );
52
52
  };
53
53
 
54
- const StorybookTree = ({ data }: StorybookTreeProps) => {
54
+ const DefaultStory = ({ data }: StorybookTreeProps) => {
55
55
  return <StorybookTreeItem data={data} />;
56
56
  };
57
57
 
58
58
  export default {
59
59
  title: 'ui/react-ui-core/Tree',
60
60
  component: Tree,
61
- render: StorybookTree,
61
+ render: DefaultStory,
62
62
  decorators: [withTheme],
63
63
  parameters: { chromatic: { disableSnapshot: false } },
64
64
  };