@dxos/react-ui 0.3.11-main.3f845e1 → 0.3.11-main.463e5cd
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/index.mjs +337 -239
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/Avatars/Avatar.d.ts +3 -3
- package/dist/types/src/components/Avatars/Avatar.d.ts.map +1 -1
- package/dist/types/src/components/Input/Input.stories.d.ts +1 -1
- package/dist/types/src/components/List/List.d.ts.map +1 -0
- package/dist/types/src/components/{Lists → List}/List.stories.d.ts +3 -1
- package/dist/types/src/components/List/List.stories.d.ts.map +1 -0
- package/dist/types/src/components/List/Tree.d.ts.map +1 -0
- package/dist/types/src/components/List/Tree.stories.d.ts.map +1 -0
- package/dist/types/src/components/List/index.d.ts.map +1 -0
- package/dist/types/src/components/Menus/ContextMenu.d.ts +50 -0
- package/dist/types/src/components/Menus/ContextMenu.d.ts.map +1 -0
- package/dist/types/src/components/Menus/ContextMenu.stories.d.ts +21 -0
- package/dist/types/src/components/Menus/ContextMenu.stories.d.ts.map +1 -0
- package/dist/types/src/components/{DropdownMenu → Menus}/DropdownMenu.d.ts +23 -23
- package/dist/types/src/components/Menus/DropdownMenu.d.ts.map +1 -0
- package/dist/types/src/components/Menus/DropdownMenu.stories.d.ts.map +1 -0
- package/dist/types/src/components/Menus/index.d.ts +3 -0
- package/dist/types/src/components/Menus/index.d.ts.map +1 -0
- package/dist/types/src/components/ThemeProvider/ThemeProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts +108 -1
- package/dist/types/src/components/ThemeProvider/TranslationsProvider.d.ts.map +1 -1
- package/dist/types/src/components/ThemeProvider/index.d.ts +1 -0
- package/dist/types/src/components/ThemeProvider/index.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +2 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTranslationsContext.d.ts +1 -0
- package/dist/types/src/hooks/useTranslationsContext.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/package.json +12 -8
- package/src/components/Avatars/Avatar.tsx +2 -1
- package/src/components/Buttons/Button.stories.tsx +2 -2
- package/src/components/Input/Input.stories.tsx +2 -2
- package/src/components/{Lists → List}/List.stories.tsx +50 -2
- package/src/components/Menus/ContextMenu.stories.tsx +106 -0
- package/src/components/Menus/ContextMenu.tsx +170 -0
- package/src/components/Menus/DropdownMenu.tsx +173 -0
- package/src/components/{DropdownMenu → Menus}/index.ts +1 -0
- package/src/components/ThemeProvider/ThemeProvider.tsx +1 -0
- package/src/components/ThemeProvider/TranslationsProvider.tsx +22 -4
- package/src/components/ThemeProvider/index.ts +1 -0
- package/src/components/index.ts +2 -2
- package/src/index.ts +1 -1
- package/src/playground/Surfaces.stories.tsx +9 -9
- package/src/playground/Typography.stories.tsx +1 -1
- package/dist/types/src/components/DropdownMenu/DropdownMenu.d.ts.map +0 -1
- package/dist/types/src/components/DropdownMenu/DropdownMenu.stories.d.ts.map +0 -1
- package/dist/types/src/components/DropdownMenu/index.d.ts +0 -2
- package/dist/types/src/components/DropdownMenu/index.d.ts.map +0 -1
- package/dist/types/src/components/Lists/List.d.ts.map +0 -1
- package/dist/types/src/components/Lists/List.stories.d.ts.map +0 -1
- package/dist/types/src/components/Lists/Tree.d.ts.map +0 -1
- package/dist/types/src/components/Lists/Tree.stories.d.ts.map +0 -1
- package/dist/types/src/components/Lists/index.d.ts.map +0 -1
- package/src/components/DropdownMenu/DropdownMenu.tsx +0 -198
- package/dist/types/src/components/{Lists → List}/List.d.ts +0 -0
- package/dist/types/src/components/{Lists → List}/Tree.d.ts +0 -0
- package/dist/types/src/components/{Lists → List}/Tree.stories.d.ts +0 -0
- package/dist/types/src/components/{Lists → List}/index.d.ts +0 -0
- package/dist/types/src/components/{DropdownMenu → Menus}/DropdownMenu.stories.d.ts +0 -0
- package/src/components/{Lists → List}/List.tsx +0 -0
- package/src/components/{Lists → List}/Tree.stories.tsx +0 -0
- package/src/components/{Lists → List}/Tree.tsx +1 -1
- /package/src/components/{Lists → List}/index.ts +0 -0
- /package/src/components/{DropdownMenu → Menus}/DropdownMenu.stories.tsx +0 -0
|
@@ -7,10 +7,18 @@ import '@dxosTheme';
|
|
|
7
7
|
import { DndContext, type DragEndEvent, type DragStartEvent } from '@dnd-kit/core';
|
|
8
8
|
import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
9
9
|
import { CSS } from '@dnd-kit/utilities';
|
|
10
|
+
import { useArrowNavigationGroup } from '@fluentui/react-tabster';
|
|
10
11
|
import { DotsSixVertical, PushPin } from '@phosphor-icons/react';
|
|
11
12
|
import React, { type FC, type ReactNode, useState } from 'react';
|
|
12
13
|
|
|
13
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
getSize,
|
|
16
|
+
ghostHover,
|
|
17
|
+
ghostSelected,
|
|
18
|
+
ghostSelectedTrackingInterFromNormal,
|
|
19
|
+
mx,
|
|
20
|
+
surfaceElevation,
|
|
21
|
+
} from '@dxos/react-ui-theme';
|
|
14
22
|
|
|
15
23
|
import { List, ListItem, type ListProps, type ListScopedProps } from './List';
|
|
16
24
|
import { withTheme } from '../../testing';
|
|
@@ -106,6 +114,7 @@ const ManySizesDraggableListItem = ({
|
|
|
106
114
|
</ListItem.Root>
|
|
107
115
|
);
|
|
108
116
|
};
|
|
117
|
+
|
|
109
118
|
export const ManySizesDraggable = {
|
|
110
119
|
render: ({ ...args }) => {
|
|
111
120
|
const [items, setItems] = useState(
|
|
@@ -183,6 +192,45 @@ export const Collapsible = {
|
|
|
183
192
|
},
|
|
184
193
|
args: {
|
|
185
194
|
variant: 'unordered',
|
|
186
|
-
toggleOpenLabel: 'Open/close storybook list item',
|
|
195
|
+
// toggleOpenLabel: 'Open/close storybook list item', // TODO(burdon): ???
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export const SelectableListbox = {
|
|
200
|
+
render: () => {
|
|
201
|
+
const [selectedId, setSelectedId] = useState<string>();
|
|
202
|
+
const domAttributes = useArrowNavigationGroup({ axis: 'vertical' });
|
|
203
|
+
const [items, _setItems] = useState(
|
|
204
|
+
[...Array(12)].map((_, index) => ({
|
|
205
|
+
id: `listItem-${index}`,
|
|
206
|
+
text: `List item ${index + 1}`,
|
|
207
|
+
})),
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const handleKeyUp = (event: any, id: string) => {
|
|
211
|
+
switch (event.key) {
|
|
212
|
+
case ' ':
|
|
213
|
+
case 'Enter': {
|
|
214
|
+
setSelectedId(id);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<List selectable {...domAttributes}>
|
|
221
|
+
{items.map(({ id, text }) => (
|
|
222
|
+
<ListItem.Root
|
|
223
|
+
key={id}
|
|
224
|
+
tabIndex={0}
|
|
225
|
+
selected={selectedId === id}
|
|
226
|
+
classNames={mx('items-center', ghostHover, ghostSelected, ghostSelectedTrackingInterFromNormal)}
|
|
227
|
+
onClick={() => setSelectedId(id)}
|
|
228
|
+
onKeyUp={(event) => handleKeyUp(event, id)}
|
|
229
|
+
>
|
|
230
|
+
<ListItem.Heading classNames='grow'>Lorem ipsum dolor sit amet</ListItem.Heading>
|
|
231
|
+
</ListItem.Root>
|
|
232
|
+
))}
|
|
233
|
+
</List>
|
|
234
|
+
);
|
|
187
235
|
},
|
|
188
236
|
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxosTheme';
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
|
|
9
|
+
import { ContextMenu } from './ContextMenu';
|
|
10
|
+
import { withTheme } from '../../testing';
|
|
11
|
+
|
|
12
|
+
const StorybookContextMenu = () => {
|
|
13
|
+
// NOTE(thure): Since long-tap will select text in some OSs, apply `select-none` to `ContextMenu.Trigger` where possible.
|
|
14
|
+
return (
|
|
15
|
+
<ContextMenu.Root>
|
|
16
|
+
<ContextMenu.Trigger className='select-none border border-dashed border-neutral-400/50 rounded-lg flex items-center justify-center p-8 font-normal'>
|
|
17
|
+
Right-click / long-tap here.
|
|
18
|
+
</ContextMenu.Trigger>
|
|
19
|
+
|
|
20
|
+
<ContextMenu.Content collisionPadding={8}>
|
|
21
|
+
<ContextMenu.Viewport>
|
|
22
|
+
<ContextMenu.Item>
|
|
23
|
+
<span className='grow'>New Tab</span>
|
|
24
|
+
<span className='opacity-50'>⌘+T</span>
|
|
25
|
+
</ContextMenu.Item>
|
|
26
|
+
<ContextMenu.Item>
|
|
27
|
+
<span className='grow'>New Window</span>
|
|
28
|
+
<span className='opacity-50'>⌘+N</span>
|
|
29
|
+
</ContextMenu.Item>
|
|
30
|
+
<ContextMenu.Item disabled>
|
|
31
|
+
<span className='grow'>New Private Window</span>
|
|
32
|
+
<span className='opacity-50'>⇧+⌘+N</span>
|
|
33
|
+
</ContextMenu.Item>
|
|
34
|
+
{/* <ContextMenu.Sub> */}
|
|
35
|
+
{/* <ContextMenu.SubTrigger> */}
|
|
36
|
+
{/* More Tools */}
|
|
37
|
+
{/* <div> */}
|
|
38
|
+
{/* <ChevronRightIcon /> */}
|
|
39
|
+
{/* </div> */}
|
|
40
|
+
{/* </ContextMenu.SubTrigger> */}
|
|
41
|
+
{/* <ContextMenu.Portal> */}
|
|
42
|
+
{/* <ContextMenu.SubContent sideOffset={2} alignOffset={-5}> */}
|
|
43
|
+
{/* <ContextMenu.Item> */}
|
|
44
|
+
{/* Save Page As… <div>⌘+S</div> */}
|
|
45
|
+
{/* </ContextMenu.Item> */}
|
|
46
|
+
{/* <ContextMenu.Item>Create Shortcut…</ContextMenu.Item> */}
|
|
47
|
+
{/* <ContextMenu.Item>Name Window…</ContextMenu.Item> */}
|
|
48
|
+
{/* <ContextMenu.Separator /> */}
|
|
49
|
+
{/* <ContextMenu.Item>Developer Tools</ContextMenu.Item> */}
|
|
50
|
+
{/* </ContextMenu.SubContent> */}
|
|
51
|
+
{/* </ContextMenu.Portal> */}
|
|
52
|
+
{/* </ContextMenu.Sub> */}
|
|
53
|
+
|
|
54
|
+
{/* <ContextMenu.Separator /> */}
|
|
55
|
+
|
|
56
|
+
{/* <ContextMenu.CheckboxItem checked={bookmarksChecked} onCheckedChange={setBookmarksChecked}> */}
|
|
57
|
+
{/* <ContextMenu.ItemIndicator> */}
|
|
58
|
+
{/* <CheckIcon /> */}
|
|
59
|
+
{/* </ContextMenu.ItemIndicator> */}
|
|
60
|
+
{/* Show Bookmarks <div>⌘+B</div> */}
|
|
61
|
+
{/* </ContextMenu.CheckboxItem> */}
|
|
62
|
+
{/* <ContextMenu.CheckboxItem checked={urlsChecked} onCheckedChange={setUrlsChecked}> */}
|
|
63
|
+
{/* <ContextMenu.ItemIndicator> */}
|
|
64
|
+
{/* <CheckIcon /> */}
|
|
65
|
+
{/* </ContextMenu.ItemIndicator> */}
|
|
66
|
+
{/* Show Full URLs */}
|
|
67
|
+
{/* </ContextMenu.CheckboxItem> */}
|
|
68
|
+
|
|
69
|
+
<ContextMenu.Separator />
|
|
70
|
+
|
|
71
|
+
<ContextMenu.GroupLabel>People</ContextMenu.GroupLabel>
|
|
72
|
+
{/* <ContextMenu.RadioGroup value={person} onValueChange={setPerson}> */}
|
|
73
|
+
{/* <ContextMenu.RadioItem value='pedro'> */}
|
|
74
|
+
{/* <ContextMenu.ItemIndicator> */}
|
|
75
|
+
{/* <DotFilledIcon /> */}
|
|
76
|
+
{/* </ContextMenu.ItemIndicator> */}
|
|
77
|
+
{/* Pedro Duarte */}
|
|
78
|
+
{/* </ContextMenu.RadioItem> */}
|
|
79
|
+
{/* <ContextMenu.RadioItem value='colm'> */}
|
|
80
|
+
{/* <ContextMenu.ItemIndicator> */}
|
|
81
|
+
{/* <DotFilledIcon /> */}
|
|
82
|
+
{/* </ContextMenu.ItemIndicator> */}
|
|
83
|
+
{/* Colm Tuite */}
|
|
84
|
+
{/* </ContextMenu.RadioItem> */}
|
|
85
|
+
{/* </ContextMenu.RadioGroup> */}
|
|
86
|
+
</ContextMenu.Viewport>
|
|
87
|
+
|
|
88
|
+
<ContextMenu.Arrow />
|
|
89
|
+
</ContextMenu.Content>
|
|
90
|
+
</ContextMenu.Root>
|
|
91
|
+
);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export default {
|
|
95
|
+
title: 'react-ui/Context menu',
|
|
96
|
+
component: StorybookContextMenu,
|
|
97
|
+
decorators: [withTheme],
|
|
98
|
+
parameters: { chromatic: { disableSnapshot: false } },
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const Default = {
|
|
102
|
+
args: {},
|
|
103
|
+
parameters: {
|
|
104
|
+
chromatic: { delay: 1600 },
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
import * as ContextMenuPrimitive from '@radix-ui/react-context-menu';
|
|
5
|
+
import { Primitive } from '@radix-ui/react-primitive';
|
|
6
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
7
|
+
import React, { type ComponentPropsWithRef, forwardRef } from 'react';
|
|
8
|
+
|
|
9
|
+
import { useThemeContext } from '../../hooks';
|
|
10
|
+
import { type ThemedClassName } from '../../util';
|
|
11
|
+
import { ElevationProvider } from '../ElevationProvider';
|
|
12
|
+
|
|
13
|
+
type ContextMenuRootProps = ContextMenuPrimitive.ContextMenuProps;
|
|
14
|
+
|
|
15
|
+
const ContextMenuRoot = ContextMenuPrimitive.ContextMenu;
|
|
16
|
+
|
|
17
|
+
type ContextMenuTriggerProps = ContextMenuPrimitive.ContextMenuTriggerProps;
|
|
18
|
+
|
|
19
|
+
const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
|
|
20
|
+
|
|
21
|
+
type ContextMenuPortalProps = ContextMenuPrimitive.ContextMenuPortalProps;
|
|
22
|
+
|
|
23
|
+
const ContextMenuPortal = ContextMenuPrimitive.Portal;
|
|
24
|
+
|
|
25
|
+
type ContextMenuContentProps = ThemedClassName<ContextMenuPrimitive.ContextMenuContentProps> & {
|
|
26
|
+
constrainBlockSize?: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const ContextMenuContent = forwardRef<HTMLDivElement, ContextMenuContentProps>(
|
|
30
|
+
({ classNames, children, ...props }, forwardedRef) => {
|
|
31
|
+
const { tx } = useThemeContext();
|
|
32
|
+
return (
|
|
33
|
+
<ContextMenuPrimitive.Content
|
|
34
|
+
collisionPadding={8}
|
|
35
|
+
{...props}
|
|
36
|
+
className={tx('menu.content', 'menu', {}, classNames)}
|
|
37
|
+
ref={forwardedRef}
|
|
38
|
+
>
|
|
39
|
+
<ElevationProvider elevation='chrome'>{children}</ElevationProvider>
|
|
40
|
+
</ContextMenuPrimitive.Content>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
type ContextMenuViewportProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.div>> & {
|
|
46
|
+
asChild?: boolean;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const ContextMenuViewport = forwardRef<HTMLDivElement, ContextMenuViewportProps>(
|
|
50
|
+
({ classNames, asChild, children, ...props }, forwardedRef) => {
|
|
51
|
+
const { tx } = useThemeContext();
|
|
52
|
+
const Root = asChild ? Slot : Primitive.div;
|
|
53
|
+
return (
|
|
54
|
+
<Root {...props} className={tx('menu.viewport', 'menu__viewport', {}, classNames)} ref={forwardedRef}>
|
|
55
|
+
{children}
|
|
56
|
+
</Root>
|
|
57
|
+
);
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
type ContextMenuArrowProps = ThemedClassName<ContextMenuPrimitive.ContextMenuArrowProps>;
|
|
62
|
+
|
|
63
|
+
const ContextMenuArrow = forwardRef<SVGSVGElement, ContextMenuArrowProps>(({ classNames, ...props }, forwardedRef) => {
|
|
64
|
+
const { tx } = useThemeContext();
|
|
65
|
+
return (
|
|
66
|
+
<ContextMenuPrimitive.Arrow
|
|
67
|
+
{...props}
|
|
68
|
+
className={tx('menu.arrow', 'menu__arrow', {}, classNames)}
|
|
69
|
+
ref={forwardedRef}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
type ContextMenuGroupProps = ContextMenuPrimitive.ContextMenuGroupProps;
|
|
75
|
+
|
|
76
|
+
const ContextMenuGroup = ContextMenuPrimitive.Group;
|
|
77
|
+
|
|
78
|
+
type ContextMenuItemIndicatorProps = ContextMenuPrimitive.ContextMenuItemIndicatorProps;
|
|
79
|
+
|
|
80
|
+
const ContextMenuItemIndicator = ContextMenuPrimitive.ItemIndicator;
|
|
81
|
+
|
|
82
|
+
type ContextMenuItemProps = ThemedClassName<ContextMenuPrimitive.ContextMenuItemProps>;
|
|
83
|
+
|
|
84
|
+
const ContextMenuItem = forwardRef<HTMLDivElement, ContextMenuItemProps>(
|
|
85
|
+
({ classNames, ...props }: ContextMenuItemProps, forwardedRef) => {
|
|
86
|
+
const { tx } = useThemeContext();
|
|
87
|
+
return (
|
|
88
|
+
<ContextMenuPrimitive.Item
|
|
89
|
+
{...props}
|
|
90
|
+
className={tx('menu.item', 'menu__item', {}, classNames)}
|
|
91
|
+
ref={forwardedRef}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
type ContextMenuCheckboxItemProps = ThemedClassName<ContextMenuPrimitive.ContextMenuCheckboxItemProps>;
|
|
98
|
+
|
|
99
|
+
const ContextMenuCheckboxItem = forwardRef<HTMLDivElement, ContextMenuCheckboxItemProps>(
|
|
100
|
+
({ classNames, ...props }: ContextMenuItemProps, forwardedRef) => {
|
|
101
|
+
const { tx } = useThemeContext();
|
|
102
|
+
return (
|
|
103
|
+
<ContextMenuPrimitive.CheckboxItem
|
|
104
|
+
{...props}
|
|
105
|
+
className={tx('menu.item', 'menu__item--checkbox', {}, classNames)}
|
|
106
|
+
ref={forwardedRef}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
type ContextMenuSeparatorProps = ThemedClassName<ContextMenuPrimitive.ContextMenuSeparatorProps>;
|
|
113
|
+
|
|
114
|
+
const ContextMenuSeparator = forwardRef<HTMLDivElement, ContextMenuSeparatorProps>(
|
|
115
|
+
({ classNames, ...props }, forwardedRef) => {
|
|
116
|
+
const { tx } = useThemeContext();
|
|
117
|
+
return (
|
|
118
|
+
<ContextMenuPrimitive.Separator
|
|
119
|
+
{...props}
|
|
120
|
+
className={tx('menu.separator', 'menu__item', {}, classNames)}
|
|
121
|
+
ref={forwardedRef}
|
|
122
|
+
/>
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
type ContextMenuGroupLabelProps = ThemedClassName<ContextMenuPrimitive.ContextMenuLabelProps>;
|
|
128
|
+
|
|
129
|
+
const ContextMenuGroupLabel = forwardRef<HTMLDivElement, ContextMenuGroupLabelProps>(
|
|
130
|
+
({ classNames, ...props }, forwardedRef) => {
|
|
131
|
+
const { tx } = useThemeContext();
|
|
132
|
+
return (
|
|
133
|
+
<ContextMenuPrimitive.Label
|
|
134
|
+
{...props}
|
|
135
|
+
className={tx('menu.groupLabel', 'menu__group__label', {}, classNames)}
|
|
136
|
+
ref={forwardedRef}
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
},
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
export const ContextMenu = {
|
|
143
|
+
Root: ContextMenuRoot,
|
|
144
|
+
Trigger: ContextMenuTrigger,
|
|
145
|
+
Portal: ContextMenuPortal,
|
|
146
|
+
Content: ContextMenuContent,
|
|
147
|
+
Viewport: ContextMenuViewport,
|
|
148
|
+
Arrow: ContextMenuArrow,
|
|
149
|
+
Group: ContextMenuGroup,
|
|
150
|
+
Item: ContextMenuItem,
|
|
151
|
+
CheckboxItem: ContextMenuCheckboxItem,
|
|
152
|
+
ItemIndicator: ContextMenuItemIndicator,
|
|
153
|
+
Separator: ContextMenuSeparator,
|
|
154
|
+
GroupLabel: ContextMenuGroupLabel,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export type {
|
|
158
|
+
ContextMenuRootProps,
|
|
159
|
+
ContextMenuTriggerProps,
|
|
160
|
+
ContextMenuPortalProps,
|
|
161
|
+
ContextMenuContentProps,
|
|
162
|
+
ContextMenuViewportProps,
|
|
163
|
+
ContextMenuArrowProps,
|
|
164
|
+
ContextMenuGroupProps,
|
|
165
|
+
ContextMenuItemProps,
|
|
166
|
+
ContextMenuCheckboxItemProps,
|
|
167
|
+
ContextMenuItemIndicatorProps,
|
|
168
|
+
ContextMenuSeparatorProps,
|
|
169
|
+
ContextMenuGroupLabelProps,
|
|
170
|
+
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
5
|
+
import { Primitive } from '@radix-ui/react-primitive';
|
|
6
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
7
|
+
import React, { type ComponentPropsWithRef, forwardRef } from 'react';
|
|
8
|
+
|
|
9
|
+
import { useThemeContext } from '../../hooks';
|
|
10
|
+
import { type ThemedClassName } from '../../util';
|
|
11
|
+
import { ElevationProvider } from '../ElevationProvider';
|
|
12
|
+
|
|
13
|
+
type DropdownMenuRootProps = DropdownMenuPrimitive.DropdownMenuProps;
|
|
14
|
+
|
|
15
|
+
const DropdownMenuRoot = DropdownMenuPrimitive.DropdownMenu;
|
|
16
|
+
|
|
17
|
+
type DropdownMenuTriggerProps = DropdownMenuPrimitive.DropdownMenuTriggerProps;
|
|
18
|
+
|
|
19
|
+
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
20
|
+
|
|
21
|
+
type DropdownMenuPortalProps = DropdownMenuPrimitive.DropdownMenuPortalProps;
|
|
22
|
+
|
|
23
|
+
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
24
|
+
|
|
25
|
+
type DropdownMenuContentProps = ThemedClassName<DropdownMenuPrimitive.DropdownMenuContentProps> & {
|
|
26
|
+
constrainBlockSize?: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const DropdownMenuContent = forwardRef<HTMLDivElement, DropdownMenuContentProps>(
|
|
30
|
+
({ classNames, children, ...props }, forwardedRef) => {
|
|
31
|
+
const { tx } = useThemeContext();
|
|
32
|
+
return (
|
|
33
|
+
<DropdownMenuPrimitive.Content
|
|
34
|
+
sideOffset={4}
|
|
35
|
+
collisionPadding={8}
|
|
36
|
+
{...props}
|
|
37
|
+
className={tx('menu.content', 'menu', {}, classNames)}
|
|
38
|
+
ref={forwardedRef}
|
|
39
|
+
>
|
|
40
|
+
<ElevationProvider elevation='chrome'>{children}</ElevationProvider>
|
|
41
|
+
</DropdownMenuPrimitive.Content>
|
|
42
|
+
);
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
type DropdownMenuViewportProps = ThemedClassName<ComponentPropsWithRef<typeof Primitive.div>> & {
|
|
47
|
+
asChild?: boolean;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const DropdownMenuViewport = forwardRef<HTMLDivElement, DropdownMenuViewportProps>(
|
|
51
|
+
({ classNames, asChild, children, ...props }, forwardedRef) => {
|
|
52
|
+
const { tx } = useThemeContext();
|
|
53
|
+
const Root = asChild ? Slot : Primitive.div;
|
|
54
|
+
return (
|
|
55
|
+
<Root {...props} className={tx('menu.viewport', 'menu__viewport', {}, classNames)} ref={forwardedRef}>
|
|
56
|
+
{children}
|
|
57
|
+
</Root>
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
type DropdownMenuArrowProps = ThemedClassName<DropdownMenuPrimitive.DropdownMenuArrowProps>;
|
|
63
|
+
|
|
64
|
+
const DropdownMenuArrow = forwardRef<SVGSVGElement, DropdownMenuArrowProps>(
|
|
65
|
+
({ classNames, ...props }, forwardedRef) => {
|
|
66
|
+
const { tx } = useThemeContext();
|
|
67
|
+
return (
|
|
68
|
+
<DropdownMenuPrimitive.Arrow
|
|
69
|
+
{...props}
|
|
70
|
+
className={tx('menu.arrow', 'menu__arrow', {}, classNames)}
|
|
71
|
+
ref={forwardedRef}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
type DropdownMenuGroupProps = DropdownMenuPrimitive.DropdownMenuGroupProps;
|
|
78
|
+
|
|
79
|
+
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
80
|
+
|
|
81
|
+
type DropdownMenuItemIndicatorProps = DropdownMenuPrimitive.DropdownMenuItemIndicatorProps;
|
|
82
|
+
|
|
83
|
+
const DropdownMenuItemIndicator = DropdownMenuPrimitive.ItemIndicator;
|
|
84
|
+
|
|
85
|
+
type DropdownMenuItemProps = ThemedClassName<DropdownMenuPrimitive.DropdownMenuItemProps>;
|
|
86
|
+
|
|
87
|
+
const DropdownMenuItem = forwardRef<HTMLDivElement, DropdownMenuItemProps>(
|
|
88
|
+
({ classNames, ...props }: DropdownMenuItemProps, forwardedRef) => {
|
|
89
|
+
const { tx } = useThemeContext();
|
|
90
|
+
return (
|
|
91
|
+
<DropdownMenuPrimitive.Item
|
|
92
|
+
{...props}
|
|
93
|
+
className={tx('menu.item', 'menu__item', {}, classNames)}
|
|
94
|
+
ref={forwardedRef}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
type DropdownMenuCheckboxItemProps = ThemedClassName<DropdownMenuPrimitive.DropdownMenuCheckboxItemProps>;
|
|
101
|
+
|
|
102
|
+
const DropdownMenuCheckboxItem = forwardRef<HTMLDivElement, DropdownMenuCheckboxItemProps>(
|
|
103
|
+
({ classNames, ...props }: DropdownMenuItemProps, forwardedRef) => {
|
|
104
|
+
const { tx } = useThemeContext();
|
|
105
|
+
return (
|
|
106
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
107
|
+
{...props}
|
|
108
|
+
className={tx('menu.item', 'menu__item--checkbox', {}, classNames)}
|
|
109
|
+
ref={forwardedRef}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
type DropdownMenuSeparatorProps = ThemedClassName<DropdownMenuPrimitive.DropdownMenuSeparatorProps>;
|
|
116
|
+
|
|
117
|
+
const DropdownMenuSeparator = forwardRef<HTMLDivElement, DropdownMenuSeparatorProps>(
|
|
118
|
+
({ classNames, ...props }, forwardedRef) => {
|
|
119
|
+
const { tx } = useThemeContext();
|
|
120
|
+
return (
|
|
121
|
+
<DropdownMenuPrimitive.Separator
|
|
122
|
+
{...props}
|
|
123
|
+
className={tx('menu.separator', 'menu__item', {}, classNames)}
|
|
124
|
+
ref={forwardedRef}
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
type DropdownMenuGroupLabelProps = ThemedClassName<DropdownMenuPrimitive.DropdownMenuLabelProps>;
|
|
131
|
+
|
|
132
|
+
const DropdownMenuGroupLabel = forwardRef<HTMLDivElement, DropdownMenuGroupLabelProps>(
|
|
133
|
+
({ classNames, ...props }, forwardedRef) => {
|
|
134
|
+
const { tx } = useThemeContext();
|
|
135
|
+
return (
|
|
136
|
+
<DropdownMenuPrimitive.Label
|
|
137
|
+
{...props}
|
|
138
|
+
className={tx('menu.groupLabel', 'menu__group__label', {}, classNames)}
|
|
139
|
+
ref={forwardedRef}
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
export const DropdownMenu = {
|
|
146
|
+
Root: DropdownMenuRoot,
|
|
147
|
+
Trigger: DropdownMenuTrigger,
|
|
148
|
+
Portal: DropdownMenuPortal,
|
|
149
|
+
Content: DropdownMenuContent,
|
|
150
|
+
Viewport: DropdownMenuViewport,
|
|
151
|
+
Arrow: DropdownMenuArrow,
|
|
152
|
+
Group: DropdownMenuGroup,
|
|
153
|
+
Item: DropdownMenuItem,
|
|
154
|
+
CheckboxItem: DropdownMenuCheckboxItem,
|
|
155
|
+
ItemIndicator: DropdownMenuItemIndicator,
|
|
156
|
+
Separator: DropdownMenuSeparator,
|
|
157
|
+
GroupLabel: DropdownMenuGroupLabel,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export type {
|
|
161
|
+
DropdownMenuRootProps,
|
|
162
|
+
DropdownMenuTriggerProps,
|
|
163
|
+
DropdownMenuPortalProps,
|
|
164
|
+
DropdownMenuContentProps,
|
|
165
|
+
DropdownMenuViewportProps,
|
|
166
|
+
DropdownMenuArrowProps,
|
|
167
|
+
DropdownMenuGroupProps,
|
|
168
|
+
DropdownMenuItemProps,
|
|
169
|
+
DropdownMenuCheckboxItemProps,
|
|
170
|
+
DropdownMenuItemIndicatorProps,
|
|
171
|
+
DropdownMenuSeparatorProps,
|
|
172
|
+
DropdownMenuGroupLabelProps,
|
|
173
|
+
};
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { enUS as dtLocaleEnUs, type Locale } from 'date-fns/locale';
|
|
5
6
|
import i18Next, { type Resource } from 'i18next';
|
|
6
|
-
import React, { type ReactNode, useEffect, createContext, useState, Suspense } from 'react';
|
|
7
|
-
import { initReactI18next } from 'react-i18next';
|
|
7
|
+
import React, { type ReactNode, useEffect, createContext, useState, Suspense, useContext } from 'react';
|
|
8
|
+
import { initReactI18next, useTranslation as useI18NextTranslation } from 'react-i18next';
|
|
8
9
|
|
|
9
10
|
const initialLng = 'en-US';
|
|
10
11
|
const initialNs = 'dxos-common';
|
|
12
|
+
const initialDtLocale = dtLocaleEnUs;
|
|
11
13
|
|
|
12
14
|
export const resources = {
|
|
13
15
|
[initialLng]: {
|
|
@@ -28,16 +30,32 @@ void i18Next.use(initReactI18next).init({
|
|
|
28
30
|
|
|
29
31
|
export interface TranslationsProviderProps {
|
|
30
32
|
children?: ReactNode;
|
|
33
|
+
// TODO(wittjosiah): Rename to `placeholder` to match ClientProvider?
|
|
34
|
+
// Placeholder => loading, fallback => error.
|
|
31
35
|
fallback?: ReactNode;
|
|
32
36
|
resourceExtensions?: Resource[];
|
|
33
37
|
appNs?: string;
|
|
38
|
+
dtLocale?: Locale;
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
export const TranslationsContext = createContext({
|
|
37
42
|
appNs: initialNs,
|
|
43
|
+
dtLocale: initialDtLocale,
|
|
38
44
|
});
|
|
39
45
|
|
|
40
|
-
export const
|
|
46
|
+
export const useTranslation = (...args: Parameters<typeof useI18NextTranslation>) => {
|
|
47
|
+
const result = useI18NextTranslation(...args);
|
|
48
|
+
const { dtLocale } = useContext(TranslationsContext);
|
|
49
|
+
return { ...result, dtLocale };
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const TranslationsProvider = ({
|
|
53
|
+
fallback,
|
|
54
|
+
resourceExtensions,
|
|
55
|
+
children,
|
|
56
|
+
appNs,
|
|
57
|
+
dtLocale,
|
|
58
|
+
}: TranslationsProviderProps) => {
|
|
41
59
|
const [loaded, setLoaded] = useState(false);
|
|
42
60
|
useEffect(() => {
|
|
43
61
|
setLoaded(false);
|
|
@@ -56,7 +74,7 @@ export const TranslationsProvider = ({ fallback, resourceExtensions, children, a
|
|
|
56
74
|
// TODO(thure): This is not ideal, but i18next was causing `Suspense` to not render the fallback even when the child was asking for namespaces yet to be added.
|
|
57
75
|
// TODO(burdon): Fallbacks should only appear after a short delay, and if the displayed then be visible for 500mx to avoid startup flickering.
|
|
58
76
|
return (
|
|
59
|
-
<TranslationsContext.Provider value={{ appNs: appNs ?? initialNs }}>
|
|
77
|
+
<TranslationsContext.Provider value={{ appNs: appNs ?? initialNs, dtLocale: dtLocale ?? initialDtLocale }}>
|
|
60
78
|
<Suspense fallback={fallback}>{loaded ? children : fallback}</Suspense>
|
|
61
79
|
</TranslationsContext.Provider>
|
|
62
80
|
);
|
package/src/components/index.ts
CHANGED
|
@@ -7,10 +7,10 @@ export * from './Avatars';
|
|
|
7
7
|
export * from './Breadcrumb';
|
|
8
8
|
export * from './Buttons';
|
|
9
9
|
export * from './Dialogs';
|
|
10
|
-
export * from './
|
|
10
|
+
export * from './Menus';
|
|
11
11
|
export * from './Input';
|
|
12
12
|
export * from './Link';
|
|
13
|
-
export * from './
|
|
13
|
+
export * from './List';
|
|
14
14
|
export * from './Main';
|
|
15
15
|
export * from './Message';
|
|
16
16
|
export * from './Popover';
|
package/src/index.ts
CHANGED
|
@@ -8,13 +8,13 @@ import React, { type PropsWithChildren } from 'react';
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
baseSurface,
|
|
11
|
-
|
|
11
|
+
modalSurface,
|
|
12
12
|
groupSurface,
|
|
13
13
|
mx,
|
|
14
14
|
surfaceElevation,
|
|
15
15
|
fixedSurface,
|
|
16
16
|
fixedBorder,
|
|
17
|
-
|
|
17
|
+
attentionSurface,
|
|
18
18
|
} from '@dxos/react-ui-theme';
|
|
19
19
|
|
|
20
20
|
import { withTheme } from '../testing';
|
|
@@ -25,14 +25,14 @@ const Surface = ({
|
|
|
25
25
|
}: PropsWithChildren & { level: 'base' | 'group' | 'chrome' | 'fixed' | 'input' }) => {
|
|
26
26
|
const surface =
|
|
27
27
|
level === 'chrome'
|
|
28
|
-
? [
|
|
28
|
+
? [modalSurface, surfaceElevation({ elevation: 'chrome' })]
|
|
29
29
|
: level === 'group'
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
? [groupSurface, surfaceElevation({ elevation: 'group' })]
|
|
31
|
+
: level === 'input'
|
|
32
|
+
? [attentionSurface, surfaceElevation({ elevation: 'group' })]
|
|
33
|
+
: level === 'fixed'
|
|
34
|
+
? [fixedSurface, fixedBorder, 'border', surfaceElevation({ elevation: 'chrome' })]
|
|
35
|
+
: [baseSurface];
|
|
36
36
|
|
|
37
37
|
return (
|
|
38
38
|
<div
|
|
@@ -44,7 +44,7 @@ const TypographyStory = () => {
|
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
export default {
|
|
47
|
-
title: '
|
|
47
|
+
title: 'react-ui/Scenarios/Typography',
|
|
48
48
|
component: TypographyStory,
|
|
49
49
|
decorators: [withTheme],
|
|
50
50
|
parameters: { chromatic: { disableSnapshot: false } },
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../../../../src/components/DropdownMenu/DropdownMenu.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,iBAAiB,IAAI,8BAA8B,EAExD,KAAK,wBAAwB,IAAI,iCAAiC,EAElE,KAAK,uBAAuB,IAAI,gCAAgC,EAEhE,KAAK,wBAAwB,IAAI,iCAAiC,EAElE,KAAK,sBAAsB,IAAI,+BAA+B,EAE9D,KAAK,sBAAsB,IAAI,+BAA+B,EAE9D,KAAK,qBAAqB,IAAI,8BAA8B,EAE5D,KAAK,6BAA6B,IAAI,sCAAsC,EAE5E,KAAK,8BAA8B,IAAI,uCAAuC,EAE9E,KAAK,0BAA0B,IAAI,mCAAmC,EAEtE,KAAK,sBAAsB,IAAI,+BAA+B,EAC/D,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEtD,OAAO,KAAK,EAAE,EAAE,KAAK,qBAAqB,EAAc,MAAM,OAAO,CAAC;AAGtE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAGlD,KAAK,qBAAqB,GAAG,8BAA8B,CAAC;AAI5D,KAAK,wBAAwB,GAAG,iCAAiC,CAAC;AAIlE,KAAK,uBAAuB,GAAG,gCAAgC,CAAC;AAIhE,KAAK,wBAAwB,GAAG,eAAe,CAAC,iCAAiC,CAAC,GAAG;IAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAmBtH,KAAK,yBAAyB,GAAG,eAAe,CAAC,qBAAqB,CAAC,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAkBF,KAAK,sBAAsB,GAAG,eAAe,CAAC,+BAA+B,CAAC,CAAC;AAe/E,KAAK,sBAAsB,GAAG,+BAA+B,CAAC;AAI9D,KAAK,8BAA8B,GAAG,uCAAuC,CAAC;AAI9E,KAAK,qBAAqB,GAAG,eAAe,CAAC,8BAA8B,CAAC,CAAC;AAe7E,KAAK,6BAA6B,GAAG,eAAe,CAAC,sCAAsC,CAAC,CAAC;AAe7F,KAAK,0BAA0B,GAAG,eAAe,CAAC,mCAAmC,CAAC,CAAC;AAevF,KAAK,2BAA2B,GAAG,eAAe,CAAC,+BAA+B,CAAC,CAAC;AAepF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;CAaxB,CAAC;AAEF,YAAY,EACV,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,EACrB,6BAA6B,EAC7B,8BAA8B,EAC9B,0BAA0B,EAC1B,2BAA2B,GAC5B,CAAC"}
|