@zukhruf/diagram 0.3.31 → 0.3.33

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 (60) hide show
  1. package/dist/lib/layouts/graph/areas.js +17 -8
  2. package/dist/lib/layouts/graph/areas.js.map +1 -1
  3. package/dist/lib/layouts/graph/attach.d.ts +25 -0
  4. package/dist/lib/layouts/graph/attach.d.ts.map +1 -0
  5. package/dist/lib/layouts/graph/attach.js +216 -0
  6. package/dist/lib/layouts/graph/attach.js.map +1 -0
  7. package/dist/lib/layouts/graph/connections.d.ts +38 -0
  8. package/dist/lib/layouts/graph/connections.d.ts.map +1 -0
  9. package/dist/lib/layouts/graph/connections.js +112 -0
  10. package/dist/lib/layouts/graph/connections.js.map +1 -0
  11. package/dist/lib/layouts/graph/graph-layout-result.d.ts +1 -1
  12. package/dist/lib/layouts/graph/graph-layout-result.d.ts.map +1 -1
  13. package/dist/lib/layouts/graph/graph-layout-result.js.map +1 -1
  14. package/dist/lib/layouts/graph/gutters.d.ts +1 -2
  15. package/dist/lib/layouts/graph/gutters.d.ts.map +1 -1
  16. package/dist/lib/layouts/graph/gutters.js +20 -19
  17. package/dist/lib/layouts/graph/gutters.js.map +1 -1
  18. package/dist/lib/layouts/graph/labels.d.ts +16 -0
  19. package/dist/lib/layouts/graph/labels.d.ts.map +1 -0
  20. package/dist/lib/layouts/graph/labels.js +76 -0
  21. package/dist/lib/layouts/graph/labels.js.map +1 -0
  22. package/dist/lib/layouts/graph/layout.d.ts.map +1 -1
  23. package/dist/lib/layouts/graph/layout.js +34 -13
  24. package/dist/lib/layouts/graph/layout.js.map +1 -1
  25. package/dist/lib/layouts/graph/measure.d.ts +7 -6
  26. package/dist/lib/layouts/graph/measure.d.ts.map +1 -1
  27. package/dist/lib/layouts/graph/measure.js +35 -29
  28. package/dist/lib/layouts/graph/measure.js.map +1 -1
  29. package/dist/lib/layouts/graph/min-heap.d.ts +12 -0
  30. package/dist/lib/layouts/graph/min-heap.d.ts.map +1 -0
  31. package/dist/lib/layouts/graph/min-heap.js +60 -0
  32. package/dist/lib/layouts/graph/min-heap.js.map +1 -0
  33. package/dist/lib/layouts/graph/node-content.d.ts +1 -2
  34. package/dist/lib/layouts/graph/node-content.d.ts.map +1 -1
  35. package/dist/lib/layouts/graph/node-content.js +43 -42
  36. package/dist/lib/layouts/graph/node-content.js.map +1 -1
  37. package/dist/lib/layouts/graph/path.d.ts +14 -0
  38. package/dist/lib/layouts/graph/path.d.ts.map +1 -0
  39. package/dist/lib/layouts/graph/path.js +55 -0
  40. package/dist/lib/layouts/graph/path.js.map +1 -0
  41. package/dist/lib/layouts/graph/route-search.d.ts +34 -0
  42. package/dist/lib/layouts/graph/route-search.d.ts.map +1 -0
  43. package/dist/lib/layouts/graph/route-search.js +208 -0
  44. package/dist/lib/layouts/graph/route-search.js.map +1 -0
  45. package/dist/lib/layouts/graph/route.d.ts +16 -0
  46. package/dist/lib/layouts/graph/route.d.ts.map +1 -0
  47. package/dist/lib/layouts/graph/route.js +241 -0
  48. package/dist/lib/layouts/graph/route.js.map +1 -0
  49. package/dist/lib/layouts/graph/sides.d.ts +23 -0
  50. package/dist/lib/layouts/graph/sides.d.ts.map +1 -0
  51. package/dist/lib/layouts/graph/sides.js +91 -0
  52. package/dist/lib/layouts/graph/sides.js.map +1 -0
  53. package/dist/lib/layouts/graph/tokens.d.ts +2 -7
  54. package/dist/lib/layouts/graph/tokens.d.ts.map +1 -1
  55. package/dist/lib/layouts/graph/tokens.js +91 -104
  56. package/dist/lib/layouts/graph/tokens.js.map +1 -1
  57. package/dist/lib/model/diagram-ir.d.ts +0 -3
  58. package/dist/lib/model/diagram-ir.d.ts.map +1 -1
  59. package/dist/lib/model/diagram-ir.js.map +1 -1
  60. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { nodeContent } from "./node-content.js";
2
2
  import { labelLines, textBlock } from "./text-block.js";
3
+ import { LAYOUT_TOKENS } from "./tokens.js";
3
4
  /** The distance from a port's point to its label: the port marker's radius plus a gap. */
4
5
  const PORT_LABEL_OFFSET = 8;
5
6
  const EDGE_LABEL_FRAME_PAD = 4;
@@ -10,11 +11,11 @@ const BADGE_PAD = {
10
11
  };
11
12
  const BADGE_MIN_CONTENT = 24;
12
13
  const SIDES = ['top', 'right', 'bottom', 'left'];
13
- export function measureNode(node, tokens) {
14
+ export function measureNode(node) {
14
15
  const kind = node.kind ?? 'node';
15
16
  if (node.hidden && kind === 'node') return hiddenNode();
16
- const content = nodeContent(node, tokens);
17
- const ports = portGeometry(node.ports ?? [], tokens);
17
+ const content = nodeContent(node);
18
+ const ports = portGeometry(node.ports ?? []);
18
19
  const w = Math.max(content.w + 2 * content.pad.x + ports.inset.left + ports.inset.right, ports.minLength.top, ports.minLength.bottom);
19
20
  const h = Math.max(content.h + 2 * content.pad.y + ports.inset.top + ports.inset.bottom, ports.minLength.left, ports.minLength.right);
20
21
  const place = box => {
@@ -24,13 +25,13 @@ export function measureNode(node, tokens) {
24
25
  left: content.pad.x,
25
26
  right: content.pad.x
26
27
  });
27
- const frames = stackFrames(node, box, tokens);
28
- const caption = placeCaption(node, union([box, ...frames]), tokens);
28
+ const frames = stackFrames(node, box);
29
+ const caption = placeCaption(node, union([box, ...frames]));
29
30
  return {
30
31
  box,
31
32
  visual: union([box, ...frames, ...(caption ? [caption.box] : [])]),
32
33
  frames,
33
- radius: frameRadius(node, box, tokens),
34
+ radius: frameRadius(node, box),
34
35
  ...content.place(inner),
35
36
  ...(caption ? {
36
37
  caption
@@ -85,7 +86,7 @@ function hiddenNode() {
85
86
  })
86
87
  };
87
88
  }
88
- function frameRadius(node, box, tokens) {
89
+ function frameRadius(node, box) {
89
90
  switch (node.kind) {
90
91
  case 'connector':
91
92
  return box.h / 2;
@@ -97,7 +98,7 @@ function frameRadius(node, box, tokens) {
97
98
  return 0;
98
99
  default:
99
100
  if (node.frame === 'none') return 0;
100
- return node.frame === 'flat' ? tokens.FLAT_RADIUS : tokens.RADIUS;
101
+ return node.frame === 'flat' ? LAYOUT_TOKENS.FLAT_RADIUS : LAYOUT_TOKENS.RADIUS;
101
102
  }
102
103
  }
103
104
 
@@ -106,8 +107,8 @@ function frameRadius(node, box, tokens) {
106
107
  * side's labels push the content inward, and a side with k ports is long
107
108
  * enough for k + 1 port spacings.
108
109
  */
109
- function portGeometry(ports, tokens) {
110
- const font = tokens.fonts.portLabel;
110
+ function portGeometry(ports) {
111
+ const font = LAYOUT_TOKENS.fonts.portLabel;
111
112
  const bySide = new Map(SIDES.map(side => [side, ports.filter(port => port.side === side).map(port => ({
112
113
  port,
113
114
  label: port.label ? textBlock(labelLines(port.label, port.accent ? 'accent' : undefined), font) : undefined
@@ -126,7 +127,7 @@ function portGeometry(ports, tokens) {
126
127
  const count = bySide.get(side).length;
127
128
  if (count === 0) return 0;
128
129
  const labelLength = side === 'top' || side === 'bottom' ? widest(side) : tallest(side);
129
- const pitch = Math.max(tokens.PORT_SPACING, labelLength + tokens.LABEL_GAP);
130
+ const pitch = Math.max(LAYOUT_TOKENS.PORT_SPACING, labelLength + LAYOUT_TOKENS.LABEL_GAP);
130
131
  return (count + 1) * pitch;
131
132
  };
132
133
  return {
@@ -154,6 +155,11 @@ function portGeometry(ports, tokens) {
154
155
  };
155
156
  }
156
157
 
158
+ /** A group's ports sit evenly along their side of its rect, like a node's ports along its frame. */
159
+ export function placeGroupPorts(ports, rect) {
160
+ return portGeometry(ports).place(rect);
161
+ }
162
+
157
163
  /** The point `fraction` of the way along `side` of `box`. */
158
164
  function portPoint(box, side, fraction) {
159
165
  switch (side) {
@@ -193,13 +199,13 @@ function placePortLabel(label, point, side) {
193
199
  }
194
200
 
195
201
  /** The back frames of a stack, farthest first, each one STACK_STEP further in the stack direction. */
196
- function stackFrames(node, box, tokens) {
202
+ function stackFrames(node, box) {
197
203
  const count = Math.max(1, Math.floor(node.stack ?? 1));
198
204
  const kind = node.kind ?? 'node';
199
205
  if (count === 1 || kind !== 'node' || node.frame === 'none') return [];
200
206
  const direction = node.stackDirection ?? 'up-left';
201
- const dx = (direction.endsWith('left') ? -1 : 1) * tokens.STACK_STEP.x;
202
- const dy = (direction.startsWith('up') ? -1 : 1) * tokens.STACK_STEP.y;
207
+ const dx = (direction.endsWith('left') ? -1 : 1) * LAYOUT_TOKENS.STACK_STEP.x;
208
+ const dy = (direction.startsWith('up') ? -1 : 1) * LAYOUT_TOKENS.STACK_STEP.y;
203
209
  return Array.from({
204
210
  length: count - 1
205
211
  }, (_, index) => {
@@ -213,8 +219,8 @@ function stackFrames(node, box, tokens) {
213
219
  }
214
220
 
215
221
  /** The caption sits beside `box`, the frame together with its stacked back frames. */
216
- function placeCaption(node, box, tokens) {
217
- const font = tokens.fonts.caption;
222
+ function placeCaption(node, box) {
223
+ const font = LAYOUT_TOKENS.fonts.caption;
218
224
  const lines = textBlock(labelLines([node.caption ?? []].flat().map(line => line.trim()), node.captionColor), font);
219
225
  if (lines.h === 0) return undefined;
220
226
  const framed = node.captionFrame ?? false;
@@ -227,7 +233,7 @@ function placeCaption(node, box, tokens) {
227
233
  };
228
234
  const w = lines.w + 2 * pad.x;
229
235
  const h = lines.h + 2 * pad.y;
230
- const gap = tokens.CAPTION_GAP;
236
+ const gap = LAYOUT_TOKENS.CAPTION_GAP;
231
237
  const side = node.captionSide ?? 'bottom';
232
238
  const centreX = box.x + (box.w - w) / 2;
233
239
  const centreY = box.y + (box.h - h) / 2;
@@ -272,9 +278,9 @@ function placeCaption(node, box, tokens) {
272
278
  text
273
279
  };
274
280
  }
275
- export function measureGroupTitle(group, tokens) {
276
- const lines = textBlock(labelLines(group.label), tokens.fonts.groupLabel);
277
- const height = lines.h > 0 ? lines.h + 2 * tokens.BAND_PAD : 0;
281
+ export function measureGroupTitle(group) {
282
+ const lines = textBlock(labelLines(group.label), LAYOUT_TOKENS.fonts.groupLabel);
283
+ const height = lines.h > 0 ? lines.h + 2 * LAYOUT_TOKENS.BAND_PAD : 0;
278
284
  return {
279
285
  height,
280
286
  place(rect) {
@@ -282,13 +288,13 @@ export function measureGroupTitle(group, tokens) {
282
288
  label: []
283
289
  };
284
290
  const y = group.labelSide === 'bottom' ? rect.y + rect.h - height : rect.y;
285
- const top = y + tokens.BAND_PAD;
291
+ const top = y + LAYOUT_TOKENS.BAND_PAD;
286
292
  const align = group.labelAlign ?? 'center';
287
293
  let label;
288
294
  if (align === 'start') {
289
- label = lines.place(rect.x + tokens.PAD_X, top, 'start');
295
+ label = lines.place(rect.x + LAYOUT_TOKENS.PAD_X, top, 'start');
290
296
  } else if (align === 'end') {
291
- label = lines.place(rect.x + rect.w - tokens.PAD_X, top, 'end');
297
+ label = lines.place(rect.x + rect.w - LAYOUT_TOKENS.PAD_X, top, 'end');
292
298
  } else {
293
299
  label = lines.place(rect.x + rect.w / 2, top, 'middle');
294
300
  }
@@ -306,8 +312,8 @@ export function measureGroupTitle(group, tokens) {
306
312
  }
307
313
  };
308
314
  }
309
- export function measureEdgeLabel(edge, tokens) {
310
- const lines = textBlock(labelLines(edge.label), tokens.fonts.edgeLabel);
315
+ export function measureEdgeLabel(edge) {
316
+ const lines = textBlock(labelLines(edge.label), LAYOUT_TOKENS.fonts.edgeLabel);
311
317
  const pad = edge.labelFrame ? EDGE_LABEL_FRAME_PAD : 0;
312
318
  return {
313
319
  w: lines.w + 2 * pad,
@@ -315,10 +321,10 @@ export function measureEdgeLabel(edge, tokens) {
315
321
  place: box => lines.place(box.x + box.w / 2, box.y + pad, 'middle')
316
322
  };
317
323
  }
318
- export function measureEdgeBadge(edge, tokens) {
319
- const lines = textBlock(labelLines(edge.badgeLabel), tokens.fonts.badge);
320
- const icon = edge.badgeIcon ? tokens.BADGE_ICON : 0;
321
- const gap = icon > 0 && lines.w > 0 ? tokens.BLOCK_GAP : 0;
324
+ export function measureEdgeBadge(edge) {
325
+ const lines = textBlock(labelLines(edge.badgeLabel), LAYOUT_TOKENS.fonts.badge);
326
+ const icon = edge.badgeIcon ? LAYOUT_TOKENS.BADGE_ICON : 0;
327
+ const gap = icon > 0 && lines.w > 0 ? LAYOUT_TOKENS.BLOCK_GAP : 0;
322
328
  const rowW = icon + gap + lines.w;
323
329
  return {
324
330
  w: Math.max(BADGE_MIN_CONTENT, rowW) + 2 * BADGE_PAD.x,
@@ -1 +1 @@
1
- {"version":3,"file":"measure.js","names":["nodeContent","labelLines","textBlock","PORT_LABEL_OFFSET","EDGE_LABEL_FRAME_PAD","BADGE_PAD","x","y","BADGE_MIN_CONTENT","SIDES","measureNode","node","tokens","kind","hidden","hiddenNode","content","ports","portGeometry","w","Math","max","pad","inset","left","right","minLength","top","bottom","h","place","box","inner","frames","stackFrames","caption","placeCaption","union","visual","radius","frameRadius","frame","overhang","stretch","text","bullets","min","FLAT_RADIUS","RADIUS","font","fonts","portLabel","bySide","Map","map","side","filter","port","label","accent","undefined","widest","get","tallest","labelDepth","depth","sideLength","count","length","labelLength","pitch","PORT_SPACING","LABEL_GAP","sidesOf","flatMap","onSide","index","fraction","point","portPoint","run","placePortLabel","id","floor","stack","direction","stackDirection","dx","endsWith","STACK_STEP","dy","startsWith","Array","from","_","level","lines","flat","line","trim","captionColor","framed","captionFrame","size","gap","CAPTION_GAP","captionSide","centreX","centreY","captionBox","measureGroupTitle","group","groupLabel","height","BAND_PAD","rect","labelSide","align","labelAlign","PAD_X","titleBand","band","measureEdgeLabel","edge","edgeLabel","labelFrame","measureEdgeBadge","badgeLabel","badge","icon","badgeIcon","BADGE_ICON","BLOCK_GAP","rowW","cy","value","by","boxes"],"sources":["../../../../src/lib/layouts/graph/measure.ts"],"sourcesContent":["import type {\n Box,\n DiagramEdge,\n DiagramGroup,\n DiagramNode,\n DiagramNodePort,\n DiagramSide,\n} from '../../model/diagram-ir.ts';\nimport type { NodeLayout, TextRun } from './graph-layout-result.ts';\nimport { nodeContent } from './node-content.ts';\nimport { type TextBlock, labelLines, textBlock } from './text-block.ts';\nimport type { LayoutTokens } from './tokens.ts';\n\ntype Sides = Record<DiagramSide, number>;\n\nexport type MeasuredNode = {\n /** The smallest frame that holds the node's content. */\n frame: { w: number; h: number };\n /** How far the stacked frames and the caption reach outside the frame. */\n overhang: Sides;\n /** Whether the frame grows to fill its grid area. */\n stretch: boolean;\n /** Positions everything the node draws, given its final frame (at least `frame`). */\n place(box: Box): Omit<NodeLayout, 'node'>;\n};\n\n/** The distance from a port's point to its label: the port marker's radius plus a gap. */\nconst PORT_LABEL_OFFSET = 8;\nconst EDGE_LABEL_FRAME_PAD = 4;\n/** Mirrors the badge drawn before content sizing: 8px side inset, 6px above and below, 24px content at least. */\nconst BADGE_PAD = { x: 8, y: 6 };\nconst BADGE_MIN_CONTENT = 24;\n\nconst SIDES: DiagramSide[] = ['top', 'right', 'bottom', 'left'];\n\nexport function measureNode(\n node: DiagramNode,\n tokens: LayoutTokens,\n): MeasuredNode {\n const kind = node.kind ?? 'node';\n if (node.hidden && kind === 'node') return hiddenNode();\n\n const content = nodeContent(node, tokens);\n const ports = portGeometry(node.ports ?? [], tokens);\n const w = Math.max(\n content.w + 2 * content.pad.x + ports.inset.left + ports.inset.right,\n ports.minLength.top,\n ports.minLength.bottom,\n );\n const h = Math.max(\n content.h + 2 * content.pad.y + ports.inset.top + ports.inset.bottom,\n ports.minLength.left,\n ports.minLength.right,\n );\n\n const place = (box: Box): Omit<NodeLayout, 'node'> => {\n const inner = inset(inset(box, ports.inset), {\n top: content.pad.y,\n bottom: content.pad.y,\n left: content.pad.x,\n right: content.pad.x,\n });\n const frames = stackFrames(node, box, tokens);\n const caption = placeCaption(node, union([box, ...frames]), tokens);\n return {\n box,\n visual: union([box, ...frames, ...(caption ? [caption.box] : [])]),\n frames,\n radius: frameRadius(node, box, tokens),\n ...content.place(inner),\n ...(caption ? { caption } : {}),\n ports: ports.place(box),\n };\n };\n\n const { visual } = place({ x: 0, y: 0, w, h });\n return {\n frame: { w, h },\n overhang: {\n top: 0 - visual.y,\n left: 0 - visual.x,\n bottom: visual.y + visual.h - h,\n right: visual.x + visual.w - w,\n },\n stretch: kind === 'node' && (node.stretch ?? true),\n place,\n };\n}\n\nfunction hiddenNode(): MeasuredNode {\n return {\n frame: { w: 0, h: 0 },\n overhang: { top: 0, right: 0, bottom: 0, left: 0 },\n stretch: false,\n place: (box) => ({\n box,\n visual: box,\n frames: [],\n radius: 0,\n text: [],\n bullets: [],\n ports: [],\n }),\n };\n}\n\nfunction frameRadius(\n node: DiagramNode,\n box: Box,\n tokens: LayoutTokens,\n): number {\n switch (node.kind) {\n case 'connector':\n return box.h / 2;\n case 'junction':\n return Math.min(box.w, box.h) / 2;\n case 'marker':\n case 'appliance':\n case 'note':\n return 0;\n default:\n if (node.frame === 'none') return 0;\n return node.frame === 'flat' ? tokens.FLAT_RADIUS : tokens.RADIUS;\n }\n}\n\n/**\n * Ports sit evenly along their side, with their labels inside the frame. A\n * side's labels push the content inward, and a side with k ports is long\n * enough for k + 1 port spacings.\n */\nfunction portGeometry(ports: DiagramNodePort[], tokens: LayoutTokens) {\n const font = tokens.fonts.portLabel;\n const bySide = new Map(\n SIDES.map((side) => [\n side,\n ports\n .filter((port) => port.side === side)\n .map((port) => ({\n port,\n label: port.label\n ? textBlock(\n labelLines(port.label, port.accent ? 'accent' : undefined),\n font,\n )\n : undefined,\n })),\n ]),\n );\n const widest = (side: DiagramSide) =>\n Math.max(0, ...bySide.get(side)!.map(({ label }) => label?.w ?? 0));\n const tallest = (side: DiagramSide) =>\n Math.max(0, ...bySide.get(side)!.map(({ label }) => label?.h ?? 0));\n const labelDepth = (side: DiagramSide) => {\n const depth =\n side === 'left' || side === 'right' ? widest(side) : tallest(side);\n return depth > 0 ? PORT_LABEL_OFFSET + depth : 0;\n };\n const sideLength = (side: DiagramSide) => {\n const count = bySide.get(side)!.length;\n if (count === 0) return 0;\n const labelLength =\n side === 'top' || side === 'bottom' ? widest(side) : tallest(side);\n const pitch = Math.max(tokens.PORT_SPACING, labelLength + tokens.LABEL_GAP);\n return (count + 1) * pitch;\n };\n\n return {\n inset: sidesOf(labelDepth),\n minLength: sidesOf(sideLength),\n place: (box: Box): NodeLayout['ports'] =>\n SIDES.flatMap((side) => {\n const onSide = bySide.get(side)!;\n return onSide.map(({ port, label }, index) => {\n const fraction = (index + 1) / (onSide.length + 1);\n const point = portPoint(box, side, fraction);\n const run = label && placePortLabel(label, point, side)[0];\n return {\n id: port.id,\n side,\n point,\n ...(run ? { label: run } : {}),\n };\n });\n }),\n };\n}\n\n/** The point `fraction` of the way along `side` of `box`. */\nfunction portPoint(\n box: Box,\n side: DiagramSide,\n fraction: number,\n): { x: number; y: number } {\n switch (side) {\n case 'top':\n return { x: box.x + box.w * fraction, y: box.y };\n case 'bottom':\n return { x: box.x + box.w * fraction, y: box.y + box.h };\n case 'left':\n return { x: box.x, y: box.y + box.h * fraction };\n case 'right':\n return { x: box.x + box.w, y: box.y + box.h * fraction };\n }\n}\n\nfunction placePortLabel(\n label: TextBlock,\n point: { x: number; y: number },\n side: DiagramSide,\n): TextRun[] {\n switch (side) {\n case 'left':\n return label.place(\n point.x + PORT_LABEL_OFFSET,\n point.y - label.h / 2,\n 'start',\n );\n case 'right':\n return label.place(\n point.x - PORT_LABEL_OFFSET,\n point.y - label.h / 2,\n 'end',\n );\n case 'top':\n return label.place(point.x, point.y + PORT_LABEL_OFFSET, 'middle');\n case 'bottom':\n return label.place(\n point.x,\n point.y - PORT_LABEL_OFFSET - label.h,\n 'middle',\n );\n }\n}\n\n/** The back frames of a stack, farthest first, each one STACK_STEP further in the stack direction. */\nfunction stackFrames(node: DiagramNode, box: Box, tokens: LayoutTokens): Box[] {\n const count = Math.max(1, Math.floor(node.stack ?? 1));\n const kind = node.kind ?? 'node';\n if (count === 1 || kind !== 'node' || node.frame === 'none') return [];\n const direction = node.stackDirection ?? 'up-left';\n const dx = (direction.endsWith('left') ? -1 : 1) * tokens.STACK_STEP.x;\n const dy = (direction.startsWith('up') ? -1 : 1) * tokens.STACK_STEP.y;\n return Array.from({ length: count - 1 }, (_, index) => {\n const level = count - 1 - index;\n return { ...box, x: box.x + level * dx, y: box.y + level * dy };\n });\n}\n\n/** The caption sits beside `box`, the frame together with its stacked back frames. */\nfunction placeCaption(\n node: DiagramNode,\n box: Box,\n tokens: LayoutTokens,\n): NodeLayout['caption'] {\n const font = tokens.fonts.caption;\n const lines = textBlock(\n labelLines(\n [node.caption ?? []].flat().map((line) => line.trim()),\n node.captionColor,\n ),\n font,\n );\n if (lines.h === 0) return undefined;\n const framed = node.captionFrame ?? false;\n const pad = framed\n ? { x: 0.9 * font.size, y: 0.55 * font.size }\n : { x: 0, y: 0 };\n const w = lines.w + 2 * pad.x;\n const h = lines.h + 2 * pad.y;\n const gap = tokens.CAPTION_GAP;\n const side = node.captionSide ?? 'bottom';\n const centreX = box.x + (box.w - w) / 2;\n const centreY = box.y + (box.h - h) / 2;\n const captionBox: Box = {\n top: { x: centreX, y: box.y - gap - h, w, h },\n bottom: { x: centreX, y: box.y + box.h + gap, w, h },\n left: { x: box.x - gap - w, y: centreY, w, h },\n right: { x: box.x + box.w + gap, y: centreY, w, h },\n }[side];\n const top = captionBox.y + pad.y;\n let text: TextRun[];\n if (side === 'left') {\n text = lines.place(captionBox.x + w - pad.x, top, 'end');\n } else if (side === 'right') {\n text = lines.place(captionBox.x + pad.x, top, 'start');\n } else {\n text = lines.place(captionBox.x + w / 2, top, 'middle');\n }\n return { box: captionBox, framed, text };\n}\n\nexport type MeasuredGroupTitle = {\n /** The height the title reserves on its side, BAND_PAD above and below included; 0 without a label. */\n height: number;\n place(rect: Box): { band?: Box; label: TextRun[] };\n};\n\nexport function measureGroupTitle(\n group: DiagramGroup,\n tokens: LayoutTokens,\n): MeasuredGroupTitle {\n const lines = textBlock(labelLines(group.label), tokens.fonts.groupLabel);\n const height = lines.h > 0 ? lines.h + 2 * tokens.BAND_PAD : 0;\n return {\n height,\n place(rect) {\n if (height === 0) return { label: [] };\n const y =\n group.labelSide === 'bottom' ? rect.y + rect.h - height : rect.y;\n const top = y + tokens.BAND_PAD;\n const align = group.labelAlign ?? 'center';\n let label: TextRun[];\n if (align === 'start') {\n label = lines.place(rect.x + tokens.PAD_X, top, 'start');\n } else if (align === 'end') {\n label = lines.place(rect.x + rect.w - tokens.PAD_X, top, 'end');\n } else {\n label = lines.place(rect.x + rect.w / 2, top, 'middle');\n }\n return group.titleBand\n ? { band: { x: rect.x, y, w: rect.w, h: height }, label }\n : { label };\n },\n };\n}\n\nexport type MeasuredEdgeLabel = {\n w: number;\n h: number;\n place(box: Box): TextRun[];\n};\n\nexport function measureEdgeLabel(\n edge: DiagramEdge,\n tokens: LayoutTokens,\n): MeasuredEdgeLabel {\n const lines = textBlock(labelLines(edge.label), tokens.fonts.edgeLabel);\n const pad = edge.labelFrame ? EDGE_LABEL_FRAME_PAD : 0;\n return {\n w: lines.w + 2 * pad,\n h: lines.h + 2 * pad,\n place: (box) => lines.place(box.x + box.w / 2, box.y + pad, 'middle'),\n };\n}\n\nexport type MeasuredEdgeBadge = {\n w: number;\n h: number;\n place(box: Box): { icon?: Box; text: TextRun[] };\n};\n\nexport function measureEdgeBadge(\n edge: DiagramEdge,\n tokens: LayoutTokens,\n): MeasuredEdgeBadge {\n const lines = textBlock(labelLines(edge.badgeLabel), tokens.fonts.badge);\n const icon = edge.badgeIcon ? tokens.BADGE_ICON : 0;\n const gap = icon > 0 && lines.w > 0 ? tokens.BLOCK_GAP : 0;\n const rowW = icon + gap + lines.w;\n return {\n w: Math.max(BADGE_MIN_CONTENT, rowW) + 2 * BADGE_PAD.x,\n h: Math.max(BADGE_MIN_CONTENT, lines.h) + 2 * BADGE_PAD.y,\n place(box) {\n const x = box.x + (box.w - rowW) / 2;\n const cy = box.y + box.h / 2;\n const text = lines.place(x + icon + gap, cy - lines.h / 2, 'start');\n return icon > 0\n ? { icon: { x, y: cy - icon / 2, w: icon, h: icon }, text }\n : { text };\n },\n };\n}\n\nfunction sidesOf(value: (side: DiagramSide) => number): Sides {\n return {\n top: value('top'),\n right: value('right'),\n bottom: value('bottom'),\n left: value('left'),\n };\n}\n\nfunction inset(box: Box, by: Sides): Box {\n return {\n x: box.x + by.left,\n y: box.y + by.top,\n w: box.w - by.left - by.right,\n h: box.h - by.top - by.bottom,\n };\n}\n\nfunction union(boxes: Box[]): Box {\n const left = Math.min(...boxes.map((box) => box.x));\n const top = Math.min(...boxes.map((box) => box.y));\n const right = Math.max(...boxes.map((box) => box.x + box.w));\n const bottom = Math.max(...boxes.map((box) => box.y + box.h));\n return { x: left, y: top, w: right - left, h: bottom - top };\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"measure.js","names":["nodeContent","labelLines","textBlock","LAYOUT_TOKENS","PORT_LABEL_OFFSET","EDGE_LABEL_FRAME_PAD","BADGE_PAD","x","y","BADGE_MIN_CONTENT","SIDES","measureNode","node","kind","hidden","hiddenNode","content","ports","portGeometry","w","Math","max","pad","inset","left","right","minLength","top","bottom","h","place","box","inner","frames","stackFrames","caption","placeCaption","union","visual","radius","frameRadius","frame","overhang","stretch","text","bullets","min","FLAT_RADIUS","RADIUS","font","fonts","portLabel","bySide","Map","map","side","filter","port","label","accent","undefined","widest","get","tallest","labelDepth","depth","sideLength","count","length","labelLength","pitch","PORT_SPACING","LABEL_GAP","sidesOf","flatMap","onSide","index","fraction","point","portPoint","run","placePortLabel","id","placeGroupPorts","rect","floor","stack","direction","stackDirection","dx","endsWith","STACK_STEP","dy","startsWith","Array","from","_","level","lines","flat","line","trim","captionColor","framed","captionFrame","size","gap","CAPTION_GAP","captionSide","centreX","centreY","captionBox","measureGroupTitle","group","groupLabel","height","BAND_PAD","labelSide","align","labelAlign","PAD_X","titleBand","band","measureEdgeLabel","edge","edgeLabel","labelFrame","measureEdgeBadge","badgeLabel","badge","icon","badgeIcon","BADGE_ICON","BLOCK_GAP","rowW","cy","value","by","boxes"],"sources":["../../../../src/lib/layouts/graph/measure.ts"],"sourcesContent":["import type {\n Box,\n DiagramEdge,\n DiagramGroup,\n DiagramNode,\n DiagramNodePort,\n DiagramSide,\n} from '../../model/diagram-ir.ts';\nimport type { NodeLayout, TextRun } from './graph-layout-result.ts';\nimport { nodeContent } from './node-content.ts';\nimport { type TextBlock, labelLines, textBlock } from './text-block.ts';\nimport { LAYOUT_TOKENS } from './tokens.ts';\n\ntype Sides = Record<DiagramSide, number>;\n\nexport type MeasuredNode = {\n /** The smallest frame that holds the node's content. */\n frame: { w: number; h: number };\n /** How far the stacked frames and the caption reach outside the frame. */\n overhang: Sides;\n /** Whether the frame grows to fill its grid area. */\n stretch: boolean;\n /** Positions everything the node draws, given its final frame (at least `frame`). */\n place(box: Box): Omit<NodeLayout, 'node'>;\n};\n\n/** The distance from a port's point to its label: the port marker's radius plus a gap. */\nconst PORT_LABEL_OFFSET = 8;\nconst EDGE_LABEL_FRAME_PAD = 4;\n/** Mirrors the badge drawn before content sizing: 8px side inset, 6px above and below, 24px content at least. */\nconst BADGE_PAD = { x: 8, y: 6 };\nconst BADGE_MIN_CONTENT = 24;\n\nconst SIDES: DiagramSide[] = ['top', 'right', 'bottom', 'left'];\n\nexport function measureNode(node: DiagramNode): MeasuredNode {\n const kind = node.kind ?? 'node';\n if (node.hidden && kind === 'node') return hiddenNode();\n\n const content = nodeContent(node);\n const ports = portGeometry(node.ports ?? []);\n const w = Math.max(\n content.w + 2 * content.pad.x + ports.inset.left + ports.inset.right,\n ports.minLength.top,\n ports.minLength.bottom,\n );\n const h = Math.max(\n content.h + 2 * content.pad.y + ports.inset.top + ports.inset.bottom,\n ports.minLength.left,\n ports.minLength.right,\n );\n\n const place = (box: Box): Omit<NodeLayout, 'node'> => {\n const inner = inset(inset(box, ports.inset), {\n top: content.pad.y,\n bottom: content.pad.y,\n left: content.pad.x,\n right: content.pad.x,\n });\n const frames = stackFrames(node, box);\n const caption = placeCaption(node, union([box, ...frames]));\n return {\n box,\n visual: union([box, ...frames, ...(caption ? [caption.box] : [])]),\n frames,\n radius: frameRadius(node, box),\n ...content.place(inner),\n ...(caption ? { caption } : {}),\n ports: ports.place(box),\n };\n };\n\n const { visual } = place({ x: 0, y: 0, w, h });\n return {\n frame: { w, h },\n overhang: {\n top: 0 - visual.y,\n left: 0 - visual.x,\n bottom: visual.y + visual.h - h,\n right: visual.x + visual.w - w,\n },\n stretch: kind === 'node' && (node.stretch ?? true),\n place,\n };\n}\n\nfunction hiddenNode(): MeasuredNode {\n return {\n frame: { w: 0, h: 0 },\n overhang: { top: 0, right: 0, bottom: 0, left: 0 },\n stretch: false,\n place: (box) => ({\n box,\n visual: box,\n frames: [],\n radius: 0,\n text: [],\n bullets: [],\n ports: [],\n }),\n };\n}\n\nfunction frameRadius(node: DiagramNode, box: Box): number {\n switch (node.kind) {\n case 'connector':\n return box.h / 2;\n case 'junction':\n return Math.min(box.w, box.h) / 2;\n case 'marker':\n case 'appliance':\n case 'note':\n return 0;\n default:\n if (node.frame === 'none') return 0;\n return node.frame === 'flat'\n ? LAYOUT_TOKENS.FLAT_RADIUS\n : LAYOUT_TOKENS.RADIUS;\n }\n}\n\n/**\n * Ports sit evenly along their side, with their labels inside the frame. A\n * side's labels push the content inward, and a side with k ports is long\n * enough for k + 1 port spacings.\n */\nfunction portGeometry(ports: DiagramNodePort[]) {\n const font = LAYOUT_TOKENS.fonts.portLabel;\n const bySide = new Map(\n SIDES.map((side) => [\n side,\n ports\n .filter((port) => port.side === side)\n .map((port) => ({\n port,\n label: port.label\n ? textBlock(\n labelLines(port.label, port.accent ? 'accent' : undefined),\n font,\n )\n : undefined,\n })),\n ]),\n );\n const widest = (side: DiagramSide) =>\n Math.max(0, ...bySide.get(side)!.map(({ label }) => label?.w ?? 0));\n const tallest = (side: DiagramSide) =>\n Math.max(0, ...bySide.get(side)!.map(({ label }) => label?.h ?? 0));\n const labelDepth = (side: DiagramSide) => {\n const depth =\n side === 'left' || side === 'right' ? widest(side) : tallest(side);\n return depth > 0 ? PORT_LABEL_OFFSET + depth : 0;\n };\n const sideLength = (side: DiagramSide) => {\n const count = bySide.get(side)!.length;\n if (count === 0) return 0;\n const labelLength =\n side === 'top' || side === 'bottom' ? widest(side) : tallest(side);\n const pitch = Math.max(\n LAYOUT_TOKENS.PORT_SPACING,\n labelLength + LAYOUT_TOKENS.LABEL_GAP,\n );\n return (count + 1) * pitch;\n };\n\n return {\n inset: sidesOf(labelDepth),\n minLength: sidesOf(sideLength),\n place: (box: Box): NodeLayout['ports'] =>\n SIDES.flatMap((side) => {\n const onSide = bySide.get(side)!;\n return onSide.map(({ port, label }, index) => {\n const fraction = (index + 1) / (onSide.length + 1);\n const point = portPoint(box, side, fraction);\n const run = label && placePortLabel(label, point, side)[0];\n return {\n id: port.id,\n side,\n point,\n ...(run ? { label: run } : {}),\n };\n });\n }),\n };\n}\n\n/** A group's ports sit evenly along their side of its rect, like a node's ports along its frame. */\nexport function placeGroupPorts(\n ports: DiagramNodePort[],\n rect: Box,\n): NodeLayout['ports'] {\n return portGeometry(ports).place(rect);\n}\n\n/** The point `fraction` of the way along `side` of `box`. */\nfunction portPoint(\n box: Box,\n side: DiagramSide,\n fraction: number,\n): { x: number; y: number } {\n switch (side) {\n case 'top':\n return { x: box.x + box.w * fraction, y: box.y };\n case 'bottom':\n return { x: box.x + box.w * fraction, y: box.y + box.h };\n case 'left':\n return { x: box.x, y: box.y + box.h * fraction };\n case 'right':\n return { x: box.x + box.w, y: box.y + box.h * fraction };\n }\n}\n\nfunction placePortLabel(\n label: TextBlock,\n point: { x: number; y: number },\n side: DiagramSide,\n): TextRun[] {\n switch (side) {\n case 'left':\n return label.place(\n point.x + PORT_LABEL_OFFSET,\n point.y - label.h / 2,\n 'start',\n );\n case 'right':\n return label.place(\n point.x - PORT_LABEL_OFFSET,\n point.y - label.h / 2,\n 'end',\n );\n case 'top':\n return label.place(point.x, point.y + PORT_LABEL_OFFSET, 'middle');\n case 'bottom':\n return label.place(\n point.x,\n point.y - PORT_LABEL_OFFSET - label.h,\n 'middle',\n );\n }\n}\n\n/** The back frames of a stack, farthest first, each one STACK_STEP further in the stack direction. */\nfunction stackFrames(node: DiagramNode, box: Box): Box[] {\n const count = Math.max(1, Math.floor(node.stack ?? 1));\n const kind = node.kind ?? 'node';\n if (count === 1 || kind !== 'node' || node.frame === 'none') return [];\n const direction = node.stackDirection ?? 'up-left';\n const dx = (direction.endsWith('left') ? -1 : 1) * LAYOUT_TOKENS.STACK_STEP.x;\n const dy = (direction.startsWith('up') ? -1 : 1) * LAYOUT_TOKENS.STACK_STEP.y;\n return Array.from({ length: count - 1 }, (_, index) => {\n const level = count - 1 - index;\n return { ...box, x: box.x + level * dx, y: box.y + level * dy };\n });\n}\n\n/** The caption sits beside `box`, the frame together with its stacked back frames. */\nfunction placeCaption(node: DiagramNode, box: Box): NodeLayout['caption'] {\n const font = LAYOUT_TOKENS.fonts.caption;\n const lines = textBlock(\n labelLines(\n [node.caption ?? []].flat().map((line) => line.trim()),\n node.captionColor,\n ),\n font,\n );\n if (lines.h === 0) return undefined;\n const framed = node.captionFrame ?? false;\n const pad = framed\n ? { x: 0.9 * font.size, y: 0.55 * font.size }\n : { x: 0, y: 0 };\n const w = lines.w + 2 * pad.x;\n const h = lines.h + 2 * pad.y;\n const gap = LAYOUT_TOKENS.CAPTION_GAP;\n const side = node.captionSide ?? 'bottom';\n const centreX = box.x + (box.w - w) / 2;\n const centreY = box.y + (box.h - h) / 2;\n const captionBox: Box = {\n top: { x: centreX, y: box.y - gap - h, w, h },\n bottom: { x: centreX, y: box.y + box.h + gap, w, h },\n left: { x: box.x - gap - w, y: centreY, w, h },\n right: { x: box.x + box.w + gap, y: centreY, w, h },\n }[side];\n const top = captionBox.y + pad.y;\n let text: TextRun[];\n if (side === 'left') {\n text = lines.place(captionBox.x + w - pad.x, top, 'end');\n } else if (side === 'right') {\n text = lines.place(captionBox.x + pad.x, top, 'start');\n } else {\n text = lines.place(captionBox.x + w / 2, top, 'middle');\n }\n return { box: captionBox, framed, text };\n}\n\nexport type MeasuredGroupTitle = {\n /** The height the title reserves on its side, BAND_PAD above and below included; 0 without a label. */\n height: number;\n place(rect: Box): { band?: Box; label: TextRun[] };\n};\n\nexport function measureGroupTitle(group: DiagramGroup): MeasuredGroupTitle {\n const lines = textBlock(\n labelLines(group.label),\n LAYOUT_TOKENS.fonts.groupLabel,\n );\n const height = lines.h > 0 ? lines.h + 2 * LAYOUT_TOKENS.BAND_PAD : 0;\n return {\n height,\n place(rect) {\n if (height === 0) return { label: [] };\n const y =\n group.labelSide === 'bottom' ? rect.y + rect.h - height : rect.y;\n const top = y + LAYOUT_TOKENS.BAND_PAD;\n const align = group.labelAlign ?? 'center';\n let label: TextRun[];\n if (align === 'start') {\n label = lines.place(rect.x + LAYOUT_TOKENS.PAD_X, top, 'start');\n } else if (align === 'end') {\n label = lines.place(rect.x + rect.w - LAYOUT_TOKENS.PAD_X, top, 'end');\n } else {\n label = lines.place(rect.x + rect.w / 2, top, 'middle');\n }\n return group.titleBand\n ? { band: { x: rect.x, y, w: rect.w, h: height }, label }\n : { label };\n },\n };\n}\n\nexport type MeasuredEdgeLabel = {\n w: number;\n h: number;\n place(box: Box): TextRun[];\n};\n\nexport function measureEdgeLabel(edge: DiagramEdge): MeasuredEdgeLabel {\n const lines = textBlock(\n labelLines(edge.label),\n LAYOUT_TOKENS.fonts.edgeLabel,\n );\n const pad = edge.labelFrame ? EDGE_LABEL_FRAME_PAD : 0;\n return {\n w: lines.w + 2 * pad,\n h: lines.h + 2 * pad,\n place: (box) => lines.place(box.x + box.w / 2, box.y + pad, 'middle'),\n };\n}\n\nexport type MeasuredEdgeBadge = {\n w: number;\n h: number;\n place(box: Box): { icon?: Box; text: TextRun[] };\n};\n\nexport function measureEdgeBadge(edge: DiagramEdge): MeasuredEdgeBadge {\n const lines = textBlock(\n labelLines(edge.badgeLabel),\n LAYOUT_TOKENS.fonts.badge,\n );\n const icon = edge.badgeIcon ? LAYOUT_TOKENS.BADGE_ICON : 0;\n const gap = icon > 0 && lines.w > 0 ? LAYOUT_TOKENS.BLOCK_GAP : 0;\n const rowW = icon + gap + lines.w;\n return {\n w: Math.max(BADGE_MIN_CONTENT, rowW) + 2 * BADGE_PAD.x,\n h: Math.max(BADGE_MIN_CONTENT, lines.h) + 2 * BADGE_PAD.y,\n place(box) {\n const x = box.x + (box.w - rowW) / 2;\n const cy = box.y + box.h / 2;\n const text = lines.place(x + icon + gap, cy - lines.h / 2, 'start');\n return icon > 0\n ? { icon: { x, y: cy - icon / 2, w: icon, h: icon }, text }\n : { text };\n },\n };\n}\n\nfunction sidesOf(value: (side: DiagramSide) => number): Sides {\n return {\n top: value('top'),\n right: value('right'),\n bottom: value('bottom'),\n left: value('left'),\n };\n}\n\nfunction inset(box: Box, by: Sides): Box {\n return {\n x: box.x + by.left,\n y: box.y + by.top,\n w: box.w - by.left - by.right,\n h: box.h - by.top - by.bottom,\n };\n}\n\nfunction union(boxes: Box[]): Box {\n const left = Math.min(...boxes.map((box) => box.x));\n const top = Math.min(...boxes.map((box) => box.y));\n const right = Math.max(...boxes.map((box) => box.x + box.w));\n const bottom = Math.max(...boxes.map((box) => box.y + box.h));\n return { x: left, y: top, w: right - left, h: bottom - top };\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * A binary min-heap of items by priority.
3
+ *
4
+ * Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.
5
+ */
6
+ export declare class MinHeap<T> {
7
+ #private;
8
+ get size(): number;
9
+ push(item: T, priority: number): void;
10
+ pop(): T | undefined;
11
+ }
12
+ //# sourceMappingURL=min-heap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"min-heap.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/min-heap.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,OAAO,CAAC,CAAC;;IAGpB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKrC,GAAG,IAAI,CAAC,GAAG,SAAS;CA2CrB"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * A binary min-heap of items by priority.
3
+ *
4
+ * Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.
5
+ */
6
+ export class MinHeap {
7
+ #data = [];
8
+ get size() {
9
+ return this.#data.length;
10
+ }
11
+ push(item, priority) {
12
+ this.#data.push({
13
+ item,
14
+ priority
15
+ });
16
+ this.#bubbleUp(this.#data.length - 1);
17
+ }
18
+ pop() {
19
+ const top = this.#data[0];
20
+ if (!top) return undefined;
21
+ const last = this.#data.pop();
22
+ if (this.#data.length > 0) {
23
+ this.#data[0] = last;
24
+ this.#bubbleDown(0);
25
+ }
26
+ return top.item;
27
+ }
28
+ #bubbleUp(index) {
29
+ let i = index;
30
+ while (i > 0) {
31
+ const parent = i - 1 >> 1;
32
+ const entry = this.#data[i];
33
+ const parentEntry = this.#data[parent];
34
+ if (entry.priority >= parentEntry.priority) break;
35
+ this.#data[i] = parentEntry;
36
+ this.#data[parent] = entry;
37
+ i = parent;
38
+ }
39
+ }
40
+ #bubbleDown(index) {
41
+ let i = index;
42
+ for (;;) {
43
+ const entry = this.#data[i];
44
+ let smallest = i;
45
+ let smallestEntry = entry;
46
+ for (const child of [2 * i + 1, 2 * i + 2]) {
47
+ const candidate = this.#data[child];
48
+ if (candidate && candidate.priority < smallestEntry.priority) {
49
+ smallest = child;
50
+ smallestEntry = candidate;
51
+ }
52
+ }
53
+ if (smallest === i) break;
54
+ this.#data[i] = smallestEntry;
55
+ this.#data[smallest] = entry;
56
+ i = smallest;
57
+ }
58
+ }
59
+ }
60
+ //# sourceMappingURL=min-heap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"min-heap.js","names":["MinHeap","data","size","length","push","item","priority","bubbleUp","pop","top","undefined","last","bubbleDown","#bubbleUp","index","i","parent","entry","parentEntry","#bubbleDown","smallest","smallestEntry","child","candidate"],"sources":["../../../../src/lib/layouts/graph/min-heap.ts"],"sourcesContent":["/**\n * A binary min-heap of items by priority.\n *\n * Moved from graph-layout.ts, whose copy step 6 deletes with the old engine.\n */\nexport class MinHeap<T> {\n readonly #data: { item: T; priority: number }[] = [];\n\n get size(): number {\n return this.#data.length;\n }\n\n push(item: T, priority: number): void {\n this.#data.push({ item, priority });\n this.#bubbleUp(this.#data.length - 1);\n }\n\n pop(): T | undefined {\n const top = this.#data[0];\n if (!top) return undefined;\n const last = this.#data.pop()!;\n if (this.#data.length > 0) {\n this.#data[0] = last;\n this.#bubbleDown(0);\n }\n return top.item;\n }\n\n #bubbleUp(index: number): void {\n let i = index;\n while (i > 0) {\n const parent = (i - 1) >> 1;\n const entry = this.#data[i]!;\n const parentEntry = this.#data[parent]!;\n if (entry.priority >= parentEntry.priority) break;\n this.#data[i] = parentEntry;\n this.#data[parent] = entry;\n i = parent;\n }\n }\n\n #bubbleDown(index: number): void {\n let i = index;\n for (;;) {\n const entry = this.#data[i]!;\n let smallest = i;\n let smallestEntry = entry;\n for (const child of [2 * i + 1, 2 * i + 2]) {\n const candidate = this.#data[child];\n if (candidate && candidate.priority < smallestEntry.priority) {\n smallest = child;\n smallestEntry = candidate;\n }\n }\n if (smallest === i) break;\n this.#data[i] = smallestEntry;\n this.#data[smallest] = entry;\n i = smallest;\n }\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,OAAO,CAAI;EACb,CAACC,IAAI,GAAoC,EAAE;EAEpD,IAAIC,IAAIA,CAAA,EAAW;IACjB,OAAO,IAAI,CAAC,CAACD,IAAI,CAACE,MAAM;EAC1B;EAEAC,IAAIA,CAACC,IAAO,EAAEC,QAAgB,EAAQ;IACpC,IAAI,CAAC,CAACL,IAAI,CAACG,IAAI,CAAC;MAAEC,IAAI;MAAEC;IAAS,CAAC,CAAC;IACnC,IAAI,CAAC,CAACC,QAAQ,CAAC,IAAI,CAAC,CAACN,IAAI,CAACE,MAAM,GAAG,CAAC,CAAC;EACvC;EAEAK,GAAGA,CAAA,EAAkB;IACnB,MAAMC,GAAG,GAAG,IAAI,CAAC,CAACR,IAAI,CAAC,CAAC,CAAC;IACzB,IAAI,CAACQ,GAAG,EAAE,OAAOC,SAAS;IAC1B,MAAMC,IAAI,GAAG,IAAI,CAAC,CAACV,IAAI,CAACO,GAAG,CAAC,CAAE;IAC9B,IAAI,IAAI,CAAC,CAACP,IAAI,CAACE,MAAM,GAAG,CAAC,EAAE;MACzB,IAAI,CAAC,CAACF,IAAI,CAAC,CAAC,CAAC,GAAGU,IAAI;MACpB,IAAI,CAAC,CAACC,UAAU,CAAC,CAAC,CAAC;IACrB;IACA,OAAOH,GAAG,CAACJ,IAAI;EACjB;EAEA,CAACE,QAAQM,CAACC,KAAa,EAAQ;IAC7B,IAAIC,CAAC,GAAGD,KAAK;IACb,OAAOC,CAAC,GAAG,CAAC,EAAE;MACZ,MAAMC,MAAM,GAAID,CAAC,GAAG,CAAC,IAAK,CAAC;MAC3B,MAAME,KAAK,GAAG,IAAI,CAAC,CAAChB,IAAI,CAACc,CAAC,CAAE;MAC5B,MAAMG,WAAW,GAAG,IAAI,CAAC,CAACjB,IAAI,CAACe,MAAM,CAAE;MACvC,IAAIC,KAAK,CAACX,QAAQ,IAAIY,WAAW,CAACZ,QAAQ,EAAE;MAC5C,IAAI,CAAC,CAACL,IAAI,CAACc,CAAC,CAAC,GAAGG,WAAW;MAC3B,IAAI,CAAC,CAACjB,IAAI,CAACe,MAAM,CAAC,GAAGC,KAAK;MAC1BF,CAAC,GAAGC,MAAM;IACZ;EACF;EAEA,CAACJ,UAAUO,CAACL,KAAa,EAAQ;IAC/B,IAAIC,CAAC,GAAGD,KAAK;IACb,SAAS;MACP,MAAMG,KAAK,GAAG,IAAI,CAAC,CAAChB,IAAI,CAACc,CAAC,CAAE;MAC5B,IAAIK,QAAQ,GAAGL,CAAC;MAChB,IAAIM,aAAa,GAAGJ,KAAK;MACzB,KAAK,MAAMK,KAAK,IAAI,CAAC,CAAC,GAAGP,CAAC,GAAG,CAAC,EAAE,CAAC,GAAGA,CAAC,GAAG,CAAC,CAAC,EAAE;QAC1C,MAAMQ,SAAS,GAAG,IAAI,CAAC,CAACtB,IAAI,CAACqB,KAAK,CAAC;QACnC,IAAIC,SAAS,IAAIA,SAAS,CAACjB,QAAQ,GAAGe,aAAa,CAACf,QAAQ,EAAE;UAC5Dc,QAAQ,GAAGE,KAAK;UAChBD,aAAa,GAAGE,SAAS;QAC3B;MACF;MACA,IAAIH,QAAQ,KAAKL,CAAC,EAAE;MACpB,IAAI,CAAC,CAACd,IAAI,CAACc,CAAC,CAAC,GAAGM,aAAa;MAC7B,IAAI,CAAC,CAACpB,IAAI,CAACmB,QAAQ,CAAC,GAAGH,KAAK;MAC5BF,CAAC,GAAGK,QAAQ;IACd;EACF;AACF","ignoreList":[]}
@@ -1,6 +1,5 @@
1
1
  import type { Box, DiagramNode } from '../../model/diagram-ir.ts';
2
2
  import type { NodeLayout } from './graph-layout-result.ts';
3
- import type { LayoutTokens } from './tokens.ts';
4
3
  export type ContentPlacement = Pick<NodeLayout, 'text' | 'bullets'> & Partial<Pick<NodeLayout, 'icon' | 'appliance'>>;
5
4
  /** What a node draws inside its frame: its measured size, the padding around it, and where it goes. */
6
5
  export type NodeContent = {
@@ -12,5 +11,5 @@ export type NodeContent = {
12
11
  };
13
12
  place(inner: Box): ContentPlacement;
14
13
  };
15
- export declare function nodeContent(node: DiagramNode, tokens: LayoutTokens): NodeContent;
14
+ export declare function nodeContent(node: DiagramNode): NodeContent;
16
15
  //# sourceMappingURL=node-content.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node-content.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/node-content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAS,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC,GACjE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC;AAElD,uGAAuG;AACvG,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,gBAAgB,CAAC;CACrC,CAAC;AAQF,wBAAgB,WAAW,CACzB,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,YAAY,GACnB,WAAW,CAeb"}
1
+ {"version":3,"file":"node-content.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/node-content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAS,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAI3D,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC,GACjE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC;AAElD,uGAAuG;AACvG,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,gBAAgB,CAAC;CACrC,CAAC;AAQF,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAe1D"}
@@ -1,4 +1,5 @@
1
1
  import { labelLines, textBlock } from "./text-block.js";
2
+ import { LAYOUT_TOKENS } from "./tokens.js";
2
3
 
3
4
  /** What a node draws inside its frame: its measured size, the padding around it, and where it goes. */
4
5
 
@@ -12,40 +13,40 @@ const NOTHING = {
12
13
  text: [],
13
14
  bullets: []
14
15
  };
15
- export function nodeContent(node, tokens) {
16
+ export function nodeContent(node) {
16
17
  switch (node.kind) {
17
18
  case 'junction':
18
- return junctionContent(tokens);
19
+ return junctionContent();
19
20
  case 'marker':
20
- return markerContent(node, tokens);
21
+ return markerContent(node);
21
22
  case 'connector':
22
- return connectorContent(node, tokens);
23
+ return connectorContent(node);
23
24
  case 'appliance':
24
- return applianceContent(node, tokens);
25
+ return applianceContent(node);
25
26
  case 'note':
26
- return noteContent(node, tokens);
27
+ return noteContent(node);
27
28
  default:
28
- return boxContent(node, tokens);
29
+ return boxContent(node);
29
30
  }
30
31
  }
31
- function boxContent(node, tokens) {
32
+ function boxContent(node) {
32
33
  const pad = node.frame === 'none' ? {
33
- x: tokens.LABEL_GAP,
34
- y: tokens.LABEL_GAP
34
+ x: LAYOUT_TOKENS.LABEL_GAP,
35
+ y: LAYOUT_TOKENS.LABEL_GAP
35
36
  } : {
36
- x: tokens.PAD_X,
37
- y: tokens.PAD_Y
37
+ x: LAYOUT_TOKENS.PAD_X,
38
+ y: LAYOUT_TOKENS.PAD_Y
38
39
  };
39
40
  const isCard = node.textAlign === 'start' || node.description !== undefined || (node.items?.length ?? 0) > 0;
40
41
  if (isCard) return {
41
- ...cardContent(node, tokens),
42
+ ...cardContent(node),
42
43
  pad
43
44
  };
44
45
  if (node.icon) return {
45
- ...iconRowContent(node, tokens),
46
+ ...iconRowContent(node),
46
47
  pad
47
48
  };
48
- const lines = textBlock(labelLines(node.label, node.textColor), tokens.fonts.boxLabel);
49
+ const lines = textBlock(labelLines(node.label, node.textColor), LAYOUT_TOKENS.fonts.boxLabel);
49
50
  return {
50
51
  w: lines.w,
51
52
  h: lines.h,
@@ -56,12 +57,12 @@ function boxContent(node, tokens) {
56
57
  })
57
58
  };
58
59
  }
59
- function iconRowContent(node, tokens) {
60
+ function iconRowContent(node) {
60
61
  const {
61
62
  ICON,
62
63
  ICON_GAP
63
- } = tokens;
64
- const title = textBlock(labelLines(node.label, node.textColor), tokens.fonts.title);
64
+ } = LAYOUT_TOKENS;
65
+ const title = textBlock(labelLines(node.label, node.textColor), LAYOUT_TOKENS.fonts.title);
65
66
  const w = title.w > 0 ? ICON + ICON_GAP + title.w : ICON;
66
67
  const h = Math.max(ICON, title.h);
67
68
  return {
@@ -82,16 +83,16 @@ function iconRowContent(node, tokens) {
82
83
  }
83
84
  };
84
85
  }
85
- function cardContent(node, tokens) {
86
+ function cardContent(node) {
86
87
  const {
87
88
  ICON,
88
89
  ICON_GAP,
89
90
  BLOCK_GAP,
90
91
  BULLET_INDENT
91
- } = tokens;
92
- const title = textBlock(labelLines(node.label, node.textColor), tokens.fonts.title);
93
- const description = textBlock(labelLines(node.description, node.textColor), tokens.fonts.body);
94
- const items = textBlock(labelLines(node.items, node.textColor), tokens.fonts.body);
92
+ } = LAYOUT_TOKENS;
93
+ const title = textBlock(labelLines(node.label, node.textColor), LAYOUT_TOKENS.fonts.title);
94
+ const description = textBlock(labelLines(node.description, node.textColor), LAYOUT_TOKENS.fonts.body);
95
+ const items = textBlock(labelLines(node.items, node.textColor), LAYOUT_TOKENS.fonts.body);
95
96
  let iconW = 0;
96
97
  if (node.icon) iconW = title.w > 0 ? ICON + ICON_GAP : ICON;
97
98
  const headerH = Math.max(node.icon ? ICON : 0, title.h);
@@ -105,7 +106,7 @@ function cardContent(node, tokens) {
105
106
  h: items.h,
106
107
  w: items.h > 0 ? BULLET_INDENT + items.w : 0
107
108
  }].filter(section => section.h > 0);
108
- const bulletRise = tokens.fonts.body.size * 0.3;
109
+ const bulletRise = LAYOUT_TOKENS.fonts.body.size * 0.3;
109
110
  return {
110
111
  w: Math.max(0, ...sections.map(section => section.w)),
111
112
  h: sections.reduce((sum, section) => sum + section.h, 0) + Math.max(0, sections.length - 1) * BLOCK_GAP,
@@ -137,14 +138,14 @@ function cardContent(node, tokens) {
137
138
  }
138
139
  };
139
140
  }
140
- function noteContent(node, tokens) {
141
- const lines = textBlock(labelLines(node.label, node.textColor ?? 'dim'), tokens.fonts.note);
141
+ function noteContent(node) {
142
+ const lines = textBlock(labelLines(node.label, node.textColor ?? 'dim'), LAYOUT_TOKENS.fonts.note);
142
143
  return {
143
144
  w: lines.w,
144
145
  h: lines.h,
145
146
  pad: {
146
- x: tokens.LABEL_GAP,
147
- y: tokens.LABEL_GAP
147
+ x: LAYOUT_TOKENS.LABEL_GAP,
148
+ y: LAYOUT_TOKENS.LABEL_GAP
148
149
  },
149
150
  place: inner => ({
150
151
  text: lines.place(inner.x, inner.y, 'start'),
@@ -152,20 +153,20 @@ function noteContent(node, tokens) {
152
153
  })
153
154
  };
154
155
  }
155
- function markerContent(node, tokens) {
156
+ function markerContent(node) {
156
157
  const {
157
158
  MARKER_ICON,
158
159
  BLOCK_GAP
159
- } = tokens;
160
- const lines = textBlock(labelLines(node.label, node.textColor), tokens.fonts.marker);
160
+ } = LAYOUT_TOKENS;
161
+ const lines = textBlock(labelLines(node.label, node.textColor), LAYOUT_TOKENS.fonts.marker);
161
162
  const gap = lines.h > 0 ? BLOCK_GAP : 0;
162
163
  const h = MARKER_ICON + gap + lines.h;
163
164
  return {
164
165
  w: Math.max(MARKER_ICON, lines.w),
165
166
  h,
166
167
  pad: {
167
- x: tokens.LABEL_GAP,
168
- y: tokens.LABEL_GAP
168
+ x: LAYOUT_TOKENS.LABEL_GAP,
169
+ y: LAYOUT_TOKENS.LABEL_GAP
169
170
  },
170
171
  place: inner => {
171
172
  const top = centredTop(inner, h);
@@ -182,12 +183,12 @@ function markerContent(node, tokens) {
182
183
  }
183
184
  };
184
185
  }
185
- function connectorContent(node, tokens) {
186
+ function connectorContent(node) {
186
187
  const {
187
188
  CONNECTOR_ICON,
188
189
  BLOCK_GAP
189
- } = tokens;
190
- const lines = textBlock(labelLines(node.label, node.textColor), tokens.fonts.connector);
190
+ } = LAYOUT_TOKENS;
191
+ const lines = textBlock(labelLines(node.label, node.textColor), LAYOUT_TOKENS.fonts.connector);
191
192
  const iconW = node.icon ? CONNECTOR_ICON + (lines.w > 0 ? BLOCK_GAP : 0) : 0;
192
193
  const h = Math.max(CONNECTOR_MIN_HEIGHT - 2 * CONNECTOR_PAD.y, lines.h);
193
194
  return {
@@ -215,10 +216,10 @@ function connectorContent(node, tokens) {
215
216
  }
216
217
  };
217
218
  }
218
- function junctionContent(tokens) {
219
+ function junctionContent() {
219
220
  return {
220
- w: tokens.JUNCTION,
221
- h: tokens.JUNCTION,
221
+ w: LAYOUT_TOKENS.JUNCTION,
222
+ h: LAYOUT_TOKENS.JUNCTION,
222
223
  pad: {
223
224
  x: 0,
224
225
  y: 0
@@ -226,12 +227,12 @@ function junctionContent(tokens) {
226
227
  place: () => NOTHING
227
228
  };
228
229
  }
229
- function applianceContent(node, tokens) {
230
+ function applianceContent(node) {
230
231
  const {
231
232
  APPLIANCE,
232
233
  LABEL_GAP
233
- } = tokens;
234
- const lines = textBlock(labelLines(node.label, node.textColor), tokens.fonts.appliance);
234
+ } = LAYOUT_TOKENS;
235
+ const lines = textBlock(labelLines(node.label, node.textColor), LAYOUT_TOKENS.fonts.appliance);
235
236
  return {
236
237
  w: Math.max(APPLIANCE.w, lines.w + 2 * LABEL_GAP),
237
238
  h: APPLIANCE.h + (lines.h > 0 ? lines.h + LABEL_GAP : 0),