@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.
- package/LICENSE +102 -5
- package/dist/lib/neutral/ExplorerArticle-EAKRB55W.mjs +277 -0
- package/dist/lib/neutral/ExplorerArticle-EAKRB55W.mjs.map +7 -0
- package/dist/lib/neutral/ExplorerPlugin.mjs +10 -0
- package/dist/lib/neutral/capabilities/index.mjs +11 -0
- package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
- package/dist/lib/neutral/chunk-7SPMPHRS.mjs +72 -0
- package/dist/lib/neutral/chunk-7SPMPHRS.mjs.map +7 -0
- package/dist/lib/{browser/chunk-UBHZGWZQ.mjs → neutral/chunk-DXIWQFYO.mjs} +3 -5
- package/dist/lib/neutral/chunk-DXIWQFYO.mjs.map +7 -0
- package/dist/lib/neutral/chunk-EM2BV4PF.mjs +290 -0
- package/dist/lib/neutral/chunk-EM2BV4PF.mjs.map +7 -0
- package/dist/lib/neutral/chunk-GRJXLL4Z.mjs +25 -0
- package/dist/lib/neutral/chunk-GRJXLL4Z.mjs.map +7 -0
- package/dist/lib/neutral/chunk-V2OFO6PI.mjs +14 -0
- package/dist/lib/neutral/chunk-V2OFO6PI.mjs.map +7 -0
- package/dist/lib/{browser/chunk-ARBGXQFH.mjs → neutral/components/index.mjs} +858 -307
- package/dist/lib/neutral/components/index.mjs.map +7 -0
- package/dist/lib/neutral/containers/index.mjs +9 -0
- package/dist/lib/neutral/containers/index.mjs.map +7 -0
- package/dist/lib/neutral/create-object-F6TKVAGV.mjs +39 -0
- package/dist/lib/neutral/create-object-F6TKVAGV.mjs.map +7 -0
- package/dist/lib/neutral/hooks/index.mjs +45 -0
- package/dist/lib/neutral/hooks/index.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +14 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/{browser → neutral}/meta.mjs +1 -1
- package/dist/lib/neutral/plugin.mjs +12 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/react-surface-APBW2VQG.mjs +26 -0
- package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +7 -0
- package/dist/lib/neutral/testing/index.mjs +193 -0
- package/dist/lib/neutral/testing/index.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +33 -0
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/lib/{browser → neutral}/types/index.mjs +1 -2
- package/dist/types/data/cities.d.ts +4 -4
- package/dist/types/data/cities.d.ts.map +1 -1
- package/dist/types/data/countries-110m.d.ts +19 -22
- package/dist/types/data/countries-110m.d.ts.map +1 -1
- package/dist/types/src/ExplorerPlugin.d.ts +3 -1
- package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
- package/dist/types/src/ExplorerPlugin.test.d.ts +2 -0
- package/dist/types/src/ExplorerPlugin.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/create-object.d.ts +11 -0
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +8 -2
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +3 -2
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/Chart/Chart.d.ts +1 -1
- package/dist/types/src/components/Chart/Chart.d.ts.map +1 -1
- package/dist/types/src/components/Chart/Chart.stories.d.ts +4 -1
- package/dist/types/src/components/Chart/Chart.stories.d.ts.map +1 -1
- package/dist/types/src/components/Globe/Globe.d.ts +1 -1
- package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
- package/dist/types/src/components/Globe/Globe.stories.d.ts +5 -2
- package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
- package/dist/types/src/components/Graph/CanvasForceGraph.d.ts +13 -0
- package/dist/types/src/components/Graph/CanvasForceGraph.d.ts.map +1 -0
- package/dist/types/src/components/Graph/CanvasForceGraph.stories.d.ts +17 -0
- package/dist/types/src/components/Graph/CanvasForceGraph.stories.d.ts.map +1 -0
- package/dist/types/src/components/Graph/ForceGraph.d.ts +12 -5
- package/dist/types/src/components/Graph/ForceGraph.d.ts.map +1 -1
- package/dist/types/src/components/Graph/ForceGraph.stories.d.ts +4 -2
- package/dist/types/src/components/Graph/ForceGraph.stories.d.ts.map +1 -1
- package/dist/types/src/components/Graph/{adapter.d.ts → graph-adapter.d.ts} +2 -2
- package/dist/types/src/components/Graph/graph-adapter.d.ts.map +1 -0
- package/dist/types/src/components/Graph/index.d.ts +1 -1
- package/dist/types/src/components/Graph/index.d.ts.map +1 -1
- package/dist/types/src/components/Lattice/Lattice.d.ts +20 -0
- package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -0
- package/dist/types/src/components/Lattice/Lattice.stories.d.ts +8 -0
- package/dist/types/src/components/Lattice/Lattice.stories.d.ts.map +1 -0
- package/dist/types/src/components/Lattice/index.d.ts +2 -0
- package/dist/types/src/components/Lattice/index.d.ts.map +1 -0
- package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +21 -0
- package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -0
- package/dist/types/src/components/Tree/Tree.d.ts +20 -23
- package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts +5 -12
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/index.d.ts +2 -0
- package/dist/types/src/components/Tree/index.d.ts.map +1 -1
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +37 -2
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +1 -1
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts +35 -2
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts +24 -2
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/layout/hierarchy.d.ts +17 -0
- package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +1 -0
- package/dist/types/src/components/Tree/layout/index.d.ts +5 -4
- package/dist/types/src/components/Tree/layout/index.d.ts.map +1 -1
- package/dist/types/src/components/Tree/layout/slots.d.ts +7 -0
- package/dist/types/src/components/Tree/layout/slots.d.ts.map +1 -0
- package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +15 -0
- package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +1 -0
- package/dist/types/src/components/Tree/types/tree.d.ts +18 -16
- package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/types/types.d.ts +14 -4
- package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts +9 -0
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -0
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +29 -0
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -0
- package/dist/types/src/containers/ExplorerArticle/experimental.stories.d.ts +7 -0
- package/dist/types/src/containers/ExplorerArticle/experimental.stories.d.ts.map +1 -0
- package/dist/types/src/containers/ExplorerArticle/index.d.ts +2 -0
- package/dist/types/src/containers/ExplorerArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +3 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useGraphModel.d.ts +2 -2
- package/dist/types/src/hooks/useGraphModel.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/plugin.d.ts +3 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/{components/Tree/testing → testing}/generator.d.ts +1 -1
- package/dist/types/src/testing/generator.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +4 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/relations.d.ts +47 -0
- package/dist/types/src/testing/relations.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +29 -28
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/ExplorerAction.d.ts +0 -17
- package/dist/types/src/types/ExplorerAction.d.ts.map +1 -1
- package/dist/types/src/types/Graph.d.ts +10 -20
- package/dist/types/src/types/Graph.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +3 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/src/util/node-color.d.ts +13 -0
- package/dist/types/src/util/node-color.d.ts.map +1 -0
- package/dist/types/src/{components → util}/plot.d.ts +1 -1
- package/dist/types/src/util/plot.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +113 -62
- package/src/ExplorerPlugin.test.ts +26 -0
- package/src/ExplorerPlugin.tsx +15 -45
- package/src/capabilities/create-object.ts +36 -0
- package/src/capabilities/index.ts +3 -3
- package/src/capabilities/react-surface.tsx +24 -18
- package/src/components/Chart/Chart.stories.tsx +16 -23
- package/src/components/Chart/Chart.tsx +1 -1
- package/src/components/Globe/Globe.stories.tsx +19 -22
- package/src/components/Globe/Globe.tsx +1 -1
- package/src/components/Graph/CanvasForceGraph.stories.tsx +83 -0
- package/src/components/Graph/CanvasForceGraph.tsx +124 -0
- package/src/components/Graph/ForceGraph.stories.tsx +83 -44
- package/src/components/Graph/ForceGraph.tsx +104 -85
- package/src/components/Graph/{adapter.ts → graph-adapter.ts} +14 -8
- package/src/components/Graph/index.ts +1 -1
- package/src/components/Lattice/Lattice.stories.tsx +90 -0
- package/src/components/Lattice/Lattice.tsx +182 -0
- package/src/components/Lattice/index.ts +5 -0
- package/src/components/Tree/EdgeBundling.stories.tsx +144 -0
- package/src/components/Tree/Tree.stories.tsx +20 -38
- package/src/components/Tree/Tree.tsx +69 -95
- package/src/components/Tree/index.ts +2 -0
- package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +296 -0
- package/src/components/Tree/layout/RadialTree.tsx +242 -0
- package/src/components/Tree/layout/TidyTree.tsx +246 -0
- package/src/components/Tree/layout/hierarchy.ts +32 -0
- package/src/components/Tree/layout/index.ts +5 -5
- package/src/components/Tree/layout/slots.ts +19 -0
- package/src/components/Tree/layout/useContainerSize.ts +43 -0
- package/src/components/Tree/types/tree.test.ts +6 -5
- package/src/components/Tree/types/tree.ts +41 -20
- package/src/components/Tree/types/types.ts +38 -29
- package/src/components/index.ts +1 -4
- package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +136 -0
- package/src/containers/ExplorerArticle/ExplorerArticle.tsx +465 -0
- package/src/containers/ExplorerArticle/experimental.stories.tsx +446 -0
- package/src/containers/ExplorerArticle/index.ts +5 -0
- package/src/containers/index.ts +7 -0
- package/src/hooks/useGraphModel.ts +25 -14
- package/src/index.ts +1 -4
- package/src/meta.ts +4 -4
- package/src/plugin.ts +9 -0
- package/src/{components/Tree/testing → testing}/generator.ts +5 -3
- package/src/testing/index.ts +9 -0
- package/src/testing/relations.ts +192 -0
- package/src/translations.ts +14 -13
- package/src/types/ExplorerAction.ts +1 -18
- package/src/types/Graph.ts +13 -28
- package/src/typings.d.ts +8 -0
- package/src/util/index.ts +6 -0
- package/src/util/node-color.ts +23 -0
- package/src/{components → util}/plot.ts +16 -4
- package/dist/lib/browser/ExplorerContainer-NOLLVUTE.mjs +0 -50
- package/dist/lib/browser/ExplorerContainer-NOLLVUTE.mjs.map +0 -7
- package/dist/lib/browser/chunk-2MKBRIUT.mjs +0 -31
- package/dist/lib/browser/chunk-2MKBRIUT.mjs.map +0 -7
- package/dist/lib/browser/chunk-6BVXZQPP.mjs +0 -188
- package/dist/lib/browser/chunk-6BVXZQPP.mjs.map +0 -7
- package/dist/lib/browser/chunk-ARBGXQFH.mjs.map +0 -7
- package/dist/lib/browser/chunk-P6FFFVPM.mjs +0 -100
- package/dist/lib/browser/chunk-P6FFFVPM.mjs.map +0 -7
- package/dist/lib/browser/chunk-UBHZGWZQ.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -112
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-EWB3H5KH.mjs +0 -35
- package/dist/lib/browser/intent-resolver-EWB3H5KH.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/react-surface-BY2DYCTH.mjs +0 -34
- package/dist/lib/browser/react-surface-BY2DYCTH.mjs.map +0 -7
- package/dist/lib/node-esm/ExplorerContainer-N3S5KSUX.mjs +0 -51
- package/dist/lib/node-esm/ExplorerContainer-N3S5KSUX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-3ODK27PU.mjs +0 -33
- package/dist/lib/node-esm/chunk-3ODK27PU.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-4BY2XZET.mjs +0 -101
- package/dist/lib/node-esm/chunk-4BY2XZET.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-CRSVAZNA.mjs +0 -190
- package/dist/lib/node-esm/chunk-CRSVAZNA.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-NPIP4VEH.mjs +0 -11091
- package/dist/lib/node-esm/chunk-NPIP4VEH.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UXZM5VJB.mjs +0 -26
- package/dist/lib/node-esm/chunk-UXZM5VJB.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -113
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-SH6PW7VF.mjs +0 -36
- package/dist/lib/node-esm/intent-resolver-SH6PW7VF.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/meta.mjs +0 -9
- package/dist/lib/node-esm/react-surface-7AAV7GBG.mjs +0 -35
- package/dist/lib/node-esm/react-surface-7AAV7GBG.mjs.map +0 -7
- package/dist/lib/node-esm/types/index.mjs +0 -12
- package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
- package/dist/types/src/components/ExplorerContainer.d.ts +0 -9
- package/dist/types/src/components/ExplorerContainer.d.ts.map +0 -1
- package/dist/types/src/components/Graph/D3ForceGraph.d.ts +0 -14
- package/dist/types/src/components/Graph/D3ForceGraph.d.ts.map +0 -1
- package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts +0 -15
- package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts.map +0 -1
- package/dist/types/src/components/Graph/adapter.d.ts.map +0 -1
- package/dist/types/src/components/Graph/testing.d.ts +0 -14
- package/dist/types/src/components/Graph/testing.d.ts.map +0 -1
- package/dist/types/src/components/Tree/testing/generator.d.ts.map +0 -1
- package/dist/types/src/components/Tree/testing/index.d.ts +0 -2
- package/dist/types/src/components/Tree/testing/index.d.ts.map +0 -1
- package/dist/types/src/components/plot.d.ts.map +0 -1
- package/src/capabilities/intent-resolver.ts +0 -23
- package/src/components/ExplorerContainer.tsx +0 -54
- package/src/components/Graph/D3ForceGraph.stories.tsx +0 -80
- package/src/components/Graph/D3ForceGraph.tsx +0 -101
- package/src/components/Graph/testing.ts +0 -55
- package/src/components/Tree/layout/HierarchicalEdgeBundling.ts +0 -162
- package/src/components/Tree/layout/RadialTree.ts +0 -94
- package/src/components/Tree/layout/TidyTree.ts +0 -101
- package/src/components/Tree/testing/index.ts +0 -5
- /package/dist/lib/{browser/chunk-J5LGTIGS.mjs.map → neutral/ExplorerPlugin.mjs.map} +0 -0
- /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
- /package/dist/lib/{browser/meta.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
- /package/dist/lib/{browser/types → neutral}/index.mjs.map +0 -0
- /package/dist/lib/{node-esm → neutral}/meta.mjs.map +0 -0
- /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/
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
57
|
-
|
|
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
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
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
|
|
10782
|
-
|
|
10783
|
-
if (!
|
|
11053
|
+
const observer = new ResizeObserver((entries) => {
|
|
11054
|
+
const entry = entries[0];
|
|
11055
|
+
if (!entry) {
|
|
10784
11056
|
return;
|
|
10785
11057
|
}
|
|
10786
|
-
const
|
|
10787
|
-
|
|
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
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
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
|
-
|
|
10827
|
-
ref: containerRef,
|
|
10828
|
-
className: "grow p-4"
|
|
11107
|
+
height,
|
|
11108
|
+
padding,
|
|
11109
|
+
onNodeHover: (n, e) => handleHoverRef.current?.(n, e)
|
|
10829
11110
|
});
|
|
10830
|
-
|
|
10831
|
-
|
|
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 {
|
|
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.
|
|
10843
|
-
import { cluster, curveBundle, hierarchy, lineRadial, select } from "d3";
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
|
|
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
|
|
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
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
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
|
-
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
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
|
|
10889
|
-
const
|
|
10890
|
-
|
|
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
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
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.
|
|
10906
|
-
import {
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
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
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
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.
|
|
10931
|
-
import { curveBumpX,
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
const
|
|
10937
|
-
const
|
|
10938
|
-
const
|
|
10939
|
-
const
|
|
10940
|
-
|
|
10941
|
-
|
|
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
|
|
10965
|
-
const
|
|
10966
|
-
|
|
10967
|
-
const
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
children:
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
}))
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
}))
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
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
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
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
|
-
|
|
11629
|
+
HierarchicalEdgeBundling,
|
|
11630
|
+
Lattice,
|
|
11631
|
+
RadialTree,
|
|
11632
|
+
TidyTree,
|
|
11086
11633
|
Tree,
|
|
11087
|
-
|
|
11634
|
+
buildHierarchy,
|
|
11635
|
+
defaultTreeLayoutSlots,
|
|
11636
|
+
isCollapsed,
|
|
11637
|
+
isLeaf,
|
|
11638
|
+
treeTypeToTreeNode
|
|
11088
11639
|
};
|
|
11089
|
-
//# sourceMappingURL=
|
|
11640
|
+
//# sourceMappingURL=index.mjs.map
|