@dxos/plugin-navtree 0.8.4-main.f9ba587 → 0.8.4-main.fffef41
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/{app-graph-builder-5J4LRWDX.mjs → app-graph-builder-OHSCN3GX.mjs} +13 -12
- package/dist/lib/browser/app-graph-builder-OHSCN3GX.mjs.map +7 -0
- package/dist/lib/browser/{chunk-WCARAZ7J.mjs → chunk-5VLWX4PK.mjs} +4 -4
- package/dist/lib/browser/chunk-5VLWX4PK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-TZA65AKW.mjs → chunk-7D2MPHXV.mjs} +317 -262
- package/dist/lib/browser/chunk-7D2MPHXV.mjs.map +7 -0
- package/dist/lib/browser/chunk-E6MZBCU5.mjs +19 -0
- package/dist/lib/browser/chunk-E6MZBCU5.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +8 -11
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-3XYN2CBU.mjs → intent-resolver-YUVXVPHG.mjs} +7 -7
- package/dist/lib/browser/intent-resolver-YUVXVPHG.mjs.map +7 -0
- package/dist/lib/browser/{keyboard-QRS6WOQH.mjs → keyboard-YYTYJW4M.mjs} +4 -4
- package/dist/lib/{node-esm/keyboard-MOZWHFUM.mjs.map → browser/keyboard-YYTYJW4M.mjs.map} +2 -2
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-N2HPMYCU.mjs → react-surface-J7MWWAGD.mjs} +10 -10
- package/dist/lib/browser/react-surface-J7MWWAGD.mjs.map +7 -0
- package/dist/lib/browser/{state-54DY3DOY.mjs → state-EUSVT6BI.mjs} +7 -7
- package/dist/lib/browser/state-EUSVT6BI.mjs.map +7 -0
- package/dist/types/src/NavTreePlugin.d.ts +1 -1
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +18 -15
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +2 -2
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/keyboard.d.ts +1 -1
- package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/state.d.ts +2 -2
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +1 -1
- package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.d.ts +2 -2
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +26 -4
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +32 -4
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts +2 -2
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts +2 -0
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +5 -6
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts +12 -0
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/index.d.ts +1 -0
- package/dist/types/src/components/Sidebar/index.d.ts.map +1 -1
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -1
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts +8 -5
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/types.d.ts +2 -2
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/events.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.d.ts +4 -5
- package/dist/types/src/experimental/Tree.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.stories.d.ts +7 -4
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -3
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +1 -1
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +4 -3
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +1 -2
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +49 -50
- package/src/NavTreePlugin.tsx +75 -76
- package/src/capabilities/app-graph-builder.ts +10 -9
- package/src/capabilities/capabilities.ts +2 -2
- package/src/capabilities/intent-resolver.ts +2 -2
- package/src/capabilities/keyboard.ts +2 -2
- package/src/capabilities/react-surface.tsx +5 -5
- package/src/capabilities/state.ts +4 -3
- package/src/components/CommandsDialog/CommandsDialog.tsx +15 -7
- package/src/components/CommandsDialog/CommandsTrigger.tsx +6 -7
- package/src/components/NavTree/NavTree.stories.tsx +67 -53
- package/src/components/NavTree/NavTree.tsx +7 -3
- package/src/components/NavTreeContainer.tsx +91 -36
- package/src/components/NavTreeDocumentTitle.tsx +2 -2
- package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +4 -6
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +11 -10
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +33 -27
- package/src/components/Sidebar/L0Menu.tsx +56 -55
- package/src/components/Sidebar/L1Panel.tsx +72 -97
- package/src/components/Sidebar/L1Tabs.tsx +58 -0
- package/src/components/Sidebar/index.ts +1 -0
- package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +9 -8
- package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +20 -12
- package/src/components/index.ts +1 -1
- package/src/components/types.ts +3 -2
- package/src/events.ts +2 -2
- package/src/experimental/Tree.stories.tsx +36 -38
- package/src/experimental/Tree.tsx +17 -35
- package/src/meta.ts +10 -7
- package/src/testing/app-graph-builder.ts +20 -19
- package/src/testing/generator.ts +2 -2
- package/src/translations.ts +1 -0
- package/src/types.ts +4 -3
- package/src/util.ts +2 -20
- package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs.map +0 -7
- package/dist/lib/browser/chunk-ERDGQTH5.mjs +0 -16
- package/dist/lib/browser/chunk-ERDGQTH5.mjs.map +0 -7
- package/dist/lib/browser/chunk-TZA65AKW.mjs.map +0 -7
- package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs.map +0 -7
- package/dist/lib/browser/keyboard-QRS6WOQH.mjs.map +0 -7
- package/dist/lib/browser/react-surface-N2HPMYCU.mjs.map +0 -7
- package/dist/lib/browser/state-54DY3DOY.mjs.map +0 -7
- package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs +0 -46
- package/dist/lib/node-esm/app-graph-builder-GY7GCTGU.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-CY7QWR4R.mjs +0 -1429
- package/dist/lib/node-esm/chunk-CY7QWR4R.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-P2JGW3WR.mjs +0 -18
- package/dist/lib/node-esm/chunk-P2JGW3WR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-V3QXFDDP.mjs +0 -16
- package/dist/lib/node-esm/chunk-V3QXFDDP.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -150
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs +0 -48
- package/dist/lib/node-esm/intent-resolver-R7UNPSZY.mjs.map +0 -7
- package/dist/lib/node-esm/keyboard-MOZWHFUM.mjs +0 -52
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs +0 -52
- package/dist/lib/node-esm/react-surface-EW5FDMW4.mjs.map +0 -7
- package/dist/lib/node-esm/state-Z3OTRC2I.mjs +0 -118
- package/dist/lib/node-esm/state-Z3OTRC2I.mjs.map +0 -7
|
@@ -5,23 +5,23 @@
|
|
|
5
5
|
import React, { Fragment, memo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { isAction } from '@dxos/app-graph';
|
|
8
|
-
import {
|
|
8
|
+
import { Popover, Treegrid, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
|
|
10
|
-
import { NavTreeItemAction } from './NavTreeItemAction';
|
|
11
10
|
import { useLoadDescendents } from '../../hooks';
|
|
12
|
-
import {
|
|
11
|
+
import { meta } from '../../meta';
|
|
13
12
|
import { NAV_TREE_ITEM } from '../NavTree';
|
|
14
13
|
import { useNavTreeContext } from '../NavTreeContext';
|
|
15
|
-
import type
|
|
14
|
+
import { type NavTreeItemColumnsProps } from '../types';
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
const { t } = useTranslation(NAVTREE_PLUGIN);
|
|
19
|
-
const { getActions, renderItemEnd: ItemEnd, popoverAnchorId } = useNavTreeContext();
|
|
16
|
+
import { NavTreeItemAction } from './NavTreeItemAction';
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
export const NavTreeItemColumns = memo(({ path, item, open }: NavTreeItemColumnsProps) => {
|
|
19
|
+
const { t } = useTranslation(meta.id);
|
|
20
|
+
const { useActions, renderItemEnd: ItemEnd, popoverAnchorId } = useNavTreeContext();
|
|
22
21
|
|
|
23
|
-
const
|
|
24
|
-
const
|
|
22
|
+
const level = path.length - 2;
|
|
23
|
+
const { actions: _actions, groupedActions } = useActions(item);
|
|
24
|
+
const [primaryAction, ...secondaryActions] = _actions.toSorted((a, _b) =>
|
|
25
25
|
a.properties?.disposition === 'list-item-primary' ? -1 : 1,
|
|
26
26
|
);
|
|
27
27
|
|
|
@@ -29,15 +29,15 @@ export const NavTreeItemColumns = memo(({ path, item, open, density = 'fine' }:
|
|
|
29
29
|
.flatMap((action) => (isAction(action) ? [action] : []))
|
|
30
30
|
.filter((a) => ['list-item', 'list-item-primary'].includes(a.properties?.disposition));
|
|
31
31
|
|
|
32
|
-
const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${item.id}` ? Popover.Anchor : Fragment;
|
|
33
|
-
|
|
34
32
|
useLoadDescendents(item);
|
|
35
33
|
useLoadDescendents(primaryAction && !isAction(primaryAction) ? primaryAction : undefined);
|
|
36
34
|
|
|
35
|
+
const ActionRoot = popoverAnchorId === `dxos.org/ui/${NAV_TREE_ITEM}/${item.id}` ? Popover.Anchor : Fragment;
|
|
36
|
+
|
|
37
37
|
return (
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
<div role='none' className='contents app-no-drag'>
|
|
39
|
+
{primaryAction?.properties?.disposition === 'list-item-primary' && !primaryAction?.properties?.disabled ? (
|
|
40
|
+
<Treegrid.Cell classNames='contents'>
|
|
41
41
|
<NavTreeItemAction
|
|
42
42
|
testId={primaryAction.properties?.testId}
|
|
43
43
|
label={toLocalizedString(primaryAction.properties?.label, t)}
|
|
@@ -48,11 +48,13 @@ export const NavTreeItemColumns = memo(({ path, item, open, density = 'fine' }:
|
|
|
48
48
|
menuType={primaryAction.properties?.menuType}
|
|
49
49
|
caller={NAV_TREE_ITEM}
|
|
50
50
|
/>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
</Treegrid.Cell>
|
|
52
|
+
) : (
|
|
53
|
+
<Treegrid.Cell role='none' />
|
|
54
|
+
)}
|
|
55
|
+
<ActionRoot>
|
|
56
|
+
{actions.length > 0 ? (
|
|
57
|
+
<Treegrid.Cell classNames='contents'>
|
|
56
58
|
<NavTreeItemAction
|
|
57
59
|
testId={`navtree.treeItem.actionsLevel${level}`}
|
|
58
60
|
label={t('tree item actions label')}
|
|
@@ -62,12 +64,16 @@ export const NavTreeItemColumns = memo(({ path, item, open, density = 'fine' }:
|
|
|
62
64
|
menuType='dropdown'
|
|
63
65
|
caller={NAV_TREE_ITEM}
|
|
64
66
|
/>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
</Treegrid.Cell>
|
|
68
|
+
) : (
|
|
69
|
+
<Treegrid.Cell role='none' />
|
|
70
|
+
)}
|
|
71
|
+
</ActionRoot>
|
|
72
|
+
{ItemEnd && (
|
|
73
|
+
<Treegrid.Cell classNames='contents'>
|
|
74
|
+
<ItemEnd node={item} open={open} />
|
|
75
|
+
</Treegrid.Cell>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
72
78
|
);
|
|
73
79
|
});
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
extractClosestEdge,
|
|
13
13
|
} from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
14
14
|
import React, {
|
|
15
|
-
forwardRef,
|
|
16
15
|
type MouseEvent,
|
|
17
16
|
type PropsWithChildren,
|
|
17
|
+
forwardRef,
|
|
18
18
|
useCallback,
|
|
19
19
|
useLayoutEffect,
|
|
20
20
|
useMemo,
|
|
@@ -24,15 +24,25 @@ import React, {
|
|
|
24
24
|
|
|
25
25
|
import { type Node } from '@dxos/app-graph';
|
|
26
26
|
import { invariant } from '@dxos/invariant';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
27
|
+
import { DxAvatar } from '@dxos/lit-ui/react';
|
|
28
|
+
import {
|
|
29
|
+
Icon,
|
|
30
|
+
ListItem,
|
|
31
|
+
ScrollArea,
|
|
32
|
+
type ThemedClassName,
|
|
33
|
+
Tooltip,
|
|
34
|
+
toLocalizedString,
|
|
35
|
+
useMediaQuery,
|
|
36
|
+
useTranslation,
|
|
37
|
+
} from '@dxos/react-ui';
|
|
38
|
+
import { DropdownMenu, type MenuItem, MenuProvider } from '@dxos/react-ui-menu';
|
|
29
39
|
import type { StackItemRearrangeHandler } from '@dxos/react-ui-stack';
|
|
30
40
|
import { Tabs } from '@dxos/react-ui-tabs';
|
|
31
41
|
import { mx } from '@dxos/react-ui-theme';
|
|
32
|
-
import { arrayMove
|
|
42
|
+
import { arrayMove } from '@dxos/util';
|
|
33
43
|
|
|
34
44
|
import { useLoadDescendents } from '../../hooks';
|
|
35
|
-
import {
|
|
45
|
+
import { meta } from '../../meta';
|
|
36
46
|
import { l0ItemType } from '../../util';
|
|
37
47
|
import { useNavTreeContext } from '../NavTreeContext';
|
|
38
48
|
import { UserAccountAvatar } from '../UserAccountAvatar';
|
|
@@ -62,7 +72,7 @@ type L0ItemProps = L0ItemRootProps & {
|
|
|
62
72
|
|
|
63
73
|
const useL0ItemClick = ({ item, parent, path }: L0ItemProps, type: string) => {
|
|
64
74
|
const { tab, isCurrent, onSelect, onTabChange } = useNavTreeContext();
|
|
65
|
-
const [isLg] = useMediaQuery('lg'
|
|
75
|
+
const [isLg] = useMediaQuery('lg');
|
|
66
76
|
|
|
67
77
|
return useCallback(
|
|
68
78
|
(event: MouseEvent) => {
|
|
@@ -92,7 +102,7 @@ const l0Breakpoints: Record<string, string> = {
|
|
|
92
102
|
};
|
|
93
103
|
|
|
94
104
|
const l0ItemRoot =
|
|
95
|
-
'group/l0item flex
|
|
105
|
+
'group/l0item flex is-full justify-center items-center relative data[type!="collection"]:cursor-pointer app-no-drag dx-focus-ring-group';
|
|
96
106
|
|
|
97
107
|
const l0ItemContent = 'flex justify-center items-center dx-focus-ring-group-indicator transition-colors rounded-sm';
|
|
98
108
|
|
|
@@ -103,55 +113,45 @@ const L0ItemRoot = forwardRef<HTMLElement, PropsWithChildren<L0ItemRootProps>>(
|
|
|
103
113
|
const type = l0ItemType(item);
|
|
104
114
|
const itemPath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
105
115
|
|
|
106
|
-
const { t } = useTranslation(
|
|
116
|
+
const { t } = useTranslation(meta.id);
|
|
107
117
|
const localizedString = toLocalizedString(item.properties.label, t);
|
|
108
118
|
|
|
109
119
|
const handleClick = useL0ItemClick({ item, parent, path: itemPath }, type);
|
|
110
120
|
const rootProps =
|
|
111
121
|
type === 'tab'
|
|
112
|
-
? { value: item.id, tabIndex: 0, onClick: handleClick, 'data-testid': testId, 'data-
|
|
122
|
+
? { value: item.id, tabIndex: 0, onClick: handleClick, 'data-testid': testId, 'data-object-id': id }
|
|
113
123
|
: type !== 'collection'
|
|
114
|
-
? { onClick: handleClick, 'data-testid': testId, 'data-
|
|
115
|
-
: { onClick: handleClick };
|
|
116
|
-
|
|
117
|
-
const Root = type === 'collection' ? 'h2' : type === 'tab' ? Tabs.TabPrimitive : 'button';
|
|
124
|
+
? { onClick: handleClick, 'data-testid': testId, 'data-object-id': id }
|
|
125
|
+
: { onClick: handleClick, role: 'button' };
|
|
118
126
|
|
|
119
127
|
return (
|
|
120
128
|
<Tooltip.Trigger asChild delayDuration={0} side='right' content={localizedString}>
|
|
121
|
-
<
|
|
129
|
+
<Tabs.TabPrimitive
|
|
122
130
|
{...(rootProps as any)}
|
|
123
131
|
data-type={type}
|
|
124
132
|
className={mx(l0ItemRoot, l0Breakpoints[item.properties.l0Breakpoint])}
|
|
125
133
|
ref={forwardedRef}
|
|
126
134
|
>
|
|
127
135
|
{children}
|
|
128
|
-
</
|
|
136
|
+
</Tabs.TabPrimitive>
|
|
129
137
|
</Tooltip.Trigger>
|
|
130
138
|
);
|
|
131
139
|
},
|
|
132
140
|
);
|
|
133
141
|
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
return (
|
|
146
|
-
<span role='img' className='place-self-center text-xl font-light' {...hueFgStyle}>
|
|
147
|
-
{avatarValue}
|
|
148
|
-
</span>
|
|
149
|
-
);
|
|
150
|
-
};
|
|
142
|
+
export const L0ItemActiveTabIndicator = ({ classNames }: ThemedClassName<{}>) => (
|
|
143
|
+
<div
|
|
144
|
+
role='none'
|
|
145
|
+
className={mx(
|
|
146
|
+
'hidden group-aria-selected/l0item:block absolute inline-start-0 inset-block-2 is-1 bg-accentSurface rounded-ie',
|
|
147
|
+
classNames,
|
|
148
|
+
)}
|
|
149
|
+
/>
|
|
150
|
+
);
|
|
151
151
|
|
|
152
152
|
// TODO(burdon): Factor out pinned (non-draggable) items.
|
|
153
153
|
const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
|
|
154
|
-
const { t } = useTranslation(
|
|
154
|
+
const { t } = useTranslation(meta.id);
|
|
155
155
|
const itemElement = useRef<HTMLElement | null>(null);
|
|
156
156
|
const [closestEdge, setEdge] = useState<Edge | null>(null);
|
|
157
157
|
const localizedString = toLocalizedString(item.properties.label, t);
|
|
@@ -228,10 +228,7 @@ const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
|
|
|
228
228
|
>
|
|
229
229
|
<ItemAvatar item={item} />
|
|
230
230
|
</div>
|
|
231
|
-
<
|
|
232
|
-
role='none'
|
|
233
|
-
className='hidden group-aria-selected/l0item:block absolute inline-start-0 inset-block-2 is-1 bg-accentSurface rounded-ie'
|
|
234
|
-
/>
|
|
231
|
+
<L0ItemActiveTabIndicator />
|
|
235
232
|
<span id={`${item.id}__label`} className='sr-only'>
|
|
236
233
|
{localizedString}
|
|
237
234
|
</span>
|
|
@@ -241,15 +238,18 @@ const L0Item = ({ item, parent, path, pinned, onRearrange }: L0ItemProps) => {
|
|
|
241
238
|
};
|
|
242
239
|
|
|
243
240
|
const ItemAvatar = ({ item }: Pick<L0ItemProps, 'item'>) => {
|
|
241
|
+
const { t } = useTranslation(meta.id);
|
|
244
242
|
const type = l0ItemType(item);
|
|
245
243
|
if (item.properties.icon) {
|
|
246
244
|
const hue = item.properties.hue ?? null;
|
|
247
245
|
const hueFgStyle = hue && { style: { color: `var(--dx-${hue}SurfaceText)` } };
|
|
248
|
-
return <Icon icon={item.properties.icon} size={
|
|
246
|
+
return <Icon icon={item.properties.icon} size={6} {...hueFgStyle} />;
|
|
249
247
|
}
|
|
250
248
|
|
|
251
249
|
if (type === 'tab' && item.properties.disposition !== 'pin-end') {
|
|
252
|
-
|
|
250
|
+
const hue = item.properties.hue ?? null;
|
|
251
|
+
const localizedString = toLocalizedString(item.properties.label, t);
|
|
252
|
+
return <DxAvatar hue={hue} hueVariant='surface' variant='square' size={12} fallback={localizedString} />;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
return null;
|
|
@@ -287,7 +287,7 @@ const L0Collection = ({ item, path }: L0ItemProps) => {
|
|
|
287
287
|
role='group'
|
|
288
288
|
className='contents group/l0c'
|
|
289
289
|
aria-labelledby={`${item.id}__label`}
|
|
290
|
-
data-
|
|
290
|
+
data-object-id={id}
|
|
291
291
|
data-testid={testId}
|
|
292
292
|
>
|
|
293
293
|
{collectionItems.map((collectionItem) => (
|
|
@@ -317,7 +317,7 @@ export type L0MenuProps = {
|
|
|
317
317
|
};
|
|
318
318
|
|
|
319
319
|
export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountItem, parent, path }: L0MenuProps) => {
|
|
320
|
-
const { t } = useTranslation(
|
|
320
|
+
const { t } = useTranslation(meta.id);
|
|
321
321
|
|
|
322
322
|
return (
|
|
323
323
|
<Tabs.Tablist
|
|
@@ -331,20 +331,22 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
|
|
|
331
331
|
<MenuProvider>
|
|
332
332
|
<DropdownMenu.Root group={parent} items={menuActions}>
|
|
333
333
|
<Tooltip.Trigger content={t('app menu label')} side='right' asChild>
|
|
334
|
-
<
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
<div
|
|
339
|
-
role='none'
|
|
340
|
-
className={mx(
|
|
341
|
-
l0ItemContent,
|
|
342
|
-
'is-[--rail-action] bs-[--rail-action] group-hover/l0item:bg-hoverSurface',
|
|
343
|
-
)}
|
|
334
|
+
<Tabs.TabPrimitive value='options' asChild role='button'>
|
|
335
|
+
<DropdownMenu.Trigger
|
|
336
|
+
data-testid='spacePlugin.addSpace'
|
|
337
|
+
className={mx(l0ItemRoot, 'grid place-items-center dx-focus-ring-group')}
|
|
344
338
|
>
|
|
345
|
-
<
|
|
346
|
-
|
|
347
|
-
|
|
339
|
+
<div
|
|
340
|
+
role='none'
|
|
341
|
+
className={mx(
|
|
342
|
+
l0ItemContent,
|
|
343
|
+
'is-[--rail-action] bs-[--rail-action] group-hover/l0item:bg-hoverSurface',
|
|
344
|
+
)}
|
|
345
|
+
>
|
|
346
|
+
<Icon icon='ph--list--regular' size={5} />
|
|
347
|
+
</div>
|
|
348
|
+
</DropdownMenu.Trigger>
|
|
349
|
+
</Tabs.TabPrimitive>
|
|
348
350
|
</Tooltip.Trigger>
|
|
349
351
|
</DropdownMenu.Root>
|
|
350
352
|
</MenuProvider>
|
|
@@ -396,7 +398,6 @@ export const L0Menu = ({ menuActions, topLevelItems, pinnedItems, userAccountIte
|
|
|
396
398
|
</L0ItemRoot>
|
|
397
399
|
</div>
|
|
398
400
|
)}
|
|
399
|
-
|
|
400
401
|
<div
|
|
401
402
|
role='none'
|
|
402
403
|
className='hidden [body[data-platform="darwin"]_&]:block absolute block-start-0 is-[calc(var(--l0-size)-1px)] bs-[calc(40px+0.25rem)]'
|
|
@@ -5,68 +5,44 @@
|
|
|
5
5
|
import React, { useCallback, useMemo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { type Node } from '@dxos/app-graph';
|
|
8
|
-
import {
|
|
8
|
+
import { DensityProvider, IconButton, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
import { Tree } from '@dxos/react-ui-list';
|
|
10
10
|
import { Tabs } from '@dxos/react-ui-tabs';
|
|
11
|
-
import { hoverableControlItem, hoverableOpenControlItem
|
|
11
|
+
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/react-ui-theme';
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
import { NAVTREE_PLUGIN } from '../../meta';
|
|
15
|
-
import { l0ItemType } from '../../util';
|
|
13
|
+
import { meta } from '../../meta';
|
|
16
14
|
import { useNavTreeContext } from '../NavTreeContext';
|
|
17
15
|
import { NavTreeItemColumns } from '../NavTreeItem';
|
|
18
16
|
|
|
19
|
-
const headingBackButtonLabel = 'inset-0 min-is-0 truncate flex items-center pis-2';
|
|
20
|
-
|
|
21
|
-
const TitleButton = ({ title, onClick }: { title: string } & Pick<ButtonProps, 'onClick'>) => {
|
|
22
|
-
return (
|
|
23
|
-
<Button
|
|
24
|
-
variant='ghost'
|
|
25
|
-
classNames='pli-1 flex-1 group text-start justify-start bs-[--rail-action] font-normal'
|
|
26
|
-
onClick={onClick}
|
|
27
|
-
>
|
|
28
|
-
<Icon icon='ph--caret-left--bold' size={3} />
|
|
29
|
-
<span className={mx(headingBackButtonLabel)}>{title}</span>
|
|
30
|
-
</Button>
|
|
31
|
-
);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
17
|
export type L1PanelProps = {
|
|
35
18
|
open?: boolean;
|
|
36
|
-
item: Node<any>;
|
|
37
19
|
path: string[];
|
|
20
|
+
item: Node<any>;
|
|
38
21
|
currentItemId: string;
|
|
39
22
|
onBack?: () => void;
|
|
40
23
|
};
|
|
41
24
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Space or settings panel.
|
|
27
|
+
*/
|
|
28
|
+
export const L1Panel = ({ open, path, item, currentItemId, onBack }: L1PanelProps) => {
|
|
29
|
+
const { t } = useTranslation(meta.id);
|
|
30
|
+
const { isAlternateTree, ...navTreeContext } = useNavTreeContext();
|
|
31
|
+
const title = toLocalizedString(item.properties.label, t);
|
|
45
32
|
|
|
46
33
|
// TODO(wittjosiah): Support multiple alternate trees.
|
|
47
|
-
const
|
|
34
|
+
const { useItems } = navTreeContext;
|
|
35
|
+
const alternateTree = useItems(item, { disposition: 'alternate-tree' })[0];
|
|
48
36
|
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
49
|
-
const handleOpen = useCallback(() => setAlternateTree?.(alternatePath, true), [alternatePath, setAlternateTree]);
|
|
50
37
|
const isAlternate = isAlternateTree?.(alternatePath, item) ?? false;
|
|
51
38
|
const useAlternateItems = useCallback(
|
|
52
39
|
(node?: Node, { disposition }: { disposition?: string } = {}) => {
|
|
53
40
|
// TODO(wittjosiah): Sorting is expensive, limit to necessary items for now.
|
|
54
|
-
return
|
|
41
|
+
return useItems(node, { disposition, sort: node?.id === alternateTree.id });
|
|
55
42
|
},
|
|
56
|
-
[
|
|
43
|
+
[alternateTree, useItems],
|
|
57
44
|
);
|
|
58
45
|
|
|
59
|
-
const handleBack = useCallback(() => {
|
|
60
|
-
if (isAlternate) {
|
|
61
|
-
setAlternateTree?.(alternatePath, false);
|
|
62
|
-
} else {
|
|
63
|
-
onBack?.();
|
|
64
|
-
}
|
|
65
|
-
}, [isAlternate, onBack, alternatePath, setAlternateTree]);
|
|
66
|
-
|
|
67
|
-
const title = toLocalizedString(item.properties.label, t);
|
|
68
|
-
const backCapable = item.id.startsWith('!') || isAlternate;
|
|
69
|
-
|
|
70
46
|
return (
|
|
71
47
|
<Tabs.Tabpanel
|
|
72
48
|
key={item.id}
|
|
@@ -79,41 +55,22 @@ const L1Panel = ({ open, item, path, currentItemId, onBack }: L1PanelProps) => {
|
|
|
79
55
|
]}
|
|
80
56
|
tabIndex={-1}
|
|
81
57
|
aria-label={title}
|
|
82
|
-
{...(!open && { inert:
|
|
58
|
+
{...(!open && { inert: true })}
|
|
83
59
|
>
|
|
84
60
|
{item.id === currentItemId && (
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
{backCapable ? (
|
|
88
|
-
<TitleButton title={title} onClick={handleBack} />
|
|
89
|
-
) : (
|
|
90
|
-
<span className='flex-1 truncate min-is-0 pis-6'>{title}</span>
|
|
91
|
-
)}
|
|
92
|
-
{alternateTree && !isAlternate && (
|
|
93
|
-
<IconButton
|
|
94
|
-
variant='ghost'
|
|
95
|
-
classNames={mx('shrink-0', hoverableControlItem, hoverableOpenControlItem, 'pli-2 pointer-fine:pli-1')}
|
|
96
|
-
iconOnly
|
|
97
|
-
size={5}
|
|
98
|
-
icon={alternateTree.properties.icon ?? 'ph--placeholder--regular'}
|
|
99
|
-
label={toLocalizedString(alternateTree.properties.label ?? alternateTree.id, t)}
|
|
100
|
-
data-testid='treeView.alternateTreeButton'
|
|
101
|
-
onClick={handleOpen}
|
|
102
|
-
/>
|
|
103
|
-
)}
|
|
104
|
-
<NavTreeItemColumns path={path} item={item} open density='coarse' />
|
|
105
|
-
</h2>
|
|
61
|
+
<DensityProvider density='fine'>
|
|
62
|
+
<L1PanelHeader path={path} item={item} currentItemId={currentItemId} onBack={onBack} />
|
|
106
63
|
<div role='none' className='overflow-y-auto'>
|
|
107
64
|
{isAlternate ? (
|
|
108
65
|
<Tree
|
|
109
66
|
{...navTreeContext}
|
|
110
|
-
useItems={useAlternateItems}
|
|
111
67
|
id={alternateTree.id}
|
|
112
68
|
root={alternateTree}
|
|
113
69
|
path={alternatePath}
|
|
114
70
|
levelOffset={5}
|
|
115
71
|
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
116
72
|
renderColumns={NavTreeItemColumns}
|
|
73
|
+
useItems={useAlternateItems}
|
|
117
74
|
/>
|
|
118
75
|
) : (
|
|
119
76
|
<Tree
|
|
@@ -122,53 +79,71 @@ const L1Panel = ({ open, item, path, currentItemId, onBack }: L1PanelProps) => {
|
|
|
122
79
|
root={item}
|
|
123
80
|
path={path}
|
|
124
81
|
levelOffset={5}
|
|
125
|
-
draggable
|
|
126
82
|
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
127
83
|
renderColumns={NavTreeItemColumns}
|
|
84
|
+
draggable
|
|
128
85
|
/>
|
|
129
86
|
)}
|
|
130
87
|
</div>
|
|
131
|
-
|
|
88
|
+
</DensityProvider>
|
|
132
89
|
)}
|
|
133
90
|
</Tabs.Tabpanel>
|
|
134
91
|
);
|
|
135
92
|
};
|
|
136
93
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
{collectionItems
|
|
145
|
-
.filter((item) => l0ItemType(item) === 'tab')
|
|
146
|
-
.map((item) => (
|
|
147
|
-
<L1Panel key={item.id} item={item} path={groupPath} {...props} />
|
|
148
|
-
))}
|
|
149
|
-
</>
|
|
150
|
-
);
|
|
151
|
-
};
|
|
94
|
+
/**
|
|
95
|
+
* Header row.
|
|
96
|
+
*/
|
|
97
|
+
const L1PanelHeader = ({ item, path, onBack }: L1PanelProps) => {
|
|
98
|
+
const { t } = useTranslation(meta.id);
|
|
99
|
+
const { isAlternateTree, setAlternateTree, ...navTreeContext } = useNavTreeContext();
|
|
100
|
+
const title = toLocalizedString(item.properties.label, t);
|
|
152
101
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
path
|
|
156
|
-
|
|
102
|
+
// TODO(wittjosiah): Support multiple alternate trees.
|
|
103
|
+
const alternateTree = navTreeContext.useItems(item, { disposition: 'alternate-tree' })[0];
|
|
104
|
+
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
105
|
+
const isAlternate = isAlternateTree?.(alternatePath, item) ?? false;
|
|
106
|
+
const backCapable = item.id.startsWith('!') || isAlternate;
|
|
107
|
+
|
|
108
|
+
const handleOpen = useCallback(() => {
|
|
109
|
+
setAlternateTree?.(alternatePath, true);
|
|
110
|
+
}, [alternatePath, setAlternateTree]);
|
|
111
|
+
|
|
112
|
+
const handleBack = useCallback(() => {
|
|
113
|
+
if (isAlternate) {
|
|
114
|
+
setAlternateTree?.(alternatePath, false);
|
|
115
|
+
} else {
|
|
116
|
+
onBack?.();
|
|
117
|
+
}
|
|
118
|
+
}, [isAlternate, alternatePath, setAlternateTree, onBack]);
|
|
157
119
|
|
|
158
|
-
|
|
120
|
+
// TODO(burdon): Reuse same grid as tree?
|
|
159
121
|
return (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
122
|
+
<div className='flex is-full items-center border-be border-subduedSeparator app-drag density-coarse'>
|
|
123
|
+
<div className='is-6' />
|
|
124
|
+
<h2 className='flex-1 truncate min-is-0'>{title}</h2>
|
|
125
|
+
{(backCapable && (
|
|
126
|
+
<IconButton
|
|
127
|
+
variant='ghost'
|
|
128
|
+
icon='ph--arrow-u-down-left--regular'
|
|
129
|
+
iconOnly
|
|
130
|
+
label={t('button back')}
|
|
131
|
+
classNames={[hoverableControlItem, hoverableOpenControlItem, 'pointer-fine:pli-1']}
|
|
132
|
+
onClick={handleBack}
|
|
133
|
+
/>
|
|
134
|
+
)) ||
|
|
135
|
+
(alternateTree && !isAlternate && (
|
|
136
|
+
<IconButton
|
|
137
|
+
data-testid='treeView.alternateTreeButton'
|
|
138
|
+
variant='ghost'
|
|
139
|
+
icon={alternateTree.properties.icon ?? 'ph--placeholder--regular'}
|
|
140
|
+
iconOnly
|
|
141
|
+
label={toLocalizedString(alternateTree.properties.label ?? alternateTree.id, t)}
|
|
142
|
+
classNames={[hoverableControlItem, hoverableOpenControlItem, 'pointer-fine:pli-1']}
|
|
143
|
+
onClick={handleOpen}
|
|
144
|
+
/>
|
|
145
|
+
))}
|
|
146
|
+
<NavTreeItemColumns open path={path} item={item} density='coarse' />
|
|
147
|
+
</div>
|
|
173
148
|
);
|
|
174
149
|
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type Node } from '@dxos/app-graph';
|
|
8
|
+
|
|
9
|
+
import { useLoadDescendents } from '../../hooks';
|
|
10
|
+
import { l0ItemType } from '../../util';
|
|
11
|
+
import { useNavTreeContext } from '../NavTreeContext';
|
|
12
|
+
|
|
13
|
+
import { L1Panel, type L1PanelProps } from './L1Panel';
|
|
14
|
+
|
|
15
|
+
export type L1TabsProps = Pick<L1PanelProps, 'open' | 'currentItemId' | 'onBack'> & {
|
|
16
|
+
path: string[];
|
|
17
|
+
topLevelItems: Node<any>[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Each space is an L1 tab.
|
|
22
|
+
*/
|
|
23
|
+
export const L1Tabs = ({ topLevelItems, onBack, ...props }: L1TabsProps) => {
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
{topLevelItems.map((item) => {
|
|
27
|
+
const type = l0ItemType(item);
|
|
28
|
+
switch (type) {
|
|
29
|
+
case 'tab':
|
|
30
|
+
return <L1Panel key={item.id} item={item} {...props} onBack={onBack} />;
|
|
31
|
+
case 'collection':
|
|
32
|
+
return <L1PanelCollection key={item.id} item={item} {...props} />;
|
|
33
|
+
default:
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
})}
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
*
|
|
43
|
+
*/
|
|
44
|
+
const L1PanelCollection = ({ item, path, ...props }: L1PanelProps) => {
|
|
45
|
+
const { useItems } = useNavTreeContext();
|
|
46
|
+
useLoadDescendents(item);
|
|
47
|
+
const collectionItems = useItems(item);
|
|
48
|
+
const groupPath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
{collectionItems
|
|
52
|
+
.filter((item) => l0ItemType(item) === 'tab')
|
|
53
|
+
.map((item) => (
|
|
54
|
+
<L1Panel key={item.id} item={item} path={groupPath} {...props} />
|
|
55
|
+
))}
|
|
56
|
+
</>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import { withTheme } from '@dxos/storybook-utils';
|
|
7
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
10
8
|
|
|
11
9
|
import { UserAccountAvatar } from './UserAccountAvatar';
|
|
12
10
|
|
|
13
|
-
const meta
|
|
11
|
+
const meta = {
|
|
14
12
|
title: 'plugins/plugin-navtree/UserAccountAvatar',
|
|
15
|
-
|
|
13
|
+
|
|
16
14
|
decorators: [withTheme],
|
|
17
|
-
|
|
15
|
+
component: UserAccountAvatar,
|
|
16
|
+
} satisfies Meta<typeof UserAccountAvatar>;
|
|
18
17
|
|
|
19
18
|
export default meta;
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
type Story = StoryObj<typeof meta>;
|
|
21
|
+
|
|
22
|
+
export const Default: Story = {};
|