@dxos/plugin-navtree 0.8.4-main.3f58842 → 0.8.4-main.52d7546f51
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-XGA4GPGL.mjs +44 -0
- package/dist/lib/browser/app-graph-builder-XGA4GPGL.mjs.map +7 -0
- package/dist/lib/browser/chunk-63YLDLLE.mjs +1373 -0
- package/dist/lib/browser/chunk-63YLDLLE.mjs.map +7 -0
- package/dist/lib/browser/chunk-X2HDG62A.mjs +23 -0
- package/dist/lib/browser/chunk-X2HDG62A.mjs.map +7 -0
- package/dist/lib/browser/chunk-YKTYPINZ.mjs +19 -0
- package/dist/lib/browser/chunk-YKTYPINZ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +85 -96
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/{keyboard-QRS6WOQH.mjs → keyboard-46XQHY2O.mjs} +21 -19
- package/dist/lib/browser/keyboard-46XQHY2O.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/operation-resolver-NNNDII45.mjs +53 -0
- package/dist/lib/browser/operation-resolver-NNNDII45.mjs.map +7 -0
- package/dist/lib/browser/react-surface-APSEG23H.mjs +59 -0
- package/dist/lib/browser/react-surface-APSEG23H.mjs.map +7 -0
- package/dist/lib/browser/state-M5YUCIQU.mjs +121 -0
- package/dist/lib/browser/state-M5YUCIQU.mjs.map +7 -0
- package/dist/types/src/NavTreePlugin.d.ts +2 -1
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +6 -0
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts +3 -0
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +5 -105
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/keyboard/index.d.ts +3 -0
- package/dist/types/src/capabilities/keyboard/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts +5 -0
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-resolver/index.d.ts +3 -0
- package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +5 -0
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface/index.d.ts +3 -0
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/state/index.d.ts +3 -0
- package/dist/types/src/capabilities/state/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/state/state.d.ts +6 -0
- package/dist/types/src/capabilities/state/state.d.ts.map +1 -0
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts +3 -2
- 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 +32 -3
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +29 -4
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeContainer.d.ts +8 -1
- package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts +1 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +6 -6
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +33 -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 +6 -4
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +6 -7
- 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.map +1 -1
- package/dist/types/src/components/types.d.ts +8 -8
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.d.ts +1 -2
- package/dist/types/src/experimental/Tree.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.stories.d.ts +23 -6
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/hooks.d.ts +32 -1
- package/dist/types/src/hooks.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +3 -4
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/app-graph-builder.d.ts +2 -3
- package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +5 -6
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/testing/update-state.d.ts +2 -2
- package/dist/types/src/testing/update-state.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/capabilities.d.ts +16 -0
- package/dist/types/src/types/capabilities.d.ts.map +1 -0
- package/dist/types/src/types/events.d.ts +5 -0
- package/dist/types/src/types/events.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +4 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/{types.d.ts → types/schema.d.ts} +10 -9
- package/dist/types/src/types/schema.d.ts.map +1 -0
- package/dist/types/src/util.d.ts +8 -9
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +56 -53
- package/src/NavTreePlugin.tsx +63 -83
- package/src/capabilities/app-graph-builder/app-graph-builder.ts +42 -0
- package/src/capabilities/app-graph-builder/index.ts +7 -0
- package/src/capabilities/index.ts +5 -9
- package/src/capabilities/keyboard/index.ts +7 -0
- package/src/capabilities/keyboard/keyboard.ts +66 -0
- package/src/capabilities/operation-resolver/index.ts +7 -0
- package/src/capabilities/operation-resolver/operation-resolver.ts +42 -0
- package/src/capabilities/react-surface/index.ts +7 -0
- package/src/capabilities/react-surface/react-surface.tsx +55 -0
- package/src/capabilities/state/index.ts +7 -0
- package/src/capabilities/state/state.ts +122 -0
- package/src/components/CommandsDialog/CommandsDialog.tsx +108 -98
- package/src/components/CommandsDialog/CommandsTrigger.tsx +6 -15
- package/src/components/NavTree/NavTree.stories.tsx +99 -93
- package/src/components/NavTree/NavTree.tsx +12 -18
- package/src/components/NavTreeContainer.tsx +282 -257
- package/src/components/NavTreeDocumentTitle.tsx +5 -4
- package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +20 -12
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +25 -18
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +38 -32
- package/src/components/Sidebar/L0Menu.tsx +115 -143
- package/src/components/Sidebar/L1Panel.tsx +177 -121
- package/src/components/Sidebar/L1Tabs.tsx +33 -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 -0
- package/src/components/types.ts +9 -8
- package/src/experimental/Tree.stories.tsx +69 -77
- package/src/experimental/Tree.tsx +7 -24
- package/src/hooks.ts +54 -2
- package/src/index.ts +1 -2
- package/src/meta.ts +11 -8
- package/src/testing/app-graph-builder.ts +159 -234
- package/src/testing/generator.ts +20 -18
- package/src/testing/update-state.ts +6 -6
- package/src/translations.ts +1 -0
- package/src/types/capabilities.ts +21 -0
- package/src/types/events.ts +12 -0
- package/src/types/index.ts +7 -0
- package/src/{types.ts → types/schema.ts} +9 -8
- package/src/util.ts +14 -35
- package/dist/lib/browser/app-graph-builder-5J4LRWDX.mjs +0 -45
- 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-SICQTLXC.mjs +0 -1442
- package/dist/lib/browser/chunk-SICQTLXC.mjs.map +0 -7
- package/dist/lib/browser/chunk-WCARAZ7J.mjs +0 -15
- package/dist/lib/browser/chunk-WCARAZ7J.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-3XYN2CBU.mjs +0 -47
- 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-WURHCBQQ.mjs +0 -51
- package/dist/lib/browser/react-surface-WURHCBQQ.mjs.map +0 -7
- package/dist/lib/browser/state-54DY3DOY.mjs +0 -117
- package/dist/lib/browser/state-54DY3DOY.mjs.map +0 -7
- package/dist/types/src/capabilities/app-graph-builder.d.ts +0 -4
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +0 -1
- package/dist/types/src/capabilities/capabilities.d.ts +0 -21
- package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
- package/dist/types/src/capabilities/keyboard.d.ts +0 -4
- package/dist/types/src/capabilities/keyboard.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface.d.ts +0 -4
- package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
- package/dist/types/src/capabilities/state.d.ts +0 -20
- package/dist/types/src/capabilities/state.d.ts.map +0 -1
- package/dist/types/src/events.d.ts +0 -4
- package/dist/types/src/events.d.ts.map +0 -1
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/capabilities/app-graph-builder.ts +0 -52
- package/src/capabilities/capabilities.ts +0 -20
- package/src/capabilities/intent-resolver.ts +0 -37
- package/src/capabilities/keyboard.ts +0 -59
- package/src/capabilities/react-surface.tsx +0 -45
- package/src/capabilities/state.ts +0 -104
- package/src/events.ts +0 -11
|
@@ -2,71 +2,52 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
5
6
|
import React, { useCallback, useMemo } from 'react';
|
|
6
7
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import { Node } from '@dxos/app-graph';
|
|
9
|
+
import { useActionRunner } from '@dxos/plugin-graph';
|
|
10
|
+
import { DensityProvider, IconButton, ScrollArea, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
9
11
|
import { Tree } from '@dxos/react-ui-list';
|
|
12
|
+
import { DropdownMenu, type MenuItem, MenuProvider } from '@dxos/react-ui-menu';
|
|
10
13
|
import { Tabs } from '@dxos/react-ui-tabs';
|
|
11
|
-
import { hoverableControlItem, hoverableOpenControlItem
|
|
14
|
+
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/ui-theme';
|
|
12
15
|
|
|
13
|
-
import { useLoadDescendents } from '../../hooks';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
+
import { useIsAlternateTree, useLoadDescendents } from '../../hooks';
|
|
17
|
+
import { meta } from '../../meta';
|
|
18
|
+
import { NAV_TREE_ITEM } from '../NavTree';
|
|
16
19
|
import { useNavTreeContext } from '../NavTreeContext';
|
|
17
|
-
import { NavTreeItemColumns } from '../NavTreeItem';
|
|
18
|
-
|
|
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
|
-
};
|
|
20
|
+
import { NavTreeItemAction, NavTreeItemColumns } from '../NavTreeItem';
|
|
33
21
|
|
|
34
22
|
export type L1PanelProps = {
|
|
35
23
|
open?: boolean;
|
|
36
|
-
item: Node<any>;
|
|
37
24
|
path: string[];
|
|
25
|
+
item: Node.Node;
|
|
38
26
|
currentItemId: string;
|
|
39
27
|
onBack?: () => void;
|
|
40
28
|
};
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Space or settings panel.
|
|
32
|
+
*/
|
|
33
|
+
export const L1Panel = ({ open, path, item, currentItemId, onBack }: L1PanelProps) => {
|
|
34
|
+
const { t } = useTranslation(meta.id);
|
|
35
|
+
const navTreeContext = useNavTreeContext();
|
|
36
|
+
const title = toLocalizedString(item.properties.label, t);
|
|
45
37
|
|
|
46
38
|
// TODO(wittjosiah): Support multiple alternate trees.
|
|
47
|
-
const
|
|
39
|
+
const { useItems } = navTreeContext;
|
|
40
|
+
const alternateTree = useItems(item, { disposition: 'alternate-tree' })[0];
|
|
48
41
|
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
49
|
-
const
|
|
50
|
-
const isAlternate = isAlternateTree?.(alternatePath, item) ?? false;
|
|
42
|
+
const isAlternate = useIsAlternateTree(alternatePath, item);
|
|
51
43
|
const useAlternateItems = useCallback(
|
|
52
|
-
(node?: Node, { disposition }: { disposition?: string } = {}) => {
|
|
44
|
+
(node?: Node.Node, { disposition }: { disposition?: string } = {}) => {
|
|
53
45
|
// TODO(wittjosiah): Sorting is expensive, limit to necessary items for now.
|
|
54
|
-
return
|
|
46
|
+
return useItems(node, { disposition, sort: node?.id === alternateTree.id });
|
|
55
47
|
},
|
|
56
|
-
[
|
|
48
|
+
[alternateTree, useItems],
|
|
57
49
|
);
|
|
58
50
|
|
|
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
51
|
return (
|
|
71
52
|
<Tabs.Tabpanel
|
|
72
53
|
key={item.id}
|
|
@@ -79,96 +60,171 @@ const L1Panel = ({ open, item, path, currentItemId, onBack }: L1PanelProps) => {
|
|
|
79
60
|
]}
|
|
80
61
|
tabIndex={-1}
|
|
81
62
|
aria-label={title}
|
|
82
|
-
{...(!open && { inert:
|
|
63
|
+
{...(!open && { inert: true })}
|
|
83
64
|
>
|
|
84
65
|
{item.id === currentItemId && (
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
116
|
-
renderColumns={NavTreeItemColumns}
|
|
117
|
-
/>
|
|
118
|
-
) : (
|
|
119
|
-
<Tree
|
|
120
|
-
{...navTreeContext}
|
|
121
|
-
id={item.id}
|
|
122
|
-
root={item}
|
|
123
|
-
path={path}
|
|
124
|
-
levelOffset={5}
|
|
125
|
-
draggable
|
|
126
|
-
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
127
|
-
renderColumns={NavTreeItemColumns}
|
|
128
|
-
/>
|
|
129
|
-
)}
|
|
130
|
-
</div>
|
|
131
|
-
</>
|
|
66
|
+
<DensityProvider density='fine'>
|
|
67
|
+
<L1PanelHeader path={path} item={item} currentItemId={currentItemId} onBack={onBack} />
|
|
68
|
+
<ScrollArea.Root thin orientation='vertical'>
|
|
69
|
+
<ScrollArea.Viewport>
|
|
70
|
+
{isAlternate ? (
|
|
71
|
+
<Tree
|
|
72
|
+
{...navTreeContext}
|
|
73
|
+
id={alternateTree.id}
|
|
74
|
+
root={alternateTree}
|
|
75
|
+
path={alternatePath}
|
|
76
|
+
levelOffset={5}
|
|
77
|
+
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
78
|
+
renderColumns={NavTreeItemColumns}
|
|
79
|
+
useItems={useAlternateItems}
|
|
80
|
+
/>
|
|
81
|
+
) : (
|
|
82
|
+
<Tree
|
|
83
|
+
{...navTreeContext}
|
|
84
|
+
id={item.id}
|
|
85
|
+
root={item}
|
|
86
|
+
path={path}
|
|
87
|
+
levelOffset={5}
|
|
88
|
+
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
89
|
+
renderColumns={NavTreeItemColumns}
|
|
90
|
+
draggable
|
|
91
|
+
/>
|
|
92
|
+
)}
|
|
93
|
+
</ScrollArea.Viewport>
|
|
94
|
+
</ScrollArea.Root>
|
|
95
|
+
</DensityProvider>
|
|
132
96
|
)}
|
|
133
97
|
</Tabs.Tabpanel>
|
|
134
98
|
);
|
|
135
99
|
};
|
|
136
100
|
|
|
137
|
-
|
|
138
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Header row.
|
|
103
|
+
*/
|
|
104
|
+
const L1PanelHeader = ({ item, path, onBack }: L1PanelProps) => {
|
|
105
|
+
const { t } = useTranslation(meta.id);
|
|
106
|
+
const { renderItemEnd: ItemEnd } = useNavTreeContext();
|
|
107
|
+
const title = toLocalizedString(item.properties.label, t);
|
|
108
|
+
|
|
109
|
+
const { primaryAction, groupedActions, menuActions, onAction } = useL1MenuActions({ item, path });
|
|
139
110
|
useLoadDescendents(item);
|
|
140
|
-
|
|
141
|
-
const groupPath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
111
|
+
|
|
142
112
|
return (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
113
|
+
<div className='flex is-full items-center border-be border-subduedSeparator app-drag density-coarse'>
|
|
114
|
+
<div className='is-6' />
|
|
115
|
+
<h2 className='flex-1 truncate min-is-0'>{title}</h2>
|
|
116
|
+
{/* TODO(wittjosiah): Reconcile with NavTreeItemColumns. */}
|
|
117
|
+
<div role='none' className='contents app-no-drag'>
|
|
118
|
+
{primaryAction?.properties?.disposition === 'list-item-primary' && !primaryAction?.properties?.disabled && (
|
|
119
|
+
<NavTreeItemAction
|
|
120
|
+
testId={primaryAction.properties?.testId}
|
|
121
|
+
label={toLocalizedString(primaryAction.properties?.label, t)}
|
|
122
|
+
icon={primaryAction.properties?.icon ?? 'ph--placeholder--regular'}
|
|
123
|
+
parent={item}
|
|
124
|
+
monolithic={Node.isAction(primaryAction)}
|
|
125
|
+
menuActions={Node.isAction(primaryAction) ? [primaryAction] : groupedActions[primaryAction?.id ?? '']}
|
|
126
|
+
menuType={primaryAction.properties?.menuType}
|
|
127
|
+
caller={NAV_TREE_ITEM}
|
|
128
|
+
/>
|
|
129
|
+
)}
|
|
130
|
+
{menuActions.length === 1 && (
|
|
131
|
+
<IconButton
|
|
132
|
+
size={5}
|
|
133
|
+
density='coarse'
|
|
134
|
+
classNames={['shrink-0 pli-2 pointer-fine:pli-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
135
|
+
variant='ghost'
|
|
136
|
+
icon={menuActions[0].properties?.icon ?? 'ph--placeholder--regular'}
|
|
137
|
+
iconOnly
|
|
138
|
+
label={toLocalizedString(menuActions[0].properties?.label, t)}
|
|
139
|
+
data-testid={menuActions[0].properties?.testId}
|
|
140
|
+
onClick={() => onAction(menuActions[0] as Node.Action)}
|
|
141
|
+
/>
|
|
142
|
+
)}
|
|
143
|
+
{menuActions.length > 1 && (
|
|
144
|
+
<MenuProvider onAction={onAction}>
|
|
145
|
+
<DropdownMenu.Root group={item} items={menuActions as MenuItem[]} caller={NAV_TREE_ITEM}>
|
|
146
|
+
<DropdownMenu.Trigger asChild>
|
|
147
|
+
<IconButton
|
|
148
|
+
size={5}
|
|
149
|
+
density='coarse'
|
|
150
|
+
classNames={['shrink-0 pli-2 pointer-fine:pli-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
151
|
+
variant='ghost'
|
|
152
|
+
icon='ph--dots-three-vertical--regular'
|
|
153
|
+
iconOnly
|
|
154
|
+
label={t('tree item actions label')}
|
|
155
|
+
data-testid='navtree.treeItem.actionsLevel0'
|
|
156
|
+
/>
|
|
157
|
+
</DropdownMenu.Trigger>
|
|
158
|
+
</DropdownMenu.Root>
|
|
159
|
+
</MenuProvider>
|
|
160
|
+
)}
|
|
161
|
+
{ItemEnd && <ItemEnd node={item} open />}
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
150
164
|
);
|
|
151
165
|
};
|
|
152
166
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
167
|
+
/**
|
|
168
|
+
* Builds the menu actions for the L1 panel header, combining graph actions with a synthetic settings/back action.
|
|
169
|
+
*/
|
|
170
|
+
const useL1MenuActions = ({ item, path }: Pick<L1PanelProps, 'item' | 'path'>) => {
|
|
171
|
+
const { t } = useTranslation(meta.id);
|
|
172
|
+
const { setAlternateTree, useActions, ...navTreeContext } = useNavTreeContext();
|
|
173
|
+
const runAction = useActionRunner();
|
|
157
174
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return <L1Panel key={item.id} item={item} {...props} onBack={onBack} />;
|
|
168
|
-
default:
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
})}
|
|
172
|
-
</>
|
|
175
|
+
// TODO(wittjosiah): Support multiple alternate trees.
|
|
176
|
+
const alternateTree = navTreeContext.useItems(item, { disposition: 'alternate-tree' })[0];
|
|
177
|
+
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
178
|
+
const isAlternate = useIsAlternateTree(alternatePath, item);
|
|
179
|
+
|
|
180
|
+
// Graph actions.
|
|
181
|
+
const { actions: _actions, groupedActions } = useActions(item);
|
|
182
|
+
const [primaryAction, ...secondaryActions] = _actions.toSorted((a, _b) =>
|
|
183
|
+
a.properties?.disposition === 'list-item-primary' ? -1 : 1,
|
|
173
184
|
);
|
|
185
|
+
|
|
186
|
+
const graphMenuActions = (
|
|
187
|
+
primaryAction?.properties?.disposition === 'list-item-primary' ? secondaryActions : _actions
|
|
188
|
+
)
|
|
189
|
+
.flatMap((action) => (Node.isAction(action) ? [action] : []))
|
|
190
|
+
.filter((a) => ['list-item', 'list-item-primary'].includes(a.properties?.disposition));
|
|
191
|
+
|
|
192
|
+
// Synthetic settings/back action.
|
|
193
|
+
const settingsActionId = `${item.id}~settings`;
|
|
194
|
+
const settingsAction = useMemo((): Node.Action | undefined => {
|
|
195
|
+
if (!alternateTree) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
id: settingsActionId,
|
|
200
|
+
type: Node.ActionType,
|
|
201
|
+
data: () => Effect.void,
|
|
202
|
+
properties: {
|
|
203
|
+
label: isAlternate ? ['button back', { ns: meta.id }] : (alternateTree.properties.label ?? alternateTree.id),
|
|
204
|
+
icon: isAlternate
|
|
205
|
+
? 'ph--arrow-u-down-left--regular'
|
|
206
|
+
: (alternateTree.properties.icon ?? 'ph--placeholder--regular'),
|
|
207
|
+
disposition: 'list-item',
|
|
208
|
+
testId: isAlternate ? 'navtree.backToSpace' : 'navtree.spaceSettings',
|
|
209
|
+
},
|
|
210
|
+
} as Node.Action;
|
|
211
|
+
}, [alternateTree, isAlternate, settingsActionId, t]);
|
|
212
|
+
|
|
213
|
+
const menuActions = useMemo(
|
|
214
|
+
() => [...graphMenuActions, ...(settingsAction ? [settingsAction] : [])],
|
|
215
|
+
[graphMenuActions, settingsAction],
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const onAction = useCallback(
|
|
219
|
+
(action: Node.Action, params?: Node.InvokeProps) => {
|
|
220
|
+
if (action.id === settingsActionId) {
|
|
221
|
+
setAlternateTree?.(alternatePath, !isAlternate);
|
|
222
|
+
} else {
|
|
223
|
+
void runAction(action, params);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
[settingsActionId, setAlternateTree, alternatePath, isAlternate, runAction],
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
return { primaryAction, groupedActions, menuActions, onAction };
|
|
174
230
|
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { type Node } from '@dxos/app-graph';
|
|
8
|
+
|
|
9
|
+
import { l0ItemType } from '../../util';
|
|
10
|
+
|
|
11
|
+
import { L1Panel, type L1PanelProps } from './L1Panel';
|
|
12
|
+
|
|
13
|
+
export type L1TabsProps = Pick<L1PanelProps, 'open' | 'currentItemId' | 'onBack'> & {
|
|
14
|
+
path: string[];
|
|
15
|
+
topLevelItems: Node.Node[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Each workspace is an L1 tab.
|
|
20
|
+
*/
|
|
21
|
+
export const L1Tabs = ({ topLevelItems, onBack, ...props }: L1TabsProps) => {
|
|
22
|
+
return (
|
|
23
|
+
<>
|
|
24
|
+
{topLevelItems.map((item) => {
|
|
25
|
+
const type = l0ItemType(item);
|
|
26
|
+
if (type === 'tab') {
|
|
27
|
+
return <L1Panel key={item.id} item={item} {...props} onBack={onBack} />;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
})}
|
|
31
|
+
</>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -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',
|
|
13
|
+
|
|
14
|
+
decorators: [withTheme()],
|
|
15
15
|
component: UserAccountAvatar,
|
|
16
|
-
|
|
17
|
-
};
|
|
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 = {};
|
|
@@ -7,6 +7,8 @@ import React from 'react';
|
|
|
7
7
|
import { Avatar, type AvatarStatus, type Size } from '@dxos/react-ui';
|
|
8
8
|
import { hexToFallback } from '@dxos/util';
|
|
9
9
|
|
|
10
|
+
import { L0ItemActiveTabIndicator } from '../Sidebar';
|
|
11
|
+
|
|
10
12
|
export type UserAccountAvatarProps = {
|
|
11
13
|
size?: Size;
|
|
12
14
|
userId?: string;
|
|
@@ -19,17 +21,23 @@ export const UserAccountAvatar = ({ size, userId, hue, emoji, status }: UserAcco
|
|
|
19
21
|
const fallbackValue = hexToFallback(userId ?? '0');
|
|
20
22
|
|
|
21
23
|
return (
|
|
22
|
-
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
<>
|
|
25
|
+
<L0ItemActiveTabIndicator classNames='inset-block-6' />
|
|
26
|
+
<div
|
|
27
|
+
className='grid place-items-center dx-focus-ring-group-indicator rounded-full'
|
|
28
|
+
data-joyride='welcome/account'
|
|
29
|
+
>
|
|
30
|
+
<Avatar.Root>
|
|
31
|
+
<Avatar.Content
|
|
32
|
+
variant='circle'
|
|
33
|
+
size={size ?? 12}
|
|
34
|
+
status={status ?? 'active'}
|
|
35
|
+
hue={hue || fallbackValue.hue}
|
|
36
|
+
fallback={emoji || fallbackValue.emoji}
|
|
37
|
+
data-testid='treeView.userAccount'
|
|
38
|
+
/>
|
|
39
|
+
</Avatar.Root>
|
|
40
|
+
</div>
|
|
41
|
+
</>
|
|
34
42
|
);
|
|
35
43
|
};
|
package/src/components/index.ts
CHANGED
package/src/components/types.ts
CHANGED
|
@@ -4,33 +4,34 @@
|
|
|
4
4
|
|
|
5
5
|
import type { FC } from 'react';
|
|
6
6
|
|
|
7
|
-
import type
|
|
7
|
+
import { type Node } from '@dxos/app-graph';
|
|
8
8
|
import type { Density } from '@dxos/react-ui';
|
|
9
9
|
import type { TreeProps } from '@dxos/react-ui-list';
|
|
10
10
|
import type { MaybePromise } from '@dxos/util';
|
|
11
11
|
|
|
12
|
-
import type { L1PanelProps } from './Sidebar';
|
|
13
12
|
import type { FlattenedActions, NavTreeItemGraphNode } from '../types';
|
|
14
13
|
|
|
14
|
+
import type { L1PanelProps } from './Sidebar';
|
|
15
|
+
|
|
15
16
|
export type NavTreeContextValue = Pick<
|
|
16
17
|
TreeProps<NavTreeItemGraphNode, { disposition?: string; sort?: boolean }>,
|
|
17
|
-
'useItems' | 'getProps' | '
|
|
18
|
+
'useItems' | 'getProps' | 'useIsCurrent' | 'useIsOpen' | 'blockInstruction' | 'canDrop' | 'onOpenChange' | 'onSelect'
|
|
18
19
|
> &
|
|
19
20
|
Pick<L1PanelProps, 'onBack'> & {
|
|
20
21
|
tab: string;
|
|
21
22
|
topbar?: boolean;
|
|
22
23
|
popoverAnchorId?: string;
|
|
23
|
-
renderItemEnd?: FC<{ node: Node; open: boolean }>;
|
|
24
|
-
|
|
25
|
-
loadDescendents?: (node: Node) => MaybePromise<void>;
|
|
26
|
-
|
|
24
|
+
renderItemEnd?: FC<{ node: Node.Node; open: boolean }>;
|
|
25
|
+
useActions: (node: Node.Node) => FlattenedActions;
|
|
26
|
+
loadDescendents?: (node: Node.Node) => MaybePromise<void>;
|
|
27
|
+
useIsAlternateTree?: (path: string[], item: NavTreeItemGraphNode) => boolean;
|
|
27
28
|
setAlternateTree?: (path: string[], open: boolean) => void;
|
|
28
29
|
onTabChange?: (node: NavTreeItemGraphNode) => void;
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
export type NavTreeItemColumnsProps = {
|
|
32
33
|
path: string[];
|
|
33
|
-
item: Node;
|
|
34
|
+
item: Node.Node;
|
|
34
35
|
open: boolean;
|
|
35
36
|
density?: Density;
|
|
36
37
|
};
|