@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.
Files changed (151) hide show
  1. package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs +101 -0
  2. package/dist/lib/neutral/ExplorerArticle-2WPXYTXV.mjs.map +7 -0
  3. package/dist/lib/neutral/ExplorerPlugin.mjs +1 -1
  4. package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs +90 -0
  5. package/dist/lib/neutral/NeighborhoodCompanion-WC6E3YE6.mjs.map +7 -0
  6. package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs +37 -0
  7. package/dist/lib/neutral/app-graph-builder-L2TJ6GNR.mjs.map +7 -0
  8. package/dist/lib/neutral/capabilities/index.mjs +4 -2
  9. package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
  10. package/dist/lib/neutral/{chunk-JXYIG54N.mjs → chunk-4F6AT7RA.mjs} +4 -2
  11. package/dist/lib/neutral/chunk-4F6AT7RA.mjs.map +7 -0
  12. package/dist/lib/neutral/{chunk-7XUDLV6E.mjs → chunk-EZ52JY7X.mjs} +34 -31
  13. package/dist/lib/neutral/chunk-EZ52JY7X.mjs.map +7 -0
  14. package/dist/lib/neutral/{chunk-YBCHBVCJ.mjs → chunk-TTFPTHAQ.mjs} +8 -8
  15. package/dist/lib/neutral/chunk-TTFPTHAQ.mjs.map +7 -0
  16. package/dist/lib/neutral/components/index.mjs +430 -506
  17. package/dist/lib/neutral/components/index.mjs.map +4 -4
  18. package/dist/lib/neutral/containers/index.mjs +4 -2
  19. package/dist/lib/neutral/containers/index.mjs.map +3 -3
  20. package/dist/lib/neutral/{create-object-F6TKVAGV.mjs → create-object-WKIN3OB6.mjs} +3 -4
  21. package/dist/lib/neutral/{create-object-F6TKVAGV.mjs.map → create-object-WKIN3OB6.mjs.map} +3 -3
  22. package/dist/lib/neutral/hooks/index.mjs +64 -1
  23. package/dist/lib/neutral/hooks/index.mjs.map +4 -4
  24. package/dist/lib/neutral/index.mjs +1 -1
  25. package/dist/lib/neutral/meta.json +1 -1
  26. package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs +39 -0
  27. package/dist/lib/neutral/react-surface-EWPG5PUQ.mjs.map +7 -0
  28. package/dist/lib/neutral/testing/index.mjs +2 -2
  29. package/dist/lib/neutral/testing/index.mjs.map +2 -2
  30. package/dist/lib/neutral/translations.mjs +4 -1
  31. package/dist/lib/neutral/translations.mjs.map +2 -2
  32. package/dist/lib/neutral/types/index.mjs +1 -1
  33. package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
  34. package/dist/types/src/capabilities/app-graph-builder.d.ts +9 -0
  35. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  36. package/dist/types/src/capabilities/create-object.d.ts +1 -7
  37. package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
  38. package/dist/types/src/capabilities/index.d.ts +1 -0
  39. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  40. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  41. package/dist/types/src/components/Lattice/Lattice.d.ts +1 -1
  42. package/dist/types/src/components/Lattice/Lattice.d.ts.map +1 -1
  43. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts +1 -1
  44. package/dist/types/src/components/Tree/EdgeBundling.stories.d.ts.map +1 -1
  45. package/dist/types/src/components/Tree/Tree.stories.d.ts +1 -1
  46. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  47. package/dist/types/src/components/Tree/index.d.ts +1 -3
  48. package/dist/types/src/components/Tree/index.d.ts.map +1 -1
  49. package/dist/types/src/components/Tree/types/tree.d.ts +10 -27
  50. package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
  51. package/dist/types/src/components/Tree/types/types.d.ts +1 -10
  52. package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
  53. package/dist/types/src/components/Visualization/Visualization.d.ts +39 -0
  54. package/dist/types/src/components/Visualization/Visualization.d.ts.map +1 -0
  55. package/dist/types/src/components/Visualization/Visualization.stories.d.ts +13 -0
  56. package/dist/types/src/components/Visualization/Visualization.stories.d.ts.map +1 -0
  57. package/dist/types/src/components/Visualization/index.d.ts +3 -0
  58. package/dist/types/src/components/Visualization/index.d.ts.map +1 -0
  59. package/dist/types/src/components/Visualization/variants.d.ts +53 -0
  60. package/dist/types/src/components/Visualization/variants.d.ts.map +1 -0
  61. package/dist/types/src/components/index.d.ts +1 -0
  62. package/dist/types/src/components/index.d.ts.map +1 -1
  63. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts +1 -1
  64. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.d.ts.map +1 -1
  65. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts +2 -2
  66. package/dist/types/src/containers/ExplorerArticle/ExplorerArticle.stories.d.ts.map +1 -1
  67. package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts +14 -0
  68. package/dist/types/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.d.ts.map +1 -0
  69. package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts +2 -0
  70. package/dist/types/src/containers/NeighborhoodCompanion/index.d.ts.map +1 -0
  71. package/dist/types/src/containers/index.d.ts +1 -0
  72. package/dist/types/src/containers/index.d.ts.map +1 -1
  73. package/dist/types/src/hooks/index.d.ts +1 -0
  74. package/dist/types/src/hooks/index.d.ts.map +1 -1
  75. package/dist/types/src/hooks/useNeighborhoodModel.d.ts +14 -0
  76. package/dist/types/src/hooks/useNeighborhoodModel.d.ts.map +1 -0
  77. package/dist/types/src/meta.d.ts +4 -0
  78. package/dist/types/src/meta.d.ts.map +1 -1
  79. package/dist/types/src/testing/relations.d.ts +1 -2
  80. package/dist/types/src/testing/relations.d.ts.map +1 -1
  81. package/dist/types/src/translations.d.ts +6 -0
  82. package/dist/types/src/translations.d.ts.map +1 -1
  83. package/dist/types/src/types/Graph.d.ts +6 -8
  84. package/dist/types/src/types/Graph.d.ts.map +1 -1
  85. package/dist/types/tsconfig.tsbuildinfo +1 -1
  86. package/package.json +41 -37
  87. package/src/ExplorerPlugin.tsx +2 -1
  88. package/src/capabilities/app-graph-builder.ts +40 -0
  89. package/src/capabilities/create-object.ts +3 -2
  90. package/src/capabilities/index.ts +1 -0
  91. package/src/capabilities/react-surface.tsx +14 -4
  92. package/src/components/Lattice/Lattice.tsx +1 -2
  93. package/src/components/Tree/EdgeBundling.stories.tsx +5 -3
  94. package/src/components/Tree/Tree.stories.tsx +7 -2
  95. package/src/components/Tree/index.ts +3 -3
  96. package/src/components/Tree/types/tree.ts +6 -6
  97. package/src/components/Tree/types/types.ts +1 -11
  98. package/src/components/Visualization/Visualization.stories.tsx +104 -0
  99. package/src/components/Visualization/Visualization.tsx +209 -0
  100. package/src/components/Visualization/index.ts +6 -0
  101. package/src/components/Visualization/variants.ts +508 -0
  102. package/src/components/index.ts +1 -0
  103. package/src/containers/ExplorerArticle/ExplorerArticle.stories.tsx +3 -3
  104. package/src/containers/ExplorerArticle/ExplorerArticle.tsx +7 -8
  105. package/src/containers/NeighborhoodCompanion/NeighborhoodCompanion.tsx +102 -0
  106. package/src/containers/NeighborhoodCompanion/index.ts +5 -0
  107. package/src/containers/index.ts +1 -0
  108. package/src/hooks/index.ts +1 -0
  109. package/src/hooks/useNeighborhoodModel.ts +81 -0
  110. package/src/testing/relations.ts +1 -3
  111. package/src/translations.ts +3 -0
  112. package/src/types/Graph.ts +18 -20
  113. package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs +0 -460
  114. package/dist/lib/neutral/ExplorerArticle-MHEINWUL.mjs.map +0 -7
  115. package/dist/lib/neutral/chunk-7XUDLV6E.mjs.map +0 -7
  116. package/dist/lib/neutral/chunk-IKHJV3Q4.mjs +0 -20
  117. package/dist/lib/neutral/chunk-IKHJV3Q4.mjs.map +0 -7
  118. package/dist/lib/neutral/chunk-JXYIG54N.mjs.map +0 -7
  119. package/dist/lib/neutral/chunk-YBCHBVCJ.mjs.map +0 -7
  120. package/dist/lib/neutral/react-surface-APBW2VQG.mjs +0 -26
  121. package/dist/lib/neutral/react-surface-APBW2VQG.mjs.map +0 -7
  122. package/dist/types/src/components/Tree/Tree.d.ts +0 -24
  123. package/dist/types/src/components/Tree/Tree.d.ts.map +0 -1
  124. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +0 -40
  125. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +0 -1
  126. package/dist/types/src/components/Tree/layout/RadialTree.d.ts +0 -37
  127. package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +0 -1
  128. package/dist/types/src/components/Tree/layout/TidyTree.d.ts +0 -26
  129. package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +0 -1
  130. package/dist/types/src/components/Tree/layout/hierarchy.d.ts +0 -17
  131. package/dist/types/src/components/Tree/layout/hierarchy.d.ts.map +0 -1
  132. package/dist/types/src/components/Tree/layout/index.d.ts +0 -6
  133. package/dist/types/src/components/Tree/layout/index.d.ts.map +0 -1
  134. package/dist/types/src/components/Tree/layout/slots.d.ts +0 -7
  135. package/dist/types/src/components/Tree/layout/slots.d.ts.map +0 -1
  136. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts +0 -15
  137. package/dist/types/src/components/Tree/layout/useContainerSize.d.ts.map +0 -1
  138. package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts +0 -18
  139. package/dist/types/src/containers/ExplorerArticle/Visualization.d.ts.map +0 -1
  140. package/dist/types/src/containers/ExplorerArticle/variants.d.ts +0 -9
  141. package/dist/types/src/containers/ExplorerArticle/variants.d.ts.map +0 -1
  142. package/src/components/Tree/Tree.tsx +0 -81
  143. package/src/components/Tree/layout/HierarchicalEdgeBundling.tsx +0 -335
  144. package/src/components/Tree/layout/RadialTree.tsx +0 -242
  145. package/src/components/Tree/layout/TidyTree.tsx +0 -246
  146. package/src/components/Tree/layout/hierarchy.ts +0 -32
  147. package/src/components/Tree/layout/index.ts +0 -9
  148. package/src/components/Tree/layout/slots.ts +0 -19
  149. package/src/components/Tree/layout/useContainerSize.ts +0 -43
  150. package/src/containers/ExplorerArticle/Visualization.tsx +0 -523
  151. 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
+ };
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export * from './Visualization';
6
+ export * from './variants';