@dxos/plugin-explorer 0.8.4-main.7ace549 → 0.8.4-main.8baae0fced

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 (264) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/neutral/ExplorerArticle-EAKRB55W.mjs +277 -0
  3. package/dist/lib/neutral/ExplorerArticle-EAKRB55W.mjs.map +7 -0
  4. package/dist/lib/neutral/ExplorerPlugin.mjs +10 -0
  5. package/dist/lib/neutral/capabilities/index.mjs +11 -0
  6. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  7. package/dist/lib/neutral/chunk-7SPMPHRS.mjs +72 -0
  8. package/dist/lib/neutral/chunk-7SPMPHRS.mjs.map +7 -0
  9. package/dist/lib/{browser/chunk-UBHZGWZQ.mjs → neutral/chunk-DXIWQFYO.mjs} +3 -5
  10. package/dist/lib/neutral/chunk-DXIWQFYO.mjs.map +7 -0
  11. package/dist/lib/neutral/chunk-EM2BV4PF.mjs +290 -0
  12. package/dist/lib/neutral/chunk-EM2BV4PF.mjs.map +7 -0
  13. package/dist/lib/neutral/chunk-GRJXLL4Z.mjs +25 -0
  14. package/dist/lib/neutral/chunk-GRJXLL4Z.mjs.map +7 -0
  15. package/dist/lib/neutral/chunk-V2OFO6PI.mjs +14 -0
  16. package/dist/lib/neutral/chunk-V2OFO6PI.mjs.map +7 -0
  17. package/dist/lib/{browser/chunk-ARBGXQFH.mjs → neutral/components/index.mjs} +858 -307
  18. package/dist/lib/neutral/components/index.mjs.map +7 -0
  19. package/dist/lib/neutral/containers/index.mjs +9 -0
  20. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  21. package/dist/lib/neutral/create-object-F6TKVAGV.mjs +39 -0
  22. package/dist/lib/neutral/create-object-F6TKVAGV.mjs.map +7 -0
  23. package/dist/lib/neutral/hooks/index.mjs +45 -0
  24. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  25. package/dist/lib/neutral/index.mjs +14 -0
  26. package/dist/lib/neutral/meta.json +1 -0
  27. package/dist/lib/{browser → neutral}/meta.mjs +1 -1
  28. package/dist/lib/neutral/plugin.mjs +12 -0
  29. package/dist/lib/neutral/plugin.mjs.map +7 -0
  30. package/dist/lib/neutral/react-surface-APBW2VQG.mjs +26 -0
  31. package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +7 -0
  32. package/dist/lib/neutral/testing/index.mjs +193 -0
  33. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  34. package/dist/lib/neutral/translations.mjs +33 -0
  35. package/dist/lib/neutral/translations.mjs.map +7 -0
  36. package/dist/lib/{browser → neutral}/types/index.mjs +1 -2
  37. package/dist/types/data/cities.d.ts +4 -4
  38. package/dist/types/data/cities.d.ts.map +1 -1
  39. package/dist/types/data/countries-110m.d.ts +19 -22
  40. package/dist/types/data/countries-110m.d.ts.map +1 -1
  41. package/dist/types/src/ExplorerPlugin.d.ts +3 -1
  42. package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
  43. package/dist/types/src/ExplorerPlugin.test.d.ts +2 -0
  44. package/dist/types/src/ExplorerPlugin.test.d.ts.map +1 -0
  45. package/dist/types/src/capabilities/create-object.d.ts +11 -0
  46. package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
  47. package/dist/types/src/capabilities/index.d.ts +8 -2
  48. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  49. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  50. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  51. package/dist/types/src/components/Chart/Chart.d.ts +1 -1
  52. package/dist/types/src/components/Chart/Chart.d.ts.map +1 -1
  53. package/dist/types/src/components/Chart/Chart.stories.d.ts +4 -1
  54. package/dist/types/src/components/Chart/Chart.stories.d.ts.map +1 -1
  55. package/dist/types/src/components/Globe/Globe.d.ts +1 -1
  56. package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
  57. package/dist/types/src/components/Globe/Globe.stories.d.ts +5 -2
  58. package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
  59. package/dist/types/src/components/Graph/CanvasForceGraph.d.ts +13 -0
  60. package/dist/types/src/components/Graph/CanvasForceGraph.d.ts.map +1 -0
  61. package/dist/types/src/components/Graph/CanvasForceGraph.stories.d.ts +17 -0
  62. package/dist/types/src/components/Graph/CanvasForceGraph.stories.d.ts.map +1 -0
  63. package/dist/types/src/components/Graph/ForceGraph.d.ts +12 -5
  64. package/dist/types/src/components/Graph/ForceGraph.d.ts.map +1 -1
  65. package/dist/types/src/components/Graph/ForceGraph.stories.d.ts +4 -2
  66. package/dist/types/src/components/Graph/ForceGraph.stories.d.ts.map +1 -1
  67. package/dist/types/src/components/Graph/{adapter.d.ts → graph-adapter.d.ts} +2 -2
  68. package/dist/types/src/components/Graph/graph-adapter.d.ts.map +1 -0
  69. package/dist/types/src/components/Graph/index.d.ts +1 -1
  70. package/dist/types/src/components/Graph/index.d.ts.map +1 -1
  71. package/dist/types/src/components/Lattice/Lattice.d.ts +20 -0
  72. package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -0
  73. package/dist/types/src/components/Lattice/Lattice.stories.d.ts +8 -0
  74. package/dist/types/src/components/Lattice/Lattice.stories.d.ts.map +1 -0
  75. package/dist/types/src/components/Lattice/index.d.ts +2 -0
  76. package/dist/types/src/components/Lattice/index.d.ts.map +1 -0
  77. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +21 -0
  78. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -0
  79. package/dist/types/src/components/Tree/Tree.d.ts +20 -23
  80. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  81. package/dist/types/src/components/Tree/Tree.stories.d.ts +5 -12
  82. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  83. package/dist/types/src/components/Tree/index.d.ts +2 -0
  84. package/dist/types/src/components/Tree/index.d.ts.map +1 -1
  85. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +37 -2
  86. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +1 -1
  87. package/dist/types/src/components/Tree/layout/RadialTree.d.ts +35 -2
  88. package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +1 -1
  89. package/dist/types/src/components/Tree/layout/TidyTree.d.ts +24 -2
  90. package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +1 -1
  91. package/dist/types/src/components/Tree/layout/hierarchy.d.ts +17 -0
  92. package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +1 -0
  93. package/dist/types/src/components/Tree/layout/index.d.ts +5 -4
  94. package/dist/types/src/components/Tree/layout/index.d.ts.map +1 -1
  95. package/dist/types/src/components/Tree/layout/slots.d.ts +7 -0
  96. package/dist/types/src/components/Tree/layout/slots.d.ts.map +1 -0
  97. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +15 -0
  98. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +1 -0
  99. package/dist/types/src/components/Tree/types/tree.d.ts +18 -16
  100. package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
  101. package/dist/types/src/components/Tree/types/types.d.ts +14 -4
  102. package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
  103. package/dist/types/src/components/index.d.ts +1 -2
  104. package/dist/types/src/components/index.d.ts.map +1 -1
  105. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts +9 -0
  106. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -0
  107. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +29 -0
  108. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -0
  109. package/dist/types/src/containers/ExplorerArticle/experimental.stories.d.ts +7 -0
  110. package/dist/types/src/containers/ExplorerArticle/experimental.stories.d.ts.map +1 -0
  111. package/dist/types/src/containers/ExplorerArticle/index.d.ts +2 -0
  112. package/dist/types/src/containers/ExplorerArticle/index.d.ts.map +1 -0
  113. package/dist/types/src/containers/index.d.ts +3 -0
  114. package/dist/types/src/containers/index.d.ts.map +1 -0
  115. package/dist/types/src/hooks/useGraphModel.d.ts +2 -2
  116. package/dist/types/src/hooks/useGraphModel.d.ts.map +1 -1
  117. package/dist/types/src/index.d.ts +1 -3
  118. package/dist/types/src/index.d.ts.map +1 -1
  119. package/dist/types/src/meta.d.ts +2 -2
  120. package/dist/types/src/meta.d.ts.map +1 -1
  121. package/dist/types/src/plugin.d.ts +3 -0
  122. package/dist/types/src/plugin.d.ts.map +1 -0
  123. package/dist/types/src/{components/Tree/testing → testing}/generator.d.ts +1 -1
  124. package/dist/types/src/testing/generator.d.ts.map +1 -0
  125. package/dist/types/src/testing/index.d.ts +4 -0
  126. package/dist/types/src/testing/index.d.ts.map +1 -0
  127. package/dist/types/src/testing/relations.d.ts +47 -0
  128. package/dist/types/src/testing/relations.d.ts.map +1 -0
  129. package/dist/types/src/translations.d.ts +29 -28
  130. package/dist/types/src/translations.d.ts.map +1 -1
  131. package/dist/types/src/types/ExplorerAction.d.ts +0 -17
  132. package/dist/types/src/types/ExplorerAction.d.ts.map +1 -1
  133. package/dist/types/src/types/Graph.d.ts +10 -20
  134. package/dist/types/src/types/Graph.d.ts.map +1 -1
  135. package/dist/types/src/util/index.d.ts +3 -0
  136. package/dist/types/src/util/index.d.ts.map +1 -0
  137. package/dist/types/src/util/node-color.d.ts +13 -0
  138. package/dist/types/src/util/node-color.d.ts.map +1 -0
  139. package/dist/types/src/{components → util}/plot.d.ts +1 -1
  140. package/dist/types/src/util/plot.d.ts.map +1 -0
  141. package/dist/types/tsconfig.tsbuildinfo +1 -1
  142. package/package.json +113 -62
  143. package/src/ExplorerPlugin.test.ts +26 -0
  144. package/src/ExplorerPlugin.tsx +15 -45
  145. package/src/capabilities/create-object.ts +36 -0
  146. package/src/capabilities/index.ts +3 -3
  147. package/src/capabilities/react-surface.tsx +24 -18
  148. package/src/components/Chart/Chart.stories.tsx +16 -23
  149. package/src/components/Chart/Chart.tsx +1 -1
  150. package/src/components/Globe/Globe.stories.tsx +19 -22
  151. package/src/components/Globe/Globe.tsx +1 -1
  152. package/src/components/Graph/CanvasForceGraph.stories.tsx +83 -0
  153. package/src/components/Graph/CanvasForceGraph.tsx +124 -0
  154. package/src/components/Graph/ForceGraph.stories.tsx +83 -44
  155. package/src/components/Graph/ForceGraph.tsx +104 -85
  156. package/src/components/Graph/{adapter.ts → graph-adapter.ts} +14 -8
  157. package/src/components/Graph/index.ts +1 -1
  158. package/src/components/Lattice/Lattice.stories.tsx +90 -0
  159. package/src/components/Lattice/Lattice.tsx +182 -0
  160. package/src/components/Lattice/index.ts +5 -0
  161. package/src/components/Tree/EdgeBundling.stories.tsx +144 -0
  162. package/src/components/Tree/Tree.stories.tsx +20 -38
  163. package/src/components/Tree/Tree.tsx +69 -95
  164. package/src/components/Tree/index.ts +2 -0
  165. package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +296 -0
  166. package/src/components/Tree/layout/RadialTree.tsx +242 -0
  167. package/src/components/Tree/layout/TidyTree.tsx +246 -0
  168. package/src/components/Tree/layout/hierarchy.ts +32 -0
  169. package/src/components/Tree/layout/index.ts +5 -5
  170. package/src/components/Tree/layout/slots.ts +19 -0
  171. package/src/components/Tree/layout/useContainerSize.ts +43 -0
  172. package/src/components/Tree/types/tree.test.ts +6 -5
  173. package/src/components/Tree/types/tree.ts +41 -20
  174. package/src/components/Tree/types/types.ts +38 -29
  175. package/src/components/index.ts +1 -4
  176. package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +136 -0
  177. package/src/containers/ExplorerArticle/ExplorerArticle.tsx +465 -0
  178. package/src/containers/ExplorerArticle/experimental.stories.tsx +446 -0
  179. package/src/containers/ExplorerArticle/index.ts +5 -0
  180. package/src/containers/index.ts +7 -0
  181. package/src/hooks/useGraphModel.ts +25 -14
  182. package/src/index.ts +1 -4
  183. package/src/meta.ts +4 -4
  184. package/src/plugin.ts +9 -0
  185. package/src/{components/Tree/testing → testing}/generator.ts +5 -3
  186. package/src/testing/index.ts +9 -0
  187. package/src/testing/relations.ts +192 -0
  188. package/src/translations.ts +14 -13
  189. package/src/types/ExplorerAction.ts +1 -18
  190. package/src/types/Graph.ts +13 -28
  191. package/src/typings.d.ts +8 -0
  192. package/src/util/index.ts +6 -0
  193. package/src/util/node-color.ts +23 -0
  194. package/src/{components → util}/plot.ts +16 -4
  195. package/dist/lib/browser/ExplorerContainer-NOLLVUTE.mjs +0 -50
  196. package/dist/lib/browser/ExplorerContainer-NOLLVUTE.mjs.map +0 -7
  197. package/dist/lib/browser/chunk-2MKBRIUT.mjs +0 -31
  198. package/dist/lib/browser/chunk-2MKBRIUT.mjs.map +0 -7
  199. package/dist/lib/browser/chunk-6BVXZQPP.mjs +0 -188
  200. package/dist/lib/browser/chunk-6BVXZQPP.mjs.map +0 -7
  201. package/dist/lib/browser/chunk-ARBGXQFH.mjs.map +0 -7
  202. package/dist/lib/browser/chunk-P6FFFVPM.mjs +0 -100
  203. package/dist/lib/browser/chunk-P6FFFVPM.mjs.map +0 -7
  204. package/dist/lib/browser/chunk-UBHZGWZQ.mjs.map +0 -7
  205. package/dist/lib/browser/index.mjs +0 -112
  206. package/dist/lib/browser/index.mjs.map +0 -7
  207. package/dist/lib/browser/intent-resolver-EWB3H5KH.mjs +0 -35
  208. package/dist/lib/browser/intent-resolver-EWB3H5KH.mjs.map +0 -7
  209. package/dist/lib/browser/meta.json +0 -1
  210. package/dist/lib/browser/react-surface-BY2DYCTH.mjs +0 -34
  211. package/dist/lib/browser/react-surface-BY2DYCTH.mjs.map +0 -7
  212. package/dist/lib/node-esm/ExplorerContainer-N3S5KSUX.mjs +0 -51
  213. package/dist/lib/node-esm/ExplorerContainer-N3S5KSUX.mjs.map +0 -7
  214. package/dist/lib/node-esm/chunk-3ODK27PU.mjs +0 -33
  215. package/dist/lib/node-esm/chunk-3ODK27PU.mjs.map +0 -7
  216. package/dist/lib/node-esm/chunk-4BY2XZET.mjs +0 -101
  217. package/dist/lib/node-esm/chunk-4BY2XZET.mjs.map +0 -7
  218. package/dist/lib/node-esm/chunk-CRSVAZNA.mjs +0 -190
  219. package/dist/lib/node-esm/chunk-CRSVAZNA.mjs.map +0 -7
  220. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  221. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-NPIP4VEH.mjs +0 -11091
  223. package/dist/lib/node-esm/chunk-NPIP4VEH.mjs.map +0 -7
  224. package/dist/lib/node-esm/chunk-UXZM5VJB.mjs +0 -26
  225. package/dist/lib/node-esm/chunk-UXZM5VJB.mjs.map +0 -7
  226. package/dist/lib/node-esm/index.mjs +0 -113
  227. package/dist/lib/node-esm/index.mjs.map +0 -7
  228. package/dist/lib/node-esm/intent-resolver-SH6PW7VF.mjs +0 -36
  229. package/dist/lib/node-esm/intent-resolver-SH6PW7VF.mjs.map +0 -7
  230. package/dist/lib/node-esm/meta.json +0 -1
  231. package/dist/lib/node-esm/meta.mjs +0 -9
  232. package/dist/lib/node-esm/react-surface-7AAV7GBG.mjs +0 -35
  233. package/dist/lib/node-esm/react-surface-7AAV7GBG.mjs.map +0 -7
  234. package/dist/lib/node-esm/types/index.mjs +0 -12
  235. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  236. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  237. package/dist/types/src/components/ExplorerContainer.d.ts +0 -9
  238. package/dist/types/src/components/ExplorerContainer.d.ts.map +0 -1
  239. package/dist/types/src/components/Graph/D3ForceGraph.d.ts +0 -14
  240. package/dist/types/src/components/Graph/D3ForceGraph.d.ts.map +0 -1
  241. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts +0 -15
  242. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts.map +0 -1
  243. package/dist/types/src/components/Graph/adapter.d.ts.map +0 -1
  244. package/dist/types/src/components/Graph/testing.d.ts +0 -14
  245. package/dist/types/src/components/Graph/testing.d.ts.map +0 -1
  246. package/dist/types/src/components/Tree/testing/generator.d.ts.map +0 -1
  247. package/dist/types/src/components/Tree/testing/index.d.ts +0 -2
  248. package/dist/types/src/components/Tree/testing/index.d.ts.map +0 -1
  249. package/dist/types/src/components/plot.d.ts.map +0 -1
  250. package/src/capabilities/intent-resolver.ts +0 -23
  251. package/src/components/ExplorerContainer.tsx +0 -54
  252. package/src/components/Graph/D3ForceGraph.stories.tsx +0 -80
  253. package/src/components/Graph/D3ForceGraph.tsx +0 -101
  254. package/src/components/Graph/testing.ts +0 -55
  255. package/src/components/Tree/layout/HierarchicalEdgeBundling.ts +0 -162
  256. package/src/components/Tree/layout/RadialTree.ts +0 -94
  257. package/src/components/Tree/layout/TidyTree.ts +0 -101
  258. package/src/components/Tree/testing/index.ts +0 -5
  259. /package/dist/lib/{browser/chunk-J5LGTIGS.mjs.map → neutral/ExplorerPlugin.mjs.map} +0 -0
  260. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
  261. /package/dist/lib/{browser/meta.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
  262. /package/dist/lib/{browser/types → neutral}/index.mjs.map +0 -0
  263. /package/dist/lib/{node-esm → neutral}/meta.mjs.map +0 -0
  264. /package/dist/lib/{node-esm → neutral}/types/index.mjs.map +0 -0
@@ -1,10 +1,17 @@
1
+ import {
2
+ treeTypeToTreeNode
3
+ } from "../chunk-EM2BV4PF.mjs";
4
+ import {
5
+ getNodeFillForObject
6
+ } from "../chunk-V2OFO6PI.mjs";
7
+ import "../chunk-J5LGTIGS.mjs";
8
+
1
9
  // src/components/Chart/Chart.tsx
2
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
3
10
  import * as Plot from "@observablehq/plot";
4
11
  import React, { useEffect } from "react";
5
12
  import { useResizeDetector } from "react-resize-detector";
6
13
 
7
- // src/components/plot.ts
14
+ // src/util/plot.ts
8
15
  var createAdapter = (prop, accessor) => accessor ? {
9
16
  transform: (values) => values.map((value) => accessor(value)[prop])
10
17
  } : prop;
@@ -17,49 +24,43 @@ var defaultOptions = {
17
24
  fillOpacity: 0.2
18
25
  };
19
26
  var Chart = ({ items = [], accessor, options = defaultOptions }) => {
20
- var _effect = _useSignals();
21
- try {
22
- const { ref: containerRef, width = 0, height = 0 } = useResizeDetector({
23
- refreshRate: 200
24
- });
25
- useEffect(() => {
26
- if (!width || !height) {
27
- return;
28
- }
29
- const plot3 = Plot.plot({
30
- grid: true,
31
- width,
32
- height,
33
- style: {
34
- background: "transparent"
35
- },
36
- marks: [
37
- Plot.frame(),
38
- Plot.dot(items, {
39
- x: createAdapter("x", accessor),
40
- y: createAdapter("y", accessor),
41
- ...options
42
- })
43
- ]
44
- });
45
- containerRef.current.append(plot3);
46
- return () => plot3?.remove();
47
- }, [
48
- items,
27
+ const { ref: containerRef, width = 0, height = 0 } = useResizeDetector({
28
+ refreshRate: 200
29
+ });
30
+ useEffect(() => {
31
+ if (!width || !height) {
32
+ return;
33
+ }
34
+ const plot3 = Plot.plot({
35
+ grid: true,
49
36
  width,
50
- height
51
- ]);
52
- return /* @__PURE__ */ React.createElement("div", {
53
- ref: containerRef,
54
- className: "grow"
37
+ height,
38
+ style: {
39
+ background: "transparent"
40
+ },
41
+ marks: [
42
+ Plot.frame(),
43
+ Plot.dot(items, {
44
+ x: createAdapter("x", accessor),
45
+ y: createAdapter("y", accessor),
46
+ ...options
47
+ })
48
+ ]
55
49
  });
56
- } finally {
57
- _effect.f();
58
- }
50
+ containerRef.current.append(plot3);
51
+ return () => plot3?.remove();
52
+ }, [
53
+ items,
54
+ width,
55
+ height
56
+ ]);
57
+ return /* @__PURE__ */ React.createElement("div", {
58
+ ref: containerRef,
59
+ className: "grow"
60
+ });
59
61
  };
60
62
 
61
63
  // src/components/Globe/Globe.tsx
62
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
63
64
  import * as Plot2 from "@observablehq/plot";
64
65
  import React2, { useEffect as useEffect2 } from "react";
65
66
  import { useResizeDetector as useResizeDetector2 } from "react-resize-detector";
@@ -10773,180 +10774,764 @@ var defaultOptions2 = {
10773
10774
  fill: "#003300"
10774
10775
  };
10775
10776
  var Globe = ({ items = [], accessor, projection = "orthographic", options = defaultOptions2 }) => {
10776
- var _effect = _useSignals2();
10777
- try {
10778
- const { ref: containerRef, width = 0, height = 0 } = useResizeDetector2({
10779
- refreshRate: 200
10777
+ const { ref: containerRef, width = 0, height = 0 } = useResizeDetector2({
10778
+ refreshRate: 200
10779
+ });
10780
+ const land = topojson.feature(countries_110m_default, countries_110m_default.objects.land);
10781
+ useEffect2(() => {
10782
+ if (!width || !height) {
10783
+ return;
10784
+ }
10785
+ const plot3 = Plot2.plot({
10786
+ // https://observablehq.com/plot/features/projections
10787
+ projection: {
10788
+ type: projection,
10789
+ rotate: [
10790
+ -100,
10791
+ -20
10792
+ ]
10793
+ },
10794
+ // projection: { type: 'equirectangular', rotate: [-140, -30] },
10795
+ width,
10796
+ height,
10797
+ style: {
10798
+ background: "transparent"
10799
+ },
10800
+ // TODO(burdon): Create simple wrapper for Plot with good defaults.
10801
+ marks: [
10802
+ Plot2.sphere({
10803
+ fill: "lightblue",
10804
+ fillOpacity: 0.5
10805
+ }),
10806
+ Plot2.geo(land, {
10807
+ fill: "darkgreen",
10808
+ fillOpacity: 0.5
10809
+ }),
10810
+ Plot2.graticule(),
10811
+ Plot2.dot(items, {
10812
+ x: createAdapter("lat", accessor),
10813
+ y: createAdapter("lng", accessor),
10814
+ ...options
10815
+ })
10816
+ ]
10817
+ });
10818
+ containerRef.current.append(plot3);
10819
+ return () => plot3?.remove();
10820
+ }, [
10821
+ items,
10822
+ width,
10823
+ height
10824
+ ]);
10825
+ return /* @__PURE__ */ React2.createElement("div", {
10826
+ ref: containerRef,
10827
+ className: "grow p-4"
10828
+ });
10829
+ };
10830
+
10831
+ // src/components/Graph/CanvasForceGraph.tsx
10832
+ import { forceLink, forceManyBody } from "d3";
10833
+ import NativeForceGraph from "force-graph";
10834
+ import React3, { useCallback, useEffect as useEffect3, useRef, useState } from "react";
10835
+ import { useResizeDetector as useResizeDetector3 } from "react-resize-detector";
10836
+ import { composable, composableProps } from "@dxos/ui-theme";
10837
+
10838
+ // src/components/Graph/graph-adapter.ts
10839
+ var GraphAdapter = class {
10840
+ graph;
10841
+ _nodes = [];
10842
+ _links = [];
10843
+ constructor(graph) {
10844
+ this.graph = graph;
10845
+ this._nodes = graph.nodes.map((node) => ({
10846
+ id: node.id,
10847
+ type: node.type,
10848
+ data: node.data
10849
+ }));
10850
+ const nodeIds = new Set(this._nodes.map((node) => node.id));
10851
+ this._links = graph.edges.filter((edge) => nodeIds.has(edge.source) && nodeIds.has(edge.target)).map((edge) => ({
10852
+ type: edge.type,
10853
+ source: edge.source,
10854
+ target: edge.target,
10855
+ data: edge.data
10856
+ }));
10857
+ }
10858
+ get nodes() {
10859
+ return this._nodes;
10860
+ }
10861
+ get links() {
10862
+ return this._links;
10863
+ }
10864
+ };
10865
+
10866
+ // src/components/Graph/CanvasForceGraph.tsx
10867
+ var CanvasForceGraph = composable(({ model, match, onClick, ...props }, forwardedRef) => {
10868
+ const { ref: resizeRef, width, height } = useResizeDetector3({
10869
+ refreshRate: 200
10870
+ });
10871
+ const setRef = useCallback((node) => {
10872
+ resizeRef(node);
10873
+ assignRef(forwardedRef, node);
10874
+ }, [
10875
+ resizeRef,
10876
+ forwardedRef
10877
+ ]);
10878
+ const rootRef = useRef(null);
10879
+ const forceGraph = useRef(null);
10880
+ const [data, setData] = useState();
10881
+ useEffect3(() => {
10882
+ return model?.subscribe((model2) => setData(new GraphAdapter(model2.graph)));
10883
+ }, [
10884
+ model
10885
+ ]);
10886
+ useEffect3(() => {
10887
+ if (rootRef.current) {
10888
+ forceGraph.current = new NativeForceGraph(rootRef.current).nodeRelSize(6).nodeLabel((node) => node.type === "schema" ? node.data.typename : node.data.label ?? node.id).nodeAutoColorBy((node) => node.type === "schema" ? "schema" : node.data.typename).linkAutoColorBy((link) => link.type);
10889
+ }
10890
+ return () => {
10891
+ forceGraph.current?.pauseAnimation().graphData({
10892
+ nodes: [],
10893
+ links: []
10894
+ });
10895
+ forceGraph.current = null;
10896
+ };
10897
+ }, []);
10898
+ useEffect3(() => {
10899
+ if (!data || !width || !height || !forceGraph.current) {
10900
+ return;
10901
+ }
10902
+ forceGraph.current.pauseAnimation().width(width).height(height).onEngineStop(() => handleZoomToFit()).onNodeClick((node) => {
10903
+ forceGraph.current?.emitParticle(node);
10904
+ }).d3Force("link", forceLink().distance(160).strength(0.5)).d3Force("charge", forceManyBody().strength(-30)).graphData(data).warmupTicks(100).cooldownTime(1e3).resumeAnimation();
10905
+ }, [
10906
+ data,
10907
+ width,
10908
+ height
10909
+ ]);
10910
+ const handleZoomToFit = () => {
10911
+ forceGraph.current?.zoomToFit(400, 40);
10912
+ };
10913
+ const handleClick = useCallback((event) => {
10914
+ onClick?.(event);
10915
+ if (!event.defaultPrevented) {
10916
+ handleZoomToFit();
10917
+ }
10918
+ }, [
10919
+ onClick
10920
+ ]);
10921
+ return /* @__PURE__ */ React3.createElement("div", {
10922
+ ...composableProps(props, {
10923
+ classNames: "relative grow"
10924
+ }),
10925
+ onClick: handleClick,
10926
+ ref: setRef
10927
+ }, /* @__PURE__ */ React3.createElement("div", {
10928
+ ref: rootRef,
10929
+ className: "absolute inset-0"
10930
+ }));
10931
+ });
10932
+ var assignRef = (ref, value) => {
10933
+ if (typeof ref === "function") {
10934
+ ref(value);
10935
+ } else if (ref) {
10936
+ ref.current = value;
10937
+ }
10938
+ };
10939
+
10940
+ // src/components/Graph/ForceGraph.tsx
10941
+ import { Atom, useAtomValue } from "@effect-atom/atom-react";
10942
+ import React4, { useCallback as useCallback2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState2 } from "react";
10943
+ import { Obj } from "@dxos/echo";
10944
+ import { SelectionModel } from "@dxos/graph";
10945
+ import { GraphForceProjector, SVG } from "@dxos/react-ui-graph";
10946
+ import { composable as composable2, composableProps as composableProps2, getHashStyles } from "@dxos/ui-theme";
10947
+ import "@dxos/react-ui-graph/styles/graph.css";
10948
+ var EMPTY_ATOM = Atom.make({
10949
+ nodes: [],
10950
+ edges: []
10951
+ });
10952
+ var ForceGraph = composable2(({ model, selection: selectionProp, grid, drag, onInspect, ...props }, forwardedRef) => {
10953
+ useAtomValue(model?.graphAtom ?? EMPTY_ATOM);
10954
+ const graph = useRef2(null);
10955
+ const selection = useMemo(() => selectionProp ?? new SelectionModel(), [
10956
+ selectionProp
10957
+ ]);
10958
+ useEffect4(() => {
10959
+ const unsubscribe = selection.subscribe(() => graph.current?.repaint());
10960
+ return unsubscribe;
10961
+ }, [
10962
+ selection
10963
+ ]);
10964
+ const svgRef = useRef2(null);
10965
+ const [projector, setProjector] = useState2();
10966
+ useEffect4(() => {
10967
+ if (svgRef.current) {
10968
+ setProjector(new GraphForceProjector(svgRef.current, {
10969
+ attributes: {
10970
+ // TODO(burdon): Check type (currently assumes Employee property).
10971
+ // Edge shouldn't contribute to force if it's not active.
10972
+ linkForce: (edge) => edge.data?.object?.active !== false
10973
+ },
10974
+ forces: {
10975
+ point: {
10976
+ strength: 0.01
10977
+ }
10978
+ }
10979
+ }));
10980
+ }
10981
+ }, []);
10982
+ const handleSelect = useCallback2((node) => {
10983
+ if (selection.contains(node.id)) {
10984
+ selection.remove(node.id);
10985
+ } else {
10986
+ selection.add(node.id);
10987
+ }
10988
+ }, [
10989
+ selection
10990
+ ]);
10991
+ return /* @__PURE__ */ React4.createElement("div", {
10992
+ ...composableProps2(props, {
10993
+ classNames: "dx-container"
10994
+ }),
10995
+ ref: forwardedRef
10996
+ }, /* @__PURE__ */ React4.createElement(SVG.Root, {
10997
+ ref: svgRef
10998
+ }, /* @__PURE__ */ React4.createElement(SVG.Markers, null), grid && /* @__PURE__ */ React4.createElement(SVG.Grid, {
10999
+ axis: true
11000
+ }), /* @__PURE__ */ React4.createElement(SVG.Zoom, {
11001
+ extent: [
11002
+ 1 / 2,
11003
+ 2
11004
+ ]
11005
+ }, /* @__PURE__ */ React4.createElement(SVG.Graph, {
11006
+ ref: graph,
11007
+ drag,
11008
+ model,
11009
+ projector,
11010
+ labels: {
11011
+ text: (node) => node.data?.data.label ?? node.id
11012
+ },
11013
+ attributes: {
11014
+ node: (node) => {
11015
+ const obj = node.data?.data.object;
11016
+ return {
11017
+ data: {
11018
+ color: getHashStyles(obj && Obj.getTypename(obj))?.hue
11019
+ },
11020
+ classes: {
11021
+ "dx-selected": selection.contains(node.id)
11022
+ }
11023
+ };
11024
+ }
11025
+ },
11026
+ onSelect: handleSelect,
11027
+ onInspect
11028
+ }))));
11029
+ });
11030
+
11031
+ // src/components/Lattice/Lattice.tsx
11032
+ import { select } from "d3";
11033
+ import React5, { useEffect as useEffect6, useMemo as useMemo2, useRef as useRef3 } from "react";
11034
+ import { Obj as Obj2 } from "@dxos/echo";
11035
+
11036
+ // src/components/Tree/layout/useContainerSize.ts
11037
+ import { useEffect as useEffect5, useState as useState3 } from "react";
11038
+ var useContainerSize = () => {
11039
+ const [el, setEl] = useState3(null);
11040
+ const [size, setSize] = useState3({
11041
+ width: 0,
11042
+ height: 0
11043
+ });
11044
+ useEffect5(() => {
11045
+ if (!el) {
11046
+ return;
11047
+ }
11048
+ const rect = el.getBoundingClientRect();
11049
+ setSize({
11050
+ width: rect.width,
11051
+ height: rect.height
10780
11052
  });
10781
- const land = topojson.feature(countries_110m_default, countries_110m_default.objects.land);
10782
- useEffect2(() => {
10783
- if (!width || !height) {
11053
+ const observer = new ResizeObserver((entries) => {
11054
+ const entry = entries[0];
11055
+ if (!entry) {
10784
11056
  return;
10785
11057
  }
10786
- const plot3 = Plot2.plot({
10787
- // https://observablehq.com/plot/features/projections
10788
- projection: {
10789
- type: projection,
10790
- rotate: [
10791
- -100,
10792
- -20
10793
- ]
10794
- },
10795
- // projection: { type: 'equirectangular', rotate: [-140, -30] },
11058
+ const { width, height } = entry.contentRect;
11059
+ setSize((prev) => prev.width === width && prev.height === height ? prev : {
10796
11060
  width,
10797
- height,
10798
- style: {
10799
- background: "transparent"
10800
- },
10801
- // TODO(burdon): Create simple wrapper for Plot with good defaults.
10802
- marks: [
10803
- Plot2.sphere({
10804
- fill: "lightblue",
10805
- fillOpacity: 0.5
10806
- }),
10807
- Plot2.geo(land, {
10808
- fill: "darkgreen",
10809
- fillOpacity: 0.5
10810
- }),
10811
- Plot2.graticule(),
10812
- Plot2.dot(items, {
10813
- x: createAdapter("lat", accessor),
10814
- y: createAdapter("lng", accessor),
10815
- ...options
10816
- })
10817
- ]
11061
+ height
10818
11062
  });
10819
- containerRef.current.append(plot3);
10820
- return () => plot3?.remove();
10821
- }, [
10822
- items,
11063
+ });
11064
+ observer.observe(el);
11065
+ return () => observer.disconnect();
11066
+ }, [
11067
+ el
11068
+ ]);
11069
+ return {
11070
+ setRef: setEl,
11071
+ width: size.width,
11072
+ height: size.height
11073
+ };
11074
+ };
11075
+
11076
+ // src/components/Lattice/Lattice.tsx
11077
+ var TRANSITION_MS = 350;
11078
+ var Lattice = ({ nodes, padding = 16, onNodeHover }) => {
11079
+ const svgRef = useRef3(null);
11080
+ const { setRef, width, height } = useContainerSize();
11081
+ const cells = useMemo2(() => {
11082
+ return nodes.map((node) => {
11083
+ const object = node.data?.object;
11084
+ if (!object) {
11085
+ return void 0;
11086
+ }
11087
+ const label = node.data?.label ?? Obj2.getLabel(object) ?? node.id;
11088
+ const typename = Obj2.getTypename(object) ?? "(untyped)";
11089
+ return {
11090
+ id: node.id,
11091
+ label,
11092
+ typename,
11093
+ object
11094
+ };
11095
+ }).filter((cell) => cell !== void 0).sort((a, b) => a.typename.localeCompare(b.typename) || a.label.localeCompare(b.label));
11096
+ }, [
11097
+ nodes
11098
+ ]);
11099
+ const handleHoverRef = useRef3(void 0);
11100
+ handleHoverRef.current = onNodeHover;
11101
+ useEffect6(() => {
11102
+ if (!svgRef.current || !width || !height) {
11103
+ return;
11104
+ }
11105
+ renderLattice(svgRef.current, cells, {
10823
11106
  width,
10824
- height
10825
- ]);
10826
- return /* @__PURE__ */ React2.createElement("div", {
10827
- ref: containerRef,
10828
- className: "grow p-4"
11107
+ height,
11108
+ padding,
11109
+ onNodeHover: (n, e) => handleHoverRef.current?.(n, e)
10829
11110
  });
10830
- } finally {
10831
- _effect.f();
11111
+ return () => {
11112
+ handleHoverRef.current?.(null);
11113
+ };
11114
+ }, [
11115
+ cells,
11116
+ width,
11117
+ height,
11118
+ padding
11119
+ ]);
11120
+ return /* @__PURE__ */ React5.createElement("div", {
11121
+ ref: setRef,
11122
+ className: "dx-expander relative"
11123
+ }, width > 0 && height > 0 && /* @__PURE__ */ React5.createElement("svg", {
11124
+ ref: svgRef,
11125
+ xmlns: "http://www.w3.org/2000/svg",
11126
+ width,
11127
+ height,
11128
+ viewBox: `0 0 ${width} ${height}`
11129
+ }));
11130
+ };
11131
+ var renderLattice = (svgElement, cells, options) => {
11132
+ const { width, height, padding, onNodeHover } = options;
11133
+ const svg = select(svgElement);
11134
+ if (!cells.length) {
11135
+ onNodeHover(null);
11136
+ svg.selectAll("g.dx-lattice-root").remove();
11137
+ return;
10832
11138
  }
11139
+ const count = cells.length;
11140
+ const columns = Math.max(1, Math.ceil(Math.sqrt(count)));
11141
+ const rows = Math.ceil(count / columns);
11142
+ const innerW = Math.max(0, width - 2 * padding);
11143
+ const innerH = Math.max(0, height - 2 * padding);
11144
+ const cellSize = Math.max(0, Math.min(innerW / columns, innerH / rows));
11145
+ const gutter = Math.max(2, cellSize * 0.12);
11146
+ const rectSize = Math.max(0, cellSize - gutter);
11147
+ const radius = Math.max(2, rectSize * 0.18);
11148
+ const gridW = cellSize * columns;
11149
+ const gridH = cellSize * rows;
11150
+ const offsetX = (width - gridW) / 2;
11151
+ const offsetY = (height - gridH) / 2;
11152
+ const g = svg.selectAll("g.dx-lattice-root").data([
11153
+ null
11154
+ ]).join("g").classed("dx-lattice-root", true);
11155
+ const positioned = cells.map((cell, i) => ({
11156
+ ...cell,
11157
+ x: offsetX + i % columns * cellSize + gutter / 2,
11158
+ y: offsetY + Math.floor(i / columns) * cellSize + gutter / 2
11159
+ }));
11160
+ const node = g.selectAll("g.dx-lattice-cell").data(positioned, (d) => d.id).join((enter) => {
11161
+ const ge = enter.append("g").classed("dx-lattice-cell", true).attr("opacity", 0);
11162
+ ge.append("rect").style("cursor", "pointer");
11163
+ return ge;
11164
+ }, (update) => update, (exit) => exit.each(function() {
11165
+ select(this).interrupt();
11166
+ }).transition().duration(TRANSITION_MS).attr("opacity", 0).remove());
11167
+ node.transition().duration(TRANSITION_MS).attr("opacity", 1).attr("transform", (d) => `translate(${d.x},${d.y})`);
11168
+ node.select("rect").attr("width", rectSize).attr("height", rectSize).attr("rx", radius).attr("ry", radius).style("fill", (d) => getNodeFillForObject(d.object)).on("pointerenter", (event, d) => onNodeHover({
11169
+ id: d.id,
11170
+ label: d.label,
11171
+ data: d.object
11172
+ }, event)).on("pointerleave", () => onNodeHover(null));
10833
11173
  };
10834
11174
 
10835
11175
  // src/components/Tree/Tree.tsx
10836
- import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
10837
- import React3, { useEffect as useEffect3, useRef, useState } from "react";
10838
- import { useAsyncState } from "@dxos/react-ui";
10839
- import { SVG } from "@dxos/react-ui-graph";
10840
- import { SpaceGraphModel } from "@dxos/schema";
11176
+ import React9, { useMemo as useMemo6 } from "react";
10841
11177
 
10842
- // src/components/Tree/layout/HierarchicalEdgeBundling.ts
10843
- import { cluster, curveBundle, hierarchy, lineRadial, select } from "d3";
10844
- var HierarchicalEdgeBundling = (s, data, options) => {
10845
- const svg = select(s);
10846
- svg.selectAll("*").remove();
10847
- const { radius = 600, padding = 100, slots } = options;
10848
- const root = hierarchy(flatten(data));
10849
- const tree3 = cluster().size([
10850
- 2 * Math.PI,
10851
- radius - padding
11178
+ // src/components/Tree/layout/HierarchicalEdgeBundling.tsx
11179
+ import { cluster, curveBundle, hierarchy, lineRadial, select as select2 } from "d3";
11180
+ import React6, { useEffect as useEffect7, useMemo as useMemo3, useRef as useRef4 } from "react";
11181
+ import { mx } from "@dxos/ui-theme";
11182
+
11183
+ // src/components/Tree/layout/slots.ts
11184
+ var defaultTreeLayoutSlots = {
11185
+ // Cursor + transition so the hover swap reads clearly; SVG circles support the `:hover` pseudo-class
11186
+ // via Tailwind variants exactly like HTML elements.
11187
+ node: "fill-blue-600 hover:fill-orange-500 cursor-pointer transition-colors",
11188
+ // 0.5px is fine on a white background, but on a dark Storybook background the lines disappear.
11189
+ // Use stroke-1 with opacity 50% so they read in both themes; dx-bundle-dim/out/in further tune on hover.
11190
+ path: "fill-none stroke-blue-500/50 stroke-[1px] dark:stroke-blue-400/60",
11191
+ text: "fill-neutral-700 dark:fill-neutral-300 text-xs hover:fill-orange-500 cursor-pointer transition-colors"
11192
+ };
11193
+
11194
+ // src/components/Tree/layout/HierarchicalEdgeBundling.tsx
11195
+ var TRANSITION_MS2 = 350;
11196
+ var HierarchicalEdgeBundling = ({ classNames, data, edges = [], label = (d) => d.label ?? d.id, padding = 120, tension = 0.85, r = 4, slots = defaultTreeLayoutSlots, onNodeHover }) => {
11197
+ const svgRef = useRef4(null);
11198
+ const { setRef, width, height } = useContainerSize();
11199
+ const root = useMemo3(() => buildBundleHierarchy(data, edges), [
11200
+ data,
11201
+ edges
10852
11202
  ]);
10853
- const layout = tree3(addLinks(root));
10854
- const node = svg.append("g").selectAll().data(layout.leaves()).join("g").attr("transform", (d) => `rotate(${d.x * (180 / Math.PI) - 90}) translate(${d.y},0)`).append("text").attr("class", slots?.text ?? "").attr("dy", "0.31em").attr("x", (d) => d.x < Math.PI ? 6 : -6).attr("text-anchor", (d) => d.x < Math.PI ? "start" : "end").attr("transform", (d) => d.x >= Math.PI ? "rotate(180)" : null).call((text) => text.text((d) => d.data.id.slice(0, 8)));
10855
- const line = lineRadial().curve(curveBundle.beta(0.85)).radius((d) => d.y).angle((d) => d.x);
10856
- const links = svg.append("g").selectAll().data(layout.leaves().flatMap((leaf) => leaf.outgoing)).join("path").style("mix-blend-mode", "multiply").attr("class", slots?.path ?? "").attr("d", ([i, o]) => {
10857
- return line(i.path(o));
10858
- }).each(function(d) {
10859
- d.path = this;
11203
+ const handleHoverRef = useRef4(() => {
10860
11204
  });
10861
- };
10862
- var addLinks = (root) => {
10863
- const nodes = new Map(root.descendants().map((d) => [
10864
- d.data.id,
10865
- d
10866
- ]));
10867
- const parents = root.descendants().reduce((map, d) => {
10868
- if (d.children?.length) {
10869
- map.set(d.data.id, d);
11205
+ handleHoverRef.current = (node, event) => onNodeHover?.(node, event);
11206
+ useEffect7(() => {
11207
+ if (!svgRef.current || !width || !height) {
11208
+ return;
10870
11209
  }
10871
- return map;
10872
- }, /* @__PURE__ */ new Map());
10873
- for (const d of root.leaves()) {
10874
- const parent = parents.get(d.data.id);
10875
- if (parent) {
10876
- d.outgoing = parent.data.children?.slice(1).map((child) => {
10877
- return [
10878
- d,
10879
- nodes.get(child.id)
10880
- ];
10881
- }) ?? [];
10882
- } else {
10883
- d.outgoing = [];
11210
+ const radius = Math.max(0, Math.min(width, height) / 2 - padding);
11211
+ renderBundling(svgRef.current, root, {
11212
+ radius,
11213
+ r,
11214
+ label,
11215
+ slots,
11216
+ tension,
11217
+ onNodeHover: (n, e) => handleHoverRef.current(n, e)
11218
+ });
11219
+ }, [
11220
+ root,
11221
+ width,
11222
+ height,
11223
+ padding,
11224
+ tension,
11225
+ r,
11226
+ label,
11227
+ slots
11228
+ ]);
11229
+ return /* @__PURE__ */ React6.createElement("div", {
11230
+ ref: setRef,
11231
+ className: mx("dx-expander relative", classNames)
11232
+ }, width > 0 && height > 0 && /* @__PURE__ */ React6.createElement("svg", {
11233
+ ref: svgRef,
11234
+ xmlns: "http://www.w3.org/2000/svg",
11235
+ width,
11236
+ height,
11237
+ viewBox: `${-width / 2} ${-height / 2} ${width} ${height}`
11238
+ }));
11239
+ };
11240
+ var buildBundleHierarchy = (data, edges) => {
11241
+ const root = hierarchy(data);
11242
+ const byId = /* @__PURE__ */ new Map();
11243
+ for (const node of root.descendants()) {
11244
+ byId.set(node.data.id, node);
11245
+ node.outgoing = [];
11246
+ node.incoming = [];
11247
+ }
11248
+ for (const edge of edges) {
11249
+ const source = byId.get(edge.source);
11250
+ const target = byId.get(edge.target);
11251
+ if (!source || !target || source === target) {
11252
+ continue;
10884
11253
  }
11254
+ source.outgoing.push([
11255
+ source,
11256
+ target,
11257
+ edge
11258
+ ]);
11259
+ target.incoming.push([
11260
+ source,
11261
+ target,
11262
+ edge
11263
+ ]);
10885
11264
  }
10886
11265
  return root;
10887
11266
  };
10888
- var flatten = (node) => {
10889
- const clone = {
10890
- id: node.id
11267
+ var renderBundling = (svgElement, root, options) => {
11268
+ const { radius, r, tension, label, slots, onNodeHover } = options;
11269
+ const svg = select2(svgElement);
11270
+ if (!root.children?.length) {
11271
+ svg.selectAll("g.dx-bundle-root").remove();
11272
+ return;
11273
+ }
11274
+ cluster().size([
11275
+ 2 * Math.PI,
11276
+ radius
11277
+ ])(root);
11278
+ const g = svg.selectAll("g.dx-bundle-root").data([
11279
+ null
11280
+ ]).join("g").classed("dx-bundle-root", true);
11281
+ const linksLayer = g.selectAll("g.dx-bundle-links").data([
11282
+ null
11283
+ ]).join("g").classed("dx-bundle-links", true);
11284
+ const nodesLayer = g.selectAll("g.dx-bundle-nodes").data([
11285
+ null
11286
+ ]).join("g").classed("dx-bundle-nodes", true);
11287
+ const line = lineRadial().curve(curveBundle.beta(tension)).radius((d) => d.y).angle((d) => d.x);
11288
+ const leaves = root.leaves();
11289
+ const flatEdges = leaves.flatMap((leaf) => leaf.outgoing ?? []);
11290
+ const paths = linksLayer.selectAll("path").data(flatEdges, (d) => `${d[0].data.id}->${d[1].data.id}`).join((enter) => enter.append("path").attr("class", slots.path ?? "").attr("fill", "none").attr("opacity", 0), (update) => update, (exit) => exit.each(function() {
11291
+ select2(this).interrupt();
11292
+ }).transition().duration(TRANSITION_MS2).attr("opacity", 0).remove());
11293
+ paths.each(function(d) {
11294
+ d[0].pathEl = this;
11295
+ }).transition().duration(TRANSITION_MS2).attr("opacity", 1).attr("d", ([s, t]) => line(s.path(t)));
11296
+ const labels = nodesLayer.selectAll("g.dx-bundle-leaf").data(leaves, (d) => d.data.id).join((enter) => {
11297
+ const ge = enter.append("g").classed("dx-bundle-leaf", true).attr("opacity", 0);
11298
+ ge.append("circle").style("cursor", "pointer");
11299
+ ge.append("text").attr("dy", "0.32em").attr("paint-order", "stroke").style("cursor", "pointer");
11300
+ return ge;
11301
+ }, (update) => update, (exit) => exit.each(function() {
11302
+ select2(this).interrupt();
11303
+ }).transition().duration(TRANSITION_MS2).attr("opacity", 0).remove());
11304
+ labels.transition().duration(TRANSITION_MS2).attr("opacity", 1).attr("transform", (d) => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`);
11305
+ const onEnter = function(event, d) {
11306
+ onNodeHover(d.data, event);
11307
+ hover(linksLayer, leaves, d, true);
10891
11308
  };
10892
- if (node.children?.length) {
10893
- const children = node.children.map((child) => flatten(child));
10894
- clone.children = [
10895
- {
10896
- id: node.id
10897
- },
10898
- ...children
10899
- ];
11309
+ const onLeave = function(event, d) {
11310
+ onNodeHover(null);
11311
+ hover(linksLayer, leaves, d, false);
11312
+ };
11313
+ labels.select("circle").attr("class", [
11314
+ slots.node ?? "",
11315
+ "dx-leaf"
11316
+ ].filter(Boolean).join(" ")).attr("r", r).style("fill", (d) => getNodeFillForObject(d.data.data)).on("pointerenter", onEnter).on("pointerleave", onLeave);
11317
+ labels.select("text").attr("class", slots.text ?? "").attr("x", (d) => d.x < Math.PI ? r + 4 : -(r + 4)).attr("text-anchor", (d) => d.x < Math.PI ? "start" : "end").attr("transform", (d) => d.x >= Math.PI ? "rotate(180)" : null).each(function(d) {
11318
+ d.text = this;
11319
+ }).text((d) => label(d.data)).on("pointerenter", onEnter).on("pointerleave", onLeave);
11320
+ };
11321
+ var hover = (linksLayer, leaves, focused, on) => {
11322
+ const outgoing = new Set((focused.outgoing ?? []).map(([, t]) => t));
11323
+ const incoming = new Set((focused.incoming ?? []).map(([s]) => s));
11324
+ linksLayer.selectAll("path").classed("dx-bundle-out", (d) => on && d[0] === focused).classed("dx-bundle-in", (d) => on && d[1] === focused).classed("dx-bundle-dim", (d) => on && d[0] !== focused && d[1] !== focused);
11325
+ for (const leaf of leaves) {
11326
+ if (!leaf.text) {
11327
+ continue;
11328
+ }
11329
+ select2(leaf.text).classed("dx-bundle-focused", on && leaf === focused).classed("dx-bundle-out-text", on && outgoing.has(leaf)).classed("dx-bundle-in-text", on && incoming.has(leaf));
10900
11330
  }
10901
- return clone;
10902
11331
  };
10903
- var HierarchicalEdgeBundling_default = HierarchicalEdgeBundling;
10904
11332
 
10905
- // src/components/Tree/layout/RadialTree.ts
10906
- import { hierarchy as hierarchy2, linkRadial, select as select2, tree } from "d3";
10907
- var RadialTree = (s, data, options) => {
10908
- const svg = select2(s);
10909
- svg.selectAll("*").remove();
10910
- const { label, radius = 400, r = 4, slots } = options;
10911
- const arc = 2 * Math.PI;
10912
- const root = hierarchy2(data);
10913
- const descendants = root.descendants();
10914
- const getLabel = label === null ? null : descendants.map((d) => label(d.data));
10915
- const layout = tree().size([
10916
- arc,
11333
+ // src/components/Tree/layout/RadialTree.tsx
11334
+ import { cluster as d3Cluster, linkRadial, select as select3, tree as d3Tree } from "d3";
11335
+ import React7, { useCallback as useCallback3, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef5, useState as useState4 } from "react";
11336
+ import { mx as mx2 } from "@dxos/ui-theme";
11337
+
11338
+ // src/components/Tree/layout/hierarchy.ts
11339
+ import { hierarchy as d3Hierarchy } from "d3";
11340
+ var buildHierarchy = (data, collapsed = /* @__PURE__ */ new Set()) => {
11341
+ return d3Hierarchy(data, (d) => {
11342
+ if (!d.children?.length) {
11343
+ return void 0;
11344
+ }
11345
+ return collapsed.has(d.id) ? void 0 : d.children;
11346
+ });
11347
+ };
11348
+ var isCollapsed = (data, collapsed) => Boolean(data.children?.length) && collapsed.has(data.id);
11349
+ var isLeaf = (data) => !data.children?.length;
11350
+
11351
+ // src/components/Tree/layout/RadialTree.tsx
11352
+ var TRANSITION_MS3 = 350;
11353
+ var RadialTree = ({ classNames, data, label = (d) => d.label ?? d.id, slots = defaultTreeLayoutSlots, r = 4, padding = 80, initialCollapsed, cluster: cluster2 = false, onNodeClick, onNodeHover }) => {
11354
+ const svgRef = useRef5(null);
11355
+ const { setRef, width, height } = useContainerSize();
11356
+ const [collapsed, setCollapsed] = useState4(() => new Set(initialCollapsed ?? []));
11357
+ const toggle = useCallback3((id) => {
11358
+ setCollapsed((prev) => {
11359
+ const next = new Set(prev);
11360
+ if (next.has(id)) {
11361
+ next.delete(id);
11362
+ } else {
11363
+ next.add(id);
11364
+ }
11365
+ return next;
11366
+ });
11367
+ }, []);
11368
+ const handleClickRef = useRef5(() => {
11369
+ });
11370
+ handleClickRef.current = (node) => {
11371
+ onNodeClick?.(node);
11372
+ if (node.children?.length) {
11373
+ toggle(node.id);
11374
+ }
11375
+ };
11376
+ const handleHoverRef = useRef5(() => {
11377
+ });
11378
+ handleHoverRef.current = (node, event) => onNodeHover?.(node, event);
11379
+ const root = useMemo4(() => buildHierarchy(data, collapsed), [
11380
+ data,
11381
+ collapsed
11382
+ ]);
11383
+ useEffect8(() => {
11384
+ if (!svgRef.current || !width || !height) {
11385
+ return;
11386
+ }
11387
+ const radius = Math.max(0, Math.min(width, height) / 2 - padding);
11388
+ renderRadialTree(svgRef.current, root, {
11389
+ radius,
11390
+ r,
11391
+ label,
11392
+ slots,
11393
+ collapsed,
11394
+ cluster: cluster2,
11395
+ onNodeClick: (n) => handleClickRef.current(n),
11396
+ onNodeHover: (n, e) => handleHoverRef.current(n, e)
11397
+ });
11398
+ }, [
11399
+ root,
11400
+ width,
11401
+ height,
11402
+ r,
11403
+ padding,
11404
+ label,
11405
+ slots,
11406
+ collapsed,
11407
+ cluster2
11408
+ ]);
11409
+ return /* @__PURE__ */ React7.createElement("div", {
11410
+ ref: setRef,
11411
+ className: mx2("dx-expander relative", classNames)
11412
+ }, width > 0 && height > 0 && /* @__PURE__ */ React7.createElement("svg", {
11413
+ ref: svgRef,
11414
+ xmlns: "http://www.w3.org/2000/svg",
11415
+ width,
11416
+ height,
11417
+ viewBox: `${-width / 2} ${-height / 2} ${width} ${height}`
11418
+ }));
11419
+ };
11420
+ var renderRadialTree = (svgElement, root, options) => {
11421
+ const { radius, r, label, slots, collapsed, cluster: cluster2, onNodeClick, onNodeHover } = options;
11422
+ const svg = select3(svgElement);
11423
+ const layout = cluster2 ? d3Cluster() : d3Tree();
11424
+ layout.size([
11425
+ 2 * Math.PI,
10917
11426
  radius
10918
- ]).separation((a, b) => (a.parent === b.parent ? 1 : 2) / a.depth);
10919
- layout(root);
10920
- svg.append("g").selectAll("path").data(root.links()).join("path").attr("class", slots?.path ?? "").attr("d", linkRadial().angle((d) => d.x + Math.PI / 2).radius((d) => d.y));
10921
- const node = svg.append("g").selectAll("a").data(root.descendants()).join("a").attr("transform", (d) => `rotate(${d.x * 180 / Math.PI}) translate(${d.y},0)`);
10922
- node.append("circle").attr("class", slots?.node ?? "").attr("r", r);
10923
- if (getLabel) {
10924
- node.append("text").attr("transform", (d) => `rotate(${d.x >= Math.PI ? 180 : 0})`).attr("dy", "0.32em").attr("x", (d) => d.x < Math.PI === !d.children ? 6 : -6).attr("text-anchor", (d) => d.x < Math.PI === !d.children ? "start" : "end").attr("class", slots?.text ?? "").text((d, i) => getLabel[i]);
10925
- }
10926
- return svg.node();
11427
+ ]).separation((a, b) => (a.parent === b.parent ? 1 : 2) / Math.max(1, a.depth))(root);
11428
+ const g = svg.selectAll("g.dx-radial-root").data([
11429
+ null
11430
+ ]).join("g").classed("dx-radial-root", true);
11431
+ const linksLayer = g.selectAll("g.dx-radial-links").data([
11432
+ null
11433
+ ]).join("g").classed("dx-radial-links", true);
11434
+ const nodesLayer = g.selectAll("g.dx-radial-nodes").data([
11435
+ null
11436
+ ]).join("g").classed("dx-radial-nodes", true);
11437
+ const linkPath = linkRadial().angle((d) => d.x).radius((d) => d.y);
11438
+ linksLayer.selectAll("path").data(root.links(), (d) => `${d.source.data.id}->${d.target.data.id}`).join((enter) => enter.append("path").attr("class", slots.path ?? "").attr("fill", "none").attr("opacity", 0), (update) => update, (exit) => exit.transition().duration(TRANSITION_MS3).attr("opacity", 0).remove()).transition().duration(TRANSITION_MS3).attr("opacity", 1).attr("d", linkPath);
11439
+ const node = nodesLayer.selectAll("g.dx-radial-node").data(root.descendants(), (d) => d.data.id);
11440
+ const nodeEnter = node.enter().append("g").classed("dx-radial-node", true).attr("opacity", 0).attr("transform", (d) => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`).style("cursor", (d) => d.data.children?.length ? "pointer" : "default").on("click", (_, d) => onNodeClick(d.data));
11441
+ nodeEnter.append("circle").attr("r", r).on("pointerenter", (event, d) => onNodeHover(d.data, event)).on("pointerleave", (event) => onNodeHover(null, event));
11442
+ nodeEnter.append("text").attr("dy", "0.32em").attr("paint-order", "stroke").text((d) => label(d.data));
11443
+ const nodeMerge = nodeEnter.merge(node);
11444
+ nodeMerge.transition().duration(TRANSITION_MS3).attr("opacity", 1).attr("transform", (d) => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`);
11445
+ nodeMerge.select("circle").attr("class", (d) => {
11446
+ const collapsedHere = isCollapsed(d.data, collapsed);
11447
+ const leaf = isLeaf(d.data);
11448
+ return [
11449
+ slots.node ?? "",
11450
+ collapsedHere ? "dx-collapsed" : leaf ? "dx-leaf" : "dx-branch"
11451
+ ].filter(Boolean).join(" ");
11452
+ }).attr("r", r).style("fill", (d) => isLeaf(d.data) ? getNodeFillForObject(d.data.data) : null);
11453
+ nodeMerge.select("text").attr("class", slots.text ?? "").attr("transform", (d) => d.x >= Math.PI ? "rotate(180)" : null).attr("x", (d) => d.x < Math.PI === !d.children ? r + 4 : -(r + 4)).attr("text-anchor", (d) => d.x < Math.PI === !d.children ? "start" : "end").text((d) => label(d.data));
11454
+ node.exit().transition().duration(TRANSITION_MS3).attr("opacity", 0).remove();
10927
11455
  };
10928
- var RadialTree_default = RadialTree;
10929
11456
 
10930
- // src/components/Tree/layout/TidyTree.ts
10931
- import { curveBumpX, hierarchy as hierarchy3, link, select as select3, tree as tree2 } from "d3";
10932
- var TidyTree = (s, data, options) => {
10933
- const svg = select3(s);
10934
- svg.selectAll("*").remove();
10935
- const { label, width, height, r = 4, padding = 4, margin = 60, slots } = options;
10936
- const root = hierarchy3(data);
10937
- const descendants = root.descendants();
10938
- const getLabel = label == null ? null : descendants.map((d) => label(d.data));
10939
- const dx = 16;
10940
- const dy = width / (root.height + padding);
10941
- const layout = tree2().nodeSize([
11457
+ // src/components/Tree/layout/TidyTree.tsx
11458
+ import { curveBumpX, link as d3Link, select as select4, tree as d3Tree2 } from "d3";
11459
+ import React8, { useCallback as useCallback4, useEffect as useEffect9, useMemo as useMemo5, useRef as useRef6, useState as useState5 } from "react";
11460
+ import { mx as mx3 } from "@dxos/ui-theme";
11461
+ var TRANSITION_MS4 = 350;
11462
+ var TidyTree = ({ classNames, data, label = (d) => d.label ?? d.id, slots = defaultTreeLayoutSlots, r = 4, margin = 24, initialCollapsed, onNodeClick }) => {
11463
+ const svgRef = useRef6(null);
11464
+ const { setRef, width, height } = useContainerSize();
11465
+ const [collapsed, setCollapsed] = useState5(() => new Set(initialCollapsed ?? []));
11466
+ const toggle = useCallback4((id) => {
11467
+ setCollapsed((prev) => {
11468
+ const next = new Set(prev);
11469
+ if (next.has(id)) {
11470
+ next.delete(id);
11471
+ } else {
11472
+ next.add(id);
11473
+ }
11474
+ return next;
11475
+ });
11476
+ }, []);
11477
+ const handleClickRef = useRef6(() => {
11478
+ });
11479
+ handleClickRef.current = (node) => {
11480
+ onNodeClick?.(node);
11481
+ if (node.children?.length) {
11482
+ toggle(node.id);
11483
+ }
11484
+ };
11485
+ const root = useMemo5(() => buildHierarchy(data, collapsed), [
11486
+ data,
11487
+ collapsed
11488
+ ]);
11489
+ useEffect9(() => {
11490
+ if (!svgRef.current || !width || !height) {
11491
+ return;
11492
+ }
11493
+ renderTidyTree(svgRef.current, root, {
11494
+ width,
11495
+ height,
11496
+ r,
11497
+ margin,
11498
+ label,
11499
+ slots,
11500
+ collapsed,
11501
+ onNodeClick: (n) => handleClickRef.current(n)
11502
+ });
11503
+ }, [
11504
+ root,
11505
+ width,
11506
+ height,
11507
+ r,
11508
+ margin,
11509
+ label,
11510
+ slots,
11511
+ collapsed
11512
+ ]);
11513
+ return /* @__PURE__ */ React8.createElement("div", {
11514
+ ref: setRef,
11515
+ className: mx3("dx-expander relative", classNames)
11516
+ }, width > 0 && height > 0 && /* @__PURE__ */ React8.createElement("svg", {
11517
+ ref: svgRef,
11518
+ xmlns: "http://www.w3.org/2000/svg",
11519
+ width,
11520
+ height,
11521
+ viewBox: `${-width / 2} ${-height / 2} ${width} ${height}`
11522
+ }));
11523
+ };
11524
+ var renderTidyTree = (svgElement, root, options) => {
11525
+ const { width, height, r, margin, label, slots, collapsed, onNodeClick } = options;
11526
+ const svg = select4(svgElement);
11527
+ const dx = 18;
11528
+ const dy = Math.max(60, (width - margin * 2) / Math.max(1, root.height + 1));
11529
+ d3Tree2().nodeSize([
10942
11530
  dx,
10943
11531
  dy
10944
- ]);
10945
- layout(root);
11532
+ ])(root);
10946
11533
  let x0 = Infinity;
10947
11534
  let x1 = -x0;
10948
- let y0 = Infinity;
10949
- let y1 = -y0;
10950
11535
  root.each((d) => {
10951
11536
  if (d.x > x1) {
10952
11537
  x1 = d.x;
@@ -10954,136 +11539,102 @@ var TidyTree = (s, data, options) => {
10954
11539
  if (d.x < x0) {
10955
11540
  x0 = d.x;
10956
11541
  }
10957
- if (d.y > y1) {
10958
- y1 = d.y;
10959
- }
10960
- if (d.y < y0) {
10961
- y0 = d.y;
10962
- }
10963
11542
  });
10964
- const sx = Math.min(2, Math.max(1, (height - margin * 2) / (x1 - x0)));
10965
- const oy = -(width - (y1 - y0)) / 2;
10966
- svg.append("g").selectAll("path").data(root.links()).join("path").attr("class", slots?.path ?? "").attr("d", link(curveBumpX).x((d) => d.y + oy).y((d) => d.x * sx));
10967
- const node = svg.append("g").selectAll("a").data(root.descendants()).join("a").attr("transform", (d) => `translate(${d.y + oy},${d.x * sx})`);
10968
- node.append("circle").attr("class", slots?.node ?? "").attr("r", r);
10969
- if (getLabel) {
10970
- node.append("text").attr("dy", "0.32em").attr("x", (d) => d.children ? -6 : 6).attr("text-anchor", (d) => d.children ? "end" : "start").attr("class", slots?.text ?? "").text((d, i) => getLabel[i]);
10971
- }
10972
- };
10973
- var TidyTree_default = TidyTree;
10974
-
10975
- // src/components/Tree/types/tree.ts
10976
- import * as Schema from "effect/Schema";
10977
- import { Key, Obj, Type } from "@dxos/echo";
10978
- import { invariant } from "@dxos/invariant";
10979
- var TreeNodeType = Schema.Struct({
10980
- id: Key.ObjectId,
10981
- children: Schema.mutable(Schema.Array(Key.ObjectId)),
10982
- data: Schema.mutable(Schema.Record({
10983
- key: Schema.String,
10984
- value: Schema.Any
10985
- })),
10986
- ref: Schema.optional(Type.Ref(Type.Expando))
10987
- }).pipe(Schema.mutable);
10988
- var TreeType = Schema.Struct({
10989
- root: Key.ObjectId,
10990
- nodes: Schema.mutable(Schema.Record({
10991
- key: Key.ObjectId,
10992
- value: TreeNodeType
10993
- }))
10994
- }).pipe(Type.Obj({
10995
- typename: "dxos.org/type/Tree",
10996
- version: "0.1.0"
10997
- }));
10998
-
10999
- // src/components/Tree/types/types.ts
11000
- var mapGraphToTreeData = (model, maxDepth = 8) => {
11001
- let data;
11002
- return data;
11543
+ const treeWidth = width - margin * 2;
11544
+ const treeHeight = x1 - x0;
11545
+ const scaleY = treeHeight > 0 ? Math.min(1, (height - margin * 2) / treeHeight) : 1;
11546
+ const offsetX = -treeWidth / 2;
11547
+ const offsetY = -(x0 + x1) / 2;
11548
+ const g = svg.selectAll("g.dx-tidy-root").data([
11549
+ null
11550
+ ]).join("g").classed("dx-tidy-root", true);
11551
+ const linksLayer = g.selectAll("g.dx-tidy-links").data([
11552
+ null
11553
+ ]).join("g").classed("dx-tidy-links", true);
11554
+ const nodesLayer = g.selectAll("g.dx-tidy-nodes").data([
11555
+ null
11556
+ ]).join("g").classed("dx-tidy-nodes", true);
11557
+ const linkPath = d3Link(curveBumpX).x((d) => offsetX + d.y).y((d) => (d.x + offsetY) * scaleY);
11558
+ linksLayer.selectAll("path").data(root.links(), (d) => `${d.source.data.id}->${d.target.data.id}`).join((enter) => enter.append("path").attr("class", slots.path ?? "").attr("fill", "none").attr("opacity", 0), (update) => update, (exit) => exit.transition().duration(TRANSITION_MS4).attr("opacity", 0).remove()).transition().duration(TRANSITION_MS4).attr("opacity", 1).attr("d", linkPath);
11559
+ const node = nodesLayer.selectAll("g.dx-tidy-node").data(root.descendants(), (d) => d.data.id);
11560
+ const nodeEnter = node.enter().append("g").classed("dx-tidy-node", true).attr("transform", (d) => `translate(${offsetX + d.y},${(d.x + offsetY) * scaleY})`).attr("opacity", 0).style("cursor", (d) => d.data.children?.length ? "pointer" : "default").on("click", (_, d) => onNodeClick(d.data));
11561
+ nodeEnter.append("circle").attr("r", r);
11562
+ nodeEnter.append("text").attr("dy", "0.32em").attr("x", (d) => d.children ? -(r + 4) : r + 4).attr("text-anchor", (d) => d.children ? "end" : "start").text((d) => label(d.data));
11563
+ const nodeMerge = nodeEnter.merge(node);
11564
+ nodeMerge.transition().duration(TRANSITION_MS4).attr("opacity", 1).attr("transform", (d) => `translate(${offsetX + d.y},${(d.x + offsetY) * scaleY})`);
11565
+ nodeMerge.select("circle").attr("class", (d) => {
11566
+ const collapsedHere = isCollapsed(d.data, collapsed);
11567
+ const leaf = isLeaf(d.data);
11568
+ return [
11569
+ slots.node ?? "",
11570
+ collapsedHere ? "dx-collapsed" : leaf ? "dx-leaf" : "dx-branch"
11571
+ ].filter(Boolean).join(" ");
11572
+ }).attr("r", r);
11573
+ nodeMerge.select("text").attr("class", slots.text ?? "").attr("x", (d) => d.children ? -(r + 4) : r + 4).attr("text-anchor", (d) => d.children ? "end" : "start").text((d) => label(d.data));
11574
+ node.exit().each(function() {
11575
+ select4(this).interrupt();
11576
+ }).transition().duration(TRANSITION_MS4).attr("opacity", 0).remove();
11003
11577
  };
11004
11578
 
11005
11579
  // src/components/Tree/Tree.tsx
11006
- var defaultTreeLayoutSlots = {
11007
- node: "fill-blue-600",
11008
- path: "fill-none stroke-blue-400 stroke-[0.5px]",
11009
- text: "stroke-[0.5px] stroke-neutral-700 text-xs"
11010
- };
11011
- var renderers = /* @__PURE__ */ new Map([
11012
- [
11013
- "tidy",
11014
- TidyTree_default
11015
- ],
11016
- [
11017
- "radial",
11018
- RadialTree_default
11019
- ],
11020
- [
11021
- "edge",
11022
- HierarchicalEdgeBundling_default
11023
- ]
11024
- ]);
11025
- var Tree = ({ space, selected, variant = "tidy", onNodeClick }) => {
11026
- var _effect = _useSignals3();
11027
- try {
11028
- const [model] = useAsyncState(async () => space ? new SpaceGraphModel().open(space) : void 0, [
11029
- space,
11030
- selected
11031
- ]);
11032
- const [tree3, setTree] = useState();
11033
- useEffect3(() => {
11034
- return model?.subscribe(() => {
11035
- const tree4 = mapGraphToTreeData(model);
11036
- setTree(tree4);
11037
- }, true);
11038
- }, [
11039
- model
11040
- ]);
11041
- const context = useRef(null);
11042
- useEffect3(() => {
11043
- if (context.current?.size) {
11044
- const { width, height } = context.current.size;
11045
- const size = Math.min(width, height);
11046
- const radius = size * 0.4;
11047
- const options = {
11048
- // TODO(burdon): Type.
11049
- label: (d) => d.label ?? d.id,
11050
- width,
11051
- height,
11052
- radius,
11053
- marginLeft: (width - radius * 2) / 2,
11054
- marginRight: (width - radius * 2) / 2,
11055
- marginTop: (height - radius * 2) / 2,
11056
- marginBottom: (height - radius * 2) / 2,
11057
- slots: defaultTreeLayoutSlots
11058
- };
11059
- if (tree3) {
11060
- const renderer = renderers.get(variant);
11061
- renderer?.(context.current.svg, tree3, options);
11062
- }
11063
- }
11064
- }, [
11065
- context.current,
11066
- tree3
11067
- ]);
11068
- return /* @__PURE__ */ React3.createElement("div", {
11069
- onClick: () => onNodeClick?.()
11070
- }, /* @__PURE__ */ React3.createElement(SVG.Root, {
11071
- ref: context
11072
- }));
11073
- } finally {
11074
- _effect.f();
11075
- }
11580
+ var Tree = ({ classNames, data, edges, variant = "tidy", label, slots, initialCollapsed, onNodeClick, onNodeHover }) => {
11581
+ return useMemo6(() => {
11582
+ switch (variant) {
11583
+ case "tidy":
11584
+ return /* @__PURE__ */ React9.createElement(TidyTree, {
11585
+ classNames,
11586
+ data,
11587
+ label,
11588
+ slots,
11589
+ initialCollapsed,
11590
+ onNodeClick
11591
+ });
11592
+ case "radial":
11593
+ return /* @__PURE__ */ React9.createElement(RadialTree, {
11594
+ classNames,
11595
+ data,
11596
+ label,
11597
+ slots,
11598
+ initialCollapsed,
11599
+ onNodeClick,
11600
+ onNodeHover
11601
+ });
11602
+ case "edge":
11603
+ return /* @__PURE__ */ React9.createElement(HierarchicalEdgeBundling, {
11604
+ classNames,
11605
+ data,
11606
+ edges: edges ?? [],
11607
+ label,
11608
+ slots,
11609
+ onNodeHover
11610
+ });
11611
+ }
11612
+ }, [
11613
+ variant,
11614
+ classNames,
11615
+ data,
11616
+ edges,
11617
+ label,
11618
+ slots,
11619
+ initialCollapsed,
11620
+ onNodeClick,
11621
+ onNodeHover
11622
+ ]);
11076
11623
  };
11077
-
11078
- // src/components/index.ts
11079
- import { lazy } from "react";
11080
- var ExplorerContainer = lazy(() => import("./ExplorerContainer-NOLLVUTE.mjs"));
11081
-
11082
11624
  export {
11625
+ CanvasForceGraph,
11083
11626
  Chart,
11627
+ ForceGraph,
11084
11628
  Globe,
11085
- defaultTreeLayoutSlots,
11629
+ HierarchicalEdgeBundling,
11630
+ Lattice,
11631
+ RadialTree,
11632
+ TidyTree,
11086
11633
  Tree,
11087
- ExplorerContainer
11634
+ buildHierarchy,
11635
+ defaultTreeLayoutSlots,
11636
+ isCollapsed,
11637
+ isLeaf,
11638
+ treeTypeToTreeNode
11088
11639
  };
11089
- //# sourceMappingURL=chunk-ARBGXQFH.mjs.map
11640
+ //# sourceMappingURL=index.mjs.map