@principal-ai/subsystems-react 0.43.2 → 0.44.1
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/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/subsystem/SubsystemModelTransition.d.ts +51 -0
- package/dist/subsystem/SubsystemModelTransition.d.ts.map +1 -0
- package/dist/subsystem/SubsystemModelTransition.js +404 -0
- package/dist/subsystem/SubsystemModelTransition.js.map +1 -0
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +3 -0
- package/dist/subsystem/model.js.map +1 -1
- package/dist/utils/elkLayout.d.ts +8 -0
- package/dist/utils/elkLayout.d.ts.map +1 -1
- package/dist/utils/elkLayout.js +100 -0
- package/dist/utils/elkLayout.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +5 -0
- package/src/stories/Subsystem/ComponentGraph/AnimatedProgression.stories.tsx +143 -0
- package/src/subsystem/SubsystemModelTransition.tsx +614 -0
- package/src/subsystem/model.ts +3 -0
- package/src/utils/elkLayout.ts +106 -0
package/src/utils/elkLayout.ts
CHANGED
|
@@ -94,6 +94,15 @@ export interface ElkLayoutOptions {
|
|
|
94
94
|
*/
|
|
95
95
|
orderByLine?: boolean;
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Reflow root-level compound frames into a column-major grid after ELK runs:
|
|
99
|
+
* fill each column top-to-bottom, then start the next column to the right.
|
|
100
|
+
* Gives an approximately square shape for edge-less containment graphs, which
|
|
101
|
+
* ELK otherwise packs into one long strip. No effect when edges exist (their
|
|
102
|
+
* routes would need re-routing).
|
|
103
|
+
*/
|
|
104
|
+
reflowGrid?: boolean;
|
|
105
|
+
|
|
97
106
|
/**
|
|
98
107
|
* Compound groups — each becomes an ELK parent whose `memberIds` are laid
|
|
99
108
|
* out inside it. `memberIds` may be leaf node ids or other group ids
|
|
@@ -529,6 +538,7 @@ export async function computeElkLayout(
|
|
|
529
538
|
const edgeLabels = options.edgeLabels;
|
|
530
539
|
const endpointInset = options.endpointInset ?? 0;
|
|
531
540
|
const direction = options.direction ?? 'RIGHT';
|
|
541
|
+
const reflowGrid = options.reflowGrid === true;
|
|
532
542
|
const orderByLine = options.orderByLine ?? false;
|
|
533
543
|
|
|
534
544
|
// Build a map of original node positions BEFORE passing to ELK
|
|
@@ -1023,6 +1033,102 @@ export async function computeElkLayout(
|
|
|
1023
1033
|
return node;
|
|
1024
1034
|
});
|
|
1025
1035
|
|
|
1036
|
+
// Optional column-major grid reflow for edge-less containment graphs. ELK
|
|
1037
|
+
// packs disconnected root frames into one long strip; fold them into a grid
|
|
1038
|
+
// (fill a column top-to-bottom, then start the next column) so the shape
|
|
1039
|
+
// approaches a square. Root frames are moved; their descendants (relative
|
|
1040
|
+
// group bounds / leaf positions) ride along, and absoluteRects is rebased so
|
|
1041
|
+
// hit-testing stays correct.
|
|
1042
|
+
if (reflowGrid && edges.length === 0) {
|
|
1043
|
+
const rootGroupIds: string[] = [];
|
|
1044
|
+
for (const g of groupDefs) {
|
|
1045
|
+
if (!builtGroups.has(g.id)) continue;
|
|
1046
|
+
if (g.parentId && builtGroups.has(g.parentId)) continue;
|
|
1047
|
+
rootGroupIds.push(g.id);
|
|
1048
|
+
}
|
|
1049
|
+
type GridItem = {
|
|
1050
|
+
id: string;
|
|
1051
|
+
kind: 'group' | 'leaf';
|
|
1052
|
+
x: number;
|
|
1053
|
+
y: number;
|
|
1054
|
+
w: number;
|
|
1055
|
+
h: number;
|
|
1056
|
+
};
|
|
1057
|
+
const items: GridItem[] = [];
|
|
1058
|
+
for (const id of rootGroupIds) {
|
|
1059
|
+
const b = groupBounds.get(id);
|
|
1060
|
+
if (b) items.push({ id, kind: 'group', x: b.x, y: b.y, w: b.width, h: b.height });
|
|
1061
|
+
}
|
|
1062
|
+
for (const id of ungroupedElkNodes.map((nd) => nd.id)) {
|
|
1063
|
+
const rel = elkRelativePositions.get(id) ?? { x: 0, y: 0 };
|
|
1064
|
+
const r = absoluteRects.get(id);
|
|
1065
|
+
items.push({ id, kind: 'leaf', x: rel.x, y: rel.y, w: r?.width ?? 160, h: r?.height ?? 60 });
|
|
1066
|
+
}
|
|
1067
|
+
if (items.length > 1) {
|
|
1068
|
+
const count = items.length;
|
|
1069
|
+
const rows = Math.max(1, Math.ceil(Math.sqrt(count)));
|
|
1070
|
+
const cols = Math.ceil(count / rows);
|
|
1071
|
+
const GAP = 80;
|
|
1072
|
+
const PAD = 40;
|
|
1073
|
+
const colW: number[] = new Array(cols).fill(0);
|
|
1074
|
+
const rowH: number[] = new Array(rows).fill(0);
|
|
1075
|
+
items.forEach((it, i) => {
|
|
1076
|
+
const c = Math.floor(i / rows);
|
|
1077
|
+
const r = i % rows;
|
|
1078
|
+
colW[c] = Math.max(colW[c] ?? 0, it.w);
|
|
1079
|
+
rowH[r] = Math.max(rowH[r] ?? 0, it.h);
|
|
1080
|
+
});
|
|
1081
|
+
const colX: number[] = [];
|
|
1082
|
+
let acc = PAD;
|
|
1083
|
+
for (let c = 0; c < cols; c++) {
|
|
1084
|
+
colX[c] = acc;
|
|
1085
|
+
acc += (colW[c] ?? 0) + GAP;
|
|
1086
|
+
}
|
|
1087
|
+
const rowY: number[] = [];
|
|
1088
|
+
acc = PAD;
|
|
1089
|
+
for (let r = 0; r < rows; r++) {
|
|
1090
|
+
rowY[r] = acc;
|
|
1091
|
+
acc += (rowH[r] ?? 0) + GAP;
|
|
1092
|
+
}
|
|
1093
|
+
const shiftAbsSubtree = (id: string, dx: number, dy: number) => {
|
|
1094
|
+
const ar = absoluteRects.get(id);
|
|
1095
|
+
if (ar) absoluteRects.set(id, { ...ar, x: ar.x + dx, y: ar.y + dy });
|
|
1096
|
+
const g = groupById.get(id);
|
|
1097
|
+
if (!g) return;
|
|
1098
|
+
for (const mid of g.memberIds) {
|
|
1099
|
+
if (builtGroups.has(mid)) shiftAbsSubtree(mid, dx, dy);
|
|
1100
|
+
else {
|
|
1101
|
+
const mar = absoluteRects.get(mid);
|
|
1102
|
+
if (mar) absoluteRects.set(mid, { ...mar, x: mar.x + dx, y: mar.y + dy });
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
1106
|
+
const movedLeaves = new Map<string, { x: number; y: number }>();
|
|
1107
|
+
items.forEach((it, i) => {
|
|
1108
|
+
const c = Math.floor(i / rows);
|
|
1109
|
+
const r = i % rows;
|
|
1110
|
+
const dx = (colX[c] ?? 0) - it.x;
|
|
1111
|
+
const dy = (rowY[r] ?? 0) - it.y;
|
|
1112
|
+
if (dx === 0 && dy === 0) return;
|
|
1113
|
+
if (it.kind === 'group') {
|
|
1114
|
+
const b = groupBounds.get(it.id);
|
|
1115
|
+
if (b) groupBounds.set(it.id, { ...b, x: b.x + dx, y: b.y + dy });
|
|
1116
|
+
shiftAbsSubtree(it.id, dx, dy);
|
|
1117
|
+
} else {
|
|
1118
|
+
shiftAbsSubtree(it.id, dx, dy);
|
|
1119
|
+
const rel = elkRelativePositions.get(it.id);
|
|
1120
|
+
if (rel) movedLeaves.set(it.id, { x: rel.x + dx, y: rel.y + dy });
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
if (movedLeaves.size > 0) {
|
|
1124
|
+
for (const node of resultNodes) {
|
|
1125
|
+
const m = movedLeaves.get(node.id);
|
|
1126
|
+
if (m) (node as { position: { x: number; y: number } }).position = m;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1026
1132
|
return {
|
|
1027
1133
|
nodes: resultNodes,
|
|
1028
1134
|
edgePaths,
|