@principal-ai/subsystems-react 0.21.1 → 0.22.0
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/graphify/consolidated.d.ts +5 -24
- package/dist/graphify/consolidated.d.ts.map +1 -1
- package/dist/graphify/index.d.ts +1 -1
- package/dist/graphify/index.d.ts.map +1 -1
- package/dist/graphify/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pierre/PierreSnippetView.d.ts.map +1 -1
- package/dist/pierre/PierreSnippetView.js +4 -19
- package/dist/pierre/PierreSnippetView.js.map +1 -1
- package/dist/pierre/PierreWalkthroughCodeView.d.ts.map +1 -1
- package/dist/pierre/PierreWalkthroughCodeView.js +20 -3
- package/dist/pierre/PierreWalkthroughCodeView.js.map +1 -1
- package/dist/pierre/constructColors.d.ts.map +1 -1
- package/dist/pierre/constructColors.js +0 -5
- package/dist/pierre/constructColors.js.map +1 -1
- package/dist/pierre/index.d.ts +1 -1
- package/dist/pierre/index.d.ts.map +1 -1
- package/dist/pierre/index.js +1 -1
- package/dist/pierre/index.js.map +1 -1
- package/dist/pierre/sliceSnippet.d.ts +6 -0
- package/dist/pierre/sliceSnippet.d.ts.map +1 -1
- package/dist/pierre/sliceSnippet.js +25 -0
- package/dist/pierre/sliceSnippet.js.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js +0 -3
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
- package/dist/subsystem/formatDeclaration.d.ts.map +1 -1
- package/dist/subsystem/formatDeclaration.js +0 -15
- package/dist/subsystem/formatDeclaration.js.map +1 -1
- package/dist/subsystem/model.d.ts +61 -22
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +186 -63
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/nodes.d.ts +3 -4
- package/dist/subsystem/nodes.d.ts.map +1 -1
- package/dist/subsystem/nodes.js +5 -6
- package/dist/subsystem/nodes.js.map +1 -1
- package/dist/utils/elkLayout.d.ts +6 -4
- package/dist/utils/elkLayout.d.ts.map +1 -1
- package/dist/utils/elkLayout.js +144 -54
- package/dist/utils/elkLayout.js.map +1 -1
- package/package.json +3 -3
- package/src/graphify/consolidated.ts +4 -26
- package/src/graphify/index.ts +0 -2
- package/src/index.ts +0 -2
- package/src/pierre/PierreSnippetView.tsx +4 -18
- package/src/pierre/PierreWalkthroughCodeView.tsx +39 -3
- package/src/pierre/constructColors.test.ts +1 -2
- package/src/pierre/constructColors.ts +0 -5
- package/src/pierre/index.ts +1 -1
- package/src/pierre/sliceSnippet.test.ts +44 -1
- package/src/pierre/sliceSnippet.ts +28 -0
- package/src/stories/Subsystem/ComponentDeclarationAudit.stories.tsx +0 -31
- package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +2 -46
- package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +9 -24
- package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +2 -2
- package/src/stories/Subsystem/ComponentGraph/Modules.stories.tsx +287 -0
- package/src/stories/Subsystem/ComponentGraph/Processes.stories.tsx +1 -1
- package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +6 -6
- package/src/stories/Subsystem/ComponentGraph/fixtures.ts +0 -3
- package/src/subsystem/formatDeclaration.ts +0 -19
- package/src/subsystem/model.test.ts +190 -9
- package/src/subsystem/model.ts +219 -73
- package/src/subsystem/nodes.tsx +6 -6
- package/src/utils/elkLayout.ts +148 -58
package/src/utils/elkLayout.ts
CHANGED
|
@@ -73,12 +73,13 @@ export interface ElkLayoutOptions {
|
|
|
73
73
|
direction?: 'RIGHT' | 'LEFT' | 'DOWN' | 'UP';
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Compound groups — each becomes
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
76
|
+
* Compound groups — each becomes an ELK parent whose `memberIds` are laid
|
|
77
|
+
* out inside it. `memberIds` may be leaf node ids or other group ids
|
|
78
|
+
* (for nesting, e.g. process → module → leaves). Optional `parentId`
|
|
79
|
+
* nests this group under another group; omit for a root-level frame.
|
|
80
|
+
* Members reference their immediate parent via React Flow `parentId`.
|
|
80
81
|
*/
|
|
81
|
-
groups?: Array<{ id: string; memberIds: string[] }>;
|
|
82
|
+
groups?: Array<{ id: string; memberIds: string[]; parentId?: string }>;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
/** Result of ELK layout computation */
|
|
@@ -502,51 +503,134 @@ export async function computeElkLayout(
|
|
|
502
503
|
|
|
503
504
|
// Partition leaf nodes into compound parents when groups are given.
|
|
504
505
|
// Group shells themselves are NOT part of `nodes` — they are reconstructed
|
|
505
|
-
// by the caller from `groupBounds`.
|
|
506
|
+
// by the caller from `groupBounds`. `memberIds` may reference leaves or
|
|
507
|
+
// other group ids (process → module → leaves).
|
|
506
508
|
const groupDefs = (options.groups ?? []).filter((g) => g.memberIds.length > 0);
|
|
507
|
-
const
|
|
509
|
+
const groupById = new Map(groupDefs.map((g) => [g.id, g]));
|
|
510
|
+
const elkById = new Map(elkNodes.map((n) => [n.id, n]));
|
|
511
|
+
|
|
512
|
+
const compoundLayoutOptions: LayoutOptions = {
|
|
513
|
+
'elk.algorithm': 'layered',
|
|
514
|
+
'elk.direction': direction,
|
|
515
|
+
'elk.padding': '[top=48,left=24,bottom=24,right=24]',
|
|
516
|
+
'elk.spacing.nodeNode': '40',
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
/** Descendant leaf count for singleton checks (nested groups count through). */
|
|
520
|
+
const leafDescendantCount = (memberIds: string[]): number => {
|
|
521
|
+
let n = 0;
|
|
522
|
+
for (const mid of memberIds) {
|
|
523
|
+
if (elkById.has(mid)) n += 1;
|
|
524
|
+
else {
|
|
525
|
+
const g = groupById.get(mid);
|
|
526
|
+
if (g) n += leafDescendantCount(g.memberIds);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return n;
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const builtGroups = new Map<string, ElkNode>();
|
|
533
|
+
const skippedGroups = new Set<string>();
|
|
534
|
+
const pending = [...groupDefs];
|
|
535
|
+
// Build bottom-up: a group is ready when every member is a leaf or an
|
|
536
|
+
// already-built / skipped group. Skipped groups promote their members.
|
|
537
|
+
while (pending.length > 0) {
|
|
538
|
+
let progress = false;
|
|
539
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
540
|
+
const g = pending[i]!;
|
|
541
|
+
const childNodes: ElkNode[] = [];
|
|
542
|
+
let ready = true;
|
|
543
|
+
for (const mid of g.memberIds) {
|
|
544
|
+
if (elkById.has(mid)) {
|
|
545
|
+
childNodes.push(elkById.get(mid)!);
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
if (skippedGroups.has(mid)) {
|
|
549
|
+
// Promote skipped group's members into this parent.
|
|
550
|
+
const skipped = groupById.get(mid);
|
|
551
|
+
if (!skipped) {
|
|
552
|
+
ready = false;
|
|
553
|
+
break;
|
|
554
|
+
}
|
|
555
|
+
for (const sm of skipped.memberIds) {
|
|
556
|
+
if (elkById.has(sm)) childNodes.push(elkById.get(sm)!);
|
|
557
|
+
else if (builtGroups.has(sm)) childNodes.push(builtGroups.get(sm)!);
|
|
558
|
+
else if (!skippedGroups.has(sm)) {
|
|
559
|
+
ready = false;
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (!ready) break;
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
if (builtGroups.has(mid)) {
|
|
567
|
+
childNodes.push(builtGroups.get(mid)!);
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
if (groupById.has(mid)) {
|
|
571
|
+
ready = false;
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
// Unknown id — ignore (external stubs etc. may be absent).
|
|
575
|
+
}
|
|
576
|
+
if (!ready) continue;
|
|
577
|
+
|
|
578
|
+
pending.splice(i, 1);
|
|
579
|
+
progress = true;
|
|
580
|
+
|
|
581
|
+
// Skip frames with fewer than 2 leaf descendants — promote children up.
|
|
582
|
+
if (leafDescendantCount(g.memberIds) < 2 || childNodes.length < 1) {
|
|
583
|
+
skippedGroups.add(g.id);
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
builtGroups.set(g.id, {
|
|
588
|
+
id: g.id,
|
|
589
|
+
children: childNodes,
|
|
590
|
+
layoutOptions: compoundLayoutOptions,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
if (!progress) {
|
|
594
|
+
// Cycle or unresolved refs — leave remaining groups unbuilt.
|
|
595
|
+
for (const g of pending) skippedGroups.add(g.id);
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
508
600
|
const groupedLeafIds = new Set<string>();
|
|
509
|
-
|
|
510
|
-
for (const mid of
|
|
511
|
-
if (
|
|
512
|
-
|
|
513
|
-
|
|
601
|
+
const markLeaves = (memberIds: string[]) => {
|
|
602
|
+
for (const mid of memberIds) {
|
|
603
|
+
if (elkById.has(mid)) groupedLeafIds.add(mid);
|
|
604
|
+
else {
|
|
605
|
+
const g = groupById.get(mid);
|
|
606
|
+
if (g && builtGroups.has(g.id)) markLeaves(g.memberIds);
|
|
607
|
+
else if (g && skippedGroups.has(g.id)) markLeaves(g.memberIds);
|
|
514
608
|
}
|
|
515
609
|
}
|
|
610
|
+
};
|
|
611
|
+
for (const [id] of builtGroups) {
|
|
612
|
+
const g = groupById.get(id);
|
|
613
|
+
if (g) markLeaves(g.memberIds);
|
|
516
614
|
}
|
|
517
|
-
|
|
615
|
+
|
|
518
616
|
const ungroupedElkNodes: ElkNode[] = [];
|
|
519
617
|
for (const n of elkNodes) {
|
|
520
618
|
if (!groupedLeafIds.has(n.id)) ungroupedElkNodes.push(n);
|
|
521
619
|
}
|
|
620
|
+
|
|
621
|
+
// Root-level compound parents: built groups with no parent, or whose parent
|
|
622
|
+
// was skipped / never built.
|
|
522
623
|
const elkParents: ElkNode[] = [];
|
|
523
|
-
for (const
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
// the caller drops the shell and leaves the node top-level.
|
|
529
|
-
if (children.length < 2) {
|
|
530
|
-
for (const c of children) ungroupedElkNodes.push(c);
|
|
531
|
-
memberToGroup.delete(g.memberIds[0]);
|
|
532
|
-
groupedLeafIds.delete(g.memberIds[0]);
|
|
533
|
-
continue;
|
|
534
|
-
}
|
|
535
|
-
elkParents.push({
|
|
536
|
-
id: g.id,
|
|
537
|
-
children,
|
|
538
|
-
layoutOptions: {
|
|
539
|
-
'elk.algorithm': 'layered',
|
|
540
|
-
'elk.direction': direction,
|
|
541
|
-
'elk.padding': '[top=48,left=24,bottom=24,right=24]',
|
|
542
|
-
'elk.spacing.nodeNode': '40',
|
|
543
|
-
},
|
|
544
|
-
});
|
|
624
|
+
for (const [id, node] of builtGroups) {
|
|
625
|
+
const g = groupById.get(id);
|
|
626
|
+
const parentId = g?.parentId;
|
|
627
|
+
if (parentId && builtGroups.has(parentId)) continue; // nested inside parent
|
|
628
|
+
elkParents.push(node);
|
|
545
629
|
}
|
|
546
630
|
|
|
547
631
|
// Create ELK graph
|
|
548
632
|
const rootOptions = getElkOptions(options);
|
|
549
|
-
if (elkParents.length > 0) {
|
|
633
|
+
if (elkParents.length > 0 || builtGroups.size > 0) {
|
|
550
634
|
rootOptions['elk.hierarchyHandling'] = 'INCLUDE_CHILDREN';
|
|
551
635
|
}
|
|
552
636
|
const elkGraph: ElkNode = {
|
|
@@ -562,9 +646,6 @@ export async function computeElkLayout(
|
|
|
562
646
|
// Build maps of ELK-computed positions. Nested children report
|
|
563
647
|
// parent-relative coords — flatten to absolute for edges, and keep the
|
|
564
648
|
// relative form for React Flow children (whose position is parent-relative).
|
|
565
|
-
// Absolute offset of every ELK node (parents included), accumulated down
|
|
566
|
-
// the ancestor chain — edge sections/labels are relative to their
|
|
567
|
-
// `container`, so each edge needs its container's absolute offset.
|
|
568
649
|
const elkAbsOffsets = new Map<string, { x: number; y: number }>();
|
|
569
650
|
const elkPositions = new Map<string, { x: number; y: number }>();
|
|
570
651
|
const elkRelativePositions = new Map<string, { x: number; y: number }>();
|
|
@@ -576,27 +657,36 @@ export async function computeElkLayout(
|
|
|
576
657
|
for (const c of n.children ?? []) walkElk(c, ax, ay);
|
|
577
658
|
};
|
|
578
659
|
walkElk(layoutedGraph, 0, 0);
|
|
660
|
+
|
|
661
|
+
const collectGroupResults = (n: ElkNode, isRootChild: boolean) => {
|
|
662
|
+
const isGroup = builtGroups.has(n.id);
|
|
663
|
+
if (isGroup) {
|
|
664
|
+
// Nested group positions are parent-relative (RF child semantics);
|
|
665
|
+
// root-level groups use absolute coords.
|
|
666
|
+
groupBounds.set(n.id, {
|
|
667
|
+
x: n.x ?? 0,
|
|
668
|
+
y: n.y ?? 0,
|
|
669
|
+
width: n.width ?? 0,
|
|
670
|
+
height: n.height ?? 0,
|
|
671
|
+
});
|
|
672
|
+
for (const c of n.children ?? []) {
|
|
673
|
+
const rx = c.x ?? 0;
|
|
674
|
+
const ry = c.y ?? 0;
|
|
675
|
+
elkRelativePositions.set(c.id, { x: rx, y: ry });
|
|
676
|
+
const abs = elkAbsOffsets.get(c.id) ?? { x: rx, y: ry };
|
|
677
|
+
elkPositions.set(c.id, abs);
|
|
678
|
+
if (builtGroups.has(c.id)) collectGroupResults(c, false);
|
|
679
|
+
}
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
if (isRootChild) {
|
|
683
|
+
elkPositions.set(n.id, { x: n.x ?? 0, y: n.y ?? 0 });
|
|
684
|
+
elkRelativePositions.set(n.id, { x: n.x ?? 0, y: n.y ?? 0 });
|
|
685
|
+
}
|
|
686
|
+
};
|
|
579
687
|
if (layoutedGraph.children) {
|
|
580
688
|
for (const child of layoutedGraph.children) {
|
|
581
|
-
|
|
582
|
-
const gx = child.x ?? 0;
|
|
583
|
-
const gy = child.y ?? 0;
|
|
584
|
-
groupBounds.set(child.id, {
|
|
585
|
-
x: gx,
|
|
586
|
-
y: gy,
|
|
587
|
-
width: child.width ?? 0,
|
|
588
|
-
height: child.height ?? 0,
|
|
589
|
-
});
|
|
590
|
-
for (const grand of child.children) {
|
|
591
|
-
const rx = grand.x ?? 0;
|
|
592
|
-
const ry = grand.y ?? 0;
|
|
593
|
-
elkRelativePositions.set(grand.id, { x: rx, y: ry });
|
|
594
|
-
elkPositions.set(grand.id, { x: gx + rx, y: gy + ry });
|
|
595
|
-
}
|
|
596
|
-
} else {
|
|
597
|
-
elkPositions.set(child.id, { x: child.x ?? 0, y: child.y ?? 0 });
|
|
598
|
-
elkRelativePositions.set(child.id, { x: child.x ?? 0, y: child.y ?? 0 });
|
|
599
|
-
}
|
|
689
|
+
collectGroupResults(child, true);
|
|
600
690
|
}
|
|
601
691
|
}
|
|
602
692
|
|