@zukhruf/diagram 0.0.0-stage → 0.3.28

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