@dxos/react-ui 0.8.4-main.69d29f4 → 0.8.4-main.6fa680abb7
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.
- package/dist/lib/browser/{chunk-CEKVHJ27.mjs → chunk-2FKSMWNY.mjs} +117 -117
- package/dist/lib/browser/chunk-2FKSMWNY.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +2804 -1957
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +56 -32
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node-esm/{chunk-2NHEX4AD.mjs → chunk-ZNBLTSHI.mjs} +117 -117
- package/dist/lib/node-esm/chunk-ZNBLTSHI.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +2804 -1957
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +56 -32
- package/dist/lib/node-esm/testing/index.mjs.map +4 -4
- package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
- package/dist/types/src/components/Avatars/Avatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
- package/dist/types/src/components/Button/Button.d.ts.map +1 -1
- package/dist/types/src/components/Card/Card.d.ts +107 -0
- package/dist/types/src/components/Card/Card.d.ts.map +1 -0
- package/dist/types/src/components/Card/Card.stories.d.ts +21 -0
- package/dist/types/src/components/Card/Card.stories.d.ts.map +1 -0
- package/dist/types/src/components/Card/index.d.ts +2 -0
- package/dist/types/src/components/Card/index.d.ts.map +1 -0
- package/dist/types/src/components/Dialog/AlertDialog.d.ts +12 -3
- package/dist/types/src/components/Dialog/AlertDialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/AlertDialog.stories.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/Dialog.d.ts +11 -4
- package/dist/types/src/components/Dialog/Dialog.d.ts.map +1 -1
- package/dist/types/src/components/Dialog/Dialog.stories.d.ts +3 -6
- package/dist/types/src/components/Dialog/Dialog.stories.d.ts.map +1 -1
- package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts +11 -0
- package/dist/types/src/components/ErrorFallback/ErrorFallback.d.ts.map +1 -0
- package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts +7 -0
- package/dist/types/src/components/ErrorFallback/ErrorFallback.stories.d.ts.map +1 -0
- package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts +8 -0
- package/dist/types/src/components/ErrorFallback/ErrorStack.d.ts.map +1 -0
- package/dist/types/src/components/ErrorFallback/ThrowError.d.ts +9 -0
- package/dist/types/src/components/ErrorFallback/ThrowError.d.ts.map +1 -0
- package/dist/types/src/components/ErrorFallback/index.d.ts +5 -0
- package/dist/types/src/components/ErrorFallback/index.d.ts.map +1 -0
- package/dist/types/src/components/Image/Image.d.ts +14 -0
- package/dist/types/src/components/Image/Image.d.ts.map +1 -0
- package/dist/types/src/components/Image/Image.stories.d.ts +33 -0
- package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -0
- package/dist/types/src/components/Image/index.d.ts +2 -0
- package/dist/types/src/components/Image/index.d.ts.map +1 -0
- package/dist/types/src/components/Input/Input.d.ts +2 -5
- package/dist/types/src/components/Input/Input.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.stories.d.ts +7 -7
- package/dist/types/src/components/Input/Input.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/List.d.ts.map +1 -1
- package/dist/types/src/components/List/List.stories.d.ts.map +1 -1
- package/dist/types/src/components/List/Treegrid.d.ts.map +1 -1
- package/dist/types/src/components/Main/Main.d.ts +9 -10
- package/dist/types/src/components/Main/Main.d.ts.map +1 -1
- package/dist/types/src/components/Main/Main.stories.d.ts +0 -3
- package/dist/types/src/components/Main/Main.stories.d.ts.map +1 -1
- package/dist/types/src/components/Menu/ContextMenu.d.ts.map +1 -1
- package/dist/types/src/components/Message/Message.d.ts.map +1 -1
- package/dist/types/src/components/Message/Message.stories.d.ts +2 -3
- package/dist/types/src/components/Message/Message.stories.d.ts.map +1 -1
- package/dist/types/src/components/Popover/Popover.d.ts +1 -0
- package/dist/types/src/components/Popover/Popover.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts +21 -26
- package/dist/types/src/components/ScrollArea/ScrollArea.d.ts.map +1 -1
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts +41 -9
- package/dist/types/src/components/ScrollArea/ScrollArea.stories.d.ts.map +1 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.d.ts.map +1 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts +6 -1
- package/dist/types/src/components/ScrollContainer/ScrollContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Select/Select.d.ts.map +1 -1
- package/dist/types/src/components/Skeleton/Skeleton.d.ts +12 -0
- package/dist/types/src/components/Skeleton/Skeleton.d.ts.map +1 -0
- package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts +17 -0
- package/dist/types/src/components/Skeleton/Skeleton.stories.d.ts.map +1 -0
- package/dist/types/src/components/Skeleton/index.d.ts +2 -0
- package/dist/types/src/components/Skeleton/index.d.ts.map +1 -0
- package/dist/types/src/components/Splitter/Splitter.d.ts +32 -0
- package/dist/types/src/components/Splitter/Splitter.d.ts.map +1 -0
- package/dist/types/src/components/Splitter/Splitter.stories.d.ts +7 -0
- package/dist/types/src/components/Splitter/Splitter.stories.d.ts.map +1 -0
- package/dist/types/src/components/Splitter/index.d.ts +2 -0
- package/dist/types/src/components/Splitter/index.d.ts.map +1 -0
- package/dist/types/src/components/Status/Status.stories.d.ts +4 -2
- package/dist/types/src/components/Status/Status.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tag/Tag.d.ts.map +1 -1
- package/dist/types/src/components/Tag/Tag.stories.d.ts +0 -5
- package/dist/types/src/components/Tag/Tag.stories.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts +1 -0
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts +12 -0
- package/dist/types/src/components/ThemeProvider/ThemeProvider.stories.d.ts.map +1 -0
- package/dist/types/src/components/Toast/Toast.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +33 -7
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/types/src/components/Tooltip/Tooltip.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +8 -4
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/exemplars/generics.stories.d.ts +18 -0
- package/dist/types/src/exemplars/generics.stories.d.ts.map +1 -0
- package/dist/types/src/exemplars/slot.stories.d.ts +14 -0
- package/dist/types/src/exemplars/slot.stories.d.ts.map +1 -0
- package/dist/types/src/exemplars/tabster.stories.d.ts +8 -0
- package/dist/types/src/exemplars/tabster.stories.d.ts.map +1 -0
- package/dist/types/src/exemplars/virtualizer.stories.d.ts +11 -0
- package/dist/types/src/exemplars/virtualizer.stories.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/playground/Controls.stories.d.ts.map +1 -1
- package/dist/types/src/primitives/Column/Column.d.ts +26 -0
- package/dist/types/src/primitives/Column/Column.d.ts.map +1 -0
- package/dist/types/src/primitives/Column/Column.stories.d.ts +6 -0
- package/dist/types/src/primitives/Column/Column.stories.d.ts.map +1 -0
- package/dist/types/src/primitives/Column/index.d.ts +2 -0
- package/dist/types/src/primitives/Column/index.d.ts.map +1 -0
- package/dist/types/src/primitives/Container/Container.d.ts +8 -0
- package/dist/types/src/primitives/Container/Container.d.ts.map +1 -0
- package/dist/types/src/primitives/Container/Container.stories.d.ts +6 -0
- package/dist/types/src/primitives/Container/Container.stories.d.ts.map +1 -0
- package/dist/types/src/primitives/Container/index.d.ts +2 -0
- package/dist/types/src/primitives/Container/index.d.ts.map +1 -0
- package/dist/types/src/primitives/Flex/Flex.d.ts +13 -0
- package/dist/types/src/primitives/Flex/Flex.d.ts.map +1 -0
- package/dist/types/src/primitives/Flex/Flex.stories.d.ts +8 -0
- package/dist/types/src/primitives/Flex/Flex.stories.d.ts.map +1 -0
- package/dist/types/src/primitives/Flex/index.d.ts +2 -0
- package/dist/types/src/primitives/Flex/index.d.ts.map +1 -0
- package/dist/types/src/primitives/Grid/Grid.d.ts +15 -0
- package/dist/types/src/primitives/Grid/Grid.d.ts.map +1 -0
- package/dist/types/src/primitives/Grid/Grid.stories.d.ts +8 -0
- package/dist/types/src/primitives/Grid/Grid.stories.d.ts.map +1 -0
- package/dist/types/src/primitives/Grid/index.d.ts +2 -0
- package/dist/types/src/primitives/Grid/index.d.ts.map +1 -0
- package/dist/types/src/primitives/Panel/Panel.d.ts +26 -0
- package/dist/types/src/primitives/Panel/Panel.d.ts.map +1 -0
- package/dist/types/src/primitives/Panel/Panel.stories.d.ts +6 -0
- package/dist/types/src/primitives/Panel/Panel.stories.d.ts.map +1 -0
- package/dist/types/src/primitives/Panel/index.d.ts +2 -0
- package/dist/types/src/primitives/Panel/index.d.ts.map +1 -0
- package/dist/types/src/primitives/index.d.ts +6 -0
- package/dist/types/src/primitives/index.d.ts.map +1 -0
- package/dist/types/src/testing/Loading.d.ts +9 -0
- package/dist/types/src/testing/Loading.d.ts.map +1 -0
- package/dist/types/src/testing/decorators/withLayout.d.ts +1 -1
- package/dist/types/src/testing/decorators/withLayout.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withLayoutVariants.d.ts.map +1 -1
- package/dist/types/src/testing/decorators/withTheme.d.ts +3 -2
- package/dist/types/src/testing/decorators/withTheme.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +11 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +25 -21
- package/src/components/Avatars/Avatar.stories.tsx +5 -6
- package/src/components/Avatars/Avatar.tsx +5 -12
- package/src/components/Avatars/AvatarGroup.stories.tsx +2 -2
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +3 -3
- package/src/components/Breadcrumb/Breadcrumb.tsx +11 -37
- package/src/components/Button/Button.stories.tsx +3 -3
- package/src/components/Button/Button.tsx +6 -12
- package/src/components/Button/IconButton.stories.tsx +4 -4
- package/src/components/Button/IconButton.tsx +1 -1
- package/src/components/Button/Toggle.stories.tsx +2 -2
- package/src/components/Button/ToggleGroup.stories.tsx +2 -2
- package/src/components/Card/Card.stories.tsx +151 -0
- package/src/components/Card/Card.tsx +347 -0
- package/src/components/Card/index.ts +5 -0
- package/src/components/Clipboard/CopyButton.tsx +3 -3
- package/src/components/Dialog/AlertDialog.stories.tsx +15 -15
- package/src/components/Dialog/AlertDialog.tsx +116 -16
- package/src/components/Dialog/Dialog.stories.tsx +40 -15
- package/src/components/Dialog/Dialog.tsx +75 -45
- package/src/components/ErrorFallback/ErrorFallback.stories.tsx +50 -0
- package/src/components/ErrorFallback/ErrorFallback.tsx +70 -0
- package/src/components/ErrorFallback/ErrorStack.tsx +80 -0
- package/src/components/ErrorFallback/ThrowError.tsx +37 -0
- package/src/components/ErrorFallback/index.ts +9 -0
- package/src/components/Icon/Icon.stories.tsx +2 -2
- package/src/components/Icon/Icon.tsx +1 -1
- package/src/components/Image/Image.stories.tsx +86 -0
- package/src/components/Image/Image.tsx +223 -0
- package/src/components/Image/index.ts +5 -0
- package/src/components/Input/Input.stories.tsx +20 -39
- package/src/components/Input/Input.tsx +20 -65
- package/src/components/Link/Link.stories.tsx +2 -2
- package/src/components/Link/Link.tsx +2 -2
- package/src/components/List/List.stories.tsx +15 -22
- package/src/components/List/List.tsx +11 -16
- package/src/components/List/ListDropIndicator.tsx +7 -7
- package/src/components/List/Tree.stories.tsx +4 -4
- package/src/components/List/TreeDropIndicator.tsx +6 -6
- package/src/components/List/Treegrid.stories.tsx +3 -3
- package/src/components/List/Treegrid.tsx +10 -15
- package/src/components/Main/Main.stories.tsx +41 -23
- package/src/components/Main/Main.tsx +138 -81
- package/src/components/Menu/ContextMenu.stories.tsx +2 -2
- package/src/components/Menu/ContextMenu.tsx +9 -33
- package/src/components/Menu/DropdownMenu.stories.tsx +2 -2
- package/src/components/Menu/DropdownMenu.tsx +10 -10
- package/src/components/Message/Message.stories.tsx +25 -10
- package/src/components/Message/Message.tsx +17 -29
- package/src/components/Popover/Popover.stories.tsx +4 -4
- package/src/components/Popover/Popover.tsx +23 -20
- package/src/components/ScrollArea/ScrollArea.stories.tsx +152 -76
- package/src/components/ScrollArea/ScrollArea.tsx +72 -116
- package/src/components/ScrollArea/index.ts +1 -1
- package/src/components/ScrollContainer/ScrollContainer.stories.tsx +41 -22
- package/src/components/ScrollContainer/ScrollContainer.tsx +18 -13
- package/src/components/Select/Select.stories.tsx +2 -2
- package/src/components/Select/Select.tsx +11 -27
- package/src/components/Separator/Separator.tsx +1 -1
- package/src/components/Skeleton/Skeleton.stories.tsx +52 -0
- package/src/components/Skeleton/Skeleton.tsx +26 -0
- package/src/components/Skeleton/index.ts +5 -0
- package/src/components/Splitter/Splitter.stories.tsx +83 -0
- package/src/components/Splitter/Splitter.tsx +126 -0
- package/src/components/Splitter/index.ts +5 -0
- package/src/components/Status/Status.stories.tsx +21 -17
- package/src/components/Status/Status.tsx +2 -2
- package/src/components/Tag/Tag.stories.tsx +4 -9
- package/src/components/Tag/Tag.tsx +2 -7
- package/src/components/ThemeProvider/ThemeProvider.stories.tsx +32 -0
- package/src/components/ThemeProvider/ThemeProvider.tsx +4 -3
- package/src/components/Toast/Toast.stories.tsx +2 -2
- package/src/components/Toast/Toast.tsx +10 -14
- package/src/components/Toolbar/Toolbar.stories.tsx +2 -2
- package/src/components/Toolbar/Toolbar.tsx +174 -12
- package/src/components/Tooltip/Tooltip.stories.tsx +15 -13
- package/src/components/Tooltip/Tooltip.tsx +3 -2
- package/src/components/index.ts +9 -5
- package/src/exemplars/generics.stories.tsx +49 -0
- package/src/exemplars/slot.stories.tsx +107 -0
- package/src/exemplars/tabster.stories.tsx +127 -0
- package/src/exemplars/virtualizer.stories.tsx +137 -0
- package/src/index.ts +1 -0
- package/src/playground/Controls.stories.tsx +3 -10
- package/src/playground/Custom.stories.tsx +10 -10
- package/src/playground/Typography.stories.tsx +3 -3
- package/src/primitives/Column/Column.stories.tsx +78 -0
- package/src/primitives/Column/Column.tsx +134 -0
- package/src/primitives/Column/index.ts +5 -0
- package/src/primitives/Container/Container.stories.tsx +30 -0
- package/src/primitives/Container/Container.tsx +22 -0
- package/src/primitives/Container/index.ts +5 -0
- package/src/primitives/Flex/Flex.stories.tsx +58 -0
- package/src/primitives/Flex/Flex.tsx +29 -0
- package/src/primitives/Flex/index.ts +5 -0
- package/src/primitives/Grid/Grid.stories.tsx +57 -0
- package/src/primitives/Grid/Grid.tsx +35 -0
- package/src/primitives/Grid/index.ts +5 -0
- package/src/primitives/Panel/Panel.stories.tsx +67 -0
- package/src/primitives/Panel/Panel.tsx +119 -0
- package/src/primitives/Panel/index.ts +5 -0
- package/src/primitives/index.ts +9 -0
- package/src/testing/Loading.tsx +26 -0
- package/src/testing/decorators/withLayout.tsx +21 -7
- package/src/testing/decorators/withLayoutVariants.tsx +18 -21
- package/src/testing/decorators/withTheme.tsx +19 -17
- package/src/testing/index.ts +2 -0
- package/src/translations.ts +19 -0
- package/dist/lib/browser/chunk-CEKVHJ27.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-2NHEX4AD.mjs.map +0 -7
- package/dist/types/src/components/AnchoredOverflow/AnchoredOverflow.d.ts +0 -15
- package/dist/types/src/components/AnchoredOverflow/AnchoredOverflow.d.ts.map +0 -1
- package/dist/types/src/components/AnchoredOverflow/index.d.ts +0 -2
- package/dist/types/src/components/AnchoredOverflow/index.d.ts.map +0 -1
- package/src/components/AnchoredOverflow/AnchoredOverflow.tsx +0 -59
- package/src/components/AnchoredOverflow/index.ts +0 -5
|
@@ -2,11 +2,18 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { Primitive } from '@radix-ui/react-primitive';
|
|
6
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
5
7
|
import type { ToggleGroupItemProps as ToggleGroupItemPrimitiveProps } from '@radix-ui/react-toggle-group';
|
|
6
8
|
import * as ToolbarPrimitive from '@radix-ui/react-toolbar';
|
|
7
9
|
import React, { Fragment, forwardRef } from 'react';
|
|
10
|
+
import { useTranslation } from 'react-i18next';
|
|
11
|
+
|
|
12
|
+
import { composableProps, type ToolbarStyleProps } from '@dxos/ui-theme';
|
|
13
|
+
import { type SlottableProps } from '@dxos/ui-types';
|
|
8
14
|
|
|
9
15
|
import { useThemeContext } from '../../hooks';
|
|
16
|
+
import { translationKey } from '../../translations';
|
|
10
17
|
import { type ThemedClassName } from '../../util';
|
|
11
18
|
import {
|
|
12
19
|
Button,
|
|
@@ -20,33 +27,42 @@ import {
|
|
|
20
27
|
type ToggleProps,
|
|
21
28
|
} from '../Button';
|
|
22
29
|
import { Link, type LinkProps } from '../Link';
|
|
30
|
+
import { DropdownMenu } from '../Menu';
|
|
23
31
|
import { Separator, type SeparatorProps } from '../Separator';
|
|
24
32
|
|
|
33
|
+
//
|
|
34
|
+
// Root
|
|
35
|
+
//
|
|
36
|
+
|
|
25
37
|
type ToolbarRootProps = ThemedClassName<
|
|
26
|
-
ToolbarPrimitive.ToolbarProps &
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
38
|
+
ToolbarPrimitive.ToolbarProps &
|
|
39
|
+
ToolbarStyleProps & {
|
|
40
|
+
textBlockWidth?: boolean;
|
|
41
|
+
}
|
|
31
42
|
>;
|
|
32
43
|
|
|
33
|
-
// TODO(burdon): Implement asChild.
|
|
44
|
+
// TODO(burdon): Implement asChild property.
|
|
34
45
|
const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
|
|
35
|
-
(
|
|
46
|
+
(
|
|
47
|
+
{ children, density, disabled, layoutManaged, textBlockWidth: textBlockWidthProp, orientation, ...props },
|
|
48
|
+
forwardedRef,
|
|
49
|
+
) => {
|
|
50
|
+
const { className, dir: _, ...rest } = composableProps(props);
|
|
36
51
|
const { tx } = useThemeContext();
|
|
37
52
|
const InnerRoot = textBlockWidthProp ? 'div' : Fragment;
|
|
38
53
|
const innerRootProps = textBlockWidthProp
|
|
39
54
|
? {
|
|
40
55
|
role: 'none',
|
|
41
|
-
className: tx('toolbar.inner',
|
|
56
|
+
className: tx('toolbar.inner', { layoutManaged }, className),
|
|
42
57
|
}
|
|
43
58
|
: {};
|
|
44
59
|
|
|
45
60
|
return (
|
|
46
61
|
<ToolbarPrimitive.Root
|
|
47
|
-
{...
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
{...rest}
|
|
63
|
+
orientation={orientation}
|
|
64
|
+
data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}
|
|
65
|
+
className={tx('toolbar.root', { density, disabled, layoutManaged }, className)}
|
|
50
66
|
ref={forwardedRef}
|
|
51
67
|
>
|
|
52
68
|
<InnerRoot {...innerRootProps}>{children}</InnerRoot>
|
|
@@ -55,6 +71,27 @@ const ToolbarRoot = forwardRef<HTMLDivElement, ToolbarRootProps>(
|
|
|
55
71
|
},
|
|
56
72
|
);
|
|
57
73
|
|
|
74
|
+
//
|
|
75
|
+
// Text
|
|
76
|
+
//
|
|
77
|
+
|
|
78
|
+
type ToolbarTextProps = SlottableProps<HTMLDivElement>;
|
|
79
|
+
|
|
80
|
+
const ToolbarText = forwardRef<HTMLDivElement, ToolbarTextProps>(({ children, asChild, ...props }, forwardedRef) => {
|
|
81
|
+
const { className, ...rest } = composableProps(props);
|
|
82
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
83
|
+
const { tx } = useThemeContext();
|
|
84
|
+
return (
|
|
85
|
+
<Comp {...rest} className={tx('toolbar.text', {}, className)} ref={forwardedRef}>
|
|
86
|
+
{children}
|
|
87
|
+
</Comp>
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
//
|
|
92
|
+
// Button
|
|
93
|
+
//
|
|
94
|
+
|
|
58
95
|
type ToolbarButtonProps = ButtonProps;
|
|
59
96
|
|
|
60
97
|
const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>((props, forwardedRef) => {
|
|
@@ -65,6 +102,10 @@ const ToolbarButton = forwardRef<HTMLButtonElement, ToolbarButtonProps>((props,
|
|
|
65
102
|
);
|
|
66
103
|
});
|
|
67
104
|
|
|
105
|
+
//
|
|
106
|
+
// IconButton
|
|
107
|
+
//
|
|
108
|
+
|
|
68
109
|
type ToolbarIconButtonProps = IconButtonProps;
|
|
69
110
|
|
|
70
111
|
const ToolbarIconButton = forwardRef<HTMLButtonElement, ToolbarIconButtonProps>((props, forwardedRef) => {
|
|
@@ -85,6 +126,10 @@ const ToolbarToggle = forwardRef<HTMLButtonElement, ToolbarToggleProps>((props,
|
|
|
85
126
|
);
|
|
86
127
|
});
|
|
87
128
|
|
|
129
|
+
//
|
|
130
|
+
// Link
|
|
131
|
+
//
|
|
132
|
+
|
|
88
133
|
type ToolbarLinkProps = LinkProps;
|
|
89
134
|
|
|
90
135
|
const ToolbarLink = forwardRef<HTMLAnchorElement, ToolbarLinkProps>((props, forwardedRef) => {
|
|
@@ -101,6 +146,10 @@ type ToolbarToggleGroupProps = (
|
|
|
101
146
|
) &
|
|
102
147
|
ButtonGroupProps;
|
|
103
148
|
|
|
149
|
+
//
|
|
150
|
+
// ToggleGroup
|
|
151
|
+
//
|
|
152
|
+
|
|
104
153
|
const ToolbarToggleGroup = forwardRef<HTMLDivElement, ToolbarToggleGroupProps>(
|
|
105
154
|
({ classNames, children, elevation, ...props }, forwardedRef) => {
|
|
106
155
|
return (
|
|
@@ -146,10 +195,14 @@ const ToolbarToggleGroupIconItem = forwardRef<HTMLButtonElement, ToolbarToggleGr
|
|
|
146
195
|
},
|
|
147
196
|
);
|
|
148
197
|
|
|
198
|
+
//
|
|
199
|
+
// Separator
|
|
200
|
+
//
|
|
201
|
+
|
|
149
202
|
type ToolbarSeparatorProps = SeparatorProps & { variant?: 'gap' | 'line' };
|
|
150
203
|
|
|
151
204
|
const ToolbarSeparator = forwardRef<HTMLDivElement, ToolbarSeparatorProps>(
|
|
152
|
-
({ variant = '
|
|
205
|
+
({ variant = 'gap', ...props }, forwardedRef) => {
|
|
153
206
|
return variant === 'line' ? (
|
|
154
207
|
<ToolbarPrimitive.Separator asChild>
|
|
155
208
|
<Separator {...props} ref={forwardedRef} />
|
|
@@ -160,8 +213,109 @@ const ToolbarSeparator = forwardRef<HTMLDivElement, ToolbarSeparatorProps>(
|
|
|
160
213
|
},
|
|
161
214
|
);
|
|
162
215
|
|
|
216
|
+
//
|
|
217
|
+
// DragHandle
|
|
218
|
+
//
|
|
219
|
+
|
|
220
|
+
type ToolbarDragHandleProps = { testId?: string; label?: string };
|
|
221
|
+
|
|
222
|
+
const ToolbarDragHandle = forwardRef<HTMLButtonElement, ToolbarDragHandleProps>(
|
|
223
|
+
({ testId = 'drag-handle', label }, forwardedRef) => {
|
|
224
|
+
const { t } = useTranslation(translationKey);
|
|
225
|
+
return (
|
|
226
|
+
<ToolbarIconButton
|
|
227
|
+
data-testid={testId}
|
|
228
|
+
noTooltip
|
|
229
|
+
iconOnly
|
|
230
|
+
icon='ph--dots-six-vertical--regular'
|
|
231
|
+
variant='ghost'
|
|
232
|
+
label={label ?? t('toolbar drag handle label')}
|
|
233
|
+
classNames='cursor-pointer'
|
|
234
|
+
size={5}
|
|
235
|
+
disabled={!forwardedRef}
|
|
236
|
+
ref={forwardedRef}
|
|
237
|
+
/>
|
|
238
|
+
);
|
|
239
|
+
},
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
//
|
|
243
|
+
// CloseIconButton
|
|
244
|
+
//
|
|
245
|
+
|
|
246
|
+
type ToolbarCloseIconButtonProps = { onClick?: () => void; label?: string };
|
|
247
|
+
|
|
248
|
+
const ToolbarCloseIconButton = forwardRef<HTMLButtonElement, ToolbarCloseIconButtonProps>(
|
|
249
|
+
({ onClick, label }, forwardedRef) => {
|
|
250
|
+
const { t } = useTranslation(translationKey);
|
|
251
|
+
return (
|
|
252
|
+
<ToolbarIconButton
|
|
253
|
+
iconOnly
|
|
254
|
+
icon='ph--x--regular'
|
|
255
|
+
variant='ghost'
|
|
256
|
+
label={label ?? t('toolbar close label')}
|
|
257
|
+
classNames='cursor-pointer'
|
|
258
|
+
size={5}
|
|
259
|
+
onClick={onClick}
|
|
260
|
+
ref={forwardedRef}
|
|
261
|
+
/>
|
|
262
|
+
);
|
|
263
|
+
},
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
//
|
|
267
|
+
// Menu
|
|
268
|
+
//
|
|
269
|
+
|
|
270
|
+
type ToolbarMenuItem<T extends any | void = void> = {
|
|
271
|
+
label: string;
|
|
272
|
+
onClick: (context: T) => void;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
type ToolbarMenuProps<T extends any | void = void> = {
|
|
276
|
+
context?: T;
|
|
277
|
+
items?: ToolbarMenuItem<T>[];
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// TODO(burdon): Make slottable.
|
|
281
|
+
const ToolbarMenu = <T extends any | void = void>({ context, items }: ToolbarMenuProps<T>) => {
|
|
282
|
+
const { t } = useTranslation(translationKey);
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<DropdownMenu.Root>
|
|
286
|
+
<DropdownMenu.Trigger disabled={!items?.length} asChild>
|
|
287
|
+
<ToolbarIconButton
|
|
288
|
+
iconOnly
|
|
289
|
+
variant='ghost'
|
|
290
|
+
icon='ph--dots-three-vertical--regular'
|
|
291
|
+
label={t('toolbar menu label')}
|
|
292
|
+
/>
|
|
293
|
+
</DropdownMenu.Trigger>
|
|
294
|
+
{(items?.length ?? 0) > 0 && (
|
|
295
|
+
<DropdownMenu.Portal>
|
|
296
|
+
<DropdownMenu.Content>
|
|
297
|
+
<DropdownMenu.Viewport>
|
|
298
|
+
{items?.map(({ label, onClick: onSelect }, index) => (
|
|
299
|
+
<DropdownMenu.Item key={index} onSelect={() => onSelect(context as T)}>
|
|
300
|
+
{label}
|
|
301
|
+
</DropdownMenu.Item>
|
|
302
|
+
))}
|
|
303
|
+
</DropdownMenu.Viewport>
|
|
304
|
+
<DropdownMenu.Arrow />
|
|
305
|
+
</DropdownMenu.Content>
|
|
306
|
+
</DropdownMenu.Portal>
|
|
307
|
+
)}
|
|
308
|
+
</DropdownMenu.Root>
|
|
309
|
+
);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
//
|
|
313
|
+
// Toolbar
|
|
314
|
+
//
|
|
315
|
+
|
|
163
316
|
export const Toolbar = {
|
|
164
317
|
Root: ToolbarRoot,
|
|
318
|
+
Text: ToolbarText,
|
|
165
319
|
Button: ToolbarButton,
|
|
166
320
|
IconButton: ToolbarIconButton,
|
|
167
321
|
Link: ToolbarLink,
|
|
@@ -170,10 +324,14 @@ export const Toolbar = {
|
|
|
170
324
|
ToggleGroupItem: ToolbarToggleGroupItem,
|
|
171
325
|
ToggleGroupIconItem: ToolbarToggleGroupIconItem,
|
|
172
326
|
Separator: ToolbarSeparator,
|
|
327
|
+
DragHandle: ToolbarDragHandle,
|
|
328
|
+
CloseIconButton: ToolbarCloseIconButton,
|
|
329
|
+
Menu: ToolbarMenu,
|
|
173
330
|
};
|
|
174
331
|
|
|
175
332
|
export type {
|
|
176
333
|
ToolbarRootProps,
|
|
334
|
+
ToolbarTextProps,
|
|
177
335
|
ToolbarButtonProps,
|
|
178
336
|
ToolbarIconButtonProps,
|
|
179
337
|
ToolbarLinkProps,
|
|
@@ -182,4 +340,8 @@ export type {
|
|
|
182
340
|
ToolbarToggleGroupItemProps,
|
|
183
341
|
ToolbarToggleGroupIconItemProps,
|
|
184
342
|
ToolbarSeparatorProps,
|
|
343
|
+
ToolbarDragHandleProps,
|
|
344
|
+
ToolbarCloseIconButtonProps,
|
|
345
|
+
ToolbarMenuItem,
|
|
346
|
+
ToolbarMenuProps,
|
|
185
347
|
};
|
|
@@ -17,23 +17,25 @@ type StoryProps = {
|
|
|
17
17
|
defaultOpen?: boolean;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
const DefaultStory = ({ tooltips, defaultOpen }: StoryProps) =>
|
|
21
|
-
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
const DefaultStory = ({ tooltips, defaultOpen }: StoryProps) => {
|
|
21
|
+
return (
|
|
22
|
+
<Tooltip.Provider defaultOpen={defaultOpen}>
|
|
23
|
+
<div role='none' className='w-32'>
|
|
24
|
+
{tooltips.map(({ label, content }, i) => (
|
|
25
|
+
<Tooltip.Trigger asChild key={i} content={content} side='right'>
|
|
26
|
+
<Button classNames='block w-full'>{label}</Button>
|
|
27
|
+
</Tooltip.Trigger>
|
|
28
|
+
))}
|
|
29
|
+
</div>
|
|
30
|
+
</Tooltip.Provider>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
31
33
|
|
|
32
34
|
const meta = {
|
|
33
|
-
title: 'ui/react-ui-core/Tooltip',
|
|
35
|
+
title: 'ui/react-ui-core/components/Tooltip',
|
|
34
36
|
component: Tooltip as any,
|
|
35
37
|
render: DefaultStory,
|
|
36
|
-
decorators: [withTheme],
|
|
38
|
+
decorators: [withTheme()],
|
|
37
39
|
} satisfies Meta<typeof DefaultStory>;
|
|
38
40
|
|
|
39
41
|
export default meta;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
// This is based upon `@radix-ui/react-tooltip` fetched 17 March 2025 at https://github.com/radix-ui/primitives at commit 6e75e11.
|
|
6
|
+
// TODO(burdon): Replace with https://ui.shadcn.com/docs/components/radix/tooltip
|
|
6
7
|
|
|
7
8
|
import { composeEventHandlers } from '@radix-ui/primitive';
|
|
8
9
|
import { useComposedRefs } from '@radix-ui/react-compose-refs';
|
|
@@ -215,9 +216,9 @@ const TooltipProvider: FC<TooltipProviderProps> = (props: TooltipScopedProps<Too
|
|
|
215
216
|
isPointerInTransitRef.current = inTransit;
|
|
216
217
|
}, [])}
|
|
217
218
|
>
|
|
218
|
-
<TooltipContent side={side} className={tx('tooltip.content',
|
|
219
|
+
<TooltipContent side={side} className={tx('tooltip.content', { elevation })}>
|
|
219
220
|
{content}
|
|
220
|
-
<TooltipArrow className={tx('tooltip.arrow'
|
|
221
|
+
<TooltipArrow className={tx('tooltip.arrow')} />
|
|
221
222
|
</TooltipContent>
|
|
222
223
|
<TooltipVirtualTrigger virtualRef={triggerRef as RefObject<HTMLButtonElement>} />
|
|
223
224
|
{children}
|
package/src/components/index.ts
CHANGED
|
@@ -2,13 +2,19 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './DensityProvider';
|
|
6
|
+
export * from './ElevationProvider';
|
|
7
|
+
export * from './ThemeProvider';
|
|
8
|
+
|
|
6
9
|
export * from './Avatars';
|
|
7
10
|
export * from './Breadcrumb';
|
|
8
11
|
export * from './Button';
|
|
12
|
+
export * from './Card';
|
|
9
13
|
export * from './Clipboard';
|
|
10
14
|
export * from './Dialog';
|
|
15
|
+
export * from './ErrorFallback';
|
|
11
16
|
export * from './Icon';
|
|
17
|
+
export * from './Image';
|
|
12
18
|
export * from './Input';
|
|
13
19
|
export * from './Link';
|
|
14
20
|
export * from './List';
|
|
@@ -21,11 +27,9 @@ export * from './ScrollArea';
|
|
|
21
27
|
export * from './ScrollContainer';
|
|
22
28
|
export * from './Select';
|
|
23
29
|
export * from './Separator';
|
|
30
|
+
export * from './Skeleton';
|
|
31
|
+
export * from './Splitter';
|
|
24
32
|
export * from './Tag';
|
|
25
33
|
export * from './Toast';
|
|
26
34
|
export * from './Toolbar';
|
|
27
35
|
export * from './Tooltip';
|
|
28
|
-
|
|
29
|
-
export * from './DensityProvider';
|
|
30
|
-
export * from './ElevationProvider';
|
|
31
|
-
export * from './ThemeProvider';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React, { type ReactElement, type Ref, forwardRef } from 'react';
|
|
7
|
+
|
|
8
|
+
import { type SlottableProps } from '@dxos/ui-types';
|
|
9
|
+
|
|
10
|
+
import { withTheme } from '../testing';
|
|
11
|
+
|
|
12
|
+
const ComponentInner = forwardRef<HTMLDivElement, ComponentProps>(({ children, ...props }, forwardedRef) => {
|
|
13
|
+
return (
|
|
14
|
+
<div {...props} ref={forwardedRef}>
|
|
15
|
+
{children}
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
ComponentInner.displayName = 'Component';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generic component pattern.
|
|
24
|
+
*/
|
|
25
|
+
type ComponentProps<P extends HTMLElement = any> = SlottableProps<P>;
|
|
26
|
+
|
|
27
|
+
const Component = ComponentInner as <P extends HTMLElement>(
|
|
28
|
+
props: SlottableProps<P> & { ref?: Ref<P> },
|
|
29
|
+
) => ReactElement;
|
|
30
|
+
|
|
31
|
+
const meta = {
|
|
32
|
+
title: 'ui/react-ui-core/exemplars/generics',
|
|
33
|
+
component: Component,
|
|
34
|
+
render: (props) => <Component<HTMLDivElement> {...props} />,
|
|
35
|
+
decorators: [withTheme()],
|
|
36
|
+
parameters: {
|
|
37
|
+
layout: 'centered',
|
|
38
|
+
},
|
|
39
|
+
} satisfies Meta;
|
|
40
|
+
|
|
41
|
+
export default meta;
|
|
42
|
+
|
|
43
|
+
type Story = StoryObj<typeof meta>;
|
|
44
|
+
|
|
45
|
+
export const Default: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
children: 'Hello',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Primitive } from '@radix-ui/react-primitive';
|
|
6
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
|
+
import React, { HTMLAttributes, type PropsWithChildren, forwardRef } from 'react';
|
|
8
|
+
|
|
9
|
+
import { composableProps } from '@dxos/ui-theme';
|
|
10
|
+
import { type ComposableProps, type SlottableProps, type ThemedClassName } from '@dxos/ui-types';
|
|
11
|
+
|
|
12
|
+
import { withTheme } from '../testing';
|
|
13
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Composition
|
|
17
|
+
*
|
|
18
|
+
* All Radix primitive parts that render a DOM element accept an asChild prop.
|
|
19
|
+
* When asChild is set to true, Radix will not render a default DOM element, instead cloning the part's child and passing it the props and behavior required to make it functional.
|
|
20
|
+
* https://www.radix-ui.com/primitives/docs/guides/composition
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const Outer = forwardRef<HTMLDivElement, SlottableProps<HTMLDivElement>>(
|
|
24
|
+
({ children, asChild, ...props }, forwardedRef) => {
|
|
25
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
26
|
+
return (
|
|
27
|
+
<Comp {...composableProps<HTMLDivElement>(props, { role: 'none' })} ref={forwardedRef}>
|
|
28
|
+
{children}
|
|
29
|
+
</Comp>
|
|
30
|
+
);
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const Middle = forwardRef<HTMLDivElement, SlottableProps<HTMLDivElement>>(
|
|
35
|
+
({ children, asChild, ...props }, forwardedRef) => {
|
|
36
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
37
|
+
return (
|
|
38
|
+
<Comp {...composableProps<HTMLDivElement>(props, { role: 'none' })} ref={forwardedRef}>
|
|
39
|
+
{children}
|
|
40
|
+
</Comp>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const Leaf = forwardRef<HTMLButtonElement, ComposableProps<HTMLButtonElement>>(
|
|
46
|
+
({ children, ...props }, forwardedRef) => {
|
|
47
|
+
return (
|
|
48
|
+
<button {...composableProps<HTMLButtonElement>(props, { role: 'none' })} ref={forwardedRef}>
|
|
49
|
+
{children}
|
|
50
|
+
</button>
|
|
51
|
+
);
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const TestSingle = (props: ThemedClassName<{ role?: string }>) => {
|
|
56
|
+
return (
|
|
57
|
+
<Outer asChild {...composableProps<HTMLDivElement>(props, { role: 'none' })}>
|
|
58
|
+
<Leaf>Single asChild (non-compliant — see console)</Leaf>
|
|
59
|
+
</Outer>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const TestNested = (props: ThemedClassName<{ role?: string }>) => {
|
|
64
|
+
return (
|
|
65
|
+
<Outer asChild {...composableProps<HTMLDivElement>(props, { role: 'none' })}>
|
|
66
|
+
<Middle asChild>
|
|
67
|
+
<Leaf>Nested asChild</Leaf>
|
|
68
|
+
</Middle>
|
|
69
|
+
</Outer>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const TestInner = (props: ThemedClassName<{ role?: string }>) => {
|
|
74
|
+
return (
|
|
75
|
+
<Outer asChild {...composableProps<HTMLDivElement>(props, { role: 'none' })}>
|
|
76
|
+
<Middle asChild>
|
|
77
|
+
<Leaf>
|
|
78
|
+
<div role='none'>Leaf</div>
|
|
79
|
+
</Leaf>
|
|
80
|
+
</Middle>
|
|
81
|
+
</Outer>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const meta = {
|
|
86
|
+
title: 'ui/react-ui-core/exemplars/slot',
|
|
87
|
+
decorators: [withTheme()],
|
|
88
|
+
parameters: {
|
|
89
|
+
layout: 'centered',
|
|
90
|
+
},
|
|
91
|
+
} satisfies Meta;
|
|
92
|
+
|
|
93
|
+
export default meta;
|
|
94
|
+
|
|
95
|
+
type Story = StoryObj<typeof meta>;
|
|
96
|
+
|
|
97
|
+
export const Single: Story = {
|
|
98
|
+
render: () => <TestSingle role='listitem' classNames='border-red-500' />,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const Nested: Story = {
|
|
102
|
+
render: () => <TestNested role='listitem' classNames='border-green-500' />,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const Inner: Story = {
|
|
106
|
+
render: () => <TestInner role='listitem' classNames='border-blue-500' />,
|
|
107
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
useArrowNavigationGroup,
|
|
7
|
+
useFocusFinders,
|
|
8
|
+
useFocusableGroup,
|
|
9
|
+
useMergedTabsterAttributes_unstable,
|
|
10
|
+
} from '@fluentui/react-tabster';
|
|
11
|
+
import { type Decorator, type Meta, type StoryObj } from '@storybook/react-vite';
|
|
12
|
+
import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
|
|
13
|
+
import { createTabster, disposeTabster } from 'tabster';
|
|
14
|
+
|
|
15
|
+
import { Input, ScrollArea } from '@dxos/react-ui';
|
|
16
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
17
|
+
import { mx } from '@dxos/ui-theme';
|
|
18
|
+
|
|
19
|
+
// TODO(burdon): Factor out styles (incl. tabster debugging).
|
|
20
|
+
// TODO(burdon): Implement horizontal movement between columns when column is selected.
|
|
21
|
+
// TODO(burdon): Prevent tab out of app.
|
|
22
|
+
|
|
23
|
+
const border =
|
|
24
|
+
'rounded-xs outline-hidden border border-subdued-separator focus:border-primary-500 focus-within:border-rose-500';
|
|
25
|
+
|
|
26
|
+
const Board = forwardRef<HTMLDivElement, { columns: string[][] }>(({ columns }, ref) => {
|
|
27
|
+
const arrowNavigationAttrs = useArrowNavigationGroup({ axis: 'horizontal', memorizeCurrent: true, tabbable: true });
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div ref={ref} tabIndex={0} {...arrowNavigationAttrs} className='flex h-full w-full overflow-hidden'>
|
|
31
|
+
<div className={mx('flex h-full overflow-x-auto p-4 gap-4')}>
|
|
32
|
+
{columns.map((column) => (
|
|
33
|
+
<Column key={column[0]} items={column} />
|
|
34
|
+
))}
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const Column = forwardRef<HTMLDivElement, { items: string[] }>(({ items }, ref) => {
|
|
41
|
+
const focusableGroupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
|
|
42
|
+
const arrowNavigationAttrs = useArrowNavigationGroup({ axis: 'vertical', memorizeCurrent: true });
|
|
43
|
+
const tabsterAttrs = useMergedTabsterAttributes_unstable(focusableGroupAttrs, arrowNavigationAttrs);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<ScrollArea.Root tabIndex={0} orientation='vertical' classNames={mx('w-[25rem]', border)}>
|
|
47
|
+
<ScrollArea.Viewport {...tabsterAttrs} classNames='p-4 gap-4' ref={ref}>
|
|
48
|
+
{items.map((item) => (
|
|
49
|
+
<Item key={item} value={item} />
|
|
50
|
+
))}
|
|
51
|
+
</ScrollArea.Viewport>
|
|
52
|
+
</ScrollArea.Root>
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const Item = forwardRef<HTMLDivElement, { value: string }>(({ value }, ref) => {
|
|
57
|
+
const focusableGroupAttrs = useFocusableGroup();
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div
|
|
61
|
+
ref={ref}
|
|
62
|
+
tabIndex={0}
|
|
63
|
+
{...focusableGroupAttrs}
|
|
64
|
+
className={mx('flex shrink-0 w-full gap-4 p-4 items-center', border)}
|
|
65
|
+
>
|
|
66
|
+
<Input.Root>
|
|
67
|
+
<Input.Checkbox />
|
|
68
|
+
</Input.Root>
|
|
69
|
+
<Input.Root>
|
|
70
|
+
<Input.TextInput defaultValue={value} />
|
|
71
|
+
</Input.Root>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const DefaultStory = () => {
|
|
77
|
+
const columns = useMemo(() => {
|
|
78
|
+
return [['A1', 'A2', 'A3'], ['B1'], ['C1', 'C2', 'C3', 'C4', 'C5', 'C6'], ['D1', 'D2']];
|
|
79
|
+
}, []);
|
|
80
|
+
|
|
81
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
82
|
+
const { findFirstFocusable } = useFocusFinders();
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (ref.current) {
|
|
85
|
+
findFirstFocusable(ref.current)?.focus();
|
|
86
|
+
}
|
|
87
|
+
}, []);
|
|
88
|
+
|
|
89
|
+
return <Board columns={columns} ref={ref} />;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// TODO(burdon): This doesn't seem to be necessary or recongized; memoization doesn't work.
|
|
93
|
+
const withTabster: Decorator = (Story) => {
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
const tabster = createTabster(window, {
|
|
96
|
+
autoRoot: {},
|
|
97
|
+
// TODO(burdon): Not called.
|
|
98
|
+
// checkUncontrolledCompletely: (el) => {
|
|
99
|
+
// console.log(el);
|
|
100
|
+
// return true;
|
|
101
|
+
// },
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return () => {
|
|
105
|
+
disposeTabster(tabster);
|
|
106
|
+
};
|
|
107
|
+
}, []);
|
|
108
|
+
|
|
109
|
+
return <Story />;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const meta: Meta<typeof DefaultStory> = {
|
|
113
|
+
title: 'ui/react-ui-core/exemplars/tabster',
|
|
114
|
+
component: DefaultStory,
|
|
115
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withTabster],
|
|
116
|
+
parameters: {
|
|
117
|
+
layout: 'fullscreen',
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export default meta;
|
|
122
|
+
|
|
123
|
+
type Story = StoryObj<typeof meta>;
|
|
124
|
+
|
|
125
|
+
export const Default: Story = {
|
|
126
|
+
args: {},
|
|
127
|
+
};
|