@rankonelabs/livid-svg 0.1.0
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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/geometry.d.ts +45 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +94 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/render.d.ts +27 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +159 -0
- package/dist/render.js.map +1 -0
- package/dist/shapes.d.ts +19 -0
- package/dist/shapes.d.ts.map +1 -0
- package/dist/shapes.js +81 -0
- package/dist/shapes.js.map +1 -0
- package/dist/theme.d.ts +78 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +63 -0
- package/dist/theme.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Steven Ciraolo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @rankonelabs/livid-svg
|
|
2
|
+
|
|
3
|
+
`LaidOutDiagram` to an SVG string, for [livid](https://github.com/RankOneLabs/livid).
|
|
4
|
+
|
|
5
|
+
Build-time only. No DOM, no client JS, and nothing measured — geometry arrives
|
|
6
|
+
from [`@rankonelabs/livid-core`](https://www.npmjs.com/package/@rankonelabs/livid-core)
|
|
7
|
+
already computed, so this package draws and does not lay out. That is what makes
|
|
8
|
+
the SVG in a post and the React canvas in an app the *same map* rather than two
|
|
9
|
+
drawings that drifted.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
npm install @rankonelabs/livid-svg @rankonelabs/livid-core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Core is a peer dependency, and the only one. Nothing is imported at runtime —
|
|
18
|
+
this package emits zero dependencies of its own.
|
|
19
|
+
|
|
20
|
+
## Use
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { layout, validateDiagram } from '@rankonelabs/livid-core'
|
|
24
|
+
import { renderSvg } from '@rankonelabs/livid-svg'
|
|
25
|
+
|
|
26
|
+
const valid = validateDiagram(registry, spec)
|
|
27
|
+
if (!valid.ok) return valid.error
|
|
28
|
+
|
|
29
|
+
const laid = await layout(valid.value)
|
|
30
|
+
if (!laid.ok) return laid.error
|
|
31
|
+
|
|
32
|
+
const svg = renderSvg(laid.value, {
|
|
33
|
+
title: 'Refund approval at HITL',
|
|
34
|
+
theme: { palette: { lines: { 'line-critical': '#D64500', 'line-parallel': '#1B6CA8' } } },
|
|
35
|
+
})
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Labels
|
|
39
|
+
|
|
40
|
+
Boxes carry their own text. Circles and diamonds cannot — core holds them to a
|
|
41
|
+
fixed width because growing one distorts it past recognition, and shape carries
|
|
42
|
+
type — so their labels sit alongside with a leader tick, which is also how a
|
|
43
|
+
transit map names a junction. Set `metrics.labelSide` to `right` for a
|
|
44
|
+
top-to-bottom layout.
|
|
45
|
+
|
|
46
|
+
Text is estimated rather than measured (there is no DOM at build time) and the
|
|
47
|
+
estimate errs wide: a label with room to spare reads fine, a clipped one does
|
|
48
|
+
not. The viewport always includes outside labels, so nothing is cut off.
|
|
49
|
+
|
|
50
|
+
## Colour
|
|
51
|
+
|
|
52
|
+
`LineSpec.color` is a token, not a colour — core has no palette. Configure
|
|
53
|
+
tokens through `palette.lines`; any token left unconfigured takes a colour from
|
|
54
|
+
`palette.ramp` by line order, so an unthemed diagram still renders as a map
|
|
55
|
+
rather than one grey tangle.
|
|
56
|
+
|
|
57
|
+
An edge takes the colour of where it is *going*. Track between two stations on
|
|
58
|
+
one line is that line; track leaving a router onto another line already belongs
|
|
59
|
+
to the new one, which is what makes an interchange read as a change. Edges that
|
|
60
|
+
cross lines are drawn at `branchWeight`, lighter than the track they leave.
|
|
61
|
+
|
|
62
|
+
## Drill-down
|
|
63
|
+
|
|
64
|
+
Levels are stacked, not made interactive: a static file has to contain every
|
|
65
|
+
level it can reveal, and stacking reveals them without script. Pass
|
|
66
|
+
`levels: 'root'` to draw only the top. Descending on demand belongs to the React
|
|
67
|
+
renderer.
|
|
68
|
+
|
|
69
|
+
Feed it `layoutDeep()` output if you want nested levels to have geometry.
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
Everything visual is config — `palette`, `typography`, `metrics` — and nothing
|
|
74
|
+
is component injection. Both renderers are closed, which is what guarantees they
|
|
75
|
+
agree.
|
|
76
|
+
|
|
77
|
+
MIT.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["../src/geometry.ts","../src/index.ts","../src/render.ts","../src/shapes.ts","../src/theme.ts"],"version":"5.9.3"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where things sit. Core lays out the graph; this works out what the graph's
|
|
3
|
+
* *labels* need on top of that, which core cannot know because it has no
|
|
4
|
+
* opinion about type.
|
|
5
|
+
*/
|
|
6
|
+
import type { NodeShape, Point, Size } from '@rankonelabs/livid-core';
|
|
7
|
+
import type { Metrics, Typography } from './theme.js';
|
|
8
|
+
export interface Box {
|
|
9
|
+
readonly minX: number;
|
|
10
|
+
readonly minY: number;
|
|
11
|
+
readonly maxX: number;
|
|
12
|
+
readonly maxY: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function boxOf(position: Point, size: Size): Box;
|
|
15
|
+
export declare const EMPTY_BOX: Box;
|
|
16
|
+
export declare function unionOf(boxes: readonly Box[]): Box;
|
|
17
|
+
export declare function boxAround(points: readonly Point[], slack: number): Box;
|
|
18
|
+
/**
|
|
19
|
+
* Text is estimated, not measured: rendering happens at build time with no DOM
|
|
20
|
+
* and no font metrics. The estimate only has to be good enough to reserve
|
|
21
|
+
* space, and it errs wide — a label with room to spare reads fine, a clipped
|
|
22
|
+
* one does not.
|
|
23
|
+
*/
|
|
24
|
+
export declare function estimateTextWidth(text: string, fontSize: number, advanceRatio: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Whether a shape can carry its own label.
|
|
27
|
+
*
|
|
28
|
+
* Circles and diamonds cannot: core holds them to a fixed width because
|
|
29
|
+
* growing one distorts it past recognition, and shape carries type. So their
|
|
30
|
+
* names sit alongside, which is also how a transit map names a junction.
|
|
31
|
+
*/
|
|
32
|
+
export type LabelPlacement = 'inside' | 'beside';
|
|
33
|
+
export declare function labelPlacementOf(shape: NodeShape): LabelPlacement;
|
|
34
|
+
export interface PlacedLabel {
|
|
35
|
+
readonly text: string;
|
|
36
|
+
readonly x: number;
|
|
37
|
+
readonly y: number;
|
|
38
|
+
readonly anchor: 'middle' | 'start';
|
|
39
|
+
/** Space the label occupies, which the viewport has to include. */
|
|
40
|
+
readonly box: Box;
|
|
41
|
+
/** Tick from the shape out to the label; absent when the label is inside. */
|
|
42
|
+
readonly leader: readonly [Point, Point] | null;
|
|
43
|
+
}
|
|
44
|
+
export declare function placeLabel(text: string, shape: NodeShape, position: Point, size: Size, typography: Typography, metrics: Metrics): PlacedLabel;
|
|
45
|
+
//# sourceMappingURL=geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,GAAG;IAClB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,GAAG,CAOtD;AAED,eAAO,MAAM,SAAS,EAAE,GAA0E,CAAC;AAEnG,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,EAAE,GAAG,GAAG,CAUlD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CAStE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAE9F;AAED;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAIjD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAEjE;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;IACpC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;CACjD;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,KAAK,EACf,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,GACf,WAAW,CAoDb"}
|
package/dist/geometry.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where things sit. Core lays out the graph; this works out what the graph's
|
|
3
|
+
* *labels* need on top of that, which core cannot know because it has no
|
|
4
|
+
* opinion about type.
|
|
5
|
+
*/
|
|
6
|
+
export function boxOf(position, size) {
|
|
7
|
+
return {
|
|
8
|
+
minX: position.x,
|
|
9
|
+
minY: position.y,
|
|
10
|
+
maxX: position.x + size.width,
|
|
11
|
+
maxY: position.y + size.height,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export const EMPTY_BOX = { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };
|
|
15
|
+
export function unionOf(boxes) {
|
|
16
|
+
return boxes.reduce((left, right) => ({
|
|
17
|
+
minX: Math.min(left.minX, right.minX),
|
|
18
|
+
minY: Math.min(left.minY, right.minY),
|
|
19
|
+
maxX: Math.max(left.maxX, right.maxX),
|
|
20
|
+
maxY: Math.max(left.maxY, right.maxY),
|
|
21
|
+
}), EMPTY_BOX);
|
|
22
|
+
}
|
|
23
|
+
export function boxAround(points, slack) {
|
|
24
|
+
return unionOf(points.map((point) => ({
|
|
25
|
+
minX: point.x - slack,
|
|
26
|
+
minY: point.y - slack,
|
|
27
|
+
maxX: point.x + slack,
|
|
28
|
+
maxY: point.y + slack,
|
|
29
|
+
})));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Text is estimated, not measured: rendering happens at build time with no DOM
|
|
33
|
+
* and no font metrics. The estimate only has to be good enough to reserve
|
|
34
|
+
* space, and it errs wide — a label with room to spare reads fine, a clipped
|
|
35
|
+
* one does not.
|
|
36
|
+
*/
|
|
37
|
+
export function estimateTextWidth(text, fontSize, advanceRatio) {
|
|
38
|
+
return text.length * fontSize * advanceRatio;
|
|
39
|
+
}
|
|
40
|
+
const POINT_SHAPES = new Set(['circle', 'diamond']);
|
|
41
|
+
export function labelPlacementOf(shape) {
|
|
42
|
+
return POINT_SHAPES.has(shape) ? 'beside' : 'inside';
|
|
43
|
+
}
|
|
44
|
+
export function placeLabel(text, shape, position, size, typography, metrics) {
|
|
45
|
+
const width = estimateTextWidth(text, typography.labelSize, typography.advanceRatio);
|
|
46
|
+
const height = typography.labelSize;
|
|
47
|
+
const centreX = position.x + size.width / 2;
|
|
48
|
+
const centreY = position.y + size.height / 2;
|
|
49
|
+
if (labelPlacementOf(shape) === 'inside') {
|
|
50
|
+
// Dominant-baseline is unreliable across renderers, so the baseline is
|
|
51
|
+
// nudged by a third of the cap height instead.
|
|
52
|
+
const y = centreY + height / 3;
|
|
53
|
+
return {
|
|
54
|
+
text,
|
|
55
|
+
x: centreX,
|
|
56
|
+
y,
|
|
57
|
+
anchor: 'middle',
|
|
58
|
+
box: boxOf(position, size),
|
|
59
|
+
leader: null,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (metrics.labelSide === 'right') {
|
|
63
|
+
const startX = position.x + size.width + metrics.leader + metrics.labelGap;
|
|
64
|
+
return {
|
|
65
|
+
text,
|
|
66
|
+
x: startX,
|
|
67
|
+
y: centreY + height / 3,
|
|
68
|
+
anchor: 'start',
|
|
69
|
+
box: { minX: startX, minY: centreY - height, maxX: startX + width, maxY: centreY + height },
|
|
70
|
+
leader: [
|
|
71
|
+
{ x: position.x + size.width, y: centreY },
|
|
72
|
+
{ x: position.x + size.width + metrics.leader, y: centreY },
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const baseline = position.y + size.height + metrics.leader + metrics.labelGap + height;
|
|
77
|
+
return {
|
|
78
|
+
text,
|
|
79
|
+
x: centreX,
|
|
80
|
+
y: baseline,
|
|
81
|
+
anchor: 'middle',
|
|
82
|
+
box: {
|
|
83
|
+
minX: centreX - width / 2,
|
|
84
|
+
minY: position.y + size.height,
|
|
85
|
+
maxX: centreX + width / 2,
|
|
86
|
+
maxY: baseline + metrics.labelGap,
|
|
87
|
+
},
|
|
88
|
+
leader: [
|
|
89
|
+
{ x: centreX, y: position.y + size.height },
|
|
90
|
+
{ x: centreX, y: position.y + size.height + metrics.leader },
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rankonelabs/livid-svg — `LaidOutDiagram` to an SVG string.
|
|
3
|
+
*
|
|
4
|
+
* Build-time, zero client JS. Geometry comes from core already computed, so
|
|
5
|
+
* this package measures nothing and lays out nothing; it draws.
|
|
6
|
+
*/
|
|
7
|
+
export { type SvgOptions, renderSvg, escapeText, escapeAttr } from './render.js';
|
|
8
|
+
export { type LabelSide, type Palette, type Typography, type Metrics, type SvgTheme, type SvgThemeOverrides, DEFAULT_PALETTE, DEFAULT_TYPOGRAPHY, DEFAULT_METRICS, DEFAULT_THEME, resolveTheme, lineColour, } from './theme.js';
|
|
9
|
+
export { type Box, type LabelPlacement, type PlacedLabel, boxOf, unionOf, boxAround, estimateTextWidth, labelPlacementOf, placeLabel, } from './geometry.js';
|
|
10
|
+
export { type ShapeStyle, shapeMarkup, glyphMarkup } from './shapes.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEjF,OAAO,EACL,KAAK,SAAS,EACd,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,KAAK,GAAG,EACR,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,EACL,OAAO,EACP,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,GACX,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,KAAK,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rankonelabs/livid-svg — `LaidOutDiagram` to an SVG string.
|
|
3
|
+
*
|
|
4
|
+
* Build-time, zero client JS. Geometry comes from core already computed, so
|
|
5
|
+
* this package measures nothing and lays out nothing; it draws.
|
|
6
|
+
*/
|
|
7
|
+
export { renderSvg, escapeText, escapeAttr } from './render.js';
|
|
8
|
+
export { DEFAULT_PALETTE, DEFAULT_TYPOGRAPHY, DEFAULT_METRICS, DEFAULT_THEME, resolveTheme, lineColour, } from './theme.js';
|
|
9
|
+
export { boxOf, unionOf, boxAround, estimateTextWidth, labelPlacementOf, placeLabel, } from './geometry.js';
|
|
10
|
+
export { shapeMarkup, glyphMarkup } from './shapes.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAmB,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEjF,OAAO,EAOL,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAIL,KAAK,EACL,OAAO,EACP,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,GACX,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAmB,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `LaidOutDiagram` to an SVG string.
|
|
3
|
+
*
|
|
4
|
+
* Build-time only: no DOM, no client JS, and nothing measured — geometry
|
|
5
|
+
* arrives from core already computed. The renderer's whole job is turning
|
|
6
|
+
* placed boxes and routes into markup, plus the one thing core cannot know,
|
|
7
|
+
* which is where labels go.
|
|
8
|
+
*
|
|
9
|
+
* Drill-down levels are stacked rather than made interactive. A static file
|
|
10
|
+
* has to contain every level it can reveal, and stacking reveals them without
|
|
11
|
+
* script; the React renderer is where descending on demand belongs.
|
|
12
|
+
*/
|
|
13
|
+
import type { AnyRegistry, LaidOutDiagram } from '@rankonelabs/livid-core';
|
|
14
|
+
import { type SvgThemeOverrides } from './theme.js';
|
|
15
|
+
export interface SvgOptions {
|
|
16
|
+
readonly theme?: SvgThemeOverrides;
|
|
17
|
+
/** Accessible name for the whole figure. */
|
|
18
|
+
readonly title?: string | null;
|
|
19
|
+
/** Caption above the top level. Nested levels caption themselves. */
|
|
20
|
+
readonly caption?: string | null;
|
|
21
|
+
/** `all` stacks every drill-down level present; `root` draws only the top. */
|
|
22
|
+
readonly levels?: 'root' | 'all';
|
|
23
|
+
}
|
|
24
|
+
export declare function renderSvg<R extends AnyRegistry>(diagram: LaidOutDiagram<R>, options?: SvgOptions): string;
|
|
25
|
+
export declare function escapeText(value: string): string;
|
|
26
|
+
export declare function escapeAttr(value: string): string;
|
|
27
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAmC,MAAM,yBAAyB,CAAC;AAI5G,OAAO,EAAiB,KAAK,iBAAiB,EAA4B,MAAM,YAAY,CAAC;AAE7F,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,iBAAiB,CAAC;IACnC,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAClC;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,UAAe,GAAG,MAAM,CAsD7G;AAmKD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD"}
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `LaidOutDiagram` to an SVG string.
|
|
3
|
+
*
|
|
4
|
+
* Build-time only: no DOM, no client JS, and nothing measured — geometry
|
|
5
|
+
* arrives from core already computed. The renderer's whole job is turning
|
|
6
|
+
* placed boxes and routes into markup, plus the one thing core cannot know,
|
|
7
|
+
* which is where labels go.
|
|
8
|
+
*
|
|
9
|
+
* Drill-down levels are stacked rather than made interactive. A static file
|
|
10
|
+
* has to contain every level it can reveal, and stacking reveals them without
|
|
11
|
+
* script; the React renderer is where descending on demand belongs.
|
|
12
|
+
*/
|
|
13
|
+
import { boxAround, boxOf, placeLabel, unionOf } from './geometry.js';
|
|
14
|
+
import { glyphMarkup, shapeMarkup } from './shapes.js';
|
|
15
|
+
import { lineColour, resolveTheme } from './theme.js';
|
|
16
|
+
export function renderSvg(diagram, options = {}) {
|
|
17
|
+
const theme = resolveTheme(options.theme);
|
|
18
|
+
const { padding, levelGap } = theme.metrics;
|
|
19
|
+
const levels = levelsOf(diagram, options.caption ?? null, options.levels !== 'root');
|
|
20
|
+
const rendered = levels.map((level) => renderLevel(level, theme));
|
|
21
|
+
const captionHeight = theme.typography.captionSize + theme.metrics.labelGap * 2;
|
|
22
|
+
const width = Math.max(...rendered.map((level) => level.box.maxX - level.box.minX), 0) + padding * 2;
|
|
23
|
+
const placed = rendered.map((level, index) => {
|
|
24
|
+
const above = rendered
|
|
25
|
+
.slice(0, index)
|
|
26
|
+
.reduce((total, previous) => total + heightOf(previous, captionHeight) + levelGap, 0);
|
|
27
|
+
return { ...level, top: padding + above };
|
|
28
|
+
});
|
|
29
|
+
const height = placed.reduce((total, level) => total + heightOf(level, captionHeight) + levelGap, 0) - levelGap + padding * 2;
|
|
30
|
+
const body = placed
|
|
31
|
+
.map((level) => {
|
|
32
|
+
const captionY = level.top + theme.typography.captionSize;
|
|
33
|
+
const contentTop = level.caption === null ? level.top : level.top + captionHeight;
|
|
34
|
+
const shiftX = padding - level.box.minX;
|
|
35
|
+
const shiftY = contentTop - level.box.minY;
|
|
36
|
+
return [
|
|
37
|
+
level.caption === null
|
|
38
|
+
? ''
|
|
39
|
+
: `<text x="${padding}" y="${round(captionY)}" font-family="${escapeAttr(theme.typography.captionFamily)}" ` +
|
|
40
|
+
`font-size="${theme.typography.captionSize}" fill="${theme.palette.caption}">${escapeText(level.caption)}</text>`,
|
|
41
|
+
`<g transform="translate(${round(shiftX)},${round(shiftY)})">`,
|
|
42
|
+
level.markup,
|
|
43
|
+
`</g>`,
|
|
44
|
+
]
|
|
45
|
+
.filter((part) => part !== '')
|
|
46
|
+
.join('\n');
|
|
47
|
+
})
|
|
48
|
+
.join(`\n<line x1="${padding}" x2="${round(width - padding)}" y1="0" y2="0" stroke="${theme.palette.divider}" stroke-width="0"/>\n`);
|
|
49
|
+
const title = options.title ?? null;
|
|
50
|
+
return [
|
|
51
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${round(width)}" height="${round(height)}" ` +
|
|
52
|
+
`viewBox="0 0 ${round(width)} ${round(height)}" role="img"${title === null ? '' : ` aria-label="${escapeAttr(title)}"`}>`,
|
|
53
|
+
title === null ? '' : `<title>${escapeText(title)}</title>`,
|
|
54
|
+
`<rect width="100%" height="100%" fill="${theme.palette.surface}"/>`,
|
|
55
|
+
body,
|
|
56
|
+
`</svg>`,
|
|
57
|
+
]
|
|
58
|
+
.filter((part) => part !== '')
|
|
59
|
+
.join('\n');
|
|
60
|
+
}
|
|
61
|
+
/** The tree of drill-down levels, flattened depth-first into a stack. */
|
|
62
|
+
function levelsOf(diagram, caption, deep) {
|
|
63
|
+
const here = { caption, diagram };
|
|
64
|
+
if (!deep)
|
|
65
|
+
return [here];
|
|
66
|
+
const nested = diagram.nodes.flatMap((node) => node.children === null
|
|
67
|
+
? []
|
|
68
|
+
: levelsOf(node.children, caption === null ? node.node.label : `${caption} ▸ ${node.node.label}`, true));
|
|
69
|
+
return [here, ...nested];
|
|
70
|
+
}
|
|
71
|
+
function heightOf(level, captionHeight) {
|
|
72
|
+
const content = level.box.maxY - level.box.minY;
|
|
73
|
+
return level.caption === null ? content : content + captionHeight;
|
|
74
|
+
}
|
|
75
|
+
/* ------------------------------------------------------------------ *
|
|
76
|
+
* One level
|
|
77
|
+
* ------------------------------------------------------------------ */
|
|
78
|
+
function renderLevel(level, theme) {
|
|
79
|
+
const { diagram } = level;
|
|
80
|
+
const colours = new Map(diagram.lines.map((line, index) => [line.id, lineColour(theme.palette, line.color, index)]));
|
|
81
|
+
const colourOf = (line) => (line === null ? undefined : colours.get(line)) ?? theme.palette.caption;
|
|
82
|
+
const lineOfNode = new Map(diagram.nodes.map((node) => [node.node.id, node.node.line]));
|
|
83
|
+
const edges = diagram.edges.map((edge) => renderEdge(edge, lineOfNode, colourOf, theme));
|
|
84
|
+
const nodes = diagram.nodes.map((node) => renderNode(node, diagram, colourOf, theme));
|
|
85
|
+
const box = unionOf([...edges.map((part) => part.box), ...nodes.map((part) => part.box)]);
|
|
86
|
+
// Edges first so tracks pass under stations rather than over them.
|
|
87
|
+
return {
|
|
88
|
+
caption: level.caption,
|
|
89
|
+
markup: [...edges.map((part) => part.markup), ...nodes.map((part) => part.markup)].join('\n'),
|
|
90
|
+
box,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* An edge takes the colour of where it is going. Track between two stations on
|
|
95
|
+
* one line is that line; track leaving a router onto another line already
|
|
96
|
+
* belongs to the new one, which is what makes an interchange read as a change.
|
|
97
|
+
*/
|
|
98
|
+
function renderEdge(edge, lineOfNode, colourOf, theme) {
|
|
99
|
+
const sourceLine = lineOfNode.get(edge.edge.source) ?? null;
|
|
100
|
+
const targetLine = lineOfNode.get(edge.edge.target) ?? null;
|
|
101
|
+
const branching = sourceLine !== targetLine;
|
|
102
|
+
const weight = branching ? theme.metrics.branchWeight : theme.metrics.lineWeight;
|
|
103
|
+
if (edge.route.length < 2)
|
|
104
|
+
return { markup: '', box: { ...EMPTY } };
|
|
105
|
+
const points = edge.route.map((point) => `${round(point.x)},${round(point.y)}`).join(' ');
|
|
106
|
+
return {
|
|
107
|
+
markup: `<polyline points="${points}" fill="none" stroke="${colourOf(targetLine)}" stroke-width="${weight}" ` +
|
|
108
|
+
`stroke-linejoin="round" stroke-linecap="round"/>`,
|
|
109
|
+
box: boxAround(edge.route, weight / 2),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const EMPTY = { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };
|
|
113
|
+
function renderNode(placed, diagram, colourOf, theme) {
|
|
114
|
+
const typeDef = diagram.registry.nodeTypes[placed.node.type];
|
|
115
|
+
const shape = typeDef?.shape ?? 'rect';
|
|
116
|
+
const glyph = typeDef?.glyph ?? 'none';
|
|
117
|
+
const colour = colourOf(placed.node.line);
|
|
118
|
+
const box = boxOf(placed.position, placed.size);
|
|
119
|
+
const label = placeLabel(placed.node.label, shape, placed.position, placed.size, theme.typography, theme.metrics);
|
|
120
|
+
const leader = label.leader === null
|
|
121
|
+
? ''
|
|
122
|
+
: `<line x1="${round(label.leader[0].x)}" y1="${round(label.leader[0].y)}" ` +
|
|
123
|
+
`x2="${round(label.leader[1].x)}" y2="${round(label.leader[1].y)}" ` +
|
|
124
|
+
`stroke="${colour}" stroke-width="${theme.metrics.nodeStroke}" stroke-linecap="round"/>`;
|
|
125
|
+
const description = typeDef === undefined ? placed.node.label : `${placed.node.label} — ${typeDef.label}`;
|
|
126
|
+
return {
|
|
127
|
+
markup: [
|
|
128
|
+
`<g>`,
|
|
129
|
+
`<title>${escapeText(description)}</title>`,
|
|
130
|
+
shapeMarkup(shape, box, {
|
|
131
|
+
fill: theme.palette.nodeFill,
|
|
132
|
+
stroke: colour,
|
|
133
|
+
strokeWidth: theme.metrics.nodeStroke,
|
|
134
|
+
}),
|
|
135
|
+
glyph === 'none' ? '' : glyphMarkup(glyph, box, colour),
|
|
136
|
+
leader,
|
|
137
|
+
`<text x="${round(label.x)}" y="${round(label.y)}" text-anchor="${label.anchor}" ` +
|
|
138
|
+
`font-family="${escapeAttr(theme.typography.fontFamily)}" font-size="${theme.typography.labelSize}" ` +
|
|
139
|
+
`font-weight="${theme.typography.labelWeight}" fill="${theme.palette.label}">${escapeText(label.text)}</text>`,
|
|
140
|
+
`</g>`,
|
|
141
|
+
]
|
|
142
|
+
.filter((part) => part !== '')
|
|
143
|
+
.join('\n'),
|
|
144
|
+
box: unionOf([box, label.box]),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/* ------------------------------------------------------------------ *
|
|
148
|
+
* Markup helpers
|
|
149
|
+
* ------------------------------------------------------------------ */
|
|
150
|
+
const round = (value) => (Math.round(value * 100) / 100).toString();
|
|
151
|
+
const TEXT_ESCAPES = { '&': '&', '<': '<', '>': '>' };
|
|
152
|
+
const ATTR_ESCAPES = { ...TEXT_ESCAPES, '"': '"', "'": ''' };
|
|
153
|
+
export function escapeText(value) {
|
|
154
|
+
return value.replace(/[&<>]/g, (character) => TEXT_ESCAPES[character] ?? character);
|
|
155
|
+
}
|
|
156
|
+
export function escapeAttr(value) {
|
|
157
|
+
return value.replace(/[&<>"']/g, (character) => ATTR_ESCAPES[character] ?? character);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/shapes.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape and glyph markup. One function per closed vocabulary in core, so a
|
|
3
|
+
* shape core can name is always a shape this can draw — which is the whole
|
|
4
|
+
* reason `NodeShape` and `Glyph` are closed sets.
|
|
5
|
+
*/
|
|
6
|
+
import type { Glyph, NodeShape } from '@rankonelabs/livid-core';
|
|
7
|
+
import type { Box } from './geometry.js';
|
|
8
|
+
export interface ShapeStyle {
|
|
9
|
+
readonly fill: string;
|
|
10
|
+
readonly stroke: string;
|
|
11
|
+
readonly strokeWidth: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function shapeMarkup(shape: NodeShape, box: Box, style: ShapeStyle): string;
|
|
14
|
+
/**
|
|
15
|
+
* The station mark. Drawn at the leading edge rather than the centre so it
|
|
16
|
+
* does not fight the label for the middle of a box.
|
|
17
|
+
*/
|
|
18
|
+
export declare function glyphMarkup(glyph: Glyph, box: Box, colour: string): string;
|
|
19
|
+
//# sourceMappingURL=shapes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../src/shapes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAQD,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CA+CjF;AAMD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAqB1E"}
|
package/dist/shapes.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape and glyph markup. One function per closed vocabulary in core, so a
|
|
3
|
+
* shape core can name is always a shape this can draw — which is the whole
|
|
4
|
+
* reason `NodeShape` and `Glyph` are closed sets.
|
|
5
|
+
*/
|
|
6
|
+
function attrs(style) {
|
|
7
|
+
return `fill="${style.fill}" stroke="${style.stroke}" stroke-width="${style.strokeWidth}"`;
|
|
8
|
+
}
|
|
9
|
+
const round = (value) => (Math.round(value * 100) / 100).toString();
|
|
10
|
+
export function shapeMarkup(shape, box, style) {
|
|
11
|
+
const x = box.minX;
|
|
12
|
+
const y = box.minY;
|
|
13
|
+
const w = box.maxX - box.minX;
|
|
14
|
+
const h = box.maxY - box.minY;
|
|
15
|
+
const common = attrs(style);
|
|
16
|
+
switch (shape) {
|
|
17
|
+
case 'rect':
|
|
18
|
+
return `<rect x="${round(x)}" y="${round(y)}" width="${round(w)}" height="${round(h)}" ${common}/>`;
|
|
19
|
+
case 'rounded':
|
|
20
|
+
return `<rect x="${round(x)}" y="${round(y)}" width="${round(w)}" height="${round(h)}" rx="10" ${common}/>`;
|
|
21
|
+
case 'stadium':
|
|
22
|
+
return `<rect x="${round(x)}" y="${round(y)}" width="${round(w)}" height="${round(h)}" rx="${round(h / 2)}" ${common}/>`;
|
|
23
|
+
case 'circle':
|
|
24
|
+
return `<circle cx="${round(x + w / 2)}" cy="${round(y + h / 2)}" r="${round(Math.min(w, h) / 2)}" ${common}/>`;
|
|
25
|
+
case 'hexagon': {
|
|
26
|
+
const inset = w * 0.18;
|
|
27
|
+
const points = [
|
|
28
|
+
[x + inset, y],
|
|
29
|
+
[x + w - inset, y],
|
|
30
|
+
[x + w, y + h / 2],
|
|
31
|
+
[x + w - inset, y + h],
|
|
32
|
+
[x + inset, y + h],
|
|
33
|
+
[x, y + h / 2],
|
|
34
|
+
];
|
|
35
|
+
return `<polygon points="${polygon(points)}" ${common}/>`;
|
|
36
|
+
}
|
|
37
|
+
case 'diamond': {
|
|
38
|
+
const points = [
|
|
39
|
+
[x + w / 2, y],
|
|
40
|
+
[x + w, y + h / 2],
|
|
41
|
+
[x + w / 2, y + h],
|
|
42
|
+
[x, y + h / 2],
|
|
43
|
+
];
|
|
44
|
+
return `<polygon points="${polygon(points)}" ${common}/>`;
|
|
45
|
+
}
|
|
46
|
+
case 'cylinder': {
|
|
47
|
+
const lip = 9;
|
|
48
|
+
return (`<path d="M${round(x)},${round(y + lip)} a${round(w / 2)},${lip} 0 0 1 ${round(w)},0 ` +
|
|
49
|
+
`v${round(h - lip * 2)} a${round(w / 2)},${lip} 0 0 1 ${round(-w)},0 z" ${common}/>` +
|
|
50
|
+
`<ellipse cx="${round(x + w / 2)}" cy="${round(y + lip)}" rx="${round(w / 2)}" ry="${lip}" ` +
|
|
51
|
+
`fill="none" stroke="${style.stroke}" stroke-width="${style.strokeWidth}"/>`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function polygon(points) {
|
|
56
|
+
return points.map((point) => `${round(point[0] ?? 0)},${round(point[1] ?? 0)}`).join(' ');
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The station mark. Drawn at the leading edge rather than the centre so it
|
|
60
|
+
* does not fight the label for the middle of a box.
|
|
61
|
+
*/
|
|
62
|
+
export function glyphMarkup(glyph, box, colour) {
|
|
63
|
+
if (glyph === 'none')
|
|
64
|
+
return '';
|
|
65
|
+
const cx = box.minX + (box.maxX - box.minX) / 2;
|
|
66
|
+
const cy = box.minY + (box.maxY - box.minY) / 2;
|
|
67
|
+
switch (glyph) {
|
|
68
|
+
case 'dot':
|
|
69
|
+
return `<circle cx="${round(cx)}" cy="${round(cy)}" r="4" fill="${colour}"/>`;
|
|
70
|
+
case 'ring':
|
|
71
|
+
return `<circle cx="${round(cx)}" cy="${round(cy)}" r="4.5" fill="none" stroke="${colour}" stroke-width="2"/>`;
|
|
72
|
+
case 'bar':
|
|
73
|
+
return `<rect x="${round(cx - 1.5)}" y="${round(cy - 6)}" width="3" height="12" rx="1.5" fill="${colour}"/>`;
|
|
74
|
+
case 'square':
|
|
75
|
+
return `<rect x="${round(cx - 3.5)}" y="${round(cy - 3.5)}" width="7" height="7" fill="${colour}"/>`;
|
|
76
|
+
case 'chevron':
|
|
77
|
+
return (`<path d="M${round(cx - 3)},${round(cy - 5)} L${round(cx + 3)},${round(cy)} L${round(cx - 3)},${round(cy + 5)}" ` +
|
|
78
|
+
`fill="none" stroke="${colour}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=shapes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../src/shapes.ts"],"names":[],"mappings":"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"}
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything about how a diagram looks, as config.
|
|
3
|
+
*
|
|
4
|
+
* User control stops at config here as it does in core: a consumer picks
|
|
5
|
+
* colours, weights, and type, and cannot inject markup. That is what keeps the
|
|
6
|
+
* SVG in a post and the React canvas in an app the same map.
|
|
7
|
+
*/
|
|
8
|
+
/** Where a label sits when its shape cannot hold text. */
|
|
9
|
+
export type LabelSide = 'below' | 'right';
|
|
10
|
+
export interface Palette {
|
|
11
|
+
/**
|
|
12
|
+
* Colour token from `LineSpec.color` to a CSS colour. Tokens are the
|
|
13
|
+
* consumer's vocabulary — core never sees a colour — so any token missing
|
|
14
|
+
* here falls back to the ramp below, by line order.
|
|
15
|
+
*/
|
|
16
|
+
readonly lines: Readonly<Record<string, string>>;
|
|
17
|
+
/** Assigned by line index to any line whose token is not in `lines`. */
|
|
18
|
+
readonly ramp: readonly string[];
|
|
19
|
+
readonly surface: string;
|
|
20
|
+
readonly nodeFill: string;
|
|
21
|
+
readonly label: string;
|
|
22
|
+
readonly caption: string;
|
|
23
|
+
readonly divider: string;
|
|
24
|
+
}
|
|
25
|
+
export interface Typography {
|
|
26
|
+
readonly fontFamily: string;
|
|
27
|
+
readonly labelSize: number;
|
|
28
|
+
readonly labelWeight: number;
|
|
29
|
+
readonly captionFamily: string;
|
|
30
|
+
readonly captionSize: number;
|
|
31
|
+
/**
|
|
32
|
+
* Mean glyph advance as a fraction of font size. Text is measured by
|
|
33
|
+
* estimate rather than measurement because there is no DOM at build time;
|
|
34
|
+
* see `estimateTextWidth`.
|
|
35
|
+
*/
|
|
36
|
+
readonly advanceRatio: number;
|
|
37
|
+
}
|
|
38
|
+
export interface Metrics {
|
|
39
|
+
/** Track weight on the critical path. Thick lines are what read as transit. */
|
|
40
|
+
readonly lineWeight: number;
|
|
41
|
+
/** Branches are lighter, so the eye follows the main route first. */
|
|
42
|
+
readonly branchWeight: number;
|
|
43
|
+
readonly nodeStroke: number;
|
|
44
|
+
/** Tick drawn from a point-shaped node out to its label. */
|
|
45
|
+
readonly leader: number;
|
|
46
|
+
readonly labelGap: number;
|
|
47
|
+
readonly padding: number;
|
|
48
|
+
/** Vertical space between stacked drill-down levels. */
|
|
49
|
+
readonly levelGap: number;
|
|
50
|
+
readonly labelSide: LabelSide;
|
|
51
|
+
}
|
|
52
|
+
export interface SvgTheme {
|
|
53
|
+
readonly palette: Palette;
|
|
54
|
+
readonly typography: Typography;
|
|
55
|
+
readonly metrics: Metrics;
|
|
56
|
+
}
|
|
57
|
+
/** Overrides are per-section rather than deep, so the shapes stay nameable. */
|
|
58
|
+
export interface SvgThemeOverrides {
|
|
59
|
+
readonly palette?: Partial<Palette>;
|
|
60
|
+
readonly typography?: Partial<Typography>;
|
|
61
|
+
readonly metrics?: Partial<Metrics>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Restrained and high-contrast: the map should read on a white page in a post
|
|
65
|
+
* and survive being printed. Deliberately not any existing brand palette.
|
|
66
|
+
*/
|
|
67
|
+
export declare const DEFAULT_PALETTE: Palette;
|
|
68
|
+
export declare const DEFAULT_TYPOGRAPHY: Typography;
|
|
69
|
+
export declare const DEFAULT_METRICS: Metrics;
|
|
70
|
+
export declare const DEFAULT_THEME: SvgTheme;
|
|
71
|
+
export declare function resolveTheme(overrides?: SvgThemeOverrides): SvgTheme;
|
|
72
|
+
/**
|
|
73
|
+
* Colour for one line. A configured token wins; otherwise the ramp assigns by
|
|
74
|
+
* declaration order, so an unconfigured diagram still renders as a map rather
|
|
75
|
+
* than as one grey tangle.
|
|
76
|
+
*/
|
|
77
|
+
export declare function lineColour(palette: Palette, token: string, index: number): string;
|
|
78
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,0DAA0D;AAC1D,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1C,MAAM,WAAW,OAAO;IACtB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,OAAO;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACrC;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,OAQ7B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,UAOhC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,OAS7B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,QAI3B,CAAC;AAEF,wBAAgB,YAAY,CAAC,SAAS,GAAE,iBAAsB,GAAG,QAAQ,CAMxE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjF"}
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything about how a diagram looks, as config.
|
|
3
|
+
*
|
|
4
|
+
* User control stops at config here as it does in core: a consumer picks
|
|
5
|
+
* colours, weights, and type, and cannot inject markup. That is what keeps the
|
|
6
|
+
* SVG in a post and the React canvas in an app the same map.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Restrained and high-contrast: the map should read on a white page in a post
|
|
10
|
+
* and survive being printed. Deliberately not any existing brand palette.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_PALETTE = {
|
|
13
|
+
lines: {},
|
|
14
|
+
ramp: ['#D64500', '#1B6CA8', '#5B3E96', '#0F7B6C', '#A8341F', '#6B7280'],
|
|
15
|
+
surface: '#FFFFFF',
|
|
16
|
+
nodeFill: '#FFFFFF',
|
|
17
|
+
label: '#16181D',
|
|
18
|
+
caption: '#6B7280',
|
|
19
|
+
divider: '#D8DCE3',
|
|
20
|
+
};
|
|
21
|
+
export const DEFAULT_TYPOGRAPHY = {
|
|
22
|
+
fontFamily: 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif',
|
|
23
|
+
labelSize: 13,
|
|
24
|
+
labelWeight: 600,
|
|
25
|
+
captionFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
|
|
26
|
+
captionSize: 11,
|
|
27
|
+
advanceRatio: 0.55,
|
|
28
|
+
};
|
|
29
|
+
export const DEFAULT_METRICS = {
|
|
30
|
+
lineWeight: 7,
|
|
31
|
+
branchWeight: 4,
|
|
32
|
+
nodeStroke: 2.5,
|
|
33
|
+
leader: 14,
|
|
34
|
+
labelGap: 6,
|
|
35
|
+
padding: 44,
|
|
36
|
+
levelGap: 96,
|
|
37
|
+
labelSide: 'below',
|
|
38
|
+
};
|
|
39
|
+
export const DEFAULT_THEME = {
|
|
40
|
+
palette: DEFAULT_PALETTE,
|
|
41
|
+
typography: DEFAULT_TYPOGRAPHY,
|
|
42
|
+
metrics: DEFAULT_METRICS,
|
|
43
|
+
};
|
|
44
|
+
export function resolveTheme(overrides = {}) {
|
|
45
|
+
return {
|
|
46
|
+
palette: { ...DEFAULT_PALETTE, ...overrides.palette, lines: { ...DEFAULT_PALETTE.lines, ...overrides.palette?.lines } },
|
|
47
|
+
typography: { ...DEFAULT_TYPOGRAPHY, ...overrides.typography },
|
|
48
|
+
metrics: { ...DEFAULT_METRICS, ...overrides.metrics },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Colour for one line. A configured token wins; otherwise the ramp assigns by
|
|
53
|
+
* declaration order, so an unconfigured diagram still renders as a map rather
|
|
54
|
+
* than as one grey tangle.
|
|
55
|
+
*/
|
|
56
|
+
export function lineColour(palette, token, index) {
|
|
57
|
+
const configured = palette.lines[token];
|
|
58
|
+
if (configured !== undefined)
|
|
59
|
+
return configured;
|
|
60
|
+
const fallback = palette.ramp[index % palette.ramp.length];
|
|
61
|
+
return fallback ?? palette.caption;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA+DH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAY;IACtC,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC;IACxE,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,SAAS;IACnB,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAe;IAC5C,UAAU,EAAE,uEAAuE;IACnF,SAAS,EAAE,EAAE;IACb,WAAW,EAAE,GAAG;IAChB,aAAa,EAAE,gDAAgD;IAC/D,WAAW,EAAE,EAAE;IACf,YAAY,EAAE,IAAI;CACnB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAY;IACtC,UAAU,EAAE,CAAC;IACb,YAAY,EAAE,CAAC;IACf,UAAU,EAAE,GAAG;IACf,MAAM,EAAE,EAAE;IACV,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,EAAE;IACZ,SAAS,EAAE,OAAO;CACnB,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAa;IACrC,OAAO,EAAE,eAAe;IACxB,UAAU,EAAE,kBAAkB;IAC9B,OAAO,EAAE,eAAe;CACzB,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,YAA+B,EAAE;IAC5D,OAAO;QACL,OAAO,EAAE,EAAE,GAAG,eAAe,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,eAAe,CAAC,KAAK,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;QACvH,UAAU,EAAE,EAAE,GAAG,kBAAkB,EAAE,GAAG,SAAS,CAAC,UAAU,EAAE;QAC9D,OAAO,EAAE,EAAE,GAAG,eAAe,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE;KACtD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAgB,EAAE,KAAa,EAAE,KAAa;IACvE,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,UAAU,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IAEhD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3D,OAAO,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;AACrC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rankonelabs/livid-svg",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "LaidOutDiagram to SVG string. Build-time, zero client JS.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"diagram",
|
|
9
|
+
"svg",
|
|
10
|
+
"architecture",
|
|
11
|
+
"static-site"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/RankOneLabs/livid.git",
|
|
16
|
+
"directory": "packages/svg"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/RankOneLabs/livid#readme",
|
|
19
|
+
"bugs": "https://github.com/RankOneLabs/livid/issues",
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=20.19.0"
|
|
22
|
+
},
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -b",
|
|
39
|
+
"check": "tsc -b",
|
|
40
|
+
"prepublishOnly": "tsc -b --force"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@rankonelabs/livid-core": "^0.1.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@rankonelabs/livid-core": "^0.1.0"
|
|
47
|
+
}
|
|
48
|
+
}
|