@dxos/plugin-explorer 0.8.4-main.7996785055 → 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/{browser/chunk-6KEHUEEZ.mjs → neutral/chunk-7SPMPHRS.mjs} +6 -5
- package/dist/lib/neutral/chunk-7SPMPHRS.mjs.map +7 -0
- package/dist/lib/{browser/chunk-LSUP47BZ.mjs → neutral/chunk-DXIWQFYO.mjs} +2 -4
- 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-56VV76WZ.mjs → neutral/components/index.mjs} +706 -356
- 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 -1
- 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 +1 -0
- 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 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- 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/{D3ForceGraph.stories.d.ts → CanvasForceGraph.stories.d.ts} +3 -7
- 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 +3 -1
- 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} +1 -1
- 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 +6 -6
- 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 -0
- 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 +1 -1
- package/dist/types/src/containers/index.d.ts.map +1 -1
- 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/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 +28 -28
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Graph.d.ts +3 -4
- 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 +102 -56
- package/src/ExplorerPlugin.test.ts +26 -0
- package/src/ExplorerPlugin.tsx +7 -35
- package/src/capabilities/create-object.ts +36 -0
- package/src/capabilities/index.ts +4 -1
- package/src/capabilities/react-surface.tsx +32 -0
- package/src/components/Chart/Chart.stories.tsx +14 -21
- package/src/components/Chart/Chart.tsx +1 -1
- package/src/components/Globe/Globe.stories.tsx +17 -20
- 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 +78 -42
- package/src/components/Graph/ForceGraph.tsx +104 -85
- 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 +19 -40
- package/src/components/Tree/Tree.tsx +69 -100
- 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 +4 -5
- package/src/components/Tree/types/tree.ts +9 -9
- package/src/components/Tree/types/types.ts +38 -29
- package/src/components/index.ts +1 -0
- 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 +1 -1
- package/src/hooks/useGraphModel.ts +10 -6
- package/src/index.ts +1 -4
- package/src/meta.ts +1 -1
- package/src/plugin.ts +9 -0
- package/src/{components/Tree/testing → testing}/generator.ts +2 -2
- package/src/testing/index.ts +9 -0
- package/src/testing/relations.ts +192 -0
- package/src/translations.ts +14 -14
- package/src/types/ExplorerAction.ts +1 -1
- package/src/types/Graph.ts +2 -3
- 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-H5RGY6AD.mjs +0 -48
- package/dist/lib/browser/ExplorerContainer-H5RGY6AD.mjs.map +0 -7
- package/dist/lib/browser/chunk-56VV76WZ.mjs.map +0 -7
- package/dist/lib/browser/chunk-6KEHUEEZ.mjs.map +0 -7
- package/dist/lib/browser/chunk-LSUP47BZ.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -107
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/react-surface-JYGFP5ZN.mjs +0 -38
- package/dist/lib/browser/react-surface-JYGFP5ZN.mjs.map +0 -7
- package/dist/lib/node-esm/ExplorerContainer-KFHE5KU3.mjs +0 -49
- package/dist/lib/node-esm/ExplorerContainer-KFHE5KU3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-35JCF4SD.mjs +0 -11292
- package/dist/lib/node-esm/chunk-35JCF4SD.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-EN3JZNEY.mjs +0 -26
- package/dist/lib/node-esm/chunk-EN3JZNEY.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-WSE2Z4OT.mjs +0 -72
- package/dist/lib/node-esm/chunk-WSE2Z4OT.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -108
- package/dist/lib/node-esm/index.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-HJEJL53N.mjs +0 -39
- package/dist/lib/node-esm/react-surface-HJEJL53N.mjs.map +0 -7
- package/dist/lib/node-esm/types/index.mjs +0 -11
- package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
- package/dist/types/src/components/Graph/D3ForceGraph.d.ts +0 -19
- package/dist/types/src/components/Graph/D3ForceGraph.d.ts.map +0 -1
- 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/dist/types/src/containers/ExplorerContainer/ExplorerContainer.d.ts +0 -6
- package/dist/types/src/containers/ExplorerContainer/ExplorerContainer.d.ts.map +0 -1
- package/dist/types/src/containers/ExplorerContainer/index.d.ts +0 -3
- package/dist/types/src/containers/ExplorerContainer/index.d.ts.map +0 -1
- package/src/capabilities/react-surface/index.ts +0 -7
- package/src/capabilities/react-surface/react-surface.tsx +0 -31
- package/src/components/Graph/D3ForceGraph.stories.tsx +0 -83
- package/src/components/Graph/D3ForceGraph.tsx +0 -109
- package/src/components/Graph/testing.ts +0 -58
- 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/src/containers/ExplorerContainer/ExplorerContainer.tsx +0 -53
- package/src/containers/ExplorerContainer/index.ts +0 -7
- /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
- /package/dist/types/src/capabilities/{react-surface/react-surface.d.ts → react-surface.d.ts} +0 -0
- /package/src/components/Graph/{adapter.ts → graph-adapter.ts} +0 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import { linkRadial } from 'd3';
|
|
7
|
+
import React from 'react';
|
|
8
|
+
|
|
9
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
10
|
+
|
|
11
|
+
const meta: Meta = {
|
|
12
|
+
title: 'plugins/plugin-explorer/containers/ExplorerArticle/experimental',
|
|
13
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
14
|
+
parameters: {
|
|
15
|
+
layout: 'fullscreen',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
|
|
21
|
+
type Story = StoryObj;
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// PathProbe — renders a fixed set of example bezier paths the cluster layout
|
|
25
|
+
// might emit, side-by-side across five columns:
|
|
26
|
+
// 1. Baked path strings (cubic / quadratic) as the cluster projector once
|
|
27
|
+
// emitted them.
|
|
28
|
+
// 2. linkRadial output from polar coordinates — should match column 1.
|
|
29
|
+
// 3. radialQuadratic — Q with control at (target.angle, source.radius).
|
|
30
|
+
// 4. radialElbow — sharp 2-segment elbow through the same knee.
|
|
31
|
+
// 5. radialSmoothElbow — cubic with both controls at the knee.
|
|
32
|
+
//
|
|
33
|
+
// Kept around so future curve experiments can compare candidate generators
|
|
34
|
+
// at a glance without touching the production cluster projector.
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
const PROBE_PATHS = [
|
|
38
|
+
// Source group at M(-174.87, -44.729). All three paths share that origin.
|
|
39
|
+
{
|
|
40
|
+
label: 'good (target angle 5.19, clockwise)',
|
|
41
|
+
color: 'lime',
|
|
42
|
+
d: 'M-174.87,-44.729 C-262.305,-67.094, -240.395,-124.563, -320.527,-166.083',
|
|
43
|
+
target: [-320.527, -166.083] as [number, number],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
label: 'good (target angle 5.55, clockwise)',
|
|
47
|
+
color: 'cyan',
|
|
48
|
+
d: 'M-174.87,-44.729 C-262.305,-67.094, -180.249,-202.029, -240.332,-269.372',
|
|
49
|
+
target: [-240.332, -269.372] as [number, number],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: 'bad (target angle 4.28, counter-clockwise)',
|
|
53
|
+
color: 'orange',
|
|
54
|
+
d: 'M-174.87,-44.729 C-262.305,-67.094, -245.815,113.492, -327.754,151.323',
|
|
55
|
+
target: [-327.754, 151.323] as [number, number],
|
|
56
|
+
},
|
|
57
|
+
// Live path the user reports as not rendering correctly in the full cluster.
|
|
58
|
+
// Source polar ≈ (1.14, 190.5); target polar ≈ (1.82, 380.9). Clockwise direction.
|
|
59
|
+
{
|
|
60
|
+
label: 'live broken (clockwise, source.x=1.14 → target.x=1.82)',
|
|
61
|
+
color: 'magenta',
|
|
62
|
+
d: 'M172.95585588832455,-79.85312713937451Q184.55815606041466,47.20738323164743 369.1163121208293,94.41476646329485',
|
|
63
|
+
target: [369.1163121208293, 94.41476646329485] as [number, number],
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const SOURCE_XY: [number, number] = [-174.87, -44.729];
|
|
68
|
+
|
|
69
|
+
// Reverse-engineered polar coords from the user's reported path strings.
|
|
70
|
+
// Source group: polar (4.96 rad, 181) → cartesian (-174.87, -44.729).
|
|
71
|
+
// We use linkRadial here directly to verify the strings d3 produces match what we expect.
|
|
72
|
+
const SOURCE_POLAR = { x: 4.96, y: 181 } as { x: number; y: number };
|
|
73
|
+
const PROBE_POLAR_TARGETS = [
|
|
74
|
+
{ label: 'target 5.19 (clockwise)', color: 'lime', polar: { x: 5.19, y: 360 } },
|
|
75
|
+
{ label: 'target 5.55 (clockwise)', color: 'cyan', polar: { x: 5.55, y: 361 } },
|
|
76
|
+
{ label: 'target 4.28 (counter-clockwise)', color: 'orange', polar: { x: 4.28, y: 361 } },
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
/** Convert d3-cluster polar (angle from 12 o'clock, sweeping clockwise) to cartesian. */
|
|
80
|
+
const polarToCartesian = (angle: number, radius: number): [number, number] => [
|
|
81
|
+
Math.cos(angle - Math.PI / 2) * radius,
|
|
82
|
+
Math.sin(angle - Math.PI / 2) * radius,
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Alternative curve: quadratic bezier from source to target with a single control point at
|
|
87
|
+
* (target.angle, source.radius). This makes the curve emerge from source heading TOWARD
|
|
88
|
+
* the target's angular direction (vs. linkRadial's curveBumpPolar, which emerges along
|
|
89
|
+
* source's angle and may bow far away from the target on the way).
|
|
90
|
+
*/
|
|
91
|
+
const radialQuadratic = (source: { x: number; y: number }, target: { x: number; y: number }) => {
|
|
92
|
+
const [sx, sy] = polarToCartesian(source.x, source.y);
|
|
93
|
+
const [tx, ty] = polarToCartesian(target.x, target.y);
|
|
94
|
+
const [cx, cy] = polarToCartesian(target.x, source.y);
|
|
95
|
+
return `M${sx},${sy}Q${cx},${cy} ${tx},${ty}`;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** Sharp elbow: M source L (target.angle, source.radius) L target. Hard-corner radial elbow. */
|
|
99
|
+
const radialElbow = (source: { x: number; y: number }, target: { x: number; y: number }) => {
|
|
100
|
+
const [sx, sy] = polarToCartesian(source.x, source.y);
|
|
101
|
+
const [tx, ty] = polarToCartesian(target.x, target.y);
|
|
102
|
+
const [cx, cy] = polarToCartesian(target.x, source.y);
|
|
103
|
+
return `M${sx},${sy}L${cx},${cy}L${tx},${ty}`;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Smoothed radial elbow: cubic bezier whose control points sit at the elbow knee. Curve
|
|
108
|
+
* emerges from source TOWARD the target angle (around the source ring), then bends OUT to
|
|
109
|
+
* target's radius. Eliminates the wide-ear from linkRadial AND the missing-stub from the
|
|
110
|
+
* pure quadratic — both halves of the curve are visible and follow the radial layout.
|
|
111
|
+
*/
|
|
112
|
+
const radialSmoothElbow = (source: { x: number; y: number }, target: { x: number; y: number }) => {
|
|
113
|
+
const [sx, sy] = polarToCartesian(source.x, source.y);
|
|
114
|
+
const [tx, ty] = polarToCartesian(target.x, target.y);
|
|
115
|
+
const [kx, ky] = polarToCartesian(target.x, source.y); // "knee" — at source radius, target angle
|
|
116
|
+
// Both control points near the knee so the curve hugs the elbow.
|
|
117
|
+
return `M${sx},${sy}C${kx},${ky} ${kx},${ky} ${tx},${ty}`;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const PathProbe = () => {
|
|
121
|
+
const radialLink = linkRadial<any, any>()
|
|
122
|
+
.angle((d) => d.x)
|
|
123
|
+
.radius((d) => d.y);
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<div style={{ width: '100vw', height: '100vh', background: '#0c0c0c', position: 'relative' }}>
|
|
127
|
+
<svg
|
|
128
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
129
|
+
width='100%'
|
|
130
|
+
height='100%'
|
|
131
|
+
viewBox='-450 -350 4000 700'
|
|
132
|
+
style={{ display: 'block' }}
|
|
133
|
+
>
|
|
134
|
+
{/* Center reference (column 1: baked paths) */}
|
|
135
|
+
<line x1={-450} y1={0} x2={450} y2={0} stroke='#222' />
|
|
136
|
+
<line x1={0} y1={-350} x2={0} y2={350} stroke='#222' />
|
|
137
|
+
|
|
138
|
+
{/* Origin marker */}
|
|
139
|
+
<circle cx={0} cy={0} r={3} fill='#444' />
|
|
140
|
+
<text x={-440} y={-330} fill='#666' fontSize={11}>
|
|
141
|
+
baked path strings (left)
|
|
142
|
+
</text>
|
|
143
|
+
|
|
144
|
+
{/* Source group circle */}
|
|
145
|
+
<circle cx={SOURCE_XY[0]} cy={SOURCE_XY[1]} r={5} fill='#888' />
|
|
146
|
+
|
|
147
|
+
{/* Pre-baked path strings (left column visualization). Handles both cubic (C) and
|
|
148
|
+
quadratic (Q) bezier commands. */}
|
|
149
|
+
{PROBE_PATHS.map((p, i) => {
|
|
150
|
+
const cubic = p.d.match(
|
|
151
|
+
/M\s*([-\d.]+),\s*([-\d.]+)\s*C\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+)/,
|
|
152
|
+
);
|
|
153
|
+
const quad = p.d.match(/M\s*([-\d.]+),\s*([-\d.]+)\s*Q\s*([-\d.]+),\s*([-\d.]+)\s+([-\d.]+),\s*([-\d.]+)/);
|
|
154
|
+
const controls: Array<[number, number]> = [];
|
|
155
|
+
let mx = 0,
|
|
156
|
+
my = 0,
|
|
157
|
+
ex = 0,
|
|
158
|
+
ey = 0;
|
|
159
|
+
if (cubic) {
|
|
160
|
+
const v = cubic.map(parseFloat);
|
|
161
|
+
mx = v[1];
|
|
162
|
+
my = v[2];
|
|
163
|
+
controls.push([v[3], v[4]], [v[5], v[6]]);
|
|
164
|
+
ex = v[7];
|
|
165
|
+
ey = v[8];
|
|
166
|
+
} else if (quad) {
|
|
167
|
+
const v = quad.map(parseFloat);
|
|
168
|
+
mx = v[1];
|
|
169
|
+
my = v[2];
|
|
170
|
+
controls.push([v[3], v[4]]);
|
|
171
|
+
ex = v[5];
|
|
172
|
+
ey = v[6];
|
|
173
|
+
}
|
|
174
|
+
return (
|
|
175
|
+
<g key={`baked-${i}`}>
|
|
176
|
+
<path d={p.d} fill='none' stroke={p.color} strokeWidth={2} />
|
|
177
|
+
<polyline
|
|
178
|
+
points={[`${mx},${my}`, ...controls.map(([x, y]) => `${x},${y}`), `${ex},${ey}`].join(' ')}
|
|
179
|
+
fill='none'
|
|
180
|
+
stroke={p.color}
|
|
181
|
+
strokeOpacity={0.3}
|
|
182
|
+
strokeWidth={1}
|
|
183
|
+
strokeDasharray='2 3'
|
|
184
|
+
/>
|
|
185
|
+
{controls.map(([x, y], j) => (
|
|
186
|
+
<circle key={j} cx={x} cy={y} r={3} fill={p.color} opacity={0.5} />
|
|
187
|
+
))}
|
|
188
|
+
<circle cx={p.target[0]} cy={p.target[1]} r={5} fill={p.color} />
|
|
189
|
+
<text x={p.target[0] + 8} y={p.target[1]} fill={p.color} fontSize={11}>
|
|
190
|
+
{p.label}
|
|
191
|
+
</text>
|
|
192
|
+
</g>
|
|
193
|
+
);
|
|
194
|
+
})}
|
|
195
|
+
|
|
196
|
+
{/* Re-generate the same paths via linkRadial from polar coords. Shift right by 700 so they
|
|
197
|
+
sit in a second column for direct visual comparison. */}
|
|
198
|
+
<g transform='translate(750, 0)'>
|
|
199
|
+
<line x1={-450} y1={0} x2={450} y2={0} stroke='#222' />
|
|
200
|
+
<line x1={0} y1={-350} x2={0} y2={350} stroke='#222' />
|
|
201
|
+
<circle cx={0} cy={0} r={3} fill='#444' />
|
|
202
|
+
<circle cx={SOURCE_XY[0]} cy={SOURCE_XY[1]} r={5} fill='#888' />
|
|
203
|
+
<text x={-440} y={-330} fill='#666' fontSize={11}>
|
|
204
|
+
linkRadial output from polar (middle)
|
|
205
|
+
</text>
|
|
206
|
+
{PROBE_POLAR_TARGETS.map((p, i) => {
|
|
207
|
+
const d = radialLink({ source: SOURCE_POLAR, target: p.polar }) ?? '';
|
|
208
|
+
const m = d.match(
|
|
209
|
+
/M\s*([-\d.]+),\s*([-\d.]+)\s*C\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+),\s*([-\d.]+)/,
|
|
210
|
+
);
|
|
211
|
+
if (!m) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
const [, , , c1x, c1y, c2x, c2y, ex, ey] = m.map(parseFloat);
|
|
215
|
+
return (
|
|
216
|
+
<g key={`fresh-${i}`}>
|
|
217
|
+
<path d={d} fill='none' stroke={p.color} strokeWidth={2} />
|
|
218
|
+
<circle cx={c1x} cy={c1y} r={3} fill={p.color} opacity={0.5} />
|
|
219
|
+
<circle cx={c2x} cy={c2y} r={3} fill={p.color} opacity={0.5} />
|
|
220
|
+
<circle cx={ex} cy={ey} r={5} fill={p.color} />
|
|
221
|
+
<text x={ex + 8} y={ey} fill={p.color} fontSize={11}>
|
|
222
|
+
{p.label}
|
|
223
|
+
</text>
|
|
224
|
+
</g>
|
|
225
|
+
);
|
|
226
|
+
})}
|
|
227
|
+
</g>
|
|
228
|
+
|
|
229
|
+
{/* Alternative A: quadratic with control at (target.angle, source.radius). */}
|
|
230
|
+
<g transform='translate(1500, 0)'>
|
|
231
|
+
<line x1={-450} y1={0} x2={450} y2={0} stroke='#222' />
|
|
232
|
+
<line x1={0} y1={-350} x2={0} y2={350} stroke='#222' />
|
|
233
|
+
<circle cx={0} cy={0} r={3} fill='#444' />
|
|
234
|
+
<circle cx={SOURCE_XY[0]} cy={SOURCE_XY[1]} r={5} fill='#888' />
|
|
235
|
+
<text x={-440} y={-330} fill='#666' fontSize={11}>
|
|
236
|
+
radialQuadratic — control at (target.angle, source.radius)
|
|
237
|
+
</text>
|
|
238
|
+
{PROBE_POLAR_TARGETS.map((p, i) => {
|
|
239
|
+
const d = radialQuadratic(SOURCE_POLAR, p.polar);
|
|
240
|
+
const [tx, ty] = polarToCartesian(p.polar.x, p.polar.y);
|
|
241
|
+
const [cx, cy] = polarToCartesian(p.polar.x, SOURCE_POLAR.y);
|
|
242
|
+
return (
|
|
243
|
+
<g key={`alt-${i}`}>
|
|
244
|
+
<path d={d} fill='none' stroke={p.color} strokeWidth={2} />
|
|
245
|
+
<circle cx={cx} cy={cy} r={3} fill={p.color} opacity={0.5} />
|
|
246
|
+
<circle cx={tx} cy={ty} r={5} fill={p.color} />
|
|
247
|
+
<text x={tx + 8} y={ty} fill={p.color} fontSize={11}>
|
|
248
|
+
{p.label}
|
|
249
|
+
</text>
|
|
250
|
+
</g>
|
|
251
|
+
);
|
|
252
|
+
})}
|
|
253
|
+
</g>
|
|
254
|
+
|
|
255
|
+
{/* Alternative B: sharp elbow — two line segments. */}
|
|
256
|
+
<g transform='translate(2250, 0)'>
|
|
257
|
+
<line x1={-450} y1={0} x2={450} y2={0} stroke='#222' />
|
|
258
|
+
<line x1={0} y1={-350} x2={0} y2={350} stroke='#222' />
|
|
259
|
+
<circle cx={0} cy={0} r={3} fill='#444' />
|
|
260
|
+
<circle cx={SOURCE_XY[0]} cy={SOURCE_XY[1]} r={5} fill='#888' />
|
|
261
|
+
<text x={-440} y={-330} fill='#666' fontSize={11}>
|
|
262
|
+
radialElbow — sharp 2-segment elbow
|
|
263
|
+
</text>
|
|
264
|
+
{PROBE_POLAR_TARGETS.map((p, i) => {
|
|
265
|
+
const d = radialElbow(SOURCE_POLAR, p.polar);
|
|
266
|
+
const [tx, ty] = polarToCartesian(p.polar.x, p.polar.y);
|
|
267
|
+
return (
|
|
268
|
+
<g key={`elbow-${i}`}>
|
|
269
|
+
<path d={d} fill='none' stroke={p.color} strokeWidth={2} />
|
|
270
|
+
<circle cx={tx} cy={ty} r={5} fill={p.color} />
|
|
271
|
+
<text x={tx + 8} y={ty} fill={p.color} fontSize={11}>
|
|
272
|
+
{p.label}
|
|
273
|
+
</text>
|
|
274
|
+
</g>
|
|
275
|
+
);
|
|
276
|
+
})}
|
|
277
|
+
</g>
|
|
278
|
+
|
|
279
|
+
{/* Alternative C: smoothed elbow — cubic with both controls at the knee. */}
|
|
280
|
+
<g transform='translate(3000, 0)'>
|
|
281
|
+
<line x1={-450} y1={0} x2={450} y2={0} stroke='#222' />
|
|
282
|
+
<line x1={0} y1={-350} x2={0} y2={350} stroke='#222' />
|
|
283
|
+
<circle cx={0} cy={0} r={3} fill='#444' />
|
|
284
|
+
<circle cx={SOURCE_XY[0]} cy={SOURCE_XY[1]} r={5} fill='#888' />
|
|
285
|
+
<text x={-440} y={-330} fill='#666' fontSize={11}>
|
|
286
|
+
radialSmoothElbow — cubic with both controls at the knee
|
|
287
|
+
</text>
|
|
288
|
+
{PROBE_POLAR_TARGETS.map((p, i) => {
|
|
289
|
+
const d = radialSmoothElbow(SOURCE_POLAR, p.polar);
|
|
290
|
+
const [tx, ty] = polarToCartesian(p.polar.x, p.polar.y);
|
|
291
|
+
return (
|
|
292
|
+
<g key={`smooth-${i}`}>
|
|
293
|
+
<path d={d} fill='none' stroke={p.color} strokeWidth={2} />
|
|
294
|
+
<circle cx={tx} cy={ty} r={5} fill={p.color} />
|
|
295
|
+
<text x={tx + 8} y={ty} fill={p.color} fontSize={11}>
|
|
296
|
+
{p.label}
|
|
297
|
+
</text>
|
|
298
|
+
</g>
|
|
299
|
+
);
|
|
300
|
+
})}
|
|
301
|
+
</g>
|
|
302
|
+
</svg>
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
export const PathProbeStory: Story = {
|
|
308
|
+
name: 'PathProbe',
|
|
309
|
+
render: () => <PathProbe />,
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// ---------------------------------------------------------------------------
|
|
313
|
+
// PathInspector — paste any `d` string, click Diagnose. The path is rendered
|
|
314
|
+
// in an SVG and the same diagnostics (bbox, pathLength, computed CSS) we'd
|
|
315
|
+
// otherwise pull from the console are printed alongside. Loops to avoid the
|
|
316
|
+
// console-snippet ping-pong when debugging "this path doesn't render."
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
|
|
319
|
+
const PathInspector = () => {
|
|
320
|
+
const [input, setInput] = React.useState(
|
|
321
|
+
'M172.95585588832455,-79.85312713937451Q184.55815606041466,47.20738323164743 369.1163121208293,94.41476646329485',
|
|
322
|
+
);
|
|
323
|
+
const [info, setInfo] = React.useState<Record<string, unknown> | null>(null);
|
|
324
|
+
const pathRef = React.useRef<SVGPathElement | null>(null);
|
|
325
|
+
|
|
326
|
+
const diagnose = React.useCallback(() => {
|
|
327
|
+
const el = pathRef.current;
|
|
328
|
+
if (!el) {
|
|
329
|
+
setInfo({ error: 'no path element' });
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const cs = getComputedStyle(el);
|
|
333
|
+
let bbox: any = null;
|
|
334
|
+
try {
|
|
335
|
+
const b = el.getBBox();
|
|
336
|
+
bbox = { x: b.x, y: b.y, width: b.width, height: b.height };
|
|
337
|
+
} catch (e: any) {
|
|
338
|
+
bbox = `error: ${e?.message}`;
|
|
339
|
+
}
|
|
340
|
+
let len: number | string = 0;
|
|
341
|
+
try {
|
|
342
|
+
len = el.getTotalLength();
|
|
343
|
+
} catch (e: any) {
|
|
344
|
+
len = `error: ${e?.message}`;
|
|
345
|
+
}
|
|
346
|
+
setInfo({
|
|
347
|
+
d: el.getAttribute('d'),
|
|
348
|
+
bbox,
|
|
349
|
+
pathLength: len,
|
|
350
|
+
stroke: cs.stroke,
|
|
351
|
+
strokeWidth: cs.strokeWidth,
|
|
352
|
+
strokeOpacity: cs.strokeOpacity,
|
|
353
|
+
opacity: cs.opacity,
|
|
354
|
+
visibility: cs.visibility,
|
|
355
|
+
display: cs.display,
|
|
356
|
+
clipPath: cs.clipPath,
|
|
357
|
+
transform: cs.transform,
|
|
358
|
+
});
|
|
359
|
+
}, []);
|
|
360
|
+
|
|
361
|
+
// Run on mount.
|
|
362
|
+
React.useEffect(() => {
|
|
363
|
+
diagnose();
|
|
364
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
365
|
+
}, []);
|
|
366
|
+
|
|
367
|
+
return (
|
|
368
|
+
<div
|
|
369
|
+
style={{
|
|
370
|
+
width: '100vw',
|
|
371
|
+
height: '100vh',
|
|
372
|
+
background: '#0c0c0c',
|
|
373
|
+
color: '#ddd',
|
|
374
|
+
fontFamily: 'monospace',
|
|
375
|
+
padding: 12,
|
|
376
|
+
boxSizing: 'border-box',
|
|
377
|
+
display: 'flex',
|
|
378
|
+
flexDirection: 'column',
|
|
379
|
+
gap: 8,
|
|
380
|
+
}}
|
|
381
|
+
>
|
|
382
|
+
<div style={{ display: 'flex', gap: 8, alignItems: 'flex-start' }}>
|
|
383
|
+
<textarea
|
|
384
|
+
value={input}
|
|
385
|
+
onChange={(e) => setInput(e.target.value)}
|
|
386
|
+
rows={3}
|
|
387
|
+
style={{
|
|
388
|
+
flex: 1,
|
|
389
|
+
background: '#111',
|
|
390
|
+
color: '#ddd',
|
|
391
|
+
border: '1px solid #333',
|
|
392
|
+
padding: 6,
|
|
393
|
+
fontFamily: 'monospace',
|
|
394
|
+
fontSize: 12,
|
|
395
|
+
}}
|
|
396
|
+
placeholder='paste a `d` attribute string (M ... C/Q ...)'
|
|
397
|
+
/>
|
|
398
|
+
<button
|
|
399
|
+
onClick={diagnose}
|
|
400
|
+
style={{
|
|
401
|
+
background: '#222',
|
|
402
|
+
color: '#ddd',
|
|
403
|
+
border: '1px solid #444',
|
|
404
|
+
padding: '8px 14px',
|
|
405
|
+
cursor: 'pointer',
|
|
406
|
+
}}
|
|
407
|
+
>
|
|
408
|
+
Diagnose
|
|
409
|
+
</button>
|
|
410
|
+
</div>
|
|
411
|
+
|
|
412
|
+
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, flex: 1, minHeight: 0 }}>
|
|
413
|
+
<svg
|
|
414
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
415
|
+
width='100%'
|
|
416
|
+
height='100%'
|
|
417
|
+
viewBox='-450 -350 900 700'
|
|
418
|
+
style={{ background: '#000', border: '1px solid #222' }}
|
|
419
|
+
>
|
|
420
|
+
<line x1={-450} y1={0} x2={450} y2={0} stroke='#222' />
|
|
421
|
+
<line x1={0} y1={-350} x2={0} y2={350} stroke='#222' />
|
|
422
|
+
<circle cx={0} cy={0} r={3} fill='#444' />
|
|
423
|
+
<path ref={pathRef} d={input} fill='none' stroke='magenta' strokeWidth={2} />
|
|
424
|
+
</svg>
|
|
425
|
+
|
|
426
|
+
<pre
|
|
427
|
+
style={{
|
|
428
|
+
background: '#111',
|
|
429
|
+
padding: 10,
|
|
430
|
+
overflow: 'auto',
|
|
431
|
+
fontSize: 12,
|
|
432
|
+
margin: 0,
|
|
433
|
+
border: '1px solid #222',
|
|
434
|
+
}}
|
|
435
|
+
>
|
|
436
|
+
{info ? JSON.stringify(info, null, 2) : '(click Diagnose)'}
|
|
437
|
+
</pre>
|
|
438
|
+
</div>
|
|
439
|
+
</div>
|
|
440
|
+
);
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
export const PathInspectorStory: Story = {
|
|
444
|
+
name: 'PathInspector',
|
|
445
|
+
render: () => <PathInspector />,
|
|
446
|
+
};
|
package/src/containers/index.ts
CHANGED
|
@@ -6,38 +6,42 @@ import { useEffect, useState } from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { Capabilities } from '@dxos/app-framework';
|
|
8
8
|
import { useCapability } from '@dxos/app-framework/ui';
|
|
9
|
-
import { type
|
|
9
|
+
import { type Database, type Entity, type Filter } from '@dxos/echo';
|
|
10
10
|
import { SpaceGraphModel, type SpaceGraphModelOptions } from '@dxos/schema';
|
|
11
11
|
|
|
12
12
|
// TODO(burdon): Factor out.
|
|
13
13
|
export const useGraphModel = (
|
|
14
|
-
|
|
14
|
+
db: Database.Database | undefined,
|
|
15
15
|
filter?: Filter.Any | undefined,
|
|
16
16
|
options?: SpaceGraphModelOptions,
|
|
17
|
-
|
|
17
|
+
items?: readonly Entity.Unknown[],
|
|
18
18
|
): SpaceGraphModel | undefined => {
|
|
19
19
|
const registry = useCapability(Capabilities.AtomRegistry);
|
|
20
20
|
const [model, setModel] = useState<SpaceGraphModel | undefined>(undefined);
|
|
21
21
|
|
|
22
22
|
useEffect(() => {
|
|
23
|
-
if (!
|
|
23
|
+
if (!db) {
|
|
24
24
|
setModel(undefined);
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const newModel = new SpaceGraphModel(registry);
|
|
29
|
-
void newModel.open(
|
|
29
|
+
void newModel.open(db);
|
|
30
30
|
setModel(newModel);
|
|
31
31
|
|
|
32
32
|
return () => {
|
|
33
33
|
setModel(undefined);
|
|
34
34
|
void newModel.close();
|
|
35
35
|
};
|
|
36
|
-
}, [
|
|
36
|
+
}, [db, registry]);
|
|
37
37
|
|
|
38
38
|
useEffect(() => {
|
|
39
39
|
model?.setFilter(filter).setOptions(options);
|
|
40
40
|
}, [model, filter, options]);
|
|
41
41
|
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
model?.setItems(items);
|
|
44
|
+
}, [model, items]);
|
|
45
|
+
|
|
42
46
|
return model;
|
|
43
47
|
};
|
package/src/index.ts
CHANGED
package/src/meta.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { trim } from '@dxos/util';
|
|
|
8
8
|
export const meta: Plugin.Meta = {
|
|
9
9
|
id: 'org.dxos.plugin.explorer',
|
|
10
10
|
name: 'Explorer',
|
|
11
|
+
author: 'DXOS',
|
|
11
12
|
description: trim`
|
|
12
13
|
Interactive hypergraph visualization that reveals relationships between objects in your workspace.
|
|
13
14
|
Navigate complex data structures and discover connections through a dynamic network view.
|
|
@@ -15,6 +16,5 @@ export const meta: Plugin.Meta = {
|
|
|
15
16
|
icon: 'ph--graph--regular',
|
|
16
17
|
iconHue: 'green',
|
|
17
18
|
source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-explorer',
|
|
18
|
-
tags: ['labs'],
|
|
19
19
|
screenshots: ['https://dxos.network/plugin-details-explorer-dark.png'],
|
|
20
20
|
};
|
package/src/plugin.ts
ADDED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Key, Obj } from '@dxos/echo';
|
|
6
6
|
import { range } from '@dxos/util';
|
|
7
7
|
|
|
8
|
-
import { Tree, type TreeNodeType } from '../types';
|
|
8
|
+
import { Tree, type TreeNodeType } from '../components/Tree/types';
|
|
9
9
|
|
|
10
10
|
type NumberOrNumberArray = number | number[];
|
|
11
11
|
|
|
@@ -16,7 +16,7 @@ const random = (min: number, max: number) => Math.floor(Math.random() * (max - m
|
|
|
16
16
|
*/
|
|
17
17
|
export const createTree = (spec: NumberOrNumberArray[] = [], createText?: () => string): Tree => {
|
|
18
18
|
const tree = new Tree();
|
|
19
|
-
Obj.
|
|
19
|
+
Obj.update(tree.tree, () => {
|
|
20
20
|
tree.root.data = { text: 'root' };
|
|
21
21
|
});
|
|
22
22
|
|