@dxos/plugin-explorer 0.9.1-main.c7dcc2e112 → 0.9.1-staging.ee54ba693a
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/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs +101 -0
- package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs.map +7 -0
- package/dist/lib/neutral/ExplorerPlugin.mjs +1 -1
- package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs +90 -0
- package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs.map +7 -0
- package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs +37 -0
- package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +4 -2
- package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
- package/dist/lib/neutral/{chunk-JXYIG54N.mjs → chunk-4F6AT7RA.mjs} +4 -2
- package/dist/lib/neutral/chunk-4F6AT7RA.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7XUDLV6E.mjs → chunk-EZ52JY7X.mjs} +34 -31
- package/dist/lib/neutral/chunk-EZ52JY7X.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-YBCHBVCJ.mjs → chunk-TTFPTHAQ.mjs} +8 -8
- package/dist/lib/neutral/chunk-TTFPTHAQ.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +430 -506
- package/dist/lib/neutral/components/index.mjs.map +4 -4
- package/dist/lib/neutral/containers/index.mjs +4 -2
- package/dist/lib/neutral/containers/index.mjs.map +3 -3
- package/dist/lib/neutral/{create-object-F6TKVAGV.mjs → create-object-WKIN3OB6.mjs} +3 -4
- package/dist/lib/neutral/{create-object-F6TKVAGV.mjs.map → create-object-WKIN3OB6.mjs.map} +3 -3
- package/dist/lib/neutral/hooks/index.mjs +64 -1
- package/dist/lib/neutral/hooks/index.mjs.map +4 -4
- package/dist/lib/neutral/index.mjs +1 -1
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs +39 -0
- package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs.map +7 -0
- package/dist/lib/neutral/testing/index.mjs +2 -2
- package/dist/lib/neutral/testing/index.mjs.map +2 -2
- package/dist/lib/neutral/translations.mjs +4 -1
- package/dist/lib/neutral/translations.mjs.map +2 -2
- package/dist/lib/neutral/types/index.mjs +1 -1
- package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +9 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/create-object.d.ts +1 -7
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +1 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/components/Lattice/Lattice.d.ts +1 -1
- package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -1
- package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +1 -1
- package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts +1 -1
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
- package/dist/types/src/components/Tree/index.d.ts +1 -3
- package/dist/types/src/components/Tree/index.d.ts.map +1 -1
- package/dist/types/src/components/Tree/types/tree.d.ts +10 -27
- package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
- package/dist/types/src/components/Tree/types/types.d.ts +1 -10
- package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
- package/dist/types/src/components/Visualization/Visualization.d.ts +39 -0
- package/dist/types/src/components/Visualization/Visualization.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/Visualization.stories.d.ts +13 -0
- package/dist/types/src/components/Visualization/Visualization.stories.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/index.d.ts +3 -0
- package/dist/types/src/components/Visualization/index.d.ts.map +1 -0
- package/dist/types/src/components/Visualization/variants.d.ts +53 -0
- package/dist/types/src/components/Visualization/variants.d.ts.map +1 -0
- 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 +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +2 -2
- package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -1
- package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts +14 -0
- package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts.map +1 -0
- package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts +2 -0
- package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +1 -0
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useNeighborhoodModel.d.ts +14 -0
- package/dist/types/src/hooks/useNeighborhoodModel.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +4 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/relations.d.ts +1 -2
- package/dist/types/src/testing/relations.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +6 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Graph.d.ts +6 -8
- package/dist/types/src/types/Graph.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +41 -37
- package/src/ExplorerPlugin.tsx +2 -1
- package/src/capabilities/app-graph-builder.ts +40 -0
- package/src/capabilities/create-object.ts +3 -2
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/react-surface.tsx +14 -4
- package/src/components/Lattice/Lattice.tsx +1 -2
- package/src/components/Tree/EdgeBundling.stories.tsx +5 -3
- package/src/components/Tree/Tree.stories.tsx +7 -2
- package/src/components/Tree/index.ts +3 -3
- package/src/components/Tree/types/tree.ts +6 -6
- package/src/components/Tree/types/types.ts +1 -11
- package/src/components/Visualization/Visualization.stories.tsx +104 -0
- package/src/components/Visualization/Visualization.tsx +209 -0
- package/src/components/Visualization/index.ts +6 -0
- package/src/components/Visualization/variants.ts +508 -0
- package/src/components/index.ts +1 -0
- package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +3 -3
- package/src/containers/ExplorerArticle/ExplorerArticle.tsx +7 -8
- package/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.tsx +102 -0
- package/src/containers/NeighborhoodCompanion/index.ts +5 -0
- package/src/containers/index.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useNeighborhoodModel.ts +81 -0
- package/src/testing/relations.ts +1 -3
- package/src/translations.ts +3 -0
- package/src/types/Graph.ts +18 -20
- package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs +0 -460
- package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7XUDLV6E.mjs.map +0 -7
- package/dist/lib/neutral/chunk-IKHJV3Q4.mjs +0 -20
- package/dist/lib/neutral/chunk-IKHJV3Q4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-JXYIG54N.mjs.map +0 -7
- package/dist/lib/neutral/chunk-YBCHBVCJ.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-APBW2VQG.mjs +0 -26
- package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +0 -7
- package/dist/types/src/components/Tree/Tree.d.ts +0 -24
- package/dist/types/src/components/Tree/Tree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +0 -40
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts +0 -37
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts +0 -26
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/hierarchy.d.ts +0 -17
- package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/index.d.ts +0 -6
- package/dist/types/src/components/Tree/layout/index.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/slots.d.ts +0 -7
- package/dist/types/src/components/Tree/layout/slots.d.ts.map +0 -1
- package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +0 -15
- package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +0 -1
- package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts +0 -18
- package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts.map +0 -1
- package/dist/types/src/containers/ExplorerArticle/variants.d.ts +0 -9
- package/dist/types/src/containers/ExplorerArticle/variants.d.ts.map +0 -1
- package/src/components/Tree/Tree.tsx +0 -81
- package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +0 -335
- package/src/components/Tree/layout/RadialTree.tsx +0 -242
- package/src/components/Tree/layout/TidyTree.tsx +0 -246
- package/src/components/Tree/layout/hierarchy.ts +0 -32
- package/src/components/Tree/layout/index.ts +0 -9
- package/src/components/Tree/layout/slots.ts +0 -19
- package/src/components/Tree/layout/useContainerSize.ts +0 -43
- package/src/containers/ExplorerArticle/Visualization.tsx +0 -523
- package/src/containers/ExplorerArticle/variants.ts +0 -47
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createContext } from '@radix-ui/react-context';
|
|
6
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
7
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { composableProps, slottable } from '@dxos/react-ui';
|
|
10
|
+
import {
|
|
11
|
+
type GraphLayout,
|
|
12
|
+
type GraphLayoutNode,
|
|
13
|
+
type GraphProjector,
|
|
14
|
+
GraphSwarmProjector,
|
|
15
|
+
type ModelPoint,
|
|
16
|
+
SVG,
|
|
17
|
+
type SVGContext,
|
|
18
|
+
type TreeNode,
|
|
19
|
+
} from '@dxos/react-ui-graph';
|
|
20
|
+
import { type SpaceGraphEdge, type SpaceGraphModel, type SpaceGraphNode } from '@dxos/schema';
|
|
21
|
+
import { type SlottableProps } from '@dxos/ui-types';
|
|
22
|
+
|
|
23
|
+
import { type VisualizationVariant, type VisualizationVariantId, getVariant } from './variants';
|
|
24
|
+
|
|
25
|
+
//
|
|
26
|
+
// Context
|
|
27
|
+
//
|
|
28
|
+
|
|
29
|
+
type VisualizationContextValue = {
|
|
30
|
+
model: SpaceGraphModel;
|
|
31
|
+
variant: VisualizationVariant;
|
|
32
|
+
/** Externally-supplied focus (ego centre); overrides click-driven focus when set. */
|
|
33
|
+
focus?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const [VisualizationProvider, useVisualizationContext] = createContext<VisualizationContextValue>('Visualization.Root');
|
|
37
|
+
|
|
38
|
+
//
|
|
39
|
+
// Root
|
|
40
|
+
//
|
|
41
|
+
|
|
42
|
+
export type VisualizationRootProps = SlottableProps<{
|
|
43
|
+
model: SpaceGraphModel;
|
|
44
|
+
variant: VisualizationVariantId;
|
|
45
|
+
/** Focus node id placed at the centre of ego/plexus layouts (e.g. the active node for the companion). */
|
|
46
|
+
focus?: string;
|
|
47
|
+
/** Called when the user clicks the visualization surface (e.g. to dismiss a node preview). */
|
|
48
|
+
onSurfaceClick?: () => void;
|
|
49
|
+
}>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Surface for a visualization. Resolves the variant definition and shares it (plus the model and
|
|
53
|
+
* focus) with the child `Visualization.Graph` via context, so the variant string is set in one
|
|
54
|
+
* place. The surface element is slottable via `asChild` for composition into a host layout.
|
|
55
|
+
*/
|
|
56
|
+
const VisualizationRoot = slottable<
|
|
57
|
+
HTMLDivElement,
|
|
58
|
+
{ model: SpaceGraphModel; variant: VisualizationVariantId; focus?: string; onSurfaceClick?: () => void }
|
|
59
|
+
>(({ children, asChild, model, variant, focus, onSurfaceClick, ...props }, forwardedRef) => {
|
|
60
|
+
const { className, ...rest } = composableProps(props, { classNames: 'dx-expander relative' });
|
|
61
|
+
const Comp = asChild ? Slot : 'div';
|
|
62
|
+
return (
|
|
63
|
+
<VisualizationProvider model={model} variant={getVariant(variant)} focus={focus}>
|
|
64
|
+
<Comp {...rest} className={className} onClick={onSurfaceClick} ref={forwardedRef}>
|
|
65
|
+
{children}
|
|
66
|
+
</Comp>
|
|
67
|
+
</VisualizationProvider>
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
VisualizationRoot.displayName = 'Visualization.Root';
|
|
72
|
+
|
|
73
|
+
//
|
|
74
|
+
// Graph
|
|
75
|
+
//
|
|
76
|
+
|
|
77
|
+
export type VisualizationGraphProps = {
|
|
78
|
+
debug?: boolean;
|
|
79
|
+
onNodeHover?: (node: TreeNode | null, event?: MouseEvent) => void;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Renders the active variant's projector + node renderer into a zoomable SVG surface. Reads the
|
|
84
|
+
* model, variant definition, and focus from `Visualization.Root` context; owns the live projector,
|
|
85
|
+
* click-driven focus, and the layout snapshot that lets each variant swap animate from prior positions.
|
|
86
|
+
*/
|
|
87
|
+
const VisualizationGraph = ({ debug = false, onNodeHover }: VisualizationGraphProps) => {
|
|
88
|
+
const { model, variant, focus } = useVisualizationContext('Visualization.Graph');
|
|
89
|
+
|
|
90
|
+
const svgRef = useRef<SVGContext>(null);
|
|
91
|
+
const [projector, setProjector] = useState<GraphProjector<SpaceGraphNode> | undefined>();
|
|
92
|
+
const projectorRef = useRef<GraphProjector<SpaceGraphNode> | undefined>(undefined);
|
|
93
|
+
projectorRef.current = projector;
|
|
94
|
+
|
|
95
|
+
// Click-driven focus for focusable variants (plexus). `undefined` means "no node focused".
|
|
96
|
+
const [clickFocusId, setClickFocusId] = useState<string | undefined>(undefined);
|
|
97
|
+
|
|
98
|
+
// Externally-supplied focus (e.g. the active node for the neighborhood companion) wins; otherwise
|
|
99
|
+
// the click-driven focus drives focusable variants.
|
|
100
|
+
const focusId = focus ?? clickFocusId;
|
|
101
|
+
|
|
102
|
+
// Latest layout we hand to the next SVG projector as `prev`. Captured from the live
|
|
103
|
+
// projector when the variant changes so node x/y survive the swap.
|
|
104
|
+
const lastLayoutRef = useRef<GraphLayout<SpaceGraphNode> | undefined>(undefined);
|
|
105
|
+
|
|
106
|
+
// Subscribe to the graph atom — keeps it alive across child unmounts (effect-atom
|
|
107
|
+
// disposes atoms with no subscribers) and triggers re-renders when query results land.
|
|
108
|
+
useEffect(() => model?.subscribe(() => undefined), [model]);
|
|
109
|
+
|
|
110
|
+
// Clear any click focus when leaving a focusable variant so returning starts from the bundle layout.
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (!variant.focusable) {
|
|
113
|
+
setClickFocusId(undefined);
|
|
114
|
+
}
|
|
115
|
+
}, [variant]);
|
|
116
|
+
|
|
117
|
+
// Recreate the projector when the variant or focus changes; snapshot the live layout
|
|
118
|
+
// first so the next projector animates from where the previous one left off.
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (projectorRef.current?.layout) {
|
|
121
|
+
lastLayoutRef.current = projectorRef.current.layout as GraphLayout<SpaceGraphNode>;
|
|
122
|
+
}
|
|
123
|
+
if (!svgRef.current) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
setProjector(variant.createProjector(svgRef.current, { focusId, prev: lastLayoutRef.current }));
|
|
128
|
+
}, [variant, focusId]);
|
|
129
|
+
|
|
130
|
+
// Focusable variants (plexus): clicking an object node re-focuses on it; clicking the current
|
|
131
|
+
// focus clears it. Synthetic nodes carry no ECHO object, so their clicks are ignored.
|
|
132
|
+
const handleSelect = useCallback(
|
|
133
|
+
(node: GraphLayoutNode<SpaceGraphNode>) => {
|
|
134
|
+
if (!variant.focusable || !node.data?.data?.object) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
setClickFocusId((current) => (current === node.id ? undefined : node.id));
|
|
138
|
+
},
|
|
139
|
+
[variant],
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Cursor avoidance for the SVG swarm. The Graph component hands us pre-transformed
|
|
143
|
+
// SVG model coordinates — same space the boids live in.
|
|
144
|
+
const handlePointerMove = useCallback(
|
|
145
|
+
(point: ModelPoint) => {
|
|
146
|
+
if (projector instanceof GraphSwarmProjector) {
|
|
147
|
+
projector.setCursor(point.x, point.y);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
[projector],
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const handlePointerLeave = useCallback(() => {
|
|
154
|
+
if (projector instanceof GraphSwarmProjector) {
|
|
155
|
+
projector.setCursor(null);
|
|
156
|
+
}
|
|
157
|
+
}, [projector]);
|
|
158
|
+
|
|
159
|
+
const handleInspect = useCallback(
|
|
160
|
+
(node: GraphLayoutNode<SpaceGraphNode> | null, event: MouseEvent) => {
|
|
161
|
+
if (!variant.emitsHover) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
onNodeHover?.(node ? { id: node.id, data: node.data?.data?.object } : null, event);
|
|
165
|
+
},
|
|
166
|
+
[variant, onNodeHover],
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Only attach pointer handlers when the variant tracks the cursor — others don't need them
|
|
170
|
+
// and we want to avoid the per-move CTM math when it'd be a no-op.
|
|
171
|
+
const pointerProps = variant.trackPointer
|
|
172
|
+
? { onPointerMove: handlePointerMove, onPointerLeave: handlePointerLeave }
|
|
173
|
+
: undefined;
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<SVG.Root ref={svgRef}>
|
|
177
|
+
<SVG.Zoom extent={[1 / 2, 2]}>
|
|
178
|
+
{/* Mount only once the variant's projector exists; otherwise SVG.Graph falls back to a
|
|
179
|
+
force projector for a frame, flashing the wrong layout for non-force variants. */}
|
|
180
|
+
{projector && (
|
|
181
|
+
<SVG.Graph<SpaceGraphNode, SpaceGraphEdge>
|
|
182
|
+
model={model}
|
|
183
|
+
projector={projector}
|
|
184
|
+
renderNode={variant.renderNode}
|
|
185
|
+
applyNode={variant.applyNode}
|
|
186
|
+
edgeOpacity={variant.edgeOpacity}
|
|
187
|
+
drag={variant.drag}
|
|
188
|
+
highlightOnHover={variant.highlightOnHover}
|
|
189
|
+
onSelect={handleSelect}
|
|
190
|
+
onInspect={handleInspect}
|
|
191
|
+
{...pointerProps}
|
|
192
|
+
/>
|
|
193
|
+
)}
|
|
194
|
+
</SVG.Zoom>
|
|
195
|
+
{debug && <SVG.FPS />}
|
|
196
|
+
</SVG.Root>
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
VisualizationGraph.displayName = 'Visualization.Graph';
|
|
201
|
+
|
|
202
|
+
//
|
|
203
|
+
// Visualization
|
|
204
|
+
//
|
|
205
|
+
|
|
206
|
+
export const Visualization = {
|
|
207
|
+
Root: VisualizationRoot,
|
|
208
|
+
Graph: VisualizationGraph,
|
|
209
|
+
};
|