@dxos/plugin-explorer 0.8.4-main.c85a9c8dae → 0.8.4-main.d9fc60f731

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