@dxos/plugin-explorer 0.9.1-main.c7dcc2e112 → 0.10.0
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/neutral/ExplorerArticle-2WPXYTXV.mjs +101 -0
- package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs.map +7 -0
- package/dist/lib/neutral/ExplorerPlugin.mjs +1 -1
- package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs +90 -0
- package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs.map +7 -0
- package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs +37 -0
- package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +4 -2
- package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
- package/dist/lib/neutral/{chunk-JXYIG54N.mjs → chunk-4F6AT7RA.mjs} +4 -2
- package/dist/lib/neutral/chunk-4F6AT7RA.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7XUDLV6E.mjs → chunk-EZ52JY7X.mjs} +34 -31
- package/dist/lib/neutral/chunk-EZ52JY7X.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-YBCHBVCJ.mjs → chunk-TTFPTHAQ.mjs} +8 -8
- package/dist/lib/neutral/chunk-TTFPTHAQ.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +430 -506
- package/dist/lib/neutral/components/index.mjs.map +4 -4
- package/dist/lib/neutral/containers/index.mjs +4 -2
- package/dist/lib/neutral/containers/index.mjs.map +3 -3
- package/dist/lib/neutral/{create-object-F6TKVAGV.mjs → create-object-WKIN3OB6.mjs} +3 -4
- package/dist/lib/neutral/{create-object-F6TKVAGV.mjs.map → create-object-WKIN3OB6.mjs.map} +3 -3
- package/dist/lib/neutral/hooks/index.mjs +64 -1
- package/dist/lib/neutral/hooks/index.mjs.map +4 -4
- package/dist/lib/neutral/index.mjs +1 -1
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs +39 -0
- package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs.map +7 -0
- package/dist/lib/neutral/testing/index.mjs +2 -2
- package/dist/lib/neutral/testing/index.mjs.map +2 -2
- package/dist/lib/neutral/translations.mjs +4 -1
- package/dist/lib/neutral/translations.mjs.map +2 -2
- package/dist/lib/neutral/types/index.mjs +1 -1
- package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +9 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/create-object.d.ts +1 -7
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +1 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/components/Lattice/Lattice.d.ts +1 -1
- package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -1
- package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +1 -1
- package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/index.d.ts +1 -3
- package/dist/types/src/components/Tree/index.d.ts.map +1 -1
- package/dist/types/src/components/Tree/types/tree.d.ts +10 -27
- package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/types/types.d.ts +1 -10
- package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
- package/dist/types/src/components/Visualization/Visualization.d.ts +39 -0
- package/dist/types/src/components/Visualization/Visualization.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/Visualization.stories.d.ts +13 -0
- package/dist/types/src/components/Visualization/Visualization.stories.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/index.d.ts +3 -0
- package/dist/types/src/components/Visualization/index.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/variants.d.ts +53 -0
- package/dist/types/src/components/Visualization/variants.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +2 -2
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts +14 -0
- package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts.map +1 -0
- package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts +2 -0
- package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +1 -0
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useNeighborhoodModel.d.ts +14 -0
- package/dist/types/src/hooks/useNeighborhoodModel.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +4 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/relations.d.ts +1 -2
- package/dist/types/src/testing/relations.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +6 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Graph.d.ts +6 -8
- package/dist/types/src/types/Graph.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +41 -37
- package/src/ExplorerPlugin.tsx +2 -1
- package/src/capabilities/app-graph-builder.ts +40 -0
- package/src/capabilities/create-object.ts +3 -2
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/react-surface.tsx +14 -4
- package/src/components/Lattice/Lattice.tsx +1 -2
- package/src/components/Tree/EdgeBundling.stories.tsx +5 -3
- package/src/components/Tree/Tree.stories.tsx +7 -2
- package/src/components/Tree/index.ts +3 -3
- package/src/components/Tree/types/tree.ts +6 -6
- package/src/components/Tree/types/types.ts +1 -11
- package/src/components/Visualization/Visualization.stories.tsx +104 -0
- package/src/components/Visualization/Visualization.tsx +209 -0
- package/src/components/Visualization/index.ts +6 -0
- package/src/components/Visualization/variants.ts +508 -0
- package/src/components/index.ts +1 -0
- package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +3 -3
- package/src/containers/ExplorerArticle/ExplorerArticle.tsx +7 -8
- package/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.tsx +102 -0
- package/src/containers/NeighborhoodCompanion/index.ts +5 -0
- package/src/containers/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useNeighborhoodModel.ts +81 -0
- package/src/testing/relations.ts +1 -3
- package/src/translations.ts +3 -0
- package/src/types/Graph.ts +18 -20
- package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs +0 -460
- package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7XUDLV6E.mjs.map +0 -7
- package/dist/lib/neutral/chunk-IKHJV3Q4.mjs +0 -20
- package/dist/lib/neutral/chunk-IKHJV3Q4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-JXYIG54N.mjs.map +0 -7
- package/dist/lib/neutral/chunk-YBCHBVCJ.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-APBW2VQG.mjs +0 -26
- package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +0 -7
- package/dist/types/src/components/Tree/Tree.d.ts +0 -24
- package/dist/types/src/components/Tree/Tree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +0 -40
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts +0 -37
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts +0 -26
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/hierarchy.d.ts +0 -17
- package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/index.d.ts +0 -6
- package/dist/types/src/components/Tree/layout/index.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/slots.d.ts +0 -7
- package/dist/types/src/components/Tree/layout/slots.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +0 -15
- package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +0 -1
- package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts +0 -18
- package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts.map +0 -1
- package/dist/types/src/containers/ExplorerArticle/variants.d.ts +0 -9
- package/dist/types/src/containers/ExplorerArticle/variants.d.ts.map +0 -1
- package/src/components/Tree/Tree.tsx +0 -81
- package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +0 -335
- package/src/components/Tree/layout/RadialTree.tsx +0 -242
- package/src/components/Tree/layout/TidyTree.tsx +0 -246
- package/src/components/Tree/layout/hierarchy.ts +0 -32
- package/src/components/Tree/layout/index.ts +0 -9
- package/src/components/Tree/layout/slots.ts +0 -19
- package/src/components/Tree/layout/useContainerSize.ts +0 -43
- package/src/containers/ExplorerArticle/Visualization.tsx +0 -523
- package/src/containers/ExplorerArticle/variants.ts +0 -47
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-explorer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Braneframe data visualization plugin",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -97,57 +97,61 @@
|
|
|
97
97
|
"dependencies": {
|
|
98
98
|
"@effect-atom/atom-react": "^0.5.0",
|
|
99
99
|
"@observablehq/plot": "^0.6.11",
|
|
100
|
+
"@radix-ui/react-context": "1.1.1",
|
|
101
|
+
"@radix-ui/react-slot": "1.1.2",
|
|
100
102
|
"d3": "^7.9.0",
|
|
101
|
-
"effect": "3.21.
|
|
103
|
+
"effect": "3.21.4",
|
|
102
104
|
"force-graph": "^1.49.4",
|
|
103
105
|
"react-resize-detector": "^11.0.1",
|
|
104
106
|
"topojson-client": "^3.1.0",
|
|
105
|
-
"@dxos/app-toolkit": "0.
|
|
106
|
-
"@dxos/
|
|
107
|
-
"@dxos/
|
|
108
|
-
"@dxos/
|
|
109
|
-
"@dxos/
|
|
110
|
-
"@dxos/
|
|
111
|
-
"@dxos/
|
|
112
|
-
"@dxos/
|
|
113
|
-
"@dxos/
|
|
114
|
-
"@dxos/
|
|
115
|
-
"@dxos/plugin-
|
|
116
|
-
"@dxos/
|
|
117
|
-
"@dxos/react-
|
|
118
|
-
"@dxos/react-ui-
|
|
119
|
-
"@dxos/react-ui-
|
|
120
|
-
"@dxos/
|
|
121
|
-
"@dxos/react-ui-
|
|
122
|
-
"@dxos/
|
|
123
|
-
"@dxos/
|
|
124
|
-
"@dxos/
|
|
107
|
+
"@dxos/app-toolkit": "0.10.0",
|
|
108
|
+
"@dxos/compute": "0.10.0",
|
|
109
|
+
"@dxos/echo": "0.10.0",
|
|
110
|
+
"@dxos/echo-query": "0.10.0",
|
|
111
|
+
"@dxos/graph": "0.10.0",
|
|
112
|
+
"@dxos/invariant": "0.10.0",
|
|
113
|
+
"@dxos/keys": "0.10.0",
|
|
114
|
+
"@dxos/app-framework": "0.10.0",
|
|
115
|
+
"@dxos/log": "0.10.0",
|
|
116
|
+
"@dxos/plugin-client": "0.10.0",
|
|
117
|
+
"@dxos/plugin-graph": "0.10.0",
|
|
118
|
+
"@dxos/plugin-space": "0.10.0",
|
|
119
|
+
"@dxos/react-client": "0.10.0",
|
|
120
|
+
"@dxos/react-ui-attention": "0.10.0",
|
|
121
|
+
"@dxos/react-ui-graph": "0.10.0",
|
|
122
|
+
"@dxos/react-ui-components": "0.10.0",
|
|
123
|
+
"@dxos/react-ui-mosaic": "0.10.0",
|
|
124
|
+
"@dxos/types": "0.10.0",
|
|
125
|
+
"@dxos/ui-types": "0.10.0",
|
|
126
|
+
"@dxos/schema": "0.10.0",
|
|
127
|
+
"@dxos/client": "0.10.0",
|
|
128
|
+
"@dxos/util": "0.10.0"
|
|
125
129
|
},
|
|
126
130
|
"devDependencies": {
|
|
127
131
|
"@types/d3": "^7.4.3",
|
|
128
132
|
"@types/d3-hierarchy": "^3.1.6",
|
|
129
133
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
130
|
-
"@types/react": "~19.2.
|
|
134
|
+
"@types/react": "~19.2.17",
|
|
131
135
|
"@types/react-dom": "~19.2.3",
|
|
132
136
|
"@types/topojson-client": "^3.1.4",
|
|
133
137
|
"@types/topojson-specification": "^1.0.5",
|
|
134
|
-
"react": "~19.2.
|
|
135
|
-
"react-dom": "~19.2.
|
|
138
|
+
"react": "~19.2.7",
|
|
139
|
+
"react-dom": "~19.2.7",
|
|
136
140
|
"vite": "^8.0.16",
|
|
137
|
-
"@dxos/echo-generator": "0.
|
|
138
|
-
"@dxos/plugin-preview": "0.
|
|
139
|
-
"@dxos/plugin-testing": "0.
|
|
140
|
-
"@dxos/
|
|
141
|
-
"@dxos/
|
|
142
|
-
"@dxos/ui-theme": "0.
|
|
143
|
-
"@dxos/storybook-utils": "0.
|
|
141
|
+
"@dxos/echo-generator": "0.10.0",
|
|
142
|
+
"@dxos/plugin-preview": "0.10.0",
|
|
143
|
+
"@dxos/plugin-testing": "0.10.0",
|
|
144
|
+
"@dxos/random": "0.10.0",
|
|
145
|
+
"@dxos/react-ui": "0.10.0",
|
|
146
|
+
"@dxos/ui-theme": "0.10.0",
|
|
147
|
+
"@dxos/storybook-utils": "0.10.0"
|
|
144
148
|
},
|
|
145
149
|
"peerDependencies": {
|
|
146
|
-
"effect": "3.21.
|
|
147
|
-
"react": "~19.2.
|
|
148
|
-
"react-dom": "~19.2.
|
|
149
|
-
"@dxos/react-ui": "0.
|
|
150
|
-
"@dxos/ui-theme": "0.
|
|
150
|
+
"effect": "3.21.4",
|
|
151
|
+
"react": "~19.2.7",
|
|
152
|
+
"react-dom": "~19.2.7",
|
|
153
|
+
"@dxos/react-ui": "0.10.0",
|
|
154
|
+
"@dxos/ui-theme": "0.10.0"
|
|
151
155
|
},
|
|
152
156
|
"publishConfig": {
|
|
153
157
|
"access": "public"
|
package/src/ExplorerPlugin.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Plugin } from '@dxos/app-framework';
|
|
6
6
|
import { AppPlugin } from '@dxos/app-toolkit';
|
|
7
7
|
|
|
8
|
-
import { CreateObject, ReactSurface } from '#capabilities';
|
|
8
|
+
import { AppGraphBuilder, CreateObject, ReactSurface } from '#capabilities';
|
|
9
9
|
import { meta } from '#meta';
|
|
10
10
|
import { translations } from '#translations';
|
|
11
11
|
import { Graph } from '#types';
|
|
@@ -15,6 +15,7 @@ import pluginSpec from '../PLUGIN.mdl?raw';
|
|
|
15
15
|
|
|
16
16
|
export const ExplorerPlugin = Plugin.define(meta).pipe(
|
|
17
17
|
AppPlugin.addCreateObjectModule({ activate: CreateObject }),
|
|
18
|
+
AppPlugin.addAppGraphModule({ activate: AppGraphBuilder }),
|
|
18
19
|
AppPlugin.addSchemaModule({ schema: [Graph.Graph] }),
|
|
19
20
|
AppPlugin.addSurfaceModule({ activate: ReactSurface }),
|
|
20
21
|
AppPlugin.addTranslationsModule({ translations }),
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import { Capability } from '@dxos/app-framework';
|
|
8
|
+
import { AppCapabilities, AppNode } from '@dxos/app-toolkit';
|
|
9
|
+
import { GraphBuilder, NodeMatcher } from '@dxos/plugin-graph';
|
|
10
|
+
import { linkedSegment } from '@dxos/react-ui-attention';
|
|
11
|
+
import { Position } from '@dxos/util';
|
|
12
|
+
|
|
13
|
+
import { meta } from '#meta';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Offers a "Neighborhood" companion on any ECHO object. The matched node is passed through as the
|
|
17
|
+
* companion's `companionTo` (the active node), which the surface renders as an ego-centric graph.
|
|
18
|
+
*/
|
|
19
|
+
export default Capability.makeModule(
|
|
20
|
+
Effect.fnUntraced(function* () {
|
|
21
|
+
const extensions = yield* Effect.all([
|
|
22
|
+
GraphBuilder.createExtension({
|
|
23
|
+
id: 'neighborhoodCompanion',
|
|
24
|
+
match: NodeMatcher.whenEchoObjectMatches,
|
|
25
|
+
connector: () =>
|
|
26
|
+
Effect.succeed([
|
|
27
|
+
AppNode.makeCompanion({
|
|
28
|
+
id: linkedSegment('neighborhood'),
|
|
29
|
+
label: ['neighborhood-companion.label', { ns: meta.profile.key }],
|
|
30
|
+
icon: 'ph--share-network--regular',
|
|
31
|
+
data: 'neighborhood',
|
|
32
|
+
position: Position.last,
|
|
33
|
+
}),
|
|
34
|
+
]),
|
|
35
|
+
}),
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
return Capability.contributes(AppCapabilities.AppGraphBuilder, extensions);
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
@@ -21,13 +21,14 @@ export default Capability.makeModule(
|
|
|
21
21
|
createObject: (props, options) =>
|
|
22
22
|
Effect.gen(function* () {
|
|
23
23
|
const object = yield* Effect.promise(async () => {
|
|
24
|
-
const
|
|
24
|
+
const view = props.typename
|
|
25
|
+
? (await ViewModel.makeFromDatabase({ db: options.db, typename: props.typename })).view
|
|
26
|
+
: undefined;
|
|
25
27
|
return Graph.make({ name: props.name, view });
|
|
26
28
|
});
|
|
27
29
|
return yield* Operation.invoke(SpaceOperation.AddObject, {
|
|
28
30
|
object,
|
|
29
31
|
target: options.target,
|
|
30
|
-
hidden: true,
|
|
31
32
|
targetNodeId: options.targetNodeId,
|
|
32
33
|
});
|
|
33
34
|
}),
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { Capability } from '@dxos/app-framework';
|
|
6
6
|
|
|
7
|
+
export const AppGraphBuilder = Capability.lazy('AppGraphBuilder', () => import('./app-graph-builder'));
|
|
7
8
|
export const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));
|
|
8
9
|
export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
|
|
@@ -9,13 +9,12 @@ import { Capabilities, Capability } from '@dxos/app-framework';
|
|
|
9
9
|
import { Surface } from '@dxos/app-framework/ui';
|
|
10
10
|
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
11
11
|
|
|
12
|
-
import { ExplorerArticle } from '#containers';
|
|
12
|
+
import { ExplorerArticle, NeighborhoodCompanion } from '#containers';
|
|
13
13
|
import { Graph } from '#types';
|
|
14
14
|
|
|
15
15
|
export default Capability.makeModule(() =>
|
|
16
16
|
Effect.succeed(
|
|
17
|
-
Capability.contributes(
|
|
18
|
-
Capabilities.ReactSurface,
|
|
17
|
+
Capability.contributes(Capabilities.ReactSurface, [
|
|
19
18
|
Surface.create({
|
|
20
19
|
id: 'article',
|
|
21
20
|
// TODO(wittjosiah): Split into multiple surfaces if this filter proves too strict for non-article roles.
|
|
@@ -27,6 +26,17 @@ export default Capability.makeModule(() =>
|
|
|
27
26
|
return <ExplorerArticle role={role} subject={data.subject} attendableId={data.attendableId} />;
|
|
28
27
|
},
|
|
29
28
|
}),
|
|
30
|
-
|
|
29
|
+
// Neighborhood companion offered on any ECHO object; `companionTo` is the active node.
|
|
30
|
+
Surface.create({
|
|
31
|
+
id: 'neighborhood',
|
|
32
|
+
filter: AppSurface.allOf(
|
|
33
|
+
AppSurface.literal(AppSurface.Article, 'neighborhood'),
|
|
34
|
+
AppSurface.companion(AppSurface.Article),
|
|
35
|
+
),
|
|
36
|
+
component: ({ data, role }) => {
|
|
37
|
+
return <NeighborhoodCompanion role={role} subject={data.companionTo} />;
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
]),
|
|
31
41
|
),
|
|
32
42
|
);
|
|
@@ -6,11 +6,10 @@ import { select } from 'd3';
|
|
|
6
6
|
import React, { useEffect, useMemo, useRef } from 'react';
|
|
7
7
|
|
|
8
8
|
import { Obj } from '@dxos/echo';
|
|
9
|
+
import { type TreeNode, useContainerSize } from '@dxos/react-ui-graph';
|
|
9
10
|
import { type SpaceGraphNode } from '@dxos/schema';
|
|
10
11
|
|
|
11
12
|
import { getNodeFillForObject } from '../../util/node-color';
|
|
12
|
-
import { useContainerSize } from '../Tree/layout/useContainerSize';
|
|
13
|
-
import { type TreeNode } from '../Tree/types';
|
|
14
13
|
|
|
15
14
|
const TRANSITION_MS = 350;
|
|
16
15
|
|
|
@@ -7,18 +7,18 @@ import * as Effect from 'effect/Effect';
|
|
|
7
7
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
8
8
|
|
|
9
9
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
10
|
-
import { Query } from '@dxos/echo';
|
|
10
|
+
import { type Obj, Query } from '@dxos/echo';
|
|
11
11
|
import { ClientPlugin, initializeIdentity } from '@dxos/plugin-client/testing';
|
|
12
12
|
import { corePlugins } from '@dxos/plugin-testing';
|
|
13
13
|
import { random } from '@dxos/random';
|
|
14
14
|
import { useSpaces } from '@dxos/react-client/echo';
|
|
15
|
+
import { Tree, type TreeComponentProps, type TreeNode } from '@dxos/react-ui-graph';
|
|
15
16
|
import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
16
17
|
import { type ValueGenerator } from '@dxos/schema/testing';
|
|
17
18
|
import { HasConnection, Organization, Person } from '@dxos/types';
|
|
18
19
|
|
|
19
20
|
import { buildOrgHierarchy, connectionsToEdges, generateConnectedOrgs } from '../../testing';
|
|
20
|
-
import {
|
|
21
|
-
import { type TreeNode } from './types';
|
|
21
|
+
import { getNodeFillForObject } from '../../util';
|
|
22
22
|
|
|
23
23
|
const generator = random as any as ValueGenerator;
|
|
24
24
|
|
|
@@ -61,6 +61,8 @@ const DefaultStory = ({ variant = 'edge', tension }: { variant?: TreeComponentPr
|
|
|
61
61
|
node: 'fill-neutral-700 dark:fill-neutral-300',
|
|
62
62
|
path: 'stroke-orange-400/40 dark:stroke-orange-500/40',
|
|
63
63
|
text: 'fill-neutral-700 dark:fill-neutral-200 text-xs',
|
|
64
|
+
// Boundary cast: the generic node `data` is an ECHO object here (carried opaquely by the renderer).
|
|
65
|
+
nodeFill: (data: unknown) => getNodeFillForObject(data as Obj.Unknown | undefined),
|
|
64
66
|
}),
|
|
65
67
|
[],
|
|
66
68
|
);
|
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
import React, { useMemo } from 'react';
|
|
7
7
|
|
|
8
|
+
import { type Obj } from '@dxos/echo';
|
|
8
9
|
import { random } from '@dxos/random';
|
|
10
|
+
import { Tree, type TreeComponentProps } from '@dxos/react-ui-graph';
|
|
9
11
|
import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
10
12
|
|
|
11
13
|
import { createTree } from '../../testing';
|
|
12
|
-
import {
|
|
14
|
+
import { getNodeFillForObject } from '../../util';
|
|
13
15
|
import { treeTypeToTreeNode } from './types';
|
|
14
16
|
|
|
15
17
|
random.seed(1);
|
|
@@ -22,7 +24,10 @@ const DefaultStory = ({ variant }: StoryArgs) => {
|
|
|
22
24
|
return <Loading />;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
// Inject the ECHO-aware leaf fill (radial/edge variants) now that the renderer is domain-agnostic.
|
|
28
|
+
// Boundary cast: the generic node `data` is an ECHO object here (the renderer carries it opaquely).
|
|
29
|
+
const slots = { nodeFill: (data: unknown) => getNodeFillForObject(data as Obj.Unknown | undefined) };
|
|
30
|
+
return <Tree data={data} variant={variant} slots={slots} />;
|
|
26
31
|
};
|
|
27
32
|
|
|
28
33
|
const meta: Meta<StoryArgs> = {
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
5
|
+
// The Tree renderer + layouts moved to @dxos/react-ui-graph; this keeps the ECHO `TreeType` schema
|
|
6
|
+
// and the `treeTypeToTreeNode` converter that adapt plugin-explorer data to the renderer.
|
|
7
|
+
export * from './types';
|
|
@@ -19,12 +19,12 @@ export const TreeNodeType = Schema.Struct({
|
|
|
19
19
|
|
|
20
20
|
export type TreeNodeType = Schema.Schema.Type<typeof TreeNodeType>;
|
|
21
21
|
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
export class TreeType extends Type.makeObject<TreeType>(DXN.make('org.dxos.type.tree', '0.1.0'))(
|
|
23
|
+
Schema.Struct({
|
|
24
|
+
root: Key.EntityId,
|
|
25
|
+
nodes: Schema.mutable(Schema.Record({ key: Key.EntityId, value: TreeNodeType })),
|
|
26
|
+
}),
|
|
27
|
+
) {}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Wrapper object for tree.
|
|
@@ -3,20 +3,10 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Key } from '@dxos/echo';
|
|
6
|
+
import { type TreeNode } from '@dxos/react-ui-graph';
|
|
6
7
|
|
|
7
8
|
import { type TreeType } from './tree';
|
|
8
9
|
|
|
9
|
-
/**
|
|
10
|
-
* In-memory tree shape used by the d3 layouts.
|
|
11
|
-
* `data` carries through to layout callbacks (e.g. hover/inspect) — typically an ECHO object on leaves.
|
|
12
|
-
*/
|
|
13
|
-
export type TreeNode<TData = unknown> = {
|
|
14
|
-
id: string;
|
|
15
|
-
label?: string;
|
|
16
|
-
data?: TData;
|
|
17
|
-
children?: TreeNode<TData>[];
|
|
18
|
-
};
|
|
19
|
-
|
|
20
10
|
/**
|
|
21
11
|
* Convert an ECHO `TreeType` (id-keyed node map) into a nested `TreeNode` hierarchy.
|
|
22
12
|
* Returns `undefined` if the root id is missing — the tree is then incomplete and shouldn't render.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Registry } from '@effect-atom/atom-react';
|
|
6
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
|
+
import React, { useMemo } from 'react';
|
|
8
|
+
|
|
9
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
10
|
+
import { type SpaceGraphEdge, SpaceGraphModel, type SpaceGraphNode } from '@dxos/schema';
|
|
11
|
+
import '@dxos/react-ui-graph/styles/graph.css';
|
|
12
|
+
|
|
13
|
+
import { type VisualizationVariantId } from './variants';
|
|
14
|
+
import { Visualization } from './Visualization';
|
|
15
|
+
|
|
16
|
+
// Synthetic neighbourhood: inbound sources → focus (left), focus → near → far (right, outgoing).
|
|
17
|
+
const NODES: SpaceGraphNode[] = [
|
|
18
|
+
{ id: 'focus', type: 'object', data: { label: 'Focus' } },
|
|
19
|
+
...Array.from(
|
|
20
|
+
{ length: 3 },
|
|
21
|
+
(_, index): SpaceGraphNode => ({
|
|
22
|
+
id: `src-${index}`,
|
|
23
|
+
type: 'object',
|
|
24
|
+
data: { label: `Source ${index}` },
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
...Array.from(
|
|
28
|
+
{ length: 5 },
|
|
29
|
+
(_, index): SpaceGraphNode => ({
|
|
30
|
+
id: `near-${index}`,
|
|
31
|
+
type: 'object',
|
|
32
|
+
data: { label: `Near ${index}` },
|
|
33
|
+
}),
|
|
34
|
+
),
|
|
35
|
+
...Array.from(
|
|
36
|
+
{ length: 8 },
|
|
37
|
+
(_, index): SpaceGraphNode => ({
|
|
38
|
+
id: `far-${index}`,
|
|
39
|
+
type: 'object',
|
|
40
|
+
data: { label: `Far ${index}` },
|
|
41
|
+
}),
|
|
42
|
+
),
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const EDGES: SpaceGraphEdge[] = [
|
|
46
|
+
// Inbound: sources point at the focus (left side, terminal).
|
|
47
|
+
...Array.from(
|
|
48
|
+
{ length: 3 },
|
|
49
|
+
(_, index): SpaceGraphEdge => ({
|
|
50
|
+
id: `e-src-focus-${index}`,
|
|
51
|
+
type: 'ref',
|
|
52
|
+
source: `src-${index}`,
|
|
53
|
+
target: 'focus',
|
|
54
|
+
data: { force: true },
|
|
55
|
+
}),
|
|
56
|
+
),
|
|
57
|
+
// Outgoing: focus → near → far (right side, explored).
|
|
58
|
+
...Array.from(
|
|
59
|
+
{ length: 5 },
|
|
60
|
+
(_, index): SpaceGraphEdge => ({
|
|
61
|
+
id: `e-focus-near-${index}`,
|
|
62
|
+
type: 'ref',
|
|
63
|
+
source: 'focus',
|
|
64
|
+
target: `near-${index}`,
|
|
65
|
+
data: { force: true },
|
|
66
|
+
}),
|
|
67
|
+
),
|
|
68
|
+
...Array.from(
|
|
69
|
+
{ length: 8 },
|
|
70
|
+
(_, index): SpaceGraphEdge => ({
|
|
71
|
+
id: `e-near-far-${index}`,
|
|
72
|
+
type: 'ref',
|
|
73
|
+
source: `near-${index % 5}`,
|
|
74
|
+
target: `far-${index}`,
|
|
75
|
+
data: { force: true },
|
|
76
|
+
}),
|
|
77
|
+
),
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
type StoryArgs = { variant: VisualizationVariantId; focus?: string };
|
|
81
|
+
|
|
82
|
+
const DefaultStory = ({ variant, focus }: StoryArgs) => {
|
|
83
|
+
const model = useMemo(() => new SpaceGraphModel(Registry.make(), { nodes: NODES, edges: EDGES }), []);
|
|
84
|
+
return (
|
|
85
|
+
<Visualization.Root classNames='bg-base-surface' model={model} variant={variant} focus={focus}>
|
|
86
|
+
<Visualization.Graph debug={false} />
|
|
87
|
+
</Visualization.Root>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const meta: Meta<StoryArgs> = {
|
|
92
|
+
title: 'plugins/plugin-explorer/components/Visualization',
|
|
93
|
+
render: DefaultStory,
|
|
94
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
95
|
+
parameters: { layout: 'fullscreen' },
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default meta;
|
|
99
|
+
|
|
100
|
+
type Story = StoryObj<typeof meta>;
|
|
101
|
+
|
|
102
|
+
export const Force: Story = { args: { variant: 'force' } };
|
|
103
|
+
|
|
104
|
+
export const Neighborhood: Story = { args: { variant: 'neighborhood', focus: 'focus' } };
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createContext } from '@radix-ui/react-context';
|
|
6
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
7
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { composableProps, slottable } from '@dxos/react-ui';
|
|
10
|
+
import {
|
|
11
|
+
type GraphLayout,
|
|
12
|
+
type GraphLayoutNode,
|
|
13
|
+
type GraphProjector,
|
|
14
|
+
GraphSwarmProjector,
|
|
15
|
+
type ModelPoint,
|
|
16
|
+
SVG,
|
|
17
|
+
type SVGContext,
|
|
18
|
+
type TreeNode,
|
|
19
|
+
} from '@dxos/react-ui-graph';
|
|
20
|
+
import { type SpaceGraphEdge, type SpaceGraphModel, type SpaceGraphNode } from '@dxos/schema';
|
|
21
|
+
import { type SlottableProps } from '@dxos/ui-types';
|
|
22
|
+
|
|
23
|
+
import { type VisualizationVariant, type VisualizationVariantId, getVariant } from './variants';
|
|
24
|
+
|
|
25
|
+
//
|
|
26
|
+
// Context
|
|
27
|
+
//
|
|
28
|
+
|
|
29
|
+
type VisualizationContextValue = {
|
|
30
|
+
model: SpaceGraphModel;
|
|
31
|
+
variant: VisualizationVariant;
|
|
32
|
+
/** Externally-supplied focus (ego centre); overrides click-driven focus when set. */
|
|
33
|
+
focus?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const [VisualizationProvider, useVisualizationContext] = createContext<VisualizationContextValue>('Visualization.Root');
|
|
37
|
+
|
|
38
|
+
//
|
|
39
|
+
// Root
|
|
40
|
+
//
|
|
41
|
+
|
|
42
|
+
export type VisualizationRootProps = SlottableProps<{
|
|
43
|
+
model: SpaceGraphModel;
|
|
44
|
+
variant: VisualizationVariantId;
|
|
45
|
+
/** Focus node id placed at the centre of ego/plexus layouts (e.g. the active node for the companion). */
|
|
46
|
+
focus?: string;
|
|
47
|
+
/** Called when the user clicks the visualization surface (e.g. to dismiss a node preview). */
|
|
48
|
+
onSurfaceClick?: () => void;
|
|
49
|
+
}>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Surface for a visualization. Resolves the variant definition and shares it (plus the model and
|
|
53
|
+
* focus) with the child `Visualization.Graph` via context, so the variant string is set in one
|
|
54
|
+
* place. The surface element is slottable via `asChild` for composition into a host layout.
|
|
55
|
+
*/
|
|
56
|
+
const VisualizationRoot = slottable<
|
|
57
|
+
HTMLDivElement,
|
|
58
|
+
{ model: SpaceGraphModel; variant: VisualizationVariantId; focus?: string; onSurfaceClick?: () => void }
|
|
59
|
+
>(({ children, asChild, model, variant, focus, onSurfaceClick, ...props }, forwardedRef) => {
|
|
60
|
+
const { className, ...rest } = composableProps(props, { classNames: 'dx-expander relative' });
|
|
61
|
+
const Comp = asChild ? Slot : 'div';
|
|
62
|
+
return (
|
|
63
|
+
<VisualizationProvider model={model} variant={getVariant(variant)} focus={focus}>
|
|
64
|
+
<Comp {...rest} className={className} onClick={onSurfaceClick} ref={forwardedRef}>
|
|
65
|
+
{children}
|
|
66
|
+
</Comp>
|
|
67
|
+
</VisualizationProvider>
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
VisualizationRoot.displayName = 'Visualization.Root';
|
|
72
|
+
|
|
73
|
+
//
|
|
74
|
+
// Graph
|
|
75
|
+
//
|
|
76
|
+
|
|
77
|
+
export type VisualizationGraphProps = {
|
|
78
|
+
debug?: boolean;
|
|
79
|
+
onNodeHover?: (node: TreeNode | null, event?: MouseEvent) => void;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Renders the active variant's projector + node renderer into a zoomable SVG surface. Reads the
|
|
84
|
+
* model, variant definition, and focus from `Visualization.Root` context; owns the live projector,
|
|
85
|
+
* click-driven focus, and the layout snapshot that lets each variant swap animate from prior positions.
|
|
86
|
+
*/
|
|
87
|
+
const VisualizationGraph = ({ debug = false, onNodeHover }: VisualizationGraphProps) => {
|
|
88
|
+
const { model, variant, focus } = useVisualizationContext('Visualization.Graph');
|
|
89
|
+
|
|
90
|
+
const svgRef = useRef<SVGContext>(null);
|
|
91
|
+
const [projector, setProjector] = useState<GraphProjector<SpaceGraphNode> | undefined>();
|
|
92
|
+
const projectorRef = useRef<GraphProjector<SpaceGraphNode> | undefined>(undefined);
|
|
93
|
+
projectorRef.current = projector;
|
|
94
|
+
|
|
95
|
+
// Click-driven focus for focusable variants (plexus). `undefined` means "no node focused".
|
|
96
|
+
const [clickFocusId, setClickFocusId] = useState<string | undefined>(undefined);
|
|
97
|
+
|
|
98
|
+
// Externally-supplied focus (e.g. the active node for the neighborhood companion) wins; otherwise
|
|
99
|
+
// the click-driven focus drives focusable variants.
|
|
100
|
+
const focusId = focus ?? clickFocusId;
|
|
101
|
+
|
|
102
|
+
// Latest layout we hand to the next SVG projector as `prev`. Captured from the live
|
|
103
|
+
// projector when the variant changes so node x/y survive the swap.
|
|
104
|
+
const lastLayoutRef = useRef<GraphLayout<SpaceGraphNode> | undefined>(undefined);
|
|
105
|
+
|
|
106
|
+
// Subscribe to the graph atom — keeps it alive across child unmounts (effect-atom
|
|
107
|
+
// disposes atoms with no subscribers) and triggers re-renders when query results land.
|
|
108
|
+
useEffect(() => model?.subscribe(() => undefined), [model]);
|
|
109
|
+
|
|
110
|
+
// Clear any click focus when leaving a focusable variant so returning starts from the bundle layout.
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (!variant.focusable) {
|
|
113
|
+
setClickFocusId(undefined);
|
|
114
|
+
}
|
|
115
|
+
}, [variant]);
|
|
116
|
+
|
|
117
|
+
// Recreate the projector when the variant or focus changes; snapshot the live layout
|
|
118
|
+
// first so the next projector animates from where the previous one left off.
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (projectorRef.current?.layout) {
|
|
121
|
+
lastLayoutRef.current = projectorRef.current.layout as GraphLayout<SpaceGraphNode>;
|
|
122
|
+
}
|
|
123
|
+
if (!svgRef.current) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
setProjector(variant.createProjector(svgRef.current, { focusId, prev: lastLayoutRef.current }));
|
|
128
|
+
}, [variant, focusId]);
|
|
129
|
+
|
|
130
|
+
// Focusable variants (plexus): clicking an object node re-focuses on it; clicking the current
|
|
131
|
+
// focus clears it. Synthetic nodes carry no ECHO object, so their clicks are ignored.
|
|
132
|
+
const handleSelect = useCallback(
|
|
133
|
+
(node: GraphLayoutNode<SpaceGraphNode>) => {
|
|
134
|
+
if (!variant.focusable || !node.data?.data?.object) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
setClickFocusId((current) => (current === node.id ? undefined : node.id));
|
|
138
|
+
},
|
|
139
|
+
[variant],
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Cursor avoidance for the SVG swarm. The Graph component hands us pre-transformed
|
|
143
|
+
// SVG model coordinates — same space the boids live in.
|
|
144
|
+
const handlePointerMove = useCallback(
|
|
145
|
+
(point: ModelPoint) => {
|
|
146
|
+
if (projector instanceof GraphSwarmProjector) {
|
|
147
|
+
projector.setCursor(point.x, point.y);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
[projector],
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const handlePointerLeave = useCallback(() => {
|
|
154
|
+
if (projector instanceof GraphSwarmProjector) {
|
|
155
|
+
projector.setCursor(null);
|
|
156
|
+
}
|
|
157
|
+
}, [projector]);
|
|
158
|
+
|
|
159
|
+
const handleInspect = useCallback(
|
|
160
|
+
(node: GraphLayoutNode<SpaceGraphNode> | null, event: MouseEvent) => {
|
|
161
|
+
if (!variant.emitsHover) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
onNodeHover?.(node ? { id: node.id, data: node.data?.data?.object } : null, event);
|
|
165
|
+
},
|
|
166
|
+
[variant, onNodeHover],
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Only attach pointer handlers when the variant tracks the cursor — others don't need them
|
|
170
|
+
// and we want to avoid the per-move CTM math when it'd be a no-op.
|
|
171
|
+
const pointerProps = variant.trackPointer
|
|
172
|
+
? { onPointerMove: handlePointerMove, onPointerLeave: handlePointerLeave }
|
|
173
|
+
: undefined;
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<SVG.Root ref={svgRef}>
|
|
177
|
+
<SVG.Zoom extent={[1 / 2, 2]}>
|
|
178
|
+
{/* Mount only once the variant's projector exists; otherwise SVG.Graph falls back to a
|
|
179
|
+
force projector for a frame, flashing the wrong layout for non-force variants. */}
|
|
180
|
+
{projector && (
|
|
181
|
+
<SVG.Graph<SpaceGraphNode, SpaceGraphEdge>
|
|
182
|
+
model={model}
|
|
183
|
+
projector={projector}
|
|
184
|
+
renderNode={variant.renderNode}
|
|
185
|
+
applyNode={variant.applyNode}
|
|
186
|
+
edgeOpacity={variant.edgeOpacity}
|
|
187
|
+
drag={variant.drag}
|
|
188
|
+
highlightOnHover={variant.highlightOnHover}
|
|
189
|
+
onSelect={handleSelect}
|
|
190
|
+
onInspect={handleInspect}
|
|
191
|
+
{...pointerProps}
|
|
192
|
+
/>
|
|
193
|
+
)}
|
|
194
|
+
</SVG.Zoom>
|
|
195
|
+
{debug && <SVG.FPS />}
|
|
196
|
+
</SVG.Root>
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
VisualizationGraph.displayName = 'Visualization.Graph';
|
|
201
|
+
|
|
202
|
+
//
|
|
203
|
+
// Visualization
|
|
204
|
+
//
|
|
205
|
+
|
|
206
|
+
export const Visualization = {
|
|
207
|
+
Root: VisualizationRoot,
|
|
208
|
+
Graph: VisualizationGraph,
|
|
209
|
+
};
|