@dxos/plugin-navtree 0.8.4-main.9be5663bfe → 0.8.4-main.abd8ff62ef
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/NavTreePlugin-53I3ONRE.mjs +74 -0
- package/dist/lib/browser/NavTreePlugin-53I3ONRE.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +28 -111
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/translations.mjs +21 -0
- package/dist/lib/browser/translations.mjs.map +7 -0
- package/dist/types/src/NavTreePlugin.d.ts +1 -0
- package/dist/types/src/NavTreePlugin.d.ts.map +1 -1
- package/dist/types/src/NavTreePlugin.node.d.ts +4 -0
- package/dist/types/src/NavTreePlugin.node.d.ts.map +1 -0
- package/dist/types/src/NavTreePlugin.test.d.ts +2 -0
- package/dist/types/src/NavTreePlugin.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/keyboard.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts +8 -9
- package/dist/types/src/components/NavTree/NavTree.stories.d.ts.map +1 -1
- package/dist/types/src/components/NavTreeItem/NavTreeItemAction.d.ts +2 -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/NavTreeItemAction.stories.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L0Menu.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Panel.d.ts.map +1 -1
- package/dist/types/src/components/Sidebar/L1Tabs.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.map +1 -1
- package/dist/types/src/components/types.d.ts +0 -1
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.d.ts.map +1 -1
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts +8 -9
- package/dist/types/src/containers/CommandsDialogContent/CommandsDialogContent.stories.d.ts.map +1 -1
- package/dist/types/src/containers/NavTreeContainer/NavTreeContainer.d.ts.map +1 -1
- package/dist/types/src/containers/NavTreeDocumentTitle/NavTreeDocumentTitle.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.d.ts +2 -2
- package/dist/types/src/experimental/Tree.d.ts.map +1 -1
- package/dist/types/src/experimental/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useActions.d.ts.map +1 -1
- package/dist/types/src/hooks/useLoadDescendents.d.ts.map +1 -1
- package/dist/types/src/hooks/useNavTreeModel.d.ts.map +1 -1
- package/dist/types/src/hooks/useNavTreeState.d.ts +1 -5
- package/dist/types/src/hooks/useNavTreeState.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/operations/expose.d.ts +1 -1
- package/dist/types/src/operations/expose.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts +1 -1
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/testing/generator.d.ts.map +1 -1
- package/dist/types/src/testing/update-state.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +8 -10
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/capabilities.d.ts +1 -2
- package/dist/types/src/types/capabilities.d.ts.map +1 -1
- package/dist/types/src/types/events.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +1 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +49 -40
- package/src/NavTreePlugin.node.ts +37 -0
- package/src/NavTreePlugin.test.ts +29 -0
- package/src/NavTreePlugin.tsx +4 -3
- package/src/capabilities/app-graph-builder.ts +1 -1
- package/src/capabilities/index.ts +1 -1
- package/src/capabilities/operation-handler.ts +1 -1
- package/src/capabilities/react-surface.tsx +2 -3
- package/src/capabilities/state.ts +2 -2
- package/src/components/NavTree/NavTree.stories.tsx +2 -2
- package/src/components/NavTreeItem/NavTreeItemAction.tsx +3 -4
- package/src/components/Sidebar/L1Panel.tsx +82 -141
- package/src/components/types.ts +0 -1
- package/src/containers/CommandsDialogContent/CommandsDialogContent.stories.tsx +2 -1
- package/src/containers/CommandsDialogContent/CommandsDialogContent.tsx +42 -46
- package/src/containers/NavTreeContainer/NavTreeContainer.tsx +0 -9
- package/src/hooks/useNavTreeState.ts +1 -8
- package/src/index.ts +8 -2
- package/src/operations/expose.ts +1 -1
- package/src/operations/index.ts +1 -1
- package/src/translations.ts +0 -1
- package/src/types/capabilities.ts +2 -2
- package/src/util.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-navtree",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.abd8ff62ef",
|
|
4
4
|
"description": "DXOS Surface plugin for a tree view visualization of the graph.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"sideEffects": true,
|
|
14
14
|
"type": "module",
|
|
15
15
|
"imports": {
|
|
16
|
+
"#plugin": {
|
|
17
|
+
"browser": "./src/NavTreePlugin.tsx",
|
|
18
|
+
"node": "./src/NavTreePlugin.node.ts",
|
|
19
|
+
"default": "./src/NavTreePlugin.tsx"
|
|
20
|
+
},
|
|
16
21
|
"#capabilities": "./src/capabilities/index.ts",
|
|
17
22
|
"#components": "./src/components/index.ts",
|
|
18
23
|
"#containers": "./src/containers/index.ts",
|
|
@@ -20,6 +25,7 @@
|
|
|
20
25
|
"#meta": "./src/meta.ts",
|
|
21
26
|
"#operations": "./src/operations/index.ts",
|
|
22
27
|
"#testing": "./src/testing/index.ts",
|
|
28
|
+
"#translations": "./src/translations.ts",
|
|
23
29
|
"#types": "./src/types/index.ts"
|
|
24
30
|
},
|
|
25
31
|
"exports": {
|
|
@@ -27,12 +33,15 @@
|
|
|
27
33
|
"source": "./src/index.ts",
|
|
28
34
|
"types": "./dist/types/src/index.d.ts",
|
|
29
35
|
"browser": "./dist/lib/browser/index.mjs"
|
|
36
|
+
},
|
|
37
|
+
"./translations": {
|
|
38
|
+
"source": "./src/translations.ts",
|
|
39
|
+
"types": "./dist/types/src/translations.d.ts",
|
|
40
|
+
"browser": "./dist/lib/browser/translations.mjs",
|
|
41
|
+
"node": "./dist/lib/node-esm/translations.mjs"
|
|
30
42
|
}
|
|
31
43
|
},
|
|
32
44
|
"types": "dist/types/src/index.d.ts",
|
|
33
|
-
"typesVersions": {
|
|
34
|
-
"*": {}
|
|
35
|
-
},
|
|
36
45
|
"files": [
|
|
37
46
|
"dist",
|
|
38
47
|
"src"
|
|
@@ -43,30 +52,30 @@
|
|
|
43
52
|
"@radix-ui/react-dismissable-layer": "1.1.5",
|
|
44
53
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
45
54
|
"date-fns": "^3.6.0",
|
|
46
|
-
"@dxos/app-
|
|
47
|
-
"@dxos/
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/app-
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/
|
|
52
|
-
"@dxos/invariant": "0.8.4-main.
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/log": "0.8.4-main.
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/plugin-
|
|
58
|
-
"@dxos/plugin-
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/react-client": "0.8.4-main.
|
|
62
|
-
"@dxos/react-ui-attention": "0.8.4-main.
|
|
63
|
-
"@dxos/react-ui-
|
|
64
|
-
"@dxos/react-ui-
|
|
65
|
-
"@dxos/react-ui-mosaic": "0.8.4-main.
|
|
66
|
-
"@dxos/react-ui-search": "0.8.4-main.
|
|
67
|
-
"@dxos/react-ui-tabs": "0.8.4-main.
|
|
68
|
-
"@dxos/react-ui-stack": "0.8.4-main.
|
|
69
|
-
"@dxos/util": "0.8.4-main.
|
|
55
|
+
"@dxos/app-framework": "0.8.4-main.abd8ff62ef",
|
|
56
|
+
"@dxos/app-toolkit": "0.8.4-main.abd8ff62ef",
|
|
57
|
+
"@dxos/async": "0.8.4-main.abd8ff62ef",
|
|
58
|
+
"@dxos/app-graph": "0.8.4-main.abd8ff62ef",
|
|
59
|
+
"@dxos/debug": "0.8.4-main.abd8ff62ef",
|
|
60
|
+
"@dxos/compute": "0.8.4-main.abd8ff62ef",
|
|
61
|
+
"@dxos/invariant": "0.8.4-main.abd8ff62ef",
|
|
62
|
+
"@dxos/echo": "0.8.4-main.abd8ff62ef",
|
|
63
|
+
"@dxos/keyboard": "0.8.4-main.abd8ff62ef",
|
|
64
|
+
"@dxos/log": "0.8.4-main.abd8ff62ef",
|
|
65
|
+
"@dxos/lit-ui": "0.8.4-main.abd8ff62ef",
|
|
66
|
+
"@dxos/plugin-deck": "0.8.4-main.abd8ff62ef",
|
|
67
|
+
"@dxos/plugin-graph": "0.8.4-main.abd8ff62ef",
|
|
68
|
+
"@dxos/plugin-observability": "0.8.4-main.abd8ff62ef",
|
|
69
|
+
"@dxos/protocols": "0.8.4-main.abd8ff62ef",
|
|
70
|
+
"@dxos/react-client": "0.8.4-main.abd8ff62ef",
|
|
71
|
+
"@dxos/react-ui-attention": "0.8.4-main.abd8ff62ef",
|
|
72
|
+
"@dxos/react-ui-list": "0.8.4-main.abd8ff62ef",
|
|
73
|
+
"@dxos/react-ui-menu": "0.8.4-main.abd8ff62ef",
|
|
74
|
+
"@dxos/react-ui-mosaic": "0.8.4-main.abd8ff62ef",
|
|
75
|
+
"@dxos/react-ui-search": "0.8.4-main.abd8ff62ef",
|
|
76
|
+
"@dxos/react-ui-tabs": "0.8.4-main.abd8ff62ef",
|
|
77
|
+
"@dxos/react-ui-stack": "0.8.4-main.abd8ff62ef",
|
|
78
|
+
"@dxos/util": "0.8.4-main.abd8ff62ef"
|
|
70
79
|
},
|
|
71
80
|
"devDependencies": {
|
|
72
81
|
"@effect-atom/atom-react": "^0.5.0",
|
|
@@ -76,16 +85,16 @@
|
|
|
76
85
|
"effect": "3.20.0",
|
|
77
86
|
"react": "~19.2.3",
|
|
78
87
|
"react-dom": "~19.2.3",
|
|
79
|
-
"vite": "^
|
|
80
|
-
"@dxos/plugin-attention": "0.8.4-main.
|
|
81
|
-
"@dxos/plugin-space": "0.8.4-main.
|
|
82
|
-
"@dxos/plugin-client": "0.8.4-main.
|
|
83
|
-
"@dxos/plugin-testing": "0.8.4-main.
|
|
84
|
-
"@dxos/plugin-theme": "0.8.4-main.
|
|
85
|
-
"@dxos/random": "0.8.4-main.
|
|
86
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
87
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
88
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
88
|
+
"vite": "^8.0.10",
|
|
89
|
+
"@dxos/plugin-attention": "0.8.4-main.abd8ff62ef",
|
|
90
|
+
"@dxos/plugin-space": "0.8.4-main.abd8ff62ef",
|
|
91
|
+
"@dxos/plugin-client": "0.8.4-main.abd8ff62ef",
|
|
92
|
+
"@dxos/plugin-testing": "0.8.4-main.abd8ff62ef",
|
|
93
|
+
"@dxos/plugin-theme": "0.8.4-main.abd8ff62ef",
|
|
94
|
+
"@dxos/random": "0.8.4-main.abd8ff62ef",
|
|
95
|
+
"@dxos/react-ui": "0.8.4-main.abd8ff62ef",
|
|
96
|
+
"@dxos/storybook-utils": "0.8.4-main.abd8ff62ef",
|
|
97
|
+
"@dxos/ui-theme": "0.8.4-main.abd8ff62ef"
|
|
89
98
|
},
|
|
90
99
|
"peerDependencies": {
|
|
91
100
|
"@effect-atom/atom-react": "^0.5.0",
|
|
@@ -93,8 +102,8 @@
|
|
|
93
102
|
"effect": "3.20.0",
|
|
94
103
|
"react": "~19.2.3",
|
|
95
104
|
"react-dom": "~19.2.3",
|
|
96
|
-
"@dxos/
|
|
97
|
-
"@dxos/ui
|
|
105
|
+
"@dxos/ui-theme": "0.8.4-main.abd8ff62ef",
|
|
106
|
+
"@dxos/react-ui": "0.8.4-main.abd8ff62ef"
|
|
98
107
|
},
|
|
99
108
|
"publishConfig": {
|
|
100
109
|
"access": "public"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Plugin } from '@dxos/app-framework';
|
|
6
|
+
import { AppPlugin } from '@dxos/app-toolkit';
|
|
7
|
+
import { type TreeData } from '@dxos/react-ui-list';
|
|
8
|
+
|
|
9
|
+
import { AppGraphBuilder, OperationHandler } from '#capabilities';
|
|
10
|
+
import { meta } from '#meta';
|
|
11
|
+
|
|
12
|
+
const NODE_TYPE = 'dxos/app-graph/node';
|
|
13
|
+
|
|
14
|
+
export const NavTreePlugin = Plugin.define(meta).pipe(
|
|
15
|
+
AppPlugin.addAppGraphModule({ activate: AppGraphBuilder }),
|
|
16
|
+
AppPlugin.addMetadataModule({
|
|
17
|
+
metadata: {
|
|
18
|
+
id: NODE_TYPE,
|
|
19
|
+
metadata: {
|
|
20
|
+
parse: ({ item }: TreeData, type: string) => {
|
|
21
|
+
switch (type) {
|
|
22
|
+
case 'node':
|
|
23
|
+
return item;
|
|
24
|
+
case 'object':
|
|
25
|
+
return item.data;
|
|
26
|
+
case 'view-object':
|
|
27
|
+
return { id: `${item.id}-view`, object: item.data };
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),
|
|
34
|
+
Plugin.make,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
export default NavTreePlugin;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { ActivationEvents } from '@dxos/app-framework';
|
|
8
|
+
import { createComposerTestApp } from '@dxos/plugin-testing/harness';
|
|
9
|
+
|
|
10
|
+
import { NavTreePlugin } from '#plugin';
|
|
11
|
+
|
|
12
|
+
import { meta } from './meta';
|
|
13
|
+
|
|
14
|
+
const moduleId = (name: string) => `${meta.id}.module.${name}`;
|
|
15
|
+
|
|
16
|
+
describe('NavTreePlugin', () => {
|
|
17
|
+
test('modules activate on the expected events', async ({ expect }) => {
|
|
18
|
+
await using harness = await createComposerTestApp({
|
|
19
|
+
plugins: [NavTreePlugin()],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
expect(harness.manager.getActive()).toEqual(
|
|
23
|
+
expect.arrayContaining([moduleId('AppGraphBuilder'), moduleId('metadata')]),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
await harness.fire(ActivationEvents.SetupOperationHandler);
|
|
27
|
+
expect(harness.manager.getActive()).toContain(moduleId('OperationHandler'));
|
|
28
|
+
});
|
|
29
|
+
});
|
package/src/NavTreePlugin.tsx
CHANGED
|
@@ -12,10 +12,9 @@ import { type TreeData } from '@dxos/react-ui-list';
|
|
|
12
12
|
import { AppGraphBuilder, Keyboard, OperationHandler, ReactSurface, State } from '#capabilities';
|
|
13
13
|
import { NODE_TYPE } from '#containers';
|
|
14
14
|
import { meta } from '#meta';
|
|
15
|
+
import { translations } from '#translations';
|
|
15
16
|
import { NavTreeEvents } from '#types';
|
|
16
17
|
|
|
17
|
-
import { translations } from './translations';
|
|
18
|
-
|
|
19
18
|
export const NavTreePlugin = Plugin.define(meta).pipe(
|
|
20
19
|
AppPlugin.addAppGraphModule({ activate: AppGraphBuilder }),
|
|
21
20
|
AppPlugin.addMetadataModule({
|
|
@@ -41,7 +40,7 @@ export const NavTreePlugin = Plugin.define(meta).pipe(
|
|
|
41
40
|
Plugin.addModule({
|
|
42
41
|
id: 'state',
|
|
43
42
|
activatesOn: AppActivationEvents.LayoutReady,
|
|
44
|
-
|
|
43
|
+
firesAfterActivation: [NavTreeEvents.StateReady],
|
|
45
44
|
activate: State,
|
|
46
45
|
}),
|
|
47
46
|
Plugin.addModule({
|
|
@@ -74,3 +73,5 @@ export const NavTreePlugin = Plugin.define(meta).pipe(
|
|
|
74
73
|
}),
|
|
75
74
|
Plugin.make,
|
|
76
75
|
);
|
|
76
|
+
|
|
77
|
+
export default NavTreePlugin;
|
|
@@ -6,7 +6,7 @@ import * as Effect from 'effect/Effect';
|
|
|
6
6
|
|
|
7
7
|
import { Capability } from '@dxos/app-framework';
|
|
8
8
|
import { AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
|
|
9
|
-
import { Operation } from '@dxos/
|
|
9
|
+
import { Operation } from '@dxos/compute';
|
|
10
10
|
import { GraphBuilder, Node, NodeMatcher } from '@dxos/plugin-graph';
|
|
11
11
|
|
|
12
12
|
import { COMMANDS_DIALOG, meta } from '#meta';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Capability } from '@dxos/app-framework';
|
|
6
|
-
import { OperationHandlerSet } from '@dxos/
|
|
6
|
+
import { OperationHandlerSet } from '@dxos/compute';
|
|
7
7
|
|
|
8
8
|
export const AppGraphBuilder = Capability.lazy('AppGraphBuilder', () => import('./app-graph-builder'));
|
|
9
9
|
export const Keyboard = Capability.lazy('Keyboard', () => import('./keyboard'));
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as Effect from 'effect/Effect';
|
|
6
6
|
|
|
7
7
|
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
8
|
-
import type { OperationHandlerSet } from '@dxos/
|
|
8
|
+
import type { OperationHandlerSet } from '@dxos/compute';
|
|
9
9
|
|
|
10
10
|
import { NavTreeOperationHandlerSet } from '#operations';
|
|
11
11
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import * as Effect from 'effect/Effect';
|
|
6
|
-
import React from 'react';
|
|
6
|
+
import React, { type ComponentProps } from 'react';
|
|
7
7
|
|
|
8
8
|
import { Capabilities, Capability } from '@dxos/app-framework';
|
|
9
9
|
import { Surface } from '@dxos/app-framework/ui';
|
|
@@ -18,8 +18,7 @@ export default Capability.makeModule(() =>
|
|
|
18
18
|
Capability.contributes(Capabilities.ReactSurface, [
|
|
19
19
|
Surface.create({
|
|
20
20
|
id: COMMANDS_DIALOG,
|
|
21
|
-
|
|
22
|
-
filter: AppSurface.componentDialog(COMMANDS_DIALOG),
|
|
21
|
+
filter: AppSurface.component<ComponentProps<typeof CommandsDialogContent>>(AppSurface.Dialog, COMMANDS_DIALOG),
|
|
23
22
|
component: ({ data, ref }) => <CommandsDialogContent {...data.props} ref={ref} />,
|
|
24
23
|
}),
|
|
25
24
|
Surface.create({
|
|
@@ -16,7 +16,7 @@ import { type NavTreeCapabilities as NC, NavTreeCapabilities } from '#types';
|
|
|
16
16
|
const KEY = `${meta.id}.state.v1`;
|
|
17
17
|
|
|
18
18
|
/** Default item state for new entries. */
|
|
19
|
-
const defaultItemState: NC.NavTreeItemState = { open: false, current: false
|
|
19
|
+
const defaultItemState: NC.NavTreeItemState = { open: false, current: false };
|
|
20
20
|
|
|
21
21
|
/** L0 (top-level workspace) paths are direct children of root — not part of the expandable tree model. */
|
|
22
22
|
const isTopLevelPath = (path: string[]): boolean => path.length === 2 && path[0] === Node.RootId;
|
|
@@ -66,7 +66,7 @@ export default Capability.makeModule(
|
|
|
66
66
|
return registry.get(getItemAtom(path));
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
const setItem = (path: string[], key: 'open' | 'current'
|
|
69
|
+
const setItem = (path: string[], key: 'open' | 'current', next: boolean) => {
|
|
70
70
|
const pathString = Path.create(...path);
|
|
71
71
|
const atom = itemAtomFamily(pathString);
|
|
72
72
|
const currentValue = registry.get(atom);
|
|
@@ -12,7 +12,7 @@ import { Capabilities, Capability } from '@dxos/app-framework';
|
|
|
12
12
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
13
13
|
import { useAtomCapability } from '@dxos/app-framework/ui';
|
|
14
14
|
import { AppCapabilities, LayoutOperation } from '@dxos/app-toolkit';
|
|
15
|
-
import { Operation, OperationHandlerSet } from '@dxos/
|
|
15
|
+
import { Operation, OperationHandlerSet } from '@dxos/compute';
|
|
16
16
|
import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
|
|
17
17
|
import { random } from '@dxos/random';
|
|
18
18
|
import { IconButton, Input, Main, Toolbar } from '@dxos/react-ui';
|
|
@@ -23,9 +23,9 @@ import { mx } from '@dxos/ui-theme';
|
|
|
23
23
|
|
|
24
24
|
import { NavTreeContainer } from '#containers';
|
|
25
25
|
import { storybookGraphBuilders } from '#testing';
|
|
26
|
+
import { translations } from '#translations';
|
|
26
27
|
|
|
27
28
|
import { NavTreePlugin } from '../../NavTreePlugin';
|
|
28
|
-
import { translations } from '../../translations';
|
|
29
29
|
|
|
30
30
|
random.seed(1234);
|
|
31
31
|
|
|
@@ -113,7 +113,7 @@ export const NavTreeItemAction = ({
|
|
|
113
113
|
monolithic,
|
|
114
114
|
menuActions,
|
|
115
115
|
menuType,
|
|
116
|
-
parent
|
|
116
|
+
parent,
|
|
117
117
|
path,
|
|
118
118
|
...props
|
|
119
119
|
}: NavTreeItemActionMenuProps) => {
|
|
@@ -121,10 +121,9 @@ export const NavTreeItemAction = ({
|
|
|
121
121
|
|
|
122
122
|
const monolithicAction = menuActions?.length === 1 && menuActions[0];
|
|
123
123
|
const baseLabel = toLocalizedString(monolithicAction ? monolithicAction.properties!.label : props.label, t);
|
|
124
|
-
|
|
125
124
|
return monolithic && menuActions?.length === 1 ? (
|
|
126
|
-
<NavTreeItemMonolithicAction baseLabel={baseLabel} parent={
|
|
125
|
+
<NavTreeItemMonolithicAction baseLabel={baseLabel} parent={parent} path={path} {...menuActions[0]} />
|
|
127
126
|
) : (
|
|
128
|
-
<NavTreeItemActionDropdownMenu {...props} label={baseLabel} parent={
|
|
127
|
+
<NavTreeItemActionDropdownMenu {...props} label={baseLabel} parent={parent} path={path} menuActions={menuActions} />
|
|
129
128
|
);
|
|
130
129
|
};
|
|
@@ -2,22 +2,20 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import * as Effect from 'effect/Effect';
|
|
6
5
|
import * as Option from 'effect/Option';
|
|
7
6
|
import React, { memo, useCallback, useMemo } from 'react';
|
|
8
7
|
|
|
9
8
|
import { Node } from '@dxos/app-graph';
|
|
10
9
|
import { isPinnedWorkspace } from '@dxos/app-toolkit';
|
|
11
10
|
import { useAppGraph } from '@dxos/app-toolkit/ui';
|
|
12
|
-
import { Graph, useActionRunner,
|
|
11
|
+
import { Graph, useActionRunner, useEdges } from '@dxos/plugin-graph';
|
|
13
12
|
import { DensityProvider, IconButton, ScrollArea, toLocalizedString, useTranslation } from '@dxos/react-ui';
|
|
14
|
-
import { useAttended } from '@dxos/react-ui-attention';
|
|
15
13
|
import { Tree } from '@dxos/react-ui-list';
|
|
16
14
|
import { Menu, type MenuItem } from '@dxos/react-ui-menu';
|
|
17
15
|
import { Tabs } from '@dxos/react-ui-tabs';
|
|
18
16
|
import { hoverableControlItem, hoverableOpenControlItem } from '@dxos/ui-theme';
|
|
19
17
|
|
|
20
|
-
import { useActions,
|
|
18
|
+
import { useActions, useLoadDescendents } from '#hooks';
|
|
21
19
|
import { meta } from '#meta';
|
|
22
20
|
|
|
23
21
|
import { NAV_TREE_ITEM } from '../NavTree';
|
|
@@ -84,49 +82,27 @@ const useIsActivatedWorkspace = (item: Node.Node): boolean => {
|
|
|
84
82
|
const L1PanelContent = ({ path, item, onBack }: Pick<L1PanelProps, 'open' | 'path' | 'item' | 'onBack'>) => {
|
|
85
83
|
const navTreeContext = useNavTreeContext();
|
|
86
84
|
|
|
87
|
-
const alternateTree = useAlternateTreeItem(item);
|
|
88
|
-
const alternatePath = useMemo(() => [...path, item.id], [item.id, path]);
|
|
89
|
-
const isAlternate = useIsAlternateTree(alternatePath, item);
|
|
90
|
-
|
|
91
85
|
return (
|
|
92
86
|
<DensityProvider density='fine'>
|
|
93
87
|
<L1PanelHeader path={path} item={item} onBack={onBack} />
|
|
94
88
|
<ScrollArea.Root thin orientation='vertical'>
|
|
95
89
|
<ScrollArea.Viewport>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
) : (
|
|
113
|
-
<Tree
|
|
114
|
-
model={navTreeContext.model}
|
|
115
|
-
id={item.id}
|
|
116
|
-
rootId={item.id}
|
|
117
|
-
path={path}
|
|
118
|
-
levelOffset={5}
|
|
119
|
-
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
120
|
-
draggable
|
|
121
|
-
renderColumns={NavTreeItemColumns}
|
|
122
|
-
blockInstruction={navTreeContext.blockInstruction}
|
|
123
|
-
canDrop={navTreeContext.canDrop}
|
|
124
|
-
canSelect={navTreeContext.canSelect}
|
|
125
|
-
onOpenChange={navTreeContext.onOpenChange}
|
|
126
|
-
onSelect={navTreeContext.onSelect}
|
|
127
|
-
onItemHover={navTreeContext.onItemHover}
|
|
128
|
-
/>
|
|
129
|
-
)}
|
|
90
|
+
<Tree
|
|
91
|
+
model={navTreeContext.model}
|
|
92
|
+
id={item.id}
|
|
93
|
+
rootId={item.id}
|
|
94
|
+
path={path}
|
|
95
|
+
levelOffset={5}
|
|
96
|
+
gridTemplateColumns='[tree-row-start] 1fr min-content min-content min-content [tree-row-end]'
|
|
97
|
+
draggable
|
|
98
|
+
renderColumns={NavTreeItemColumns}
|
|
99
|
+
blockInstruction={navTreeContext.blockInstruction}
|
|
100
|
+
canDrop={navTreeContext.canDrop}
|
|
101
|
+
canSelect={navTreeContext.canSelect}
|
|
102
|
+
onOpenChange={navTreeContext.onOpenChange}
|
|
103
|
+
onSelect={navTreeContext.onSelect}
|
|
104
|
+
onItemHover={navTreeContext.onItemHover}
|
|
105
|
+
/>
|
|
130
106
|
</ScrollArea.Viewport>
|
|
131
107
|
</ScrollArea.Root>
|
|
132
108
|
</DensityProvider>
|
|
@@ -145,20 +121,6 @@ const L1PanelHeader = ({ item, path, onBack }: Pick<L1PanelProps, 'item' | 'path
|
|
|
145
121
|
const { primaryAction, groupedActions, menuActions, onAction } = useL1MenuActions({ item, path });
|
|
146
122
|
useLoadDescendents(item);
|
|
147
123
|
|
|
148
|
-
// TODO(wittjosiah): Hack to only show containsAttended when attended item is within alternate tree (e.g. settings).
|
|
149
|
-
// Since every object in the space is a descendant of the space node, we'd otherwise always show containsAttended.
|
|
150
|
-
const alternateTree = useAlternateTreeItem(item);
|
|
151
|
-
const attended = useAttended();
|
|
152
|
-
const alternateTreeOpen = useMemo(() => {
|
|
153
|
-
if (!alternateTree) {
|
|
154
|
-
return true;
|
|
155
|
-
}
|
|
156
|
-
const hasAlternateAttended = attended.some(
|
|
157
|
-
(attendedId) => attendedId === alternateTree.id || attendedId.startsWith(alternateTree.id + '/'),
|
|
158
|
-
);
|
|
159
|
-
return !hasAlternateAttended;
|
|
160
|
-
}, [alternateTree, attended]);
|
|
161
|
-
|
|
162
124
|
return (
|
|
163
125
|
<div
|
|
164
126
|
data-tauri-drag-region
|
|
@@ -196,115 +158,94 @@ const L1PanelHeader = ({ item, path, onBack }: Pick<L1PanelProps, 'item' | 'path
|
|
|
196
158
|
caller={NAV_TREE_ITEM}
|
|
197
159
|
/>
|
|
198
160
|
)}
|
|
199
|
-
{menuActions
|
|
200
|
-
|
|
201
|
-
density='coarse'
|
|
202
|
-
classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
203
|
-
variant='ghost'
|
|
204
|
-
icon={menuActions[0].properties?.icon ?? 'ph--placeholder--regular'}
|
|
205
|
-
iconOnly
|
|
206
|
-
label={toLocalizedString(menuActions[0].properties?.label, t)}
|
|
207
|
-
data-testid={menuActions[0].properties?.testId}
|
|
208
|
-
onClick={() => onAction(menuActions[0] as Node.Action)}
|
|
209
|
-
/>
|
|
210
|
-
)}
|
|
211
|
-
{menuActions.length > 1 && (
|
|
212
|
-
<Menu.Root caller={NAV_TREE_ITEM} onAction={onAction}>
|
|
213
|
-
<Menu.Trigger asChild>
|
|
214
|
-
<IconButton
|
|
215
|
-
density='coarse'
|
|
216
|
-
classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
217
|
-
variant='ghost'
|
|
218
|
-
icon='ph--dots-three-vertical--regular'
|
|
219
|
-
iconOnly
|
|
220
|
-
label={t('tree-item-actions.label')}
|
|
221
|
-
data-testid='navtree.treeItem.actionsLevel0'
|
|
222
|
-
/>
|
|
223
|
-
</Menu.Trigger>
|
|
224
|
-
<Menu.Content group={item} items={menuActions as MenuItem[]} />
|
|
225
|
-
</Menu.Root>
|
|
226
|
-
)}
|
|
227
|
-
{ItemEnd && <ItemEnd node={item} open={alternateTreeOpen} />}
|
|
161
|
+
<MenuActions item={item} menuActions={menuActions} onAction={onAction} />
|
|
162
|
+
{ItemEnd && <ItemEnd node={item} open />}
|
|
228
163
|
</div>
|
|
229
164
|
</div>
|
|
230
165
|
);
|
|
231
166
|
};
|
|
232
167
|
|
|
168
|
+
type L1MenuActions = {
|
|
169
|
+
primaryAction: Node.ActionLike;
|
|
170
|
+
groupedActions: Record<string, Node.Action[]>;
|
|
171
|
+
menuActions: Node.Action[];
|
|
172
|
+
onAction: (action: Node.Action, params?: Node.InvokeProps) => void;
|
|
173
|
+
};
|
|
174
|
+
|
|
233
175
|
/**
|
|
234
|
-
*
|
|
176
|
+
* Header menu actions for an L1 workspace tab. Renders nothing for an empty
|
|
177
|
+
* `menuActions`, a single inline icon button for one action, and a
|
|
178
|
+
* `…`-menu trigger for multiple.
|
|
235
179
|
*/
|
|
236
|
-
const
|
|
180
|
+
const MenuActions = ({
|
|
181
|
+
item,
|
|
182
|
+
menuActions,
|
|
183
|
+
onAction,
|
|
184
|
+
}: {
|
|
185
|
+
item: Node.Node;
|
|
186
|
+
} & Pick<L1MenuActions, 'menuActions' | 'onAction'>) => {
|
|
237
187
|
const { t } = useTranslation(meta.id);
|
|
238
|
-
const { setAlternateTree } = useNavTreeContext();
|
|
239
|
-
const { graph } = useAppGraph();
|
|
240
|
-
const runAction = useActionRunner();
|
|
241
188
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
189
|
+
if (menuActions.length === 0) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (menuActions.length === 1) {
|
|
194
|
+
return (
|
|
195
|
+
<IconButton
|
|
196
|
+
density='coarse'
|
|
197
|
+
classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
198
|
+
variant='ghost'
|
|
199
|
+
icon={menuActions[0].properties?.icon ?? 'ph--placeholder--regular'}
|
|
200
|
+
iconOnly
|
|
201
|
+
label={toLocalizedString(menuActions[0].properties?.label, t)}
|
|
202
|
+
data-testid={menuActions[0].properties?.testId}
|
|
203
|
+
onClick={() => onAction(menuActions[0] as Node.Action)}
|
|
204
|
+
/>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<Menu.Root caller={NAV_TREE_ITEM} onAction={onAction}>
|
|
210
|
+
<Menu.Trigger asChild>
|
|
211
|
+
<IconButton
|
|
212
|
+
density='coarse'
|
|
213
|
+
classNames={['shrink-0 px-2 pointer-fine:px-1', hoverableControlItem, hoverableOpenControlItem]}
|
|
214
|
+
variant='ghost'
|
|
215
|
+
icon='ph--dots-three-vertical--regular'
|
|
216
|
+
iconOnly
|
|
217
|
+
label={t('tree-item-actions.label')}
|
|
218
|
+
data-testid='navtree.treeItem.actionsLevel0'
|
|
219
|
+
/>
|
|
220
|
+
</Menu.Trigger>
|
|
221
|
+
<Menu.Content group={item} items={menuActions as MenuItem[]} />
|
|
222
|
+
</Menu.Root>
|
|
223
|
+
);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Builds the menu actions for the L1 panel header.
|
|
228
|
+
*/
|
|
229
|
+
const useL1MenuActions = ({ item, path }: Pick<L1PanelProps, 'item' | 'path'>): L1MenuActions => {
|
|
230
|
+
const runAction = useActionRunner();
|
|
245
231
|
|
|
246
|
-
// Graph actions.
|
|
247
232
|
const { actions: actionsProp, groupedActions } = useActions(item);
|
|
248
233
|
const [primaryAction, ...secondaryActions] = actionsProp.toSorted((a, _b) =>
|
|
249
234
|
a.properties?.disposition === 'list-item-primary' ? -1 : 1,
|
|
250
235
|
);
|
|
251
236
|
|
|
252
|
-
const
|
|
253
|
-
primaryAction?.properties?.disposition === 'list-item-primary' ? secondaryActions : actionsProp
|
|
254
|
-
)
|
|
237
|
+
const menuActions = (primaryAction?.properties?.disposition === 'list-item-primary' ? secondaryActions : actionsProp)
|
|
255
238
|
.flatMap((action) => (Node.isAction(action) ? [action] : []))
|
|
256
239
|
.filter((a) => ['list-item', 'list-item-primary'].includes(a.properties?.disposition));
|
|
257
240
|
|
|
258
|
-
// Synthetic settings/back action.
|
|
259
|
-
const settingsActionId = `${item.id}~settings`;
|
|
260
|
-
const settingsAction = useMemo((): Node.Action | undefined => {
|
|
261
|
-
if (!alternateTree) {
|
|
262
|
-
return undefined;
|
|
263
|
-
}
|
|
264
|
-
return {
|
|
265
|
-
id: settingsActionId,
|
|
266
|
-
type: Node.ActionType,
|
|
267
|
-
data: () => Effect.void,
|
|
268
|
-
properties: {
|
|
269
|
-
label: isAlternate
|
|
270
|
-
? ['button-back.button', { ns: meta.id }]
|
|
271
|
-
: (alternateTree.properties.label ?? alternateTree.id),
|
|
272
|
-
icon: isAlternate
|
|
273
|
-
? 'ph--arrow-u-down-left--regular'
|
|
274
|
-
: (alternateTree.properties.icon ?? 'ph--placeholder--regular'),
|
|
275
|
-
disposition: 'list-item',
|
|
276
|
-
testId: isAlternate ? 'navtree.backToSpace' : 'navtree.spaceSettings',
|
|
277
|
-
},
|
|
278
|
-
} as Node.Action;
|
|
279
|
-
}, [alternateTree, isAlternate, settingsActionId, t]);
|
|
280
|
-
|
|
281
|
-
const menuActions = useMemo(
|
|
282
|
-
() => [...graphMenuActions, ...(settingsAction ? [settingsAction] : [])],
|
|
283
|
-
[graphMenuActions, settingsAction],
|
|
284
|
-
);
|
|
285
|
-
|
|
286
241
|
const onAction = useCallback(
|
|
287
242
|
(action: Node.Action, params?: Node.InvokeProps) => {
|
|
288
|
-
|
|
289
|
-
if (alternateTree && !isAlternate) {
|
|
290
|
-
Graph.expand(graph, alternateTree.id, 'child');
|
|
291
|
-
}
|
|
292
|
-
setAlternateTree?.(alternatePath, !isAlternate);
|
|
293
|
-
} else {
|
|
294
|
-
void runAction(action, { ...params, path });
|
|
295
|
-
}
|
|
243
|
+
void runAction(action, { ...params, path });
|
|
296
244
|
},
|
|
297
|
-
[
|
|
245
|
+
[runAction, path],
|
|
298
246
|
);
|
|
299
247
|
|
|
300
248
|
return { primaryAction, groupedActions, menuActions, onAction };
|
|
301
249
|
};
|
|
302
250
|
|
|
303
|
-
/** Finds the first child with disposition 'alternate-tree' using graph connections directly. */
|
|
304
|
-
const useAlternateTreeItem = (item: Node.Node): Node.Node | undefined => {
|
|
305
|
-
const { graph } = useAppGraph();
|
|
306
|
-
const connections = useConnections(graph, item.id, 'child');
|
|
307
|
-
return connections.find((node) => node.properties.disposition === 'alternate-tree');
|
|
308
|
-
};
|
|
309
|
-
|
|
310
251
|
export const L1Panel = memo(L1Panel$);
|
package/src/components/types.ts
CHANGED
|
@@ -16,7 +16,6 @@ export type NavTreeContextValue = {
|
|
|
16
16
|
model: TreeModel<NavTreeItemGraphNode>;
|
|
17
17
|
popoverAnchorId?: string;
|
|
18
18
|
renderItemEnd?: FC<{ node: Node.Node; open: boolean }>;
|
|
19
|
-
setAlternateTree?: (path: string[], open: boolean) => void;
|
|
20
19
|
onTabChange?: (node: NavTreeItemGraphNode) => void;
|
|
21
20
|
} & Pick<
|
|
22
21
|
TreeProps<NavTreeItemGraphNode>,
|
|
@@ -10,8 +10,9 @@ import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
|
|
|
10
10
|
import { Dialog } from '@dxos/react-ui';
|
|
11
11
|
import { withLayout } from '@dxos/react-ui/testing';
|
|
12
12
|
|
|
13
|
+
import { translations } from '#translations';
|
|
14
|
+
|
|
13
15
|
import { NavTreePlugin } from '../../NavTreePlugin';
|
|
14
|
-
import { translations } from '../../translations';
|
|
15
16
|
import { CommandsDialogContent } from './CommandsDialogContent';
|
|
16
17
|
|
|
17
18
|
const DefaultStory = () => (
|