@dxos/plugin-explorer 0.8.4-main.406dc2a → 0.8.4-main.43cb759274

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 (270) hide show
  1. package/LICENSE +102 -5
  2. package/PLUGIN.mdl +340 -0
  3. package/dist/lib/neutral/ExplorerArticle-4I7PNGDC.mjs +459 -0
  4. package/dist/lib/neutral/ExplorerArticle-4I7PNGDC.mjs.map +7 -0
  5. package/dist/lib/neutral/ExplorerPlugin.mjs +10 -0
  6. package/dist/lib/neutral/capabilities/index.mjs +11 -0
  7. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  8. package/dist/lib/neutral/chunk-3D7BYXOR.mjs +37 -0
  9. package/dist/lib/neutral/chunk-3D7BYXOR.mjs.map +7 -0
  10. package/dist/lib/neutral/chunk-42BYLQQA.mjs +42 -0
  11. package/dist/lib/neutral/chunk-42BYLQQA.mjs.map +7 -0
  12. package/dist/lib/neutral/chunk-7XUDLV6E.mjs +287 -0
  13. package/dist/lib/neutral/chunk-7XUDLV6E.mjs.map +7 -0
  14. package/dist/lib/neutral/chunk-HI324IB4.mjs +69 -0
  15. package/dist/lib/neutral/chunk-HI324IB4.mjs.map +7 -0
  16. package/dist/lib/neutral/chunk-IKHJV3Q4.mjs +20 -0
  17. package/dist/lib/neutral/chunk-IKHJV3Q4.mjs.map +7 -0
  18. package/dist/lib/{browser/chunk-MOM5KCKC.mjs → neutral/components/index.mjs} +882 -556
  19. package/dist/lib/neutral/components/index.mjs.map +7 -0
  20. package/dist/lib/neutral/containers/index.mjs +9 -0
  21. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  22. package/dist/lib/neutral/create-object-F6TKVAGV.mjs +39 -0
  23. package/dist/lib/neutral/create-object-F6TKVAGV.mjs.map +7 -0
  24. package/dist/lib/neutral/hooks/index.mjs +45 -0
  25. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  26. package/dist/lib/neutral/index.mjs +14 -0
  27. package/dist/lib/neutral/meta.json +1 -0
  28. package/dist/lib/{browser → neutral}/meta.mjs +1 -1
  29. package/dist/lib/neutral/plugin.mjs +12 -0
  30. package/dist/lib/neutral/plugin.mjs.map +7 -0
  31. package/dist/lib/neutral/react-surface-APBW2VQG.mjs +26 -0
  32. package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +7 -0
  33. package/dist/lib/neutral/testing/index.mjs +139 -0
  34. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  35. package/dist/lib/neutral/translations.mjs +33 -0
  36. package/dist/lib/neutral/translations.mjs.map +7 -0
  37. package/dist/lib/{browser → neutral}/types/index.mjs +1 -2
  38. package/dist/types/data/cities.d.ts +4 -4
  39. package/dist/types/data/cities.d.ts.map +1 -1
  40. package/dist/types/data/countries-110m.d.ts +19 -22
  41. package/dist/types/data/countries-110m.d.ts.map +1 -1
  42. package/dist/types/src/ExplorerPlugin.d.ts +3 -1
  43. package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
  44. package/dist/types/src/ExplorerPlugin.test.d.ts +2 -0
  45. package/dist/types/src/ExplorerPlugin.test.d.ts.map +1 -0
  46. package/dist/types/src/capabilities/create-object.d.ts +11 -0
  47. package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
  48. package/dist/types/src/capabilities/index.d.ts +8 -2
  49. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  50. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  51. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  52. package/dist/types/src/components/Chart/Chart.d.ts +1 -1
  53. package/dist/types/src/components/Chart/Chart.d.ts.map +1 -1
  54. package/dist/types/src/components/Chart/Chart.stories.d.ts +4 -1
  55. package/dist/types/src/components/Chart/Chart.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/Globe/Globe.d.ts +1 -1
  57. package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
  58. package/dist/types/src/components/Globe/Globe.stories.d.ts +5 -2
  59. package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
  60. package/dist/types/src/components/Graph/CanvasForceGraph.d.ts +13 -0
  61. package/dist/types/src/components/Graph/CanvasForceGraph.d.ts.map +1 -0
  62. package/dist/types/src/components/Graph/CanvasForceGraph.stories.d.ts +17 -0
  63. package/dist/types/src/components/Graph/CanvasForceGraph.stories.d.ts.map +1 -0
  64. package/dist/types/src/components/Graph/ForceGraph.d.ts +12 -5
  65. package/dist/types/src/components/Graph/ForceGraph.d.ts.map +1 -1
  66. package/dist/types/src/components/Graph/ForceGraph.stories.d.ts +4 -2
  67. package/dist/types/src/components/Graph/ForceGraph.stories.d.ts.map +1 -1
  68. package/dist/types/src/components/Graph/{adapter.d.ts → graph-adapter.d.ts} +2 -2
  69. package/dist/types/src/components/Graph/graph-adapter.d.ts.map +1 -0
  70. package/dist/types/src/components/Graph/index.d.ts +1 -1
  71. package/dist/types/src/components/Graph/index.d.ts.map +1 -1
  72. package/dist/types/src/components/Lattice/Lattice.d.ts +20 -0
  73. package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -0
  74. package/dist/types/src/components/Lattice/Lattice.stories.d.ts +8 -0
  75. package/dist/types/src/components/Lattice/Lattice.stories.d.ts.map +1 -0
  76. package/dist/types/src/components/Lattice/index.d.ts +2 -0
  77. package/dist/types/src/components/Lattice/index.d.ts.map +1 -0
  78. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +21 -0
  79. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -0
  80. package/dist/types/src/components/Tree/Tree.d.ts +20 -23
  81. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  82. package/dist/types/src/components/Tree/Tree.stories.d.ts +5 -12
  83. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  84. package/dist/types/src/components/Tree/index.d.ts +2 -0
  85. package/dist/types/src/components/Tree/index.d.ts.map +1 -1
  86. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +37 -2
  87. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +1 -1
  88. package/dist/types/src/components/Tree/layout/RadialTree.d.ts +35 -2
  89. package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +1 -1
  90. package/dist/types/src/components/Tree/layout/TidyTree.d.ts +24 -2
  91. package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +1 -1
  92. package/dist/types/src/components/Tree/layout/hierarchy.d.ts +17 -0
  93. package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +1 -0
  94. package/dist/types/src/components/Tree/layout/index.d.ts +5 -4
  95. package/dist/types/src/components/Tree/layout/index.d.ts.map +1 -1
  96. package/dist/types/src/components/Tree/layout/slots.d.ts +7 -0
  97. package/dist/types/src/components/Tree/layout/slots.d.ts.map +1 -0
  98. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +15 -0
  99. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +1 -0
  100. package/dist/types/src/components/Tree/types/tree.d.ts +50 -27
  101. package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
  102. package/dist/types/src/components/Tree/types/types.d.ts +14 -4
  103. package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
  104. package/dist/types/src/components/index.d.ts +1 -4
  105. package/dist/types/src/components/index.d.ts.map +1 -1
  106. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts +8 -0
  107. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -0
  108. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +15 -0
  109. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -0
  110. package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts +18 -0
  111. package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts.map +1 -0
  112. package/dist/types/src/containers/ExplorerArticle/index.d.ts +2 -0
  113. package/dist/types/src/containers/ExplorerArticle/index.d.ts.map +1 -0
  114. package/dist/types/src/containers/ExplorerArticle/variants.d.ts +9 -0
  115. package/dist/types/src/containers/ExplorerArticle/variants.d.ts.map +1 -0
  116. package/dist/types/src/containers/index.d.ts +3 -0
  117. package/dist/types/src/containers/index.d.ts.map +1 -0
  118. package/dist/types/src/hooks/useGraphModel.d.ts +2 -2
  119. package/dist/types/src/hooks/useGraphModel.d.ts.map +1 -1
  120. package/dist/types/src/index.d.ts +1 -3
  121. package/dist/types/src/index.d.ts.map +1 -1
  122. package/dist/types/src/meta.d.ts +2 -2
  123. package/dist/types/src/meta.d.ts.map +1 -1
  124. package/dist/types/src/plugin.d.ts +3 -0
  125. package/dist/types/src/plugin.d.ts.map +1 -0
  126. package/dist/types/src/{components/Tree/testing → testing}/generator.d.ts +1 -1
  127. package/dist/types/src/testing/generator.d.ts.map +1 -0
  128. package/dist/types/src/testing/index.d.ts +4 -0
  129. package/dist/types/src/testing/index.d.ts.map +1 -0
  130. package/dist/types/src/testing/relations.d.ts +32 -0
  131. package/dist/types/src/testing/relations.d.ts.map +1 -0
  132. package/dist/types/src/translations.d.ts +31 -22
  133. package/dist/types/src/translations.d.ts.map +1 -1
  134. package/dist/types/src/types/ExplorerAction.d.ts +1 -18
  135. package/dist/types/src/types/ExplorerAction.d.ts.map +1 -1
  136. package/dist/types/src/types/Graph.d.ts +14 -25
  137. package/dist/types/src/types/Graph.d.ts.map +1 -1
  138. package/dist/types/src/util/index.d.ts +3 -0
  139. package/dist/types/src/util/index.d.ts.map +1 -0
  140. package/dist/types/src/util/node-color.d.ts +13 -0
  141. package/dist/types/src/util/node-color.d.ts.map +1 -0
  142. package/dist/types/src/{components → util}/plot.d.ts +1 -1
  143. package/dist/types/src/util/plot.d.ts.map +1 -0
  144. package/dist/types/tsconfig.tsbuildinfo +1 -1
  145. package/package.json +113 -65
  146. package/src/ExplorerPlugin.test.ts +26 -0
  147. package/src/ExplorerPlugin.tsx +20 -54
  148. package/src/capabilities/create-object.ts +36 -0
  149. package/src/capabilities/index.ts +3 -3
  150. package/src/capabilities/react-surface.tsx +24 -19
  151. package/src/components/Chart/Chart.stories.tsx +16 -23
  152. package/src/components/Chart/Chart.tsx +1 -1
  153. package/src/components/Globe/Globe.stories.tsx +19 -22
  154. package/src/components/Globe/Globe.tsx +1 -1
  155. package/src/components/Graph/CanvasForceGraph.stories.tsx +97 -0
  156. package/src/components/Graph/CanvasForceGraph.tsx +124 -0
  157. package/src/components/Graph/ForceGraph.stories.tsx +98 -42
  158. package/src/components/Graph/ForceGraph.tsx +105 -85
  159. package/src/components/Graph/{adapter.ts → graph-adapter.ts} +14 -8
  160. package/src/components/Graph/index.ts +1 -1
  161. package/src/components/Lattice/Lattice.stories.tsx +104 -0
  162. package/src/components/Lattice/Lattice.tsx +182 -0
  163. package/src/components/Lattice/index.ts +5 -0
  164. package/src/components/Tree/EdgeBundling.stories.tsx +144 -0
  165. package/src/components/Tree/Tree.stories.tsx +20 -38
  166. package/src/components/Tree/Tree.tsx +69 -95
  167. package/src/components/Tree/index.ts +2 -0
  168. package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +335 -0
  169. package/src/components/Tree/layout/RadialTree.tsx +242 -0
  170. package/src/components/Tree/layout/TidyTree.tsx +246 -0
  171. package/src/components/Tree/layout/hierarchy.ts +32 -0
  172. package/src/components/Tree/layout/index.ts +5 -5
  173. package/src/components/Tree/layout/slots.ts +19 -0
  174. package/src/components/Tree/layout/useContainerSize.ts +43 -0
  175. package/src/components/Tree/types/tree.test.ts +8 -7
  176. package/src/components/Tree/types/tree.ts +51 -35
  177. package/src/components/Tree/types/types.ts +38 -29
  178. package/src/components/index.ts +1 -4
  179. package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +152 -0
  180. package/src/containers/ExplorerArticle/ExplorerArticle.tsx +120 -0
  181. package/src/containers/ExplorerArticle/Visualization.tsx +523 -0
  182. package/src/containers/ExplorerArticle/index.ts +5 -0
  183. package/src/containers/ExplorerArticle/variants.ts +47 -0
  184. package/src/containers/index.ts +7 -0
  185. package/src/hooks/useGraphModel.ts +25 -14
  186. package/src/index.ts +1 -4
  187. package/src/meta.ts +30 -6
  188. package/src/plugin.ts +9 -0
  189. package/src/{components/Tree/testing → testing}/generator.ts +6 -4
  190. package/src/testing/index.ts +9 -0
  191. package/src/testing/relations.ts +117 -0
  192. package/src/translations.ts +16 -13
  193. package/src/types/ExplorerAction.ts +10 -19
  194. package/src/types/Graph.ts +20 -24
  195. package/src/typings.d.ts +8 -0
  196. package/src/util/index.ts +6 -0
  197. package/src/util/node-color.ts +23 -0
  198. package/src/{components → util}/plot.ts +16 -4
  199. package/src/vite-env.d.ts +10 -0
  200. package/dist/lib/browser/ExplorerContainer-6SHZJ6AK.mjs +0 -50
  201. package/dist/lib/browser/ExplorerContainer-6SHZJ6AK.mjs.map +0 -7
  202. package/dist/lib/browser/chunk-2DGFNLRO.mjs +0 -19
  203. package/dist/lib/browser/chunk-2DGFNLRO.mjs.map +0 -7
  204. package/dist/lib/browser/chunk-2MKBRIUT.mjs +0 -31
  205. package/dist/lib/browser/chunk-2MKBRIUT.mjs.map +0 -7
  206. package/dist/lib/browser/chunk-BZ65T5M3.mjs +0 -79
  207. package/dist/lib/browser/chunk-BZ65T5M3.mjs.map +0 -7
  208. package/dist/lib/browser/chunk-MOM5KCKC.mjs.map +0 -7
  209. package/dist/lib/browser/chunk-NXGP6NTP.mjs +0 -203
  210. package/dist/lib/browser/chunk-NXGP6NTP.mjs.map +0 -7
  211. package/dist/lib/browser/index.mjs +0 -118
  212. package/dist/lib/browser/index.mjs.map +0 -7
  213. package/dist/lib/browser/intent-resolver-K57C3LIX.mjs +0 -31
  214. package/dist/lib/browser/intent-resolver-K57C3LIX.mjs.map +0 -7
  215. package/dist/lib/browser/meta.json +0 -1
  216. package/dist/lib/browser/react-surface-OPBND5W3.mjs +0 -35
  217. package/dist/lib/browser/react-surface-OPBND5W3.mjs.map +0 -7
  218. package/dist/lib/node-esm/ExplorerContainer-FRTDXZI5.mjs +0 -51
  219. package/dist/lib/node-esm/ExplorerContainer-FRTDXZI5.mjs.map +0 -7
  220. package/dist/lib/node-esm/chunk-3ODK27PU.mjs +0 -33
  221. package/dist/lib/node-esm/chunk-3ODK27PU.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-6JACZE7E.mjs +0 -205
  223. package/dist/lib/node-esm/chunk-6JACZE7E.mjs.map +0 -7
  224. package/dist/lib/node-esm/chunk-ES6AOMCY.mjs +0 -80
  225. package/dist/lib/node-esm/chunk-ES6AOMCY.mjs.map +0 -7
  226. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  227. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  228. package/dist/lib/node-esm/chunk-PX6LHR2N.mjs +0 -21
  229. package/dist/lib/node-esm/chunk-PX6LHR2N.mjs.map +0 -7
  230. package/dist/lib/node-esm/chunk-ZCV4U7LT.mjs +0 -11343
  231. package/dist/lib/node-esm/chunk-ZCV4U7LT.mjs.map +0 -7
  232. package/dist/lib/node-esm/index.mjs +0 -119
  233. package/dist/lib/node-esm/index.mjs.map +0 -7
  234. package/dist/lib/node-esm/intent-resolver-BLPPTTEY.mjs +0 -32
  235. package/dist/lib/node-esm/intent-resolver-BLPPTTEY.mjs.map +0 -7
  236. package/dist/lib/node-esm/meta.json +0 -1
  237. package/dist/lib/node-esm/meta.mjs +0 -9
  238. package/dist/lib/node-esm/react-surface-HCKQSHKJ.mjs +0 -36
  239. package/dist/lib/node-esm/react-surface-HCKQSHKJ.mjs.map +0 -7
  240. package/dist/lib/node-esm/types/index.mjs +0 -12
  241. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  242. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  243. package/dist/types/src/components/ExplorerContainer.d.ts +0 -9
  244. package/dist/types/src/components/ExplorerContainer.d.ts.map +0 -1
  245. package/dist/types/src/components/Graph/D3ForceGraph.d.ts +0 -14
  246. package/dist/types/src/components/Graph/D3ForceGraph.d.ts.map +0 -1
  247. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts +0 -15
  248. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts.map +0 -1
  249. package/dist/types/src/components/Graph/adapter.d.ts.map +0 -1
  250. package/dist/types/src/components/Graph/testing.d.ts +0 -14
  251. package/dist/types/src/components/Graph/testing.d.ts.map +0 -1
  252. package/dist/types/src/components/Tree/testing/generator.d.ts.map +0 -1
  253. package/dist/types/src/components/Tree/testing/index.d.ts +0 -2
  254. package/dist/types/src/components/Tree/testing/index.d.ts.map +0 -1
  255. package/dist/types/src/components/plot.d.ts.map +0 -1
  256. package/src/capabilities/intent-resolver.ts +0 -21
  257. package/src/components/ExplorerContainer.tsx +0 -54
  258. package/src/components/Graph/D3ForceGraph.stories.tsx +0 -77
  259. package/src/components/Graph/D3ForceGraph.tsx +0 -101
  260. package/src/components/Graph/testing.ts +0 -55
  261. package/src/components/Tree/layout/HierarchicalEdgeBundling.ts +0 -162
  262. package/src/components/Tree/layout/RadialTree.ts +0 -94
  263. package/src/components/Tree/layout/TidyTree.ts +0 -101
  264. package/src/components/Tree/testing/index.ts +0 -5
  265. /package/dist/lib/{browser/chunk-J5LGTIGS.mjs.map → neutral/ExplorerPlugin.mjs.map} +0 -0
  266. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
  267. /package/dist/lib/{browser/meta.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
  268. /package/dist/lib/{browser/types → neutral}/index.mjs.map +0 -0
  269. /package/dist/lib/{node-esm → neutral}/meta.mjs.map +0 -0
  270. /package/dist/lib/{node-esm → neutral}/types/index.mjs.map +0 -0
@@ -4,38 +4,34 @@
4
4
 
5
5
  import * as Schema from 'effect/Schema';
6
6
 
7
- import { Key, Obj, Type } from '@dxos/echo';
7
+ import { DXN, Key, Obj, Ref, Type } from '@dxos/echo';
8
+ import { TestSchema } from '@dxos/echo/testing';
8
9
  import { invariant } from '@dxos/invariant';
9
10
 
10
11
  // TODO(burdon): Reconcile with @dxos/graph (i.e., common types).
11
12
 
12
13
  export const TreeNodeType = Schema.Struct({
13
- id: Key.ObjectId,
14
- children: Schema.mutable(Schema.Array(Key.ObjectId)),
14
+ id: Key.EntityId,
15
+ children: Schema.mutable(Schema.Array(Key.EntityId)),
15
16
  data: Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.Any })),
16
- ref: Schema.optional(Type.Ref(Type.Expando)),
17
+ ref: Schema.optional(Ref.Ref(TestSchema.Expando)),
17
18
  }).pipe(Schema.mutable);
18
19
 
19
- export interface TreeNodeType extends Schema.Schema.Type<typeof TreeNodeType> {}
20
+ export type TreeNodeType = Schema.Schema.Type<typeof TreeNodeType>;
20
21
 
21
22
  export const TreeType = Schema.Struct({
22
- root: Key.ObjectId,
23
- nodes: Schema.mutable(Schema.Record({ key: Key.ObjectId, value: TreeNodeType })),
24
- }).pipe(
25
- Type.Obj({
26
- typename: 'dxos.org/type/Tree',
27
- version: '0.1.0',
28
- }),
29
- );
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')));
30
26
 
31
- export interface TreeType extends Schema.Schema.Type<typeof TreeType> {}
27
+ export type TreeType = Type.InstanceType<typeof TreeType>;
32
28
 
33
29
  /**
34
30
  * Wrapper object for tree.
35
31
  */
36
32
  export class Tree {
37
33
  static create = (): TreeType => {
38
- const id = Key.ObjectId.random();
34
+ const id = Key.EntityId.random();
39
35
  return Obj.make(TreeType, {
40
36
  root: id,
41
37
  nodes: {
@@ -76,7 +72,7 @@ export class Tree {
76
72
  */
77
73
  tranverse<T>(
78
74
  callback: (node: TreeNodeType, depth: number) => T | void,
79
- root: Key.ObjectId = this._tree.root,
75
+ root: Key.EntityId = this._tree.root,
80
76
  depth = 0,
81
77
  ): T | void {
82
78
  const node = this._tree.nodes[root];
@@ -93,7 +89,7 @@ export class Tree {
93
89
  }
94
90
  }
95
91
 
96
- getNode(id: Key.ObjectId): TreeNodeType {
92
+ getNode(id: Key.EntityId): TreeNodeType {
97
93
  const node = this._tree.nodes[id];
98
94
  invariant(node);
99
95
  return node;
@@ -184,9 +180,11 @@ export class Tree {
184
180
  clear(): void {
185
181
  const root = this._tree.nodes[this._tree.root];
186
182
  root.children.length = 0;
187
- this._tree.nodes = {
188
- [root.id]: root,
189
- };
183
+ Obj.update(this._tree, (obj) => {
184
+ obj.nodes = {
185
+ [root.id]: root,
186
+ };
187
+ });
190
188
  }
191
189
 
192
190
  /**
@@ -194,28 +192,35 @@ export class Tree {
194
192
  */
195
193
  addNode(parent: TreeNodeType, node?: TreeNodeType, index?: number): TreeNodeType {
196
194
  if (!node) {
197
- const id = Key.ObjectId.random();
195
+ const id = Key.EntityId.random();
198
196
  node = { id, children: [], data: { text: '' } }; // TODO(burdon): Generic.
199
197
  }
200
198
 
201
- this._tree.nodes[node.id] = node;
202
- parent.children.splice(index ?? parent.children.length, 0, node.id);
199
+ const nodeToAdd = node;
200
+ Obj.update(this._tree, (obj) => {
201
+ obj.nodes[nodeToAdd.id] = nodeToAdd;
202
+ parent.children.splice(index ?? parent.children.length, 0, nodeToAdd.id);
203
+ });
203
204
  return node;
204
205
  }
205
206
 
206
207
  /**
207
208
  * Delete node.
208
209
  */
209
- deleteNode(parent: TreeNodeType, id: Key.ObjectId): TreeNodeType | undefined {
210
+ deleteNode(parent: TreeNodeType, id: Key.EntityId): TreeNodeType | undefined {
210
211
  const node = this._tree.nodes[id];
211
212
  if (!node) {
212
213
  return undefined;
213
214
  }
214
215
 
215
- delete this._tree.nodes[node.id];
216
+ Obj.update(this._tree, (obj) => {
217
+ delete obj.nodes[node.id];
218
+ });
216
219
  const idx = parent.children.findIndex((child) => child === id);
217
220
  if (idx !== -1) {
218
- parent.children.splice(idx, 1);
221
+ Obj.update(this._tree, () => {
222
+ parent.children.splice(idx, 1);
223
+ });
219
224
  }
220
225
 
221
226
  return node;
@@ -232,8 +237,10 @@ export class Tree {
232
237
  }
233
238
 
234
239
  const child = node.children[from];
235
- node.children.splice(from, 1);
236
- node.children.splice(to, 0, child);
240
+ Obj.update(this._tree, () => {
241
+ node.children.splice(from, 1);
242
+ node.children.splice(to, 0, child);
243
+ });
237
244
  return this.getNode(child);
238
245
  }
239
246
 
@@ -252,8 +259,10 @@ export class Tree {
252
259
  }
253
260
 
254
261
  const previous = this.getNode(parent.children[idx - 1]);
255
- parent.children.splice(idx, 1);
256
- previous.children.push(node.id);
262
+ Obj.update(this._tree, () => {
263
+ parent.children.splice(idx, 1);
264
+ previous.children.push(node.id);
265
+ });
257
266
  }
258
267
 
259
268
  /**
@@ -270,16 +279,23 @@ export class Tree {
270
279
  return;
271
280
  }
272
281
 
273
- // Remove node from parent.
282
+ // Remove node from parent and get following siblings.
274
283
  const nodeIdx = parent.children.findIndex((id) => id === node.id);
275
- const [_, ...rest] = parent.children.splice(nodeIdx, parent.children.length - nodeIdx);
276
- parent.children.splice(nodeIdx, parent.children.length - nodeIdx);
284
+ let rest: Key.EntityId[] = [];
285
+ Obj.update(this._tree, () => {
286
+ const removed = parent.children.splice(nodeIdx, parent.children.length - nodeIdx);
287
+ rest = removed.slice(1); // Skip the node itself.
288
+ });
277
289
 
278
290
  // Add to ancestor.
279
291
  const parentIdx = this.getChildNodes(ancestor).findIndex((n) => n.id === parent.id);
280
- ancestor.children.splice(parentIdx + 1, 0, node.id);
292
+ Obj.update(this._tree, () => {
293
+ ancestor.children.splice(parentIdx + 1, 0, node.id);
294
+ });
281
295
 
282
296
  // Transplant following siblings to current node.
283
- node.children.push(...rest);
297
+ Obj.update(this._tree, () => {
298
+ node.children.push(...rest);
299
+ });
284
300
  }
285
301
  }
@@ -2,40 +2,49 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type GraphModel } from '@dxos/graph';
5
+ import { type Key } from '@dxos/echo';
6
6
 
7
- export type TreeNode = {
7
+ import { type TreeType } from './tree';
8
+
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> = {
8
14
  id: string;
9
15
  label?: string;
10
- children?: TreeNode[];
16
+ data?: TData;
17
+ children?: TreeNode<TData>[];
11
18
  };
12
19
 
13
- export const mapGraphToTreeData = (model: GraphModel, maxDepth = 8): TreeNode | undefined => {
14
- // TODO(burdon): Convert to common/graph.
15
- // const mapNode = (node: N, depth = 0): TreeNode => {
16
- // const treeNode: TreeNode = {
17
- // id: model.idAccessor(node),
18
- // label: model.idAccessor(node).slice(0, 8),
19
- // };
20
-
21
- // const links = model.graph.links.filter((link) => link.source === treeNode.id);
22
- // if (depth < maxDepth) {
23
- // treeNode.children = links.map((link) =>
24
- // mapNode(model.graph.nodes.find((node) => model.idAccessor(node) === link.target)!, depth + 1),
25
- // );
26
- // }
20
+ /**
21
+ * Convert an ECHO `TreeType` (id-keyed node map) into a nested `TreeNode` hierarchy.
22
+ * Returns `undefined` if the root id is missing the tree is then incomplete and shouldn't render.
23
+ */
24
+ export const treeTypeToTreeNode = (
25
+ tree: TreeType,
26
+ rootId: Key.EntityId = tree.root,
27
+ visited: Set<string> = new Set(),
28
+ ): TreeNode | undefined => {
29
+ const node = tree.nodes[rootId];
30
+ if (!node) {
31
+ return undefined;
32
+ }
33
+ if (visited.has(rootId)) {
34
+ return { id: rootId, label: labelOf(node), data: node.data };
35
+ }
36
+ visited.add(rootId);
27
37
 
28
- // return treeNode;
29
- // };
30
-
31
- let data: TreeNode | undefined;
32
- // TODO(burdon): Selection model.
33
- // if (model.selected) {
34
- // const node = model.graph.nodes.find((node) => model.idAccessor(node) === model.selected);
35
- // if (node) {
36
- // data = mapNode(node);
37
- // }
38
- // }
38
+ return {
39
+ id: rootId,
40
+ label: labelOf(node),
41
+ data: node.data,
42
+ children: node.children
43
+ .map((childId) => treeTypeToTreeNode(tree, childId, visited))
44
+ .filter((c): c is TreeNode => Boolean(c)),
45
+ };
46
+ };
39
47
 
40
- return data;
48
+ const labelOf = (node: { data: Record<string, any> }): string | undefined => {
49
+ return typeof node.data?.text === 'string' ? node.data.text : undefined;
41
50
  };
@@ -2,11 +2,8 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { lazy } from 'react';
6
-
7
- export const ExplorerContainer = lazy(() => import('./ExplorerContainer'));
8
-
9
5
  export * from './Chart';
10
6
  export * from './Globe';
11
7
  export * from './Graph';
8
+ export * from './Lattice';
12
9
  export * from './Tree';
@@ -0,0 +1,152 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import * as Effect from 'effect/Effect';
7
+ import React from 'react';
8
+
9
+ import { withPluginManager } from '@dxos/app-framework/testing';
10
+ import { Filter, Query, Type, View } from '@dxos/echo';
11
+ import { ClientPlugin, initializeIdentity } from '@dxos/plugin-client/testing';
12
+ import { PreviewPlugin } from '@dxos/plugin-preview/testing';
13
+ import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
14
+ import { random } from '@dxos/random';
15
+ import { useQuery, useSpaces } from '@dxos/react-client/echo';
16
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
17
+ import { ViewModel } from '@dxos/schema';
18
+ import { type ValueGenerator, createObjectFactory, createRelationFactory } from '@dxos/schema/testing';
19
+ import { HasConnection, HasRelationship, Organization, Person, Pipeline } from '@dxos/types';
20
+
21
+ import { Graph } from '../../types';
22
+ import { ExplorerArticle, type ExplorerArticleVariant } from './ExplorerArticle';
23
+
24
+ const generator = random as any as ValueGenerator;
25
+
26
+ random.seed(7);
27
+
28
+ type DefaultStoryProps = { variant: ExplorerArticleVariant };
29
+
30
+ const DefaultStory = ({ variant }: DefaultStoryProps) => {
31
+ const [space] = useSpaces();
32
+ const [graph] = useQuery(space?.db, Filter.type(Graph.Graph));
33
+ if (!space || !graph) {
34
+ return <Loading data={{ space: !!space, graph: !!graph }} />;
35
+ }
36
+
37
+ return <ExplorerArticle role='article' subject={graph as any} attendableId={graph.id} variant={variant} />;
38
+ };
39
+
40
+ const meta: Meta<DefaultStoryProps> = {
41
+ title: 'plugins/plugin-explorer/containers/ExplorerArticle',
42
+ render: DefaultStory,
43
+ decorators: [
44
+ withTheme(),
45
+ withLayout({ layout: 'fullscreen' }),
46
+ withPluginManager({
47
+ plugins: [
48
+ ...corePlugins(),
49
+ StorybookPlugin({}),
50
+ ClientPlugin({
51
+ types: [
52
+ Graph.Graph,
53
+ HasRelationship.HasRelationship,
54
+ Organization.Organization,
55
+ Person.Person,
56
+ Pipeline.Pipeline,
57
+ View.View,
58
+ ],
59
+ onClientInitialized: ({ client }) =>
60
+ Effect.gen(function* () {
61
+ const { personalSpace } = yield* initializeIdentity(client);
62
+ yield* Effect.promise(() =>
63
+ createObjectFactory(
64
+ personalSpace.db,
65
+ generator,
66
+ )([
67
+ { type: Organization.Organization, count: 20 },
68
+ { type: Person.Person, count: 30 },
69
+ { type: Pipeline.Pipeline, count: 10 },
70
+ ]),
71
+ );
72
+ // Denser HasRelationship graph so the plexus variant shows multiple relation
73
+ // groups (organization ref + relationships) fanning out from a focused person.
74
+ yield* Effect.promise(() =>
75
+ createRelationFactory(
76
+ personalSpace.db,
77
+ generator,
78
+ )([
79
+ { type: HasRelationship.HasRelationship, count: 40, data: { kind: 'friend' } },
80
+ { type: HasConnection.HasConnection, count: 20, data: { kind: 'vendor' } },
81
+ ]),
82
+ );
83
+
84
+ const { view } = yield* Effect.promise(() =>
85
+ ViewModel.makeFromDatabase({
86
+ db: personalSpace.db,
87
+ typename: Type.getTypename(Graph.Graph),
88
+ }),
89
+ );
90
+
91
+ const graph = personalSpace.db.add(
92
+ Graph.make({
93
+ name: 'Root',
94
+ view,
95
+ query: {
96
+ ast: Query.select(Filter.everything()).ast,
97
+ },
98
+ }),
99
+ );
100
+
101
+ yield* Effect.promise(() => personalSpace.db.flush({ indexes: true }));
102
+ return graph;
103
+ }),
104
+ }),
105
+ PreviewPlugin(),
106
+ ],
107
+ }),
108
+ ],
109
+ parameters: {
110
+ layout: 'fullscreen',
111
+ },
112
+ };
113
+
114
+ export default meta;
115
+
116
+ type Story = StoryObj<typeof meta>;
117
+
118
+ export const Force: Story = {
119
+ args: {
120
+ variant: 'force',
121
+ },
122
+ };
123
+
124
+ export const Cluster: Story = {
125
+ args: {
126
+ variant: 'cluster',
127
+ },
128
+ };
129
+
130
+ export const Bundle: Story = {
131
+ args: {
132
+ variant: 'bundle',
133
+ },
134
+ };
135
+
136
+ export const Plexus: Story = {
137
+ args: {
138
+ variant: 'plexus',
139
+ },
140
+ };
141
+
142
+ export const Lattice: Story = {
143
+ args: {
144
+ variant: 'lattice',
145
+ },
146
+ };
147
+
148
+ export const Swarm: Story = {
149
+ args: {
150
+ variant: 'swarm',
151
+ },
152
+ };
@@ -0,0 +1,120 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
6
+
7
+ import { type AppSurface } from '@dxos/app-toolkit/ui';
8
+ import { type Filter, Obj, type View } from '@dxos/echo';
9
+ import { QueryBuilder } from '@dxos/echo-query';
10
+ import { useObject } from '@dxos/react-client/echo';
11
+ import { DxAnchorActivate, Icon, Panel, Toolbar } from '@dxos/react-ui';
12
+ import { QueryEditor, type QueryEditorProps } from '@dxos/react-ui-components';
13
+ import '@dxos/react-ui-graph/styles/graph.css';
14
+
15
+ import { type TreeNode } from '#components';
16
+ import { useGraphModel } from '#hooks';
17
+
18
+ import { type ExplorerArticleVariant, VARIANTS, isVariant } from './variants';
19
+ import { Visualization } from './Visualization';
20
+
21
+ export type { ExplorerArticleVariant } from './variants';
22
+
23
+ export type ExplorerArticleProps = AppSurface.ObjectArticleProps<View.View>;
24
+
25
+ export const ExplorerArticle = ({ role, subject, variant }: ExplorerArticleProps) => {
26
+ const [view] = useObject(subject);
27
+ const [filter, setFilter] = useState<Filter.Any>();
28
+
29
+ const db = view && Obj.getDatabase(view);
30
+ const model = useGraphModel(db, filter);
31
+
32
+ const builder = useMemo(() => new QueryBuilder(), []);
33
+ const handleChange = useCallback<NonNullable<QueryEditorProps['onChange']>>(
34
+ (value) => {
35
+ setFilter(builder.build(value).filter);
36
+ },
37
+ [builder],
38
+ );
39
+
40
+ const [selected, setSelected] = useState<ExplorerArticleVariant>(isVariant(variant) ? variant : 'force');
41
+ useEffect(() => {
42
+ if (isVariant(variant)) {
43
+ setSelected(variant);
44
+ }
45
+ }, [variant]);
46
+
47
+ const handleVariantChange = useCallback((value: string) => {
48
+ if (isVariant(value)) {
49
+ setSelected(value);
50
+ }
51
+ }, []);
52
+
53
+ // Dismiss the preview popover. The dxn/label/trigger fields are placeholders ignored on
54
+ // `state: false`.
55
+ const handleDismiss = useCallback(() => {
56
+ document.defaultView?.dispatchEvent(
57
+ new DxAnchorActivate({ dxn: '', label: '', trigger: document.body, state: false }),
58
+ );
59
+ }, []);
60
+
61
+ const handleHover = useCallback((node: TreeNode | null, event?: MouseEvent) => {
62
+ // Pointer left the node/label: keep the popover open so it can be hovered/interacted with.
63
+ // The popover is dismissed only on an explicit click on the component surface (handleDismiss).
64
+ if (!node || !event) {
65
+ return;
66
+ }
67
+ const obj = node.data;
68
+ if (!obj || !Obj.isObject(obj)) {
69
+ return;
70
+ }
71
+ const dxn = Obj.getURI(obj);
72
+ if (!dxn) {
73
+ return;
74
+ }
75
+
76
+ const target = event.target as HTMLElement;
77
+ target.dispatchEvent(
78
+ new DxAnchorActivate({
79
+ dxn,
80
+ kind: 'card',
81
+ trigger: target,
82
+ label: Obj.getLabel(obj) ?? dxn,
83
+ }),
84
+ );
85
+ }, []);
86
+
87
+ const showToolbar = role === 'article';
88
+
89
+ if (!db || !model) {
90
+ return null;
91
+ }
92
+
93
+ return (
94
+ <Panel.Root role={role}>
95
+ {showToolbar && (
96
+ <Panel.Toolbar asChild>
97
+ <Toolbar.Root>
98
+ <QueryEditor db={db} onChange={handleChange} />
99
+ <Toolbar.ToggleGroup type='single' value={selected} onValueChange={handleVariantChange}>
100
+ {VARIANTS.map(({ value, icon, label }) => (
101
+ <Toolbar.ToggleGroupItem key={value} value={value} aria-label={label} title={label}>
102
+ <Icon icon={icon} size={4} />
103
+ </Toolbar.ToggleGroupItem>
104
+ ))}
105
+ </Toolbar.ToggleGroup>
106
+ </Toolbar.Root>
107
+ </Panel.Toolbar>
108
+ )}
109
+ <Panel.Content>
110
+ <Visualization
111
+ classNames='bg-base-surface'
112
+ variant={selected}
113
+ model={model}
114
+ onNodeHover={handleHover}
115
+ onSurfaceClick={handleDismiss}
116
+ />
117
+ </Panel.Content>
118
+ </Panel.Root>
119
+ );
120
+ };