@zukhruf/diagram 0.3.33 → 0.3.35

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 (117) hide show
  1. package/README.md +98 -52
  2. package/dist/index.d.ts +5 -3
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/compiler/diagram-compile.d.ts +3 -4
  7. package/dist/lib/compiler/diagram-compile.d.ts.map +1 -1
  8. package/dist/lib/compiler/diagram-compile.js +85 -370
  9. package/dist/lib/compiler/diagram-compile.js.map +1 -1
  10. package/dist/lib/layouts/graph/attach.d.ts.map +1 -1
  11. package/dist/lib/layouts/graph/attach.js +64 -8
  12. package/dist/lib/layouts/graph/attach.js.map +1 -1
  13. package/dist/lib/layouts/graph/connections.d.ts +11 -4
  14. package/dist/lib/layouts/graph/connections.d.ts.map +1 -1
  15. package/dist/lib/layouts/graph/connections.js +43 -17
  16. package/dist/lib/layouts/graph/connections.js.map +1 -1
  17. package/dist/lib/layouts/graph/graph-layout-result.d.ts +4 -2
  18. package/dist/lib/layouts/graph/graph-layout-result.d.ts.map +1 -1
  19. package/dist/lib/layouts/graph/graph-layout-result.js.map +1 -1
  20. package/dist/lib/layouts/graph/gutters.js +40 -21
  21. package/dist/lib/layouts/graph/gutters.js.map +1 -1
  22. package/dist/lib/layouts/graph/labels.d.ts +16 -9
  23. package/dist/lib/layouts/graph/labels.d.ts.map +1 -1
  24. package/dist/lib/layouts/graph/labels.js +62 -18
  25. package/dist/lib/layouts/graph/labels.js.map +1 -1
  26. package/dist/lib/layouts/graph/layout.d.ts +1 -1
  27. package/dist/lib/layouts/graph/layout.d.ts.map +1 -1
  28. package/dist/lib/layouts/graph/layout.js +6 -3
  29. package/dist/lib/layouts/graph/layout.js.map +1 -1
  30. package/dist/lib/layouts/graph/measure.d.ts +8 -5
  31. package/dist/lib/layouts/graph/measure.d.ts.map +1 -1
  32. package/dist/lib/layouts/graph/measure.js +47 -9
  33. package/dist/lib/layouts/graph/measure.js.map +1 -1
  34. package/dist/lib/layouts/graph/min-heap.d.ts +1 -5
  35. package/dist/lib/layouts/graph/min-heap.d.ts.map +1 -1
  36. package/dist/lib/layouts/graph/min-heap.js +1 -5
  37. package/dist/lib/layouts/graph/min-heap.js.map +1 -1
  38. package/dist/lib/layouts/graph/node-content.d.ts +1 -1
  39. package/dist/lib/layouts/graph/node-content.d.ts.map +1 -1
  40. package/dist/lib/layouts/graph/node-content.js +26 -7
  41. package/dist/lib/layouts/graph/node-content.js.map +1 -1
  42. package/dist/lib/layouts/graph/path.d.ts +2 -10
  43. package/dist/lib/layouts/graph/path.d.ts.map +1 -1
  44. package/dist/lib/layouts/graph/path.js +11 -13
  45. package/dist/lib/layouts/graph/path.js.map +1 -1
  46. package/dist/lib/layouts/graph/round.d.ts +11 -0
  47. package/dist/lib/layouts/graph/round.d.ts.map +1 -0
  48. package/dist/lib/layouts/graph/round.js +181 -0
  49. package/dist/lib/layouts/graph/round.js.map +1 -0
  50. package/dist/lib/layouts/graph/route.d.ts +10 -6
  51. package/dist/lib/layouts/graph/route.d.ts.map +1 -1
  52. package/dist/lib/layouts/graph/route.js +68 -33
  53. package/dist/lib/layouts/graph/route.js.map +1 -1
  54. package/dist/lib/layouts/graph/sides.d.ts +10 -5
  55. package/dist/lib/layouts/graph/sides.d.ts.map +1 -1
  56. package/dist/lib/layouts/graph/sides.js +14 -7
  57. package/dist/lib/layouts/graph/sides.js.map +1 -1
  58. package/dist/lib/layouts/timeline/timeline-layout.d.ts +2 -1
  59. package/dist/lib/layouts/timeline/timeline-layout.d.ts.map +1 -1
  60. package/dist/lib/layouts/timeline/timeline-layout.js +9 -4
  61. package/dist/lib/layouts/timeline/timeline-layout.js.map +1 -1
  62. package/dist/lib/model/diagram-ir.d.ts +19 -156
  63. package/dist/lib/model/diagram-ir.d.ts.map +1 -1
  64. package/dist/lib/model/diagram-ir.js.map +1 -1
  65. package/dist/lib/model/validate-graph.d.ts +7 -0
  66. package/dist/lib/model/validate-graph.d.ts.map +1 -0
  67. package/dist/lib/model/validate-graph.js +54 -0
  68. package/dist/lib/model/validate-graph.js.map +1 -0
  69. package/dist/lib/react/Diagram.d.ts +3 -9
  70. package/dist/lib/react/Diagram.d.ts.map +1 -1
  71. package/dist/lib/react/Diagram.js +1 -13
  72. package/dist/lib/react/Diagram.js.map +1 -1
  73. package/dist/lib/react/diagram-types.d.ts +17 -46
  74. package/dist/lib/react/diagram-types.d.ts.map +1 -1
  75. package/dist/lib/react/diagram-types.js.map +1 -1
  76. package/dist/lib/renderers/canvas/graph-canvas.d.ts +2 -5
  77. package/dist/lib/renderers/canvas/graph-canvas.d.ts.map +1 -1
  78. package/dist/lib/renderers/canvas/graph-canvas.js +68 -43
  79. package/dist/lib/renderers/canvas/graph-canvas.js.map +1 -1
  80. package/dist/lib/renderers/html/graph-html.d.ts +2 -3
  81. package/dist/lib/renderers/html/graph-html.d.ts.map +1 -1
  82. package/dist/lib/renderers/html/graph-html.js +298 -289
  83. package/dist/lib/renderers/html/graph-html.js.map +1 -1
  84. package/dist/lib/renderers/shared/graph-parts.d.ts +3 -1
  85. package/dist/lib/renderers/shared/graph-parts.d.ts.map +1 -1
  86. package/dist/lib/renderers/shared/graph-parts.js +350 -418
  87. package/dist/lib/renderers/shared/graph-parts.js.map +1 -1
  88. package/dist/lib/renderers/shared/node-parts.d.ts +5 -6
  89. package/dist/lib/renderers/shared/node-parts.d.ts.map +1 -1
  90. package/dist/lib/renderers/shared/node-parts.js +112 -190
  91. package/dist/lib/renderers/shared/node-parts.js.map +1 -1
  92. package/dist/lib/renderers/shared/run-spans.js +2 -2
  93. package/dist/lib/renderers/shared/run-spans.js.map +1 -1
  94. package/dist/lib/renderers/shared/text-runs.d.ts +0 -6
  95. package/dist/lib/renderers/shared/text-runs.d.ts.map +1 -1
  96. package/dist/lib/renderers/shared/text-runs.js +0 -12
  97. package/dist/lib/renderers/shared/text-runs.js.map +1 -1
  98. package/dist/lib/renderers/svg/graph-svg.d.ts +1 -3
  99. package/dist/lib/renderers/svg/graph-svg.d.ts.map +1 -1
  100. package/dist/lib/renderers/svg/graph-svg.js +66 -80
  101. package/dist/lib/renderers/svg/graph-svg.js.map +1 -1
  102. package/dist/lib/renderers/svg/timeline-svg.d.ts.map +1 -1
  103. package/dist/lib/renderers/svg/timeline-svg.js +7 -5
  104. package/dist/lib/renderers/svg/timeline-svg.js.map +1 -1
  105. package/package.json +1 -1
  106. package/dist/lib/layouts/graph/graph-layout.d.ts +0 -154
  107. package/dist/lib/layouts/graph/graph-layout.d.ts.map +0 -1
  108. package/dist/lib/layouts/graph/graph-layout.js +0 -2340
  109. package/dist/lib/layouts/graph/graph-layout.js.map +0 -1
  110. package/dist/lib/layouts/graph/legacy-graph-layout.d.ts +0 -6
  111. package/dist/lib/layouts/graph/legacy-graph-layout.d.ts.map +0 -1
  112. package/dist/lib/layouts/graph/legacy-graph-layout.js +0 -542
  113. package/dist/lib/layouts/graph/legacy-graph-layout.js.map +0 -1
  114. package/dist/lib/layouts/text-metrics.d.ts +0 -7
  115. package/dist/lib/layouts/text-metrics.d.ts.map +0 -1
  116. package/dist/lib/layouts/text-metrics.js +0 -40
  117. package/dist/lib/layouts/text-metrics.js.map +0 -1
@@ -1,7 +1,6 @@
1
1
  import { Children, Fragment, isValidElement } from 'react';
2
- import { parseEndpointRef } from "../model/endpoint-ref.js";
3
2
  export const DIAGRAM_PRIMITIVE = Symbol.for('@zukhruf/diagram/primitive');
4
- const PRIMITIVE_KINDS = ['node', 'box', 'card', 'port', 'label', 'float', 'phantom', 'appliance', 'connector', 'junction', 'edge', 'arrow', 'wire', 'group', 'text', 'line', 'lane', 'signal', 'frame', 'marker', 'guide', 'waypoint', 'entry', 'exit', 'content'];
3
+ const PRIMITIVE_KINDS = ['node', 'box', 'card', 'port', 'label', 'float', 'appliance', 'connector', 'junction', 'edge', 'arrow', 'wire', 'group', 'note', 'line', 'lane', 'signal', 'frame', 'marker', 'content'];
5
4
  export function primitive(kind) {
6
5
  return Object.assign(() => null, {
7
6
  [DIAGRAM_PRIMITIVE]: kind
@@ -24,24 +23,20 @@ function emptyCompileResult() {
24
23
  nodes: [],
25
24
  edges: [],
26
25
  groups: [],
27
- annotations: [],
28
26
  lanes: [],
29
27
  signals: [],
30
- frames: [],
31
- guides: []
28
+ frames: []
32
29
  };
33
30
  }
34
31
  function mergeCompileResults(target, source) {
35
32
  target.nodes.push(...source.nodes);
36
33
  target.edges.push(...source.edges);
37
34
  target.groups.push(...source.groups);
38
- target.annotations.push(...source.annotations);
39
35
  target.lanes.push(...source.lanes);
40
36
  target.signals.push(...source.signals);
41
37
  target.frames.push(...source.frames);
42
- target.guides.push(...source.guides);
43
38
  }
44
- export function compileGraph(children, layout) {
39
+ export function compileGraph(children) {
45
40
  const result = compileChildren(children, {});
46
41
  if (result.lanes.length > 0 || result.signals.length > 0 || result.frames.length > 0) {
47
42
  throw new Error('A graph diagram cannot contain Diagram.Lane, Diagram.Signal or Diagram.Frame; draw those with SvgTimelineDiagram.');
@@ -49,15 +44,12 @@ export function compileGraph(children, layout) {
49
44
  return {
50
45
  nodes: result.nodes,
51
46
  edges: result.edges,
52
- groups: result.groups,
53
- annotations: result.annotations,
54
- guides: result.guides,
55
- layout
47
+ groups: result.groups
56
48
  };
57
49
  }
58
50
  export function compileTimeline(children) {
59
51
  const result = compileChildren(children, {});
60
- if (result.nodes.length > 0 || result.edges.length > 0 || result.groups.length > 0 || result.annotations.length > 0 || result.guides.length > 0) {
52
+ if (result.nodes.length > 0 || result.edges.length > 0 || result.groups.length > 0) {
61
53
  throw new Error('A timeline diagram only accepts Diagram.Lane, Diagram.Signal and Diagram.Frame; draw other primitives with SvgGraphDiagram or CanvasGraphDiagram.');
62
54
  }
63
55
  return {
@@ -99,10 +91,6 @@ function compileChildren(children, context) {
99
91
  mergeCompileResults(result, group.children);
100
92
  return;
101
93
  }
102
- if (kind === 'text') {
103
- result.annotations.push(compileText(child));
104
- return;
105
- }
106
94
  if (kind === 'lane') {
107
95
  result.lanes.push(compileLane(child));
108
96
  return;
@@ -118,10 +106,6 @@ function compileChildren(children, context) {
118
106
  result.frames.push(compileFrame(child));
119
107
  return;
120
108
  }
121
- if (kind === 'guide') {
122
- result.guides.push(requirePrimitiveProps(child));
123
- return;
124
- }
125
109
  throw new Error(`<Diagram.${kind}> cannot be a direct child of Diagram.`);
126
110
  });
127
111
  return result;
@@ -130,7 +114,7 @@ function isTextNode(child) {
130
114
  return typeof child === 'string' || typeof child === 'number';
131
115
  }
132
116
  function isNodeKind(kind) {
133
- return kind === 'node' || kind === 'box' || kind === 'card' || kind === 'port' || kind === 'label' || kind === 'float' || kind === 'phantom' || kind === 'appliance' || kind === 'connector' || kind === 'junction' || kind === 'marker';
117
+ return kind === 'node' || kind === 'box' || kind === 'card' || kind === 'port' || kind === 'label' || kind === 'float' || kind === 'note' || kind === 'appliance' || kind === 'connector' || kind === 'junction' || kind === 'marker';
134
118
  }
135
119
  function isEdgeKind(kind) {
136
120
  return kind === 'edge' || kind === 'arrow' || kind === 'wire';
@@ -144,182 +128,97 @@ function requirePrimitiveProps(child) {
144
128
  return child.props;
145
129
  }
146
130
  function compileNode(kind, child, context) {
147
- if (kind === 'phantom') {
148
- const props = requirePrimitiveProps(child);
149
- const label = compileLabelChildren(props.children, 'Diagram.Phantom');
150
- const hasLabel = label.length > 0;
131
+ const group = context.groupId === undefined ? {} : {
132
+ group: context.groupId
133
+ };
134
+ if (kind === 'note') {
135
+ const {
136
+ children,
137
+ ...props
138
+ } = requirePrimitiveProps(child);
151
139
  return {
152
- id: props.id,
153
- label: hasLabel ? label : '',
154
- row: props.row,
155
- col: props.col,
156
- width: props.width ?? 1,
157
- height: props.height ?? 1,
158
- ...(props.group ?? context.groupId ? {
159
- group: props.group ?? context.groupId
160
- } : {}),
161
- frame: 'none',
162
- hidden: props.hidden ?? !hasLabel,
163
- ...(props.fontSize ? {
164
- fontSize: props.fontSize
165
- } : {}),
166
- ...(props.fontWeight ? {
167
- fontWeight: props.fontWeight
168
- } : {}),
169
- ...(props.textColor ? {
170
- textColor: props.textColor
171
- } : {}),
172
- ...(props.accent !== undefined ? {
173
- accent: props.accent
174
- } : {}),
175
- ...(props.textAlign ? {
176
- textAlign: props.textAlign
177
- } : {}),
178
- ...(props.connectable !== undefined ? {
179
- connectable: props.connectable
180
- } : {})
140
+ ...props,
141
+ kind: 'note',
142
+ label: nodeLabel(children, 'Diagram.Note'),
143
+ ...group,
144
+ frame: 'none'
181
145
  };
182
146
  }
183
147
  if (kind === 'junction') {
184
- const props = requirePrimitiveProps(child);
185
- const label = compileLabelChildren(props.children, 'Diagram.Junction');
186
- const group = props.group ?? context.groupId;
148
+ const {
149
+ children,
150
+ ...props
151
+ } = requirePrimitiveProps(child);
187
152
  return {
188
- id: props.id,
153
+ ...props,
189
154
  kind: 'junction',
190
- label: label.length > 0 ? label : '',
191
- row: props.row,
192
- col: props.col,
193
- width: props.width ?? 16,
194
- height: props.height ?? 16,
195
- ...(group ? {
196
- group
197
- } : {}),
198
- frame: 'none',
199
- connectable: true,
200
- hidden: props.hidden,
201
- accent: props.accent,
202
- tone: props.tone,
203
- fontSize: props.fontSize,
204
- fontWeight: props.fontWeight,
205
- textColor: props.textColor,
206
- caption: props.caption,
207
- captionSide: props.captionSide,
208
- captionOffset: props.captionOffset,
209
- captionColor: props.captionColor,
210
- captionFontSize: props.captionFontSize,
211
- captionFontWeight: props.captionFontWeight
155
+ label: nodeLabel(children, 'Diagram.Junction'),
156
+ ...group,
157
+ frame: 'none'
212
158
  };
213
159
  }
214
160
  if (kind === 'connector') {
215
- const props = requirePrimitiveProps(child);
216
- const label = compileLabelChildren(props.children, 'Diagram.Connector');
217
- const group = props.group ?? context.groupId;
161
+ const {
162
+ children,
163
+ ...props
164
+ } = requirePrimitiveProps(child);
218
165
  return {
219
- id: props.id,
166
+ ...props,
220
167
  kind: 'connector',
221
- label: label.length > 0 ? label : '',
222
- row: props.row,
223
- col: props.col,
224
- colSpan: props.colSpan,
225
- width: props.width ?? 148,
226
- height: props.height ?? 40,
227
- ...(group ? {
228
- group
229
- } : {}),
230
- frame: 'solid',
231
- connectable: true,
232
- rx: props.rx ?? 10,
233
- accent: props.accent,
234
- tone: props.tone,
235
- texture: props.texture,
236
- icon: props.icon,
237
- iconSize: props.iconSize,
238
- ports: props.ports,
239
- fontSize: props.fontSize,
240
- fontWeight: props.fontWeight,
241
- textColor: props.textColor,
242
- caption: props.caption,
243
- captionSide: props.captionSide,
244
- captionOffset: props.captionOffset,
245
- captionColor: props.captionColor,
246
- captionFontSize: props.captionFontSize,
247
- captionFontWeight: props.captionFontWeight
168
+ label: nodeLabel(children, 'Diagram.Connector'),
169
+ ...group,
170
+ frame: 'solid'
248
171
  };
249
172
  }
250
173
  if (kind === 'appliance') {
251
- const props = requirePrimitiveProps(child);
252
- const label = compileLabelChildren(props.children, 'Diagram.Appliance');
253
- const group = props.group ?? context.groupId;
174
+ const {
175
+ children,
176
+ ...props
177
+ } = requirePrimitiveProps(child);
254
178
  return {
255
- id: props.id,
179
+ ...props,
256
180
  kind: 'appliance',
257
- label: label.length > 0 ? label : '',
258
- row: props.row,
259
- col: props.col,
260
- width: props.width ?? 112,
261
- height: props.height ?? 72,
262
- ...(group ? {
263
- group
264
- } : {}),
265
- frame: 'none',
266
- connectable: true,
267
- accent: props.accent,
268
- tone: props.tone,
269
- texture: props.texture,
270
- ports: props.ports,
271
- fontSize: props.fontSize,
272
- fontWeight: props.fontWeight,
273
- textColor: props.textColor,
274
- caption: props.caption,
275
- captionSide: props.captionSide,
276
- captionOffset: props.captionOffset,
277
- captionColor: props.captionColor,
278
- captionFontSize: props.captionFontSize,
279
- captionFontWeight: props.captionFontWeight,
280
- appliancePorts: props.appliancePorts,
281
- antenna: props.antenna,
282
- slant: props.slant
181
+ label: nodeLabel(children, 'Diagram.Appliance'),
182
+ ...group,
183
+ frame: 'none'
283
184
  };
284
185
  }
285
- const props = requirePrimitiveProps(child);
286
186
  const {
287
- children: _children,
288
- ...nodeProps
289
- } = props;
187
+ children,
188
+ ...props
189
+ } = requirePrimitiveProps(child);
290
190
  const {
291
191
  labelChildren,
292
192
  content
293
- } = splitNodeContent(props.children, kind);
294
- const label = compileLabelChildren(labelChildren, `Diagram.${kind}`);
295
- const group = nodeProps.group ?? context.groupId;
193
+ } = splitNodeContent(children, kind);
296
194
  return {
297
- ...nodeProps,
298
- label: label.length > 0 ? label : '',
299
- ...(content.length > 0 ? {
300
- content: content[0]
195
+ ...props,
196
+ label: nodeLabel(labelChildren, `Diagram.${kind}`),
197
+ ...(content ? {
198
+ content
301
199
  } : {}),
302
200
  ...(kind === 'marker' ? {
303
- kind: 'marker',
304
- width: nodeProps.width ?? 72,
305
- height: nodeProps.height ?? 76
201
+ kind: 'marker'
306
202
  } : {}),
307
- ...(group ? {
308
- group
203
+ ...group,
204
+ frame: nodeFrame(kind, props.frame),
205
+ ...(kind === 'card' ? {
206
+ textAlign: 'start'
309
207
  } : {}),
310
- frame: nodeFrame(kind, nodeProps.frame),
311
- textAlign: kind === 'card' ? nodeProps.textAlign ?? 'start' : nodeProps.textAlign,
312
- hidden: kind === 'marker' ? false : nodeProps.hidden,
313
- connectable: kind === 'float' ? false : nodeProps.connectable,
314
- ...(kind === 'marker' ? {
315
- frame: nodeProps.frame ?? 'none'
208
+ hidden: kind === 'marker' ? false : props.hidden,
209
+ ...(kind === 'float' ? {
210
+ connectable: false
316
211
  } : {})
317
212
  };
318
213
  }
214
+ function nodeLabel(children, owner) {
215
+ const label = compileLabelChildren(children, owner);
216
+ return label.length > 0 ? label : '';
217
+ }
319
218
  const CONTENT_HOSTS = new Set(['node', 'box', 'card']);
320
219
  function splitNodeContent(children, kind) {
321
220
  const labelChildren = [];
322
- const content = [];
221
+ let content;
323
222
  Children.forEach(children, child => {
324
223
  if (!isValidElement(child) || primitiveKind(child) !== 'content') {
325
224
  labelChildren.push(child);
@@ -328,10 +227,17 @@ function splitNodeContent(children, kind) {
328
227
  if (!CONTENT_HOSTS.has(kind)) {
329
228
  throw new Error(`Diagram.Content goes inside Diagram.Box, Diagram.Card or Diagram.Node, not Diagram.${kind}.`);
330
229
  }
331
- if (content.length > 0) {
230
+ if (content) {
332
231
  throw new Error(`Diagram.${kind} accepts one Diagram.Content.`);
333
232
  }
334
- content.push(requirePrimitiveProps(child).children);
233
+ const {
234
+ children: element,
235
+ size
236
+ } = requirePrimitiveProps(child);
237
+ content = {
238
+ element,
239
+ size
240
+ };
335
241
  });
336
242
  return {
337
243
  labelChildren,
@@ -348,51 +254,12 @@ function nodeFrame(kind, explicit) {
348
254
  return 'solid';
349
255
  }
350
256
  function compileEdge(kind, child) {
351
- const props = requirePrimitiveProps(child);
352
257
  const {
353
- children: _children,
258
+ children,
354
259
  badgeLabel,
355
260
  ...edgeProps
356
- } = props;
357
- const lines = [];
358
- const waypoints = [...(props.waypoints ?? [])];
359
- let entrySide = props.entrySide;
360
- let exitSide = props.exitSide;
361
- let entryGap = props.entryGap;
362
- Children.forEach(props.children, edgeChild => {
363
- if (edgeChild === null || edgeChild === undefined || typeof edgeChild === 'boolean') return;
364
- if (isTextNode(edgeChild)) {
365
- const text = String(edgeChild).trim();
366
- if (text.length > 0) lines.push(text);
367
- return;
368
- }
369
- if (!isValidElement(edgeChild)) {
370
- throw new Error('Diagram edges only accept text, Line, Entry, Exit, and Waypoint children.');
371
- }
372
- if (edgeChild.type === Fragment) {
373
- throw new Error('Diagram edges do not accept fragments. Use direct Line/Entry/Exit/Waypoint children.');
374
- }
375
- const edgeChildKind = primitiveKind(edgeChild);
376
- if (edgeChildKind === 'line') {
377
- lines.push(lineText(edgeChild));
378
- return;
379
- }
380
- if (edgeChildKind === 'entry') {
381
- const entry = requirePrimitiveProps(edgeChild);
382
- entrySide = entry.side;
383
- entryGap = entry.gap ?? entryGap;
384
- return;
385
- }
386
- if (edgeChildKind === 'exit') {
387
- exitSide = requirePrimitiveProps(edgeChild).side;
388
- return;
389
- }
390
- if (edgeChildKind === 'waypoint') {
391
- waypoints.push(requirePrimitiveProps(edgeChild));
392
- return;
393
- }
394
- throw new Error(`Diagram edge cannot contain <Diagram.${edgeChildKind ?? 'Unknown'}>.`);
395
- });
261
+ } = requirePrimitiveProps(child);
262
+ const lines = compileStringLines(children, `Diagram.${kind}`);
396
263
  return {
397
264
  ...edgeProps,
398
265
  ...(lines.length > 0 ? {
@@ -401,18 +268,6 @@ function compileEdge(kind, child) {
401
268
  ...(badgeLabel !== undefined ? {
402
269
  badgeLabel: normalizeStringLines(badgeLabel)
403
270
  } : {}),
404
- ...(waypoints.length > 0 ? {
405
- waypoints
406
- } : {}),
407
- ...(entrySide ? {
408
- entrySide
409
- } : {}),
410
- ...(exitSide ? {
411
- exitSide
412
- } : {}),
413
- ...(entryGap !== undefined ? {
414
- entryGap
415
- } : {}),
416
271
  headless: kind === 'wire' ? true : edgeProps.headless
417
272
  };
418
273
  }
@@ -420,39 +275,20 @@ function normalizeStringLines(value) {
420
275
  return (Array.isArray(value) ? value : [value]).map(line => line.trim()).filter(Boolean);
421
276
  }
422
277
  function compileGroup(child, context) {
423
- const props = requirePrimitiveProps(child);
424
- const children = compileChildren(props.children, {
278
+ const {
279
+ children: groupChildren,
280
+ label,
281
+ ...props
282
+ } = requirePrimitiveProps(child);
283
+ const children = compileChildren(groupChildren, {
425
284
  ...context,
426
285
  groupId: props.id
427
286
  });
428
- const bounds = props.rowStart !== undefined && props.rowEnd !== undefined && props.colStart !== undefined && props.colEnd !== undefined ? {
429
- rowStart: props.rowStart,
430
- rowEnd: props.rowEnd,
431
- colStart: props.colStart,
432
- colEnd: props.colEnd
433
- } : inferGroupBounds(props.id, children.nodes, children.groups);
434
287
  return {
435
288
  group: {
436
- id: props.id,
437
- label: normalizeGroupLabel(props.label),
438
- labelAlign: props.labelAlign,
439
- labelSide: props.labelSide,
440
- accent: props.accent,
441
- tone: props.tone,
442
- texture: props.texture,
443
- rx: props.rx,
444
- frame: props.frame,
445
- fill: props.fill,
446
- ports: props.ports,
447
- parent: context.groupId,
448
- tight: props.tight,
449
- tightX: props.tightX,
450
- tightY: props.tightY,
451
- titleBand: props.titleBand,
452
- titleGap: props.titleGap,
453
- padding: props.padding,
454
- dividers: props.dividers,
455
- bounds
289
+ ...props,
290
+ label: normalizeGroupLabel(label),
291
+ parent: context.groupId
456
292
  },
457
293
  children
458
294
  };
@@ -463,54 +299,6 @@ function normalizeGroupLabel(label) {
463
299
  }
464
300
  return label?.trim() ?? '';
465
301
  }
466
- function inferGroupBounds(groupId, nodes, groups = []) {
467
- const grouped = nodes.filter(node => node.group === groupId);
468
- const childGroups = groups.filter(group => group.parent === groupId);
469
- if (grouped.length === 0 && childGroups.length === 0) {
470
- throw new Error(`Diagram.Group "${groupId}" needs bounds or direct node/group children so bounds can be inferred.`);
471
- }
472
- const bounds = emptyGroupBounds();
473
- for (const node of grouped) {
474
- if (node.row === undefined || node.col === undefined) return undefined;
475
- includeGroupBounds(bounds, {
476
- rowStart: node.row,
477
- rowEnd: node.row,
478
- colStart: node.col,
479
- colEnd: node.col + (node.colSpan ?? 1) - 1
480
- });
481
- }
482
- for (const group of childGroups) {
483
- if (!group.bounds) return undefined;
484
- includeGroupBounds(bounds, group.bounds);
485
- }
486
- return bounds;
487
- }
488
- function emptyGroupBounds() {
489
- return {
490
- rowStart: Number.POSITIVE_INFINITY,
491
- rowEnd: Number.NEGATIVE_INFINITY,
492
- colStart: Number.POSITIVE_INFINITY,
493
- colEnd: Number.NEGATIVE_INFINITY
494
- };
495
- }
496
- function includeGroupBounds(target, source) {
497
- target.rowStart = Math.min(target.rowStart, source.rowStart);
498
- target.rowEnd = Math.max(target.rowEnd, source.rowEnd);
499
- target.colStart = Math.min(target.colStart, source.colStart);
500
- target.colEnd = Math.max(target.colEnd, source.colEnd);
501
- }
502
- function compileText(child) {
503
- const props = requirePrimitiveProps(child);
504
- const {
505
- children: _children,
506
- ...textProps
507
- } = props;
508
- const lines = compileStringLines(props.children, 'Diagram.Text');
509
- return {
510
- ...textProps,
511
- text: lines.length > 0 ? lines : ['']
512
- };
513
- }
514
302
  function compileLane(child) {
515
303
  const props = requirePrimitiveProps(child);
516
304
  return {
@@ -619,79 +407,6 @@ function lineText(child) {
619
407
  return String(part).trim();
620
408
  }).filter(Boolean).join('');
621
409
  }
622
- export function validateGraph(ir) {
623
- const nodeIds = new Set();
624
- for (const node of ir.nodes) {
625
- if (nodeIds.has(node.id)) throw new Error(`Duplicate Diagram node id "${node.id}".`);
626
- nodeIds.add(node.id);
627
- }
628
- const groupIds = new Set();
629
- for (const group of ir.groups) {
630
- if (groupIds.has(group.id)) throw new Error(`Duplicate Diagram group id "${group.id}".`);
631
- groupIds.add(group.id);
632
- }
633
- const guideIds = new Set();
634
- for (const guide of ir.guides) {
635
- if (!guide.id) continue;
636
- if (guideIds.has(guide.id)) throw new Error(`Duplicate Diagram guide id "${guide.id}".`);
637
- guideIds.add(guide.id);
638
- }
639
- const nodesById = new Map(ir.nodes.map(node => [node.id, node]));
640
- const groupsById = new Map(ir.groups.map(group => [group.id, group]));
641
- for (const node of ir.nodes) {
642
- if (groupsById.has(node.id)) {
643
- throw new Error(`Diagram node id "${node.id}" conflicts with a Diagram group id. Node and group endpoint ids must be unique.`);
644
- }
645
- if (node.bodyFontSize !== undefined && (!Number.isFinite(node.bodyFontSize) || node.bodyFontSize <= 0)) {
646
- throw new Error(`Diagram node "${node.id}" bodyFontSize must be a positive finite number, got ${node.bodyFontSize}.`);
647
- }
648
- if (node.bodyLineGap !== undefined && (!Number.isFinite(node.bodyLineGap) || node.bodyLineGap < 0)) {
649
- throw new Error(`Diagram node "${node.id}" bodyLineGap must be a non-negative finite number, got ${node.bodyLineGap}.`);
650
- }
651
- }
652
- for (const edge of ir.edges) {
653
- if (edge.route !== undefined && edge.route !== 'orthogonal' && edge.route !== 'straight') {
654
- throw new Error(`Diagram edge route must be "orthogonal" or "straight", got "${edge.route}".`);
655
- }
656
- if (edge.labelLineGap !== undefined && (!Number.isFinite(edge.labelLineGap) || edge.labelLineGap < 0)) {
657
- throw new Error(`Diagram edge labelLineGap must be a non-negative finite number, got ${edge.labelLineGap}.`);
658
- }
659
- if (edge.exitOffset !== undefined && !Number.isFinite(edge.exitOffset)) {
660
- throw new Error(`Diagram edge exitOffset must be a finite number, got ${edge.exitOffset}.`);
661
- }
662
- if (edge.entryOffset !== undefined && !Number.isFinite(edge.entryOffset)) {
663
- throw new Error(`Diagram edge entryOffset must be a finite number, got ${edge.entryOffset}.`);
664
- }
665
- if (edge.stubDistance !== undefined && (!Number.isFinite(edge.stubDistance) || edge.stubDistance < 0)) {
666
- throw new Error(`Diagram edge stubDistance must be a non-negative finite number, got ${edge.stubDistance}.`);
667
- }
668
- const {
669
- nodeId: sourceNodeId,
670
- portId: sourcePortId
671
- } = parseEndpointRef(edge.from);
672
- const {
673
- nodeId: targetNodeId,
674
- portId: targetPortId
675
- } = parseEndpointRef(edge.to);
676
- if (!nodeIds.has(sourceNodeId) && !groupsById.has(sourceNodeId)) {
677
- throw new Error(`Diagram edge ${edge.from}->${edge.to} references missing source "${sourceNodeId}".`);
678
- }
679
- if (!nodeIds.has(targetNodeId) && !groupsById.has(targetNodeId)) {
680
- throw new Error(`Diagram edge ${edge.from}->${edge.to} references missing target "${targetNodeId}".`);
681
- }
682
- if (sourcePortId && !(nodesById.get(sourceNodeId)?.ports?.some(port => port.id === sourcePortId) || groupsById.get(sourceNodeId)?.ports?.some(port => port.id === sourcePortId))) {
683
- throw new Error(`Diagram edge ${edge.from}->${edge.to} references missing source port "${sourcePortId}" on "${sourceNodeId}".`);
684
- }
685
- if (targetPortId && !(nodesById.get(targetNodeId)?.ports?.some(port => port.id === targetPortId) || groupsById.get(targetNodeId)?.ports?.some(port => port.id === targetPortId))) {
686
- throw new Error(`Diagram edge ${edge.from}->${edge.to} references missing target port "${targetPortId}" on "${targetNodeId}".`);
687
- }
688
- }
689
- for (const annotation of ir.annotations) {
690
- if (annotation.lineGap !== undefined && (!Number.isFinite(annotation.lineGap) || annotation.lineGap < 0)) {
691
- throw new Error(`Diagram.Text lineGap must be a non-negative finite number, got ${annotation.lineGap}.`);
692
- }
693
- }
694
- }
695
410
  export function validateTimeline(ir) {
696
411
  const laneIds = new Set();
697
412
  for (const lane of ir.lanes) {