@misoto22/design 0.6.0 → 0.7.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.
Files changed (157) hide show
  1. package/README.md +12 -0
  2. package/dist/agent/Accordion.md +1 -1
  3. package/dist/agent/Alert.md +1 -1
  4. package/dist/agent/AppShell.md +1 -1
  5. package/dist/agent/ArchitectureFigure.md +48 -0
  6. package/dist/agent/AreaChart.md +2 -2
  7. package/dist/agent/Article.md +1 -1
  8. package/dist/agent/Avatar.md +1 -1
  9. package/dist/agent/Badge.md +1 -1
  10. package/dist/agent/BarChart.md +2 -2
  11. package/dist/agent/BarList.md +2 -2
  12. package/dist/agent/BigNumber.md +2 -2
  13. package/dist/agent/BoxPlot.md +2 -2
  14. package/dist/agent/Breadcrumb.md +1 -1
  15. package/dist/agent/BulletChart.md +2 -2
  16. package/dist/agent/Button.md +1 -1
  17. package/dist/agent/Calendar.md +1 -1
  18. package/dist/agent/Card.md +1 -1
  19. package/dist/agent/Checkbox.md +1 -1
  20. package/dist/agent/Collapsible.md +1 -1
  21. package/dist/agent/Combobox.md +1 -1
  22. package/dist/agent/Command.md +1 -1
  23. package/dist/agent/ComposedChart.md +2 -2
  24. package/dist/agent/ContextMenu.md +1 -1
  25. package/dist/agent/DataflowFigure.md +27 -0
  26. package/dist/agent/DatePicker.md +1 -1
  27. package/dist/agent/Diagram.md +1 -1
  28. package/dist/agent/DiagramCanvas.md +47 -0
  29. package/dist/agent/DiagramExportMenu.md +38 -0
  30. package/dist/agent/DiagramInspector.md +50 -0
  31. package/dist/agent/DiagramLegend.md +34 -0
  32. package/dist/agent/DiagramMinimap.md +48 -0
  33. package/dist/agent/DiagramToolbar.md +47 -0
  34. package/dist/agent/Dialog.md +1 -1
  35. package/dist/agent/DropdownMenu.md +1 -1
  36. package/dist/agent/EmptyState.md +1 -1
  37. package/dist/agent/ErrorState.md +1 -1
  38. package/dist/agent/Facet.md +2 -2
  39. package/dist/agent/Field.md +1 -1
  40. package/dist/agent/FigureBand.md +1 -1
  41. package/dist/agent/FloatingIconButton.md +1 -1
  42. package/dist/agent/FunnelChart.md +2 -2
  43. package/dist/agent/Heatmap.md +2 -2
  44. package/dist/agent/Histogram.md +2 -2
  45. package/dist/agent/Input.md +1 -1
  46. package/dist/agent/Kbd.md +1 -1
  47. package/dist/agent/LifecycleFigure.md +28 -0
  48. package/dist/agent/LineChart.md +2 -2
  49. package/dist/agent/LinkArrow.md +1 -1
  50. package/dist/agent/NativeSelect.md +1 -1
  51. package/dist/agent/NavItem.md +1 -1
  52. package/dist/agent/Pagination.md +1 -1
  53. package/dist/agent/PieChart.md +2 -2
  54. package/dist/agent/Popover.md +1 -1
  55. package/dist/agent/Progress.md +1 -1
  56. package/dist/agent/RadarChart.md +2 -2
  57. package/dist/agent/RadialChart.md +2 -2
  58. package/dist/agent/RadioGroup.md +1 -1
  59. package/dist/agent/SankeyChart.md +2 -2
  60. package/dist/agent/ScatterChart.md +2 -2
  61. package/dist/agent/ScrollArea.md +1 -1
  62. package/dist/agent/SearchableMenu.md +1 -1
  63. package/dist/agent/Select.md +1 -1
  64. package/dist/agent/Separator.md +1 -1
  65. package/dist/agent/SequenceFigure.md +28 -0
  66. package/dist/agent/Sheet.md +1 -1
  67. package/dist/agent/Skeleton.md +1 -1
  68. package/dist/agent/Slider.md +1 -1
  69. package/dist/agent/Sparkline.md +2 -2
  70. package/dist/agent/Spinner.md +1 -1
  71. package/dist/agent/StatusDot.md +1 -1
  72. package/dist/agent/StatusPill.md +1 -1
  73. package/dist/agent/Steps.md +1 -1
  74. package/dist/agent/Switch.md +1 -1
  75. package/dist/agent/Table.md +1 -1
  76. package/dist/agent/Tabs.md +1 -1
  77. package/dist/agent/Tag.md +1 -1
  78. package/dist/agent/Textarea.md +1 -1
  79. package/dist/agent/Toast.md +1 -1
  80. package/dist/agent/ToggleGroup.md +1 -1
  81. package/dist/agent/Tooltip.md +1 -1
  82. package/dist/agent/TreemapChart.md +2 -2
  83. package/dist/agent/WaterfallChart.md +2 -2
  84. package/dist/agent/WorkflowFigure.md +28 -0
  85. package/dist/agent/catalog.json +295 -3
  86. package/dist/agent/index.md +15 -1
  87. package/dist/charts/index.d.ts +2 -1
  88. package/dist/charts/lib/export.d.ts +33 -43
  89. package/dist/charts/lib/export.js +16 -158
  90. package/dist/charts/lib/export.js.map +1 -1
  91. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +49 -0
  92. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +135 -0
  93. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -0
  94. package/dist/diagrams/DataflowFigure/DataflowFigure.d.ts +28 -0
  95. package/dist/diagrams/DataflowFigure/DataflowFigure.js +129 -0
  96. package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -0
  97. package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +64 -0
  98. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +222 -0
  99. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -0
  100. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +72 -0
  101. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +125 -0
  102. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -0
  103. package/dist/diagrams/DiagramInspector/DiagramInspector.d.ts +70 -0
  104. package/dist/diagrams/DiagramInspector/DiagramInspector.js +94 -0
  105. package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -0
  106. package/dist/diagrams/DiagramLegend/DiagramLegend.d.ts +42 -0
  107. package/dist/diagrams/DiagramLegend/DiagramLegend.js +35 -0
  108. package/dist/diagrams/DiagramLegend/DiagramLegend.js.map +1 -0
  109. package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +61 -0
  110. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +79 -0
  111. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -0
  112. package/dist/diagrams/DiagramToolbar/DiagramToolbar.d.ts +48 -0
  113. package/dist/diagrams/DiagramToolbar/DiagramToolbar.js +53 -0
  114. package/dist/diagrams/DiagramToolbar/DiagramToolbar.js.map +1 -0
  115. package/dist/diagrams/LifecycleFigure/LifecycleFigure.d.ts +31 -0
  116. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +202 -0
  117. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -0
  118. package/dist/diagrams/SequenceFigure/SequenceFigure.d.ts +38 -0
  119. package/dist/diagrams/SequenceFigure/SequenceFigure.js +231 -0
  120. package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -0
  121. package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +34 -0
  122. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +211 -0
  123. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -0
  124. package/dist/diagrams/index.d.ts +16 -0
  125. package/dist/diagrams/index.js +19 -0
  126. package/dist/diagrams/index.js.map +1 -0
  127. package/dist/diagrams/lib/frame.d.ts +97 -0
  128. package/dist/diagrams/lib/frame.js +116 -0
  129. package/dist/diagrams/lib/frame.js.map +1 -0
  130. package/dist/diagrams/lib/geometry.d.ts +114 -0
  131. package/dist/diagrams/lib/geometry.js +113 -0
  132. package/dist/diagrams/lib/geometry.js.map +1 -0
  133. package/dist/diagrams/lib/legend.d.ts +32 -0
  134. package/dist/diagrams/lib/legend.js +84 -0
  135. package/dist/diagrams/lib/legend.js.map +1 -0
  136. package/dist/diagrams/lib/marks.d.ts +207 -0
  137. package/dist/diagrams/lib/marks.js +480 -0
  138. package/dist/diagrams/lib/marks.js.map +1 -0
  139. package/dist/diagrams/lib/route.d.ts +85 -0
  140. package/dist/diagrams/lib/route.js +178 -0
  141. package/dist/diagrams/lib/route.js.map +1 -0
  142. package/dist/diagrams/lib/wires.d.ts +59 -0
  143. package/dist/diagrams/lib/wires.js +90 -0
  144. package/dist/diagrams/lib/wires.js.map +1 -0
  145. package/dist/diagrams/spec.d.ts +353 -0
  146. package/dist/diagrams/spec.js +1 -0
  147. package/dist/diagrams/spec.js.map +1 -0
  148. package/dist/lib/svg-export.d.ts +138 -0
  149. package/dist/lib/svg-export.js +198 -0
  150. package/dist/lib/svg-export.js.map +1 -0
  151. package/dist/semantic.css +34 -0
  152. package/dist/styles.css +1 -1
  153. package/dist/tokens.d.ts +16 -0
  154. package/dist/tokens.js +82 -0
  155. package/dist/tokens.json +82 -0
  156. package/package.json +5 -1
  157. package/skills/misoto22-design/SKILL.md +58 -6
@@ -0,0 +1,53 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { cn } from "../../lib/cn.js";
4
+ function DiagramToolbar({
5
+ children,
6
+ className,
7
+ placement = "inline",
8
+ align = "end",
9
+ label,
10
+ ...rest
11
+ }) {
12
+ return /* @__PURE__ */ jsx(
13
+ "div",
14
+ {
15
+ role: "toolbar",
16
+ "aria-label": label,
17
+ "aria-orientation": "horizontal",
18
+ className: cn(
19
+ "flex items-center gap-1 rounded-(--radius) border border-(--rule-2) bg-(--panel-bg) p-1",
20
+ placement === "floating" && "absolute top-3 z-(--z-sticky)",
21
+ placement === "floating" && (align === "end" ? "end-3" : "start-3"),
22
+ className
23
+ ),
24
+ ...rest,
25
+ children
26
+ }
27
+ );
28
+ }
29
+ function DiagramToolbarGroup({
30
+ children,
31
+ className,
32
+ ...rest
33
+ }) {
34
+ return /* @__PURE__ */ jsx(
35
+ "div",
36
+ {
37
+ className: cn(
38
+ "flex items-center gap-0.5",
39
+ "border-s border-(--rule) ps-1 first:border-s-0 first:ps-0",
40
+ className
41
+ ),
42
+ ...rest,
43
+ children
44
+ }
45
+ );
46
+ }
47
+ var DiagramToolbar_default = DiagramToolbar;
48
+ export {
49
+ DiagramToolbar,
50
+ DiagramToolbarGroup,
51
+ DiagramToolbar_default as default
52
+ };
53
+ //# sourceMappingURL=DiagramToolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/diagrams/DiagramToolbar/DiagramToolbar.tsx"],"sourcesContent":["'use client'\n\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface DiagramToolbarProps extends Omit<ComponentProps<'div'>, 'children'> {\n children: ReactNode\n /** Where it sits. `floating` pins it over the surface it acts on. */\n placement?: 'inline' | 'floating'\n /** Which corner a floating bar pins to. */\n align?: 'start' | 'end'\n label: string\n}\n\n/**\n * A bar of actions that belong to the surface underneath them.\n *\n * The package already has `FloatingIconButton` for ONE pinned action. This is\n * the container for several — which is a different problem, because several\n * pinned buttons need to read as one object rather than as a scatter: one\n * plate, one border, hairlines between the groups, and a single `role=\"toolbar\"`\n * so a screen reader announces a toolbar instead of six unrelated buttons.\n *\n * `role=\"toolbar\"` also changes the keyboard contract, and callers should know\n * what they are opting into: arrow keys are expected to move between the\n * controls and Tab is expected to leave the bar. This component does not\n * implement roving focus for you — a bar of three buttons where Tab visits all\n * three is honest and fine — so pass `placement=\"inline\"` and skip the role by\n * using a plain `<div>` if that is not what you want.\n *\n * @example\n * <DiagramToolbar label=\"Diagram actions\" placement=\"floating\">\n * <DiagramToolbarGroup>\n * <Button size=\"sm\" variant=\"ghost\">Theme</Button>\n * </DiagramToolbarGroup>\n * <DiagramToolbarGroup>\n * <DiagramExportMenu targetRef={svg} title=\"Request path\" />\n * </DiagramToolbarGroup>\n * </DiagramToolbar>\n */\nexport function DiagramToolbar({\n children,\n className,\n placement = 'inline',\n align = 'end',\n label,\n ...rest\n}: DiagramToolbarProps) {\n return (\n <div\n role=\"toolbar\"\n aria-label={label}\n aria-orientation=\"horizontal\"\n className={cn(\n 'flex items-center gap-1 rounded-(--radius) border border-(--rule-2) bg-(--panel-bg) p-1',\n placement === 'floating' && 'absolute top-3 z-(--z-sticky)',\n placement === 'floating' && (align === 'end' ? 'end-3' : 'start-3'),\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n )\n}\n\n/**\n * One run of related controls inside the bar.\n *\n * Separated by a hairline rather than by space, because a gap large enough to\n * read as a group boundary is also large enough to stop the bar reading as one\n * object — which is the whole reason the controls were collected into a bar.\n */\nexport function DiagramToolbarGroup({\n children,\n className,\n ...rest\n}: ComponentProps<'div'>) {\n return (\n <div\n className={cn(\n 'flex items-center gap-0.5',\n 'border-s border-(--rule) ps-1 first:border-s-0 first:ps-0',\n className,\n )}\n {...rest}\n >\n {children}\n </div>\n )\n}\n\nexport default DiagramToolbar\n"],"mappings":";AAiDI;AA9CJ,SAAS,UAAU;AAqCZ,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR;AAAA,EACA,GAAG;AACL,GAAwB;AACtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,oBAAiB;AAAA,MACjB,WAAW;AAAA,QACT;AAAA,QACA,cAAc,cAAc;AAAA,QAC5B,cAAc,eAAe,UAAU,QAAQ,UAAU;AAAA,QACzD;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AASO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA0B;AACxB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,yBAAQ;","names":[]}
@@ -0,0 +1,31 @@
1
+ import * as react from 'react';
2
+ import { FigureChrome } from '../lib/frame.js';
3
+ import { LifecycleSpec } from '../spec.js';
4
+ import '../lib/geometry.js';
5
+
6
+ interface LifecycleFigureProps extends FigureChrome {
7
+ spec: LifecycleSpec;
8
+ }
9
+ /**
10
+ * A state machine: what something can BE, and what moves it.
11
+ *
12
+ * The one figure here that spends colour, and it spends exactly the two tokens
13
+ * this system reserves for state: `--success` on a terminal success,
14
+ * `--danger` on a terminal failure. Nothing else in the package is allowed
15
+ * those two, and a lifecycle diagram is the case they were reserved for — the
16
+ * whole point of the picture is which end a run came out of.
17
+ *
18
+ * The other six kinds are carried by shape, so a greyscale print loses the two
19
+ * outcomes' hue and keeps every other distinction: a start is a filled cap, a
20
+ * decision is a diamond, a wait is a dashed frame, an external is a plate with
21
+ * a cut corner.
22
+ *
23
+ * A RECOVERABLE FAILURE IS A FAILURE WITH A WAY BACK. `type: "failure"` says
24
+ * how a state is drawn; a transition OUT of it is what says whether the run is
25
+ * over. A retryable error and a terminal one look identical until you follow
26
+ * the arrows, which is correct — the difference between them is a real edge in
27
+ * the machine, not an adjective on a box.
28
+ */
29
+ declare function LifecycleFigure({ spec, className, legend, cards, heading, activeIds, onSelectNode, }: LifecycleFigureProps): react.JSX.Element;
30
+
31
+ export { LifecycleFigure, type LifecycleFigureProps, LifecycleFigure as default };
@@ -0,0 +1,202 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useId, useMemo } from "react";
4
+ import { DiagramFrame } from "../lib/frame.js";
5
+ import { inflate, round, TYPE, textWidth, union, wrapText } from "../lib/geometry.js";
6
+ import { resolveLegend, stateLegend } from "../lib/legend.js";
7
+ import { Chip, PLATE, plateHeight, StatePlate } from "../lib/marks.js";
8
+ import { renderWires, wiresFor } from "../lib/wires.js";
9
+ const KINDS = [
10
+ "start",
11
+ "active",
12
+ "waiting",
13
+ "decision",
14
+ "success",
15
+ "failure",
16
+ "neutral",
17
+ "external"
18
+ ];
19
+ const GRID = { originX: 132, originY: 56, colW: 158, gapX: 62, laneGap: 52, stateH: 68 };
20
+ const SECONDARY_LANE_OFFSET = 2;
21
+ function textRoom(width, kind) {
22
+ return kind === "decision" ? width * 0.56 : width - PLATE.padX * 2;
23
+ }
24
+ function LifecycleFigure({
25
+ spec,
26
+ className,
27
+ legend = "auto",
28
+ cards = true,
29
+ heading = true,
30
+ activeIds,
31
+ onSelectNode
32
+ }) {
33
+ const uid = useId().replace(/:/g, "");
34
+ const model = useMemo(
35
+ () => buildModel(spec, uid, activeIds, onSelectNode),
36
+ [spec, uid, activeIds, onSelectNode]
37
+ );
38
+ return /* @__PURE__ */ jsx(
39
+ DiagramFrame,
40
+ {
41
+ meta: spec.meta,
42
+ model,
43
+ cards: spec.cards,
44
+ showCards: cards,
45
+ heading,
46
+ legend,
47
+ className,
48
+ activeIds,
49
+ onSelectNode
50
+ }
51
+ );
52
+ }
53
+ function buildModel(spec, uid, activeIds, onSelectNode) {
54
+ const lanes = spec.lanes ?? [{ id: "", label: "" }];
55
+ const laneIndex = new Map(lanes.map((lane, index) => [lane.id, index]));
56
+ const boxes = /* @__PURE__ */ new Map();
57
+ const placed = spec.states.map((state) => {
58
+ const w = state.width ?? (state.type === "decision" ? GRID.colW + 34 : GRID.colW);
59
+ const lines = wrapText(state.label, TYPE.label, textRoom(w, state.type), 2);
60
+ const h = plateHeight(lines.length, Boolean(state.sublabel), true, state.height ?? GRID.stateH);
61
+ const lane = laneIndex.get(state.lane ?? "") ?? 0;
62
+ const col = state.col + (lane === 0 ? 0 : SECONDARY_LANE_OFFSET);
63
+ const x = GRID.originX + col * (GRID.colW + GRID.gapX);
64
+ const y = GRID.originY + lane * (GRID.stateH + GRID.laneGap);
65
+ const box = { x, y, w, h };
66
+ boxes.set(state.id, box);
67
+ return { state, box, lane };
68
+ });
69
+ const rail = placed.filter((entry) => entry.lane === 0).sort((a, b) => a.state.col - b.state.col);
70
+ const declared = new Set((spec.transitions ?? []).map((t) => `${t.from}\u2192${t.to}`));
71
+ const implied = rail.slice(0, -1).map((entry, index) => ({ from: entry.state.id, to: rail[index + 1].state.id })).filter((edge) => !declared.has(`${edge.from}\u2192${edge.to}`));
72
+ const wires = [
73
+ ...wiresFor(implied, boxes, () => ({ weight: 2.1 })),
74
+ ...wiresFor(spec.transitions, boxes)
75
+ ];
76
+ const { paths, labels } = renderWires(wires, uid);
77
+ const extent = inflate(union([...boxes.values()]) ?? { x: 0, y: 0, w: 500, h: 240 }, 34);
78
+ const active = activeIds && activeIds.length > 0 ? new Set(activeIds) : null;
79
+ const laneRules = lanes.map((lane, index) => {
80
+ const inside = placed.filter((entry) => entry.lane === index).map((entry) => entry.box);
81
+ const span = union(inside);
82
+ return span ? { lane, y: span.y - 16, x1: extent.x + 18, x2: span.x + span.w } : null;
83
+ });
84
+ const artwork = /* @__PURE__ */ jsxs(Fragment, { children: [
85
+ laneRules.map(
86
+ (rule, index) => rule && rule.lane.label ? /* @__PURE__ */ jsxs("g", { "aria-hidden": "true", children: [
87
+ /* @__PURE__ */ jsx(
88
+ "path",
89
+ {
90
+ d: `M ${round(rule.x1)} ${round(rule.y)} H ${round(rule.x2)}`,
91
+ className: "stroke-(--diagram-rule) [stroke-width:1]"
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsx(
95
+ "text",
96
+ {
97
+ x: round(rule.x1),
98
+ y: round(rule.y - 7),
99
+ className: "fill-(--diagram-ink-3) font-mono [font-size:10.5px] [letter-spacing:0.08em] uppercase",
100
+ children: rule.lane.label
101
+ }
102
+ )
103
+ ] }, `lane-${index}`) : null
104
+ ),
105
+ paths,
106
+ placed.map(({ state, box }) => {
107
+ const lines = wrapText(state.label, TYPE.label, textRoom(box.w, state.type), 2);
108
+ const bottomReserve = state.tag ? 20 : 0;
109
+ const blockHeight = lines.length * (TYPE.label * 1.25) + (state.sublabel ? TYPE.sub * 1.5 : 0);
110
+ const top = box.y + (box.h - bottomReserve - blockHeight) / 2;
111
+ const reversed = state.type === "start";
112
+ const centreX = box.x + box.w / 2;
113
+ return /* @__PURE__ */ jsx(
114
+ "g",
115
+ {
116
+ "data-node": state.id,
117
+ "data-active": active?.has(state.id) ? "" : void 0,
118
+ className: active && !active.has(state.id) ? "opacity-25" : void 0,
119
+ onClick: onSelectNode ? () => onSelectNode(state.id) : void 0,
120
+ children: /* @__PURE__ */ jsxs(StatePlate, { box, kind: state.type, children: [
121
+ active?.has(state.id) && /* @__PURE__ */ jsx(
122
+ "rect",
123
+ {
124
+ x: round(box.x) - 3,
125
+ y: round(box.y) - 3,
126
+ width: round(box.w) + 6,
127
+ height: round(box.h) + 6,
128
+ rx: 9,
129
+ fill: "none",
130
+ className: "stroke-(--accent) [stroke-width:1.4]"
131
+ }
132
+ ),
133
+ state.step && /* @__PURE__ */ jsx(
134
+ "text",
135
+ {
136
+ x: round(box.x + 10),
137
+ y: round(box.y + 15),
138
+ className: reversed ? "fill-(--diagram-plate-ink) font-mono [font-size:9.5px] opacity-70" : "fill-(--diagram-ink-3) font-mono [font-size:9.5px]",
139
+ children: state.step
140
+ }
141
+ ),
142
+ lines.map((line, index) => /* @__PURE__ */ jsx(
143
+ "text",
144
+ {
145
+ x: round(centreX),
146
+ y: round(top + (index + 1) * TYPE.label * 1.25 - 3.5),
147
+ textAnchor: "middle",
148
+ className: reversed ? "fill-(--diagram-plate-ink) font-sans [font-size:13px]" : "fill-(--diagram-ink) font-sans [font-size:13px]",
149
+ children: line
150
+ },
151
+ index
152
+ )),
153
+ state.sublabel && /* @__PURE__ */ jsx(
154
+ "text",
155
+ {
156
+ x: round(centreX),
157
+ y: round(top + lines.length * TYPE.label * 1.25 + TYPE.sub),
158
+ textAnchor: "middle",
159
+ className: reversed ? "fill-(--diagram-plate-ink) font-mono [font-size:10.5px] opacity-70" : "fill-(--diagram-ink-3) font-mono [font-size:10.5px]",
160
+ children: state.sublabel
161
+ }
162
+ ),
163
+ state.tag && /* @__PURE__ */ jsx(Chip, { x: centreX, y: box.y + box.h - 9, text: state.tag, align: "middle" })
164
+ ] })
165
+ },
166
+ state.id
167
+ );
168
+ }),
169
+ labels
170
+ ] });
171
+ const used = [...new Set(spec.states.map((state) => state.type))];
172
+ const widest = Math.max(
173
+ 0,
174
+ ...lanes.map((lane) => textWidth(lane.label, TYPE.band))
175
+ );
176
+ const railLeft = Math.min(extent.x, GRID.originX - widest - 30);
177
+ return {
178
+ extent: { ...extent, x: railLeft, w: extent.w + (extent.x - railLeft) },
179
+ artwork,
180
+ nodes: spec.states.map((state) => ({
181
+ id: state.id,
182
+ label: state.label,
183
+ sublabel: state.sublabel,
184
+ kind: state.type
185
+ })),
186
+ edges: (spec.transitions ?? []).map((transition) => ({
187
+ from: transition.from,
188
+ to: transition.to,
189
+ label: [transition.label, transition.note].filter(Boolean).join(" \u2014 ") || void 0
190
+ })),
191
+ legend: stateLegend(
192
+ resolveLegend(used, spec.meta.legend?.mode, KINDS, spec.meta.legend?.entries),
193
+ spec.meta.legend?.entries
194
+ )
195
+ };
196
+ }
197
+ var LifecycleFigure_default = LifecycleFigure;
198
+ export {
199
+ LifecycleFigure,
200
+ LifecycleFigure_default as default
201
+ };
202
+ //# sourceMappingURL=LifecycleFigure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/diagrams/LifecycleFigure/LifecycleFigure.tsx"],"sourcesContent":["'use client'\n\nimport { useId, useMemo } from 'react'\nimport { DiagramFrame, type FigureChrome, type FigureModel } from '../lib/frame'\nimport { inflate, round, TYPE, textWidth, union, wrapText, type Box } from '../lib/geometry'\nimport { resolveLegend, stateLegend } from '../lib/legend'\nimport { Chip, PLATE, plateHeight, StatePlate } from '../lib/marks'\nimport { renderWires, wiresFor } from '../lib/wires'\nimport type { LifecycleSpec, LifecycleStateKind } from '../spec'\n\nconst KINDS: LifecycleStateKind[] = [\n 'start',\n 'active',\n 'waiting',\n 'decision',\n 'success',\n 'failure',\n 'neutral',\n 'external',\n]\n\nconst GRID = { originX: 132, originY: 56, colW: 158, gapX: 62, laneGap: 52, stateH: 68 }\n\n/**\n * How far a secondary lane's columns are shifted along the main rail.\n *\n * archify's lifecycle contract: the first lane holds the ordered phases in\n * columns 0–4, and a secondary lane's column N sits exactly beneath main column\n * N + 2. It is a convention rather than a derivation — the alternative would be\n * making every author restate a column index they already implied — and\n * honouring it is what keeps `executing → approval` a straight vertical drop\n * instead of a dogleg across two unrelated states.\n */\nconst SECONDARY_LANE_OFFSET = 2\n\n/** How much horizontal room a state's own shape leaves for its name. */\nfunction textRoom(width: number, kind: LifecycleStateKind): number {\n return kind === 'decision' ? width * 0.56 : width - PLATE.padX * 2\n}\n\nexport interface LifecycleFigureProps extends FigureChrome {\n spec: LifecycleSpec\n}\n\n/**\n * A state machine: what something can BE, and what moves it.\n *\n * The one figure here that spends colour, and it spends exactly the two tokens\n * this system reserves for state: `--success` on a terminal success,\n * `--danger` on a terminal failure. Nothing else in the package is allowed\n * those two, and a lifecycle diagram is the case they were reserved for — the\n * whole point of the picture is which end a run came out of.\n *\n * The other six kinds are carried by shape, so a greyscale print loses the two\n * outcomes' hue and keeps every other distinction: a start is a filled cap, a\n * decision is a diamond, a wait is a dashed frame, an external is a plate with\n * a cut corner.\n *\n * A RECOVERABLE FAILURE IS A FAILURE WITH A WAY BACK. `type: \"failure\"` says\n * how a state is drawn; a transition OUT of it is what says whether the run is\n * over. A retryable error and a terminal one look identical until you follow\n * the arrows, which is correct — the difference between them is a real edge in\n * the machine, not an adjective on a box.\n */\nexport function LifecycleFigure({\n spec,\n className,\n legend = 'auto',\n cards = true,\n heading = true,\n activeIds,\n onSelectNode,\n}: LifecycleFigureProps) {\n const uid = useId().replace(/:/g, '')\n const model = useMemo(\n () => buildModel(spec, uid, activeIds, onSelectNode),\n [spec, uid, activeIds, onSelectNode],\n )\n\n return (\n <DiagramFrame\n meta={spec.meta}\n model={model}\n cards={spec.cards}\n showCards={cards}\n heading={heading}\n legend={legend}\n className={className}\n activeIds={activeIds}\n onSelectNode={onSelectNode}\n />\n )\n}\n\nfunction buildModel(\n spec: LifecycleSpec,\n uid: string,\n activeIds: string[] | undefined,\n onSelectNode: ((id: string) => void) | undefined,\n): FigureModel {\n const lanes = spec.lanes ?? [{ id: '', label: '' }]\n const laneIndex = new Map(lanes.map((lane, index) => [lane.id, index]))\n\n const boxes = new Map<string, Box>()\n const placed = spec.states.map((state) => {\n // A diamond is only half as wide as its box where the label crosses it, so\n // it gets a wider box for the same words. Sizing it like a rectangle is\n // what pushes a decision's name out past its own two sloping edges.\n const w = state.width ?? (state.type === 'decision' ? GRID.colW + 34 : GRID.colW)\n const lines = wrapText(state.label, TYPE.label, textRoom(w, state.type), 2)\n const h = plateHeight(lines.length, Boolean(state.sublabel), true, state.height ?? GRID.stateH)\n\n const lane = laneIndex.get(state.lane ?? '') ?? 0\n const col = state.col + (lane === 0 ? 0 : SECONDARY_LANE_OFFSET)\n\n // `yOffset` is deliberately NOT applied. It is an absolute nudge measured in\n // archify's own lane heights, and this renderer's lanes are a different\n // depth — so a 78-unit push that cleared a neighbour there drops a state\n // squarely on top of the lane below here. Two overlapping plates are worse\n // than a state sitting on its lane's centre line, which is where the\n // specification put it before the nudge.\n const x = GRID.originX + col * (GRID.colW + GRID.gapX)\n const y = GRID.originY + lane * (GRID.stateH + GRID.laneGap)\n\n const box: Box = { x, y, w, h }\n boxes.set(state.id, box)\n return { state, box, lane }\n })\n\n // The main rail is IMPLICIT, and has to be. archify's lifecycle contract\n // gives the first lane's columns 0..4 to the ordered phases and does not ask\n // an author to restate `queued → planning → executing` as transitions —\n // those are the diagram's spine, not its exceptions. Without them drawn, the\n // top row reads as five unconnected boxes.\n const rail = placed\n .filter((entry) => entry.lane === 0)\n .sort((a, b) => a.state.col - b.state.col)\n const declared = new Set((spec.transitions ?? []).map((t) => `${t.from}→${t.to}`))\n const implied = rail\n .slice(0, -1)\n .map((entry, index) => ({ from: entry.state.id, to: rail[index + 1]!.state.id }))\n .filter((edge) => !declared.has(`${edge.from}→${edge.to}`))\n\n const wires = [\n ...wiresFor(implied, boxes, () => ({ weight: 2.1 })),\n ...wiresFor(spec.transitions, boxes),\n ]\n const { paths, labels } = renderWires(wires, uid)\n\n const extent = inflate(union([...boxes.values()]) ?? { x: 0, y: 0, w: 500, h: 240 }, 34)\n const active = activeIds && activeIds.length > 0 ? new Set(activeIds) : null\n\n // A lane's rule spans what it actually holds. Drawing it across the figure's\n // full width would claim a band reaches columns nothing in it occupies.\n const laneRules = lanes.map((lane, index) => {\n const inside = placed.filter((entry) => entry.lane === index).map((entry) => entry.box)\n const span = union(inside)\n return span ? { lane, y: span.y - 16, x1: extent.x + 18, x2: span.x + span.w } : null\n })\n\n const artwork = (\n <>\n {laneRules.map((rule, index) =>\n rule && rule.lane.label ? (\n <g key={`lane-${index}`} aria-hidden=\"true\">\n <path\n d={`M ${round(rule.x1)} ${round(rule.y)} H ${round(rule.x2)}`}\n className=\"stroke-(--diagram-rule) [stroke-width:1]\"\n />\n <text\n x={round(rule.x1)}\n y={round(rule.y - 7)}\n className=\"fill-(--diagram-ink-3) font-mono [font-size:10.5px] [letter-spacing:0.08em] uppercase\"\n >\n {rule.lane.label}\n </text>\n </g>\n ) : null,\n )}\n\n {paths}\n\n {placed.map(({ state, box }) => {\n const lines = wrapText(state.label, TYPE.label, textRoom(box.w, state.type), 2)\n const bottomReserve = state.tag ? 20 : 0\n const blockHeight = lines.length * (TYPE.label * 1.25) + (state.sublabel ? TYPE.sub * 1.5 : 0)\n const top = box.y + (box.h - bottomReserve - blockHeight) / 2\n const reversed = state.type === 'start'\n const centreX = box.x + box.w / 2\n\n return (\n <g\n key={state.id}\n data-node={state.id}\n data-active={active?.has(state.id) ? '' : undefined}\n className={active && !active.has(state.id) ? 'opacity-25' : undefined}\n onClick={onSelectNode ? () => onSelectNode(state.id) : undefined}\n >\n <StatePlate box={box} kind={state.type}>\n {active?.has(state.id) && (\n <rect\n x={round(box.x) - 3}\n y={round(box.y) - 3}\n width={round(box.w) + 6}\n height={round(box.h) + 6}\n rx={9}\n fill=\"none\"\n className=\"stroke-(--accent) [stroke-width:1.4]\"\n />\n )}\n {state.step && (\n <text\n x={round(box.x + 10)}\n y={round(box.y + 15)}\n className={\n reversed\n ? 'fill-(--diagram-plate-ink) font-mono [font-size:9.5px] opacity-70'\n : 'fill-(--diagram-ink-3) font-mono [font-size:9.5px]'\n }\n >\n {state.step}\n </text>\n )}\n {lines.map((line, index) => (\n <text\n key={index}\n x={round(centreX)}\n y={round(top + (index + 1) * TYPE.label * 1.25 - 3.5)}\n textAnchor=\"middle\"\n className={\n reversed\n ? 'fill-(--diagram-plate-ink) font-sans [font-size:13px]'\n : 'fill-(--diagram-ink) font-sans [font-size:13px]'\n }\n >\n {line}\n </text>\n ))}\n {state.sublabel && (\n <text\n x={round(centreX)}\n y={round(top + lines.length * TYPE.label * 1.25 + TYPE.sub)}\n textAnchor=\"middle\"\n className={\n reversed\n ? 'fill-(--diagram-plate-ink) font-mono [font-size:10.5px] opacity-70'\n : 'fill-(--diagram-ink-3) font-mono [font-size:10.5px]'\n }\n >\n {state.sublabel}\n </text>\n )}\n {state.tag && <Chip x={centreX} y={box.y + box.h - 9} text={state.tag} align=\"middle\" />}\n </StatePlate>\n </g>\n )\n })}\n\n {labels}\n\n </>\n )\n\n const used = [...new Set(spec.states.map((state) => state.type))]\n const widest = Math.max(\n 0,\n ...lanes.map((lane) => textWidth(lane.label, TYPE.band)),\n )\n\n // Widening the frame to the LEFT for the lane names has to widen it, not\n // slide it: moving `x` without adding the same amount to `w` trims exactly\n // that much off the right-hand edge, which cost the last column of states.\n const railLeft = Math.min(extent.x, GRID.originX - widest - 30)\n\n return {\n extent: { ...extent, x: railLeft, w: extent.w + (extent.x - railLeft) },\n artwork,\n nodes: spec.states.map((state) => ({\n id: state.id,\n label: state.label,\n sublabel: state.sublabel,\n kind: state.type,\n })),\n edges: (spec.transitions ?? []).map((transition) => ({\n from: transition.from,\n to: transition.to,\n label: [transition.label, transition.note].filter(Boolean).join(' — ') || undefined,\n })),\n legend: stateLegend(\n resolveLegend(used, spec.meta.legend?.mode, KINDS, spec.meta.legend?.entries),\n spec.meta.legend?.entries,\n ),\n }\n}\n\nexport default LifecycleFigure\n"],"mappings":"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","names":[]}
@@ -0,0 +1,38 @@
1
+ import * as react from 'react';
2
+ import { FigureChrome } from '../lib/frame.js';
3
+ import { SequenceSpec } from '../spec.js';
4
+ import '../lib/geometry.js';
5
+
6
+ interface SequenceFigureProps extends FigureChrome {
7
+ spec: SequenceSpec;
8
+ }
9
+ /**
10
+ * A call chain over time: who asks whom, in what order, and what comes back.
11
+ *
12
+ * The one diagram type here whose vertical axis MEANS something. Every other
13
+ * figure's y is layout; a sequence's y is time, which is why a message carries
14
+ * an explicit `y` rather than an index — two calls 8 units apart happened
15
+ * together, and two 200 apart did not, and an evenly spaced list of messages
16
+ * would erase that distinction while looking tidier.
17
+ *
18
+ * **Lifelines** are hairlines, not solid rules, because they are the axis
19
+ * rather than the content. A lifeline drawn at the weight of a message is a
20
+ * diagram where seven vertical lines compete with twelve horizontal ones.
21
+ *
22
+ * **Activation bars** say who is BUSY, which is the fact a sequence diagram
23
+ * carries that a list of calls does not — the third participant's bar
24
+ * overlapping the second's is the reason to draw them at all.
25
+ *
26
+ * **Segments** band the axis into phases — request, fallback, response —
27
+ * printed as a rule with a mono caption rather than as a tinted panel, for the
28
+ * same reason architecture boundaries are: a second ground inside the figure
29
+ * would sit under every message label's mask.
30
+ *
31
+ * A `return` message is dashed AND takes an open arrowhead. Two signals rather
32
+ * than one, because the reply is the thing a reader most often needs to pick
33
+ * out of a dense trace, and a dash alone is doing the same work as `dashed`
34
+ * already does for an asynchronous call.
35
+ */
36
+ declare function SequenceFigure({ spec, className, legend, cards, heading, activeIds, onSelectNode, }: SequenceFigureProps): react.JSX.Element;
37
+
38
+ export { SequenceFigure, type SequenceFigureProps, SequenceFigure as default };
@@ -0,0 +1,231 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useId, useMemo } from "react";
4
+ import { DiagramFrame } from "../lib/frame.js";
5
+ import { round, textWidth, TYPE } from "../lib/geometry.js";
6
+ import { resolveLegend, variantLegend } from "../lib/legend.js";
7
+ import { EdgeLabel, NodePlate } from "../lib/marks.js";
8
+ const HEAD = { y: 44, h: 62, w: 148, gap: 40 };
9
+ const VARIANTS = ["default", "emphasis", "security", "dashed", "return"];
10
+ function SequenceFigure({
11
+ spec,
12
+ className,
13
+ legend = "auto",
14
+ cards = true,
15
+ heading = true,
16
+ activeIds,
17
+ onSelectNode
18
+ }) {
19
+ const uid = useId().replace(/:/g, "");
20
+ const model = useMemo(
21
+ () => buildModel(spec, uid, activeIds, onSelectNode),
22
+ [spec, uid, activeIds, onSelectNode]
23
+ );
24
+ return /* @__PURE__ */ jsx(
25
+ DiagramFrame,
26
+ {
27
+ meta: spec.meta,
28
+ model,
29
+ cards: spec.cards,
30
+ showCards: cards,
31
+ heading,
32
+ legend,
33
+ className,
34
+ activeIds,
35
+ onSelectNode
36
+ }
37
+ );
38
+ }
39
+ function buildModel(spec, _uid, activeIds, onSelectNode) {
40
+ const natural = Math.max(
41
+ HEAD.w,
42
+ ...spec.participants.map(
43
+ (participant) => Math.max(
44
+ textWidth(participant.label, TYPE.label),
45
+ textWidth(participant.sublabel ?? "", TYPE.sub)
46
+ ) + 44
47
+ )
48
+ );
49
+ const colW = spec.meta.column_fit === "spread" ? natural : HEAD.w;
50
+ const pitch = colW + HEAD.gap;
51
+ const centre = /* @__PURE__ */ new Map();
52
+ const heads = spec.participants.map((participant, index) => {
53
+ const x = 40 + index * pitch;
54
+ centre.set(participant.id, x + colW / 2);
55
+ return { participant, box: { x, y: HEAD.y, w: colW, h: HEAD.h } };
56
+ });
57
+ const lastY = Math.max(
58
+ HEAD.y + HEAD.h + 80,
59
+ ...spec.messages.map((message) => message.y),
60
+ ...(spec.activations ?? []).map((activation) => activation.to),
61
+ ...(spec.segments ?? []).map((segment) => segment.to)
62
+ );
63
+ const lifelineBottom = lastY + 42;
64
+ const active = activeIds && activeIds.length > 0 ? new Set(activeIds) : null;
65
+ const width = 40 + spec.participants.length * pitch - HEAD.gap + 40;
66
+ const artwork = /* @__PURE__ */ jsxs(Fragment, { children: [
67
+ (spec.segments ?? []).map((segment, index) => /* @__PURE__ */ jsxs("g", { "aria-hidden": "true", children: [
68
+ /* @__PURE__ */ jsx(
69
+ "path",
70
+ {
71
+ d: `M 20 ${round(segment.from)} H ${round(width - 20)}`,
72
+ className: "stroke-(--diagram-rule) [stroke-width:1] [stroke-dasharray:2_4]"
73
+ }
74
+ ),
75
+ /* @__PURE__ */ jsx(
76
+ "rect",
77
+ {
78
+ x: 20,
79
+ y: round(segment.from - 7),
80
+ width: round(textWidth(segment.label, TYPE.band) + 14),
81
+ height: 14,
82
+ className: "fill-(--diagram-surface)"
83
+ }
84
+ ),
85
+ /* @__PURE__ */ jsx(
86
+ "text",
87
+ {
88
+ x: 27,
89
+ y: round(segment.from + 3.5),
90
+ className: "fill-(--diagram-ink-3) font-mono [font-size:10.5px] [letter-spacing:0.08em] uppercase",
91
+ children: segment.label
92
+ }
93
+ )
94
+ ] }, `segment-${index}`)),
95
+ heads.map(({ participant, box }) => /* @__PURE__ */ jsx(
96
+ "path",
97
+ {
98
+ d: `M ${round(box.x + colW / 2)} ${round(box.y + box.h)} V ${round(lifelineBottom)}`,
99
+ className: "stroke-(--diagram-rule) [stroke-width:1]",
100
+ "aria-hidden": "true"
101
+ },
102
+ `life-${participant.id}`
103
+ )),
104
+ (spec.activations ?? []).map((activation, index) => {
105
+ const x = centre.get(activation.participant);
106
+ if (x === void 0) return null;
107
+ return /* @__PURE__ */ jsx(
108
+ "rect",
109
+ {
110
+ x: round(x - 5),
111
+ y: round(activation.from),
112
+ width: 10,
113
+ height: round(Math.max(6, activation.to - activation.from)),
114
+ rx: 2,
115
+ className: "fill-(--diagram-node-2) stroke-(--diagram-rule)",
116
+ strokeWidth: 1,
117
+ "aria-hidden": "true"
118
+ },
119
+ `act-${index}`
120
+ );
121
+ }),
122
+ spec.messages.map((message, index) => {
123
+ const from = centre.get(message.from);
124
+ const to = centre.get(message.to);
125
+ if (from === void 0 || to === void 0) return null;
126
+ const forward = to >= from;
127
+ const inset = 6;
128
+ const x1 = forward ? from + inset : from - inset;
129
+ const x2 = forward ? to - inset : to + inset;
130
+ return /* @__PURE__ */ jsx(
131
+ "path",
132
+ {
133
+ d: `M ${round(x1)} ${round(message.y)} H ${round(x2)}`,
134
+ fill: "none",
135
+ "data-edge": message.id,
136
+ markerEnd: `url(#${_uid}-${messageMarker(message.variant)})`,
137
+ className: messageClasses(message.variant),
138
+ ...messageStroke(message.variant)
139
+ },
140
+ message.id ?? `msg-${index}`
141
+ );
142
+ }),
143
+ heads.map(({ participant, box }) => /* @__PURE__ */ jsx(
144
+ NodePlate,
145
+ {
146
+ nodeId: participant.id,
147
+ box,
148
+ label: participant.label,
149
+ sublabel: participant.sublabel,
150
+ kind: participant.type,
151
+ active: active?.has(participant.id),
152
+ dimmed: active ? !active.has(participant.id) : false,
153
+ onSelect: onSelectNode ? () => onSelectNode(participant.id) : void 0
154
+ },
155
+ participant.id
156
+ )),
157
+ spec.messages.map((message, index) => {
158
+ const from = centre.get(message.from);
159
+ const to = centre.get(message.to);
160
+ if (from === void 0 || to === void 0 || !message.label) return null;
161
+ return /* @__PURE__ */ jsx(
162
+ EdgeLabel,
163
+ {
164
+ x: (from + to) / 2,
165
+ y: message.y,
166
+ axis: "x",
167
+ text: message.label
168
+ },
169
+ `label-${message.id ?? index}`
170
+ );
171
+ })
172
+ ] });
173
+ const used = [
174
+ ...new Set(spec.messages.map((message) => message.variant ?? "default"))
175
+ ];
176
+ return {
177
+ extent: { x: 0, y: 0, w: width, h: lifelineBottom + 24 },
178
+ artwork,
179
+ nodes: spec.participants.map((participant) => ({
180
+ id: participant.id,
181
+ label: participant.label,
182
+ sublabel: participant.sublabel,
183
+ kind: participant.type
184
+ })),
185
+ edges: spec.messages.map((message) => ({
186
+ from: message.from,
187
+ to: message.to,
188
+ label: message.label
189
+ })),
190
+ legend: variantLegend(
191
+ resolveLegend(used, spec.meta.legend?.mode, VARIANTS, spec.meta.legend?.entries),
192
+ spec.meta.legend?.entries
193
+ )
194
+ };
195
+ }
196
+ function messageMarker(variant) {
197
+ if (variant === "emphasis") return "arrow-strong";
198
+ if (variant === "return") return "arrow-open";
199
+ return "arrow";
200
+ }
201
+ function messageClasses(variant) {
202
+ switch (variant) {
203
+ case "emphasis":
204
+ return "stroke-(--diagram-line-strong)";
205
+ case "return":
206
+ case "dashed":
207
+ return "stroke-(--diagram-line-soft)";
208
+ default:
209
+ return "stroke-(--diagram-line)";
210
+ }
211
+ }
212
+ function messageStroke(variant) {
213
+ switch (variant) {
214
+ case "emphasis":
215
+ return { strokeWidth: 2 };
216
+ case "security":
217
+ return { strokeWidth: 1.4, strokeDasharray: "6 3" };
218
+ case "return":
219
+ return { strokeWidth: 1.2, strokeDasharray: "4 3.5" };
220
+ case "dashed":
221
+ return { strokeWidth: 1.2, strokeDasharray: "3 3" };
222
+ default:
223
+ return { strokeWidth: 1.4 };
224
+ }
225
+ }
226
+ var SequenceFigure_default = SequenceFigure;
227
+ export {
228
+ SequenceFigure,
229
+ SequenceFigure_default as default
230
+ };
231
+ //# sourceMappingURL=SequenceFigure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/diagrams/SequenceFigure/SequenceFigure.tsx"],"sourcesContent":["'use client'\n\nimport { useId, useMemo } from 'react'\nimport { DiagramFrame, type FigureChrome, type FigureModel } from '../lib/frame'\nimport { round, textWidth, TYPE, type Box } from '../lib/geometry'\nimport { resolveLegend, variantLegend } from '../lib/legend'\nimport { EdgeLabel, NodePlate } from '../lib/marks'\nimport type { SequenceSpec, Variant } from '../spec'\n\nconst HEAD = { y: 44, h: 62, w: 148, gap: 40 }\nconst VARIANTS: (Variant | 'return')[] = ['default', 'emphasis', 'security', 'dashed', 'return']\n\nexport interface SequenceFigureProps extends FigureChrome {\n spec: SequenceSpec\n}\n\n/**\n * A call chain over time: who asks whom, in what order, and what comes back.\n *\n * The one diagram type here whose vertical axis MEANS something. Every other\n * figure's y is layout; a sequence's y is time, which is why a message carries\n * an explicit `y` rather than an index — two calls 8 units apart happened\n * together, and two 200 apart did not, and an evenly spaced list of messages\n * would erase that distinction while looking tidier.\n *\n * **Lifelines** are hairlines, not solid rules, because they are the axis\n * rather than the content. A lifeline drawn at the weight of a message is a\n * diagram where seven vertical lines compete with twelve horizontal ones.\n *\n * **Activation bars** say who is BUSY, which is the fact a sequence diagram\n * carries that a list of calls does not — the third participant's bar\n * overlapping the second's is the reason to draw them at all.\n *\n * **Segments** band the axis into phases — request, fallback, response —\n * printed as a rule with a mono caption rather than as a tinted panel, for the\n * same reason architecture boundaries are: a second ground inside the figure\n * would sit under every message label's mask.\n *\n * A `return` message is dashed AND takes an open arrowhead. Two signals rather\n * than one, because the reply is the thing a reader most often needs to pick\n * out of a dense trace, and a dash alone is doing the same work as `dashed`\n * already does for an asynchronous call.\n */\nexport function SequenceFigure({\n spec,\n className,\n legend = 'auto',\n cards = true,\n heading = true,\n activeIds,\n onSelectNode,\n}: SequenceFigureProps) {\n const uid = useId().replace(/:/g, '')\n const model = useMemo(\n () => buildModel(spec, uid, activeIds, onSelectNode),\n [spec, uid, activeIds, onSelectNode],\n )\n\n return (\n <DiagramFrame\n meta={spec.meta}\n model={model}\n cards={spec.cards}\n showCards={cards}\n heading={heading}\n legend={legend}\n className={className}\n activeIds={activeIds}\n onSelectNode={onSelectNode}\n />\n )\n}\n\nfunction buildModel(\n spec: SequenceSpec,\n _uid: string,\n activeIds: string[] | undefined,\n onSelectNode: ((id: string) => void) | undefined,\n): FigureModel {\n // A participant's box has to hold its own name. `spread` lets the widest\n // label set the pitch for every column, which is the layout archify reaches\n // for when a fixed 86-unit column would clip a meaningful name — and\n // shortening the name instead is not a repair, it is a different diagram.\n const natural = Math.max(\n HEAD.w,\n ...spec.participants.map(\n (participant) =>\n Math.max(\n textWidth(participant.label, TYPE.label),\n textWidth(participant.sublabel ?? '', TYPE.sub),\n ) + 44,\n ),\n )\n const colW = spec.meta.column_fit === 'spread' ? natural : HEAD.w\n const pitch = colW + HEAD.gap\n\n const centre = new Map<string, number>()\n const heads = spec.participants.map((participant, index) => {\n const x = 40 + index * pitch\n centre.set(participant.id, x + colW / 2)\n return { participant, box: { x, y: HEAD.y, w: colW, h: HEAD.h } as Box }\n })\n\n const lastY = Math.max(\n HEAD.y + HEAD.h + 80,\n ...spec.messages.map((message) => message.y),\n ...(spec.activations ?? []).map((activation) => activation.to),\n ...(spec.segments ?? []).map((segment) => segment.to),\n )\n const lifelineBottom = lastY + 42\n\n const active = activeIds && activeIds.length > 0 ? new Set(activeIds) : null\n const width = 40 + spec.participants.length * pitch - HEAD.gap + 40\n\n const artwork = (\n <>\n {/* Segments first: they are the ground the whole exchange happens on. */}\n {(spec.segments ?? []).map((segment, index) => (\n <g key={`segment-${index}`} aria-hidden=\"true\">\n <path\n d={`M 20 ${round(segment.from)} H ${round(width - 20)}`}\n className=\"stroke-(--diagram-rule) [stroke-width:1] [stroke-dasharray:2_4]\"\n />\n <rect\n x={20}\n y={round(segment.from - 7)}\n width={round(textWidth(segment.label, TYPE.band) + 14)}\n height={14}\n className=\"fill-(--diagram-surface)\"\n />\n <text\n x={27}\n y={round(segment.from + 3.5)}\n className=\"fill-(--diagram-ink-3) font-mono [font-size:10.5px] [letter-spacing:0.08em] uppercase\"\n >\n {segment.label}\n </text>\n </g>\n ))}\n\n {/* Lifelines. */}\n {heads.map(({ participant, box }) => (\n <path\n key={`life-${participant.id}`}\n d={`M ${round(box.x + colW / 2)} ${round(box.y + box.h)} V ${round(lifelineBottom)}`}\n className=\"stroke-(--diagram-rule) [stroke-width:1]\"\n aria-hidden=\"true\"\n />\n ))}\n\n {/* Activation bars. */}\n {(spec.activations ?? []).map((activation, index) => {\n const x = centre.get(activation.participant)\n if (x === undefined) return null\n return (\n <rect\n key={`act-${index}`}\n x={round(x - 5)}\n y={round(activation.from)}\n width={10}\n height={round(Math.max(6, activation.to - activation.from))}\n rx={2}\n className=\"fill-(--diagram-node-2) stroke-(--diagram-rule)\"\n strokeWidth={1}\n aria-hidden=\"true\"\n />\n )\n })}\n\n {/* Messages. */}\n {spec.messages.map((message, index) => {\n const from = centre.get(message.from)\n const to = centre.get(message.to)\n if (from === undefined || to === undefined) return null\n const forward = to >= from\n const inset = 6\n const x1 = forward ? from + inset : from - inset\n const x2 = forward ? to - inset : to + inset\n return (\n <path\n key={message.id ?? `msg-${index}`}\n d={`M ${round(x1)} ${round(message.y)} H ${round(x2)}`}\n fill=\"none\"\n data-edge={message.id}\n markerEnd={`url(#${_uid}-${messageMarker(message.variant)})`}\n className={messageClasses(message.variant)}\n {...messageStroke(message.variant)}\n />\n )\n })}\n\n {/* Participants, over the lines that end at them. */}\n {heads.map(({ participant, box }) => (\n <NodePlate\n key={participant.id}\n nodeId={participant.id}\n box={box}\n label={participant.label}\n sublabel={participant.sublabel}\n kind={participant.type}\n active={active?.has(participant.id)}\n dimmed={active ? !active.has(participant.id) : false}\n onSelect={onSelectNode ? () => onSelectNode(participant.id) : undefined}\n />\n ))}\n\n {/* Message wording last, so its mask covers every line. */}\n {spec.messages.map((message, index) => {\n const from = centre.get(message.from)\n const to = centre.get(message.to)\n if (from === undefined || to === undefined || !message.label) return null\n return (\n <EdgeLabel\n key={`label-${message.id ?? index}`}\n x={(from + to) / 2}\n y={message.y}\n axis=\"x\"\n text={message.label}\n />\n )\n })}\n </>\n )\n\n const used = [\n ...new Set(spec.messages.map((message) => message.variant ?? 'default')),\n ] as (Variant | 'return')[]\n\n return {\n extent: { x: 0, y: 0, w: width, h: lifelineBottom + 24 },\n artwork,\n nodes: spec.participants.map((participant) => ({\n id: participant.id,\n label: participant.label,\n sublabel: participant.sublabel,\n kind: participant.type,\n })),\n edges: spec.messages.map((message) => ({\n from: message.from,\n to: message.to,\n label: message.label,\n })),\n legend: variantLegend(\n resolveLegend(used, spec.meta.legend?.mode, VARIANTS, spec.meta.legend?.entries),\n spec.meta.legend?.entries,\n ),\n }\n}\n\n/** Which arrowhead a message ends in. */\nfunction messageMarker(\n variant: SequenceSpec['messages'][number]['variant'],\n): 'arrow' | 'arrow-strong' | 'arrow-open' {\n if (variant === 'emphasis') return 'arrow-strong'\n if (variant === 'return') return 'arrow-open'\n return 'arrow'\n}\n\n/** A message's colour. Geometry goes through attributes — see `edgeClasses`. */\nfunction messageClasses(variant: SequenceSpec['messages'][number]['variant']): string {\n switch (variant) {\n case 'emphasis':\n return 'stroke-(--diagram-line-strong)'\n case 'return':\n case 'dashed':\n return 'stroke-(--diagram-line-soft)'\n default:\n return 'stroke-(--diagram-line)'\n }\n}\n\n/** A message's width and dash pattern. Heavier than a map's line: it IS the content. */\nfunction messageStroke(variant: SequenceSpec['messages'][number]['variant']): {\n strokeWidth: number\n strokeDasharray?: string\n} {\n switch (variant) {\n case 'emphasis':\n return { strokeWidth: 2 }\n case 'security':\n return { strokeWidth: 1.4, strokeDasharray: '6 3' }\n case 'return':\n return { strokeWidth: 1.2, strokeDasharray: '4 3.5' }\n case 'dashed':\n return { strokeWidth: 1.2, strokeDasharray: '3 3' }\n default:\n return { strokeWidth: 1.4 }\n }\n}\n\nexport default SequenceFigure\n"],"mappings":"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","names":[]}