@zukhruf/diagram 0.3.30 → 0.3.32
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.
- package/dist/lib/layouts/graph/areas.d.ts +27 -0
- package/dist/lib/layouts/graph/areas.d.ts.map +1 -0
- package/dist/lib/layouts/graph/areas.js +196 -0
- package/dist/lib/layouts/graph/areas.js.map +1 -0
- package/dist/lib/layouts/graph/graph-layout-result.d.ts +95 -0
- package/dist/lib/layouts/graph/graph-layout-result.d.ts.map +1 -0
- package/dist/lib/layouts/graph/graph-layout-result.js +2 -0
- package/dist/lib/layouts/graph/graph-layout-result.js.map +1 -0
- package/dist/lib/layouts/graph/graph-layout.d.ts +2 -1
- package/dist/lib/layouts/graph/graph-layout.d.ts.map +1 -1
- package/dist/lib/layouts/graph/graph-layout.js +5 -3
- package/dist/lib/layouts/graph/graph-layout.js.map +1 -1
- package/dist/lib/layouts/graph/gutters.d.ts +25 -0
- package/dist/lib/layouts/graph/gutters.d.ts.map +1 -0
- package/dist/lib/layouts/graph/gutters.js +124 -0
- package/dist/lib/layouts/graph/gutters.js.map +1 -0
- package/dist/lib/layouts/graph/layout.d.ts +10 -0
- package/dist/lib/layouts/graph/layout.d.ts.map +1 -0
- package/dist/lib/layouts/graph/layout.js +164 -0
- package/dist/lib/layouts/graph/layout.js.map +1 -0
- package/dist/lib/layouts/graph/legacy-graph-layout.d.ts +6 -0
- package/dist/lib/layouts/graph/legacy-graph-layout.d.ts.map +1 -0
- package/dist/lib/layouts/graph/legacy-graph-layout.js +542 -0
- package/dist/lib/layouts/graph/legacy-graph-layout.js.map +1 -0
- package/dist/lib/layouts/graph/measure.d.ts +44 -0
- package/dist/lib/layouts/graph/measure.d.ts.map +1 -0
- package/dist/lib/layouts/graph/measure.js +372 -0
- package/dist/lib/layouts/graph/measure.js.map +1 -0
- package/dist/lib/layouts/graph/node-content.d.ts +16 -0
- package/dist/lib/layouts/graph/node-content.d.ts.map +1 -0
- package/dist/lib/layouts/graph/node-content.js +323 -0
- package/dist/lib/layouts/graph/node-content.js.map +1 -0
- package/dist/lib/layouts/graph/text-block.d.ts +19 -0
- package/dist/lib/layouts/graph/text-block.d.ts.map +1 -0
- package/dist/lib/layouts/graph/text-block.js +86 -0
- package/dist/lib/layouts/graph/text-block.js.map +1 -0
- package/dist/lib/layouts/graph/tokens.d.ts +53 -0
- package/dist/lib/layouts/graph/tokens.d.ts.map +1 -0
- package/dist/lib/layouts/graph/tokens.js +95 -0
- package/dist/lib/layouts/graph/tokens.js.map +1 -0
- package/dist/lib/layouts/graph/tracks.d.ts +20 -0
- package/dist/lib/layouts/graph/tracks.d.ts.map +1 -0
- package/dist/lib/layouts/graph/tracks.js +47 -0
- package/dist/lib/layouts/graph/tracks.js.map +1 -0
- package/dist/lib/layouts/text/font-metrics.generated.d.ts +18 -0
- package/dist/lib/layouts/text/font-metrics.generated.d.ts.map +1 -0
- package/dist/lib/layouts/text/font-metrics.generated.js +1043 -0
- package/dist/lib/layouts/text/font-metrics.generated.js.map +1 -0
- package/dist/lib/layouts/text/font.d.ts +14 -0
- package/dist/lib/layouts/text/font.d.ts.map +1 -0
- package/dist/lib/layouts/text/font.js +11 -0
- package/dist/lib/layouts/text/font.js.map +1 -0
- package/dist/lib/layouts/text/measure-text.d.ts +13 -0
- package/dist/lib/layouts/text/measure-text.d.ts.map +1 -0
- package/dist/lib/layouts/text/measure-text.js +67 -0
- package/dist/lib/layouts/text/measure-text.js.map +1 -0
- package/dist/lib/model/diagram-ir.d.ts +11 -1
- package/dist/lib/model/diagram-ir.d.ts.map +1 -1
- package/dist/lib/model/diagram-ir.js.map +1 -1
- package/dist/lib/renderers/canvas/graph-canvas.d.ts.map +1 -1
- package/dist/lib/renderers/canvas/graph-canvas.js +148 -138
- package/dist/lib/renderers/canvas/graph-canvas.js.map +1 -1
- package/dist/lib/renderers/html/graph-html.d.ts.map +1 -1
- package/dist/lib/renderers/html/graph-html.js +462 -511
- package/dist/lib/renderers/html/graph-html.js.map +1 -1
- package/dist/lib/renderers/shared/graph-parts.d.ts +15 -13
- package/dist/lib/renderers/shared/graph-parts.d.ts.map +1 -1
- package/dist/lib/renderers/shared/graph-parts.js +649 -644
- package/dist/lib/renderers/shared/graph-parts.js.map +1 -1
- package/dist/lib/renderers/shared/node-parts.d.ts +20 -19
- package/dist/lib/renderers/shared/node-parts.d.ts.map +1 -1
- package/dist/lib/renderers/shared/node-parts.js +678 -811
- package/dist/lib/renderers/shared/node-parts.js.map +1 -1
- package/dist/lib/renderers/shared/run-spans.d.ts +8 -0
- package/dist/lib/renderers/shared/run-spans.d.ts.map +1 -0
- package/dist/lib/renderers/shared/run-spans.js +18 -0
- package/dist/lib/renderers/shared/run-spans.js.map +1 -0
- package/dist/lib/renderers/shared/text-runs.d.ts +21 -0
- package/dist/lib/renderers/shared/text-runs.d.ts.map +1 -0
- package/dist/lib/renderers/shared/text-runs.js +44 -0
- package/dist/lib/renderers/shared/text-runs.js.map +1 -0
- package/dist/lib/renderers/svg/graph-svg.d.ts.map +1 -1
- package/dist/lib/renderers/svg/graph-svg.js +304 -465
- package/dist/lib/renderers/svg/graph-svg.js.map +1 -1
- package/dist/lib/renderers/svg/timeline-svg.d.ts.map +1 -1
- package/dist/lib/renderers/svg/timeline-svg.js +10 -5
- package/dist/lib/renderers/svg/timeline-svg.js.map +1 -1
- package/dist/lib/renderers/webgpu/graph-flow-effects.d.ts +2 -2
- package/dist/lib/renderers/webgpu/graph-flow-effects.d.ts.map +1 -1
- package/dist/lib/renderers/webgpu/graph-flow-effects.js.map +1 -1
- package/package.json +3 -1
- 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,53 @@
|
|
|
1
|
+
import type { Font } from '../text/font.ts';
|
|
2
|
+
export type LayoutFonts = {
|
|
3
|
+
/** The title of a Card, or of a Box with an icon. */
|
|
4
|
+
title: Font;
|
|
5
|
+
/** A Card's description and items. */
|
|
6
|
+
body: Font;
|
|
7
|
+
caption: Font;
|
|
8
|
+
/** A centred Box label without an icon. */
|
|
9
|
+
boxLabel: Font;
|
|
10
|
+
note: Font;
|
|
11
|
+
marker: Font;
|
|
12
|
+
connector: Font;
|
|
13
|
+
appliance: Font;
|
|
14
|
+
groupLabel: Font;
|
|
15
|
+
edgeLabel: Font;
|
|
16
|
+
badge: Font;
|
|
17
|
+
portLabel: Font;
|
|
18
|
+
};
|
|
19
|
+
export type LayoutTokens = {
|
|
20
|
+
PAD_X: number;
|
|
21
|
+
PAD_Y: number;
|
|
22
|
+
ICON: number;
|
|
23
|
+
ICON_GAP: number;
|
|
24
|
+
GAP: number;
|
|
25
|
+
CHANNEL: number;
|
|
26
|
+
STUB: number;
|
|
27
|
+
LABEL_GAP: number;
|
|
28
|
+
CONTENT_PAD: number;
|
|
29
|
+
GROUP_PAD: number;
|
|
30
|
+
BAND_PAD: number;
|
|
31
|
+
BULLET_INDENT: number;
|
|
32
|
+
BLOCK_GAP: number;
|
|
33
|
+
CAPTION_GAP: number;
|
|
34
|
+
PORT_SPACING: number;
|
|
35
|
+
STACK_STEP: {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
};
|
|
39
|
+
MARKER_ICON: number;
|
|
40
|
+
CONNECTOR_ICON: number;
|
|
41
|
+
BADGE_ICON: number;
|
|
42
|
+
JUNCTION: number;
|
|
43
|
+
APPLIANCE: {
|
|
44
|
+
w: number;
|
|
45
|
+
h: number;
|
|
46
|
+
};
|
|
47
|
+
RADIUS: number;
|
|
48
|
+
FLAT_RADIUS: number;
|
|
49
|
+
fonts: LayoutFonts;
|
|
50
|
+
};
|
|
51
|
+
/** The sizes the engine lays out with. */
|
|
52
|
+
export declare const LAYOUT_TOKENS: LayoutTokens;
|
|
53
|
+
//# 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,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;AAEF,0CAA0C;AAC1C,eAAO,MAAM,aAAa,EAAE,YAsC3B,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** The sizes the engine lays out with. */
|
|
2
|
+
export const LAYOUT_TOKENS = {
|
|
3
|
+
PAD_X: 16,
|
|
4
|
+
PAD_Y: 12,
|
|
5
|
+
ICON: 28,
|
|
6
|
+
ICON_GAP: 12,
|
|
7
|
+
GAP: 24,
|
|
8
|
+
CHANNEL: 8,
|
|
9
|
+
STUB: 16,
|
|
10
|
+
LABEL_GAP: 4,
|
|
11
|
+
CONTENT_PAD: 40,
|
|
12
|
+
GROUP_PAD: 12,
|
|
13
|
+
BAND_PAD: 6,
|
|
14
|
+
BULLET_INDENT: 12,
|
|
15
|
+
BLOCK_GAP: 8,
|
|
16
|
+
CAPTION_GAP: 8,
|
|
17
|
+
PORT_SPACING: 24,
|
|
18
|
+
STACK_STEP: {
|
|
19
|
+
x: 12,
|
|
20
|
+
y: 8
|
|
21
|
+
},
|
|
22
|
+
MARKER_ICON: 34,
|
|
23
|
+
CONNECTOR_ICON: 16,
|
|
24
|
+
BADGE_ICON: 22,
|
|
25
|
+
JUNCTION: 16,
|
|
26
|
+
APPLIANCE: {
|
|
27
|
+
w: 112,
|
|
28
|
+
h: 72
|
|
29
|
+
},
|
|
30
|
+
RADIUS: 16,
|
|
31
|
+
FLAT_RADIUS: 4,
|
|
32
|
+
fonts: {
|
|
33
|
+
title: {
|
|
34
|
+
face: 'sans',
|
|
35
|
+
size: 14,
|
|
36
|
+
weight: 600
|
|
37
|
+
},
|
|
38
|
+
body: {
|
|
39
|
+
face: 'sans',
|
|
40
|
+
size: 11,
|
|
41
|
+
weight: 400
|
|
42
|
+
},
|
|
43
|
+
caption: {
|
|
44
|
+
face: 'sans',
|
|
45
|
+
size: 11,
|
|
46
|
+
weight: 500
|
|
47
|
+
},
|
|
48
|
+
boxLabel: {
|
|
49
|
+
face: 'mono',
|
|
50
|
+
size: 12,
|
|
51
|
+
weight: 500
|
|
52
|
+
},
|
|
53
|
+
note: {
|
|
54
|
+
face: 'sans',
|
|
55
|
+
size: 10,
|
|
56
|
+
weight: 600
|
|
57
|
+
},
|
|
58
|
+
marker: {
|
|
59
|
+
face: 'sans',
|
|
60
|
+
size: 11,
|
|
61
|
+
weight: 700
|
|
62
|
+
},
|
|
63
|
+
connector: {
|
|
64
|
+
face: 'sans',
|
|
65
|
+
size: 10,
|
|
66
|
+
weight: 700
|
|
67
|
+
},
|
|
68
|
+
appliance: {
|
|
69
|
+
face: 'sans',
|
|
70
|
+
size: 12,
|
|
71
|
+
weight: 600
|
|
72
|
+
},
|
|
73
|
+
groupLabel: {
|
|
74
|
+
face: 'sans',
|
|
75
|
+
size: 12,
|
|
76
|
+
weight: 600
|
|
77
|
+
},
|
|
78
|
+
edgeLabel: {
|
|
79
|
+
face: 'mono',
|
|
80
|
+
size: 10,
|
|
81
|
+
weight: 400
|
|
82
|
+
},
|
|
83
|
+
badge: {
|
|
84
|
+
face: 'sans',
|
|
85
|
+
size: 10,
|
|
86
|
+
weight: 600
|
|
87
|
+
},
|
|
88
|
+
portLabel: {
|
|
89
|
+
face: 'sans',
|
|
90
|
+
size: 9,
|
|
91
|
+
weight: 600
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","names":["LAYOUT_TOKENS","PAD_X","PAD_Y","ICON","ICON_GAP","GAP","CHANNEL","STUB","LABEL_GAP","CONTENT_PAD","GROUP_PAD","BAND_PAD","BULLET_INDENT","BLOCK_GAP","CAPTION_GAP","PORT_SPACING","STACK_STEP","x","y","MARKER_ICON","CONNECTOR_ICON","BADGE_ICON","JUNCTION","APPLIANCE","w","h","RADIUS","FLAT_RADIUS","fonts","title","face","size","weight","body","caption","boxLabel","note","marker","connector","appliance","groupLabel","edgeLabel","badge","portLabel"],"sources":["../../../../src/lib/layouts/graph/tokens.ts"],"sourcesContent":["import type { Font } from '../text/font.ts';\n\nexport type LayoutFonts = {\n /** The title of a Card, or of a Box with an icon. */\n title: Font;\n /** A Card's description and items. */\n body: Font;\n caption: Font;\n /** A centred Box label without an icon. */\n boxLabel: Font;\n note: Font;\n marker: Font;\n connector: Font;\n appliance: Font;\n groupLabel: Font;\n edgeLabel: Font;\n badge: Font;\n portLabel: Font;\n};\n\nexport type LayoutTokens = {\n PAD_X: number;\n PAD_Y: number;\n ICON: number;\n ICON_GAP: number;\n GAP: number;\n CHANNEL: number;\n STUB: number;\n LABEL_GAP: number;\n CONTENT_PAD: number;\n GROUP_PAD: number;\n BAND_PAD: number;\n BULLET_INDENT: number;\n BLOCK_GAP: number;\n CAPTION_GAP: number;\n PORT_SPACING: number;\n STACK_STEP: { x: number; y: number };\n MARKER_ICON: number;\n CONNECTOR_ICON: number;\n BADGE_ICON: number;\n JUNCTION: number;\n APPLIANCE: { w: number; h: number };\n RADIUS: number;\n FLAT_RADIUS: number;\n fonts: LayoutFonts;\n};\n\n/** The sizes the engine lays out with. */\nexport const LAYOUT_TOKENS: LayoutTokens = {\n PAD_X: 16,\n PAD_Y: 12,\n ICON: 28,\n ICON_GAP: 12,\n GAP: 24,\n CHANNEL: 8,\n STUB: 16,\n LABEL_GAP: 4,\n CONTENT_PAD: 40,\n GROUP_PAD: 12,\n BAND_PAD: 6,\n BULLET_INDENT: 12,\n BLOCK_GAP: 8,\n CAPTION_GAP: 8,\n PORT_SPACING: 24,\n STACK_STEP: { x: 12, y: 8 },\n MARKER_ICON: 34,\n CONNECTOR_ICON: 16,\n BADGE_ICON: 22,\n JUNCTION: 16,\n APPLIANCE: { w: 112, h: 72 },\n RADIUS: 16,\n FLAT_RADIUS: 4,\n fonts: {\n title: { face: 'sans', size: 14, weight: 600 },\n body: { face: 'sans', size: 11, weight: 400 },\n caption: { face: 'sans', size: 11, weight: 500 },\n boxLabel: { face: 'mono', size: 12, weight: 500 },\n note: { face: 'sans', size: 10, weight: 600 },\n marker: { face: 'sans', size: 11, weight: 700 },\n connector: { face: 'sans', size: 10, weight: 700 },\n appliance: { face: 'sans', size: 12, weight: 600 },\n groupLabel: { face: 'sans', size: 12, weight: 600 },\n edgeLabel: { face: 'mono', size: 10, weight: 400 },\n badge: { face: 'sans', size: 10, weight: 600 },\n portLabel: { face: 'sans', size: 9, weight: 600 },\n },\n};\n"],"mappings":"AA+CA;AACA,OAAO,MAAMA,aAA2B,GAAG;EACzCC,KAAK,EAAE,EAAE;EACTC,KAAK,EAAE,EAAE;EACTC,IAAI,EAAE,EAAE;EACRC,QAAQ,EAAE,EAAE;EACZC,GAAG,EAAE,EAAE;EACPC,OAAO,EAAE,CAAC;EACVC,IAAI,EAAE,EAAE;EACRC,SAAS,EAAE,CAAC;EACZC,WAAW,EAAE,EAAE;EACfC,SAAS,EAAE,EAAE;EACbC,QAAQ,EAAE,CAAC;EACXC,aAAa,EAAE,EAAE;EACjBC,SAAS,EAAE,CAAC;EACZC,WAAW,EAAE,CAAC;EACdC,YAAY,EAAE,EAAE;EAChBC,UAAU,EAAE;IAAEC,CAAC,EAAE,EAAE;IAAEC,CAAC,EAAE;EAAE,CAAC;EAC3BC,WAAW,EAAE,EAAE;EACfC,cAAc,EAAE,EAAE;EAClBC,UAAU,EAAE,EAAE;EACdC,QAAQ,EAAE,EAAE;EACZC,SAAS,EAAE;IAAEC,CAAC,EAAE,GAAG;IAAEC,CAAC,EAAE;EAAG,CAAC;EAC5BC,MAAM,EAAE,EAAE;EACVC,WAAW,EAAE,CAAC;EACdC,KAAK,EAAE;IACLC,KAAK,EAAE;MAAEC,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAC9CC,IAAI,EAAE;MAAEH,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAC7CE,OAAO,EAAE;MAAEJ,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAChDG,QAAQ,EAAE;MAAEL,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IACjDI,IAAI,EAAE;MAAEN,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAC7CK,MAAM,EAAE;MAAEP,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAC/CM,SAAS,EAAE;MAAER,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAClDO,SAAS,EAAE;MAAET,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAClDQ,UAAU,EAAE;MAAEV,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IACnDS,SAAS,EAAE;MAAEX,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAClDU,KAAK,EAAE;MAAEZ,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,EAAE;MAAEC,MAAM,EAAE;IAAI,CAAC;IAC9CW,SAAS,EAAE;MAAEb,IAAI,EAAE,MAAM;MAAEC,IAAI,EAAE,CAAC;MAAEC,MAAM,EAAE;IAAI;EAClD;AACF,CAAC","ignoreList":[]}
|