@cardenelabs/dragon 0.36.3 → 0.37.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/export.js CHANGED
@@ -275,13 +275,46 @@ var LOOK = {
275
275
  region: { pad: 18, gap: 10, radius: 14, inset: 14, icon: 24, iconRadius: 7, iconScale: 0.68, nameY: 58, line: 16, minH: 108 },
276
276
  architecture: { columns: 4, columnGap: 56, maxColumnGap: 160, rowGap: 44, labelRoom: 16 },
277
277
  sequence: { columnGap: 40, labelRoom: 16, firstRow: 22, rowGap: 14, stepGap: 8, minPitch: 40, tail: 18, selfW: 34, selfH: 18 },
278
- edge: { inset: 3, arrow: 6, arrowHalf: 3.5, parallel: 5, ghostDash: 5, flowDash: 9 },
278
+ /**
279
+ * 状態遷移図 (#3163)。状態は `columns` つずつ並べて次の段へ折り返し、段の間 (`rowGap`) の真ん中を、段をまたぐ線が通る。
280
+ * `start` と `end` は始まりと終わりの印の半径と、印の中の丸の半径。`drop` は最初の状態の上端から始まりの印の中心まで、
281
+ * `below` は状態の下端から終わりの印の中心まで、`beside` は状態の右端から右に置く終わりの印の中心まで、`text` は印の中心から字の左端まで。
282
+ * `loop` は同じ状態へ戻る輪の幅と深さ。`side` は脇道の囲みの内側の余白、1 段目の上端との間、脇道へ入る線が横に通る所の囲みの下端からの離れ、
283
+ * 点線の線が箱へ入る所を箱の端から離す幅。
284
+ * `ghost` は脇道の点線の札で、絵柄を左に、名前と下の字を右に並べる (#3171)。`h` は札の高さ、`pad` は左右の余白、`gap` は絵柄と字の間、
285
+ * `nameY` と `subY` は札の真ん中から名前と下の字の基準線まで。
286
+ * `done` は出た状態の右上の済んだ印の半径と、箱の右上の角からの離れ。
287
+ * `loop` の `samples` は同じ状態へ戻る弧を区切る点の数、`badgeAt` は弧の段の番号を弧の上端から深さのどこに置くかの割合。
288
+ * `pastLabel` は段が終わった後に薄く残す線の名前の濃さ (#3171)
289
+ */
290
+ state: {
291
+ columns: 4,
292
+ columnGap: 64,
293
+ rowGap: 108,
294
+ labelRoom: 16,
295
+ start: 7,
296
+ end: { r: 9, inner: 5 },
297
+ drop: 56,
298
+ below: 64,
299
+ beside: 38,
300
+ text: 16,
301
+ loop: { w: 24, h: 34, samples: 12, badgeAt: 0.6 },
302
+ side: { pad: 16, gap: 76, lane: 30, entry: 28 },
303
+ ghost: { h: 52, pad: 12, gap: 10, nameY: -2, subY: 14 },
304
+ done: { r: 6.5, inset: 13 },
305
+ pastLabel: 0.85
306
+ },
307
+ /** `bend` は線の曲がりを丸める半径 (#3171) */
308
+ edge: { inset: 3, arrow: 6, arrowHalf: 3.5, parallel: 5, ghostDash: 5, flowDash: 9, bend: 12 },
279
309
  label: { h: 20, padX: 9, radius: 10, offset: 22, side: 14, search: 4, searchMax: 400, soft: 6 },
280
310
  action: { h: 22, padX: 10, radius: 11 },
281
311
  badge: { r: 9.5, ring: 9, inset: 4, along: 14, short: 44 },
282
312
  carrier: { envW: 24, envH: 17, coinR: 6.5, coinIn: 3.8, tagH: 18, tagPadX: 8, samples: 16 },
283
- strip: { h: 72, line: 44, pad: 12, icon: 24, titleX: 44, fieldGap: 22, sepInset: 14, tagGap: 6, tagH: 15, tagPadX: 7, nameY: 22, valueY: 43 },
284
- stroke: { hair: 1, edge: 1.7, edgeOn: 2.25, arrow: 1.5, flow: 1.3, halo: 7, on: 1.75, glyph: 2, lifeline: 1.2, envelope: 1.5, badgeRing: 1.5 },
313
+ /**
314
+ * `trail` は状態遷移図の帯の最後の、通った状態の点 (#3171)。`r` は点の半径、`step` は点の中心どうしの間、`now` は変わった値の欄の名前の横の点の半径と、名前からの離れ
315
+ */
316
+ strip: { h: 72, line: 44, pad: 12, icon: 24, titleX: 44, fieldGap: 22, sepInset: 14, tagGap: 6, tagH: 15, tagPadX: 7, nameY: 22, valueY: 43, trail: { r: 5.4, step: 16 }, now: { r: 3, gap: 7 } },
317
+ stroke: { hair: 1, edge: 1.7, edgeOn: 2.25, arrow: 1.5, flow: 1.3, halo: 7, on: 1.75, glyph: 2, lifeline: 1.2, envelope: 1.5, badgeRing: 1.5, path: 1.6, end: 1.6, done: 1.2, trail: 1.2 },
285
318
  shadow: { near: 0.8, far: 4, nearY: 1, farY: 3 },
286
319
  mini: { w: 168, pad: 8, title: 14, inset: 12, radius: 10 },
287
320
  /**
@@ -295,9 +328,9 @@ var LOOK = {
295
328
  */
296
329
  follow: { aspect: 0.75, minH: 320, fitMinH: 160, ease: 0.6, narrow: 440, badgeRoom: 8, headRoom: 10, head: { pad: 8, h: 40, nameY: 17, subY: 31 } },
297
330
  /** 色を混ぜる割合 (%) */
298
- mix: { icon: 14, regionIcon: 16, regionIconEdge: 34, cap: 12, capEdge: 42, badgePast: 14, badgePastEdge: 70, mini: 62, miniBand: 16, miniBandEdge: 36, view: 6 },
331
+ mix: { icon: 14, regionIcon: 16, regionIconEdge: 34, cap: 12, capEdge: 42, badgePast: 14, badgePastEdge: 70, mini: 62, miniBand: 16, miniBandEdge: 36, view: 6, side: 4, sideEdge: 36, ghostEdge: 60, path: 55, past: 72 },
299
332
  /** 字の並びの基準線を、置きたい高さの真ん中からどれだけ下げるか */
300
- baseline: { label: 3.8, badge: 3.5, carrier: 3.7, stripTitle: 4.5, tag: 3.6, action: 3.8 },
333
+ baseline: { label: 3.8, badge: 3.5, carrier: 3.7, stripTitle: 4.5, tag: 3.6, action: 3.8, mark: 4 },
301
334
  /** 浮いて出る物が下から上がる長さと、弾んで出る物の始まりの大きさ */
302
335
  rise: 5,
303
336
  popFrom: 0.4};
@@ -331,7 +364,9 @@ var MOTION = {
331
364
  popFade: 0.4,
332
365
  untilFade: 0.2,
333
366
  /** 段の止め絵を撮る時刻を、段の終わりからどれだけ前にするか */
334
- still: 0.45
367
+ still: 0.45,
368
+ /** 状態遷移図で、札が状態を出てから済んだ印が出るまで */
369
+ done: 0.3
335
370
  };
336
371
  var READABLE_PX = 10.5;
337
372
  var EASE = {
@@ -349,7 +384,13 @@ var FIGURE_TEXT = {
349
384
  pause: "\u6B62\u3081\u308B",
350
385
  play: "\u52D5\u304B\u3059",
351
386
  next: "\u6B21\u306E\u6BB5",
352
- steps: (title) => `${title} \u306E\u6BB5`
387
+ steps: (title) => `${title} \u306E\u6BB5`,
388
+ side: "\u8107\u9053",
389
+ sideNote: "\u4ECA\u56DE\u306F\u901A\u3089\u306A\u3044",
390
+ sideFrom: (count) => `${count} \u3064\u306E\u72B6\u614B\u304B\u3089\u5165\u308C\u308B`,
391
+ trail: "\u901A\u3063\u305F\u72B6\u614B",
392
+ start: "\u59CB\u307E\u308A",
393
+ end: "\u7D42\u308F\u308A"
353
394
  },
354
395
  en: {
355
396
  cannotDraw: (detail) => `Cannot draw the diagram: ${detail}`,
@@ -358,7 +399,13 @@ var FIGURE_TEXT = {
358
399
  pause: "Pause",
359
400
  play: "Play",
360
401
  next: "Next step",
361
- steps: (title) => `Steps of ${title}`
402
+ steps: (title) => `Steps of ${title}`,
403
+ side: "Side path",
404
+ sideNote: "Not taken this time",
405
+ sideFrom: (count) => `Enterable from ${count} ${count === 1 ? "state" : "states"}`,
406
+ trail: "States passed",
407
+ start: "Start",
408
+ end: "End"
362
409
  }
363
410
  };
364
411
 
@@ -453,12 +500,12 @@ function placeLabel(request, obstacles) {
453
500
  const segment = longest(request.points);
454
501
  const mx = (segment.a[0] + segment.b[0]) / 2;
455
502
  const my = (segment.a[1] + segment.b[1]) / 2;
456
- const side = request.side ?? (segment.vertical ? "right" : "above");
503
+ const side2 = request.side ?? (segment.vertical ? "right" : "above");
457
504
  const { offset, side: sideGap } = LOOK.label;
458
- const base = side === "above" ? { x: mx - w / 2, y: my - offset - h / 2, w, h } : side === "below" ? { x: mx - w / 2, y: my + offset - h / 2, w, h } : side === "left" ? { x: mx - sideGap - w, y: my - h / 2, w, h } : { x: mx + sideGap, y: my - h / 2, w, h };
459
- const away = side === "above" ? [0, -1] : side === "below" ? [0, 1] : side === "left" ? [-1, 0] : [1, 0];
505
+ const base = side2 === "above" ? { x: mx - w / 2, y: my - offset - h / 2, w, h } : side2 === "below" ? { x: mx - w / 2, y: my + offset - h / 2, w, h } : side2 === "left" ? { x: mx - sideGap - w, y: my - h / 2, w, h } : { x: mx + sideGap, y: my - h / 2, w, h };
506
+ const away = side2 === "above" ? [0, -1] : side2 === "below" ? [0, 1] : side2 === "left" ? [-1, 0] : [1, 0];
460
507
  const slideAxis = [Math.abs(away[1]), Math.abs(away[0])];
461
- const slideMax = side === "above" || side === "below" ? w : h * 4;
508
+ const slideMax = side2 === "above" || side2 === "below" ? w : h * 4;
462
509
  const clear = (rect) => obstacles.hard.every((box) => gapBetween(rect, box) >= LOOK.gap) && obstacles.soft.every((other) => gapBetween(rect, other) >= LOOK.label.soft);
463
510
  const { search, searchMax } = LOOK.label;
464
511
  for (let d = 0; d <= searchMax; d += search) {
@@ -484,29 +531,36 @@ function fieldWidth(diagram, name) {
484
531
  const both = value + (tag > 0 ? (value > 0 ? LOOK.strip.tagGap : 0) + tag : 0);
485
532
  return Math.max(textWidth(name, TYPE.fieldName), both);
486
533
  }
487
- function stripNeed(diagram) {
534
+ var trailWidth = (trail) => Math.max(textWidth(trail.title, TYPE.fieldName), trail.states.length * LOOK.strip.trail.step);
535
+ function stripNeed(diagram, trail) {
488
536
  if (!diagram.strip) return 0;
489
537
  const { titleX, fieldGap, pad: pad2 } = LOOK.strip;
490
538
  const start = titleX + textWidth(diagram.strip.title, TYPE.stripTitle) + fieldGap;
491
- return start + diagram.strip.fields.reduce((sum, name) => sum + fieldWidth(diagram, name) + fieldGap, 0) - fieldGap + pad2;
539
+ const widths = [...diagram.strip.fields.map((name) => fieldWidth(diagram, name)), ...trail ? [trailWidth(trail)] : []];
540
+ return start + widths.reduce((sum, w) => sum + w + fieldGap, 0) - fieldGap + pad2;
492
541
  }
493
- function layoutStrip(diagram, x, y, width) {
542
+ function layoutStrip(diagram, x, y, width, trail) {
494
543
  if (!diagram.strip) return void 0;
495
544
  const { titleX, fieldGap, pad: pad2, line, h } = LOOK.strip;
496
545
  const start = titleX + textWidth(diagram.strip.title, TYPE.stripTitle) + fieldGap;
497
546
  const fields = [];
498
547
  let cx = start;
499
548
  let row = 0;
500
- for (const name of diagram.strip.fields) {
501
- const w = fieldWidth(diagram, name);
549
+ const place = (w) => {
502
550
  if (cx > start && cx + w > width - pad2) {
503
551
  cx = start;
504
552
  row++;
505
553
  }
506
- fields.push({ name, x: x + cx, y: y + row * line, w });
554
+ const at2 = { x: x + cx, y: y + row * line };
507
555
  cx += w + fieldGap;
556
+ return at2;
557
+ };
558
+ for (const name of diagram.strip.fields) {
559
+ const w = fieldWidth(diagram, name);
560
+ fields.push({ name, ...place(w), w });
508
561
  }
509
- return { x, y, w: width, h: h + row * line, title: diagram.strip.title, fields };
562
+ const laidTrail = trail ? { ...trail, ...place(trailWidth(trail)), w: trailWidth(trail) } : void 0;
563
+ return { x, y, w: width, h: h + row * line, title: diagram.strip.title, fields, ...laidTrail ? { trail: laidTrail } : {} };
510
564
  }
511
565
  function shiftContent(layout, dx, dy) {
512
566
  const move = (rect) => {
@@ -532,6 +586,15 @@ function shiftContent(layout, dx, dy) {
532
586
  if (edge2.settle) edge2.settle = [edge2.settle[0] + dx, edge2.settle[1] + dy];
533
587
  }
534
588
  for (const label2 of layout.labels) move(label2);
589
+ for (const path2 of layout.paths) {
590
+ path2.points = path2.points.map(([px, py]) => [px + dx, py + dy]);
591
+ if (path2.label) move(path2.label);
592
+ }
593
+ for (const end of layout.ends) {
594
+ end.x += dx;
595
+ end.y += dy;
596
+ }
597
+ if (layout.side) move(layout.side);
535
598
  for (const action2 of layout.actions) move(action2);
536
599
  for (const badge2 of layout.badges) {
537
600
  badge2.x += dx;
@@ -543,6 +606,10 @@ function shiftContent(layout, dx, dy) {
543
606
  field.x += dx;
544
607
  field.y += dy;
545
608
  }
609
+ if (layout.strip.trail) {
610
+ layout.strip.trail.x += dx;
611
+ layout.strip.trail.y += dy;
612
+ }
546
613
  }
547
614
  }
548
615
  function cornerBadge(events, step, layout) {
@@ -574,7 +641,7 @@ function groupsOf(diagram) {
574
641
  if (loose.length > 0) groups.push({ members: loose });
575
642
  return groups;
576
643
  }
577
- var vertical = (side) => side === "left" || side === "right";
644
+ var vertical = (side2) => side2 === "left" || side2 === "right";
578
645
  function placeBoxes(diagram, groups) {
579
646
  const columns = LOOK.architecture.columns;
580
647
  const edges = edgesOf(diagram).map((e) => e.edge);
@@ -821,7 +888,7 @@ function arrange(diagram, groups, slots, rooms) {
821
888
  )
822
889
  );
823
890
  }
824
- const layout = { kind: "architecture", width: 0, height: 0, regions, boxes, lifelines: [], edges: sceneEdges, labels, actions: [], badges: [] };
891
+ const layout = { kind: "architecture", width: 0, height: 0, regions, boxes, lifelines: [], edges: sceneEdges, labels, actions: [], badges: [], paths: [], ends: [] };
825
892
  const shift = labels.length > 0 ? Math.max(0, margin + LOOK.label.soft - Math.min(...labels.map((l) => l.x))) : 0;
826
893
  if (shift > 0) shiftContent(layout, shift, 0);
827
894
  const contentRight = Math.max(...boxes.map((b) => b.x + b.w + R.pad), ...labels.map((l) => l.x + l.w + LOOK.label.soft), ...sceneEdges.flatMap((e) => e.points.map((p) => p[0] + R.pad)));
@@ -928,11 +995,11 @@ function layoutSequence(diagram) {
928
995
  let above;
929
996
  let under;
930
997
  if (event.type === "edge") {
931
- const side = event.labelSide ?? "above";
998
+ const side2 = event.labelSide ?? "above";
932
999
  const self = event.from === event.to;
933
1000
  const named = event.label !== void 0;
934
- above = named && side === "above" ? L.offset + L.h / 2 : gap;
935
- under = self ? Q.selfH + gap : named && side === "below" ? L.offset + L.h / 2 : gap;
1001
+ above = named && side2 === "above" ? L.offset + L.h / 2 : gap;
1002
+ under = self ? Q.selfH + gap : named && side2 === "below" ? L.offset + L.h / 2 : gap;
936
1003
  } else {
937
1004
  above = LOOK.action.h / 2;
938
1005
  under = LOOK.action.h / 2;
@@ -979,7 +1046,7 @@ function layoutSequence(diagram) {
979
1046
  const soft = [...labels.filter((l) => l.step === request.step), ...actions];
980
1047
  labels.push(placeLabel(request, { hard: boxes, soft }));
981
1048
  }
982
- const layout = { kind: "sequence", width: 0, height: 0, regions: [], boxes, lifelines, edges, labels, actions, badges: [] };
1049
+ const layout = { kind: "sequence", width: 0, height: 0, regions: [], boxes, lifelines, edges, labels, actions, badges: [], paths: [], ends: [] };
983
1050
  const lefts = [...boxes.map((b) => b.x), ...labels.map((l) => l.x), ...actions.map((a) => a.x)];
984
1051
  const shift = Math.max(0, margin - Math.min(...lefts));
985
1052
  if (shift > 0) shiftContent(layout, shift, 0);
@@ -1005,6 +1072,302 @@ function badges(diagram, layout) {
1005
1072
  return cornerBadge(step.events, s, layout);
1006
1073
  });
1007
1074
  }
1075
+ var STATE_ENDS = ["start", "finish"];
1076
+
1077
+ // src/layout/state.ts
1078
+ var isEnd = (id) => STATE_ENDS.includes(id);
1079
+ function visitOrder(diagram) {
1080
+ const order = [];
1081
+ const add = (id) => {
1082
+ if (!isEnd(id) && !order.includes(id)) order.push(id);
1083
+ };
1084
+ for (const { edge: edge2 } of edgesOf(diagram)) {
1085
+ add(edge2.from);
1086
+ add(edge2.to);
1087
+ }
1088
+ return order;
1089
+ }
1090
+ function carrierHalf(carry) {
1091
+ const C = LOOK.carrier;
1092
+ if (carry.kind === "tag") return (textWidth(carry.text, hasWide(carry.text) ? TYPE.carrierJa : TYPE.carrier) + C.tagPadX * 2) / 2;
1093
+ if (carry.kind === "coin") return C.coinR;
1094
+ return C.envW / 2;
1095
+ }
1096
+ var same = (a, b) => a.from === b.from && a.to === b.to;
1097
+ function layoutState(diagram, lang) {
1098
+ const { box: B, state: T, margin, gap } = LOOK;
1099
+ const inset = LOOK.edge.inset;
1100
+ const words = FIGURE_TEXT[lang];
1101
+ const colors = boxColors(diagram);
1102
+ const steps = edgesOf(diagram);
1103
+ const walked = visitOrder(diagram);
1104
+ const ghosts = diagram.boxes.map((b) => b.id).filter((id) => !walked.includes(id));
1105
+ const notTaken = (diagram.state?.paths ?? []).filter((p) => !steps.some(({ edge: edge2 }) => same(edge2, p)));
1106
+ const lines = [...steps.map(({ edge: edge2 }) => edge2), ...notTaken];
1107
+ const G = T.ghost;
1108
+ const ghostWidth = (id) => {
1109
+ const source = diagram.boxes.find((b) => b.id === id);
1110
+ return G.pad * 2 + B.icon + G.gap + Math.max(textWidth(source?.name ?? id, TYPE.boxName), textWidth(source?.sub ?? "", TYPE.boxSub));
1111
+ };
1112
+ const widths = new Map(diagram.boxes.map((b) => [b.id, ghosts.includes(b.id) ? ghostWidth(b.id) : boxWidth(diagram, b.id, true)]));
1113
+ const columnCount = Math.max(1, Math.min(T.columns, walked.length));
1114
+ const rowCount = Math.max(1, Math.ceil(walked.length / T.columns));
1115
+ const slot = new Map(
1116
+ walked.map((id, k) => {
1117
+ const row = Math.floor(k / T.columns);
1118
+ const at2 = k % T.columns;
1119
+ return [id, { row, col: row % 2 === 0 ? at2 : columnCount - 1 - at2 }];
1120
+ })
1121
+ );
1122
+ const colW = Array.from({ length: columnCount }, (_, c) => Math.max(B.minW, ...walked.filter((id) => slot.get(id)?.col === c).map((id) => widths.get(id) ?? B.minW)));
1123
+ const between = Array.from({ length: Math.max(0, columnCount - 1) }, () => T.columnGap);
1124
+ for (const line of lines) {
1125
+ const a = slot.get(line.from);
1126
+ const b = slot.get(line.to);
1127
+ if (!a || !b || line.label === void 0 || a.row !== b.row || Math.abs(a.col - b.col) !== 1) continue;
1128
+ const i = Math.min(a.col, b.col);
1129
+ between[i] = Math.max(between[i] ?? 0, textWidth(line.label, labelStyle(line.label)) + LOOK.label.padX * 2 + T.labelRoom * 2);
1130
+ }
1131
+ const colLeft = [];
1132
+ for (let c = 0; c < columnCount; c++) colLeft.push(c === 0 ? margin : colLeft[c - 1] + colW[c - 1] + between[c - 1]);
1133
+ const center = (c) => colLeft[c] + colW[c] / 2;
1134
+ const isGhost = (id) => ghosts.includes(id);
1135
+ const enteringFrom = new Set(notTaken.filter((p) => isGhost(p.to) && !isGhost(p.from) && !isEnd(p.from)).map((p) => p.from));
1136
+ const notes = [words.sideNote, ...enteringFrom.size > 0 ? [words.sideFrom(enteringFrom.size)] : []];
1137
+ const titleW = Math.max(textWidth(words.side, TYPE.regionName), ...notes.map((note) => textWidth(note, TYPE.regionNote)));
1138
+ const sideH = T.side.pad * 2 + Math.max(G.h, TYPE.regionName.size + LOOK.region.line * notes.length + T.side.pad / 4);
1139
+ const starts = lines.some((line) => line.from === "start");
1140
+ const top0 = margin + (ghosts.length > 0 ? sideH + T.side.gap : starts ? T.start + T.drop : 0);
1141
+ const rowY = (row) => top0 + row * (B.h + T.rowGap);
1142
+ const boxOf = (id, cx, y, ghost) => {
1143
+ const source = diagram.boxes.find((b) => b.id === id);
1144
+ const w = widths.get(id) ?? B.minW;
1145
+ const h = ghost ? G.h : B.h;
1146
+ return {
1147
+ id,
1148
+ name: source?.name ?? id,
1149
+ ...source?.sub !== void 0 ? { sub: source.sub } : {},
1150
+ ...source?.icon !== void 0 ? { icon: source.icon } : {},
1151
+ color: colors.get(id) ?? "slate",
1152
+ x: cx - w / 2,
1153
+ y,
1154
+ w,
1155
+ h,
1156
+ cx,
1157
+ cy: y + h / 2,
1158
+ ...ghost ? { ghost: true } : {}
1159
+ };
1160
+ };
1161
+ const boxes = walked.map((id) => {
1162
+ const s = slot.get(id);
1163
+ return boxOf(id, center(s.col), rowY(s.row), false);
1164
+ });
1165
+ const byId = new Map(boxes.map((b) => [b.id, b]));
1166
+ const below = (box) => boxes.some((other) => other !== box && Math.abs(other.cx - box.cx) < 0.5 && other.y > box.y);
1167
+ const ends = [];
1168
+ const first = boxes[0];
1169
+ const contentRight = Math.max(...boxes.map((b) => b.x + b.w));
1170
+ let side2;
1171
+ const lane = margin + sideH + T.side.lane;
1172
+ if (ghosts.length > 0) {
1173
+ const sourcesOf = (id) => notTaken.filter((p) => p.to === id).flatMap((p) => byId.get(p.from) ?? []);
1174
+ const all = ghosts.flatMap(sourcesOf);
1175
+ const x = Math.max(margin, Math.min(...all.length > 0 ? all.map((b) => b.x) : [margin + T.side.pad]) - T.side.pad);
1176
+ let cursor = x + T.side.pad + titleW + gap * 2;
1177
+ const wanted = ghosts.map((id) => {
1178
+ const from = sourcesOf(id);
1179
+ return { id, cx: from.length > 0 ? from.reduce((sum, b) => sum + b.cx, 0) / from.length : cursor };
1180
+ });
1181
+ wanted.sort((a, b) => a.cx - b.cx);
1182
+ let right = x;
1183
+ for (const { id, cx } of wanted) {
1184
+ const w = widths.get(id) ?? B.minW;
1185
+ const left = Math.max(cx - w / 2, cursor);
1186
+ const ghost = boxOf(id, left + w / 2, margin + (sideH - G.h) / 2, true);
1187
+ boxes.push(ghost);
1188
+ byId.set(id, ghost);
1189
+ const finishes = notTaken.some((p) => p.from === id && p.to === "finish");
1190
+ if (finishes) ends.push({ kind: "finish", x: ghost.x + ghost.w + T.beside, y: ghost.cy, r: T.end.r, ghost: true, text: "", box: id });
1191
+ right = finishes ? ghost.x + ghost.w + T.beside + T.end.r : ghost.x + ghost.w;
1192
+ cursor = right + gap * 2;
1193
+ }
1194
+ const rightmost = Math.max(right + T.side.pad, contentRight);
1195
+ side2 = { x, y: margin, w: rightmost - x, h: sideH, title: words.side, notes };
1196
+ }
1197
+ if (first && starts) {
1198
+ const reach = first.cx + T.start + T.text + textWidth(words.start, TYPE.regionNote) + gap;
1199
+ const y = side2 && reach < side2.x ? side2.y + T.side.pad + T.start : first.y - T.drop;
1200
+ ends.unshift({ kind: "start", x: first.cx, y, r: T.start, ghost: false, text: words.start });
1201
+ }
1202
+ for (const box of boxes.filter((b) => !b.ghost && lines.some((line) => line.from === b.id && line.to === "finish"))) {
1203
+ ends.push(
1204
+ below(box) ? { kind: "finish", x: box.x + box.w + T.beside, y: box.cy, r: T.end.r, ghost: false, text: words.end, box: box.id } : { kind: "finish", x: box.cx, y: box.y + box.h + T.below, r: T.end.r, ghost: false, text: words.end, box: box.id }
1205
+ );
1206
+ }
1207
+ const between2 = (a, b) => {
1208
+ const sa = slot.get(a.id);
1209
+ const sb = slot.get(b.id);
1210
+ if (!sa || !sb) return [[a.cx, a.y + a.h], [b.cx, b.y - inset]];
1211
+ if (sa.row === sb.row && Math.abs(sa.col - sb.col) === 1) {
1212
+ return b.cx > a.cx ? [[a.x + a.w, a.cy], [b.x - inset, b.cy]] : [[a.x, a.cy], [b.x + b.w + inset, b.cy]];
1213
+ }
1214
+ if (sa.row === sb.row) {
1215
+ const y2 = a.y + a.h + T.rowGap / 4;
1216
+ return [[a.cx, a.y + a.h], [a.cx, y2], [b.cx, y2], [b.cx, b.y + b.h + inset]];
1217
+ }
1218
+ if (sb.row > sa.row) {
1219
+ if (Math.abs(a.cx - b.cx) < 0.5) return [[a.cx, a.y + a.h], [b.cx, b.y - inset]];
1220
+ const y2 = a.y + a.h + T.rowGap / 2;
1221
+ return [[a.cx, a.y + a.h], [a.cx, y2], [b.cx, y2], [b.cx, b.y - inset]];
1222
+ }
1223
+ if (Math.abs(a.cx - b.cx) < 0.5) return [[a.cx, a.y], [b.cx, b.y + b.h + inset]];
1224
+ const y = b.y + b.h + T.rowGap / 2;
1225
+ return [[a.cx, a.y], [a.cx, y], [b.cx, y], [b.cx, b.y + b.h + inset]];
1226
+ };
1227
+ const entryOf = (from, to) => {
1228
+ const sources = notTaken.filter((p) => p.to === to.id).flatMap((p) => byId.get(p.from) ?? []).sort((a, b) => a.cx - b.cx);
1229
+ const k = sources.findIndex((b) => b.id === from);
1230
+ if (sources.length <= 1) return Math.min(Math.max(sources[0]?.cx ?? to.cx, to.x + T.side.entry), to.x + to.w - T.side.entry);
1231
+ return to.x + T.side.entry + (to.w - T.side.entry * 2) * Math.max(0, k) / (sources.length - 1);
1232
+ };
1233
+ const exitX = (box) => starts && box === first ? box.cx + T.side.entry : box.cx;
1234
+ const finishOf = (id) => ends.find((e) => e.kind === "finish" && e.box === id);
1235
+ const loopOf = (box) => {
1236
+ const { w, h, samples } = T.loop;
1237
+ const bottom2 = box.y + box.h;
1238
+ const p0 = [box.cx + w / 2, bottom2];
1239
+ const c1 = [box.cx + w * 3 / 4, bottom2 + h * 4 / 3];
1240
+ const c2 = [box.cx - w * 3 / 4, bottom2 + h * 4 / 3];
1241
+ const p3 = [box.cx - w / 2, bottom2 + inset];
1242
+ return Array.from({ length: samples + 1 }, (_, k) => {
1243
+ const t = k / samples;
1244
+ const u = 1 - t;
1245
+ const at2 = (i) => u * u * u * p0[i] + 3 * u * u * t * c1[i] + 3 * u * t * t * c2[i] + t * t * t * p3[i];
1246
+ return [at2(0), at2(1)];
1247
+ });
1248
+ };
1249
+ const route = (from, to) => {
1250
+ if (from === "start") {
1251
+ const start = ends.find((e) => e.kind === "start");
1252
+ const target = byId.get(to);
1253
+ if (!start || !target) return [];
1254
+ return [[start.x, start.y + start.r], [target.cx, target.y - inset]];
1255
+ }
1256
+ const a = byId.get(from);
1257
+ if (!a) return [];
1258
+ if (to === "finish") {
1259
+ const end = finishOf(from);
1260
+ if (!end) return [];
1261
+ return Math.abs(end.x - a.cx) < 0.5 ? [[a.cx, a.y + a.h], [a.cx, end.y - end.r - inset]] : [[a.x + a.w, a.cy], [end.x - end.r - inset, a.cy]];
1262
+ }
1263
+ const b = byId.get(to);
1264
+ if (!b) return [];
1265
+ if (from === to) return loopOf(a);
1266
+ if (b.ghost && !a.ghost) {
1267
+ const sx = exitX(a);
1268
+ const ex = entryOf(from, b);
1269
+ return Math.abs(sx - ex) < 0.5 ? [[sx, a.y], [ex, b.y + b.h + inset]] : [[sx, a.y], [sx, lane], [ex, lane], [ex, b.y + b.h + inset]];
1270
+ }
1271
+ if (a.ghost && b.ghost) return [[a.x + a.w, a.cy], [b.x - inset, b.cy]];
1272
+ if (a.ghost) return [[a.cx, a.y + a.h], [a.cx, lane], [b.cx, lane], [b.cx, b.y - inset]];
1273
+ return between2(a, b);
1274
+ };
1275
+ const settleOf = (edge2) => {
1276
+ const target = byId.get(edge2.to);
1277
+ if (target) return [target.cx, target.cy + B.iconY];
1278
+ const end = edge2.to === "finish" ? finishOf(edge2.from) : void 0;
1279
+ if (!end) return void 0;
1280
+ const from = byId.get(edge2.from);
1281
+ return from && Math.abs(end.x - from.cx) < 0.5 ? [end.x - end.r - gap - carrierHalf(edge2.carry), end.y] : [end.x, end.y + end.r + gap + LOOK.carrier.tagH / 2];
1282
+ };
1283
+ const sceneEdges = steps.map(({ step, event, edge: edge2 }) => {
1284
+ const settle = settleOf(edge2);
1285
+ return {
1286
+ step,
1287
+ event,
1288
+ from: edge2.from,
1289
+ to: edge2.to,
1290
+ points: route(edge2.from, edge2.to),
1291
+ color: colorOf(edge2, colors),
1292
+ carry: edge2.carry,
1293
+ ...settle ? { settle } : {}
1294
+ };
1295
+ });
1296
+ for (const e of sceneEdges) {
1297
+ if (e.points.length !== 2 || !sceneEdges.some((o) => o.from === e.to && o.to === e.from && o.points.length === 2)) continue;
1298
+ const [p, q] = e.points;
1299
+ const flat = Math.abs(q[1] - p[1]) < Math.abs(q[0] - p[0]);
1300
+ const d = (e.from < e.to ? 1 : -1) * LOOK.edge.parallel;
1301
+ e.points = e.points.map(([x, y]) => flat ? [x, y + d] : [x + d, y]);
1302
+ }
1303
+ const paths = notTaken.map((p) => ({ from: p.from, to: p.to, points: route(p.from, p.to) }));
1304
+ const labels = [];
1305
+ const soft = side2 ? [{ x: side2.x, y: side2.y, w: T.side.pad + titleW, h: side2.h }] : [];
1306
+ for (const e of sceneEdges) {
1307
+ const source = diagram.steps[e.step]?.events[e.event];
1308
+ if (source?.type !== "edge" || source.label === void 0) continue;
1309
+ const style = labelStyle(source.label);
1310
+ if (e.from === e.to) {
1311
+ const w = textWidth(source.label, style) + LOOK.label.padX * 2;
1312
+ const bottom2 = Math.max(...e.points.map(([, y]) => y));
1313
+ labels.push({ step: e.step, event: e.event, text: source.label, family: style.family, color: e.color, x: (e.points[0]?.[0] ?? 0) - T.loop.w / 2 - w / 2, y: bottom2 + LOOK.label.soft, w, h: LOOK.label.h });
1314
+ continue;
1315
+ }
1316
+ const side22 = source.labelSide ?? (e.to === "finish" ? "left" : void 0);
1317
+ labels.push(
1318
+ placeLabel(
1319
+ { step: e.step, event: e.event, text: source.label, points: e.points, color: e.color, ...side22 ? { side: side22 } : {} },
1320
+ { hard: boxes, soft: [...soft, ...labels.filter((l) => l.step === e.step)] }
1321
+ )
1322
+ );
1323
+ }
1324
+ notTaken.forEach((p, i) => {
1325
+ const path2 = paths[i];
1326
+ if (p.label === void 0 || path2.points.length === 0) return;
1327
+ const style = labelStyle(p.label);
1328
+ const into = byId.get(p.to)?.ghost === true && byId.get(p.from)?.ghost !== true;
1329
+ const rect = into ? { x: path2.points[0][0] + LOOK.label.soft, y: lane + LOOK.label.soft, w: textWidth(p.label, style) + LOOK.label.padX * 2, h: LOOK.label.h } : placeLabel({ step: -1, event: i, text: p.label, points: path2.points, color: "slate" }, { hard: boxes, soft });
1330
+ path2.label = { x: rect.x, y: rect.y, w: rect.w, h: rect.h, text: p.label, family: style.family };
1331
+ });
1332
+ const layout = { kind: "state", width: 0, height: 0, regions: [], boxes, lifelines: [], edges: sceneEdges, labels, actions: [], badges: [], paths, ends, ...side2 ? { side: side2 } : {} };
1333
+ const lefts = [...boxes.map((b) => b.x), ...labels.map((l) => l.x), ...paths.flatMap((p) => p.label ? [p.label.x] : [])];
1334
+ const shift = Math.max(0, margin - Math.min(...lefts));
1335
+ if (shift > 0) shiftContent(layout, shift, 0);
1336
+ const endRight = (e) => e.x + (e.text === "" ? e.r : T.text + textWidth(e.text, TYPE.regionNote));
1337
+ const rights = [
1338
+ ...boxes.map((b) => b.x + b.w),
1339
+ ...labels.map((l) => l.x + l.w),
1340
+ ...ends.map(endRight),
1341
+ ...sceneEdges.flatMap((e) => e.points.map((p) => p[0])),
1342
+ ...paths.flatMap((p) => [...p.points.map((q) => q[0]), ...p.label ? [p.label.x + p.label.w] : []]),
1343
+ ...side2 ? [side2.x + side2.w] : []
1344
+ ];
1345
+ const bottoms = [...boxes.map((b) => b.y + b.h), ...labels.map((l) => l.y + l.h), ...ends.map((e) => e.y + e.r), ...sceneEdges.flatMap((e) => e.points.map((p) => p[1]))];
1346
+ const trail = { title: words.trail, states: walked.map((id) => ({ box: id, color: colors.get(id) ?? "slate" })) };
1347
+ const width = Math.max(Math.max(...rights) + margin, stripNeed(diagram, trail) + margin * 2);
1348
+ const bottom = Math.max(...bottoms, rowY(rowCount - 1) + B.h);
1349
+ const strip2 = layoutStrip(diagram, margin, bottom + gap, width - margin * 2, trail);
1350
+ layout.width = width;
1351
+ layout.height = (strip2 ? strip2.y + strip2.h : bottom) + margin;
1352
+ if (strip2) layout.strip = strip2;
1353
+ layout.badges = diagram.steps.map((step, s) => {
1354
+ const edge2 = sceneEdges.find((e) => e.step === s && e.points.length > 0);
1355
+ if (!edge2) return cornerBadge(step.events, s, layout);
1356
+ if (edge2.from === edge2.to) {
1357
+ const right = Math.max(...edge2.points.map(([px]) => px));
1358
+ const top = edge2.points[0][1];
1359
+ const deep = Math.max(...edge2.points.map(([, py]) => py));
1360
+ return { step: s, x: right + LOOK.badge.r + LOOK.badge.inset, y: top + (deep - top) * T.loop.badgeAt, color: edge2.color };
1361
+ }
1362
+ const [x, y] = badgeOnPath(edge2.points);
1363
+ return { step: s, x, y, color: edge2.color };
1364
+ });
1365
+ return layout;
1366
+ }
1367
+ function colorOf(edge2, colors) {
1368
+ if (edge2.carry.kind === "coin") return edgeColor(edge2, colors);
1369
+ return colors.get(edge2.to === "finish" ? edge2.from : edge2.to) ?? "slate";
1370
+ }
1008
1371
 
1009
1372
  // src/field-messages.ts
1010
1373
  var TYPES_JA = {
@@ -1037,6 +1400,7 @@ var ja = {
1037
1400
  minimum: (limit) => `${limit} \u4EE5\u4E0A\u306B\u3059\u308B`,
1038
1401
  const: (value) => `${value} \u306B\u3059\u308B`,
1039
1402
  not: (allowed) => allowed ? `${allowed.field} \u306E\u6B04\u306F kind \u304C ${allowed.kind} \u306E\u6642\u3060\u3051\u66F8\u3051\u308B` : "\u3053\u306E\u6B04\u306E\u7D44\u307F\u5408\u308F\u305B\u306F\u66F8\u3051\u306A\u3044",
1403
+ reserved: (names) => `${names.join(" \u3068 ")} \u306F\u72B6\u614B\u9077\u79FB\u56F3\u306E\u59CB\u307E\u308A\u3068\u7D42\u308F\u308A\u306E\u5370\u306E\u540D\u524D\u3067\u3001\u7BB1\u306E\u540D\u672D\u306B\u4F7F\u3048\u306A\u3044`,
1040
1404
  anyOf: (fields) => fields.length > 0 ? `${fields.join(" \u304B ")} \u306E${fields.length === 2 ? "\u3069\u3061\u3089\u304B" : "\u3069\u308C\u304B"}\u306E\u6B04\u304C\u8981\u308B` : "\u66F8\u3051\u308B\u5F62\u306E\u3069\u308C\u306B\u3082\u5408\u308F\u306A\u3044",
1041
1405
  oneOf: "\u66F8\u3051\u308B\u5F62\u306E\u3069\u308C\u304B 1 \u3064\u3060\u3051\u306B\u5408\u308F\u305B\u308B",
1042
1406
  discriminator: (tag, values) => `${tag} \u306F ${values.join(" / ")} \u306E\u3069\u308C\u304B\u306B\u3059\u308B`,
@@ -1053,6 +1417,7 @@ var en = {
1053
1417
  minimum: (limit) => `Use ${limit} or greater`,
1054
1418
  const: (value) => `Use ${value}`,
1055
1419
  not: (allowed) => allowed ? `The ${allowed.field} field is allowed only when kind is ${allowed.kind}` : "This combination of fields is not allowed",
1420
+ reserved: (names) => `${names.join(" and ")} name the start and end marks of a state diagram and cannot be box ids`,
1056
1421
  anyOf: (fields) => fields.length > 0 ? `Write one of the ${fields.join(" or ")} fields` : "Does not match any of the allowed shapes",
1057
1422
  oneOf: "Match exactly one of the allowed shapes",
1058
1423
  discriminator: (tag, values) => `${tag} is one of ${values.join(" / ")}`,
@@ -1067,7 +1432,7 @@ function ucs2length(str) {
1067
1432
  return length;
1068
1433
  }
1069
1434
  var validate_diagram_default = validate10;
1070
- var schema11 = { "properties": { "version": { "description": "\u5F62\u5F0F\u306E\u7248", "type": "integer", "minimum": 1 }, "kind": { "description": "\u56F3\u306E\u7A2E\u985E", "enum": ["sequence", "architecture"] }, "title": { "$ref": "#/definitions/text" }, "view": { "description": "\u898B\u305B\u65B9\u3002\u66F8\u304B\u306A\u3051\u308C\u3070\u5B57\u306E\u5927\u304D\u3055\u3067\u9078\u3076\u3002fixed \u306F\u5168\u4F53\u3092\u6B62\u3081\u3066\u4E2D\u3060\u3051\u52D5\u304B\u3057\u3001follow \u306F\u5BC4\u3063\u3066\u52D5\u304B\u3057\u5168\u4F53\u56F3\u3067\u4ECA\u3069\u3053\u304B\u3092\u793A\u3059", "enum": ["fixed", "follow"] }, "regions": { "type": "array", "items": { "$ref": "#/definitions/region" } }, "boxes": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/box" } }, "strip": { "$ref": "#/definitions/strip" }, "steps": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/step" } }, "sequence": { "$ref": "#/definitions/sequence" } }};
1435
+ var schema11 = { "properties": { "version": { "description": "\u5F62\u5F0F\u306E\u7248", "type": "integer", "minimum": 1 }, "kind": { "description": "\u56F3\u306E\u7A2E\u985E", "enum": ["sequence", "architecture", "state"] }, "title": { "$ref": "#/definitions/text" }, "view": { "description": "\u898B\u305B\u65B9\u3002\u66F8\u304B\u306A\u3051\u308C\u3070\u5B57\u306E\u5927\u304D\u3055\u3067\u9078\u3076\u3002fixed \u306F\u5168\u4F53\u3092\u6B62\u3081\u3066\u4E2D\u3060\u3051\u52D5\u304B\u3057\u3001follow \u306F\u5BC4\u3063\u3066\u52D5\u304B\u3057\u5168\u4F53\u56F3\u3067\u4ECA\u3069\u3053\u304B\u3092\u793A\u3059", "enum": ["fixed", "follow"] }, "regions": { "type": "array", "items": { "$ref": "#/definitions/region" } }, "boxes": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/box" } }, "strip": { "$ref": "#/definitions/strip" }, "steps": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/step" } }, "sequence": { "$ref": "#/definitions/sequence" }, "state": { "$ref": "#/definitions/state" } }};
1071
1436
  var func2 = Object.prototype.hasOwnProperty;
1072
1437
  var func3 = ucs2length;
1073
1438
  var schema17 = { "enum": ["blue", "amber", "green", "violet", "rose", "slate", "coin"] };
@@ -2461,6 +2826,182 @@ function validate23(data, { instancePath = "", parentData, parentDataProperty, r
2461
2826
  validate23.errors = vErrors;
2462
2827
  return errors === 0;
2463
2828
  }
2829
+ function validate26(data, { instancePath = "", parentData, parentDataProperty, rootData = data } = {}) {
2830
+ let vErrors = null;
2831
+ let errors = 0;
2832
+ if (data && typeof data == "object" && !Array.isArray(data)) {
2833
+ if (data.from === void 0) {
2834
+ const err0 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "from" }, message: "must have required property 'from'" };
2835
+ if (vErrors === null) {
2836
+ vErrors = [err0];
2837
+ } else {
2838
+ vErrors.push(err0);
2839
+ }
2840
+ errors++;
2841
+ }
2842
+ if (data.to === void 0) {
2843
+ const err1 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "to" }, message: "must have required property 'to'" };
2844
+ if (vErrors === null) {
2845
+ vErrors = [err1];
2846
+ } else {
2847
+ vErrors.push(err1);
2848
+ }
2849
+ errors++;
2850
+ }
2851
+ for (const key0 in data) {
2852
+ if (!(key0 === "from" || key0 === "to" || key0 === "label")) {
2853
+ const err2 = { instancePath, schemaPath: "#/additionalProperties", keyword: "additionalProperties", params: { additionalProperty: key0 }, message: "must NOT have additional properties" };
2854
+ if (vErrors === null) {
2855
+ vErrors = [err2];
2856
+ } else {
2857
+ vErrors.push(err2);
2858
+ }
2859
+ errors++;
2860
+ }
2861
+ }
2862
+ if (data.from !== void 0) {
2863
+ let data0 = data.from;
2864
+ if (typeof data0 === "string") {
2865
+ if (!pattern0.test(data0)) {
2866
+ const err3 = { instancePath: instancePath + "/from", schemaPath: "#/definitions/id/pattern", keyword: "pattern", params: { pattern: "^[^\\s\\[\\]\u300C\u300D=:]+$" }, message: 'must match pattern "^[^\\s\\[\\]\u300C\u300D=:]+$"' };
2867
+ if (vErrors === null) {
2868
+ vErrors = [err3];
2869
+ } else {
2870
+ vErrors.push(err3);
2871
+ }
2872
+ errors++;
2873
+ }
2874
+ } else {
2875
+ const err4 = { instancePath: instancePath + "/from", schemaPath: "#/definitions/id/type", keyword: "type", params: { type: "string" }, message: "must be string" };
2876
+ if (vErrors === null) {
2877
+ vErrors = [err4];
2878
+ } else {
2879
+ vErrors.push(err4);
2880
+ }
2881
+ errors++;
2882
+ }
2883
+ }
2884
+ if (data.to !== void 0) {
2885
+ let data1 = data.to;
2886
+ if (typeof data1 === "string") {
2887
+ if (!pattern0.test(data1)) {
2888
+ const err5 = { instancePath: instancePath + "/to", schemaPath: "#/definitions/id/pattern", keyword: "pattern", params: { pattern: "^[^\\s\\[\\]\u300C\u300D=:]+$" }, message: 'must match pattern "^[^\\s\\[\\]\u300C\u300D=:]+$"' };
2889
+ if (vErrors === null) {
2890
+ vErrors = [err5];
2891
+ } else {
2892
+ vErrors.push(err5);
2893
+ }
2894
+ errors++;
2895
+ }
2896
+ } else {
2897
+ const err6 = { instancePath: instancePath + "/to", schemaPath: "#/definitions/id/type", keyword: "type", params: { type: "string" }, message: "must be string" };
2898
+ if (vErrors === null) {
2899
+ vErrors = [err6];
2900
+ } else {
2901
+ vErrors.push(err6);
2902
+ }
2903
+ errors++;
2904
+ }
2905
+ }
2906
+ if (data.label !== void 0) {
2907
+ let data2 = data.label;
2908
+ if (typeof data2 === "string") {
2909
+ if (func3(data2) < 1) {
2910
+ const err7 = { instancePath: instancePath + "/label", schemaPath: "#/definitions/text/minLength", keyword: "minLength", params: { limit: 1 }, message: "must NOT have fewer than 1 characters" };
2911
+ if (vErrors === null) {
2912
+ vErrors = [err7];
2913
+ } else {
2914
+ vErrors.push(err7);
2915
+ }
2916
+ errors++;
2917
+ }
2918
+ } else {
2919
+ const err8 = { instancePath: instancePath + "/label", schemaPath: "#/definitions/text/type", keyword: "type", params: { type: "string" }, message: "must be string" };
2920
+ if (vErrors === null) {
2921
+ vErrors = [err8];
2922
+ } else {
2923
+ vErrors.push(err8);
2924
+ }
2925
+ errors++;
2926
+ }
2927
+ }
2928
+ } else {
2929
+ const err9 = { instancePath, schemaPath: "#/type", keyword: "type", params: { type: "object" }, message: "must be object" };
2930
+ if (vErrors === null) {
2931
+ vErrors = [err9];
2932
+ } else {
2933
+ vErrors.push(err9);
2934
+ }
2935
+ errors++;
2936
+ }
2937
+ validate26.errors = vErrors;
2938
+ return errors === 0;
2939
+ }
2940
+ function validate25(data, { instancePath = "", parentData, parentDataProperty, rootData = data } = {}) {
2941
+ let vErrors = null;
2942
+ let errors = 0;
2943
+ if (data && typeof data == "object" && !Array.isArray(data)) {
2944
+ if (data.paths === void 0) {
2945
+ const err0 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "paths" }, message: "must have required property 'paths'" };
2946
+ if (vErrors === null) {
2947
+ vErrors = [err0];
2948
+ } else {
2949
+ vErrors.push(err0);
2950
+ }
2951
+ errors++;
2952
+ }
2953
+ for (const key0 in data) {
2954
+ if (!(key0 === "paths")) {
2955
+ const err1 = { instancePath, schemaPath: "#/additionalProperties", keyword: "additionalProperties", params: { additionalProperty: key0 }, message: "must NOT have additional properties" };
2956
+ if (vErrors === null) {
2957
+ vErrors = [err1];
2958
+ } else {
2959
+ vErrors.push(err1);
2960
+ }
2961
+ errors++;
2962
+ }
2963
+ }
2964
+ if (data.paths !== void 0) {
2965
+ let data0 = data.paths;
2966
+ if (Array.isArray(data0)) {
2967
+ if (data0.length < 1) {
2968
+ const err2 = { instancePath: instancePath + "/paths", schemaPath: "#/properties/paths/minItems", keyword: "minItems", params: { limit: 1 }, message: "must NOT have fewer than 1 items" };
2969
+ if (vErrors === null) {
2970
+ vErrors = [err2];
2971
+ } else {
2972
+ vErrors.push(err2);
2973
+ }
2974
+ errors++;
2975
+ }
2976
+ const len0 = data0.length;
2977
+ for (let i0 = 0; i0 < len0; i0++) {
2978
+ if (!validate26(data0[i0], { instancePath: instancePath + "/paths/" + i0, parentData: data0, parentDataProperty: i0, rootData })) {
2979
+ vErrors = vErrors === null ? validate26.errors : vErrors.concat(validate26.errors);
2980
+ errors = vErrors.length;
2981
+ }
2982
+ }
2983
+ } else {
2984
+ const err3 = { instancePath: instancePath + "/paths", schemaPath: "#/properties/paths/type", keyword: "type", params: { type: "array" }, message: "must be array" };
2985
+ if (vErrors === null) {
2986
+ vErrors = [err3];
2987
+ } else {
2988
+ vErrors.push(err3);
2989
+ }
2990
+ errors++;
2991
+ }
2992
+ }
2993
+ } else {
2994
+ const err4 = { instancePath, schemaPath: "#/type", keyword: "type", params: { type: "object" }, message: "must be object" };
2995
+ if (vErrors === null) {
2996
+ vErrors = [err4];
2997
+ } else {
2998
+ vErrors.push(err4);
2999
+ }
3000
+ errors++;
3001
+ }
3002
+ validate25.errors = vErrors;
3003
+ return errors === 0;
3004
+ }
2464
3005
  function validate10(data, { instancePath = "", parentData, parentDataProperty, rootData = data } = {}) {
2465
3006
  let vErrors = null;
2466
3007
  let errors = 0;
@@ -2502,9 +3043,11 @@ function validate10(data, { instancePath = "", parentData, parentDataProperty, r
2502
3043
  let ifClause0;
2503
3044
  if (_valid0) {
2504
3045
  const _errs4 = errors;
3046
+ const _errs5 = errors;
3047
+ const _errs6 = errors;
2505
3048
  if (data && typeof data == "object" && !Array.isArray(data)) {
2506
- if (data.sequence === void 0) {
2507
- const err2 = { instancePath, schemaPath: "#/then/required", keyword: "required", params: { missingProperty: "sequence" }, message: "must have required property 'sequence'" };
3049
+ if (data.state === void 0 && ("state")) {
3050
+ const err2 = {};
2508
3051
  if (vErrors === null) {
2509
3052
  vErrors = [err2];
2510
3053
  } else {
@@ -2513,227 +3056,391 @@ function validate10(data, { instancePath = "", parentData, parentDataProperty, r
2513
3056
  errors++;
2514
3057
  }
2515
3058
  }
3059
+ var valid2 = _errs6 === errors;
3060
+ if (valid2) {
3061
+ const err3 = { instancePath, schemaPath: "#/then/not", keyword: "not", params: {}, message: "must NOT be valid" };
3062
+ if (vErrors === null) {
3063
+ vErrors = [err3];
3064
+ } else {
3065
+ vErrors.push(err3);
3066
+ }
3067
+ errors++;
3068
+ } else {
3069
+ errors = _errs5;
3070
+ if (vErrors !== null) {
3071
+ if (_errs5) {
3072
+ vErrors.length = _errs5;
3073
+ } else {
3074
+ vErrors = null;
3075
+ }
3076
+ }
3077
+ }
3078
+ if (data && typeof data == "object" && !Array.isArray(data)) {
3079
+ if (data.sequence === void 0) {
3080
+ const err4 = { instancePath, schemaPath: "#/then/required", keyword: "required", params: { missingProperty: "sequence" }, message: "must have required property 'sequence'" };
3081
+ if (vErrors === null) {
3082
+ vErrors = [err4];
3083
+ } else {
3084
+ vErrors.push(err4);
3085
+ }
3086
+ errors++;
3087
+ }
3088
+ }
2516
3089
  var _valid0 = _errs4 === errors;
2517
3090
  valid0 = _valid0;
2518
3091
  ifClause0 = "then";
2519
3092
  } else {
2520
- const _errs5 = errors;
2521
- const _errs6 = errors;
2522
3093
  const _errs7 = errors;
3094
+ const _errs8 = errors;
3095
+ const _errs9 = errors;
2523
3096
  if (data && typeof data == "object" && !Array.isArray(data)) {
2524
3097
  if (data.sequence === void 0 && ("sequence")) {
2525
- const err3 = {};
3098
+ const err5 = {};
2526
3099
  if (vErrors === null) {
2527
- vErrors = [err3];
3100
+ vErrors = [err5];
2528
3101
  } else {
2529
- vErrors.push(err3);
3102
+ vErrors.push(err5);
2530
3103
  }
2531
3104
  errors++;
2532
3105
  }
2533
3106
  }
2534
- var valid2 = _errs7 === errors;
2535
- if (valid2) {
2536
- const err4 = { instancePath, schemaPath: "#/else/not", keyword: "not", params: {}, message: "must NOT be valid" };
3107
+ var valid3 = _errs9 === errors;
3108
+ if (valid3) {
3109
+ const err6 = { instancePath, schemaPath: "#/else/not", keyword: "not", params: {}, message: "must NOT be valid" };
2537
3110
  if (vErrors === null) {
2538
- vErrors = [err4];
3111
+ vErrors = [err6];
2539
3112
  } else {
2540
- vErrors.push(err4);
3113
+ vErrors.push(err6);
2541
3114
  }
2542
3115
  errors++;
2543
3116
  } else {
2544
- errors = _errs6;
3117
+ errors = _errs8;
2545
3118
  if (vErrors !== null) {
2546
- if (_errs6) {
2547
- vErrors.length = _errs6;
3119
+ if (_errs8) {
3120
+ vErrors.length = _errs8;
2548
3121
  } else {
2549
3122
  vErrors = null;
2550
3123
  }
2551
3124
  }
2552
3125
  }
2553
- var _valid0 = _errs5 === errors;
3126
+ const _errs10 = errors;
3127
+ let valid4 = true;
3128
+ const _errs11 = errors;
3129
+ if (data && typeof data == "object" && !Array.isArray(data)) {
3130
+ if (data.kind === void 0 && ("kind")) {
3131
+ const err7 = {};
3132
+ if (vErrors === null) {
3133
+ vErrors = [err7];
3134
+ } else {
3135
+ vErrors.push(err7);
3136
+ }
3137
+ errors++;
3138
+ } else {
3139
+ if (data.kind !== void 0) {
3140
+ if ("state" !== data.kind) {
3141
+ const err8 = {};
3142
+ if (vErrors === null) {
3143
+ vErrors = [err8];
3144
+ } else {
3145
+ vErrors.push(err8);
3146
+ }
3147
+ errors++;
3148
+ }
3149
+ }
3150
+ }
3151
+ }
3152
+ var _valid1 = _errs11 === errors;
3153
+ errors = _errs10;
3154
+ if (vErrors !== null) {
3155
+ if (_errs10) {
3156
+ vErrors.length = _errs10;
3157
+ } else {
3158
+ vErrors = null;
3159
+ }
3160
+ }
3161
+ let ifClause1;
3162
+ if (_valid1) {
3163
+ const _errs13 = errors;
3164
+ if (data && typeof data == "object" && !Array.isArray(data)) {
3165
+ if (data.boxes !== void 0) {
3166
+ let data2 = data.boxes;
3167
+ if (Array.isArray(data2)) {
3168
+ const len0 = data2.length;
3169
+ for (let i0 = 0; i0 < len0; i0++) {
3170
+ let data3 = data2[i0];
3171
+ if (data3 && typeof data3 == "object" && !Array.isArray(data3)) {
3172
+ if (data3.id !== void 0) {
3173
+ let data4 = data3.id;
3174
+ const _errs17 = errors;
3175
+ const _errs18 = errors;
3176
+ if (!(data4 === "start" || data4 === "finish")) {
3177
+ const err9 = {};
3178
+ if (vErrors === null) {
3179
+ vErrors = [err9];
3180
+ } else {
3181
+ vErrors.push(err9);
3182
+ }
3183
+ errors++;
3184
+ }
3185
+ var valid10 = _errs18 === errors;
3186
+ if (valid10) {
3187
+ const err10 = { instancePath: instancePath + "/boxes/" + i0 + "/id", schemaPath: "#/else/then/properties/boxes/items/properties/id/not", keyword: "not", params: {}, message: "must NOT be valid" };
3188
+ if (vErrors === null) {
3189
+ vErrors = [err10];
3190
+ } else {
3191
+ vErrors.push(err10);
3192
+ }
3193
+ errors++;
3194
+ } else {
3195
+ errors = _errs17;
3196
+ if (vErrors !== null) {
3197
+ if (_errs17) {
3198
+ vErrors.length = _errs17;
3199
+ } else {
3200
+ vErrors = null;
3201
+ }
3202
+ }
3203
+ }
3204
+ }
3205
+ }
3206
+ }
3207
+ }
3208
+ }
3209
+ }
3210
+ var _valid1 = _errs13 === errors;
3211
+ valid4 = _valid1;
3212
+ ifClause1 = "then";
3213
+ } else {
3214
+ const _errs19 = errors;
3215
+ const _errs20 = errors;
3216
+ const _errs21 = errors;
3217
+ if (data && typeof data == "object" && !Array.isArray(data)) {
3218
+ if (data.state === void 0 && ("state")) {
3219
+ const err11 = {};
3220
+ if (vErrors === null) {
3221
+ vErrors = [err11];
3222
+ } else {
3223
+ vErrors.push(err11);
3224
+ }
3225
+ errors++;
3226
+ }
3227
+ }
3228
+ var valid11 = _errs21 === errors;
3229
+ if (valid11) {
3230
+ const err12 = { instancePath, schemaPath: "#/else/else/not", keyword: "not", params: {}, message: "must NOT be valid" };
3231
+ if (vErrors === null) {
3232
+ vErrors = [err12];
3233
+ } else {
3234
+ vErrors.push(err12);
3235
+ }
3236
+ errors++;
3237
+ } else {
3238
+ errors = _errs20;
3239
+ if (vErrors !== null) {
3240
+ if (_errs20) {
3241
+ vErrors.length = _errs20;
3242
+ } else {
3243
+ vErrors = null;
3244
+ }
3245
+ }
3246
+ }
3247
+ var _valid1 = _errs19 === errors;
3248
+ valid4 = _valid1;
3249
+ ifClause1 = "else";
3250
+ }
3251
+ if (!valid4) {
3252
+ const err13 = { instancePath, schemaPath: "#/else/if", keyword: "if", params: { failingKeyword: ifClause1 }, message: 'must match "' + ifClause1 + '" schema' };
3253
+ if (vErrors === null) {
3254
+ vErrors = [err13];
3255
+ } else {
3256
+ vErrors.push(err13);
3257
+ }
3258
+ errors++;
3259
+ }
3260
+ var _valid0 = _errs7 === errors;
2554
3261
  valid0 = _valid0;
2555
3262
  ifClause0 = "else";
2556
3263
  }
2557
3264
  if (!valid0) {
2558
- const err5 = { instancePath, schemaPath: "#/if", keyword: "if", params: { failingKeyword: ifClause0 }, message: 'must match "' + ifClause0 + '" schema' };
3265
+ const err14 = { instancePath, schemaPath: "#/if", keyword: "if", params: { failingKeyword: ifClause0 }, message: 'must match "' + ifClause0 + '" schema' };
2559
3266
  if (vErrors === null) {
2560
- vErrors = [err5];
3267
+ vErrors = [err14];
2561
3268
  } else {
2562
- vErrors.push(err5);
3269
+ vErrors.push(err14);
2563
3270
  }
2564
3271
  errors++;
2565
3272
  }
2566
3273
  if (data && typeof data == "object" && !Array.isArray(data)) {
2567
3274
  if (data.version === void 0) {
2568
- const err6 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "version" }, message: "must have required property 'version'" };
3275
+ const err15 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "version" }, message: "must have required property 'version'" };
2569
3276
  if (vErrors === null) {
2570
- vErrors = [err6];
3277
+ vErrors = [err15];
2571
3278
  } else {
2572
- vErrors.push(err6);
3279
+ vErrors.push(err15);
2573
3280
  }
2574
3281
  errors++;
2575
3282
  }
2576
3283
  if (data.kind === void 0) {
2577
- const err7 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "kind" }, message: "must have required property 'kind'" };
3284
+ const err16 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "kind" }, message: "must have required property 'kind'" };
2578
3285
  if (vErrors === null) {
2579
- vErrors = [err7];
3286
+ vErrors = [err16];
2580
3287
  } else {
2581
- vErrors.push(err7);
3288
+ vErrors.push(err16);
2582
3289
  }
2583
3290
  errors++;
2584
3291
  }
2585
3292
  if (data.title === void 0) {
2586
- const err8 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "title" }, message: "must have required property 'title'" };
3293
+ const err17 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "title" }, message: "must have required property 'title'" };
2587
3294
  if (vErrors === null) {
2588
- vErrors = [err8];
3295
+ vErrors = [err17];
2589
3296
  } else {
2590
- vErrors.push(err8);
3297
+ vErrors.push(err17);
2591
3298
  }
2592
3299
  errors++;
2593
3300
  }
2594
3301
  if (data.boxes === void 0) {
2595
- const err9 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "boxes" }, message: "must have required property 'boxes'" };
3302
+ const err18 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "boxes" }, message: "must have required property 'boxes'" };
2596
3303
  if (vErrors === null) {
2597
- vErrors = [err9];
3304
+ vErrors = [err18];
2598
3305
  } else {
2599
- vErrors.push(err9);
3306
+ vErrors.push(err18);
2600
3307
  }
2601
3308
  errors++;
2602
3309
  }
2603
3310
  if (data.steps === void 0) {
2604
- const err10 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "steps" }, message: "must have required property 'steps'" };
3311
+ const err19 = { instancePath, schemaPath: "#/required", keyword: "required", params: { missingProperty: "steps" }, message: "must have required property 'steps'" };
2605
3312
  if (vErrors === null) {
2606
- vErrors = [err10];
3313
+ vErrors = [err19];
2607
3314
  } else {
2608
- vErrors.push(err10);
3315
+ vErrors.push(err19);
2609
3316
  }
2610
3317
  errors++;
2611
3318
  }
2612
3319
  for (const key0 in data) {
2613
3320
  if (!func2.call(schema11.properties, key0)) {
2614
- const err11 = { instancePath, schemaPath: "#/additionalProperties", keyword: "additionalProperties", params: { additionalProperty: key0 }, message: "must NOT have additional properties" };
3321
+ const err20 = { instancePath, schemaPath: "#/additionalProperties", keyword: "additionalProperties", params: { additionalProperty: key0 }, message: "must NOT have additional properties" };
2615
3322
  if (vErrors === null) {
2616
- vErrors = [err11];
3323
+ vErrors = [err20];
2617
3324
  } else {
2618
- vErrors.push(err11);
3325
+ vErrors.push(err20);
2619
3326
  }
2620
3327
  errors++;
2621
3328
  }
2622
3329
  }
2623
3330
  if (data.version !== void 0) {
2624
- let data1 = data.version;
2625
- if (!(typeof data1 == "number" && (!(data1 % 1) && !isNaN(data1)) && isFinite(data1))) {
2626
- const err12 = { instancePath: instancePath + "/version", schemaPath: "#/properties/version/type", keyword: "type", params: { type: "integer" }, message: "must be integer" };
3331
+ let data5 = data.version;
3332
+ if (!(typeof data5 == "number" && (!(data5 % 1) && !isNaN(data5)) && isFinite(data5))) {
3333
+ const err21 = { instancePath: instancePath + "/version", schemaPath: "#/properties/version/type", keyword: "type", params: { type: "integer" }, message: "must be integer" };
2627
3334
  if (vErrors === null) {
2628
- vErrors = [err12];
3335
+ vErrors = [err21];
2629
3336
  } else {
2630
- vErrors.push(err12);
3337
+ vErrors.push(err21);
2631
3338
  }
2632
3339
  errors++;
2633
3340
  }
2634
- if (typeof data1 == "number" && isFinite(data1)) {
2635
- if (data1 < 1 || isNaN(data1)) {
2636
- const err13 = { instancePath: instancePath + "/version", schemaPath: "#/properties/version/minimum", keyword: "minimum", params: { comparison: ">=", limit: 1 }, message: "must be >= 1" };
3341
+ if (typeof data5 == "number" && isFinite(data5)) {
3342
+ if (data5 < 1 || isNaN(data5)) {
3343
+ const err22 = { instancePath: instancePath + "/version", schemaPath: "#/properties/version/minimum", keyword: "minimum", params: { comparison: ">=", limit: 1 }, message: "must be >= 1" };
2637
3344
  if (vErrors === null) {
2638
- vErrors = [err13];
3345
+ vErrors = [err22];
2639
3346
  } else {
2640
- vErrors.push(err13);
3347
+ vErrors.push(err22);
2641
3348
  }
2642
3349
  errors++;
2643
3350
  }
2644
3351
  }
2645
3352
  }
2646
3353
  if (data.kind !== void 0) {
2647
- let data2 = data.kind;
2648
- if (!(data2 === "sequence" || data2 === "architecture")) {
2649
- const err14 = { instancePath: instancePath + "/kind", schemaPath: "#/properties/kind/enum", keyword: "enum", params: { allowedValues: schema11.properties.kind.enum }, message: "must be equal to one of the allowed values" };
3354
+ let data6 = data.kind;
3355
+ if (!(data6 === "sequence" || data6 === "architecture" || data6 === "state")) {
3356
+ const err23 = { instancePath: instancePath + "/kind", schemaPath: "#/properties/kind/enum", keyword: "enum", params: { allowedValues: schema11.properties.kind.enum }, message: "must be equal to one of the allowed values" };
2650
3357
  if (vErrors === null) {
2651
- vErrors = [err14];
3358
+ vErrors = [err23];
2652
3359
  } else {
2653
- vErrors.push(err14);
3360
+ vErrors.push(err23);
2654
3361
  }
2655
3362
  errors++;
2656
3363
  }
2657
3364
  }
2658
3365
  if (data.title !== void 0) {
2659
- let data3 = data.title;
2660
- if (typeof data3 === "string") {
2661
- if (func3(data3) < 1) {
2662
- const err15 = { instancePath: instancePath + "/title", schemaPath: "#/definitions/text/minLength", keyword: "minLength", params: { limit: 1 }, message: "must NOT have fewer than 1 characters" };
3366
+ let data7 = data.title;
3367
+ if (typeof data7 === "string") {
3368
+ if (func3(data7) < 1) {
3369
+ const err24 = { instancePath: instancePath + "/title", schemaPath: "#/definitions/text/minLength", keyword: "minLength", params: { limit: 1 }, message: "must NOT have fewer than 1 characters" };
2663
3370
  if (vErrors === null) {
2664
- vErrors = [err15];
3371
+ vErrors = [err24];
2665
3372
  } else {
2666
- vErrors.push(err15);
3373
+ vErrors.push(err24);
2667
3374
  }
2668
3375
  errors++;
2669
3376
  }
2670
3377
  } else {
2671
- const err16 = { instancePath: instancePath + "/title", schemaPath: "#/definitions/text/type", keyword: "type", params: { type: "string" }, message: "must be string" };
3378
+ const err25 = { instancePath: instancePath + "/title", schemaPath: "#/definitions/text/type", keyword: "type", params: { type: "string" }, message: "must be string" };
2672
3379
  if (vErrors === null) {
2673
- vErrors = [err16];
3380
+ vErrors = [err25];
2674
3381
  } else {
2675
- vErrors.push(err16);
3382
+ vErrors.push(err25);
2676
3383
  }
2677
3384
  errors++;
2678
3385
  }
2679
3386
  }
2680
3387
  if (data.view !== void 0) {
2681
- let data4 = data.view;
2682
- if (!(data4 === "fixed" || data4 === "follow")) {
2683
- const err17 = { instancePath: instancePath + "/view", schemaPath: "#/properties/view/enum", keyword: "enum", params: { allowedValues: schema11.properties.view.enum }, message: "must be equal to one of the allowed values" };
3388
+ let data8 = data.view;
3389
+ if (!(data8 === "fixed" || data8 === "follow")) {
3390
+ const err26 = { instancePath: instancePath + "/view", schemaPath: "#/properties/view/enum", keyword: "enum", params: { allowedValues: schema11.properties.view.enum }, message: "must be equal to one of the allowed values" };
2684
3391
  if (vErrors === null) {
2685
- vErrors = [err17];
3392
+ vErrors = [err26];
2686
3393
  } else {
2687
- vErrors.push(err17);
3394
+ vErrors.push(err26);
2688
3395
  }
2689
3396
  errors++;
2690
3397
  }
2691
3398
  }
2692
3399
  if (data.regions !== void 0) {
2693
- let data5 = data.regions;
2694
- if (Array.isArray(data5)) {
2695
- const len0 = data5.length;
2696
- for (let i0 = 0; i0 < len0; i0++) {
2697
- if (!validate11(data5[i0], { instancePath: instancePath + "/regions/" + i0, parentData: data5, parentDataProperty: i0, rootData })) {
3400
+ let data9 = data.regions;
3401
+ if (Array.isArray(data9)) {
3402
+ const len1 = data9.length;
3403
+ for (let i1 = 0; i1 < len1; i1++) {
3404
+ if (!validate11(data9[i1], { instancePath: instancePath + "/regions/" + i1, parentData: data9, parentDataProperty: i1, rootData })) {
2698
3405
  vErrors = vErrors === null ? validate11.errors : vErrors.concat(validate11.errors);
2699
3406
  errors = vErrors.length;
2700
3407
  }
2701
3408
  }
2702
3409
  } else {
2703
- const err18 = { instancePath: instancePath + "/regions", schemaPath: "#/properties/regions/type", keyword: "type", params: { type: "array" }, message: "must be array" };
3410
+ const err27 = { instancePath: instancePath + "/regions", schemaPath: "#/properties/regions/type", keyword: "type", params: { type: "array" }, message: "must be array" };
2704
3411
  if (vErrors === null) {
2705
- vErrors = [err18];
3412
+ vErrors = [err27];
2706
3413
  } else {
2707
- vErrors.push(err18);
3414
+ vErrors.push(err27);
2708
3415
  }
2709
3416
  errors++;
2710
3417
  }
2711
3418
  }
2712
3419
  if (data.boxes !== void 0) {
2713
- let data7 = data.boxes;
2714
- if (Array.isArray(data7)) {
2715
- if (data7.length < 1) {
2716
- const err19 = { instancePath: instancePath + "/boxes", schemaPath: "#/properties/boxes/minItems", keyword: "minItems", params: { limit: 1 }, message: "must NOT have fewer than 1 items" };
3420
+ let data11 = data.boxes;
3421
+ if (Array.isArray(data11)) {
3422
+ if (data11.length < 1) {
3423
+ const err28 = { instancePath: instancePath + "/boxes", schemaPath: "#/properties/boxes/minItems", keyword: "minItems", params: { limit: 1 }, message: "must NOT have fewer than 1 items" };
2717
3424
  if (vErrors === null) {
2718
- vErrors = [err19];
3425
+ vErrors = [err28];
2719
3426
  } else {
2720
- vErrors.push(err19);
3427
+ vErrors.push(err28);
2721
3428
  }
2722
3429
  errors++;
2723
3430
  }
2724
- const len1 = data7.length;
2725
- for (let i1 = 0; i1 < len1; i1++) {
2726
- if (!validate13(data7[i1], { instancePath: instancePath + "/boxes/" + i1, parentData: data7, parentDataProperty: i1, rootData })) {
3431
+ const len2 = data11.length;
3432
+ for (let i2 = 0; i2 < len2; i2++) {
3433
+ if (!validate13(data11[i2], { instancePath: instancePath + "/boxes/" + i2, parentData: data11, parentDataProperty: i2, rootData })) {
2727
3434
  vErrors = vErrors === null ? validate13.errors : vErrors.concat(validate13.errors);
2728
3435
  errors = vErrors.length;
2729
3436
  }
2730
3437
  }
2731
3438
  } else {
2732
- const err20 = { instancePath: instancePath + "/boxes", schemaPath: "#/properties/boxes/type", keyword: "type", params: { type: "array" }, message: "must be array" };
3439
+ const err29 = { instancePath: instancePath + "/boxes", schemaPath: "#/properties/boxes/type", keyword: "type", params: { type: "array" }, message: "must be array" };
2733
3440
  if (vErrors === null) {
2734
- vErrors = [err20];
3441
+ vErrors = [err29];
2735
3442
  } else {
2736
- vErrors.push(err20);
3443
+ vErrors.push(err29);
2737
3444
  }
2738
3445
  errors++;
2739
3446
  }
@@ -2745,30 +3452,30 @@ function validate10(data, { instancePath = "", parentData, parentDataProperty, r
2745
3452
  }
2746
3453
  }
2747
3454
  if (data.steps !== void 0) {
2748
- let data10 = data.steps;
2749
- if (Array.isArray(data10)) {
2750
- if (data10.length < 1) {
2751
- const err21 = { instancePath: instancePath + "/steps", schemaPath: "#/properties/steps/minItems", keyword: "minItems", params: { limit: 1 }, message: "must NOT have fewer than 1 items" };
3455
+ let data14 = data.steps;
3456
+ if (Array.isArray(data14)) {
3457
+ if (data14.length < 1) {
3458
+ const err30 = { instancePath: instancePath + "/steps", schemaPath: "#/properties/steps/minItems", keyword: "minItems", params: { limit: 1 }, message: "must NOT have fewer than 1 items" };
2752
3459
  if (vErrors === null) {
2753
- vErrors = [err21];
3460
+ vErrors = [err30];
2754
3461
  } else {
2755
- vErrors.push(err21);
3462
+ vErrors.push(err30);
2756
3463
  }
2757
3464
  errors++;
2758
3465
  }
2759
- const len2 = data10.length;
2760
- for (let i2 = 0; i2 < len2; i2++) {
2761
- if (!validate17(data10[i2], { instancePath: instancePath + "/steps/" + i2, parentData: data10, parentDataProperty: i2, rootData })) {
3466
+ const len3 = data14.length;
3467
+ for (let i3 = 0; i3 < len3; i3++) {
3468
+ if (!validate17(data14[i3], { instancePath: instancePath + "/steps/" + i3, parentData: data14, parentDataProperty: i3, rootData })) {
2762
3469
  vErrors = vErrors === null ? validate17.errors : vErrors.concat(validate17.errors);
2763
3470
  errors = vErrors.length;
2764
3471
  }
2765
3472
  }
2766
3473
  } else {
2767
- const err22 = { instancePath: instancePath + "/steps", schemaPath: "#/properties/steps/type", keyword: "type", params: { type: "array" }, message: "must be array" };
3474
+ const err31 = { instancePath: instancePath + "/steps", schemaPath: "#/properties/steps/type", keyword: "type", params: { type: "array" }, message: "must be array" };
2768
3475
  if (vErrors === null) {
2769
- vErrors = [err22];
3476
+ vErrors = [err31];
2770
3477
  } else {
2771
- vErrors.push(err22);
3478
+ vErrors.push(err31);
2772
3479
  }
2773
3480
  errors++;
2774
3481
  }
@@ -2779,12 +3486,18 @@ function validate10(data, { instancePath = "", parentData, parentDataProperty, r
2779
3486
  errors = vErrors.length;
2780
3487
  }
2781
3488
  }
3489
+ if (data.state !== void 0) {
3490
+ if (!validate25(data.state, { instancePath: instancePath + "/state", parentData: data, parentDataProperty: "state", rootData })) {
3491
+ vErrors = vErrors === null ? validate25.errors : vErrors.concat(validate25.errors);
3492
+ errors = vErrors.length;
3493
+ }
3494
+ }
2782
3495
  } else {
2783
- const err23 = { instancePath, schemaPath: "#/type", keyword: "type", params: { type: "object" }, message: "must be object" };
3496
+ const err32 = { instancePath, schemaPath: "#/type", keyword: "type", params: { type: "object" }, message: "must be object" };
2784
3497
  if (vErrors === null) {
2785
- vErrors = [err23];
3498
+ vErrors = [err32];
2786
3499
  } else {
2787
- vErrors.push(err23);
3500
+ vErrors.push(err32);
2788
3501
  }
2789
3502
  errors++;
2790
3503
  }
@@ -2794,10 +3507,15 @@ function validate10(data, { instancePath = "", parentData, parentDataProperty, r
2794
3507
 
2795
3508
  // src/schema.ts
2796
3509
  var EVENT_TYPES = ["edge", "action", "swap", "strip"];
3510
+ var ROOT_NOT_ALLOWED = {
3511
+ "#/else/not": { field: "sequence", kind: "sequence" },
3512
+ "#/then/not": { field: "state", kind: "state" },
3513
+ "#/else/else/not": { field: "state", kind: "state" }
3514
+ };
2797
3515
  var NOT_ALLOWED = {
2798
- "": { field: "sequence", kind: "sequence" },
2799
3516
  carry: { field: "text", kind: "tag" }
2800
3517
  };
3518
+ var RESERVED_ID = /\/boxes\/items\/properties\/id\/not$/u;
2801
3519
  var escape = (key) => key.replaceAll("~", "~0").replaceAll("/", "~1");
2802
3520
  function forbiddenOf(pattern) {
2803
3521
  const inside = /^\^\[\^(.+)\]\+\$$/u.exec(pattern)?.[1];
@@ -2821,7 +3539,8 @@ function toFieldError(error, errors, m) {
2821
3539
  return { pointer: `${at2}/${escape(key)}`, message: m.required(key) };
2822
3540
  }
2823
3541
  case "not": {
2824
- const allowed = NOT_ALLOWED[at2.slice(at2.lastIndexOf("/") + 1)];
3542
+ if (RESERVED_ID.test(error.schemaPath)) return { pointer: at2, message: m.reserved(STATE_ENDS) };
3543
+ const allowed = at2 === "" ? ROOT_NOT_ALLOWED[error.schemaPath] : NOT_ALLOWED[at2.slice(at2.lastIndexOf("/") + 1)];
2825
3544
  return { pointer: allowed ? `${at2}/${allowed.field}` : at2, message: m.not(allowed) };
2826
3545
  }
2827
3546
  case "anyOf": {
@@ -2940,6 +3659,7 @@ function buildTimeline(diagram) {
2940
3659
  const later = named[k + 2];
2941
3660
  if (later) label2.end = Math.min(label2.end, later.start);
2942
3661
  });
3662
+ if (diagram.kind === "state") for (const label2 of named) label2.after = { start: label2.end, end: last };
2943
3663
  labels.push(...named);
2944
3664
  for (const event of p.events) events.push({ step: s, event: event.event, at: span.start + event.at });
2945
3665
  });
@@ -2963,6 +3683,7 @@ function buildTimeline(diagram) {
2963
3683
  });
2964
3684
  }
2965
3685
  carriers.sort((x, y) => x.depart - y.depart);
3686
+ const states = diagram.kind === "state" ? stateTimes(diagram, edges, last) : void 0;
2966
3687
  return {
2967
3688
  total,
2968
3689
  last,
@@ -2972,8 +3693,32 @@ function buildTimeline(diagram) {
2972
3693
  labels,
2973
3694
  badges: steps.map((span, s) => ({ step: s, appears: span.start })),
2974
3695
  events,
2975
- stills: steps.map((span) => span.end - MOTION.still)
3696
+ stills: steps.map((span) => span.end - MOTION.still),
3697
+ ...states ? { states } : {}
3698
+ };
3699
+ }
3700
+ var isEnd2 = (id) => STATE_ENDS.includes(id);
3701
+ function stateTimes(diagram, edges, last) {
3702
+ const times = /* @__PURE__ */ new Map();
3703
+ const of = (box) => {
3704
+ const found = times.get(box) ?? { box, lit: [] };
3705
+ times.set(box, found);
3706
+ return found;
2976
3707
  };
3708
+ let on;
3709
+ for (const edge2 of edges) {
3710
+ const event = diagram.steps[edge2.step]?.events[edge2.event];
3711
+ if (event?.type !== "edge" || event.from === event.to) continue;
3712
+ if (on) {
3713
+ const left = of(on.box);
3714
+ left.lit.push({ start: on.since, end: edge2.start });
3715
+ if (on.box === event.from && left.done === void 0) left.done = edge2.start + MOTION.done;
3716
+ on = void 0;
3717
+ }
3718
+ if (!isEnd2(event.to)) on = { box: event.to, since: edge2.drawn };
3719
+ }
3720
+ if (on) of(on.box).lit.push({ start: on.since, end: last });
3721
+ return [...times.values()];
2977
3722
  }
2978
3723
 
2979
3724
  // src/render/icons.ts
@@ -3008,6 +3753,8 @@ var ICONS = {
3008
3753
  branch: "M -4 -4.5 v9 M 5 0.5 c0 4 -9 3 -9 6.5 M -6.2 -7 a2.2 2.2 0 1 0 4.4 0 a2.2 2.2 0 1 0 -4.4 0 M -6.2 7 a2.2 2.2 0 1 0 4.4 0 a2.2 2.2 0 1 0 -4.4 0 M 2.8 -2 a2.2 2.2 0 1 0 4.4 0 a2.2 2.2 0 1 0 -4.4 0",
3009
3754
  cloud: "M -7 6 h13 a4.5 4.5 0 0 0 0.5 -9 a6 6 0 0 0 -11.5 -1 a4.5 4.5 0 0 0 -2 10 z",
3010
3755
  refresh: "M 7 -3 a7.5 7.5 0 1 0 0.5 5 M 7.5 -8 v5 h-5",
3756
+ undo: "M -7 -2 h10 a5 5 0 0 1 0 10 h-6 M -3 -6 l-4 4 l4 4",
3757
+ yen: "M -6 -8 l6 7 l6 -7 M 0 -1 v9 M -5 1.5 h10 M -5 5 h10",
3011
3758
  layers: "M 0 -8 l9 4.5 l-9 4.5 l-9 -4.5 z M -9 2.5 l9 4.5 l9 -4.5",
3012
3759
  code: "M -4 -6 l-5 6 l5 6 M 4 -6 l5 6 l-5 6",
3013
3760
  paint: "M -8 8 c 0 -3 2 -5 4.5 -5 l 9 -9 l 3.5 3.5 l -9 9 c 0 2.5 -2 4.5 -5 4.5 z",
@@ -3022,7 +3769,25 @@ function glyph(name, x, y, scale, cls = "dg-gl") {
3022
3769
  const d = name === void 0 ? void 0 : ICONS[name];
3023
3770
  return d ? `<path class="${cls}" transform="translate(${r1(x)} ${r1(y)}) scale(${scale})" d="${d}"/>` : "";
3024
3771
  }
3025
- var pathOf = (points) => points.map(([x, y], i) => `${i === 0 ? "M" : "L"} ${r1(x)} ${r1(y)}`).join(" ");
3772
+ function pathOf(points) {
3773
+ const pts = points.filter((p, i) => i === 0 || p[0] !== points[i - 1][0] || p[1] !== points[i - 1][1]);
3774
+ const [x0, y0] = pts[0];
3775
+ let d = `M ${r1(x0)} ${r1(y0)}`;
3776
+ for (let i = 1; i < pts.length - 1; i++) {
3777
+ const [ax, ay] = pts[i - 1];
3778
+ const [bx, by] = pts[i];
3779
+ const [cx, cy] = pts[i + 1];
3780
+ const l1 = Math.hypot(bx - ax, by - ay);
3781
+ const l2 = Math.hypot(cx - bx, cy - by);
3782
+ const a = Math.min(LOOK.edge.bend, l1 / 2, l2 / 2);
3783
+ d += ` L ${r1(bx - (bx - ax) / l1 * a)} ${r1(by - (by - ay) / l1 * a)} Q ${r1(bx)} ${r1(by)} ${r1(bx + (cx - bx) / l2 * a)} ${r1(by + (cy - by) / l2 * a)}`;
3784
+ }
3785
+ if (pts.length > 1) {
3786
+ const [lx, ly] = pts[pts.length - 1];
3787
+ d += ` L ${r1(lx)} ${r1(ly)}`;
3788
+ }
3789
+ return d;
3790
+ }
3026
3791
  function arrowHead(points) {
3027
3792
  const [ex, ey] = points[points.length - 1];
3028
3793
  const [px, py] = points[points.length - 2];
@@ -3069,10 +3834,10 @@ function cardFrame(box, ctx, act, y, h) {
3069
3834
  const rect = (cls, extra = "") => `<rect class="${cls}" x="${r1(box.x)}" y="${r1(y)}" width="${r1(box.w)}" height="${h}" rx="${LOOK.box.radius}"${extra}/>`;
3070
3835
  return `${act ? `<g class="dg-a" style="${act}">${rect("dg-halo")}</g>` : ""}${rect("dg-st", ` ${ctx.sh}`)}${act ? `<g class="dg-a" style="${act}">${rect("dg-on")}</g>` : ""}`;
3071
3836
  }
3072
- function card(box, ctx, on, changes) {
3837
+ function card(box, ctx, on, changes, lit) {
3073
3838
  const { icon, iconRadius, iconScale, iconY, nameY, subY } = LOOK.box;
3074
3839
  const subs = subLines(box, ctx.m, changes, box.cy + subY);
3075
- const act = on.length > 0 ? activeKf(ctx, on) : void 0;
3840
+ const act = lit ? lit.length > 0 ? rangeKf(ctx.m, lit.map((s) => [s.start, s.end])) : void 0 : on.length > 0 ? activeKf(ctx, on) : void 0;
3076
3841
  const mark = box.icon && ICONS[box.icon] ? `<rect class="dg-ic" x="${r1(box.cx - icon / 2)}" y="${r1(box.cy + iconY - icon / 2)}" width="${icon}" height="${icon}" rx="${iconRadius}"/>${glyph(box.icon, box.cx, box.cy + iconY, iconScale)}` : "";
3077
3842
  return `<g style="${cs(box.color)}">${cardFrame(box, ctx, act, box.y, box.h)}${mark}<text class="dg-sn" x="${r1(box.cx)}" y="${r1(box.cy + nameY)}" text-anchor="middle">${esc(box.name)}</text>${subs}</g>`;
3078
3843
  }
@@ -3082,15 +3847,54 @@ function headCard(box, ctx, on, changes) {
3082
3847
  const act = on.length > 0 ? activeKf(ctx, on) : void 0;
3083
3848
  return `<g style="${cs(box.color)}">${cardFrame(box, ctx, act, pad2, h)}<text class="dg-sn" x="${r1(box.cx)}" y="${r1(pad2 + nameY)}" text-anchor="middle">${esc(box.name)}</text>${subs}</g>`;
3084
3849
  }
3850
+ function ghostCard(box) {
3851
+ const { icon, iconRadius, iconScale, radius } = LOOK.box;
3852
+ const G = LOOK.state.ghost;
3853
+ const ix = box.x + G.pad + icon / 2;
3854
+ const tx = box.x + G.pad + icon + G.gap;
3855
+ const mark = box.icon && ICONS[box.icon] ? `<rect class="dg-ic" x="${r1(ix - icon / 2)}" y="${r1(box.cy - icon / 2)}" width="${icon}" height="${icon}" rx="${iconRadius}"/>${glyph(box.icon, ix, box.cy, iconScale)}` : "";
3856
+ const nameY = box.sub ? G.nameY : LOOK.baseline.mark;
3857
+ const sub = box.sub ? `<text class="dg-ss" x="${r1(tx)}" y="${r1(box.cy + G.subY)}" text-anchor="start">${esc(box.sub)}</text>` : "";
3858
+ return `<g data-ghost="${esc(box.id)}" style="${cs(box.color)}"><rect class="dg-ghost" x="${r1(box.x)}" y="${r1(box.y)}" width="${r1(box.w)}" height="${box.h}" rx="${radius}"/>${mark}<text class="dg-sn" x="${r1(tx)}" y="${r1(box.cy + nameY)}" text-anchor="start">${esc(box.name)}</text>${sub}</g>`;
3859
+ }
3860
+ function doneMark(box, at2, ctx) {
3861
+ const { r, inset } = LOOK.state.done;
3862
+ const x = box.x + box.w - inset;
3863
+ const y = box.y + inset;
3864
+ return `<g class="dg-popc dg-a" data-done="${esc(box.id)}" style="${cs(box.color)};${ctx.m.pop(at2)}"><circle class="dg-done" cx="${r1(x)}" cy="${r1(y)}" r="${r}"/>${glyph("check", x, y, 0.5, "dg-done-ck")}</g>`;
3865
+ }
3866
+ function path(p, color) {
3867
+ const label2 = p.label ? `<text class="dg-path-t${p.label.family === "sans" ? " dg-path-tj" : ""}" x="${r1(p.label.x + LOOK.label.padX)}" y="${r1(p.label.y + p.label.h / 2 + LOOK.baseline.label)}">${esc(p.label.text)}</text>` : "";
3868
+ return `<g data-path="${esc(`${p.from}->${p.to}`)}" style="${cs(color)}"><path class="dg-path" d="${pathOf(p.points)}"/><path class="dg-path-h" d="${arrowHead(p.points)}"/>${label2}</g>`;
3869
+ }
3870
+ function side(s, color) {
3871
+ const { pad: pad2 } = LOOK.state.side;
3872
+ const title = s.y + pad2 + TYPE.regionName.size;
3873
+ const notes = s.notes.map((note, k) => `<text class="dg-side-n" x="${r1(s.x + pad2)}" y="${r1(title + LOOK.region.line * (k + 1))}">${esc(note)}</text>`).join("");
3874
+ return `<g style="${cs(color)}"><rect class="dg-side" x="${r1(s.x + 0.5)}" y="${r1(s.y + 0.5)}" width="${r1(s.w - 1)}" height="${r1(s.h - 1)}" rx="${LOOK.region.radius}"/><text class="dg-side-t" x="${r1(s.x + pad2)}" y="${r1(title)}">${esc(s.title)}</text>${notes}</g>`;
3875
+ }
3876
+ function endMark(e, color) {
3877
+ const { end } = LOOK.state;
3878
+ const text2 = e.text === "" ? "" : `<text class="dg-mark" x="${r1(e.x + LOOK.state.text)}" y="${r1(e.y + LOOK.baseline.mark)}">${esc(e.text)}</text>`;
3879
+ const x = r1(e.x);
3880
+ const y = r1(e.y);
3881
+ if (e.kind === "start") return `<g data-end="start"><circle class="dg-start" cx="${x}" cy="${y}" r="${e.r}"/>${text2}</g>`;
3882
+ if (e.ghost) return `<g data-end="finish" style="${cs(color)}"><circle class="dg-end-x" cx="${x}" cy="${y}" r="${e.r}"/><circle class="dg-end-xi" cx="${x}" cy="${y}" r="${end.inner}"/>${text2}</g>`;
3883
+ return `<g data-end="finish"><circle class="dg-end" cx="${x}" cy="${y}" r="${e.r}"/><circle class="dg-end-in" cx="${x}" cy="${y}" r="${end.inner}"/>${text2}</g>`;
3884
+ }
3085
3885
  function lifeline(x, y1, y2) {
3086
3886
  return `<line class="dg-ll" x1="${r1(x)}" y1="${r1(y1)}" x2="${r1(x)}" y2="${r1(y2)}"/>`;
3087
3887
  }
3088
- function edge(e, time, ctx) {
3888
+ function edge(e, time, ctx, past = false) {
3089
3889
  const { m } = ctx;
3090
3890
  const d = pathOf(e.points);
3091
3891
  const head = arrowHead(e.points);
3092
3892
  const { start: a, drawn: b, end } = time;
3093
- const tail = [
3893
+ const tail = past ? [
3894
+ [end, { opacity: 1 }, EASE.inOut],
3895
+ [end + 0.4, { opacity: 0 }],
3896
+ [m.total, { opacity: 0 }]
3897
+ ] : [
3094
3898
  [end, { opacity: 1 }, EASE.inOut],
3095
3899
  [end + 0.4, { opacity: 0.45 }],
3096
3900
  [ctx.end + 0.3, { opacity: 0.45 }, EASE.inOut],
@@ -3117,15 +3921,19 @@ function edge(e, time, ctx) {
3117
3921
  [end + 0.2, { opacity: 0, "stroke-dashoffset": run }],
3118
3922
  [m.total, { opacity: 0, "stroke-dashoffset": run }]
3119
3923
  ]);
3924
+ const grey = past ? m.kf([[0, { opacity: 0 }], [end, { opacity: 0 }, EASE.inOut], [end + 0.4, { opacity: 1 }], [m.last, { opacity: 1 }, EASE.inOut], [m.total, { opacity: 0 }]]) : "";
3120
3925
  return {
3121
- base: `<path class="dg-e" d="${d}"/><path class="dg-eh" d="${head}"/>`,
3926
+ base: `<path class="dg-e" d="${d}"/><path class="dg-eh" d="${head}"/>${past ? `<path class="dg-e-past dg-a" d="${d}" style="${grey}"/><path class="dg-eh-past dg-a" d="${head}" style="${grey}"/>` : ""}`,
3122
3927
  lit: `<g style="${cs(e.color)}"><path class="dg-e-on dg-a" pathLength="1" d="${d}" style="${line}"/><path class="dg-eh-on dg-a" d="${head}" style="${hk}"/><path class="dg-flow dg-a" d="${d}" style="${flow}"/></g>`
3123
3928
  };
3124
3929
  }
3125
3930
  function label(l, time, ctx) {
3126
3931
  const ja2 = l.family === "sans" ? " dg-capj" : "";
3127
3932
  const { radius } = LOOK.label;
3128
- return `<g class="dg-cap${ja2} dg-a" style="${cs(l.color)};${ctx.m.rise(time.start, time.end, true)}"><rect x="${r1(l.x)}" y="${r1(l.y)}" width="${r1(l.w)}" height="${l.h}" rx="${radius}"/><text x="${r1(l.x + l.w / 2)}" y="${r1(l.y + l.h / 2 + LOOK.baseline.label)}" text-anchor="middle">${esc(l.text)}</text></g>`;
3933
+ const x = r1(l.x + l.w / 2);
3934
+ const y = r1(l.y + l.h / 2 + LOOK.baseline.label);
3935
+ const past = time.after ? `<g class="dg-cap-past${l.family === "sans" ? " dg-cap-pastj" : ""} dg-a" style="${ctx.m.vis(time.after.start, time.after.end)}"><text x="${x}" y="${y}" text-anchor="middle">${esc(l.text)}</text></g>` : "";
3936
+ return `${past}<g class="dg-cap${ja2} dg-a" style="${cs(l.color)};${ctx.m.rise(time.start, time.end, true)}"><rect x="${r1(l.x)}" y="${r1(l.y)}" width="${r1(l.w)}" height="${l.h}" rx="${radius}"/><text x="${x}" y="${y}" text-anchor="middle">${esc(l.text)}</text></g>`;
3129
3937
  }
3130
3938
  function action(a, at2, until, ctx) {
3131
3939
  return `<g class="dg-act dg-a" style="${cs(a.color)};${ctx.m.rise(at2, until, true)}"><rect x="${r1(a.x)}" y="${r1(a.y)}" width="${r1(a.w)}" height="${a.h}" rx="${LOOK.action.radius}"/><text x="${r1(a.x + a.w / 2)}" y="${r1(a.y + a.h / 2 + LOOK.baseline.action)}" text-anchor="middle">${esc(a.text)}</text></g>`;
@@ -3147,21 +3955,21 @@ function carrier(e, time, ctx) {
3147
3955
  const n = LOOK.carrier.samples;
3148
3956
  const length = pathLength(e.points);
3149
3957
  const { depart: a, arrive: b, start: from, end: gone } = time;
3150
- const path = [];
3958
+ const path2 = [];
3151
3959
  for (let k = 0; k <= n; k++) {
3152
3960
  const [x, y] = along(e.points, easeInOut(k / n) * length);
3153
- path.push([a + (b - a) * k / n, x, y]);
3961
+ path2.push([a + (b - a) * k / n, x, y]);
3154
3962
  }
3155
- const first = path[0];
3156
- const lastPoint = path[path.length - 1];
3963
+ const first = path2[0];
3964
+ const lastPoint = path2[path2.length - 1];
3157
3965
  const rest = e.settle ?? [lastPoint[1], lastPoint[2]];
3158
- const pts = [[0, first[1], first[2]], ...path];
3966
+ const pts = [[0, first[1], first[2]], ...path2];
3159
3967
  if (e.settle) pts.push([Math.min(b + 0.3, Math.max(gone, b + 0.01)), rest[0], rest[1]]);
3160
3968
  pts.push([gone, rest[0], rest[1]], [m.total, rest[0], rest[1]]);
3161
3969
  const fade = gone < m.last ? 0.05 : 0.18;
3162
3970
  return `<g class="dg-a" style="${m.move(pts, m.blink(from + 0.02, gone, fade))}">${carrierShape(e, ctx.sh)}</g>`;
3163
3971
  }
3164
- function badge(b, ctx) {
3972
+ function badge(b, ctx, grey = false) {
3165
3973
  const { m } = ctx;
3166
3974
  const span = ctx.t.steps[b.step];
3167
3975
  const a = span.start;
@@ -3187,9 +3995,9 @@ function badge(b, ctx) {
3187
3995
  const y = r1(b.y);
3188
3996
  const ty = r1(b.y + LOOK.baseline.badge);
3189
3997
  const no = b.step + 1;
3190
- return `<g class="dg-bd" data-step="${b.step}" style="${cs(b.color)}"><circle class="dg-bdr dg-popc dg-a" cx="${x}" cy="${y}" r="${rr}" style="${ring}"/><g class="dg-a" style="${past}"><circle class="dg-bdp" cx="${x}" cy="${y}" r="${rr}"/><text class="dg-bdpt" x="${x}" y="${ty}" text-anchor="middle">${no}</text></g><g class="dg-popc dg-a" style="${fill}"><circle class="dg-bdf" cx="${x}" cy="${y}" r="${r}"/><text class="dg-bdft" x="${x}" y="${ty}" text-anchor="middle">${no}</text></g></g>`;
3998
+ return `<g class="dg-bd" data-step="${b.step}" style="${cs(b.color)}"><circle class="dg-bdr dg-popc dg-a" cx="${x}" cy="${y}" r="${rr}" style="${ring}"/><g class="dg-a" style="${past}"><circle class="${grey ? "dg-bdp-g" : "dg-bdp"}" cx="${x}" cy="${y}" r="${rr}"/><text class="${grey ? "dg-bdpt-g" : "dg-bdpt"}" x="${x}" y="${ty}" text-anchor="middle">${no}</text></g><g class="dg-popc dg-a" style="${fill}"><circle class="dg-bdf" cx="${x}" cy="${y}" r="${r}"/><text class="dg-bdft" x="${x}" y="${ty}" text-anchor="middle">${no}</text></g></g>`;
3191
3999
  }
3192
- function strip(s, changes, ctx) {
4000
+ function strip(s, changes, ctx, now = false, arrivals = /* @__PURE__ */ new Map()) {
3193
4001
  const { m, sh } = ctx;
3194
4002
  const S2 = LOOK.strip;
3195
4003
  const my = s.y + S2.h / 2;
@@ -3211,8 +4019,18 @@ function strip(s, changes, ctx) {
3211
4019
  values.forEach((c, k) => {
3212
4020
  const next = values[k + 1]?.at;
3213
4021
  const value = c.value;
3214
- const anim = next === void 0 ? m.rise(c.at) : m.rise(c.at, next - MOTION.untilFade);
3215
- parts.push(`<g class="dg-a" style="${anim}"><text class="${hasWide(value) ? "dg-fvj" : "dg-fv"}" x="${r1(field.x)}" y="${r1(field.y + S2.valueY)}">${esc(value)}</text></g>`);
4022
+ const cls = hasWide(value) ? "dg-fvj" : "dg-fv";
4023
+ const textOf = (c2) => `<text class="${c2}" x="${r1(field.x)}" y="${r1(field.y + S2.valueY)}">${esc(value)}</text>`;
4024
+ const text2 = textOf(cls);
4025
+ if (!now) {
4026
+ const anim = next === void 0 ? m.rise(c.at) : m.rise(c.at, next - MOTION.untilFade);
4027
+ parts.push(`<g class="dg-a" style="${anim}">${text2}</g>`);
4028
+ return;
4029
+ }
4030
+ const until = Math.min(c.until, next ?? c.until);
4031
+ const dot = `<circle class="dg-fl-now" cx="${r1(field.x + textWidth(field.name, TYPE.fieldName) + S2.now.gap)}" cy="${r1(field.y + S2.nameY - TYPE.fieldName.size / 3)}" r="${S2.now.r}"/>`;
4032
+ parts.push(`<g class="dg-fv-now dg-a" data-step="${c.step}" style="${cs(c.color)};${m.rise(c.at, until - MOTION.untilFade)}">${textOf(`${cls} dg-fv-c`)}${dot}</g>`);
4033
+ if (next === void 0 || next > until) parts.push(`<g class="dg-a" style="${m.vis(until - MOTION.untilFade, next === void 0 ? m.last : next - MOTION.untilFade)}">${text2}</g>`);
3216
4034
  });
3217
4035
  tags.forEach((c, k) => {
3218
4036
  const next = tags[k + 1]?.at;
@@ -3226,6 +4044,22 @@ function strip(s, changes, ctx) {
3226
4044
  );
3227
4045
  });
3228
4046
  });
4047
+ if (s.trail) {
4048
+ const t = s.trail;
4049
+ const last = s.fields[s.fields.length - 1];
4050
+ if (last && last.y === t.y) {
4051
+ const sx = t.x - S2.fieldGap / 2;
4052
+ parts.push(`<line class="dg-sep" x1="${r1(sx)}" y1="${r1(t.y + S2.sepInset)}" x2="${r1(sx)}" y2="${r1(t.y + S2.h - S2.sepInset)}"/>`);
4053
+ }
4054
+ parts.push(`<text class="dg-fl" x="${r1(t.x)}" y="${r1(t.y + S2.nameY)}">${esc(t.title)}</text>`);
4055
+ const dy = t.y + S2.valueY - TYPE.fieldValue.size / 3;
4056
+ t.states.forEach((state, k) => {
4057
+ const cx = r1(t.x + S2.trail.r + k * S2.trail.step);
4058
+ const at2 = arrivals.get(state.box);
4059
+ const fill = at2 === void 0 ? "" : `<circle class="dg-tr-fill dg-a" cx="${cx}" cy="${r1(dy)}" r="${S2.trail.r}" style="${m.pop(at2)}"/>`;
4060
+ parts.push(`<g data-trail="${esc(state.box)}" style="${cs(state.color)}"><circle class="dg-tr-ring" cx="${cx}" cy="${r1(dy)}" r="${S2.trail.r}"/>${fill}</g>`);
4061
+ });
4062
+ }
3229
4063
  return parts.join("");
3230
4064
  }
3231
4065
 
@@ -3322,6 +4156,7 @@ var font = (t) => `font:${t.weight} ${t.size}px var(--${t.family})`;
3322
4156
  var mix = (pct, base = "var(--surf)") => `color-mix(in srgb,var(--c) ${pct}%,${base})`;
3323
4157
  var S = LOOK.stroke;
3324
4158
  var X = LOOK.mix;
4159
+ var PAST = `color-mix(in srgb,var(--mute) ${X.past}%,var(--bg))`;
3325
4160
  var PART_CSS = [
3326
4161
  ".dg{display:block;width:100%;height:auto;overflow:visible}",
3327
4162
  ".dg .dg-a{animation-duration:var(--T);animation-timing-function:linear;animation-iteration-count:infinite;animation-fill-mode:both;animation-delay:calc(var(--at,0) * -1s);animation-play-state:var(--play,running)}",
@@ -3346,15 +4181,21 @@ var PART_CSS = [
3346
4181
  `.dg-e-on{fill:none;stroke:var(--c);stroke-width:${S.edgeOn};stroke-linecap:round;stroke-dasharray:1 2}`,
3347
4182
  `.dg-eh-on{fill:none;stroke:var(--c);stroke-width:${S.edgeOn};stroke-linecap:round;stroke-linejoin:round}`,
3348
4183
  `.dg-flow{fill:none;stroke:var(--surf);stroke-width:${S.flow};stroke-linecap:round;stroke-dasharray:1.5 ${LOOK.edge.flowDash}}`,
4184
+ `.dg-e-past{fill:none;stroke:${PAST};stroke-width:${S.edge};stroke-linecap:round}`,
4185
+ `.dg-eh-past{fill:none;stroke:${PAST};stroke-width:${S.arrow};stroke-linecap:round;stroke-linejoin:round}`,
3349
4186
  ".dg-bd{cursor:pointer}",
3350
4187
  ".dg-bdf{fill:var(--c)}",
3351
4188
  `.dg-bdft{${font(TYPE.badge)};fill:var(--on-c)}`,
3352
4189
  `.dg-bdr{fill:none;stroke:var(--c);stroke-width:${S.badgeRing}}`,
3353
4190
  `.dg-bdp{fill:${mix(X.badgePast)};stroke:${mix(X.badgePastEdge, "transparent")};stroke-width:${S.hair}}`,
3354
4191
  `.dg-bdpt{${font(TYPE.badge)};fill:var(--ct)}`,
4192
+ `.dg-bdp-g{fill:var(--surf);stroke:${PAST};stroke-width:${S.hair}}`,
4193
+ `.dg-bdpt-g{${font(TYPE.badge)};fill:var(--mute)}`,
3355
4194
  `.dg-cap rect,.dg-act rect{fill:${mix(X.cap)};stroke:${mix(X.capEdge, "transparent")}}`,
3356
4195
  `.dg-cap text{${font(TYPE.label)};fill:var(--ct)}`,
3357
4196
  `.dg-capj text{${font(TYPE.labelJa)}}`,
4197
+ `.dg-cap-past text{${font(TYPE.label)};fill:var(--mute);fill-opacity:${LOOK.state.pastLabel}}`,
4198
+ `.dg-cap-pastj text{${font(TYPE.labelJa)}}`,
3358
4199
  `.dg-act text{${font(TYPE.action)};fill:var(--ct)}`,
3359
4200
  ".dg-car{fill:var(--carry,var(--ink))}",
3360
4201
  `.dg-car-t{${font(TYPE.carrier)};fill:var(--bg)}`,
@@ -3369,8 +4210,28 @@ var PART_CSS = [
3369
4210
  `.dg-fl{${font(TYPE.fieldName)};fill:var(--mute)}`,
3370
4211
  `.dg-fv{${font(TYPE.fieldValue)};fill:var(--ink)}`,
3371
4212
  `.dg-fvj{${font(TYPE.fieldValueJa)};fill:var(--ink)}`,
4213
+ ".dg-fv-c{fill:var(--ct)}",
4214
+ ".dg-fl-now{fill:var(--c)}",
4215
+ `.dg-tr-ring{fill:none;stroke:var(--line);stroke-width:${S.trail}}`,
4216
+ ".dg-tr-fill{fill:var(--c)}",
3372
4217
  ".dg-tg rect{fill:var(--c)}",
3373
4218
  `.dg-tg text{${font(TYPE.tag)};fill:var(--on-c)}`,
4219
+ `.dg-side{fill:color-mix(in srgb,var(--c) ${X.side}%,var(--bg));stroke:${mix(X.sideEdge, "transparent")};stroke-dasharray:4 4}`,
4220
+ `.dg-side-t{${font(TYPE.regionName)};fill:var(--ct)}`,
4221
+ `.dg-side-n{${font(TYPE.regionNote)};fill:var(--mute)}`,
4222
+ `.dg-ghost{fill:var(--surf);stroke:${mix(X.ghostEdge, "transparent")};stroke-dasharray:4 3}`,
4223
+ `.dg-path{fill:none;stroke:${mix(X.path, "transparent")};stroke-width:${S.path};stroke-linecap:round;stroke-dasharray:0 ${LOOK.edge.ghostDash}}`,
4224
+ `.dg-path-h{fill:none;stroke:${mix(X.path, "transparent")};stroke-width:${S.arrow};stroke-linecap:round;stroke-linejoin:round}`,
4225
+ `.dg-path-t{${font(TYPE.label)};fill:var(--ct)}`,
4226
+ `.dg-path-tj{${font(TYPE.labelJa)}}`,
4227
+ ".dg-start{fill:var(--ink)}",
4228
+ `.dg-end{fill:var(--bg);stroke:var(--ink);stroke-width:${S.end}}`,
4229
+ ".dg-end-in{fill:var(--ink)}",
4230
+ `.dg-end-x{fill:var(--bg);stroke:${mix(X.path, "transparent")};stroke-width:${S.arrow};stroke-dasharray:2 2.5}`,
4231
+ `.dg-end-xi{fill:${mix(X.path, "transparent")}}`,
4232
+ `.dg-mark{${font(TYPE.regionNote)};fill:var(--mute)}`,
4233
+ `.dg-done{fill:var(--ink);stroke:var(--surf);stroke-width:${S.done}}`,
4234
+ `.dg-done-ck{fill:none;stroke:var(--surf);stroke-width:${S.glyph};stroke-linecap:round;stroke-linejoin:round}`,
3374
4235
  ".dg-vp-bg{fill:var(--bg)}",
3375
4236
  ".dg-vp-frame{fill:none;stroke:var(--hair)}",
3376
4237
  ".dg-hd-bg{fill:var(--bg)}",
@@ -3448,7 +4309,8 @@ function fieldChanges(diagram, timeline, layout) {
3448
4309
  if (event?.type !== "strip") continue;
3449
4310
  const color = layout.badges[time.step]?.color ?? "slate";
3450
4311
  const list = out.get(event.field) ?? [];
3451
- list.push({ at: time.at, color, ...event.value !== void 0 ? { value: event.value } : {}, ...event.tag !== void 0 ? { tag: event.tag } : {} });
4312
+ const until = timeline.steps[time.step].end;
4313
+ list.push({ at: time.at, color, step: time.step, until, ...event.value !== void 0 ? { value: event.value } : {}, ...event.tag !== void 0 ? { tag: event.tag } : {} });
3452
4314
  out.set(event.field, list);
3453
4315
  }
3454
4316
  return out;
@@ -3458,20 +4320,36 @@ function drawSvg(diagram, layout, timeline, palette, theme, follow) {
3458
4320
  const m = new Motion(`dg${id}`, timeline.total, timeline.last);
3459
4321
  const ctx = { m, t: timeline, sh: `filter="url(#dg-sh-${id})"`, end: timeline.steps[timeline.steps.length - 1].end };
3460
4322
  const on = involved(diagram);
3461
- const subs = subChanges(diagram, timeline, layout.kind === "architecture");
4323
+ const subs = subChanges(diagram, timeline, layout.kind !== "sequence");
3462
4324
  const L = { band: [], base: [], lit: [], node: [], badge: [], top: [] };
3463
4325
  for (const region of layout.regions) L.band.push(band(region));
3464
- if (layout.strip) L.band.push(strip(layout.strip, fieldChanges(diagram, timeline, layout), ctx));
4326
+ const ghostColor = layout.boxes.find((b) => b.ghost)?.color ?? "slate";
4327
+ if (layout.side) L.band.push(side(layout.side, ghostColor));
4328
+ const boxColor = (id2, ghost) => layout.boxes.find((b) => b.id === id2 && (ghost === void 0 || b.ghost === ghost))?.color;
4329
+ for (const p of layout.paths) L.base.push(path(p, boxColor(p.to, true) ?? boxColor(p.from) ?? ghostColor));
4330
+ for (const e of layout.ends) L.node.push(endMark(e, ghostColor));
4331
+ const isState = layout.kind === "state";
4332
+ const arrivals = new Map((timeline.states ?? []).flatMap((s) => s.lit[0] ? [[s.box, s.lit[0].start]] : []));
4333
+ if (layout.strip) L.band.push(strip(layout.strip, fieldChanges(diagram, timeline, layout), ctx, isState, arrivals));
3465
4334
  for (const line of layout.lifelines) L.base.push(lifeline(line.x, line.y1, line.y2));
3466
4335
  for (const e of layout.edges) {
3467
4336
  const time = timeline.edges.find((t) => t.step === e.step && t.event === e.event);
3468
4337
  if (!time) continue;
3469
- const drawn = edge(e, time, ctx);
4338
+ const drawn = edge(e, time, ctx, isState);
3470
4339
  L.base.push(drawn.base);
3471
4340
  L.lit.push(drawn.lit);
3472
4341
  }
3473
- for (const box of layout.boxes) L.node.push(card(box, ctx, on.get(box.id) ?? [], subs.get(box.id) ?? []));
3474
- for (const b of layout.badges) L.badge.push(badge(b, ctx));
4342
+ const states = new Map((timeline.states ?? []).map((s) => [s.box, s]));
4343
+ for (const box of layout.boxes) {
4344
+ if (box.ghost) {
4345
+ L.node.push(ghostCard(box));
4346
+ continue;
4347
+ }
4348
+ const state = states.get(box.id);
4349
+ L.node.push(card(box, ctx, on.get(box.id) ?? [], subs.get(box.id) ?? [], isState ? state?.lit ?? [] : void 0));
4350
+ if (state?.done !== void 0) L.node.push(doneMark(box, state.done, ctx));
4351
+ }
4352
+ for (const b of layout.badges) L.badge.push(badge(b, ctx, isState));
3475
4353
  for (const l of layout.labels) {
3476
4354
  const time = timeline.labels.find((t) => t.step === l.step && t.event === l.event);
3477
4355
  if (time) L.top.push(label(l, time, ctx));
@@ -3607,7 +4485,7 @@ function renderDiagram(input, options = {}) {
3607
4485
  const diagram = read.diagram;
3608
4486
  const palette = resolvePalette(options.palette);
3609
4487
  const theme = options.theme === "dark" ? "dark" : "light";
3610
- const layout = diagram.kind === "sequence" ? layoutSequence(diagram) : layoutArchitecture(diagram);
4488
+ const layout = diagram.kind === "sequence" ? layoutSequence(diagram) : diagram.kind === "state" ? layoutState(diagram, lang) : layoutArchitecture(diagram);
3611
4489
  const timeline = buildTimeline(diagram);
3612
4490
  return {
3613
4491
  svg: drawSvg(diagram, layout, timeline, palette, theme),
@@ -3678,9 +4556,9 @@ async function stage(browser, svg, fontCss, body) {
3678
4556
  const paused = svg.replace(/^<svg\b/, '<svg style="--play:paused;--at:0"');
3679
4557
  const html = `<!doctype html><html><head><meta charset="utf-8"><style>${fontCss}html,body{margin:0}body{${body}}svg{display:block}</style><script type="module">import * as mb from "/mediabunny.js";import * as gif from "/gifenc.js";window.__tools={mb,gif};</script></head><body>${paused}</body></html>`;
3680
4558
  await page.route("http://localhost/**", async (route) => {
3681
- const path = new URL(route.request().url()).pathname;
3682
- if (path === "/") return route.fulfill({ contentType: "text/html; charset=utf-8", body: html });
3683
- const script = SCRIPTS[path];
4559
+ const path2 = new URL(route.request().url()).pathname;
4560
+ if (path2 === "/") return route.fulfill({ contentType: "text/html; charset=utf-8", body: html });
4561
+ const script = SCRIPTS[path2];
3684
4562
  return script ? route.fulfill({ contentType: "text/javascript", body: readFileSync(script) }) : route.fulfill({ status: 404 });
3685
4563
  });
3686
4564
  await page.goto("http://localhost/");
@@ -3958,9 +4836,9 @@ function writeOutputs(outDir, name, outputs) {
3958
4836
  const files = {};
3959
4837
  try {
3960
4838
  for (const [format, data] of outputs) {
3961
- const path = join(outDir, `${name}.${format}`);
3962
- writeFileSync(path, data);
3963
- files[format] = path;
4839
+ const path2 = join(outDir, `${name}.${format}`);
4840
+ writeFileSync(path2, data);
4841
+ files[format] = path2;
3964
4842
  }
3965
4843
  } catch (error) {
3966
4844
  if (created !== void 0) rmSync(created, { recursive: true, force: true });