@principal-ai/subsystems-react 0.37.9 → 0.37.11
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/subsystem/FileDrawer.d.ts +3 -1
- package/dist/subsystem/FileDrawer.d.ts.map +1 -1
- package/dist/subsystem/FileDrawer.js +2 -2
- package/dist/subsystem/FileDrawer.js.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts +13 -0
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +159 -40
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/model.d.ts +21 -0
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +4 -1
- package/dist/subsystem/model.js.map +1 -1
- package/dist/utils/elkLayout.d.ts +12 -0
- package/dist/utils/elkLayout.d.ts.map +1 -1
- package/dist/utils/elkLayout.js +10 -0
- package/dist/utils/elkLayout.js.map +1 -1
- package/package.json +1 -1
- package/src/stories/Subsystem/ComponentGraph/WalkthroughAutoplay.stories.tsx +218 -0
- package/src/subsystem/FileDrawer.tsx +4 -1
- package/src/subsystem/SubsystemComponentGraph.tsx +178 -41
- package/src/subsystem/model.ts +20 -1
- package/src/utils/elkLayout.ts +20 -0
|
@@ -13,7 +13,7 @@ export declare const FILE_DRAWER_HEIGHT_MS = 200;
|
|
|
13
13
|
* footprint so the canvas shrinks while open (nothing covered). Stays mounted
|
|
14
14
|
* so open/close/maximize animate. The header's maximize button (or a
|
|
15
15
|
* double-click) grows it over the whole graph column for whole-file reading. */
|
|
16
|
-
export declare function FileDrawer({ title, onClose, fillHeight, suppressEscape, children, }: {
|
|
16
|
+
export declare function FileDrawer({ title, onClose, fillHeight, suppressEscape, hidden, children, }: {
|
|
17
17
|
/** Drawer chrome title; `null` closes the drawer. */
|
|
18
18
|
title: string | null;
|
|
19
19
|
onClose: () => void;
|
|
@@ -21,6 +21,8 @@ export declare function FileDrawer({ title, onClose, fillHeight, suppressEscape,
|
|
|
21
21
|
fillHeight?: boolean;
|
|
22
22
|
/** Skip Escape handling (e.g. while a full-file overlay is on top). */
|
|
23
23
|
suppressEscape?: boolean;
|
|
24
|
+
/** Suppress the drawer entirely — no spacer, no panel (embeds). */
|
|
25
|
+
hidden?: boolean;
|
|
24
26
|
children?: ReactNode;
|
|
25
27
|
}): import("react").JSX.Element;
|
|
26
28
|
//# sourceMappingURL=FileDrawer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileDrawer.d.ts","sourceRoot":"","sources":["../../src/subsystem/FileDrawer.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;2EAC2E;AAC3E,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;;iFAIiF;AACjF,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,OAAO,EACP,UAAkB,EAClB,cAAsB,EACtB,QAAQ,GACT,EAAE;IACD,qDAAqD;IACrD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,+BAiJA"}
|
|
1
|
+
{"version":3,"file":"FileDrawer.d.ts","sourceRoot":"","sources":["../../src/subsystem/FileDrawer.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC;2EAC2E;AAC3E,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;;iFAIiF;AACjF,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,OAAO,EACP,UAAkB,EAClB,cAAsB,EACtB,MAAc,EACd,QAAQ,GACT,EAAE;IACD,qDAAqD;IACrD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,+BAiJA"}
|
|
@@ -16,10 +16,10 @@ export const FILE_DRAWER_HEIGHT_MS = 200;
|
|
|
16
16
|
* footprint so the canvas shrinks while open (nothing covered). Stays mounted
|
|
17
17
|
* so open/close/maximize animate. The header's maximize button (or a
|
|
18
18
|
* double-click) grows it over the whole graph column for whole-file reading. */
|
|
19
|
-
export function FileDrawer({ title, onClose, fillHeight = false, suppressEscape = false, children, }) {
|
|
19
|
+
export function FileDrawer({ title, onClose, fillHeight = false, suppressEscape = false, hidden = false, children, }) {
|
|
20
20
|
const { theme } = useTheme();
|
|
21
21
|
const muted = theme.colors.textMuted ?? theme.colors.textSecondary;
|
|
22
|
-
const open = title !== null;
|
|
22
|
+
const open = title !== null && !hidden;
|
|
23
23
|
const [closeHover, setCloseHover] = useState(false);
|
|
24
24
|
const [maxHover, setMaxHover] = useState(false);
|
|
25
25
|
// Full-height mode: the maximize button or double-clicking the header.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileDrawer.js","sourceRoot":"","sources":["../../src/subsystem/FileDrawer.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,cAAc,CAAC;AAEvD;2EAC2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC;;;;iFAIiF;AACjF,MAAM,UAAU,UAAU,CAAC,EACzB,KAAK,EACL,OAAO,EACP,UAAU,GAAG,KAAK,EAClB,cAAc,GAAG,KAAK,EACtB,QAAQ,
|
|
1
|
+
{"version":3,"file":"FileDrawer.js","sourceRoot":"","sources":["../../src/subsystem/FileDrawer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -129,6 +129,12 @@ export interface SubsystemComponentGraphProps {
|
|
|
129
129
|
* @default true
|
|
130
130
|
*/
|
|
131
131
|
zoomOnWalkthroughFocus?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Duration (ms) of the camera pan/zoom when a walkthrough step or flow is
|
|
134
|
+
* focused. Higher = a slower, more legible flight between steps.
|
|
135
|
+
* @default 300
|
|
136
|
+
*/
|
|
137
|
+
walkthroughFocusDurationMs?: number;
|
|
132
138
|
/**
|
|
133
139
|
* Subsystem title rendered as a non-interactive overlay chip on the graph
|
|
134
140
|
* canvas (top-center). Does not trigger the sidebar — for graph-only
|
|
@@ -197,6 +203,13 @@ export interface SubsystemComponentGraphProps {
|
|
|
197
203
|
* updates it as the focused step changes.
|
|
198
204
|
*/
|
|
199
205
|
renderWalkthroughViewer?: (ctx: WalkthroughViewerContext) => ReactNode;
|
|
206
|
+
/**
|
|
207
|
+
* Suppress the bottom file/walkthrough drawer entirely. Focusing a step then
|
|
208
|
+
* only frames it on the canvas (and dims the rest) without dropping a snippet
|
|
209
|
+
* panel below — for embeds that want the camera to tell the story. Defaults
|
|
210
|
+
* to false.
|
|
211
|
+
*/
|
|
212
|
+
hideDrawer?: boolean;
|
|
200
213
|
/**
|
|
201
214
|
* Legacy component-keyed variant, kept for backward compatibility. When
|
|
202
215
|
* `renderFileViewer` is absent, drawer content resolves via the first
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubsystemComponentGraph.d.ts","sourceRoot":"","sources":["../../src/subsystem/SubsystemComponentGraph.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SubsystemComponentGraph.d.ts","sourceRoot":"","sources":["../../src/subsystem/SubsystemComponentGraph.tsx"],"names":[],"mappings":"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"}
|
|
@@ -120,9 +120,9 @@ const WalkthroughDrawerContent = memo(function WalkthroughDrawerContent({ render
|
|
|
120
120
|
onSymbolClick,
|
|
121
121
|
}) }));
|
|
122
122
|
});
|
|
123
|
-
function Inner({ components, relations, walkthroughs, initialWalkthroughId, onReorderWalkthroughs, onSelect, onEdgeSelect, measured: _measured, maxNodeWidth, showEdgeLabels, showSingletonFrames = true, edgeView, title, hideSidebar, walkthroughStepMode = 'focus', autoPlayWalkthroughs = false, walkthroughAutoPlayIntervalMs = WALKTHROUGH_PLAY_PAUSE_MS, zoomOnWalkthroughFocus = true, graphTitle, showWalkthroughTitle = false, description, canvasOverlay, sidebarExtra, sidebarAfterDescription, diagnostic, issues, showIssues, focusIssueCategory, onSelectIssue, onApplyIssueFix, onHoverIssue, renderFileView, renderFileViewer, renderWalkthroughViewer, onFileSelect, componentVerification, onInspectSymbol, boundaryColors, persistKey }) {
|
|
123
|
+
function Inner({ components, relations, walkthroughs, initialWalkthroughId, onReorderWalkthroughs, onSelect, onEdgeSelect, measured: _measured, maxNodeWidth, showEdgeLabels, showSingletonFrames = true, edgeView, title, hideSidebar, walkthroughStepMode = 'focus', autoPlayWalkthroughs = false, walkthroughAutoPlayIntervalMs = WALKTHROUGH_PLAY_PAUSE_MS, zoomOnWalkthroughFocus = true, walkthroughFocusDurationMs = 300, graphTitle, showWalkthroughTitle = false, description, canvasOverlay, sidebarExtra, sidebarAfterDescription, diagnostic, issues, showIssues, focusIssueCategory, onSelectIssue, onApplyIssueFix, onHoverIssue, renderFileView, renderFileViewer, renderWalkthroughViewer, onFileSelect, componentVerification, onInspectSymbol, boundaryColors, hideDrawer = false, persistKey }) {
|
|
124
124
|
const { theme } = useTheme();
|
|
125
|
-
const { fitView } = useReactFlow();
|
|
125
|
+
const { fitView, fitBounds } = useReactFlow();
|
|
126
126
|
const viewport = useViewport();
|
|
127
127
|
// Restored once per mount from `localStorage` (see `readViewState`). Each
|
|
128
128
|
// graph is its own tab/mount, so `persistKey` is stable for a mount.
|
|
@@ -131,6 +131,7 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
131
131
|
const [built, setBuilt] = useState({
|
|
132
132
|
nodes: [],
|
|
133
133
|
edges: [],
|
|
134
|
+
absoluteRects: new Map(),
|
|
134
135
|
});
|
|
135
136
|
const [layoutReady, setLayoutReady] = useState(false);
|
|
136
137
|
const [selected, setSelected] = useState(null);
|
|
@@ -369,7 +370,7 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
369
370
|
showEdgeLabels,
|
|
370
371
|
showSingletonFrames,
|
|
371
372
|
})
|
|
372
|
-
.then(({ nodes, edges: e }) => {
|
|
373
|
+
.then(({ nodes, edges: e, absoluteRects }) => {
|
|
373
374
|
if (!alive)
|
|
374
375
|
return;
|
|
375
376
|
// Prune dims for removed leaves; keep measurements for stable ids so a
|
|
@@ -379,7 +380,7 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
379
380
|
if (!leafIds.has(id))
|
|
380
381
|
measuredDimsRef.current.delete(id);
|
|
381
382
|
}
|
|
382
|
-
setBuilt({ nodes, edges: e });
|
|
383
|
+
setBuilt({ nodes, edges: e, absoluteRects });
|
|
383
384
|
setLayoutReady(false);
|
|
384
385
|
})
|
|
385
386
|
.catch((err) => {
|
|
@@ -387,7 +388,7 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
387
388
|
if (!alive)
|
|
388
389
|
return;
|
|
389
390
|
// Reveal the cover even on failure so the UI is not stuck forever.
|
|
390
|
-
setBuilt({ nodes: [], edges: [] });
|
|
391
|
+
setBuilt({ nodes: [], edges: [], absoluteRects: new Map() });
|
|
391
392
|
setLayoutReady(true);
|
|
392
393
|
});
|
|
393
394
|
return () => { alive = false; };
|
|
@@ -419,10 +420,10 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
419
420
|
const measuredHeights = new Map(leafNodes.map((n) => [n.id, dims.get(n.id).height]));
|
|
420
421
|
const gen = ++pass2GenRef.current;
|
|
421
422
|
void buildSubsystemGraph({ components, relations, walkthroughs }, { maxNodeWidth, showEdgeLabels, measuredWidths, measuredHeights, showSingletonFrames })
|
|
422
|
-
.then(({ nodes, edges: e }) => {
|
|
423
|
+
.then(({ nodes, edges: e, absoluteRects }) => {
|
|
423
424
|
if (gen !== pass2GenRef.current)
|
|
424
425
|
return;
|
|
425
|
-
setBuilt({ nodes, edges: e });
|
|
426
|
+
setBuilt({ nodes, edges: e, absoluteRects });
|
|
426
427
|
setLayoutReady(true);
|
|
427
428
|
})
|
|
428
429
|
.catch((err) => {
|
|
@@ -516,9 +517,19 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
516
517
|
// without a stale closure value.
|
|
517
518
|
const selectedEdgeIdRef = useRef(null);
|
|
518
519
|
selectedEdgeIdRef.current = selectedEdgeId;
|
|
520
|
+
// Autoplay focus: a sidebar-less embed has no expanded flow to "open", so
|
|
521
|
+
// branding every step as a selection would hide all other nodes. Instead the
|
|
522
|
+
// autoplay sets this (flow id + step) to frame the hop and dim the rest —
|
|
523
|
+
// same treatment as hover — without hiding anything.
|
|
524
|
+
const [autoPlayFocus, setAutoPlayFocus] = useState(null);
|
|
519
525
|
// Edge ids in walkthrough focus (an active flow's edge set, or a single
|
|
520
526
|
// step's edge). Used to frame the camera. `null` = no walkthrough focus.
|
|
521
527
|
const focusEdgeIds = useMemo(() => {
|
|
528
|
+
if (autoPlayFocus) {
|
|
529
|
+
const tl = walkthroughs?.find((t) => t.id === autoPlayFocus.walkthroughId);
|
|
530
|
+
const step = tl?.steps[autoPlayFocus.stepIndex];
|
|
531
|
+
return step ? new Set([walkthroughStepGraphEdgeId(step)]) : null;
|
|
532
|
+
}
|
|
522
533
|
if (focusedWalkthroughId == null || !walkthroughs)
|
|
523
534
|
return null;
|
|
524
535
|
const tl = walkthroughs.find((t) => t.id === focusedWalkthroughId);
|
|
@@ -529,7 +540,7 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
529
540
|
return step ? new Set([walkthroughStepGraphEdgeId(step)]) : null;
|
|
530
541
|
}
|
|
531
542
|
return new Set(tl.steps.map((s) => walkthroughStepGraphEdgeId(s)));
|
|
532
|
-
}, [walkthroughs, focusedWalkthroughId, focusedStepIndex]);
|
|
543
|
+
}, [walkthroughs, focusedWalkthroughId, focusedStepIndex, autoPlayFocus]);
|
|
533
544
|
// 1-based step numbers per edge of the active flow (focused or
|
|
534
545
|
// hover/autoplay-highlighted). An edge can appear in more than one step.
|
|
535
546
|
const selectedFlowStepNos = useMemo(() => {
|
|
@@ -589,15 +600,21 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
589
600
|
// selected + hovered participants. Whole-flow focus (or no focus) keeps
|
|
590
601
|
// the old hover-replace preview so a step hover still dims the rest.
|
|
591
602
|
const previewEdgeIds = useMemo(() => {
|
|
603
|
+
// Autoplay drives focus without a hover, so its hop is the preview set.
|
|
604
|
+
if (autoPlayFocus)
|
|
605
|
+
return focusEdgeIds;
|
|
592
606
|
if (!hoverEdgeIds)
|
|
593
607
|
return null;
|
|
608
|
+
// While hovering with a *step* already selected, brighten the union of
|
|
609
|
+
// selected + hovered participants; whole-flow focus keeps the old
|
|
610
|
+
// hover-replace preview so a step hover still dims the rest.
|
|
594
611
|
if (focusedStepIndex == null || !focusEdgeIds)
|
|
595
612
|
return hoverEdgeIds;
|
|
596
613
|
const ids = new Set(hoverEdgeIds);
|
|
597
614
|
for (const id of focusEdgeIds)
|
|
598
615
|
ids.add(id);
|
|
599
616
|
return ids;
|
|
600
|
-
}, [hoverEdgeIds, focusEdgeIds, focusedStepIndex]);
|
|
617
|
+
}, [hoverEdgeIds, focusEdgeIds, focusedStepIndex, autoPlayFocus]);
|
|
601
618
|
const previewNodeIds = useMemo(() => endpointsOf(previewEdgeIds),
|
|
602
619
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
603
620
|
[baseEdges, previewEdgeIds]);
|
|
@@ -633,22 +650,26 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
633
650
|
// While a step/flow is hovered, selected + hovered participants stay
|
|
634
651
|
// bright; everything else among the currently-visible (opened-walkthrough)
|
|
635
652
|
// nodes is dimmed. Nodes outside the opened-walkthrough set stay hidden.
|
|
653
|
+
// Exception: with no expanded flow at all (a sidebar-less embed), there is
|
|
654
|
+
// nothing to hide toward — everything shows, and focus/hover only dims.
|
|
655
|
+
const noOpenedFlow = openedEdgeIds == null;
|
|
636
656
|
return xyflowNodesBase.map((n) => {
|
|
637
657
|
// Boundary frames follow their members: hidden when no member is
|
|
638
658
|
// visible, dimmed when members are dimmed. Never selectable.
|
|
639
659
|
if (n.type === 'subsystem-group') {
|
|
640
660
|
const region = n.data?.region;
|
|
641
661
|
const memberAliases = region?.memberAliases ?? [];
|
|
662
|
+
// Hover/autoplay dim-only: never hide a frame (see the node branch).
|
|
642
663
|
const vis = flowElementVisibility({
|
|
643
664
|
inOpened: memberAliases.some((alias) => openedNodeIds?.has(alias) === true),
|
|
644
665
|
inSelected: memberAliases.some((alias) => brightNodeIds?.has(alias) === true),
|
|
645
666
|
anyOpened: openedNodeIds != null,
|
|
646
|
-
anySelected: brightNodeIds != null,
|
|
667
|
+
anySelected: brightNodeIds != null || previewNodeIds != null,
|
|
647
668
|
});
|
|
648
669
|
const dimmed = previewNodeIds
|
|
649
670
|
? vis.hidden || !memberAliases.some((alias) => previewNodeIds.has(alias))
|
|
650
671
|
: vis.dimmed;
|
|
651
|
-
const hidden = vis.hidden;
|
|
672
|
+
const hidden = noOpenedFlow ? false : vis.hidden;
|
|
652
673
|
// Host override wins over the library's derived frame color.
|
|
653
674
|
const color = region?.key != null ? boundaryColors?.[region.key] : undefined;
|
|
654
675
|
return {
|
|
@@ -664,15 +685,19 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
664
685
|
}
|
|
665
686
|
const comp = n.data?.component;
|
|
666
687
|
const fileMatch = fileMatchForNode(comp?.file, openFile, focusNodeIds?.has(n.id) === true);
|
|
688
|
+
// Hover/autoplay is a dim-only signal: never hide non-participants (there
|
|
689
|
+
// may be no "opened" flow to reveal them, e.g. a sidebar-less autoplay
|
|
690
|
+
// embed), only dim them. Bases selection on the focused step, not the
|
|
691
|
+
// hover preview, so hovering doesn't strip the frame's `isSelected`.
|
|
667
692
|
const isSelected = selected?.alias !== undefined && comp?.alias === selected.alias;
|
|
668
693
|
const vis = flowElementVisibility({
|
|
669
694
|
inOpened: openedNodeIds?.has(n.id) === true,
|
|
670
695
|
inSelected: brightNodeIds?.has(n.id) === true,
|
|
671
696
|
anyOpened: openedNodeIds != null,
|
|
672
|
-
anySelected: brightNodeIds != null,
|
|
697
|
+
anySelected: brightNodeIds != null || previewNodeIds != null,
|
|
673
698
|
});
|
|
674
699
|
const dimmed = previewNodeIds ? (vis.hidden || !previewNodeIds.has(n.id)) : vis.dimmed;
|
|
675
|
-
const hidden = vis.hidden;
|
|
700
|
+
const hidden = noOpenedFlow ? false : vis.hidden;
|
|
676
701
|
if (fileMatch === undefined && !isSelected && !dimmed) {
|
|
677
702
|
const { fileMatch: _f, isSelected: _s, dimmed: _d, ...rest } = n.data;
|
|
678
703
|
return { ...n, hidden, data: rest };
|
|
@@ -846,11 +871,8 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
846
871
|
// Boundary frame → frame its members on the canvas; double-click again to
|
|
847
872
|
// zoom back out. User-initiated, so it ignores the walkthrough zoom gate.
|
|
848
873
|
if (node.type === 'subsystem-group') {
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
const key = region?.key;
|
|
852
|
-
const members = region?.memberAliases ?? [];
|
|
853
|
-
if (!key || members.length === 0)
|
|
874
|
+
const key = node.data?.region?.key;
|
|
875
|
+
if (!key)
|
|
854
876
|
return;
|
|
855
877
|
if (focusedBoundaryKey === key) {
|
|
856
878
|
setFocusedBoundaryKey(null);
|
|
@@ -864,8 +886,11 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
864
886
|
return;
|
|
865
887
|
}
|
|
866
888
|
setFocusedBoundaryKey(key);
|
|
889
|
+
// Frame the boundary node itself (not its members): the frame extends
|
|
890
|
+
// above its topmost member for the label, and fitting members alone
|
|
891
|
+
// clipped that top. The group node carries the full laid-out bounds.
|
|
867
892
|
fitView({
|
|
868
|
-
nodes:
|
|
893
|
+
nodes: [{ id: node.id }],
|
|
869
894
|
padding: 0.25,
|
|
870
895
|
duration: 300,
|
|
871
896
|
});
|
|
@@ -911,28 +936,73 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
911
936
|
window.addEventListener('keydown', onKey);
|
|
912
937
|
return () => window.removeEventListener('keydown', onKey);
|
|
913
938
|
}, [fileOverlayOpen, closeFileOverlay]);
|
|
914
|
-
// Camera helper shared by the walkthrough interactions
|
|
915
|
-
// edges' endpoint
|
|
916
|
-
//
|
|
917
|
-
//
|
|
939
|
+
// Camera helper shared by the walkthrough interactions. Fits the union of
|
|
940
|
+
// the focused edges' endpoint rects AND their routed waypoints — the edge
|
|
941
|
+
// carries its full polyline (`elkPathPoints`, absolute flow coords), so the
|
|
942
|
+
// frame is the line the hop actually traces. That keeps a hop whose route
|
|
943
|
+
// bulges out around intervening nodes from being clipped at the viewport
|
|
944
|
+
// edge, and it is the edge's own geometry doing the guiding, not fudge
|
|
945
|
+
// padding.
|
|
918
946
|
const fitFocusBounds = useCallback((ids) => {
|
|
919
947
|
if (!zoomOnWalkthroughFocus)
|
|
920
948
|
return;
|
|
921
949
|
const nodeIds = new Set();
|
|
950
|
+
const points = [];
|
|
922
951
|
for (const e of baseEdges) {
|
|
923
952
|
if (!ids.has(e.id))
|
|
924
953
|
continue;
|
|
925
954
|
nodeIds.add(e.source);
|
|
926
955
|
nodeIds.add(e.target);
|
|
956
|
+
const pts = e.data
|
|
957
|
+
?.elkPathPoints;
|
|
958
|
+
if (pts?.length)
|
|
959
|
+
points.push(...pts);
|
|
927
960
|
}
|
|
928
961
|
if (nodeIds.size === 0)
|
|
929
962
|
return;
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
963
|
+
// Box the focused edge(s): endpoint node rects UNION the routed line's
|
|
964
|
+
// waypoints. Both come from the layout in absolute flow coords, so no
|
|
965
|
+
// coordinate-space mixing (React Flow's grouped child `position`s are
|
|
966
|
+
// parent-relative and would skew the box).
|
|
967
|
+
const rects = built.absoluteRects;
|
|
968
|
+
let minX = Infinity;
|
|
969
|
+
let minY = Infinity;
|
|
970
|
+
let maxX = -Infinity;
|
|
971
|
+
let maxY = -Infinity;
|
|
972
|
+
for (const id of nodeIds) {
|
|
973
|
+
const r = rects.get(id);
|
|
974
|
+
if (!r)
|
|
975
|
+
continue;
|
|
976
|
+
minX = Math.min(minX, r.x);
|
|
977
|
+
minY = Math.min(minY, r.y);
|
|
978
|
+
maxX = Math.max(maxX, r.x + r.width);
|
|
979
|
+
maxY = Math.max(maxY, r.y + r.height);
|
|
980
|
+
}
|
|
981
|
+
for (const p of points) {
|
|
982
|
+
minX = Math.min(minX, p.x);
|
|
983
|
+
minY = Math.min(minY, p.y);
|
|
984
|
+
maxX = Math.max(maxX, p.x);
|
|
985
|
+
maxY = Math.max(maxY, p.y);
|
|
986
|
+
}
|
|
987
|
+
if (!Number.isFinite(minX) || !Number.isFinite(minY))
|
|
988
|
+
return;
|
|
989
|
+
const bounds = {
|
|
990
|
+
x: minX,
|
|
991
|
+
y: minY,
|
|
992
|
+
width: Math.max(1, maxX - minX),
|
|
993
|
+
height: Math.max(1, maxY - minY),
|
|
994
|
+
};
|
|
995
|
+
fitBounds(bounds, {
|
|
996
|
+
padding: 0.15,
|
|
997
|
+
duration: walkthroughFocusDurationMs,
|
|
934
998
|
});
|
|
935
|
-
}, [
|
|
999
|
+
}, [
|
|
1000
|
+
baseEdges,
|
|
1001
|
+
built.absoluteRects,
|
|
1002
|
+
fitBounds,
|
|
1003
|
+
zoomOnWalkthroughFocus,
|
|
1004
|
+
walkthroughFocusDurationMs,
|
|
1005
|
+
]);
|
|
936
1006
|
// Zoom back out to the full diagram after the last expanded walkthrough
|
|
937
1007
|
// closes (visibility restores non-flow nodes that were hidden).
|
|
938
1008
|
const fitOverview = useCallback(() => {
|
|
@@ -1097,9 +1167,11 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
1097
1167
|
prevPreviewEdgeIdsRef.current = previewEdgeIds;
|
|
1098
1168
|
if (!zoomOnWalkthroughFocus || walkthroughStepMode === 'dim')
|
|
1099
1169
|
return;
|
|
1100
|
-
// Camera follows hover only when a specific step is already focused
|
|
1101
|
-
|
|
1170
|
+
// Camera follows hover only when a specific step is already focused (or
|
|
1171
|
+
// autoplay is driving an auto-focus).
|
|
1172
|
+
if (!autoPlayFocus && (focusedWalkthroughId == null || focusedStepIndex == null)) {
|
|
1102
1173
|
return;
|
|
1174
|
+
}
|
|
1103
1175
|
if (previewEdgeIds) {
|
|
1104
1176
|
fitFocusBounds(previewEdgeIds);
|
|
1105
1177
|
return;
|
|
@@ -1112,46 +1184,93 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
1112
1184
|
focusEdgeIds,
|
|
1113
1185
|
focusedWalkthroughId,
|
|
1114
1186
|
focusedStepIndex,
|
|
1187
|
+
autoPlayFocus,
|
|
1115
1188
|
fitFocusBounds,
|
|
1116
1189
|
zoomOnWalkthroughFocus,
|
|
1117
1190
|
walkthroughStepMode,
|
|
1118
1191
|
]);
|
|
1119
|
-
// Graph-only embeds: cycle walkthrough steps
|
|
1192
|
+
// Graph-only embeds: cycle walkthrough steps. In `focus` mode each step is
|
|
1193
|
+
// selected (camera frames it via fitFocusBounds) and, when a walkthrough
|
|
1194
|
+
// viewer is supplied, its snippet drawer opens; in `dim` mode it only
|
|
1195
|
+
// dim-highlights the step (hover-style) with no camera move.
|
|
1120
1196
|
useEffect(() => {
|
|
1121
|
-
if (!autoPlayWalkthroughs ||
|
|
1197
|
+
if (!autoPlayWalkthroughs || walkthroughs == null || walkthroughs.length === 0)
|
|
1198
|
+
return;
|
|
1199
|
+
if (!layoutReady)
|
|
1122
1200
|
return;
|
|
1123
1201
|
const playable = walkthroughs.filter((tl) => tl.steps.length > 0);
|
|
1124
1202
|
if (playable.length === 0)
|
|
1125
1203
|
return;
|
|
1204
|
+
// Only run the cycles that can actually be shown in the current edge view.
|
|
1205
|
+
const inView = playable.filter((tl) => tl.steps.some((s) => resolvedEdgeView === 'relations'
|
|
1206
|
+
? isRelationMechanism(s.mechanism)
|
|
1207
|
+
: isWalkthroughMechanism(s.mechanism)));
|
|
1208
|
+
if (inView.length === 0)
|
|
1209
|
+
return;
|
|
1210
|
+
const cyc = inView;
|
|
1126
1211
|
let cancelled = false;
|
|
1127
1212
|
let tlIdx = 0;
|
|
1128
1213
|
let stepIdx = 0;
|
|
1129
1214
|
let timer = null;
|
|
1130
1215
|
const interval = Math.max(400, walkthroughAutoPlayIntervalMs);
|
|
1216
|
+
const focusMode = walkthroughStepMode !== 'dim';
|
|
1217
|
+
let cleanup = () => { };
|
|
1131
1218
|
const tick = () => {
|
|
1132
1219
|
if (cancelled)
|
|
1133
1220
|
return;
|
|
1134
|
-
const tl =
|
|
1221
|
+
const tl = cyc[tlIdx];
|
|
1135
1222
|
setSelected(null);
|
|
1136
1223
|
setSelectedEdgeId(null);
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1224
|
+
if (focusMode) {
|
|
1225
|
+
setHoveredWalkthroughStep(null);
|
|
1226
|
+
setFocusedWalkthroughId(null);
|
|
1227
|
+
setFocusedStepIndex(null);
|
|
1228
|
+
setAutoPlayFocus({ walkthroughId: tl.id, stepIndex: stepIdx });
|
|
1229
|
+
if (!hideDrawer) {
|
|
1230
|
+
const step = tl.steps[stepIdx];
|
|
1231
|
+
if (step) {
|
|
1232
|
+
if (renderWalkthroughViewer) {
|
|
1233
|
+
setDrawerTarget({ kind: 'walkthrough', walkthroughId: tl.id, stepIndex: stepIdx });
|
|
1234
|
+
}
|
|
1235
|
+
else {
|
|
1236
|
+
setDrawerTarget({ kind: 'file', file: step.file, startLine: step.line });
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
else {
|
|
1242
|
+
setAutoPlayFocus(null);
|
|
1243
|
+
setFocusedWalkthroughId(null);
|
|
1244
|
+
setFocusedStepIndex(null);
|
|
1245
|
+
setHoveredWalkthroughStep({ walkthroughId: tl.id, stepIndex: stepIdx });
|
|
1246
|
+
}
|
|
1140
1247
|
stepIdx += 1;
|
|
1141
1248
|
if (stepIdx >= tl.steps.length) {
|
|
1142
1249
|
stepIdx = 0;
|
|
1143
|
-
tlIdx = (tlIdx + 1) %
|
|
1250
|
+
tlIdx = (tlIdx + 1) % cyc.length;
|
|
1144
1251
|
}
|
|
1145
1252
|
timer = window.setTimeout(tick, interval);
|
|
1146
1253
|
};
|
|
1147
1254
|
tick();
|
|
1148
|
-
|
|
1255
|
+
cleanup = () => {
|
|
1149
1256
|
cancelled = true;
|
|
1150
1257
|
if (timer != null)
|
|
1151
1258
|
window.clearTimeout(timer);
|
|
1152
1259
|
setHoveredWalkthroughStep(null);
|
|
1260
|
+
setFocusedWalkthroughId(null);
|
|
1261
|
+
setFocusedStepIndex(null);
|
|
1262
|
+
setAutoPlayFocus(null);
|
|
1153
1263
|
};
|
|
1154
|
-
|
|
1264
|
+
return cleanup;
|
|
1265
|
+
}, [
|
|
1266
|
+
autoPlayWalkthroughs,
|
|
1267
|
+
walkthroughs,
|
|
1268
|
+
walkthroughAutoPlayIntervalMs,
|
|
1269
|
+
layoutReady,
|
|
1270
|
+
walkthroughStepMode,
|
|
1271
|
+
renderWalkthroughViewer,
|
|
1272
|
+
hideDrawer,
|
|
1273
|
+
]);
|
|
1155
1274
|
// Arrow keys step through the focused walkthrough once a step is active
|
|
1156
1275
|
// (sidebar click or drawer open). Ignores typing targets and chords.
|
|
1157
1276
|
useEffect(() => {
|
|
@@ -1606,7 +1725,7 @@ function Inner({ components, relations, walkthroughs, initialWalkthroughId, onRe
|
|
|
1606
1725
|
drawerTarget.startLine != null &&
|
|
1607
1726
|
!!selected.file &&
|
|
1608
1727
|
selected.file === drawerTarget.file &&
|
|
1609
|
-
selected.declarationRef?.startLine === drawerTarget.startLine }) }))] }), _jsx(FileDrawer, { title: drawerTitle, onClose: closeDrawer, fillHeight: drawerFillHeight, suppressEscape: fileOverlayOpen, children: drawerTarget?.kind === 'walkthrough' &&
|
|
1728
|
+
selected.declarationRef?.startLine === drawerTarget.startLine }) }))] }), _jsx(FileDrawer, { title: drawerTitle, onClose: closeDrawer, fillHeight: drawerFillHeight, suppressEscape: fileOverlayOpen, hidden: hideDrawer, children: drawerTarget?.kind === 'walkthrough' &&
|
|
1610
1729
|
focusedWalkthrough &&
|
|
1611
1730
|
renderWalkthroughViewer ? (_jsx(WalkthroughDrawerContent, { render: renderWalkthroughDrawerContent, walkthrough: focusedWalkthrough, stepIndex: drawerTarget.stepIndex, onOpenFile: onOpenFileFromWalkthrough, proposedAliases: proposedAliases, resolveSymbol: resolveWalkthroughSymbol, onSymbolClick: openConstructDeclaration })) : drawerTarget?.kind === 'file' ? (_jsx(FileDrawerContent, { render: renderDrawerContent, file: drawerTarget.file, startLine: drawerTarget.startLine })) : null }), fileOverlay && (_jsxs("div", { style: {
|
|
1612
1731
|
position: 'absolute',
|