@dxos/plugin-navtree 0.8.4-main.69d29f4 → 0.8.4-main.6fa680abb7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/CommandsDialogContent-2DKIOLJL.mjs +113 -0
- package/dist/lib/browser/CommandsDialogContent-2DKIOLJL.mjs.map +7 -0
- package/dist/lib/browser/CommandsTrigger-ABODVVMP.mjs +33 -0
- package/dist/lib/browser/CommandsTrigger-ABODVVMP.mjs.map +7 -0
- package/dist/lib/browser/NavTreeContainer-TLSYS4KK.mjs +12 -0
- package/dist/lib/browser/NavTreeContainer-TLSYS4KK.mjs.map +7 -0
- package/dist/lib/browser/NavTreeDocumentTitle-L6NLLWLD.mjs +26 -0
- package/dist/lib/browser/NavTreeDocumentTitle-L6NLLWLD.mjs.map +7 -0
- package/dist/lib/browser/{app-graph-builder-RSMA6I22.mjs → app-graph-builder-Z43OTNI2.mjs} +6 -5
- package/dist/lib/browser/app-graph-builder-Z43OTNI2.mjs.map +7 -0
- package/dist/lib/browser/{chunk-YKTYPINZ.mjs → chunk-A4VDCIJC.mjs} +3 -3
- package/dist/lib/browser/{chunk-YKTYPINZ.mjs.map → chunk-A4VDCIJC.mjs.map} +1 -1
- package/dist/lib/browser/chunk-AYF2TX65.mjs +14 -0
- package/dist/lib/browser/chunk-AYF2TX65.mjs.map +7 -0
- package/dist/lib/browser/chunk-JT37R5HS.mjs +1468 -0
- package/dist/lib/browser/chunk-JT37R5HS.mjs.map +7 -0
- package/dist/lib/browser/{chunk-AGQDZBPL.mjs → chunk-KF26WA4O.mjs} +5 -5
- package/dist/lib/browser/{chunk-AGQDZBPL.mjs.map → chunk-KF26WA4O.mjs.map} +3 -3
- package/dist/lib/browser/index.mjs +35 -31
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{keyboard-32EH3N4K.mjs → keyboard-HYGFQO7T.mjs} +11 -6
- package/dist/lib/browser/keyboard-HYGFQO7T.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/operation-resolver-VDWVUII5.mjs +49 -0
- package/dist/lib/browser/operation-resolver-VDWVUII5.mjs.map +7 -0
- package/dist/lib/browser/{react-surface-F6CVMS3Y.mjs → react-surface-D2RLMV4Z.mjs} +15 -14
- package/dist/lib/browser/react-surface-D2RLMV4Z.mjs.map +7 -0
- package/dist/lib/browser/{state-EVYQOUI3.mjs → state-CWMNNF7K.mjs} +34 -23
- package/dist/lib/browser/state-CWMNNF7K.mjs.map +7 -0
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts +1 -1
- package/dist/types/src/capabilities/keyboard/keyboard.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-resolver/index.d.ts +1 -1
- package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +2 -2
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface/index.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts +2 -2
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/state/state.d.ts +1 -1
- package/dist/types/src/capabilities/state/state.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.d.ts +10 -32
- package/dist/types/src/components/NavTree/NavTree.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +2 -5
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/{NavTreeContext.d.ts → NavTreeContext/NavTreeContext.d.ts} +1 -1
- package/dist/types/src/components/NavTreeContext/NavTreeContext.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeContext/index.d.ts +2 -0
- package/dist/types/src/components/NavTreeContext/index.d.ts.map +1 -0
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +4 -2
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.stories.d.ts +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemColumns.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts +4 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts +3 -6
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts +3 -2
- package/dist/types/src/components/Sidebar/L1Tabs.d.ts.map +1 -1
- package/dist/types/src/components/UserAccountAvatar/UserAccountAvatar.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +0 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/types.d.ts +5 -13
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/{components/CommandsDialog/CommandsDialog.d.ts → containers/CommandsDialogContent/CommandsDialogContent.d.ts} +1 -1
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -0
- package/dist/types/src/containers/CommandsDialogContent/index.d.ts +3 -0
- package/dist/types/src/containers/CommandsDialogContent/index.d.ts.map +1 -0
- package/dist/types/src/containers/CommandsTrigger/CommandsTrigger.d.ts.map +1 -0
- package/dist/types/src/containers/CommandsTrigger/index.d.ts +3 -0
- package/dist/types/src/containers/CommandsTrigger/index.d.ts.map +1 -0
- package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts +9 -0
- package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -0
- package/dist/types/src/containers/NavTreeContainer/index.d.ts +3 -0
- package/dist/types/src/containers/NavTreeContainer/index.d.ts.map +1 -0
- package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -0
- package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts +3 -0
- package/dist/types/src/containers/NavTreeDocumentTitle/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +7 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/experimental/Tree.stories.d.ts +18 -4
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +5 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useActions.d.ts +5 -0
- package/dist/types/src/hooks/useActions.d.ts.map +1 -0
- package/dist/types/src/hooks/useLoadDescendents.d.ts +6 -0
- package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -0
- package/dist/types/src/hooks/useNavTreeModel.d.ts +7 -0
- package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -0
- package/dist/types/src/{hooks.d.ts → hooks/useNavTreeState.d.ts} +2 -14
- package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts +3 -3
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/types/events.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +5 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +43 -42
- package/src/NavTreePlugin.tsx +22 -24
- package/src/capabilities/app-graph-builder/app-graph-builder.ts +4 -3
- package/src/capabilities/keyboard/keyboard.ts +6 -5
- package/src/capabilities/operation-resolver/operation-resolver.ts +23 -19
- package/src/capabilities/react-surface/react-surface.tsx +12 -13
- package/src/capabilities/state/state.ts +41 -13
- package/src/components/NavTree/NavTree.stories.tsx +21 -19
- package/src/components/NavTree/NavTree.tsx +61 -20
- package/src/components/{NavTreeContext.tsx → NavTreeContext/NavTreeContext.tsx} +1 -1
- package/src/components/NavTreeContext/index.ts +5 -0
- package/src/components/NavTreeItem/NavTreeItemAction.stories.tsx +2 -2
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +40 -23
- package/src/components/NavTreeItem/NavTreeItemColumns.tsx +40 -14
- package/src/components/Sidebar/L0Menu.tsx +90 -74
- package/src/components/Sidebar/L1Panel.tsx +244 -90
- package/src/components/Sidebar/L1Tabs.tsx +13 -3
- package/src/components/UserAccountAvatar/UserAccountAvatar.stories.tsx +2 -3
- package/src/components/UserAccountAvatar/UserAccountAvatar.tsx +1 -1
- package/src/components/index.ts +0 -3
- package/src/components/types.ts +12 -17
- package/src/{components/CommandsDialog/CommandsDialog.tsx → containers/CommandsDialogContent/CommandsDialogContent.tsx} +19 -13
- package/src/containers/CommandsDialogContent/index.ts +7 -0
- package/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.tsx +4 -4
- package/src/containers/CommandsTrigger/index.ts +7 -0
- package/src/{components → containers/NavTreeContainer}/NavTreeContainer.tsx +75 -141
- package/src/containers/NavTreeContainer/index.ts +6 -0
- package/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.tsx +1 -1
- package/src/containers/NavTreeDocumentTitle/index.ts +7 -0
- package/src/containers/index.ts +12 -0
- package/src/experimental/Tree.stories.tsx +54 -57
- package/src/experimental/Tree.tsx +3 -3
- package/src/hooks/index.ts +8 -0
- package/src/hooks/useActions.ts +34 -0
- package/src/hooks/useLoadDescendents.ts +23 -0
- package/src/hooks/useNavTreeModel.ts +118 -0
- package/src/{hooks.ts → hooks/useNavTreeState.ts} +3 -34
- package/src/meta.ts +2 -2
- package/src/testing/app-graph-builder.ts +5 -5
- package/src/testing/generator.ts +4 -4
- package/src/types/capabilities.ts +1 -1
- package/src/types/events.ts +3 -2
- package/src/util.ts +18 -4
- package/dist/lib/browser/app-graph-builder-RSMA6I22.mjs.map +0 -7
- package/dist/lib/browser/chunk-6YPQ625I.mjs +0 -1293
- package/dist/lib/browser/chunk-6YPQ625I.mjs.map +0 -7
- package/dist/lib/browser/keyboard-32EH3N4K.mjs.map +0 -7
- package/dist/lib/browser/operation-resolver-IB75DC5O.mjs +0 -52
- package/dist/lib/browser/operation-resolver-IB75DC5O.mjs.map +0 -7
- package/dist/lib/browser/react-surface-F6CVMS3Y.mjs.map +0 -7
- package/dist/lib/browser/state-EVYQOUI3.mjs.map +0 -7
- package/dist/types/src/components/CommandsDialog/CommandsDialog.d.ts.map +0 -1
- package/dist/types/src/components/CommandsDialog/CommandsTrigger.d.ts.map +0 -1
- package/dist/types/src/components/CommandsDialog/index.d.ts +0 -3
- package/dist/types/src/components/CommandsDialog/index.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeContainer.d.ts +0 -16
- package/dist/types/src/components/NavTreeContainer.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeContext.d.ts.map +0 -1
- package/dist/types/src/components/NavTreeDocumentTitle.d.ts.map +0 -1
- package/dist/types/src/hooks.d.ts.map +0 -1
- package/src/components/CommandsDialog/index.ts +0 -6
- /package/dist/types/src/{components/CommandsDialog → containers/CommandsTrigger}/CommandsTrigger.d.ts +0 -0
- /package/dist/types/src/{components → containers/NavTreeDocumentTitle}/NavTreeDocumentTitle.d.ts +0 -0
|
@@ -4,165 +4,107 @@
|
|
|
4
4
|
|
|
5
5
|
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
6
6
|
import { type Instruction, extractInstruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
|
|
7
|
-
import React, { forwardRef, memo, useCallback, useEffect, useMemo } from 'react';
|
|
7
|
+
import React, { forwardRef, memo, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { Surface, useOperationInvoker } from '@dxos/app-framework/ui';
|
|
10
|
+
import { LayoutOperation } from '@dxos/app-toolkit';
|
|
11
|
+
import { useAppGraph, useLayout } from '@dxos/app-toolkit/ui';
|
|
12
12
|
import { Graph, Node, useActionRunner } from '@dxos/plugin-graph';
|
|
13
|
-
import { useConnections, useActions as useGraphActions } from '@dxos/plugin-graph';
|
|
14
13
|
import { useMediaQuery, useSidebars } from '@dxos/react-ui';
|
|
15
|
-
import { type TreeData,
|
|
16
|
-
import {
|
|
17
|
-
import { arrayMove, byPosition } from '@dxos/util';
|
|
14
|
+
import { type TreeData, isTreeData } from '@dxos/react-ui-list';
|
|
15
|
+
import { arrayMove } from '@dxos/util';
|
|
18
16
|
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
import { NAV_TREE_ITEM, NavTree } from './NavTree';
|
|
25
|
-
import { NavTreeContext } from './NavTreeContext';
|
|
26
|
-
import { type NavTreeContextValue } from './types';
|
|
17
|
+
import { NAV_TREE_ITEM, NavTree, NavTreeContext } from '../../components';
|
|
18
|
+
import { useNavTreeModel, useNavTreeState } from '../../hooks';
|
|
19
|
+
import { meta } from '../../meta';
|
|
20
|
+
import { type NavTreeItemGraphNode } from '../../types';
|
|
21
|
+
import { filterItems, getParent, resolveMigrationOperation } from '../../util';
|
|
27
22
|
|
|
28
23
|
// TODO(thure): Is NavTree truly authoritative in this regard?
|
|
29
24
|
export const NODE_TYPE = 'dxos/app-graph/node';
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
const getChildrenFilter = (node: Node.Node): node is Node.Node =>
|
|
36
|
-
!Node.isActionLike(node) && node.type !== PLANK_COMPANION_TYPE && node.properties.disposition !== 'hidden';
|
|
37
|
-
|
|
38
|
-
const filterItems = (node: Node.Node, disposition?: string) => {
|
|
39
|
-
if (!disposition && (node.properties.disposition === 'hidden' || node.properties.disposition === 'alternate-tree')) {
|
|
40
|
-
return false;
|
|
41
|
-
} else if (!disposition) {
|
|
42
|
-
const action = Node.isAction(node);
|
|
43
|
-
return !action || node.properties.disposition === 'item';
|
|
44
|
-
} else {
|
|
45
|
-
return node.properties.disposition === disposition;
|
|
46
|
-
}
|
|
26
|
+
// TODO(wittjosiah): Avoid using Surface within the navtree, prefer declarative data flow.
|
|
27
|
+
const NavTreeItemEnd = ({ node, open }: { node: Node.Node; open: boolean }) => {
|
|
28
|
+
const data = useMemo(() => ({ id: node.id, subject: node.data, open }), [node.id, node.data, open]);
|
|
29
|
+
return <Surface.Surface role='navtree-item-end' data={data} limit={1} />;
|
|
47
30
|
};
|
|
48
31
|
|
|
49
32
|
const getItems = (graph: Graph.ReadableGraph, node?: Node.Node, disposition?: string) => {
|
|
50
|
-
return Graph.getConnections(graph, node?.id ?? Node.RootId, '
|
|
51
|
-
filterItems(node, disposition),
|
|
52
|
-
);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const useItems = (node?: Node.Node, options?: { disposition?: string; sort?: boolean }) => {
|
|
56
|
-
const { graph } = useAppGraph();
|
|
57
|
-
const connections = useConnections(graph, node?.id ?? Node.RootId);
|
|
58
|
-
const filtered = connections.filter((node) => filterItems(node, options?.disposition));
|
|
59
|
-
return options?.sort ? filtered.toSorted((a, b) => byPosition(a.properties, b.properties)) : filtered;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const useActions = (node: Node.Node): FlattenedActions => {
|
|
63
|
-
const { graph } = useAppGraph();
|
|
64
|
-
const actions = useGraphActions(graph, node.id);
|
|
65
|
-
|
|
66
|
-
return useMemo(
|
|
67
|
-
() =>
|
|
68
|
-
actions.reduce(
|
|
69
|
-
(acc: FlattenedActions, arg) => {
|
|
70
|
-
if (arg.properties.disposition === 'item') {
|
|
71
|
-
return acc;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
acc.actions.push(arg);
|
|
75
|
-
if (!Node.isAction(arg)) {
|
|
76
|
-
const actionGroup = Graph.getActions(graph, arg.id);
|
|
77
|
-
acc.groupedActions[arg.id] = actionGroup;
|
|
78
|
-
}
|
|
79
|
-
return acc;
|
|
80
|
-
},
|
|
81
|
-
{ actions: [], groupedActions: {} },
|
|
82
|
-
),
|
|
83
|
-
[actions],
|
|
84
|
-
);
|
|
33
|
+
return Graph.getConnections(graph, node?.id ?? Node.RootId, 'child').filter((node) => filterItems(node, disposition));
|
|
85
34
|
};
|
|
86
35
|
|
|
87
36
|
export type NavTreeContainerProps = {
|
|
88
37
|
popoverAnchorId?: string;
|
|
89
|
-
|
|
90
|
-
}
|
|
38
|
+
tab: string;
|
|
39
|
+
};
|
|
91
40
|
|
|
92
41
|
export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProps>(
|
|
93
|
-
({ tab, popoverAnchorId
|
|
42
|
+
({ tab, popoverAnchorId }, forwardedRef) => {
|
|
94
43
|
const [isLg] = useMediaQuery('lg');
|
|
95
44
|
const { invokeSync, invokePromise } = useOperationInvoker();
|
|
96
45
|
const runAction = useActionRunner();
|
|
97
46
|
const { graph } = useAppGraph();
|
|
98
47
|
const { getItem, setItem } = useNavTreeState();
|
|
99
48
|
const layout = useLayout();
|
|
49
|
+
const model = useNavTreeModel(Node.RootId);
|
|
100
50
|
const { navigationSidebarState } = useSidebars(meta.id);
|
|
51
|
+
const latestRef = useRef({
|
|
52
|
+
tab,
|
|
53
|
+
activeItems: layout.active,
|
|
54
|
+
navigationSidebarState,
|
|
55
|
+
isLg,
|
|
56
|
+
});
|
|
101
57
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
disabled: node.properties.disabled,
|
|
111
|
-
label: node.properties.label ?? node.id,
|
|
112
|
-
className: mx(node.properties.className, node.properties.modified && 'italic'), // TODO(burdon): Italic?
|
|
113
|
-
headingClassName: node.properties.headingClassName,
|
|
114
|
-
icon: node.properties.icon,
|
|
115
|
-
iconHue: node.properties.iconHue,
|
|
116
|
-
testId: node.properties.testId,
|
|
117
|
-
};
|
|
118
|
-
},
|
|
119
|
-
[graph],
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
const loadDescendents = useCallback(
|
|
123
|
-
(node: Node.Node) => {
|
|
124
|
-
Graph.expand(graph, node.id, 'outbound');
|
|
125
|
-
// Load one level deeper, which resolves some juddering observed on open/close.
|
|
126
|
-
Graph.getConnections(graph, node.id, 'outbound').forEach((child) => {
|
|
127
|
-
Graph.expand(graph, child.id, 'outbound');
|
|
128
|
-
});
|
|
129
|
-
},
|
|
130
|
-
[graph],
|
|
131
|
-
);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
latestRef.current = {
|
|
60
|
+
tab,
|
|
61
|
+
activeItems: layout.active,
|
|
62
|
+
navigationSidebarState,
|
|
63
|
+
isLg,
|
|
64
|
+
};
|
|
65
|
+
}, [tab, layout.active, navigationSidebarState, isLg]);
|
|
132
66
|
|
|
133
67
|
const handleOpenChange = useCallback(
|
|
134
68
|
({ item: { id }, path, open }: { item: Node.Node; path: string[]; open: boolean }) => {
|
|
135
69
|
// TODO(thure): This might become a localstorage leak; openItemIds that no longer exist should be removed from this map.
|
|
136
70
|
setItem(path, 'open', open);
|
|
137
|
-
Graph.expand(graph, id, '
|
|
71
|
+
Graph.expand(graph, id, 'child');
|
|
138
72
|
},
|
|
139
|
-
[graph],
|
|
73
|
+
[graph, setItem],
|
|
140
74
|
);
|
|
141
75
|
|
|
142
76
|
const handleTabChange = useCallback(
|
|
143
77
|
(node: NavTreeItemGraphNode) => {
|
|
144
|
-
|
|
78
|
+
Graph.expand(graph, node.id, 'child');
|
|
79
|
+
|
|
80
|
+
const {
|
|
81
|
+
tab: activeTab,
|
|
82
|
+
activeItems,
|
|
83
|
+
navigationSidebarState: currentSidebarState,
|
|
84
|
+
isLg: latestIsLg,
|
|
85
|
+
} = latestRef.current;
|
|
86
|
+
invokeSync(LayoutOperation.UpdateSidebar, {
|
|
145
87
|
state:
|
|
146
|
-
node.id ===
|
|
147
|
-
?
|
|
148
|
-
?
|
|
88
|
+
node.id === activeTab
|
|
89
|
+
? currentSidebarState === 'expanded'
|
|
90
|
+
? latestIsLg
|
|
149
91
|
? 'collapsed'
|
|
150
92
|
: 'closed'
|
|
151
93
|
: 'expanded'
|
|
152
94
|
: 'expanded',
|
|
153
95
|
});
|
|
154
96
|
|
|
155
|
-
invokeSync(
|
|
97
|
+
invokeSync(LayoutOperation.SwitchWorkspace, { subject: node.id });
|
|
156
98
|
|
|
157
99
|
// Open the first item if the workspace is empty.
|
|
158
|
-
if (
|
|
100
|
+
if (activeItems.length === 0) {
|
|
159
101
|
const [item] = getItems(graph, node).filter((node) => !Node.isActionLike(node));
|
|
160
102
|
if (item && item.data) {
|
|
161
|
-
invokeSync(
|
|
103
|
+
invokeSync(LayoutOperation.Open, { subject: [item.id] });
|
|
162
104
|
}
|
|
163
105
|
}
|
|
164
106
|
},
|
|
165
|
-
[invokeSync,
|
|
107
|
+
[invokeSync, graph],
|
|
166
108
|
);
|
|
167
109
|
|
|
168
110
|
const blockInstruction = useCallback(
|
|
@@ -187,20 +129,20 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
|
|
|
187
129
|
}
|
|
188
130
|
|
|
189
131
|
if (Node.isAction(node)) {
|
|
190
|
-
const [parent] = Graph.getConnections(graph, node.id, 'inbound');
|
|
132
|
+
const [parent] = Graph.getConnections(graph, node.id, Node.childRelation('inbound'));
|
|
191
133
|
if (parent) {
|
|
192
|
-
void runAction(node, { parent, caller: NAV_TREE_ITEM });
|
|
134
|
+
void runAction(node, { parent, path, caller: NAV_TREE_ITEM });
|
|
193
135
|
}
|
|
194
136
|
return;
|
|
195
137
|
}
|
|
196
138
|
|
|
197
139
|
const current = getItem(path).current;
|
|
198
140
|
if (!current) {
|
|
199
|
-
invokeSync(
|
|
141
|
+
invokeSync(LayoutOperation.Open, { subject: [node.id], key: node.properties.key });
|
|
200
142
|
} else if (option) {
|
|
201
|
-
invokeSync(
|
|
143
|
+
invokeSync(LayoutOperation.Close, { subject: [node.id] });
|
|
202
144
|
} else {
|
|
203
|
-
void invokePromise(
|
|
145
|
+
void invokePromise(LayoutOperation.ScrollIntoView, { subject: node.id });
|
|
204
146
|
}
|
|
205
147
|
|
|
206
148
|
const defaultAction = Graph.getActions(graph, node.id).find(
|
|
@@ -211,13 +153,13 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
|
|
|
211
153
|
}
|
|
212
154
|
|
|
213
155
|
if (!isLg) {
|
|
214
|
-
invokeSync(
|
|
156
|
+
invokeSync(LayoutOperation.UpdateSidebar, { state: 'closed' });
|
|
215
157
|
}
|
|
216
158
|
},
|
|
217
|
-
[graph, invokeSync, invokePromise, getItem,
|
|
159
|
+
[graph, invokeSync, invokePromise, getItem, runAction, isLg],
|
|
218
160
|
);
|
|
219
161
|
|
|
220
|
-
const handleBack = useCallback(() => invokeSync(
|
|
162
|
+
const handleBack = useCallback(() => invokeSync(LayoutOperation.RevertWorkspace), [invokeSync]);
|
|
221
163
|
|
|
222
164
|
// TODO(wittjosiah): Factor out hook.
|
|
223
165
|
useEffect(() => {
|
|
@@ -235,8 +177,9 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
|
|
|
235
177
|
const targetNode = target.data.item as NavTreeItemGraphNode;
|
|
236
178
|
const sourcePath = source.data.path as string[];
|
|
237
179
|
const targetPath = target.data.path as string[];
|
|
180
|
+
const sameParent = sourcePath.slice(0, -1).join() === targetPath.slice(0, -1).join();
|
|
238
181
|
const operation =
|
|
239
|
-
|
|
182
|
+
sameParent && instruction.type !== 'make-child'
|
|
240
183
|
? 'rearrange'
|
|
241
184
|
: resolveMigrationOperation(graph, sourceNode, targetPath, targetNode);
|
|
242
185
|
const sourceParent = getParent(graph, sourceNode, sourcePath);
|
|
@@ -265,7 +208,7 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
|
|
|
265
208
|
}
|
|
266
209
|
case 'transfer': {
|
|
267
210
|
const target = instruction.type === 'make-child' ? targetNode : targetParent;
|
|
268
|
-
if (!target?.properties.onTransferStart ||
|
|
211
|
+
if (!target?.properties.onTransferStart || target?.id === sourceParent?.id) {
|
|
269
212
|
break;
|
|
270
213
|
}
|
|
271
214
|
void target?.properties.onTransferStart(sourceNode, migrationIndex);
|
|
@@ -285,50 +228,41 @@ export const NavTreeContainer$ = forwardRef<HTMLDivElement, NavTreeContainerProp
|
|
|
285
228
|
[setItem],
|
|
286
229
|
);
|
|
287
230
|
|
|
231
|
+
const onItemHover = useCallback(({ item }: { item: Node.Node }) => Graph.expand(graph, item.id, 'child'), [graph]);
|
|
232
|
+
|
|
288
233
|
const navTreeContextValue = useMemo(
|
|
289
234
|
() => ({
|
|
235
|
+
model,
|
|
236
|
+
popoverAnchorId,
|
|
237
|
+
renderItemEnd: NavTreeItemEnd,
|
|
290
238
|
blockInstruction,
|
|
291
239
|
canDrop,
|
|
292
240
|
canSelect,
|
|
293
|
-
|
|
294
|
-
useIsAlternateTree,
|
|
295
|
-
useIsCurrent,
|
|
296
|
-
useIsOpen,
|
|
297
|
-
loadDescendents,
|
|
241
|
+
setAlternateTree,
|
|
298
242
|
onBack: handleBack,
|
|
299
243
|
onOpenChange: handleOpenChange,
|
|
300
244
|
onSelect: handleSelect,
|
|
301
245
|
onTabChange: handleTabChange,
|
|
302
|
-
|
|
303
|
-
renderItemEnd,
|
|
304
|
-
setAlternateTree,
|
|
305
|
-
tab,
|
|
306
|
-
topbar,
|
|
307
|
-
useActions,
|
|
308
|
-
useItems,
|
|
246
|
+
onItemHover,
|
|
309
247
|
}),
|
|
310
248
|
[
|
|
249
|
+
model,
|
|
250
|
+
popoverAnchorId,
|
|
311
251
|
blockInstruction,
|
|
312
252
|
canDrop,
|
|
313
253
|
canSelect,
|
|
314
|
-
|
|
254
|
+
setAlternateTree,
|
|
315
255
|
handleBack,
|
|
316
256
|
handleOpenChange,
|
|
317
257
|
handleSelect,
|
|
318
258
|
handleTabChange,
|
|
319
|
-
|
|
320
|
-
popoverAnchorId,
|
|
321
|
-
renderItemEnd,
|
|
322
|
-
setAlternateTree,
|
|
323
|
-
tab,
|
|
324
|
-
topbar,
|
|
325
|
-
useActions,
|
|
259
|
+
onItemHover,
|
|
326
260
|
],
|
|
327
261
|
);
|
|
328
262
|
|
|
329
263
|
return (
|
|
330
264
|
<NavTreeContext.Provider value={navTreeContextValue}>
|
|
331
|
-
<NavTree id={Node.RootId} root={Graph.getRoot(graph)} open={layout.sidebarOpen} ref={forwardedRef} />
|
|
265
|
+
<NavTree id={Node.RootId} root={Graph.getRoot(graph)} tab={tab} open={layout.sidebarOpen} ref={forwardedRef} />
|
|
332
266
|
</NavTreeContext.Provider>
|
|
333
267
|
);
|
|
334
268
|
},
|
|
@@ -7,7 +7,7 @@ import { type Node } from '@dxos/app-graph';
|
|
|
7
7
|
import { toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
8
8
|
import { osTranslations } from '@dxos/ui-theme';
|
|
9
9
|
|
|
10
|
-
import { meta } from '
|
|
10
|
+
import { meta } from '../../meta';
|
|
11
11
|
|
|
12
12
|
export const NavTreeDocumentTitle = ({ node }: { node?: Node.Node }) => {
|
|
13
13
|
const { t } = useTranslation(meta.id);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type ComponentType, lazy } from 'react';
|
|
6
|
+
|
|
7
|
+
export { NODE_TYPE } from './NavTreeContainer';
|
|
8
|
+
|
|
9
|
+
export const CommandsDialogContent: ComponentType<any> = lazy(() => import('./CommandsDialogContent'));
|
|
10
|
+
export const CommandsTrigger: ComponentType<any> = lazy(() => import('./CommandsTrigger'));
|
|
11
|
+
export const NavTreeContainer: ComponentType<any> = lazy(() => import('./NavTreeContainer'));
|
|
12
|
+
export const NavTreeDocumentTitle: ComponentType<any> = lazy(() => import('./NavTreeDocumentTitle'));
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Meta } from '@storybook/react-vite';
|
|
6
|
-
import React, {
|
|
6
|
+
import React, { useEffect, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { faker } from '@dxos/random';
|
|
9
|
-
import { Icon, IconButton } from '@dxos/react-ui';
|
|
9
|
+
import { Icon, IconButton, Panel, ScrollArea } from '@dxos/react-ui';
|
|
10
10
|
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
11
|
import { mx } from '@dxos/ui-theme';
|
|
12
12
|
|
|
@@ -14,28 +14,6 @@ import { type ItemMap, Tree, type TreeNodeData, type TreeProps, visitNodes, visi
|
|
|
14
14
|
|
|
15
15
|
faker.seed(1234);
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* Space:
|
|
19
|
-
* - Space panels are separated from each other to give them more weight than folders.
|
|
20
|
-
* - Private space isn't different (just first, different icon).
|
|
21
|
-
* - Edit titles in place.
|
|
22
|
-
*
|
|
23
|
-
* Navigation:
|
|
24
|
-
* - up/down across spaces/folder peers
|
|
25
|
-
* - right to enter space/folder children
|
|
26
|
-
* - left to parent
|
|
27
|
-
*/
|
|
28
|
-
const Container = ({ children, sidebar }: PropsWithChildren<{ sidebar: JSX.Element }>) => {
|
|
29
|
-
return (
|
|
30
|
-
<div className='flex'>
|
|
31
|
-
{/* TODO(burdon): Custom thin scrollbar. */}
|
|
32
|
-
{/* TODO(burdon): Horizontal scrolling within navtree? */}
|
|
33
|
-
<div className='flex flex-col overflow-y-auto is-[300px] bg-neutral-100 dark:bg-neutral-950'>{sidebar}</div>
|
|
34
|
-
<div className='flex flex-col grow overflow-hidden'>{children}</div>
|
|
35
|
-
</div>
|
|
36
|
-
);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
17
|
// TODO(burdon): Generate.
|
|
40
18
|
const data: TreeNodeData[] = [
|
|
41
19
|
{
|
|
@@ -134,7 +112,7 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
134
112
|
}
|
|
135
113
|
}, []);
|
|
136
114
|
|
|
137
|
-
const handleCreateItem: TreeProps['onMenuAction'] = (id
|
|
115
|
+
const handleCreateItem: TreeProps['onMenuAction'] = (id) => {
|
|
138
116
|
setItems((items) => {
|
|
139
117
|
let parent: TreeNodeData | undefined;
|
|
140
118
|
visitNodes(root, (node) => {
|
|
@@ -167,49 +145,68 @@ const Sidebar = ({ mutate }: { mutate?: boolean }) => {
|
|
|
167
145
|
};
|
|
168
146
|
|
|
169
147
|
return (
|
|
170
|
-
<
|
|
171
|
-
<
|
|
172
|
-
<
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
148
|
+
<Panel.Root>
|
|
149
|
+
<Panel.Content asChild>
|
|
150
|
+
<ScrollArea.Root orientation='vertical' thin>
|
|
151
|
+
<ScrollArea.Viewport>
|
|
152
|
+
<Tree
|
|
153
|
+
className='p-0.5 gap-1'
|
|
154
|
+
node={root}
|
|
155
|
+
open={openItems}
|
|
156
|
+
selected={selectedItems}
|
|
157
|
+
active={activeItems}
|
|
158
|
+
onChangeOpen={(id, open) => setOpenItems((items) => ({ ...items, [id]: open }))}
|
|
159
|
+
onChangeSelected={(id, open) => setSelectedItems((items) => ({ ...items, [id]: open }))}
|
|
160
|
+
onMenuAction={handleCreateItem}
|
|
161
|
+
getSlots={(node, open, depth) => {
|
|
162
|
+
if (depth === 1) {
|
|
163
|
+
return {
|
|
164
|
+
root: 'rounded-sm bg-white dark:bg-neutral-850',
|
|
165
|
+
header: mx('rounded-t bg-neutral-50 dark:bg-neutral-900', !open && 'rounded-b'),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}}
|
|
169
|
+
/>
|
|
170
|
+
</ScrollArea.Viewport>
|
|
171
|
+
</ScrollArea.Root>
|
|
172
|
+
</Panel.Content>
|
|
173
|
+
<Panel.Statusbar>
|
|
174
|
+
<div className='flex items-center my-2 px-2 gap-2'>
|
|
175
|
+
<IconButton icon='ph--plus-circle--regular' iconOnly label='Create space' onClick={handleCreateSpace} />
|
|
176
|
+
<span className='grow text-sm' onClick={handleCreateSpace}>
|
|
177
|
+
New space
|
|
178
|
+
</span>
|
|
179
|
+
<Icon icon='ph--list--regular' />
|
|
180
|
+
</div>
|
|
181
|
+
</Panel.Statusbar>
|
|
182
|
+
</Panel.Root>
|
|
200
183
|
);
|
|
201
184
|
};
|
|
202
185
|
|
|
203
186
|
const meta = {
|
|
204
187
|
title: 'plugins/plugin-navtree/experimental/Tree',
|
|
205
188
|
component: Tree,
|
|
206
|
-
decorators: [withTheme, withLayout({ layout: 'column' })],
|
|
189
|
+
decorators: [withTheme(), withLayout({ layout: 'column', classNames: 'w-[20rem]' })],
|
|
190
|
+
parameters: {
|
|
191
|
+
layout: 'fullscreen',
|
|
192
|
+
},
|
|
207
193
|
} satisfies Meta<typeof Tree>;
|
|
208
194
|
|
|
209
195
|
export default meta;
|
|
210
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Space:
|
|
199
|
+
* - Space panels are separated from each other to give them more weight than folders.
|
|
200
|
+
* - Private space isn't different (just first, different icon).
|
|
201
|
+
* - Edit titles in place.
|
|
202
|
+
*
|
|
203
|
+
* Navigation:
|
|
204
|
+
* - up/down across spaces/folder peers
|
|
205
|
+
* - right to enter space/folder children
|
|
206
|
+
* - left to parent
|
|
207
|
+
*/
|
|
211
208
|
export const Default = () => {
|
|
212
|
-
return <
|
|
209
|
+
return <Sidebar mutate />;
|
|
213
210
|
};
|
|
214
211
|
|
|
215
212
|
export const Visitor = () => {
|
|
@@ -19,7 +19,7 @@ export const IconButton = ({
|
|
|
19
19
|
} & Pick<HTMLAttributes<HTMLDivElement>, 'onClick'>) => {
|
|
20
20
|
// TODO(burdon): Density aware.
|
|
21
21
|
return (
|
|
22
|
-
<div className={mx('flex
|
|
22
|
+
<div className={mx('flex w-6 h-6 items-center justify-center select-none', classNames)} onClick={onClick}>
|
|
23
23
|
<Icon icon={iconName} classNames='cursor-pointer' size={size} />
|
|
24
24
|
</div>
|
|
25
25
|
);
|
|
@@ -193,9 +193,9 @@ export const TreeNodeRow = (props: TreeNodeProps & { className?: string }) => {
|
|
|
193
193
|
<Grid
|
|
194
194
|
style={{ paddingLeft: `${(depth - 1) * 24}px` }}
|
|
195
195
|
className={mx(
|
|
196
|
-
'group
|
|
196
|
+
'group w-full items-center cursor-pointer bg-hover-surface',
|
|
197
197
|
// TODO(burdon): Use data-active.
|
|
198
|
-
selected?.[id] && 'bg-
|
|
198
|
+
selected?.[id] && 'bg-active-surface',
|
|
199
199
|
className,
|
|
200
200
|
)}
|
|
201
201
|
onClick={() => selected && onChangeSelected?.(id, !selected[id])}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import { useAppGraph } from '@dxos/app-toolkit/ui';
|
|
8
|
+
import { Graph, Node, useActions as useGraphActions } from '@dxos/plugin-graph';
|
|
9
|
+
|
|
10
|
+
import { type FlattenedActions } from '../types';
|
|
11
|
+
|
|
12
|
+
/** Returns flattened actions and grouped sub-actions for a given graph node. */
|
|
13
|
+
export const useActions = (node: Node.Node): FlattenedActions => {
|
|
14
|
+
const { graph } = useAppGraph();
|
|
15
|
+
const actions = useGraphActions(graph, node.id);
|
|
16
|
+
|
|
17
|
+
return useMemo(() => {
|
|
18
|
+
return actions.reduce(
|
|
19
|
+
(acc: FlattenedActions, arg) => {
|
|
20
|
+
if (arg.properties.disposition === 'item') {
|
|
21
|
+
return acc;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
acc.actions.push(arg);
|
|
25
|
+
if (!Node.isAction(arg)) {
|
|
26
|
+
const actionGroup = Graph.getActions(graph, arg.id);
|
|
27
|
+
acc.groupedActions[arg.id] = actionGroup;
|
|
28
|
+
}
|
|
29
|
+
return acc;
|
|
30
|
+
},
|
|
31
|
+
{ actions: [], groupedActions: {} },
|
|
32
|
+
);
|
|
33
|
+
}, [actions]);
|
|
34
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type Node } from '@dxos/app-graph';
|
|
8
|
+
import { useAppGraph } from '@dxos/app-toolkit/ui';
|
|
9
|
+
import { Graph } from '@dxos/plugin-graph';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Expands a root node in the app graph.
|
|
13
|
+
*/
|
|
14
|
+
export const useLoadDescendents = (root?: Node.Node) => {
|
|
15
|
+
const { graph } = useAppGraph();
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!root) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Graph.expand(graph, root.id, 'child');
|
|
22
|
+
}, [graph, root]);
|
|
23
|
+
};
|