@dxos/plugin-navtree 0.8.2-main.f11618f → 0.8.2-main.fbd8ed0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/{app-graph-builder-26D3MUCA.mjs → app-graph-builder-P7AY3K72.mjs} +7 -6
- package/dist/lib/browser/app-graph-builder-P7AY3K72.mjs.map +7 -0
- package/dist/lib/browser/{chunk-FHOAKMRS.mjs → chunk-UM2C5XK3.mjs} +352 -360
- package/dist/lib/browser/chunk-UM2C5XK3.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +4 -10
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-OBGGMBVJ.mjs → intent-resolver-PW7B76HO.mjs} +6 -6
- package/dist/lib/browser/intent-resolver-PW7B76HO.mjs.map +7 -0
- package/dist/lib/browser/keyboard-DDFATRUG.mjs +51 -0
- package/dist/lib/browser/keyboard-DDFATRUG.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-DWMOF2TM.mjs → react-surface-M3CAS7ZP.mjs} +2 -2
- package/dist/lib/browser/{state-EW62QYEN.mjs → state-3UBYOTQT.mjs} +2 -2
- package/dist/lib/browser/state-3UBYOTQT.mjs.map +7 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +2 -179
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +4 -180
- 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 +2 -2
- package/dist/types/src/capabilities/keyboard.d.ts.map +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 -0
- package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +1 -0
- package/dist/types/src/components/CommandsDialog/index.d.ts +3 -0
- package/dist/types/src/components/CommandsDialog/index.d.ts.map +1 -0
- package/dist/types/src/components/NavTree/NavTree.d.ts +8 -0
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -0
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +8 -0
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -0
- package/dist/types/src/components/NavTree/index.d.ts +2 -0
- package/dist/types/src/components/NavTree/index.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeContext.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +1 -1
- package/dist/types/src/components/{NavTreeItemAction.d.ts → NavTreeItem/NavTreeItemAction.d.ts} +2 -3
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +8 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts.map +1 -0
- package/dist/types/src/components/{NavTreeItemColumns.d.ts → NavTreeItem/NavTreeItemColumns.d.ts} +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeItem/index.d.ts +3 -0
- package/dist/types/src/components/NavTreeItem/index.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/L0Menu.d.ts +13 -0
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +15 -0
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -0
- package/dist/types/src/components/Sidebar/index.d.ts +3 -0
- package/dist/types/src/components/Sidebar/index.d.ts.map +1 -0
- package/dist/types/src/components/{UserAccountAvatar.d.ts → UserAccountAvatar/UserAccountAvatar.d.ts} +1 -1
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.d.ts.map +1 -0
- package/dist/types/src/components/{UserAccountAvatar.stories.d.ts → UserAccountAvatar/UserAccountAvatar.stories.d.ts} +1 -2
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -0
- package/dist/types/src/components/UserAccountAvatar/index.d.ts +2 -0
- package/dist/types/src/components/UserAccountAvatar/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/types.d.ts +17 -15
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.d.ts.map +1 -1
- package/dist/types/src/hooks.d.ts.map +1 -1
- package/dist/types/src/testing/app-graph-builder.d.ts +3 -0
- package/dist/types/src/testing/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/testing/generator.d.ts +5 -4
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/update-state.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +1 -1
- package/dist/types/src/util.d.ts +7 -10
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +40 -31
- package/src/NavTreePlugin.tsx +2 -2
- package/src/capabilities/app-graph-builder.ts +38 -28
- package/src/capabilities/intent-resolver.ts +8 -7
- package/src/capabilities/keyboard.ts +37 -32
- package/src/capabilities/state.ts +3 -3
- package/src/components/{CommandsDialog.tsx → CommandsDialog/CommandsDialog.tsx} +8 -7
- package/src/components/{CommandsTrigger.tsx → CommandsDialog/CommandsTrigger.tsx} +1 -1
- package/src/components/CommandsDialog/index.ts +6 -0
- package/src/components/NavTree/NavTree.stories.tsx +159 -0
- package/src/components/NavTree/NavTree.tsx +62 -0
- package/src/components/NavTree/index.ts +5 -0
- package/src/components/NavTreeContainer.tsx +85 -79
- package/src/components/NavTreeContext.tsx +1 -1
- package/src/components/{NavTreeItemAction.stories.tsx → NavTreeItem/NavTreeItemAction.stories.tsx} +12 -6
- package/src/components/{NavTreeItemAction.tsx → NavTreeItem/NavTreeItemAction.tsx} +13 -14
- package/src/components/{NavTreeItemColumns.tsx → NavTreeItem/NavTreeItemColumns.tsx} +5 -5
- package/src/components/NavTreeItem/index.ts +6 -0
- package/src/components/{L0Menu.tsx → Sidebar/L0Menu.tsx} +188 -131
- package/src/components/{L1Panels.tsx → Sidebar/L1Panel.tsx} +40 -65
- package/src/components/Sidebar/index.ts +6 -0
- package/src/components/{UserAccountAvatar.stories.tsx → UserAccountAvatar/UserAccountAvatar.stories.tsx} +5 -5
- package/src/components/{UserAccountAvatar.tsx → UserAccountAvatar/UserAccountAvatar.tsx} +6 -6
- package/src/components/UserAccountAvatar/index.ts +5 -0
- package/src/components/index.ts +0 -1
- package/src/components/types.ts +17 -16
- package/src/hooks.ts +12 -11
- package/src/testing/app-graph-builder.ts +224 -0
- package/src/testing/generator.ts +12 -9
- package/src/testing/index.ts +1 -0
- package/src/translations.ts +1 -1
- package/src/util.ts +10 -32
- package/dist/lib/browser/app-graph-builder-26D3MUCA.mjs.map +0 -7
- package/dist/lib/browser/chunk-FHOAKMRS.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-OBGGMBVJ.mjs.map +0 -7
- package/dist/lib/browser/keyboard-IQXHKUWM.mjs +0 -46
- package/dist/lib/browser/keyboard-IQXHKUWM.mjs.map +0 -7
- package/dist/lib/browser/state-EW62QYEN.mjs.map +0 -7
- package/dist/types/src/components/CommandsDialog.d.ts.map +0 -1
- package/dist/types/src/components/CommandsTrigger.d.ts.map +0 -1
- package/dist/types/src/components/L0Menu.d.ts +0 -10
- package/dist/types/src/components/L0Menu.d.ts.map +0 -1
- package/dist/types/src/components/L1Panels.d.ts +0 -14
- package/dist/types/src/components/L1Panels.d.ts.map +0 -1
- package/dist/types/src/components/NavTree.d.ts +0 -5
- package/dist/types/src/components/NavTree.d.ts.map +0 -1
- package/dist/types/src/components/NavTree.stories.d.ts +0 -7
- package/dist/types/src/components/NavTree.stories.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeItemAction.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeItemAction.stories.d.ts +0 -41
- package/dist/types/src/components/NavTreeItemAction.stories.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeItemColumns.d.ts.map +0 -1
- package/dist/types/src/components/UserAccountAvatar.d.ts.map +0 -1
- package/dist/types/src/components/UserAccountAvatar.stories.d.ts.map +0 -1
- package/dist/types/src/stories/Graph.stories.d.ts +0 -7
- package/dist/types/src/stories/Graph.stories.d.ts.map +0 -1
- package/dist/types/src/stories/StorybookNavTree.d.ts +0 -4
- package/dist/types/src/stories/StorybookNavTree.d.ts.map +0 -1
- package/src/components/NavTree.stories.tsx +0 -107
- package/src/components/NavTree.tsx +0 -51
- package/src/stories/Graph.stories.tsx +0 -130
- package/src/stories/StorybookNavTree.tsx +0 -63
- /package/dist/lib/browser/{react-surface-DWMOF2TM.mjs.map → react-surface-M3CAS7ZP.mjs.map} +0 -0
- /package/dist/types/src/components/{CommandsDialog.d.ts → CommandsDialog/CommandsDialog.d.ts} +0 -0
- /package/dist/types/src/components/{CommandsTrigger.d.ts → CommandsDialog/CommandsTrigger.d.ts} +0 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type TreeProps } from '@dxos/react-ui-list';
|
|
8
|
+
import { Tabs } from '@dxos/react-ui-tabs';
|
|
9
|
+
|
|
10
|
+
import { useLoadDescendents } from '../../hooks';
|
|
11
|
+
import { type NavTreeItemGraphNode } from '../../types';
|
|
12
|
+
import { useNavTreeContext } from '../NavTreeContext';
|
|
13
|
+
import { L0Menu, L1Panels, type L1PanelsProps } from '../Sidebar';
|
|
14
|
+
|
|
15
|
+
export const NAV_TREE_ITEM = 'NavTreeItem';
|
|
16
|
+
|
|
17
|
+
export type NavTreeProps = Pick<TreeProps<NavTreeItemGraphNode>, 'id' | 'root'> & Pick<L1PanelsProps, 'open'>;
|
|
18
|
+
|
|
19
|
+
export const NavTree = ({ id, root, ...props }: NavTreeProps) => {
|
|
20
|
+
const { tab, useItems, onBack } = useNavTreeContext();
|
|
21
|
+
const topLevelActions = useItems(root, { disposition: 'menu', sort: true });
|
|
22
|
+
const topLevelCollections = useItems(root, { disposition: 'collection' });
|
|
23
|
+
const topLevelWorkspaces = useItems(root, { disposition: 'workspace' });
|
|
24
|
+
const topLevelNavigation = useItems(root, { disposition: 'navigation' });
|
|
25
|
+
const l0Items = useMemo(
|
|
26
|
+
() => [
|
|
27
|
+
// prettier-ignore
|
|
28
|
+
...topLevelCollections,
|
|
29
|
+
...topLevelWorkspaces,
|
|
30
|
+
...topLevelNavigation,
|
|
31
|
+
],
|
|
32
|
+
[topLevelCollections, topLevelWorkspaces, topLevelNavigation],
|
|
33
|
+
);
|
|
34
|
+
const pinnedItems = useItems(root, { disposition: 'pin-end', sort: true });
|
|
35
|
+
const userAccountItem = useItems(root, { disposition: 'user-account' })[0];
|
|
36
|
+
const topLevelItems = useMemo(
|
|
37
|
+
() => [
|
|
38
|
+
// prettier-ignore
|
|
39
|
+
...l0Items,
|
|
40
|
+
...pinnedItems,
|
|
41
|
+
...(userAccountItem ? [userAccountItem] : []),
|
|
42
|
+
],
|
|
43
|
+
[l0Items, pinnedItems, userAccountItem],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
useLoadDescendents(root);
|
|
47
|
+
const path = useMemo(() => [id], [id]);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Tabs.Root value={tab} orientation='vertical' verticalVariant='stateless' classNames='relative'>
|
|
51
|
+
<L0Menu
|
|
52
|
+
menuActions={topLevelActions}
|
|
53
|
+
topLevelItems={l0Items}
|
|
54
|
+
pinnedItems={pinnedItems}
|
|
55
|
+
userAccountItem={userAccountItem}
|
|
56
|
+
path={path}
|
|
57
|
+
parent={root}
|
|
58
|
+
/>
|
|
59
|
+
<L1Panels topLevelItems={topLevelItems} path={path} currentItemId={tab} onBack={onBack} {...props} />
|
|
60
|
+
</Tabs.Root>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
@@ -16,28 +16,22 @@ import {
|
|
|
16
16
|
useIntentDispatcher,
|
|
17
17
|
useLayout,
|
|
18
18
|
} from '@dxos/app-framework';
|
|
19
|
-
import { isAction, isActionLike, type Node } from '@dxos/app-graph';
|
|
19
|
+
import { isAction, isActionLike, type ReadableGraph, ROOT_ID, type Node } from '@dxos/app-graph';
|
|
20
20
|
import { PLANK_COMPANION_TYPE } from '@dxos/plugin-deck/types';
|
|
21
|
+
import { useConnections } from '@dxos/plugin-graph';
|
|
21
22
|
import { isEchoObject, isSpace } from '@dxos/react-client/echo';
|
|
22
|
-
import { useMediaQuery } from '@dxos/react-ui';
|
|
23
|
+
import { useMediaQuery, useSidebars } from '@dxos/react-ui';
|
|
23
24
|
import { isTreeData, type TreeData, type PropsFromTreeItem } from '@dxos/react-ui-list';
|
|
24
25
|
import { mx } from '@dxos/react-ui-theme';
|
|
25
|
-
import { arrayMove } from '@dxos/util';
|
|
26
|
+
import { arrayMove, byPosition } from '@dxos/util';
|
|
26
27
|
|
|
27
28
|
import { NAV_TREE_ITEM, NavTree } from './NavTree';
|
|
28
29
|
import { NavTreeContext } from './NavTreeContext';
|
|
29
30
|
import { type NavTreeContextValue } from './types';
|
|
30
31
|
import { NavTreeCapabilities } from '../capabilities';
|
|
32
|
+
import { NAVTREE_PLUGIN } from '../meta';
|
|
31
33
|
import { type NavTreeItemGraphNode } from '../types';
|
|
32
|
-
import {
|
|
33
|
-
expandActions,
|
|
34
|
-
expandChildren,
|
|
35
|
-
getActions as naturalGetActions,
|
|
36
|
-
getChildren,
|
|
37
|
-
getParent,
|
|
38
|
-
resolveMigrationOperation,
|
|
39
|
-
expandChildrenAndActions,
|
|
40
|
-
} from '../util';
|
|
34
|
+
import { getActions as naturalGetActions, getChildren, getParent, resolveMigrationOperation } from '../util';
|
|
41
35
|
|
|
42
36
|
// TODO(thure): Is NavTree truly authoritative in this regard?
|
|
43
37
|
export const NODE_TYPE = 'dxos/app-graph/node';
|
|
@@ -49,6 +43,29 @@ const renderItemEnd = ({ node, open }: { node: Node; open: boolean }) => (
|
|
|
49
43
|
const getChildrenFilter = (node: Node): node is Node =>
|
|
50
44
|
untracked(() => !isActionLike(node) && node.type !== PLANK_COMPANION_TYPE);
|
|
51
45
|
|
|
46
|
+
const filterItems = (node: Node, disposition?: string) => {
|
|
47
|
+
if (!disposition && (node.properties.disposition === 'hidden' || node.properties.disposition === 'alternate-tree')) {
|
|
48
|
+
return false;
|
|
49
|
+
} else if (!disposition) {
|
|
50
|
+
const action = isAction(node);
|
|
51
|
+
return !action || node.properties.disposition === 'item';
|
|
52
|
+
} else {
|
|
53
|
+
return node.properties.disposition === disposition;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const getItems = (graph: ReadableGraph, node?: Node, disposition?: string) => {
|
|
58
|
+
return graph.getConnections(node?.id ?? ROOT_ID, 'outbound').filter((node) => filterItems(node, disposition));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const useItems = (node?: Node, options?: { disposition?: string; sort?: boolean }) => {
|
|
62
|
+
const { graph } = useAppGraph();
|
|
63
|
+
const connections = useConnections(graph, node?.id ?? ROOT_ID).filter((node) =>
|
|
64
|
+
filterItems(node, options?.disposition),
|
|
65
|
+
);
|
|
66
|
+
return options?.sort ? connections.toSorted((a, b) => byPosition(a.properties, b.properties)) : connections;
|
|
67
|
+
};
|
|
68
|
+
|
|
52
69
|
export type NavTreeContainerProps = {
|
|
53
70
|
popoverAnchorId?: string;
|
|
54
71
|
topbar?: boolean;
|
|
@@ -58,37 +75,15 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
58
75
|
const [isLg] = useMediaQuery('lg', { ssr: false });
|
|
59
76
|
const { dispatchPromise: dispatch } = useIntentDispatcher();
|
|
60
77
|
const { graph } = useAppGraph();
|
|
61
|
-
const layout = useLayout();
|
|
62
78
|
const { isOpen, isCurrent, isAlternateTree, setItem } = useCapability(NavTreeCapabilities.State);
|
|
79
|
+
const layout = useLayout();
|
|
80
|
+
const { navigationSidebarState } = useSidebars(NAVTREE_PLUGIN);
|
|
63
81
|
|
|
64
82
|
const getActions = useCallback((node: Node) => naturalGetActions(graph, node), [graph]);
|
|
65
83
|
|
|
66
|
-
const getItems = useCallback(
|
|
67
|
-
(node?: Node, disposition?: string) => {
|
|
68
|
-
return graph.nodes(node ?? graph.root, {
|
|
69
|
-
filter: (node): node is Node => {
|
|
70
|
-
return untracked(() => {
|
|
71
|
-
if (
|
|
72
|
-
!disposition &&
|
|
73
|
-
(node.properties.disposition === 'hidden' || node.properties.disposition === 'alternate-tree')
|
|
74
|
-
) {
|
|
75
|
-
return false;
|
|
76
|
-
} else if (!disposition) {
|
|
77
|
-
const action = isAction(node);
|
|
78
|
-
return !action || node.properties.disposition === 'item';
|
|
79
|
-
} else {
|
|
80
|
-
return node.properties.disposition === disposition;
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
},
|
|
86
|
-
[graph],
|
|
87
|
-
);
|
|
88
|
-
|
|
89
84
|
const getProps = useCallback(
|
|
90
85
|
(node: Node, path: string[]): PropsFromTreeItem => {
|
|
91
|
-
const children = getChildren(graph, node,
|
|
86
|
+
const children = getChildren(graph, node, path).filter(getChildrenFilter);
|
|
92
87
|
const parentOf =
|
|
93
88
|
children.length > 0 ? children.map(({ id }) => id) : node.properties.role === 'branch' ? [] : undefined;
|
|
94
89
|
return {
|
|
@@ -105,51 +100,63 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
105
100
|
[graph],
|
|
106
101
|
);
|
|
107
102
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
},
|
|
120
|
-
[graph],
|
|
121
|
-
);
|
|
103
|
+
// TODO(wittjosiah): Graph is currently expanded eagerly. See graph plugin.
|
|
104
|
+
// const loadDescendents = useCallback(
|
|
105
|
+
// (node: Node) => {
|
|
106
|
+
// graph.expand(node.id, 'outbound');
|
|
107
|
+
// // Load one level deeper, which resolves some juddering observed on open/close.
|
|
108
|
+
// graph.getConnections(node.id, 'outbound').forEach((child) => {
|
|
109
|
+
// graph.expand(child.id, 'outbound');
|
|
110
|
+
// });
|
|
111
|
+
// },
|
|
112
|
+
// [graph],
|
|
113
|
+
// );
|
|
122
114
|
|
|
123
|
-
const
|
|
115
|
+
const handleOpenChange = useCallback(
|
|
124
116
|
({ item: { id }, path, open }: { item: Node; path: string[]; open: boolean }) => {
|
|
125
117
|
// TODO(thure): This might become a localstorage leak; openItemIds that no longer exist should be removed from this map.
|
|
126
118
|
setItem(path, 'open', open);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const node = graph.findNode(id);
|
|
130
|
-
return node && expandChildrenAndActions(graph, node as NavTreeItemGraphNode);
|
|
131
|
-
}
|
|
119
|
+
// TODO(wittjosiah): Graph is currently expanded eagerly. See graph plugin.
|
|
120
|
+
// graph.expand(id, 'outbound');
|
|
132
121
|
},
|
|
133
122
|
[graph],
|
|
134
123
|
);
|
|
135
124
|
|
|
136
|
-
const
|
|
125
|
+
const handleTabChange = useCallback(
|
|
137
126
|
async (node: NavTreeItemGraphNode) => {
|
|
127
|
+
await dispatch(
|
|
128
|
+
createIntent(LayoutAction.UpdateSidebar, {
|
|
129
|
+
part: 'sidebar',
|
|
130
|
+
options: {
|
|
131
|
+
state:
|
|
132
|
+
node.id === tab
|
|
133
|
+
? navigationSidebarState === 'expanded'
|
|
134
|
+
? isLg
|
|
135
|
+
? 'collapsed'
|
|
136
|
+
: 'closed'
|
|
137
|
+
: 'expanded'
|
|
138
|
+
: 'expanded',
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
);
|
|
142
|
+
|
|
138
143
|
await dispatch(createIntent(LayoutAction.SwitchWorkspace, { part: 'workspace', subject: node.id }));
|
|
144
|
+
|
|
139
145
|
// Open the first item if the workspace is empty.
|
|
140
146
|
if (layout.active.length === 0) {
|
|
141
|
-
const [item] = getItems(node).filter((node) => !isActionLike(node));
|
|
147
|
+
const [item] = getItems(graph, node).filter((node) => !isActionLike(node));
|
|
142
148
|
if (item && item.data) {
|
|
143
149
|
await dispatch(createIntent(LayoutAction.Open, { part: 'main', subject: [item.id] }));
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
},
|
|
147
|
-
[dispatch, layout],
|
|
153
|
+
[dispatch, layout.active, tab, navigationSidebarState, isLg],
|
|
148
154
|
);
|
|
149
155
|
|
|
150
156
|
const canDrop = useCallback((source: TreeData, target: TreeData) => {
|
|
151
157
|
const sourceNode = source.item as Node;
|
|
152
158
|
const targetNode = target.item as Node;
|
|
159
|
+
// TODO(wittjosiah): This shouldn't depend directly on client, there should be a graph-level abstraction.
|
|
153
160
|
if (isSpace(targetNode.data)) {
|
|
154
161
|
// TODO(wittjosiah): Find a way to only allow space as source for rearranging.
|
|
155
162
|
return isEchoObject(sourceNode.data) || isSpace(sourceNode.data);
|
|
@@ -167,8 +174,8 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
167
174
|
}
|
|
168
175
|
|
|
169
176
|
if (isAction(node)) {
|
|
170
|
-
const [parent] = graph.
|
|
171
|
-
void (parent && node.data({
|
|
177
|
+
const [parent] = graph.getConnections(node.id, 'inbound');
|
|
178
|
+
void (parent && node.data({ parent, caller: NAV_TREE_ITEM }));
|
|
172
179
|
return;
|
|
173
180
|
}
|
|
174
181
|
|
|
@@ -189,7 +196,7 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
189
196
|
void dispatch(createIntent(LayoutAction.ScrollIntoView, { part: 'current', subject: node.id }));
|
|
190
197
|
}
|
|
191
198
|
|
|
192
|
-
const defaultAction = graph.
|
|
199
|
+
const defaultAction = graph.getActions(node.id).find((action) => action.properties?.disposition === 'default');
|
|
193
200
|
if (isAction(defaultAction)) {
|
|
194
201
|
void (defaultAction.data as () => void)();
|
|
195
202
|
}
|
|
@@ -201,7 +208,7 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
201
208
|
[graph, dispatch, isCurrent, isLg],
|
|
202
209
|
);
|
|
203
210
|
|
|
204
|
-
const
|
|
211
|
+
const handleBack = useCallback(
|
|
205
212
|
() => dispatch(createIntent(LayoutAction.RevertWorkspace, { part: 'workspace', options: { revert: true } })),
|
|
206
213
|
[dispatch],
|
|
207
214
|
);
|
|
@@ -228,8 +235,8 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
228
235
|
: resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
|
|
229
236
|
const sourceParent = getParent(graph, sourceNode, sourcePath);
|
|
230
237
|
const targetParent = getParent(graph, targetNode, targetPath);
|
|
231
|
-
const sourceItems = getItems(sourceParent);
|
|
232
|
-
const targetItems = getItems(targetParent);
|
|
238
|
+
const sourceItems = getItems(graph, sourceParent);
|
|
239
|
+
const targetItems = getItems(graph, targetParent);
|
|
233
240
|
const sourceIndex = sourceItems.findIndex(({ id }) => id === sourceNode.id);
|
|
234
241
|
const targetIndex = targetItems.findIndex(({ id }) => id === targetNode.id);
|
|
235
242
|
const migrationIndex =
|
|
@@ -274,48 +281,47 @@ export const NavTreeContainer = memo(({ tab, popoverAnchorId, topbar }: NavTreeC
|
|
|
274
281
|
|
|
275
282
|
const navTreeContextValue = useMemo(
|
|
276
283
|
() => ({
|
|
284
|
+
useItems,
|
|
277
285
|
tab,
|
|
278
|
-
onTabChange,
|
|
279
|
-
onBack,
|
|
280
286
|
getActions,
|
|
281
|
-
loadDescendents,
|
|
287
|
+
// loadDescendents,
|
|
282
288
|
renderItemEnd,
|
|
283
289
|
popoverAnchorId,
|
|
284
290
|
topbar,
|
|
285
|
-
getItems,
|
|
286
291
|
getProps,
|
|
287
292
|
isCurrent,
|
|
288
293
|
isOpen,
|
|
289
|
-
onOpenChange,
|
|
290
294
|
canDrop,
|
|
291
|
-
onSelect: handleSelect,
|
|
292
295
|
isAlternateTree,
|
|
293
296
|
setAlternateTree,
|
|
297
|
+
onTabChange: handleTabChange,
|
|
298
|
+
onOpenChange: handleOpenChange,
|
|
299
|
+
onSelect: handleSelect,
|
|
300
|
+
onBack: handleBack,
|
|
294
301
|
}),
|
|
295
302
|
[
|
|
296
303
|
tab,
|
|
297
|
-
onTabChange,
|
|
298
|
-
onBack,
|
|
299
304
|
getActions,
|
|
300
|
-
loadDescendents,
|
|
305
|
+
// loadDescendents,
|
|
301
306
|
renderItemEnd,
|
|
302
307
|
popoverAnchorId,
|
|
303
308
|
topbar,
|
|
304
|
-
getItems,
|
|
305
309
|
getProps,
|
|
306
310
|
isCurrent,
|
|
307
311
|
isOpen,
|
|
308
|
-
onOpenChange,
|
|
309
312
|
canDrop,
|
|
310
|
-
handleSelect,
|
|
311
313
|
isAlternateTree,
|
|
312
314
|
setAlternateTree,
|
|
315
|
+
handleTabChange,
|
|
316
|
+
handleOpenChange,
|
|
317
|
+
handleSelect,
|
|
318
|
+
handleBack,
|
|
313
319
|
],
|
|
314
320
|
);
|
|
315
321
|
|
|
316
322
|
return (
|
|
317
323
|
<NavTreeContext.Provider value={navTreeContextValue}>
|
|
318
|
-
<NavTree root={graph.root}
|
|
324
|
+
<NavTree id={ROOT_ID} root={graph.root} open={layout.sidebarOpen} />
|
|
319
325
|
</NavTreeContext.Provider>
|
|
320
326
|
);
|
|
321
327
|
});
|
|
@@ -10,4 +10,4 @@ import { type NavTreeContextValue } from './types';
|
|
|
10
10
|
|
|
11
11
|
export const NavTreeContext = createContext<NavTreeContextValue | null>(null);
|
|
12
12
|
|
|
13
|
-
export const useNavTreeContext = () => useContext(NavTreeContext) ?? raise(new Error('NavTreeContext
|
|
13
|
+
export const useNavTreeContext = () => useContext(NavTreeContext) ?? raise(new Error('Missing NavTreeContext'));
|
package/src/components/{NavTreeItemAction.stories.tsx → NavTreeItem/NavTreeItemAction.stories.tsx}
RENAMED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
|
+
import { type Meta, type StoryObj } from '@storybook/react';
|
|
8
|
+
|
|
7
9
|
import { type NodeArg } from '@dxos/app-graph';
|
|
8
10
|
import { faker } from '@dxos/random';
|
|
9
11
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
@@ -37,19 +39,23 @@ const menuActions = faker.helpers.multiple(
|
|
|
37
39
|
{ count: 20 },
|
|
38
40
|
);
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
const meta: Meta<typeof NavTreeItemAction> = {
|
|
41
43
|
title: 'plugins/plugin-navtree/NavTreeItemAction',
|
|
42
44
|
component: NavTreeItemAction,
|
|
43
|
-
decorators: [withTheme, withLayout(
|
|
45
|
+
decorators: [withTheme, withLayout()],
|
|
44
46
|
args: {
|
|
45
47
|
icon: 'ph--list--regular',
|
|
46
48
|
parent,
|
|
47
49
|
menuActions,
|
|
48
50
|
label: 'Select action',
|
|
49
|
-
onAction: (action) => {
|
|
50
|
-
console.log(action);
|
|
51
|
-
},
|
|
52
51
|
} satisfies Partial<NavTreeItemActionMenuProps>,
|
|
52
|
+
parameters: {
|
|
53
|
+
layout: 'centered',
|
|
54
|
+
},
|
|
53
55
|
};
|
|
54
56
|
|
|
55
|
-
export
|
|
57
|
+
export default meta;
|
|
58
|
+
|
|
59
|
+
type Story = StoryObj<typeof meta>;
|
|
60
|
+
|
|
61
|
+
export const Default: Story = {};
|
|
@@ -9,8 +9,8 @@ import { useTranslation, toLocalizedString, IconButton, useDensityContext } from
|
|
|
9
9
|
import { DropdownMenu, MenuProvider, type MenuItem } from '@dxos/react-ui-menu';
|
|
10
10
|
import { hoverableControlItem, hoverableOpenControlItem, mx } from '@dxos/react-ui-theme';
|
|
11
11
|
|
|
12
|
-
import { NAVTREE_PLUGIN } from '
|
|
13
|
-
import { type ActionProperties } from '
|
|
12
|
+
import { NAVTREE_PLUGIN } from '../../meta';
|
|
13
|
+
import { type ActionProperties } from '../../types';
|
|
14
14
|
|
|
15
15
|
export type NavTreeItemActionMenuProps = ActionProperties & {
|
|
16
16
|
parent: Node;
|
|
@@ -18,7 +18,6 @@ export type NavTreeItemActionMenuProps = ActionProperties & {
|
|
|
18
18
|
monolithic?: boolean;
|
|
19
19
|
menuActions?: Action[];
|
|
20
20
|
suppressNextTooltip?: MutableRefObject<boolean>;
|
|
21
|
-
onAction?: (action: Action) => void;
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
const fallbackIcon = 'ph--placeholder--regular';
|
|
@@ -33,18 +32,24 @@ const coarseActionButtonProps = {
|
|
|
33
32
|
};
|
|
34
33
|
|
|
35
34
|
export const NavTreeItemActionDropdownMenu = ({
|
|
35
|
+
parent,
|
|
36
36
|
label,
|
|
37
37
|
icon,
|
|
38
38
|
testId,
|
|
39
39
|
menuActions,
|
|
40
|
-
|
|
40
|
+
caller,
|
|
41
41
|
}: NavTreeItemActionMenuProps) => {
|
|
42
42
|
const { t } = useTranslation(NAVTREE_PLUGIN);
|
|
43
43
|
const suppressNextTooltip = useRef<boolean>(false);
|
|
44
44
|
const density = useDensityContext();
|
|
45
45
|
return (
|
|
46
|
-
<MenuProvider
|
|
47
|
-
<DropdownMenu.Root
|
|
46
|
+
<MenuProvider>
|
|
47
|
+
<DropdownMenu.Root
|
|
48
|
+
group={parent}
|
|
49
|
+
items={menuActions as MenuItem[]}
|
|
50
|
+
caller={caller}
|
|
51
|
+
suppressNextTooltip={suppressNextTooltip}
|
|
52
|
+
>
|
|
48
53
|
<DropdownMenu.Trigger asChild>
|
|
49
54
|
<IconButton
|
|
50
55
|
{...(density === 'coarse' ? coarseActionButtonProps : fineActionButtonProps)}
|
|
@@ -88,7 +93,7 @@ export const NavTreeItemMonolithicAction = ({
|
|
|
88
93
|
return;
|
|
89
94
|
}
|
|
90
95
|
event.stopPropagation();
|
|
91
|
-
void invoke?.(caller ? {
|
|
96
|
+
void invoke?.(caller ? { parent, caller } : { parent });
|
|
92
97
|
}}
|
|
93
98
|
data-testid={testId}
|
|
94
99
|
/>
|
|
@@ -104,12 +109,6 @@ export const NavTreeItemAction = ({ monolithic, menuActions, parent: node, ...pr
|
|
|
104
109
|
return monolithic && menuActions?.length === 1 ? (
|
|
105
110
|
<NavTreeItemMonolithicAction baseLabel={baseLabel} parent={node} {...menuActions[0]} />
|
|
106
111
|
) : (
|
|
107
|
-
<NavTreeItemActionDropdownMenu
|
|
108
|
-
{...props}
|
|
109
|
-
label={baseLabel}
|
|
110
|
-
parent={node}
|
|
111
|
-
menuActions={menuActions}
|
|
112
|
-
onAction={(action) => action.data?.(props.caller ? { node, caller: props.caller } : { node })}
|
|
113
|
-
/>
|
|
112
|
+
<NavTreeItemActionDropdownMenu {...props} label={baseLabel} parent={node} menuActions={menuActions} />
|
|
114
113
|
);
|
|
115
114
|
};
|
|
@@ -7,12 +7,12 @@ import React, { Fragment, memo } from 'react';
|
|
|
7
7
|
import { isAction } from '@dxos/app-graph';
|
|
8
8
|
import { DensityProvider, Popover, toLocalizedString, Treegrid, useTranslation } from '@dxos/react-ui';
|
|
9
9
|
|
|
10
|
-
import { NAV_TREE_ITEM } from './NavTree';
|
|
11
|
-
import { useNavTreeContext } from './NavTreeContext';
|
|
12
10
|
import { NavTreeItemAction } from './NavTreeItemAction';
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
11
|
+
import { useLoadDescendents } from '../../hooks';
|
|
12
|
+
import { NAVTREE_PLUGIN } from '../../meta';
|
|
13
|
+
import { NAV_TREE_ITEM } from '../NavTree';
|
|
14
|
+
import { useNavTreeContext } from '../NavTreeContext';
|
|
15
|
+
import type { NavTreeItemColumnsProps } from '../types';
|
|
16
16
|
|
|
17
17
|
export const NavTreeItemColumns = memo(({ path, item, open, density = 'fine' }: NavTreeItemColumnsProps) => {
|
|
18
18
|
const { t } = useTranslation(NAVTREE_PLUGIN);
|