@ai-digital-factory/state-flow 0.1.0 → 0.1.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/README.md +106 -4
- package/dist/index.d.ts +119 -37
- package/dist/index.js +457 -211
- package/dist/state-flow.css +70 -5
- package/package.json +4 -4
- /package/{tsconfig.charts.json → tsconfig.flows.json} +0 -0
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ function StateFlowPlaceholder() {
|
|
|
7
7
|
// src/Flow.tsx
|
|
8
8
|
import { useId, useMemo } from "react";
|
|
9
9
|
|
|
10
|
-
// src/
|
|
10
|
+
// src/flow-visuals.tsx
|
|
11
11
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
12
12
|
function SvgIcon({
|
|
13
13
|
children,
|
|
@@ -15,10 +15,8 @@ function SvgIcon({
|
|
|
15
15
|
}) {
|
|
16
16
|
return /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 24 24", width: size, height: size, fill: "none", children });
|
|
17
17
|
}
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
}) {
|
|
21
|
-
const key = (chartId ?? "").toLowerCase();
|
|
18
|
+
function FlowHeaderIcon({ flowId }) {
|
|
19
|
+
const key = (flowId ?? "").toLowerCase();
|
|
22
20
|
if (key.includes("visitor") || key.includes("access")) {
|
|
23
21
|
return /* @__PURE__ */ jsxs(SvgIcon, { children: [
|
|
24
22
|
/* @__PURE__ */ jsx2(
|
|
@@ -126,8 +124,8 @@ function ChartHeaderIcon({
|
|
|
126
124
|
)
|
|
127
125
|
] });
|
|
128
126
|
}
|
|
129
|
-
function
|
|
130
|
-
const key =
|
|
127
|
+
function flowNavIcon(flowId) {
|
|
128
|
+
const key = flowId.toLowerCase();
|
|
131
129
|
if (key.includes("visitor") || key.includes("access")) {
|
|
132
130
|
return "\u25CE";
|
|
133
131
|
}
|
|
@@ -140,16 +138,16 @@ function chartNavIcon(chartId) {
|
|
|
140
138
|
return "\u25C6";
|
|
141
139
|
}
|
|
142
140
|
|
|
143
|
-
// src/
|
|
141
|
+
// src/FlowPageHeader.tsx
|
|
144
142
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
145
|
-
function
|
|
143
|
+
function FlowPageHeader({
|
|
146
144
|
title,
|
|
147
145
|
description,
|
|
148
|
-
|
|
146
|
+
flowId
|
|
149
147
|
}) {
|
|
150
|
-
return /* @__PURE__ */ jsxs2("header", { className: "sf-
|
|
151
|
-
/* @__PURE__ */ jsx3("div", { className: "sf-
|
|
152
|
-
/* @__PURE__ */ jsxs2("div", { className: "sf-
|
|
148
|
+
return /* @__PURE__ */ jsxs2("header", { className: "sf-flow-page-header", children: [
|
|
149
|
+
/* @__PURE__ */ jsx3("div", { className: "sf-flow-page-header-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(FlowHeaderIcon, { flowId: flowId ?? title }) }),
|
|
150
|
+
/* @__PURE__ */ jsxs2("div", { className: "sf-flow-page-header-text", children: [
|
|
153
151
|
/* @__PURE__ */ jsx3("h2", { className: "sf-title", children: title }),
|
|
154
152
|
/* @__PURE__ */ jsx3("p", { className: "sf-intro", children: description })
|
|
155
153
|
] })
|
|
@@ -377,6 +375,39 @@ function focusToSelection(focus, edges) {
|
|
|
377
375
|
function outgoingTransitions(edges, stateId) {
|
|
378
376
|
return edges.filter((edge) => edge.fromId === stateId);
|
|
379
377
|
}
|
|
378
|
+
function DestinationList({
|
|
379
|
+
edges,
|
|
380
|
+
edge
|
|
381
|
+
}) {
|
|
382
|
+
const destinations = edges.filter(
|
|
383
|
+
(candidate) => candidate.name === edge.name && candidate.fromId === edge.fromId
|
|
384
|
+
);
|
|
385
|
+
return /* @__PURE__ */ jsx5(
|
|
386
|
+
"ul",
|
|
387
|
+
{
|
|
388
|
+
className: "sf-overview-destination-list",
|
|
389
|
+
"aria-label": destinations.length > 1 ? "Branch destinations" : "Destination",
|
|
390
|
+
children: destinations.map((destination) => /* @__PURE__ */ jsxs4(
|
|
391
|
+
"li",
|
|
392
|
+
{
|
|
393
|
+
className: `sf-overview-legend-route${destination.toId === edge.toId && destinations.length > 1 ? " is-selected" : ""}`,
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ jsxs4("code", { children: [
|
|
396
|
+
destination.fromName,
|
|
397
|
+
" \u2192 ",
|
|
398
|
+
destination.toName
|
|
399
|
+
] }),
|
|
400
|
+
destination.destinationDescription ? /* @__PURE__ */ jsxs4("span", { className: "sf-overview-destination-detail", children: [
|
|
401
|
+
" ",
|
|
402
|
+
destination.destinationDescription
|
|
403
|
+
] }) : null
|
|
404
|
+
]
|
|
405
|
+
},
|
|
406
|
+
destination.toId
|
|
407
|
+
))
|
|
408
|
+
}
|
|
409
|
+
);
|
|
410
|
+
}
|
|
380
411
|
function DiagramOverview({
|
|
381
412
|
svgHtml,
|
|
382
413
|
states,
|
|
@@ -687,12 +718,8 @@ function DiagramOverview({
|
|
|
687
718
|
] }),
|
|
688
719
|
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-title", children: /* @__PURE__ */ jsx5("strong", { children: edge.name }) }),
|
|
689
720
|
guardBlockedActive ? /* @__PURE__ */ jsx5("p", { className: "sf-overview-guard-blocked-note", children: "Guard blocked this transition." }) : null,
|
|
690
|
-
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-
|
|
691
|
-
|
|
692
|
-
" \u2192 ",
|
|
693
|
-
edge.toName
|
|
694
|
-
] }) }),
|
|
695
|
-
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-detail", children: edge.description })
|
|
721
|
+
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-detail", children: edge.description }),
|
|
722
|
+
/* @__PURE__ */ jsx5(DestinationList, { edges, edge })
|
|
696
723
|
]
|
|
697
724
|
}
|
|
698
725
|
);
|
|
@@ -711,7 +738,13 @@ function DiagramOverview({
|
|
|
711
738
|
] }),
|
|
712
739
|
/* @__PURE__ */ jsxs4("div", { className: "sf-overview-detail-title-row", children: [
|
|
713
740
|
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-title", children: /* @__PURE__ */ jsx5("strong", { children: state.name }) }),
|
|
714
|
-
/* @__PURE__ */ jsx5(
|
|
741
|
+
/* @__PURE__ */ jsx5(
|
|
742
|
+
"span",
|
|
743
|
+
{
|
|
744
|
+
className: `sf-overview-detail-kind-tag${state.kind === "final" ? " is-final" : ""}`,
|
|
745
|
+
children: state.kind === "final" ? "Final state" : "State"
|
|
746
|
+
}
|
|
747
|
+
)
|
|
715
748
|
] }),
|
|
716
749
|
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-detail", children: state.description })
|
|
717
750
|
] }),
|
|
@@ -749,7 +782,8 @@ function DiagramOverview({
|
|
|
749
782
|
/* @__PURE__ */ jsxs4("span", { className: "sf-overview-transitions-route", children: [
|
|
750
783
|
edge.fromName,
|
|
751
784
|
" \u2192 ",
|
|
752
|
-
edge.toName
|
|
785
|
+
edge.toName,
|
|
786
|
+
edge.destinationCount > 1 ? ` (${edge.destinationDescription})` : ""
|
|
753
787
|
] })
|
|
754
788
|
]
|
|
755
789
|
}
|
|
@@ -776,12 +810,8 @@ function DiagramOverview({
|
|
|
776
810
|
detailContent = /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
777
811
|
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-title", children: /* @__PURE__ */ jsx5("strong", { children: edge.name }) }),
|
|
778
812
|
guardBlockedActive ? /* @__PURE__ */ jsx5("p", { className: "sf-overview-guard-blocked-note", children: "Guard blocked this transition." }) : null,
|
|
779
|
-
/* @__PURE__ */
|
|
780
|
-
|
|
781
|
-
" \u2192 ",
|
|
782
|
-
edge.toName
|
|
783
|
-
] }),
|
|
784
|
-
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-detail", children: edge.description })
|
|
813
|
+
/* @__PURE__ */ jsx5("p", { className: "sf-overview-legend-detail", children: edge.description }),
|
|
814
|
+
/* @__PURE__ */ jsx5(DestinationList, { edges, edge })
|
|
785
815
|
] });
|
|
786
816
|
}
|
|
787
817
|
} else {
|
|
@@ -1054,9 +1084,9 @@ function layoutSelfLoop(cx, top, slot, slotsOnState) {
|
|
|
1054
1084
|
function roundCoord(value) {
|
|
1055
1085
|
return Math.round(value * 10) / 10;
|
|
1056
1086
|
}
|
|
1057
|
-
function countSelfLoopsPerState(
|
|
1087
|
+
function countSelfLoopsPerState(flow) {
|
|
1058
1088
|
const counts = /* @__PURE__ */ new Map();
|
|
1059
|
-
for (const edge of
|
|
1089
|
+
for (const edge of flow.edges) {
|
|
1060
1090
|
if (edge.fromId !== edge.toId) {
|
|
1061
1091
|
continue;
|
|
1062
1092
|
}
|
|
@@ -1071,8 +1101,26 @@ function maxSelfLoopsOnOneState(counts) {
|
|
|
1071
1101
|
}
|
|
1072
1102
|
return max;
|
|
1073
1103
|
}
|
|
1104
|
+
function wrapBranchLabel(text) {
|
|
1105
|
+
const words = text.trim().split(/\s+/);
|
|
1106
|
+
const lines = [""];
|
|
1107
|
+
for (const word of words) {
|
|
1108
|
+
const last = lines.length - 1;
|
|
1109
|
+
if (lines[last] && lines[last].length + word.length + 1 > 20) {
|
|
1110
|
+
if (lines.length === 2) {
|
|
1111
|
+
lines[last] = `${lines[last].slice(0, 18)}\u2026`;
|
|
1112
|
+
return lines;
|
|
1113
|
+
}
|
|
1114
|
+
lines.push(word);
|
|
1115
|
+
} else {
|
|
1116
|
+
lines[last] += `${lines[last] ? " " : ""}${word}`;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
return lines;
|
|
1120
|
+
}
|
|
1074
1121
|
function transitionLabelBadge(options) {
|
|
1075
|
-
const
|
|
1122
|
+
const branch = options.branchLabel !== void 0;
|
|
1123
|
+
const lines = branch ? wrapBranchLabel(options.branchLabel) : wrapEdgeLabel(options.edgeName);
|
|
1076
1124
|
const charWidth = 6.35;
|
|
1077
1125
|
const lineHeight = 12;
|
|
1078
1126
|
const padX = 10;
|
|
@@ -1088,20 +1136,34 @@ function transitionLabelBadge(options) {
|
|
|
1088
1136
|
const textContent = lines.map(
|
|
1089
1137
|
(line, lineIndex) => `<tspan x="${options.cx}" y="${textAnchorY + lineIndex * lineHeight}">${escapeXml(line)}</tspan>`
|
|
1090
1138
|
).join("");
|
|
1091
|
-
|
|
1139
|
+
const label = branch ? `${options.edgeName}: ${options.branchLabel}` : options.edgeName;
|
|
1140
|
+
return `<g class="overview-edge-hit${branch ? " overview-branch-hit" : ""}" data-edge-index="${options.index}" role="button" tabindex="0" aria-label="${escapeXml(label)}"><path d="${options.path}" fill="none" stroke="transparent" stroke-width="22"/><rect class="overview-edge-hit-area" x="${x - 6}" y="${y - 6}" width="${width + 12}" height="${height + 12}" rx="${(height + 12) / 2}" fill="transparent"/><rect class="overview-edge-badge${branch ? " overview-branch-badge" : ""}" x="${x}" y="${y}" width="${width}" height="${height}" rx="${branch ? 6 : height / 2}" fill="${branch ? "var(--sf-panel)" : "var(--sf-selected)"}" stroke="var(--sf-accent)" stroke-width="${branch ? 1.5 : 2}"${branch ? ' stroke-dasharray="4 3"' : ""}/><text text-anchor="middle" fill="var(--sf-ink)" font-size="10" font-weight="${branch ? 500 : 600}" ${branch ? 'font-style="italic" ' : ""}pointer-events="none">${textContent}</text></g>`;
|
|
1092
1141
|
}
|
|
1093
|
-
function
|
|
1094
|
-
const
|
|
1142
|
+
function splitNodeMarkup(options) {
|
|
1143
|
+
const r = 7;
|
|
1144
|
+
const { x, y } = options;
|
|
1145
|
+
return `<g class="overview-edge-hit overview-split-hit" data-edge-index="${options.index}" role="button" tabindex="0" aria-label="${escapeXml(`${options.edgeName} (branches)`)}"><path class="overview-split-node" d="M ${x} ${y - r} L ${x + r} ${y} L ${x} ${y + r} L ${x - r} ${y} Z" fill="var(--sf-accent)" stroke="var(--sf-panel)" stroke-width="1.5"/></g>`;
|
|
1146
|
+
}
|
|
1147
|
+
function diagramSvg(flow, title, instanceId) {
|
|
1148
|
+
const templates = flow.states.map(
|
|
1149
|
+
(state) => (state.composition?.regions ?? []).filter((region) => region.kind !== "inline").map(
|
|
1150
|
+
(region) => region.kind === "list" ? `${region.name}: ${region.flow}[ ]` : `${region.name}: ${region.flow}`
|
|
1151
|
+
)
|
|
1152
|
+
);
|
|
1153
|
+
const labels = flow.states.map((state, index) => [
|
|
1154
|
+
...wrapLabel(state.name),
|
|
1155
|
+
...templates[index]
|
|
1156
|
+
]);
|
|
1095
1157
|
const boxHeight = Math.max(
|
|
1096
1158
|
54,
|
|
1097
1159
|
...labels.map((lines) => lines.length * 17 + 24)
|
|
1098
1160
|
);
|
|
1099
|
-
const width = Math.max(280,
|
|
1161
|
+
const width = Math.max(280, flow.states.length * 260 + 24);
|
|
1100
1162
|
const markerId = escapeXml(`${instanceId}-arrow`);
|
|
1101
1163
|
const centers = new Map(
|
|
1102
|
-
|
|
1164
|
+
flow.states.map((state, index) => [state.id, 142 + index * 260])
|
|
1103
1165
|
);
|
|
1104
|
-
const routes =
|
|
1166
|
+
const routes = flow.edges.map((edge, index) => {
|
|
1105
1167
|
const from = centers.get(edge.fromId);
|
|
1106
1168
|
const to = centers.get(edge.toId);
|
|
1107
1169
|
return {
|
|
@@ -1117,7 +1179,7 @@ function diagramSvg(chart, title, instanceId) {
|
|
|
1117
1179
|
for (const center of centers.values()) {
|
|
1118
1180
|
for (const above of [true, false]) {
|
|
1119
1181
|
const ports = routes.filter((route) => {
|
|
1120
|
-
const edge =
|
|
1182
|
+
const edge = flow.edges[route.index];
|
|
1121
1183
|
return edge.fromId !== edge.toId && route.above === above;
|
|
1122
1184
|
}).flatMap((route) => [
|
|
1123
1185
|
...route.from === center ? [{ route, key: "start", neighbor: route.to }] : [],
|
|
@@ -1130,14 +1192,23 @@ function diagramSvg(chart, title, instanceId) {
|
|
|
1130
1192
|
});
|
|
1131
1193
|
}
|
|
1132
1194
|
}
|
|
1133
|
-
const
|
|
1195
|
+
const sharedStart = /* @__PURE__ */ new Map();
|
|
1196
|
+
for (const route of routes) {
|
|
1197
|
+
const edge = flow.edges[route.index];
|
|
1198
|
+
if (edge.destinationCount < 2 || edge.fromId === edge.toId) continue;
|
|
1199
|
+
const key = `${edge.name}:${route.above}`;
|
|
1200
|
+
const shared = sharedStart.get(key);
|
|
1201
|
+
if (shared === void 0) sharedStart.set(key, route.start);
|
|
1202
|
+
else route.start = shared;
|
|
1203
|
+
}
|
|
1204
|
+
const selfLoopCounts = countSelfLoopsPerState(flow);
|
|
1134
1205
|
const maxSelfLoopsOnState = maxSelfLoopsOnOneState(selfLoopCounts);
|
|
1135
1206
|
const selfLoopReserved = maxSelfLoopsOnState > 0 ? SELF_LOOP_BAND_HEIGHT + (maxSelfLoopsOnState - 1) * 4 : 0;
|
|
1136
1207
|
const laneCounts = { above: 0, below: 0 };
|
|
1137
1208
|
for (const above of [true, false]) {
|
|
1138
1209
|
const lanes = [];
|
|
1139
1210
|
const sorted = routes.filter((route) => {
|
|
1140
|
-
const edge =
|
|
1211
|
+
const edge = flow.edges[route.index];
|
|
1141
1212
|
return edge.fromId !== edge.toId && route.above === above;
|
|
1142
1213
|
}).sort(
|
|
1143
1214
|
(a, b) => Math.abs(a.end - a.start) - Math.abs(b.end - b.start) || a.index - b.index
|
|
@@ -1161,8 +1232,12 @@ function diagramSvg(chart, title, instanceId) {
|
|
|
1161
1232
|
const bottom = top + boxHeight;
|
|
1162
1233
|
const paths = [];
|
|
1163
1234
|
const badges = [];
|
|
1235
|
+
const splits = [];
|
|
1236
|
+
const drawnSplits = /* @__PURE__ */ new Set();
|
|
1164
1237
|
const selfLoopSlot = /* @__PURE__ */ new Map();
|
|
1165
|
-
|
|
1238
|
+
const edgeClass = (edge) => edge.destinationCount > 1 ? "flow-edge flow-edge-branch" : "flow-edge";
|
|
1239
|
+
flow.edges.forEach((edge, index) => {
|
|
1240
|
+
const branching = edge.destinationCount > 1;
|
|
1166
1241
|
if (edge.fromId === edge.toId) {
|
|
1167
1242
|
const cx = centers.get(edge.fromId);
|
|
1168
1243
|
const slotsOnState = selfLoopCounts.get(edge.fromId) ?? 1;
|
|
@@ -1170,7 +1245,7 @@ function diagramSvg(chart, title, instanceId) {
|
|
|
1170
1245
|
selfLoopSlot.set(edge.fromId, slot + 1);
|
|
1171
1246
|
const layout = layoutSelfLoop(cx, top, slot, slotsOnState);
|
|
1172
1247
|
paths.push(
|
|
1173
|
-
`<path class="
|
|
1248
|
+
`<path class="${edgeClass(edge)} flow-edge-self" data-edge-index="${index}" d="${layout.path}" fill="none" stroke="var(--sf-accent)" stroke-width="2.5" data-transition="${escapeXml(edge.name)}" marker-end="url(#${markerId})"/>`
|
|
1174
1249
|
);
|
|
1175
1250
|
badges.push(
|
|
1176
1251
|
transitionLabelBadge({
|
|
@@ -1178,7 +1253,8 @@ function diagramSvg(chart, title, instanceId) {
|
|
|
1178
1253
|
cx: layout.labelCx,
|
|
1179
1254
|
cy: layout.labelCy,
|
|
1180
1255
|
index,
|
|
1181
|
-
path: layout.path
|
|
1256
|
+
path: layout.path,
|
|
1257
|
+
...branching ? { branchLabel: edge.destinationDescription } : {}
|
|
1182
1258
|
})
|
|
1183
1259
|
);
|
|
1184
1260
|
return;
|
|
@@ -1188,106 +1264,293 @@ function diagramSvg(chart, title, instanceId) {
|
|
|
1188
1264
|
const y = above ? top : bottom;
|
|
1189
1265
|
const path = orthogonalEdgePath(start, end, y, lane);
|
|
1190
1266
|
paths.push(
|
|
1191
|
-
`<path class="
|
|
1267
|
+
`<path class="${edgeClass(edge)}" data-edge-index="${index}" d="${path}" fill="none" stroke="var(--sf-accent)" stroke-width="2.5" data-transition="${escapeXml(edge.name)}" marker-end="url(#${markerId})"/>`
|
|
1192
1268
|
);
|
|
1269
|
+
if (branching) {
|
|
1270
|
+
const splitKey = `${edge.name}:${above}`;
|
|
1271
|
+
const splitY = above ? y - 32 : y + 32;
|
|
1272
|
+
if (!drawnSplits.has(splitKey)) {
|
|
1273
|
+
const firstSplit = ![...drawnSplits].some(
|
|
1274
|
+
(key) => key.startsWith(`${edge.name}:`)
|
|
1275
|
+
);
|
|
1276
|
+
drawnSplits.add(splitKey);
|
|
1277
|
+
splits.push(
|
|
1278
|
+
splitNodeMarkup({ edgeName: edge.name, x: start, y: splitY, index })
|
|
1279
|
+
);
|
|
1280
|
+
if (firstSplit) {
|
|
1281
|
+
badges.push(
|
|
1282
|
+
transitionLabelBadge({
|
|
1283
|
+
edgeName: edge.name,
|
|
1284
|
+
cx: start,
|
|
1285
|
+
cy: (y + splitY) / 2,
|
|
1286
|
+
index,
|
|
1287
|
+
path: `M ${start} ${y} L ${start} ${splitY}`
|
|
1288
|
+
}).replace(
|
|
1289
|
+
'class="overview-edge-hit"',
|
|
1290
|
+
'class="overview-edge-hit overview-split-label"'
|
|
1291
|
+
)
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1193
1296
|
badges.push(
|
|
1194
1297
|
transitionLabelBadge({
|
|
1195
1298
|
edgeName: edge.name,
|
|
1196
1299
|
cx: (start + end) / 2,
|
|
1197
1300
|
cy: lane,
|
|
1198
1301
|
index,
|
|
1199
|
-
path
|
|
1302
|
+
path,
|
|
1303
|
+
...branching ? { branchLabel: edge.destinationDescription } : {}
|
|
1200
1304
|
})
|
|
1201
1305
|
);
|
|
1202
1306
|
});
|
|
1203
|
-
const
|
|
1307
|
+
const brackets = [];
|
|
1308
|
+
for (const parent of flow.states) {
|
|
1309
|
+
for (const region of parent.composition?.regions ?? []) {
|
|
1310
|
+
if (region.kind !== "inline") continue;
|
|
1311
|
+
const children = flow.states.filter(
|
|
1312
|
+
(state) => state.parent?.state === parent.name && state.parent.region === region.name
|
|
1313
|
+
);
|
|
1314
|
+
if (children.length === 0) continue;
|
|
1315
|
+
const xs = children.map((state) => centers.get(state.id));
|
|
1316
|
+
const left = Math.min(...xs) - 95;
|
|
1317
|
+
const right = Math.max(...xs) + 95;
|
|
1318
|
+
const y = bottom + 14;
|
|
1319
|
+
const label = parent.composition.kind === "compound" ? `inside ${parent.name}` : `inside ${parent.name} \u203A ${region.name}`;
|
|
1320
|
+
brackets.push(
|
|
1321
|
+
`<g class="overview-region" pointer-events="none"><path d="M ${left} ${y - 6} L ${left} ${y} L ${right} ${y} L ${right} ${y - 6}" fill="none" stroke="var(--sf-accent)" stroke-width="1.2" stroke-dasharray="4 3"/><text x="${(left + right) / 2}" y="${y + 13}" text-anchor="middle" fill="var(--sf-ink)" font-size="10" font-style="italic">${escapeXml(label)}</text></g>`
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
const nodes = flow.states.map((state, index) => {
|
|
1204
1326
|
const x = centers.get(state.id);
|
|
1205
|
-
const initial = state.id ===
|
|
1327
|
+
const initial = state.id === flow.initialId;
|
|
1206
1328
|
const lines = labels[index];
|
|
1207
|
-
const
|
|
1329
|
+
const final = state.kind === "final";
|
|
1330
|
+
const kindTag = final ? null : state.composition?.kind === "parallel" ? "PARALLEL" : state.composition ? "COMPOUND" : null;
|
|
1331
|
+
const textY = top + boxHeight / 2 - (lines.length - 1) * 8.5 + (final || kindTag ? 9 : 4);
|
|
1208
1332
|
const iconY = top + 22;
|
|
1209
1333
|
const labelX = x + 8;
|
|
1210
|
-
|
|
1334
|
+
const stroke = final ? "var(--sf-final)" : "var(--sf-accent)";
|
|
1335
|
+
const finalMarkup = final ? `<rect class="overview-state-final-ring" x="${x - 90}" y="${top + 5}" width="180" height="${boxHeight - 10}" rx="9" fill="none" stroke="${stroke}" stroke-width="1.2" pointer-events="none"/><text class="overview-state-kind" x="${x}" y="${top + 17}" text-anchor="middle" fill="${stroke}" font-size="9" font-weight="700" letter-spacing="0.08em" pointer-events="none">FINAL</text>` : kindTag ? `<text class="overview-state-kind" x="${x}" y="${top + 17}" text-anchor="middle" fill="${stroke}" font-size="9" font-weight="700" letter-spacing="0.08em" pointer-events="none">${kindTag}</text>` : "";
|
|
1336
|
+
return `${initial ? `<circle cx="${x - 108}" cy="${top + boxHeight / 2}" r="7" fill="var(--sf-accent)"/>` : ""}${final ? "" : stateIconMarkup(state.id, x, iconY)}<g class="overview-state-hit${initial ? " is-initial-state" : ""}${final ? " is-final-state" : ""}" data-state-id="${escapeXml(state.id)}" data-state-kind="${state.kind}" role="button" tabindex="0" aria-label="${escapeXml(final ? `${state.name} (final state)` : state.name)}"><rect class="overview-state-box" x="${x - 95}" y="${top}" width="190" height="${boxHeight}" rx="12" fill="${final ? "var(--sf-final-fill)" : "var(--sf-panel)"}" stroke="${stroke}" stroke-width="${initial ? 3 : 2}"/>${finalMarkup}<text text-anchor="middle" fill="var(--sf-ink)" font-size="13" font-weight="500" pointer-events="none">${lines.map((line, lineIndex) => `<tspan x="${labelX}" y="${textY + lineIndex * 17}">${escapeXml(line)}</tspan>`).join("")}</text></g>`;
|
|
1211
1337
|
});
|
|
1212
|
-
const height = bottom + 32 + (laneCounts.below ? 64 + (laneCounts.below - 1) * 44 : 0);
|
|
1213
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" class="sf-flow-svg" style="font-family:system-ui,sans-serif"><title>${escapeXml(title)}</title><defs><marker id="${markerId}" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 1 L 9 5 L 0 9 z" fill="var(--sf-accent)"/></marker></defs>${paths.join("")}${badges.join("")}${nodes.join("")}</svg>`;
|
|
1338
|
+
const height = bottom + (brackets.length > 0 ? 40 : 32) + (laneCounts.below ? 64 + (laneCounts.below - 1) * 44 : 0);
|
|
1339
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" class="sf-flow-svg" style="font-family:system-ui,sans-serif"><title>${escapeXml(title)}</title><defs><marker id="${markerId}" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 1 L 9 5 L 0 9 z" fill="var(--sf-accent)"/></marker></defs>${paths.join("")}${brackets.join("")}${splits.join("")}${badges.join("")}${nodes.join("")}</svg>`;
|
|
1214
1340
|
}
|
|
1215
1341
|
|
|
1216
|
-
// src/parse-
|
|
1217
|
-
import {
|
|
1342
|
+
// src/parse-flow.ts
|
|
1343
|
+
import {
|
|
1344
|
+
compileFlow
|
|
1345
|
+
} from "@ai-digital-factory/state-flow-definition";
|
|
1218
1346
|
|
|
1219
|
-
// src/
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1347
|
+
// src/extract-flow-definition.ts
|
|
1348
|
+
import {
|
|
1349
|
+
Children,
|
|
1350
|
+
isValidElement
|
|
1351
|
+
} from "react";
|
|
1352
|
+
var FLOW_DISPLAY_NAME = "StateFlowFlow";
|
|
1353
|
+
var STATE_DISPLAY_NAME = "StateFlowState";
|
|
1354
|
+
var FINAL_STATE_DISPLAY_NAME = "StateFlowFinalState";
|
|
1355
|
+
var PARALLEL_STATE_DISPLAY_NAME = "StateFlowParallelState";
|
|
1356
|
+
var REGION_DISPLAY_NAME = "StateFlowRegion";
|
|
1357
|
+
var FLOW_LIST_DISPLAY_NAME = "StateFlowFlowList";
|
|
1358
|
+
var TRANSITION_DISPLAY_NAME = "StateFlowTransition";
|
|
1359
|
+
var TO_DISPLAY_NAME = "StateFlowTo";
|
|
1360
|
+
function elementDisplayName(type) {
|
|
1361
|
+
if (typeof type === "function" || typeof type === "object") {
|
|
1362
|
+
if (type && "displayName" in type) {
|
|
1363
|
+
const displayName = type.displayName;
|
|
1364
|
+
if (displayName) {
|
|
1365
|
+
return displayName;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
if (typeof type === "function" && type.name) {
|
|
1369
|
+
return type.name;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
return void 0;
|
|
1223
1373
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
function
|
|
1228
|
-
|
|
1374
|
+
function isElement(node, displayName) {
|
|
1375
|
+
return isValidElement(node) && elementDisplayName(node.type) === displayName;
|
|
1376
|
+
}
|
|
1377
|
+
function isFlowElement(node) {
|
|
1378
|
+
return isElement(node, FLOW_DISPLAY_NAME);
|
|
1379
|
+
}
|
|
1380
|
+
function stateKind(node) {
|
|
1381
|
+
if (isElement(node, STATE_DISPLAY_NAME)) return "state";
|
|
1382
|
+
if (isElement(node, FINAL_STATE_DISPLAY_NAME)) return "final";
|
|
1383
|
+
if (isElement(node, PARALLEL_STATE_DISPLAY_NAME)) return "parallel";
|
|
1229
1384
|
return null;
|
|
1230
1385
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
const rawStates = [];
|
|
1236
|
-
const edges = [];
|
|
1237
|
-
const nameToId = /* @__PURE__ */ new Map();
|
|
1238
|
-
Children.forEach(children, (child) => {
|
|
1239
|
-
if (!isValidElement(child) || child.type !== State) {
|
|
1386
|
+
function transitionsOf(children) {
|
|
1387
|
+
const transitions = [];
|
|
1388
|
+
Children.forEach(children, (transitionChild) => {
|
|
1389
|
+
if (!isElement(transitionChild, TRANSITION_DISPLAY_NAME)) {
|
|
1240
1390
|
return;
|
|
1241
1391
|
}
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1392
|
+
const destinations = [];
|
|
1393
|
+
Children.forEach(transitionChild.props.children, (toChild) => {
|
|
1394
|
+
if (isElement(toChild, TO_DISPLAY_NAME)) {
|
|
1395
|
+
destinations.push({
|
|
1396
|
+
state: toChild.props.state,
|
|
1397
|
+
description: toChild.props.description
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
const { childWork, trigger } = transitionChild.props;
|
|
1402
|
+
transitions.push({
|
|
1403
|
+
name: transitionChild.props.name,
|
|
1404
|
+
description: transitionChild.props.description,
|
|
1405
|
+
destinations,
|
|
1406
|
+
...childWork !== void 0 ? { childWork } : {},
|
|
1407
|
+
...trigger !== void 0 && trigger !== "dispatch" ? { trigger } : {}
|
|
1253
1408
|
});
|
|
1254
|
-
nameToId.set(child.props.name, id);
|
|
1255
1409
|
});
|
|
1410
|
+
return transitions;
|
|
1411
|
+
}
|
|
1412
|
+
function statesOf(children) {
|
|
1413
|
+
const states = [];
|
|
1256
1414
|
Children.forEach(children, (child) => {
|
|
1257
|
-
|
|
1258
|
-
|
|
1415
|
+
const kind = stateKind(child);
|
|
1416
|
+
if (kind === null) return;
|
|
1417
|
+
states.push(stateOf(child, kind));
|
|
1418
|
+
});
|
|
1419
|
+
return states;
|
|
1420
|
+
}
|
|
1421
|
+
function flowListRegion(node) {
|
|
1422
|
+
return {
|
|
1423
|
+
kind: "list",
|
|
1424
|
+
name: node.props.name,
|
|
1425
|
+
description: node.props.description,
|
|
1426
|
+
flow: node.props.flow
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
function stateOf(element, kind) {
|
|
1430
|
+
const props = element.props;
|
|
1431
|
+
const regions = [];
|
|
1432
|
+
if (kind === "parallel") {
|
|
1433
|
+
Children.forEach(props.children, (child) => {
|
|
1434
|
+
if (isElement(child, REGION_DISPLAY_NAME)) {
|
|
1435
|
+
const { name, description, flow } = child.props;
|
|
1436
|
+
regions.push(
|
|
1437
|
+
flow !== void 0 ? { kind: "flow", name, description, flow } : {
|
|
1438
|
+
kind: "inline",
|
|
1439
|
+
name,
|
|
1440
|
+
description,
|
|
1441
|
+
default: child.props.default ?? "",
|
|
1442
|
+
states: statesOf(child.props.children)
|
|
1443
|
+
}
|
|
1444
|
+
);
|
|
1445
|
+
} else if (isElement(child, FLOW_LIST_DISPLAY_NAME)) {
|
|
1446
|
+
regions.push(flowListRegion(child));
|
|
1447
|
+
}
|
|
1448
|
+
});
|
|
1449
|
+
} else {
|
|
1450
|
+
const nested = statesOf(props.children);
|
|
1451
|
+
if (nested.length > 0 || props.default !== void 0) {
|
|
1452
|
+
regions.push({
|
|
1453
|
+
kind: "inline",
|
|
1454
|
+
name: props.name,
|
|
1455
|
+
description: props.description,
|
|
1456
|
+
default: props.default ?? "",
|
|
1457
|
+
states: nested
|
|
1458
|
+
});
|
|
1259
1459
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1460
|
+
if (props.flow !== void 0) {
|
|
1461
|
+
regions.push({
|
|
1462
|
+
kind: "flow",
|
|
1463
|
+
name: props.name,
|
|
1464
|
+
description: props.description,
|
|
1465
|
+
flow: props.flow
|
|
1466
|
+
});
|
|
1263
1467
|
}
|
|
1264
|
-
Children.forEach(
|
|
1265
|
-
if (
|
|
1266
|
-
|
|
1468
|
+
Children.forEach(props.children, (child) => {
|
|
1469
|
+
if (isElement(child, FLOW_LIST_DISPLAY_NAME)) {
|
|
1470
|
+
regions.push(flowListRegion(child));
|
|
1471
|
+
}
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
const composite = kind === "parallel" || regions.length > 0;
|
|
1475
|
+
return {
|
|
1476
|
+
name: props.name,
|
|
1477
|
+
description: props.description,
|
|
1478
|
+
kind: kind === "final" ? "final" : "state",
|
|
1479
|
+
transitions: transitionsOf(props.children),
|
|
1480
|
+
...composite ? {
|
|
1481
|
+
composition: {
|
|
1482
|
+
kind: kind === "parallel" ? "parallel" : "compound",
|
|
1483
|
+
regions
|
|
1267
1484
|
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1485
|
+
} : {}
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
function extractFlowDefinition(node) {
|
|
1489
|
+
if (!isFlowElement(node)) {
|
|
1490
|
+
throw new Error("Application flow module must render a Flow root");
|
|
1491
|
+
}
|
|
1492
|
+
const { name, description, default: defaultState, children } = node.props;
|
|
1493
|
+
return {
|
|
1494
|
+
name,
|
|
1495
|
+
description,
|
|
1496
|
+
default: defaultState,
|
|
1497
|
+
states: statesOf(children)
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
function extractFlowDefinitionFromComponent(component) {
|
|
1501
|
+
return extractFlowDefinition(component());
|
|
1502
|
+
}
|
|
1503
|
+
function explicitStateIds(children) {
|
|
1504
|
+
const ids = /* @__PURE__ */ new Map();
|
|
1505
|
+
const visit = (nodes) => {
|
|
1506
|
+
Children.forEach(nodes, (child) => {
|
|
1507
|
+
if (!isValidElement(child)) return;
|
|
1508
|
+
const display = elementDisplayName(child.type);
|
|
1509
|
+
if (display === STATE_DISPLAY_NAME || display === FINAL_STATE_DISPLAY_NAME || display === PARALLEL_STATE_DISPLAY_NAME) {
|
|
1510
|
+
if (child.props.id !== void 0)
|
|
1511
|
+
ids.set(child.props.name, child.props.id);
|
|
1512
|
+
visit(child.props.children);
|
|
1513
|
+
} else if (display === REGION_DISPLAY_NAME) {
|
|
1514
|
+
visit(child.props.children);
|
|
1272
1515
|
}
|
|
1273
|
-
edges.push({
|
|
1274
|
-
fromId,
|
|
1275
|
-
fromName: child.props.name,
|
|
1276
|
-
toId,
|
|
1277
|
-
toName,
|
|
1278
|
-
name: transitionChild.props.name,
|
|
1279
|
-
description: transitionChild.props.description
|
|
1280
|
-
});
|
|
1281
1516
|
});
|
|
1517
|
+
};
|
|
1518
|
+
visit(children);
|
|
1519
|
+
return ids;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
// src/parse-flow.ts
|
|
1523
|
+
function parseFlow(children, defaultStateName) {
|
|
1524
|
+
const parsed = compileFlow({
|
|
1525
|
+
name: "",
|
|
1526
|
+
description: "",
|
|
1527
|
+
default: defaultStateName,
|
|
1528
|
+
states: statesOf(children)
|
|
1282
1529
|
});
|
|
1283
|
-
const
|
|
1284
|
-
if (
|
|
1285
|
-
|
|
1530
|
+
const explicit = explicitStateIds(children);
|
|
1531
|
+
if (explicit.size === 0) return parsed;
|
|
1532
|
+
const remap = new Map(
|
|
1533
|
+
parsed.states.map((state) => [
|
|
1534
|
+
state.id,
|
|
1535
|
+
explicit.get(state.name) ?? state.id
|
|
1536
|
+
])
|
|
1537
|
+
);
|
|
1538
|
+
const ids = [...remap.values()];
|
|
1539
|
+
const duplicate = ids.find((id, index) => ids.indexOf(id) !== index);
|
|
1540
|
+
if (duplicate !== void 0) {
|
|
1541
|
+
throw new Error(`Duplicate state id: ${duplicate}`);
|
|
1286
1542
|
}
|
|
1287
1543
|
return {
|
|
1288
|
-
states:
|
|
1289
|
-
|
|
1290
|
-
|
|
1544
|
+
states: parsed.states.map((state) => ({
|
|
1545
|
+
...state,
|
|
1546
|
+
id: remap.get(state.id)
|
|
1547
|
+
})),
|
|
1548
|
+
edges: parsed.edges.map((edge) => ({
|
|
1549
|
+
...edge,
|
|
1550
|
+
fromId: remap.get(edge.fromId),
|
|
1551
|
+
toId: remap.get(edge.toId)
|
|
1552
|
+
})),
|
|
1553
|
+
initialId: remap.get(parsed.initialId)
|
|
1291
1554
|
};
|
|
1292
1555
|
}
|
|
1293
1556
|
|
|
@@ -1305,42 +1568,91 @@ function Flow({
|
|
|
1305
1568
|
default: defaultStateName,
|
|
1306
1569
|
children
|
|
1307
1570
|
}) {
|
|
1308
|
-
const
|
|
1571
|
+
const flow = useMemo(
|
|
1309
1572
|
() => parseFlow(children, defaultStateName),
|
|
1310
1573
|
[children, defaultStateName]
|
|
1311
1574
|
);
|
|
1312
1575
|
const instanceId = useId();
|
|
1313
|
-
const
|
|
1314
|
-
const svgHtml = diagramSvg(
|
|
1576
|
+
const flowTitle = titleCaseName(name);
|
|
1577
|
+
const svgHtml = diagramSvg(flow, flowTitle, instanceId);
|
|
1315
1578
|
return /* @__PURE__ */ jsxs5("article", { className: "sf-root", children: [
|
|
1316
1579
|
/* @__PURE__ */ jsx6(
|
|
1317
|
-
|
|
1580
|
+
FlowPageHeader,
|
|
1318
1581
|
{
|
|
1319
|
-
title:
|
|
1582
|
+
title: flowTitle,
|
|
1320
1583
|
description,
|
|
1321
|
-
|
|
1584
|
+
flowId: name
|
|
1322
1585
|
}
|
|
1323
1586
|
),
|
|
1324
1587
|
svgHtml ? /* @__PURE__ */ jsx6(
|
|
1325
1588
|
DiagramOverview,
|
|
1326
1589
|
{
|
|
1327
1590
|
svgHtml,
|
|
1328
|
-
states:
|
|
1329
|
-
edges:
|
|
1591
|
+
states: flow.states,
|
|
1592
|
+
edges: flow.edges,
|
|
1330
1593
|
viewPersistenceKey: name,
|
|
1331
1594
|
detailLayout: "split",
|
|
1332
|
-
initialStateId:
|
|
1595
|
+
initialStateId: flow.initialId
|
|
1333
1596
|
}
|
|
1334
1597
|
) : /* @__PURE__ */ jsx6("p", { className: "sf-notice", children: "No overview diagram is available for this flow." })
|
|
1335
1598
|
] });
|
|
1336
1599
|
}
|
|
1337
1600
|
Flow.displayName = "StateFlowFlow";
|
|
1338
1601
|
|
|
1339
|
-
// src/
|
|
1602
|
+
// src/State.tsx
|
|
1603
|
+
function State(_props) {
|
|
1604
|
+
void _props;
|
|
1605
|
+
return null;
|
|
1606
|
+
}
|
|
1607
|
+
State.displayName = "StateFlowState";
|
|
1608
|
+
|
|
1609
|
+
// src/ParallelState.tsx
|
|
1610
|
+
function ParallelState(_props) {
|
|
1611
|
+
void _props;
|
|
1612
|
+
return null;
|
|
1613
|
+
}
|
|
1614
|
+
ParallelState.displayName = "StateFlowParallelState";
|
|
1615
|
+
|
|
1616
|
+
// src/Region.tsx
|
|
1617
|
+
function Region(_props) {
|
|
1618
|
+
void _props;
|
|
1619
|
+
return null;
|
|
1620
|
+
}
|
|
1621
|
+
Region.displayName = "StateFlowRegion";
|
|
1622
|
+
|
|
1623
|
+
// src/FlowList.tsx
|
|
1624
|
+
function FlowList(_props) {
|
|
1625
|
+
void _props;
|
|
1626
|
+
return null;
|
|
1627
|
+
}
|
|
1628
|
+
FlowList.displayName = "StateFlowFlowList";
|
|
1629
|
+
|
|
1630
|
+
// src/FinalState.tsx
|
|
1631
|
+
function FinalState(_props) {
|
|
1632
|
+
void _props;
|
|
1633
|
+
return null;
|
|
1634
|
+
}
|
|
1635
|
+
FinalState.displayName = "StateFlowFinalState";
|
|
1636
|
+
|
|
1637
|
+
// src/Transition.tsx
|
|
1638
|
+
function Transition(_props) {
|
|
1639
|
+
void _props;
|
|
1640
|
+
return null;
|
|
1641
|
+
}
|
|
1642
|
+
Transition.displayName = "StateFlowTransition";
|
|
1643
|
+
|
|
1644
|
+
// src/To.tsx
|
|
1645
|
+
function To(_props) {
|
|
1646
|
+
void _props;
|
|
1647
|
+
return null;
|
|
1648
|
+
}
|
|
1649
|
+
To.displayName = "StateFlowTo";
|
|
1650
|
+
|
|
1651
|
+
// src/FlowRenderer.tsx
|
|
1340
1652
|
import { useId as useId2, useMemo as useMemo2 } from "react";
|
|
1341
1653
|
import {
|
|
1342
|
-
|
|
1343
|
-
} from "@ai-digital-factory/state-flow-
|
|
1654
|
+
compileFlow as compileFlow2
|
|
1655
|
+
} from "@ai-digital-factory/state-flow-definition";
|
|
1344
1656
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1345
1657
|
function titleCaseName2(name) {
|
|
1346
1658
|
if (!name) {
|
|
@@ -1348,20 +1660,18 @@ function titleCaseName2(name) {
|
|
|
1348
1660
|
}
|
|
1349
1661
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
1350
1662
|
}
|
|
1351
|
-
function
|
|
1352
|
-
|
|
1353
|
-
}) {
|
|
1354
|
-
const parsed = useMemo2(() => compileApplicationChart(chart), [chart]);
|
|
1663
|
+
function FlowRenderer({ flow }) {
|
|
1664
|
+
const parsed = useMemo2(() => compileFlow2(flow), [flow]);
|
|
1355
1665
|
const instanceId = useId2();
|
|
1356
|
-
const
|
|
1357
|
-
const svgHtml = diagramSvg(parsed,
|
|
1666
|
+
const flowTitle = titleCaseName2(flow.name);
|
|
1667
|
+
const svgHtml = diagramSvg(parsed, flowTitle, instanceId);
|
|
1358
1668
|
return /* @__PURE__ */ jsxs6("article", { className: "sf-root", children: [
|
|
1359
1669
|
/* @__PURE__ */ jsx7(
|
|
1360
|
-
|
|
1670
|
+
FlowPageHeader,
|
|
1361
1671
|
{
|
|
1362
|
-
title:
|
|
1363
|
-
description:
|
|
1364
|
-
|
|
1672
|
+
title: flowTitle,
|
|
1673
|
+
description: flow.description,
|
|
1674
|
+
flowId: flow.name
|
|
1365
1675
|
}
|
|
1366
1676
|
),
|
|
1367
1677
|
svgHtml ? /* @__PURE__ */ jsx7(
|
|
@@ -1370,7 +1680,7 @@ function ApplicationChartRenderer({
|
|
|
1370
1680
|
svgHtml,
|
|
1371
1681
|
states: parsed.states,
|
|
1372
1682
|
edges: parsed.edges,
|
|
1373
|
-
viewPersistenceKey:
|
|
1683
|
+
viewPersistenceKey: flow.name,
|
|
1374
1684
|
detailLayout: "split",
|
|
1375
1685
|
initialStateId: parsed.initialId
|
|
1376
1686
|
}
|
|
@@ -1378,97 +1688,33 @@ function ApplicationChartRenderer({
|
|
|
1378
1688
|
] });
|
|
1379
1689
|
}
|
|
1380
1690
|
|
|
1381
|
-
// src/extract-chart-definition.ts
|
|
1382
|
-
import {
|
|
1383
|
-
Children as Children2,
|
|
1384
|
-
isValidElement as isValidElement2
|
|
1385
|
-
} from "react";
|
|
1386
|
-
var FLOW_DISPLAY_NAME = "StateFlowFlow";
|
|
1387
|
-
var STATE_DISPLAY_NAME = "StateFlowState";
|
|
1388
|
-
var TRANSITION_DISPLAY_NAME = "StateFlowTransition";
|
|
1389
|
-
function elementDisplayName(type) {
|
|
1390
|
-
if (typeof type === "function" || typeof type === "object") {
|
|
1391
|
-
if (type && "displayName" in type) {
|
|
1392
|
-
const displayName = type.displayName;
|
|
1393
|
-
if (displayName) {
|
|
1394
|
-
return displayName;
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
if (typeof type === "function" && type.name) {
|
|
1398
|
-
return type.name;
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
return void 0;
|
|
1402
|
-
}
|
|
1403
|
-
function isFlowElement(node) {
|
|
1404
|
-
return isValidElement2(node) && elementDisplayName(node.type) === FLOW_DISPLAY_NAME;
|
|
1405
|
-
}
|
|
1406
|
-
function isStateElement(node) {
|
|
1407
|
-
return isValidElement2(node) && elementDisplayName(node.type) === STATE_DISPLAY_NAME;
|
|
1408
|
-
}
|
|
1409
|
-
function isTransitionElement(node) {
|
|
1410
|
-
return isValidElement2(node) && elementDisplayName(node.type) === TRANSITION_DISPLAY_NAME;
|
|
1411
|
-
}
|
|
1412
|
-
function extractApplicationChartDefinition(node) {
|
|
1413
|
-
if (!isFlowElement(node)) {
|
|
1414
|
-
throw new Error("Application flow module must render a Flow root");
|
|
1415
|
-
}
|
|
1416
|
-
const { name, description, default: defaultState, children } = node.props;
|
|
1417
|
-
const states = [];
|
|
1418
|
-
Children2.forEach(children, (child) => {
|
|
1419
|
-
if (!isStateElement(child)) {
|
|
1420
|
-
return;
|
|
1421
|
-
}
|
|
1422
|
-
const transitions = [];
|
|
1423
|
-
Children2.forEach(child.props.children, (transitionChild) => {
|
|
1424
|
-
if (!isTransitionElement(transitionChild)) {
|
|
1425
|
-
return;
|
|
1426
|
-
}
|
|
1427
|
-
transitions.push({
|
|
1428
|
-
to: transitionChild.props.to,
|
|
1429
|
-
name: transitionChild.props.name,
|
|
1430
|
-
description: transitionChild.props.description
|
|
1431
|
-
});
|
|
1432
|
-
});
|
|
1433
|
-
states.push({
|
|
1434
|
-
name: child.props.name,
|
|
1435
|
-
description: child.props.description,
|
|
1436
|
-
transitions
|
|
1437
|
-
});
|
|
1438
|
-
});
|
|
1439
|
-
return {
|
|
1440
|
-
name,
|
|
1441
|
-
description,
|
|
1442
|
-
default: defaultState,
|
|
1443
|
-
states
|
|
1444
|
-
};
|
|
1445
|
-
}
|
|
1446
|
-
function extractApplicationChartDefinitionFromComponent(component) {
|
|
1447
|
-
return extractApplicationChartDefinition(component());
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
1691
|
// src/index.tsx
|
|
1451
1692
|
import {
|
|
1452
1693
|
DEFAULT_TRANSITION_NAME,
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
} from "@ai-digital-factory/state-flow-
|
|
1694
|
+
STATE_HANDLER_EXPORT_NAMES,
|
|
1695
|
+
TRANSITION_HANDLER_EXPORT_NAMES
|
|
1696
|
+
} from "@ai-digital-factory/state-flow-definition";
|
|
1456
1697
|
export {
|
|
1457
|
-
ApplicationChartRenderer,
|
|
1458
|
-
ChartHeaderIcon,
|
|
1459
|
-
ChartPageHeader,
|
|
1460
1698
|
DEFAULT_TRANSITION_NAME,
|
|
1461
1699
|
DiagramOverview,
|
|
1700
|
+
FinalState,
|
|
1462
1701
|
Flow,
|
|
1463
|
-
|
|
1702
|
+
FlowHeaderIcon,
|
|
1703
|
+
FlowList,
|
|
1704
|
+
FlowPageHeader,
|
|
1705
|
+
FlowRenderer,
|
|
1706
|
+
ParallelState,
|
|
1707
|
+
Region,
|
|
1708
|
+
STATE_HANDLER_EXPORT_NAMES,
|
|
1464
1709
|
State,
|
|
1465
1710
|
StateFlowPlaceholder,
|
|
1466
|
-
|
|
1711
|
+
TRANSITION_HANDLER_EXPORT_NAMES,
|
|
1712
|
+
To,
|
|
1467
1713
|
Transition,
|
|
1468
|
-
chartNavIcon,
|
|
1469
1714
|
diagramSvg,
|
|
1470
|
-
|
|
1471
|
-
|
|
1715
|
+
extractFlowDefinition,
|
|
1716
|
+
extractFlowDefinitionFromComponent,
|
|
1717
|
+
flowNavIcon,
|
|
1472
1718
|
mergeScrollYIntoSearch,
|
|
1473
1719
|
parseScrollYFromSearch,
|
|
1474
1720
|
replaceBrowserUrlSearch
|