@dxos/plugin-explorer 0.9.0 → 0.9.1-staging.ee54ba693a

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.
Files changed (162) hide show
  1. package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs +101 -0
  2. package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs.map +7 -0
  3. package/dist/lib/neutral/ExplorerPlugin.mjs +1 -1
  4. package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs +90 -0
  5. package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs.map +7 -0
  6. package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs +37 -0
  7. package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs.map +7 -0
  8. package/dist/lib/neutral/capabilities/index.mjs +4 -2
  9. package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
  10. package/dist/lib/neutral/{chunk-3D7BYXOR.mjs → chunk-4F6AT7RA.mjs} +6 -4
  11. package/dist/lib/neutral/chunk-4F6AT7RA.mjs.map +7 -0
  12. package/dist/lib/neutral/chunk-C56B464A.mjs +53 -0
  13. package/dist/lib/neutral/chunk-C56B464A.mjs.map +7 -0
  14. package/dist/lib/neutral/{chunk-7XUDLV6E.mjs → chunk-EZ52JY7X.mjs} +34 -31
  15. package/dist/lib/neutral/chunk-EZ52JY7X.mjs.map +7 -0
  16. package/dist/lib/neutral/{chunk-YBCHBVCJ.mjs → chunk-TTFPTHAQ.mjs} +8 -8
  17. package/dist/lib/neutral/chunk-TTFPTHAQ.mjs.map +7 -0
  18. package/dist/lib/neutral/components/index.mjs +430 -506
  19. package/dist/lib/neutral/components/index.mjs.map +4 -4
  20. package/dist/lib/neutral/containers/index.mjs +4 -2
  21. package/dist/lib/neutral/containers/index.mjs.map +3 -3
  22. package/dist/lib/neutral/{create-object-F6TKVAGV.mjs → create-object-WKIN3OB6.mjs} +3 -4
  23. package/dist/lib/neutral/{create-object-F6TKVAGV.mjs.map → create-object-WKIN3OB6.mjs.map} +3 -3
  24. package/dist/lib/neutral/hooks/index.mjs +64 -1
  25. package/dist/lib/neutral/hooks/index.mjs.map +4 -4
  26. package/dist/lib/neutral/index.mjs +2 -2
  27. package/dist/lib/neutral/meta.json +1 -1
  28. package/dist/lib/neutral/meta.mjs +1 -1
  29. package/dist/lib/neutral/plugin.mjs +1 -1
  30. package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs +39 -0
  31. package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs.map +7 -0
  32. package/dist/lib/neutral/testing/index.mjs +2 -2
  33. package/dist/lib/neutral/testing/index.mjs.map +2 -2
  34. package/dist/lib/neutral/translations.mjs +5 -2
  35. package/dist/lib/neutral/translations.mjs.map +3 -3
  36. package/dist/lib/neutral/types/index.mjs +1 -1
  37. package/dist/types/dx.config.d.ts +28 -0
  38. package/dist/types/dx.config.d.ts.map +1 -0
  39. package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
  40. package/dist/types/src/capabilities/app-graph-builder.d.ts +9 -0
  41. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  42. package/dist/types/src/capabilities/create-object.d.ts +1 -7
  43. package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
  44. package/dist/types/src/capabilities/index.d.ts +3 -7
  45. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  46. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  47. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  48. package/dist/types/src/components/Lattice/Lattice.d.ts +1 -1
  49. package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -1
  50. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +1 -1
  51. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/Tree/Tree.stories.d.ts +1 -1
  53. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  54. package/dist/types/src/components/Tree/index.d.ts +1 -3
  55. package/dist/types/src/components/Tree/index.d.ts.map +1 -1
  56. package/dist/types/src/components/Tree/types/tree.d.ts +10 -27
  57. package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
  58. package/dist/types/src/components/Tree/types/types.d.ts +1 -10
  59. package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
  60. package/dist/types/src/components/Visualization/Visualization.d.ts +39 -0
  61. package/dist/types/src/components/Visualization/Visualization.d.ts.map +1 -0
  62. package/dist/types/src/components/Visualization/Visualization.stories.d.ts +13 -0
  63. package/dist/types/src/components/Visualization/Visualization.stories.d.ts.map +1 -0
  64. package/dist/types/src/components/Visualization/index.d.ts +3 -0
  65. package/dist/types/src/components/Visualization/index.d.ts.map +1 -0
  66. package/dist/types/src/components/Visualization/variants.d.ts +53 -0
  67. package/dist/types/src/components/Visualization/variants.d.ts.map +1 -0
  68. package/dist/types/src/components/index.d.ts +1 -0
  69. package/dist/types/src/components/index.d.ts.map +1 -1
  70. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts +2 -2
  71. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -1
  72. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +2 -2
  73. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -1
  74. package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts +14 -0
  75. package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts.map +1 -0
  76. package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts +2 -0
  77. package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts.map +1 -0
  78. package/dist/types/src/containers/index.d.ts +1 -0
  79. package/dist/types/src/containers/index.d.ts.map +1 -1
  80. package/dist/types/src/hooks/index.d.ts +1 -0
  81. package/dist/types/src/hooks/index.d.ts.map +1 -1
  82. package/dist/types/src/hooks/useNeighborhoodModel.d.ts +14 -0
  83. package/dist/types/src/hooks/useNeighborhoodModel.d.ts.map +1 -0
  84. package/dist/types/src/meta.d.ts +32 -2
  85. package/dist/types/src/meta.d.ts.map +1 -1
  86. package/dist/types/src/testing/relations.d.ts +1 -2
  87. package/dist/types/src/testing/relations.d.ts.map +1 -1
  88. package/dist/types/src/translations.d.ts +6 -0
  89. package/dist/types/src/translations.d.ts.map +1 -1
  90. package/dist/types/src/types/Graph.d.ts +6 -8
  91. package/dist/types/src/types/Graph.d.ts.map +1 -1
  92. package/dist/types/tsconfig.tsbuildinfo +1 -1
  93. package/{dist/lib/neutral/chunk-42BYLQQA.mjs → dx.config.ts} +18 -21
  94. package/package.json +42 -37
  95. package/src/ExplorerPlugin.test.ts +1 -1
  96. package/src/ExplorerPlugin.tsx +3 -2
  97. package/src/capabilities/app-graph-builder.ts +40 -0
  98. package/src/capabilities/create-object.ts +3 -2
  99. package/src/capabilities/index.ts +1 -0
  100. package/src/capabilities/react-surface.tsx +14 -4
  101. package/src/components/Lattice/Lattice.tsx +1 -2
  102. package/src/components/Tree/EdgeBundling.stories.tsx +5 -3
  103. package/src/components/Tree/Tree.stories.tsx +7 -2
  104. package/src/components/Tree/index.ts +3 -3
  105. package/src/components/Tree/types/tree.ts +6 -6
  106. package/src/components/Tree/types/types.ts +1 -11
  107. package/src/components/Visualization/Visualization.stories.tsx +104 -0
  108. package/src/components/Visualization/Visualization.tsx +209 -0
  109. package/src/components/Visualization/index.ts +6 -0
  110. package/src/components/Visualization/variants.ts +508 -0
  111. package/src/components/index.ts +1 -0
  112. package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +3 -3
  113. package/src/containers/ExplorerArticle/ExplorerArticle.tsx +9 -10
  114. package/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.tsx +102 -0
  115. package/src/containers/NeighborhoodCompanion/index.ts +5 -0
  116. package/src/containers/index.ts +1 -0
  117. package/src/hooks/index.ts +1 -0
  118. package/src/hooks/useNeighborhoodModel.ts +81 -0
  119. package/src/meta.ts +2 -32
  120. package/src/testing/relations.ts +1 -3
  121. package/src/translations.ts +4 -1
  122. package/src/types/Graph.ts +18 -20
  123. package/dist/lib/neutral/ExplorerArticle-4I7PNGDC.mjs +0 -459
  124. package/dist/lib/neutral/ExplorerArticle-4I7PNGDC.mjs.map +0 -7
  125. package/dist/lib/neutral/chunk-3D7BYXOR.mjs.map +0 -7
  126. package/dist/lib/neutral/chunk-42BYLQQA.mjs.map +0 -7
  127. package/dist/lib/neutral/chunk-7XUDLV6E.mjs.map +0 -7
  128. package/dist/lib/neutral/chunk-IKHJV3Q4.mjs +0 -20
  129. package/dist/lib/neutral/chunk-IKHJV3Q4.mjs.map +0 -7
  130. package/dist/lib/neutral/chunk-YBCHBVCJ.mjs.map +0 -7
  131. package/dist/lib/neutral/react-surface-APBW2VQG.mjs +0 -26
  132. package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +0 -7
  133. package/dist/types/src/components/Tree/Tree.d.ts +0 -24
  134. package/dist/types/src/components/Tree/Tree.d.ts.map +0 -1
  135. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +0 -40
  136. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +0 -1
  137. package/dist/types/src/components/Tree/layout/RadialTree.d.ts +0 -37
  138. package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +0 -1
  139. package/dist/types/src/components/Tree/layout/TidyTree.d.ts +0 -26
  140. package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +0 -1
  141. package/dist/types/src/components/Tree/layout/hierarchy.d.ts +0 -17
  142. package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +0 -1
  143. package/dist/types/src/components/Tree/layout/index.d.ts +0 -6
  144. package/dist/types/src/components/Tree/layout/index.d.ts.map +0 -1
  145. package/dist/types/src/components/Tree/layout/slots.d.ts +0 -7
  146. package/dist/types/src/components/Tree/layout/slots.d.ts.map +0 -1
  147. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +0 -15
  148. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +0 -1
  149. package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts +0 -18
  150. package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts.map +0 -1
  151. package/dist/types/src/containers/ExplorerArticle/variants.d.ts +0 -9
  152. package/dist/types/src/containers/ExplorerArticle/variants.d.ts.map +0 -1
  153. package/src/components/Tree/Tree.tsx +0 -81
  154. package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +0 -335
  155. package/src/components/Tree/layout/RadialTree.tsx +0 -242
  156. package/src/components/Tree/layout/TidyTree.tsx +0 -246
  157. package/src/components/Tree/layout/hierarchy.ts +0 -32
  158. package/src/components/Tree/layout/index.ts +0 -9
  159. package/src/components/Tree/layout/slots.ts +0 -19
  160. package/src/components/Tree/layout/useContainerSize.ts +0 -43
  161. package/src/containers/ExplorerArticle/Visualization.tsx +0 -523
  162. package/src/containers/ExplorerArticle/variants.ts +0 -47
@@ -1,12 +1,16 @@
1
- // src/meta.ts
2
- import { Plugin } from "@dxos/app-framework";
3
- import { DXN } from "@dxos/keys";
4
- import { trim } from "@dxos/util";
5
- var meta = Plugin.makeMeta({
6
- key: DXN.make("org.dxos.plugin.explorer"),
7
- name: "Explorer",
8
- author: "DXOS",
9
- description: trim`
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Config2 } from '@dxos/app-framework/config';
6
+ import { trim } from '@dxos/util';
7
+
8
+ export default Config2.make({
9
+ plugin: {
10
+ key: 'org.dxos.plugin.explorer',
11
+ name: 'Explorer',
12
+ author: 'DXOS',
13
+ description: trim`
10
14
  Explorer is an interactive hypergraph visualization plugin that reveals the relationships
11
15
  between objects stored in your DXOS workspace. Each Graph document is backed by a live
12
16
  ECHO query and a View that you configure — Explorer keeps the visualization synchronized
@@ -27,16 +31,9 @@ var meta = Plugin.makeMeta({
27
31
  derives an initial View from the chosen type and persists both to ECHO so the graph is
28
32
  immediately shareable and replicable across the space.
29
33
  `,
30
- icon: "ph--graph--regular",
31
- iconHue: "green",
32
- source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-explorer",
33
- spec: "PLUGIN.mdl",
34
- screenshots: [
35
- "https://dxos.network/plugin-details-explorer-dark.png"
36
- ]
34
+ source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-explorer',
35
+ icon: { key: 'ph--graph--regular', hue: 'green' },
36
+ spec: 'PLUGIN.mdl',
37
+ screenshots: [{ dark: 'https://dxos.network/plugin-details-explorer-dark.png' }],
38
+ },
37
39
  });
38
-
39
- export {
40
- meta
41
- };
42
- //# sourceMappingURL=chunk-42BYLQQA.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-explorer",
3
- "version": "0.9.0",
3
+ "version": "0.9.1-staging.ee54ba693a",
4
4
  "description": "Braneframe data visualization plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -90,63 +90,68 @@
90
90
  "types": "dist/types/src/index.d.ts",
91
91
  "files": [
92
92
  "dist",
93
+ "dx.config.ts",
93
94
  "src",
94
95
  "PLUGIN.mdl"
95
96
  ],
96
97
  "dependencies": {
97
98
  "@effect-atom/atom-react": "^0.5.0",
98
99
  "@observablehq/plot": "^0.6.11",
100
+ "@radix-ui/react-context": "1.1.1",
101
+ "@radix-ui/react-slot": "1.1.2",
99
102
  "d3": "^7.9.0",
100
- "effect": "3.21.3",
103
+ "effect": "3.21.4",
101
104
  "force-graph": "^1.49.4",
102
105
  "react-resize-detector": "^11.0.1",
103
106
  "topojson-client": "^3.1.0",
104
- "@dxos/app-framework": "0.9.0",
105
- "@dxos/app-toolkit": "0.9.0",
106
- "@dxos/client": "0.9.0",
107
- "@dxos/echo": "0.9.0",
108
- "@dxos/echo-query": "0.9.0",
109
- "@dxos/compute": "0.9.0",
110
- "@dxos/graph": "0.9.0",
111
- "@dxos/invariant": "0.9.0",
112
- "@dxos/log": "0.9.0",
113
- "@dxos/keys": "0.9.0",
114
- "@dxos/plugin-space": "0.9.0",
115
- "@dxos/plugin-client": "0.9.0",
116
- "@dxos/react-client": "0.9.0",
117
- "@dxos/react-ui-components": "0.9.0",
118
- "@dxos/react-ui-mosaic": "0.9.0",
119
- "@dxos/react-ui-graph": "0.9.0",
120
- "@dxos/schema": "0.9.0",
121
- "@dxos/types": "0.9.0",
122
- "@dxos/util": "0.9.0",
123
- "@dxos/react-ui-stack": "0.9.0"
107
+ "@dxos/app-toolkit": "0.9.1-staging.ee54ba693a",
108
+ "@dxos/app-framework": "0.9.1-staging.ee54ba693a",
109
+ "@dxos/client": "0.9.1-staging.ee54ba693a",
110
+ "@dxos/echo": "0.9.1-staging.ee54ba693a",
111
+ "@dxos/echo-query": "0.9.1-staging.ee54ba693a",
112
+ "@dxos/graph": "0.9.1-staging.ee54ba693a",
113
+ "@dxos/invariant": "0.9.1-staging.ee54ba693a",
114
+ "@dxos/log": "0.9.1-staging.ee54ba693a",
115
+ "@dxos/compute": "0.9.1-staging.ee54ba693a",
116
+ "@dxos/keys": "0.9.1-staging.ee54ba693a",
117
+ "@dxos/plugin-client": "0.9.1-staging.ee54ba693a",
118
+ "@dxos/plugin-graph": "0.9.1-staging.ee54ba693a",
119
+ "@dxos/react-client": "0.9.1-staging.ee54ba693a",
120
+ "@dxos/plugin-space": "0.9.1-staging.ee54ba693a",
121
+ "@dxos/react-ui-graph": "0.9.1-staging.ee54ba693a",
122
+ "@dxos/react-ui-attention": "0.9.1-staging.ee54ba693a",
123
+ "@dxos/react-ui-mosaic": "0.9.1-staging.ee54ba693a",
124
+ "@dxos/types": "0.9.1-staging.ee54ba693a",
125
+ "@dxos/ui-types": "0.9.1-staging.ee54ba693a",
126
+ "@dxos/schema": "0.9.1-staging.ee54ba693a",
127
+ "@dxos/util": "0.9.1-staging.ee54ba693a",
128
+ "@dxos/react-ui-components": "0.9.1-staging.ee54ba693a"
124
129
  },
125
130
  "devDependencies": {
126
131
  "@types/d3": "^7.4.3",
127
132
  "@types/d3-hierarchy": "^3.1.6",
128
133
  "@types/lodash.defaultsdeep": "^4.6.6",
129
- "@types/react": "~19.2.7",
134
+ "@types/react": "~19.2.17",
130
135
  "@types/react-dom": "~19.2.3",
131
136
  "@types/topojson-client": "^3.1.4",
132
137
  "@types/topojson-specification": "^1.0.5",
133
- "react": "~19.2.3",
134
- "react-dom": "~19.2.3",
138
+ "react": "~19.2.7",
139
+ "react-dom": "~19.2.7",
135
140
  "vite": "^8.0.16",
136
- "@dxos/echo-generator": "0.9.0",
137
- "@dxos/plugin-testing": "0.9.0",
138
- "@dxos/plugin-preview": "0.9.0",
139
- "@dxos/react-ui": "0.9.0",
140
- "@dxos/storybook-utils": "0.9.0",
141
- "@dxos/random": "0.9.0",
142
- "@dxos/ui-theme": "0.9.0"
141
+ "@dxos/echo-generator": "0.9.1-staging.ee54ba693a",
142
+ "@dxos/plugin-preview": "0.9.1-staging.ee54ba693a",
143
+ "@dxos/plugin-testing": "0.9.1-staging.ee54ba693a",
144
+ "@dxos/storybook-utils": "0.9.1-staging.ee54ba693a",
145
+ "@dxos/ui-theme": "0.9.1-staging.ee54ba693a",
146
+ "@dxos/random": "0.9.1-staging.ee54ba693a",
147
+ "@dxos/react-ui": "0.9.1-staging.ee54ba693a"
143
148
  },
144
149
  "peerDependencies": {
145
- "effect": "3.21.3",
146
- "react": "~19.2.3",
147
- "react-dom": "~19.2.3",
148
- "@dxos/react-ui": "0.9.0",
149
- "@dxos/ui-theme": "0.9.0"
150
+ "effect": "3.21.4",
151
+ "react": "~19.2.7",
152
+ "react-dom": "~19.2.7",
153
+ "@dxos/react-ui": "0.9.1-staging.ee54ba693a",
154
+ "@dxos/ui-theme": "0.9.1-staging.ee54ba693a"
150
155
  },
151
156
  "publishConfig": {
152
157
  "access": "public"
@@ -11,7 +11,7 @@ import { ExplorerPlugin } from '#plugin';
11
11
 
12
12
  import { meta } from './meta';
13
13
 
14
- const moduleId = (name: string) => `${meta.id}.module.${name}`;
14
+ const moduleId = (name: string) => `${meta.profile.key}.module.${name}`;
15
15
 
16
16
  describe('ExplorerPlugin', () => {
17
17
  test('modules activate on the expected events', async ({ expect }) => {
@@ -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,11 +15,12 @@ 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 }),
21
22
  AppPlugin.addPluginAssetModule({
22
- asset: { pluginId: meta.id, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
23
+ asset: { pluginId: meta.profile.key, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
23
24
  }),
24
25
  Plugin.make,
25
26
  );
@@ -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 { view } = await ViewModel.makeFromDatabase({ db: options.db, typename: props.typename });
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 { Tree, type TreeComponentProps } from './Tree';
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 { Tree, type TreeComponentProps } from './Tree';
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
- return <Tree data={data} variant={variant} />;
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
- export * from './Tree';
6
- export * from './layout';
7
- export { type TreeNode, treeTypeToTreeNode } from './types';
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 const TreeType = Schema.Struct({
23
- root: Key.EntityId,
24
- nodes: Schema.mutable(Schema.Record({ key: Key.EntityId, value: TreeNodeType })),
25
- }).pipe(Type.makeObject(DXN.make('org.dxos.type.tree', '0.1.0')));
26
-
27
- export type TreeType = Type.InstanceType<typeof TreeType>;
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' } };