@zukhruf/diagram 0.3.29 → 0.3.31

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 (92) hide show
  1. package/dist/lib/layouts/graph/areas.d.ts +27 -0
  2. package/dist/lib/layouts/graph/areas.d.ts.map +1 -0
  3. package/dist/lib/layouts/graph/areas.js +187 -0
  4. package/dist/lib/layouts/graph/areas.js.map +1 -0
  5. package/dist/lib/layouts/graph/graph-layout-result.d.ts +95 -0
  6. package/dist/lib/layouts/graph/graph-layout-result.d.ts.map +1 -0
  7. package/dist/lib/layouts/graph/graph-layout-result.js +2 -0
  8. package/dist/lib/layouts/graph/graph-layout-result.js.map +1 -0
  9. package/dist/lib/layouts/graph/graph-layout.d.ts +2 -1
  10. package/dist/lib/layouts/graph/graph-layout.d.ts.map +1 -1
  11. package/dist/lib/layouts/graph/graph-layout.js +5 -3
  12. package/dist/lib/layouts/graph/graph-layout.js.map +1 -1
  13. package/dist/lib/layouts/graph/gutters.d.ts +26 -0
  14. package/dist/lib/layouts/graph/gutters.d.ts.map +1 -0
  15. package/dist/lib/layouts/graph/gutters.js +123 -0
  16. package/dist/lib/layouts/graph/gutters.js.map +1 -0
  17. package/dist/lib/layouts/graph/layout.d.ts +10 -0
  18. package/dist/lib/layouts/graph/layout.d.ts.map +1 -0
  19. package/dist/lib/layouts/graph/layout.js +165 -0
  20. package/dist/lib/layouts/graph/layout.js.map +1 -0
  21. package/dist/lib/layouts/graph/legacy-graph-layout.d.ts +6 -0
  22. package/dist/lib/layouts/graph/legacy-graph-layout.d.ts.map +1 -0
  23. package/dist/lib/layouts/graph/legacy-graph-layout.js +542 -0
  24. package/dist/lib/layouts/graph/legacy-graph-layout.js.map +1 -0
  25. package/dist/lib/layouts/graph/measure.d.ts +44 -0
  26. package/dist/lib/layouts/graph/measure.d.ts.map +1 -0
  27. package/dist/lib/layouts/graph/measure.js +372 -0
  28. package/dist/lib/layouts/graph/measure.js.map +1 -0
  29. package/dist/lib/layouts/graph/node-content.d.ts +16 -0
  30. package/dist/lib/layouts/graph/node-content.d.ts.map +1 -0
  31. package/dist/lib/layouts/graph/node-content.js +323 -0
  32. package/dist/lib/layouts/graph/node-content.js.map +1 -0
  33. package/dist/lib/layouts/graph/text-block.d.ts +19 -0
  34. package/dist/lib/layouts/graph/text-block.d.ts.map +1 -0
  35. package/dist/lib/layouts/graph/text-block.js +86 -0
  36. package/dist/lib/layouts/graph/text-block.js.map +1 -0
  37. package/dist/lib/layouts/graph/tokens.d.ts +58 -0
  38. package/dist/lib/layouts/graph/tokens.d.ts.map +1 -0
  39. package/dist/lib/layouts/graph/tokens.js +108 -0
  40. package/dist/lib/layouts/graph/tokens.js.map +1 -0
  41. package/dist/lib/layouts/graph/tracks.d.ts +20 -0
  42. package/dist/lib/layouts/graph/tracks.d.ts.map +1 -0
  43. package/dist/lib/layouts/graph/tracks.js +47 -0
  44. package/dist/lib/layouts/graph/tracks.js.map +1 -0
  45. package/dist/lib/layouts/text/font-metrics.generated.d.ts +18 -0
  46. package/dist/lib/layouts/text/font-metrics.generated.d.ts.map +1 -0
  47. package/dist/lib/layouts/text/font-metrics.generated.js +1043 -0
  48. package/dist/lib/layouts/text/font-metrics.generated.js.map +1 -0
  49. package/dist/lib/layouts/text/font.d.ts +14 -0
  50. package/dist/lib/layouts/text/font.d.ts.map +1 -0
  51. package/dist/lib/layouts/text/font.js +11 -0
  52. package/dist/lib/layouts/text/font.js.map +1 -0
  53. package/dist/lib/layouts/text/measure-text.d.ts +13 -0
  54. package/dist/lib/layouts/text/measure-text.d.ts.map +1 -0
  55. package/dist/lib/layouts/text/measure-text.js +67 -0
  56. package/dist/lib/layouts/text/measure-text.js.map +1 -0
  57. package/dist/lib/model/diagram-ir.d.ts +14 -1
  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/dist/lib/renderers/canvas/graph-canvas.d.ts.map +1 -1
  61. package/dist/lib/renderers/canvas/graph-canvas.js +148 -138
  62. package/dist/lib/renderers/canvas/graph-canvas.js.map +1 -1
  63. package/dist/lib/renderers/html/graph-html.d.ts.map +1 -1
  64. package/dist/lib/renderers/html/graph-html.js +462 -511
  65. package/dist/lib/renderers/html/graph-html.js.map +1 -1
  66. package/dist/lib/renderers/shared/graph-parts.d.ts +15 -13
  67. package/dist/lib/renderers/shared/graph-parts.d.ts.map +1 -1
  68. package/dist/lib/renderers/shared/graph-parts.js +649 -644
  69. package/dist/lib/renderers/shared/graph-parts.js.map +1 -1
  70. package/dist/lib/renderers/shared/node-parts.d.ts +20 -19
  71. package/dist/lib/renderers/shared/node-parts.d.ts.map +1 -1
  72. package/dist/lib/renderers/shared/node-parts.js +678 -811
  73. package/dist/lib/renderers/shared/node-parts.js.map +1 -1
  74. package/dist/lib/renderers/shared/run-spans.d.ts +8 -0
  75. package/dist/lib/renderers/shared/run-spans.d.ts.map +1 -0
  76. package/dist/lib/renderers/shared/run-spans.js +18 -0
  77. package/dist/lib/renderers/shared/run-spans.js.map +1 -0
  78. package/dist/lib/renderers/shared/text-runs.d.ts +21 -0
  79. package/dist/lib/renderers/shared/text-runs.d.ts.map +1 -0
  80. package/dist/lib/renderers/shared/text-runs.js +44 -0
  81. package/dist/lib/renderers/shared/text-runs.js.map +1 -0
  82. package/dist/lib/renderers/svg/graph-svg.d.ts.map +1 -1
  83. package/dist/lib/renderers/svg/graph-svg.js +304 -465
  84. package/dist/lib/renderers/svg/graph-svg.js.map +1 -1
  85. package/dist/lib/renderers/svg/timeline-svg.d.ts.map +1 -1
  86. package/dist/lib/renderers/svg/timeline-svg.js +10 -5
  87. package/dist/lib/renderers/svg/timeline-svg.js.map +1 -1
  88. package/dist/lib/renderers/webgpu/graph-flow-effects.d.ts +2 -2
  89. package/dist/lib/renderers/webgpu/graph-flow-effects.d.ts.map +1 -1
  90. package/dist/lib/renderers/webgpu/graph-flow-effects.js.map +1 -1
  91. package/package.json +3 -1
  92. package/styles.css +8 -0
@@ -0,0 +1,323 @@
1
+ import { labelLines, textBlock } from "./text-block.js";
2
+
3
+ /** What a node draws inside its frame: its measured size, the padding around it, and where it goes. */
4
+
5
+ /** Mirrors the connector pill drawn before content sizing: 10px side inset, 4px above and below the text, 28px tall at least. */
6
+ const CONNECTOR_PAD = {
7
+ x: 10,
8
+ y: 4
9
+ };
10
+ const CONNECTOR_MIN_HEIGHT = 28;
11
+ const NOTHING = {
12
+ text: [],
13
+ bullets: []
14
+ };
15
+ export function nodeContent(node, tokens) {
16
+ switch (node.kind) {
17
+ case 'junction':
18
+ return junctionContent(tokens);
19
+ case 'marker':
20
+ return markerContent(node, tokens);
21
+ case 'connector':
22
+ return connectorContent(node, tokens);
23
+ case 'appliance':
24
+ return applianceContent(node, tokens);
25
+ case 'note':
26
+ return noteContent(node, tokens);
27
+ default:
28
+ return boxContent(node, tokens);
29
+ }
30
+ }
31
+ function boxContent(node, tokens) {
32
+ const pad = node.frame === 'none' ? {
33
+ x: tokens.LABEL_GAP,
34
+ y: tokens.LABEL_GAP
35
+ } : {
36
+ x: tokens.PAD_X,
37
+ y: tokens.PAD_Y
38
+ };
39
+ const isCard = node.textAlign === 'start' || node.description !== undefined || (node.items?.length ?? 0) > 0;
40
+ if (isCard) return {
41
+ ...cardContent(node, tokens),
42
+ pad
43
+ };
44
+ if (node.icon) return {
45
+ ...iconRowContent(node, tokens),
46
+ pad
47
+ };
48
+ const lines = textBlock(labelLines(node.label, node.textColor), tokens.fonts.boxLabel);
49
+ return {
50
+ w: lines.w,
51
+ h: lines.h,
52
+ pad,
53
+ place: inner => ({
54
+ text: lines.place(centreX(inner), centredTop(inner, lines.h), 'middle'),
55
+ bullets: []
56
+ })
57
+ };
58
+ }
59
+ function iconRowContent(node, tokens) {
60
+ const {
61
+ ICON,
62
+ ICON_GAP
63
+ } = tokens;
64
+ const title = textBlock(labelLines(node.label, node.textColor), tokens.fonts.title);
65
+ const w = title.w > 0 ? ICON + ICON_GAP + title.w : ICON;
66
+ const h = Math.max(ICON, title.h);
67
+ return {
68
+ w,
69
+ h,
70
+ place: inner => {
71
+ const x = inner.x + (inner.w - w) / 2;
72
+ const y = centredTop(inner, h);
73
+ return {
74
+ icon: {
75
+ x,
76
+ y: y + (h - ICON) / 2,
77
+ size: ICON
78
+ },
79
+ text: title.place(x + ICON + ICON_GAP, y + (h - title.h) / 2, 'start'),
80
+ bullets: []
81
+ };
82
+ }
83
+ };
84
+ }
85
+ function cardContent(node, tokens) {
86
+ const {
87
+ ICON,
88
+ ICON_GAP,
89
+ BLOCK_GAP,
90
+ 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);
95
+ let iconW = 0;
96
+ if (node.icon) iconW = title.w > 0 ? ICON + ICON_GAP : ICON;
97
+ const headerH = Math.max(node.icon ? ICON : 0, title.h);
98
+ const sections = [{
99
+ h: headerH,
100
+ w: iconW + title.w
101
+ }, {
102
+ h: description.h,
103
+ w: description.w
104
+ }, {
105
+ h: items.h,
106
+ w: items.h > 0 ? BULLET_INDENT + items.w : 0
107
+ }].filter(section => section.h > 0);
108
+ const bulletRise = tokens.fonts.body.size * 0.3;
109
+ return {
110
+ w: Math.max(0, ...sections.map(section => section.w)),
111
+ h: sections.reduce((sum, section) => sum + section.h, 0) + Math.max(0, sections.length - 1) * BLOCK_GAP,
112
+ place: inner => {
113
+ let top = inner.y;
114
+ const next = h => {
115
+ const at = top;
116
+ if (h > 0) top += h + BLOCK_GAP;
117
+ return at;
118
+ };
119
+ const headerTop = next(headerH);
120
+ const descriptionTop = next(description.h);
121
+ const itemsTop = next(items.h);
122
+ const itemRuns = items.place(inner.x + BULLET_INDENT, itemsTop, 'start');
123
+ return {
124
+ ...(node.icon ? {
125
+ icon: {
126
+ x: inner.x,
127
+ y: headerTop + (headerH - ICON) / 2,
128
+ size: ICON
129
+ }
130
+ } : {}),
131
+ text: [...title.place(inner.x + iconW, headerTop + (headerH - title.h) / 2, 'start'), ...description.place(inner.x, descriptionTop, 'start'), ...itemRuns],
132
+ bullets: itemRuns.map(run => ({
133
+ x: inner.x + BULLET_INDENT / 4,
134
+ y: run.y - bulletRise
135
+ }))
136
+ };
137
+ }
138
+ };
139
+ }
140
+ function noteContent(node, tokens) {
141
+ const lines = textBlock(labelLines(node.label, node.textColor ?? 'dim'), tokens.fonts.note);
142
+ return {
143
+ w: lines.w,
144
+ h: lines.h,
145
+ pad: {
146
+ x: tokens.LABEL_GAP,
147
+ y: tokens.LABEL_GAP
148
+ },
149
+ place: inner => ({
150
+ text: lines.place(inner.x, inner.y, 'start'),
151
+ bullets: []
152
+ })
153
+ };
154
+ }
155
+ function markerContent(node, tokens) {
156
+ const {
157
+ MARKER_ICON,
158
+ BLOCK_GAP
159
+ } = tokens;
160
+ const lines = textBlock(labelLines(node.label, node.textColor), tokens.fonts.marker);
161
+ const gap = lines.h > 0 ? BLOCK_GAP : 0;
162
+ const h = MARKER_ICON + gap + lines.h;
163
+ return {
164
+ w: Math.max(MARKER_ICON, lines.w),
165
+ h,
166
+ pad: {
167
+ x: tokens.LABEL_GAP,
168
+ y: tokens.LABEL_GAP
169
+ },
170
+ place: inner => {
171
+ const top = centredTop(inner, h);
172
+ const cx = centreX(inner);
173
+ return {
174
+ icon: {
175
+ x: cx - MARKER_ICON / 2,
176
+ y: top,
177
+ size: MARKER_ICON
178
+ },
179
+ text: lines.place(cx, top + MARKER_ICON + gap, 'middle'),
180
+ bullets: []
181
+ };
182
+ }
183
+ };
184
+ }
185
+ function connectorContent(node, tokens) {
186
+ const {
187
+ CONNECTOR_ICON,
188
+ BLOCK_GAP
189
+ } = tokens;
190
+ const lines = textBlock(labelLines(node.label, node.textColor), tokens.fonts.connector);
191
+ const iconW = node.icon ? CONNECTOR_ICON + (lines.w > 0 ? BLOCK_GAP : 0) : 0;
192
+ const h = Math.max(CONNECTOR_MIN_HEIGHT - 2 * CONNECTOR_PAD.y, lines.h);
193
+ return {
194
+ w: iconW + lines.w,
195
+ h,
196
+ pad: CONNECTOR_PAD,
197
+ place: inner => {
198
+ const cy = inner.y + inner.h / 2;
199
+ const top = cy - lines.h / 2;
200
+ if (!node.icon) {
201
+ return {
202
+ text: lines.place(centreX(inner), top, 'middle'),
203
+ bullets: []
204
+ };
205
+ }
206
+ return {
207
+ icon: {
208
+ x: inner.x,
209
+ y: cy - CONNECTOR_ICON / 2,
210
+ size: CONNECTOR_ICON
211
+ },
212
+ text: lines.place(inner.x + iconW, top, 'start'),
213
+ bullets: []
214
+ };
215
+ }
216
+ };
217
+ }
218
+ function junctionContent(tokens) {
219
+ return {
220
+ w: tokens.JUNCTION,
221
+ h: tokens.JUNCTION,
222
+ pad: {
223
+ x: 0,
224
+ y: 0
225
+ },
226
+ place: () => NOTHING
227
+ };
228
+ }
229
+ function applianceContent(node, tokens) {
230
+ const {
231
+ APPLIANCE,
232
+ LABEL_GAP
233
+ } = tokens;
234
+ const lines = textBlock(labelLines(node.label, node.textColor), tokens.fonts.appliance);
235
+ return {
236
+ w: Math.max(APPLIANCE.w, lines.w + 2 * LABEL_GAP),
237
+ h: APPLIANCE.h + (lines.h > 0 ? lines.h + LABEL_GAP : 0),
238
+ pad: {
239
+ x: 0,
240
+ y: 0
241
+ },
242
+ place: inner => {
243
+ const glyph = {
244
+ x: centreX(inner) - APPLIANCE.w / 2,
245
+ y: inner.y,
246
+ ...APPLIANCE
247
+ };
248
+ return {
249
+ appliance: applianceGlyph(node, glyph),
250
+ text: lines.place(centreX(inner), glyph.y + glyph.h, 'middle'),
251
+ bullets: []
252
+ };
253
+ }
254
+ };
255
+ }
256
+
257
+ /** The router glyph: a slanted body, an optional antenna and a row of jacks, as the renderers drew it before content sizing. */
258
+ function applianceGlyph(node, glyph) {
259
+ const bodyX = glyph.x + 4;
260
+ const bodyY = glyph.y + Math.max(12, Math.min(22, glyph.h * 0.28));
261
+ const bodyW = glyph.w - 8;
262
+ const bodyH = glyph.h - (bodyY - glyph.y) - 12;
263
+ const slant = Math.max(4, Math.min(16, bodyW * 0.28, bodyH * 0.75));
264
+ const body = [{
265
+ x: bodyX + slant,
266
+ y: bodyY
267
+ }, {
268
+ x: bodyX + bodyW,
269
+ y: bodyY + 6
270
+ }, {
271
+ x: bodyX + bodyW - slant,
272
+ y: bodyY + bodyH
273
+ }, {
274
+ x: bodyX,
275
+ y: bodyY + bodyH - 6
276
+ }];
277
+ const mastX = bodyX + slant + bodyW * 0.2;
278
+ const antenna = node.antenna ?? true ? [[{
279
+ x: bodyX + slant + bodyW * 0.18,
280
+ y: bodyY + 1
281
+ }, {
282
+ x: mastX - 3,
283
+ y: glyph.y + 3
284
+ }], [{
285
+ x: mastX + 1,
286
+ y: bodyY + 2
287
+ }, {
288
+ x: mastX + 1,
289
+ y: glyph.y + 8
290
+ }]] : [];
291
+ const jackCount = Math.max(0, Math.floor(node.appliancePorts ?? 4));
292
+ const jackSpacing = Math.min(13, Math.max(8, (bodyW - slant - 42) / Math.max(jackCount, 1)));
293
+ const jacks = Array.from({
294
+ length: jackCount
295
+ }, (_, index) => ({
296
+ x: bodyX + slant + 16 + index * jackSpacing,
297
+ y: bodyY + bodyH - 15,
298
+ w: 5,
299
+ h: 12
300
+ }));
301
+ const face = [{
302
+ x: bodyX + slant,
303
+ y: bodyY + bodyH - 1
304
+ }, {
305
+ x: bodyX + bodyW - slant,
306
+ y: bodyY + bodyH + 3
307
+ }];
308
+ // Through a variable, not a literal, so the return skips the excess-property check against NodeLayout['appliance'].
309
+ const parts = {
310
+ body,
311
+ face,
312
+ antenna,
313
+ jacks
314
+ };
315
+ return parts;
316
+ }
317
+ function centreX(box) {
318
+ return box.x + box.w / 2;
319
+ }
320
+ function centredTop(box, h) {
321
+ return box.y + (box.h - h) / 2;
322
+ }
323
+ //# sourceMappingURL=node-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-content.js","names":["labelLines","textBlock","CONNECTOR_PAD","x","y","CONNECTOR_MIN_HEIGHT","NOTHING","text","bullets","nodeContent","node","tokens","kind","junctionContent","markerContent","connectorContent","applianceContent","noteContent","boxContent","pad","frame","LABEL_GAP","PAD_X","PAD_Y","isCard","textAlign","description","undefined","items","length","cardContent","icon","iconRowContent","lines","label","textColor","fonts","boxLabel","w","h","place","inner","centreX","centredTop","ICON","ICON_GAP","title","Math","max","size","BLOCK_GAP","BULLET_INDENT","body","iconW","headerH","sections","filter","section","bulletRise","map","reduce","sum","top","next","at","headerTop","descriptionTop","itemsTop","itemRuns","run","note","MARKER_ICON","marker","gap","cx","CONNECTOR_ICON","connector","cy","JUNCTION","APPLIANCE","appliance","glyph","applianceGlyph","bodyX","bodyY","min","bodyW","bodyH","slant","mastX","antenna","jackCount","floor","appliancePorts","jackSpacing","jacks","Array","from","_","index","face","parts","box"],"sources":["../../../../src/lib/layouts/graph/node-content.ts"],"sourcesContent":["import type { Box, DiagramNode, Point } from '../../model/diagram-ir.ts';\nimport type { NodeLayout } from './graph-layout-result.ts';\nimport { labelLines, textBlock } from './text-block.ts';\nimport type { LayoutTokens } from './tokens.ts';\n\nexport type ContentPlacement = Pick<NodeLayout, 'text' | 'bullets'> &\n Partial<Pick<NodeLayout, 'icon' | 'appliance'>>;\n\n/** What a node draws inside its frame: its measured size, the padding around it, and where it goes. */\nexport type NodeContent = {\n w: number;\n h: number;\n pad: { x: number; y: number };\n place(inner: Box): ContentPlacement;\n};\n\n/** Mirrors the connector pill drawn before content sizing: 10px side inset, 4px above and below the text, 28px tall at least. */\nconst CONNECTOR_PAD = { x: 10, y: 4 };\nconst CONNECTOR_MIN_HEIGHT = 28;\n\nconst NOTHING: ContentPlacement = { text: [], bullets: [] };\n\nexport function nodeContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): NodeContent {\n switch (node.kind) {\n case 'junction':\n return junctionContent(tokens);\n case 'marker':\n return markerContent(node, tokens);\n case 'connector':\n return connectorContent(node, tokens);\n case 'appliance':\n return applianceContent(node, tokens);\n case 'note':\n return noteContent(node, tokens);\n default:\n return boxContent(node, tokens);\n }\n}\n\nfunction boxContent(node: DiagramNode, tokens: LayoutTokens): NodeContent {\n const pad =\n node.frame === 'none'\n ? { x: tokens.LABEL_GAP, y: tokens.LABEL_GAP }\n : { x: tokens.PAD_X, y: tokens.PAD_Y };\n const isCard =\n node.textAlign === 'start' ||\n node.description !== undefined ||\n (node.items?.length ?? 0) > 0;\n if (isCard) return { ...cardContent(node, tokens), pad };\n if (node.icon) return { ...iconRowContent(node, tokens), pad };\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.boxLabel,\n );\n return {\n w: lines.w,\n h: lines.h,\n pad,\n place: (inner) => ({\n text: lines.place(centreX(inner), centredTop(inner, lines.h), 'middle'),\n bullets: [],\n }),\n };\n}\n\nfunction iconRowContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): Omit<NodeContent, 'pad'> {\n const { ICON, ICON_GAP } = tokens;\n const title = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.title,\n );\n const w = title.w > 0 ? ICON + ICON_GAP + title.w : ICON;\n const h = Math.max(ICON, title.h);\n return {\n w,\n h,\n place: (inner) => {\n const x = inner.x + (inner.w - w) / 2;\n const y = centredTop(inner, h);\n return {\n icon: { x, y: y + (h - ICON) / 2, size: ICON },\n text: title.place(x + ICON + ICON_GAP, y + (h - title.h) / 2, 'start'),\n bullets: [],\n };\n },\n };\n}\n\nfunction cardContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): Omit<NodeContent, 'pad'> {\n const { ICON, ICON_GAP, BLOCK_GAP, BULLET_INDENT } = tokens;\n const title = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.title,\n );\n const description = textBlock(\n labelLines(node.description, node.textColor),\n tokens.fonts.body,\n );\n const items = textBlock(\n labelLines(node.items, node.textColor),\n tokens.fonts.body,\n );\n let iconW = 0;\n if (node.icon) iconW = title.w > 0 ? ICON + ICON_GAP : ICON;\n const headerH = Math.max(node.icon ? ICON : 0, title.h);\n const sections = [\n { h: headerH, w: iconW + title.w },\n { h: description.h, w: description.w },\n { h: items.h, w: items.h > 0 ? BULLET_INDENT + items.w : 0 },\n ].filter((section) => section.h > 0);\n const bulletRise = tokens.fonts.body.size * 0.3;\n return {\n w: Math.max(0, ...sections.map((section) => section.w)),\n h:\n sections.reduce((sum, section) => sum + section.h, 0) +\n Math.max(0, sections.length - 1) * BLOCK_GAP,\n place: (inner) => {\n let top = inner.y;\n const next = (h: number) => {\n const at = top;\n if (h > 0) top += h + BLOCK_GAP;\n return at;\n };\n const headerTop = next(headerH);\n const descriptionTop = next(description.h);\n const itemsTop = next(items.h);\n const itemRuns = items.place(inner.x + BULLET_INDENT, itemsTop, 'start');\n return {\n ...(node.icon\n ? {\n icon: {\n x: inner.x,\n y: headerTop + (headerH - ICON) / 2,\n size: ICON,\n },\n }\n : {}),\n text: [\n ...title.place(\n inner.x + iconW,\n headerTop + (headerH - title.h) / 2,\n 'start',\n ),\n ...description.place(inner.x, descriptionTop, 'start'),\n ...itemRuns,\n ],\n bullets: itemRuns.map((run) => ({\n x: inner.x + BULLET_INDENT / 4,\n y: run.y - bulletRise,\n })),\n };\n },\n };\n}\n\nfunction noteContent(node: DiagramNode, tokens: LayoutTokens): NodeContent {\n const lines = textBlock(\n labelLines(node.label, node.textColor ?? 'dim'),\n tokens.fonts.note,\n );\n return {\n w: lines.w,\n h: lines.h,\n pad: { x: tokens.LABEL_GAP, y: tokens.LABEL_GAP },\n place: (inner) => ({\n text: lines.place(inner.x, inner.y, 'start'),\n bullets: [],\n }),\n };\n}\n\nfunction markerContent(node: DiagramNode, tokens: LayoutTokens): NodeContent {\n const { MARKER_ICON, BLOCK_GAP } = tokens;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.marker,\n );\n const gap = lines.h > 0 ? BLOCK_GAP : 0;\n const h = MARKER_ICON + gap + lines.h;\n return {\n w: Math.max(MARKER_ICON, lines.w),\n h,\n pad: { x: tokens.LABEL_GAP, y: tokens.LABEL_GAP },\n place: (inner) => {\n const top = centredTop(inner, h);\n const cx = centreX(inner);\n return {\n icon: { x: cx - MARKER_ICON / 2, y: top, size: MARKER_ICON },\n text: lines.place(cx, top + MARKER_ICON + gap, 'middle'),\n bullets: [],\n };\n },\n };\n}\n\nfunction connectorContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): NodeContent {\n const { CONNECTOR_ICON, BLOCK_GAP } = tokens;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.connector,\n );\n const iconW = node.icon ? CONNECTOR_ICON + (lines.w > 0 ? BLOCK_GAP : 0) : 0;\n const h = Math.max(CONNECTOR_MIN_HEIGHT - 2 * CONNECTOR_PAD.y, lines.h);\n return {\n w: iconW + lines.w,\n h,\n pad: CONNECTOR_PAD,\n place: (inner) => {\n const cy = inner.y + inner.h / 2;\n const top = cy - lines.h / 2;\n if (!node.icon) {\n return {\n text: lines.place(centreX(inner), top, 'middle'),\n bullets: [],\n };\n }\n return {\n icon: { x: inner.x, y: cy - CONNECTOR_ICON / 2, size: CONNECTOR_ICON },\n text: lines.place(inner.x + iconW, top, 'start'),\n bullets: [],\n };\n },\n };\n}\n\nfunction junctionContent(tokens: LayoutTokens): NodeContent {\n return {\n w: tokens.JUNCTION,\n h: tokens.JUNCTION,\n pad: { x: 0, y: 0 },\n place: () => NOTHING,\n };\n}\n\nfunction applianceContent(\n node: DiagramNode,\n tokens: LayoutTokens,\n): NodeContent {\n const { APPLIANCE, LABEL_GAP } = tokens;\n const lines = textBlock(\n labelLines(node.label, node.textColor),\n tokens.fonts.appliance,\n );\n return {\n w: Math.max(APPLIANCE.w, lines.w + 2 * LABEL_GAP),\n h: APPLIANCE.h + (lines.h > 0 ? lines.h + LABEL_GAP : 0),\n pad: { x: 0, y: 0 },\n place: (inner) => {\n const glyph = {\n x: centreX(inner) - APPLIANCE.w / 2,\n y: inner.y,\n ...APPLIANCE,\n };\n return {\n appliance: applianceGlyph(node, glyph),\n text: lines.place(centreX(inner), glyph.y + glyph.h, 'middle'),\n bullets: [],\n };\n },\n };\n}\n\n/** The router glyph: a slanted body, an optional antenna and a row of jacks, as the renderers drew it before content sizing. */\nfunction applianceGlyph(\n node: DiagramNode,\n glyph: Box,\n): NonNullable<NodeLayout['appliance']> {\n const bodyX = glyph.x + 4;\n const bodyY = glyph.y + Math.max(12, Math.min(22, glyph.h * 0.28));\n const bodyW = glyph.w - 8;\n const bodyH = glyph.h - (bodyY - glyph.y) - 12;\n const slant = Math.max(4, Math.min(16, bodyW * 0.28, bodyH * 0.75));\n const body: Point[] = [\n { x: bodyX + slant, y: bodyY },\n { x: bodyX + bodyW, y: bodyY + 6 },\n { x: bodyX + bodyW - slant, y: bodyY + bodyH },\n { x: bodyX, y: bodyY + bodyH - 6 },\n ];\n const mastX = bodyX + slant + bodyW * 0.2;\n const antenna: [Point, Point][] =\n (node.antenna ?? true)\n ? [\n [\n { x: bodyX + slant + bodyW * 0.18, y: bodyY + 1 },\n { x: mastX - 3, y: glyph.y + 3 },\n ],\n [\n { x: mastX + 1, y: bodyY + 2 },\n { x: mastX + 1, y: glyph.y + 8 },\n ],\n ]\n : [];\n const jackCount = Math.max(0, Math.floor(node.appliancePorts ?? 4));\n const jackSpacing = Math.min(\n 13,\n Math.max(8, (bodyW - slant - 42) / Math.max(jackCount, 1)),\n );\n const jacks = Array.from({ length: jackCount }, (_, index) => ({\n x: bodyX + slant + 16 + index * jackSpacing,\n y: bodyY + bodyH - 15,\n w: 5,\n h: 12,\n }));\n const face: [Point, Point] = [\n { x: bodyX + slant, y: bodyY + bodyH - 1 },\n { x: bodyX + bodyW - slant, y: bodyY + bodyH + 3 },\n ];\n // Through a variable, not a literal, so the return skips the excess-property check against NodeLayout['appliance'].\n const parts = { body, face, antenna, jacks };\n return parts;\n}\n\nfunction centreX(box: Box): number {\n return box.x + box.w / 2;\n}\n\nfunction centredTop(box: Box, h: number): number {\n return box.y + (box.h - h) / 2;\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,19 @@
1
+ import type { DiagramLabelLine, DiagramTextColor } from '../../model/diagram-ir.ts';
2
+ import type { Font, FontWeight } from '../text/font.ts';
3
+ import type { TextAnchor, TextRun } from './graph-layout-result.ts';
4
+ export type TextLine = {
5
+ text: string;
6
+ color?: DiagramTextColor;
7
+ weight?: FontWeight;
8
+ };
9
+ /** Lines of one font stacked at its line height, measured once and placed later. */
10
+ export type TextBlock = {
11
+ w: number;
12
+ h: number;
13
+ /** `x` is the anchor of every line; `top` is the top of the first line box. */
14
+ place(x: number, top: number, anchor: TextAnchor): TextRun[];
15
+ };
16
+ /** The non-empty lines of a label, each with its own colour and weight. */
17
+ export declare function labelLines(label: string | DiagramLabelLine[] | string[] | undefined, color?: DiagramTextColor): TextLine[];
18
+ export declare function textBlock(lines: TextLine[], font: Font): TextBlock;
19
+ //# sourceMappingURL=text-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-block.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/text-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAOxD,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEpE,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,SAAS,GAAG;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,+EAA+E;IAC/E,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,EAAE,CAAC;CAC9D,CAAC;AAUF,2EAA2E;AAC3E,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,GAAG,gBAAgB,EAAE,GAAG,MAAM,EAAE,GAAG,SAAS,EACzD,KAAK,CAAC,EAAE,gBAAgB,GACvB,QAAQ,EAAE,CAiBZ;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,GAAG,SAAS,CA+BlE"}
@@ -0,0 +1,86 @@
1
+ import { fontAscent, fontDescent, fontLineHeight, measureText } from "../text/measure-text.js";
2
+
3
+ /** Lines of one font stacked at its line height, measured once and placed later. */
4
+
5
+ const FONT_WEIGHTS = [400, 500, 600, 700];
6
+ function nearestWeight(weight) {
7
+ return FONT_WEIGHTS.reduce((best, candidate) => Math.abs(candidate - weight) < Math.abs(best - weight) ? candidate : best);
8
+ }
9
+
10
+ /** The non-empty lines of a label, each with its own colour and weight. */
11
+ export function labelLines(label, color) {
12
+ const lines = [label ?? []].flat();
13
+ return lines.flatMap(line => {
14
+ const {
15
+ text,
16
+ textColor,
17
+ fontWeight
18
+ } = typeof line === 'string' ? {
19
+ text: line
20
+ } : line;
21
+ if (text.trim().length === 0) return [];
22
+ const lineColor = textColor ?? color;
23
+ return [{
24
+ text,
25
+ ...(lineColor ? {
26
+ color: lineColor
27
+ } : {}),
28
+ ...(fontWeight === undefined ? {} : {
29
+ weight: nearestWeight(fontWeight)
30
+ })
31
+ }];
32
+ });
33
+ }
34
+ export function textBlock(lines, font) {
35
+ const lineHeight = fontLineHeight(font);
36
+ const runs = lines.map(line => {
37
+ const lineFont = line.weight ? {
38
+ ...font,
39
+ weight: line.weight
40
+ } : font;
41
+ return {
42
+ line,
43
+ font: lineFont,
44
+ width: measureText(line.text, lineFont),
45
+ ascent: fontAscent(lineFont),
46
+ ink: fontAscent(lineFont) + fontDescent(lineFont)
47
+ };
48
+ });
49
+ return {
50
+ w: Math.max(0, ...runs.map(run => run.width)),
51
+ h: runs.length * lineHeight,
52
+ place(x, top, anchor) {
53
+ return runs.map((run, index) => {
54
+ const inkTop = top + index * lineHeight + (lineHeight - run.ink) / 2;
55
+ const left = lineLeft(x, run.width, anchor);
56
+ return {
57
+ text: run.line.text,
58
+ x,
59
+ y: inkTop + run.ascent,
60
+ anchor,
61
+ font: run.font,
62
+ ...(run.line.color ? {
63
+ color: run.line.color
64
+ } : {}),
65
+ bounds: {
66
+ x: left,
67
+ y: inkTop,
68
+ w: run.width,
69
+ h: run.ink
70
+ }
71
+ };
72
+ });
73
+ }
74
+ };
75
+ }
76
+ function lineLeft(x, width, anchor) {
77
+ switch (anchor) {
78
+ case 'start':
79
+ return x;
80
+ case 'end':
81
+ return x - width;
82
+ case 'middle':
83
+ return x - width / 2;
84
+ }
85
+ }
86
+ //# sourceMappingURL=text-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-block.js","names":["fontAscent","fontDescent","fontLineHeight","measureText","FONT_WEIGHTS","nearestWeight","weight","reduce","best","candidate","Math","abs","labelLines","label","color","lines","flat","flatMap","line","text","textColor","fontWeight","trim","length","lineColor","undefined","textBlock","font","lineHeight","runs","map","lineFont","width","ascent","ink","w","max","run","h","place","x","top","anchor","index","inkTop","left","lineLeft","y","bounds"],"sources":["../../../../src/lib/layouts/graph/text-block.ts"],"sourcesContent":["import type {\n DiagramLabelLine,\n DiagramTextColor,\n} from '../../model/diagram-ir.ts';\nimport type { Font, FontWeight } from '../text/font.ts';\nimport {\n fontAscent,\n fontDescent,\n fontLineHeight,\n measureText,\n} from '../text/measure-text.ts';\nimport type { TextAnchor, TextRun } from './graph-layout-result.ts';\n\nexport type TextLine = {\n text: string;\n color?: DiagramTextColor;\n weight?: FontWeight;\n};\n\n/** Lines of one font stacked at its line height, measured once and placed later. */\nexport type TextBlock = {\n w: number;\n h: number;\n /** `x` is the anchor of every line; `top` is the top of the first line box. */\n place(x: number, top: number, anchor: TextAnchor): TextRun[];\n};\n\nconst FONT_WEIGHTS: FontWeight[] = [400, 500, 600, 700];\n\nfunction nearestWeight(weight: number): FontWeight {\n return FONT_WEIGHTS.reduce((best, candidate) =>\n Math.abs(candidate - weight) < Math.abs(best - weight) ? candidate : best,\n );\n}\n\n/** The non-empty lines of a label, each with its own colour and weight. */\nexport function labelLines(\n label: string | DiagramLabelLine[] | string[] | undefined,\n color?: DiagramTextColor,\n): TextLine[] {\n const lines = [label ?? []].flat();\n return lines.flatMap((line): TextLine[] => {\n const { text, textColor, fontWeight } =\n typeof line === 'string' ? { text: line } : line;\n if (text.trim().length === 0) return [];\n const lineColor = textColor ?? color;\n return [\n {\n text,\n ...(lineColor ? { color: lineColor } : {}),\n ...(fontWeight === undefined\n ? {}\n : { weight: nearestWeight(fontWeight) }),\n },\n ];\n });\n}\n\nexport function textBlock(lines: TextLine[], font: Font): TextBlock {\n const lineHeight = fontLineHeight(font);\n const runs = lines.map((line) => {\n const lineFont = line.weight ? { ...font, weight: line.weight } : font;\n return {\n line,\n font: lineFont,\n width: measureText(line.text, lineFont),\n ascent: fontAscent(lineFont),\n ink: fontAscent(lineFont) + fontDescent(lineFont),\n };\n });\n return {\n w: Math.max(0, ...runs.map((run) => run.width)),\n h: runs.length * lineHeight,\n place(x, top, anchor) {\n return runs.map((run, index) => {\n const inkTop = top + index * lineHeight + (lineHeight - run.ink) / 2;\n const left = lineLeft(x, run.width, anchor);\n return {\n text: run.line.text,\n x,\n y: inkTop + run.ascent,\n anchor,\n font: run.font,\n ...(run.line.color ? { color: run.line.color } : {}),\n bounds: { x: left, y: inkTop, w: run.width, h: run.ink },\n };\n });\n },\n };\n}\n\nfunction lineLeft(x: number, width: number, anchor: TextAnchor): number {\n switch (anchor) {\n case 'start':\n return x;\n case 'end':\n return x - width;\n case 'middle':\n return x - width / 2;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,58 @@
1
+ import type { DiagramDensity } from '../../model/diagram-ir.ts';
2
+ import type { Font } from '../text/font.ts';
3
+ export type LayoutFonts = {
4
+ /** The title of a Card, or of a Box with an icon. */
5
+ title: Font;
6
+ /** A Card's description and items. */
7
+ body: Font;
8
+ caption: Font;
9
+ /** A centred Box label without an icon. */
10
+ boxLabel: Font;
11
+ note: Font;
12
+ marker: Font;
13
+ connector: Font;
14
+ appliance: Font;
15
+ groupLabel: Font;
16
+ edgeLabel: Font;
17
+ badge: Font;
18
+ portLabel: Font;
19
+ };
20
+ export type LayoutTokens = {
21
+ PAD_X: number;
22
+ PAD_Y: number;
23
+ ICON: number;
24
+ ICON_GAP: number;
25
+ GAP: number;
26
+ CHANNEL: number;
27
+ STUB: number;
28
+ LABEL_GAP: number;
29
+ CONTENT_PAD: number;
30
+ GROUP_PAD: number;
31
+ BAND_PAD: number;
32
+ BULLET_INDENT: number;
33
+ BLOCK_GAP: number;
34
+ CAPTION_GAP: number;
35
+ PORT_SPACING: number;
36
+ STACK_STEP: {
37
+ x: number;
38
+ y: number;
39
+ };
40
+ MARKER_ICON: number;
41
+ CONNECTOR_ICON: number;
42
+ BADGE_ICON: number;
43
+ JUNCTION: number;
44
+ APPLIANCE: {
45
+ w: number;
46
+ h: number;
47
+ };
48
+ RADIUS: number;
49
+ FLAT_RADIUS: number;
50
+ fonts: LayoutFonts;
51
+ };
52
+ /**
53
+ * The sizes the engine lays out with. Density scales only the space between
54
+ * elements (gaps, channels, group and diagram padding); node content and
55
+ * fonts keep their size, so text never shrinks to fit.
56
+ */
57
+ export declare function layoutTokens(density?: DiagramDensity): LayoutTokens;
58
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/lib/layouts/graph/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,MAAM,WAAW,GAAG;IACxB,qDAAqD;IACrD,KAAK,EAAE,IAAI,CAAC;IACZ,sCAAsC;IACtC,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,IAAI,CAAC;IACd,2CAA2C;IAC3C,QAAQ,EAAE,IAAI,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,IAAI,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,IAAI,CAAC;IACZ,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;CACpB,CAAC;AAQF;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,GAAE,cAA0B,GAClC,YAAY,CAyCd"}
@@ -0,0 +1,108 @@
1
+ const SPACING_SCALE = {
2
+ compact: 0.75,
3
+ regular: 1,
4
+ spacious: 1.5
5
+ };
6
+
7
+ /**
8
+ * The sizes the engine lays out with. Density scales only the space between
9
+ * elements (gaps, channels, group and diagram padding); node content and
10
+ * fonts keep their size, so text never shrinks to fit.
11
+ */
12
+ export function layoutTokens(density = 'regular') {
13
+ const scale = SPACING_SCALE[density];
14
+ return {
15
+ PAD_X: 16,
16
+ PAD_Y: 12,
17
+ ICON: 28,
18
+ ICON_GAP: 12,
19
+ GAP: 24 * scale,
20
+ CHANNEL: 8 * scale,
21
+ STUB: 16,
22
+ LABEL_GAP: 4,
23
+ CONTENT_PAD: 40 * scale,
24
+ GROUP_PAD: 12 * scale,
25
+ BAND_PAD: 6,
26
+ BULLET_INDENT: 12,
27
+ BLOCK_GAP: 8,
28
+ CAPTION_GAP: 8,
29
+ PORT_SPACING: 24,
30
+ STACK_STEP: {
31
+ x: 12,
32
+ y: 8
33
+ },
34
+ MARKER_ICON: 34,
35
+ CONNECTOR_ICON: 16,
36
+ BADGE_ICON: 22,
37
+ JUNCTION: 16,
38
+ APPLIANCE: {
39
+ w: 112,
40
+ h: 72
41
+ },
42
+ RADIUS: 16,
43
+ FLAT_RADIUS: 4,
44
+ fonts: {
45
+ title: {
46
+ face: 'sans',
47
+ size: 14,
48
+ weight: 600
49
+ },
50
+ body: {
51
+ face: 'sans',
52
+ size: 11,
53
+ weight: 400
54
+ },
55
+ caption: {
56
+ face: 'sans',
57
+ size: 11,
58
+ weight: 500
59
+ },
60
+ boxLabel: {
61
+ face: 'mono',
62
+ size: 12,
63
+ weight: 500
64
+ },
65
+ note: {
66
+ face: 'sans',
67
+ size: 10,
68
+ weight: 600
69
+ },
70
+ marker: {
71
+ face: 'sans',
72
+ size: 11,
73
+ weight: 700
74
+ },
75
+ connector: {
76
+ face: 'sans',
77
+ size: 10,
78
+ weight: 700
79
+ },
80
+ appliance: {
81
+ face: 'sans',
82
+ size: 12,
83
+ weight: 600
84
+ },
85
+ groupLabel: {
86
+ face: 'sans',
87
+ size: 12,
88
+ weight: 600
89
+ },
90
+ edgeLabel: {
91
+ face: 'mono',
92
+ size: 10,
93
+ weight: 400
94
+ },
95
+ badge: {
96
+ face: 'sans',
97
+ size: 10,
98
+ weight: 600
99
+ },
100
+ portLabel: {
101
+ face: 'sans',
102
+ size: 9,
103
+ weight: 600
104
+ }
105
+ }
106
+ };
107
+ }
108
+ //# sourceMappingURL=tokens.js.map