@weasel-js/svg 1.5.0 → 1.5.2
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/README.md +43 -0
- package/dist/index.d.ts +59 -12
- package/dist/index.js +543 -110
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -40,6 +40,49 @@ answer, and the alternative is unrepresentable anyway (see above). It only
|
|
|
40
40
|
shows up on foreign SVG that sets decoration on a group and cancels it on a
|
|
41
41
|
child.
|
|
42
42
|
|
|
43
|
+
## Paints SVG cannot express
|
|
44
|
+
|
|
45
|
+
SVG has `<linearGradient>`, `<radialGradient>` and `<pattern>` and nothing
|
|
46
|
+
else, so a conic gradient — or any paint kind a consumer registers — has no
|
|
47
|
+
element to serialize into. Both go out as a def in weasel's own namespace,
|
|
48
|
+
declared on the root as `xmlns:wzl="urn:weasel-js:svg"` only when a document
|
|
49
|
+
holds such a paint:
|
|
50
|
+
|
|
51
|
+
```xml
|
|
52
|
+
<defs><wzl:conicGradient id="grad0" gradientUnits="objectBoundingBox"
|
|
53
|
+
cx="0.5" cy="0.5" angle="0.25"><stop offset="0" stop-color="#ff0000"/>
|
|
54
|
+
<stop offset="1" stop-color="#0000ff"/></wzl:conicGradient></defs>
|
|
55
|
+
<path fill="url(#grad0) #ff0000" d="…"/>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The color after the reference is SVG's own paint fallback: this package reads
|
|
59
|
+
the def back and reproduces the paint exactly, every other renderer skips the
|
|
60
|
+
def it does not know and paints that flat color instead. A registered kind's
|
|
61
|
+
`toSvg` gets the same treatment, with the fallback taken from its `colorOf` —
|
|
62
|
+
or `none` when the kind has no single color, so an unresolvable reference
|
|
63
|
+
paints nothing rather than something arbitrary.
|
|
64
|
+
|
|
65
|
+
That cuts both ways on import: a `fill="url(#mesh1) #c04a3f"` from Inkscape,
|
|
66
|
+
whose mesh gradients this package does not model, imports as flat `#c04a3f`
|
|
67
|
+
rather than as a dropped fill.
|
|
68
|
+
|
|
69
|
+
### A gradient's blend space
|
|
70
|
+
|
|
71
|
+
A gradient's `interpolate` — `'oklab'` or `'oklch'` — has no SVG spelling
|
|
72
|
+
either: `color-interpolation` carries `sRGB` and `linearRGB` only. It goes out
|
|
73
|
+
as `wzl:interpolate` on the gradient's *own* element, which stays
|
|
74
|
+
`<linearGradient>` or `<radialGradient>`:
|
|
75
|
+
|
|
76
|
+
```xml
|
|
77
|
+
<linearGradient id="grad0" gradientUnits="objectBoundingBox"
|
|
78
|
+
x1="0" y1="0" x2="1" y2="0" wzl:interpolate="oklch">…</linearGradient>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
No fallback color rides along, because a foreign renderer still paints the
|
|
82
|
+
gradient — it just blends the stops in sRGB, which moves the midpoint rather
|
|
83
|
+
than losing the paint. A space this package does not know is dropped on import
|
|
84
|
+
rather than carried through.
|
|
85
|
+
|
|
43
86
|
## Raster images
|
|
44
87
|
|
|
45
88
|
`<image>` parses to an `SvgImageNode` holding the `href` verbatim — an
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Mat3 } from '@weasel-js/geom';
|
|
2
|
+
import { Path, FillStyle, ScreenLength, StrokeAlign, StyledRun, TextStyle, TextVerticalAlign, Stroke, MarkerEntry, TilePatternSpec, IngestCtx } from '@weasel-js/core';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Public types for `@weasel-js/svg`. The package exposes a flat,
|
|
@@ -47,10 +48,15 @@ interface NamespacedElement {
|
|
|
47
48
|
children?: Record<string, NamespacedElement[]>;
|
|
48
49
|
}
|
|
49
50
|
/**
|
|
50
|
-
* 2x3 affine matrix in
|
|
51
|
-
*
|
|
51
|
+
* 2x3 affine matrix in SVG's `matrix(a b c d e f)` order, mapping
|
|
52
|
+
* `[x', y'] = [a*x + c*y + e, b*x + d*y + f]`.
|
|
53
|
+
*
|
|
54
|
+
* The same order the kernel's affine tier uses, so this is that type under
|
|
55
|
+
* the name the SVG spec gives it — not a parallel one. An `SvgGroupNode`'s
|
|
56
|
+
* transform and a geom `Mat3` are interchangeable without a conversion.
|
|
52
57
|
*/
|
|
53
|
-
type Matrix =
|
|
58
|
+
type Matrix = Mat3;
|
|
59
|
+
|
|
54
60
|
/** Identity matrix — useful as a default in tests / constructors. */
|
|
55
61
|
declare const IDENTITY_MATRIX: Matrix;
|
|
56
62
|
/**
|
|
@@ -73,11 +79,9 @@ type SvgPaint = {
|
|
|
73
79
|
interface SvgStroke {
|
|
74
80
|
paint: SvgPaint;
|
|
75
81
|
/** World units, or `{ px }` for a width that holds its rendered thickness
|
|
76
|
-
* however the document is scaled — SVG's `vector-effect="non-scaling-stroke"
|
|
77
|
-
*
|
|
78
|
-
width:
|
|
79
|
-
px: number;
|
|
80
|
-
};
|
|
82
|
+
* however the document is scaled — SVG's `vector-effect="non-scaling-stroke"`.
|
|
83
|
+
* Literally the kit's own unit, not a second spelling of it. */
|
|
84
|
+
width: ScreenLength;
|
|
81
85
|
opacity?: number;
|
|
82
86
|
/** `stroke-linecap`. Default per SVG spec is `'butt'`. */
|
|
83
87
|
cap?: 'butt' | 'round' | 'square';
|
|
@@ -91,6 +95,10 @@ interface SvgStroke {
|
|
|
91
95
|
* attribute may render with longer miters than the source SVG intended.
|
|
92
96
|
*/
|
|
93
97
|
miterLimit?: number;
|
|
98
|
+
/** The kit stroke's `align`. SVG has no stroke alignment, so the serializer
|
|
99
|
+
* writes the stroke centered and says so through `onWarn`; the parser
|
|
100
|
+
* never sets it. */
|
|
101
|
+
align?: StrokeAlign;
|
|
94
102
|
/** `marker-start` / `marker-mid` / `marker-end`, as the bare `url(#id)` key. */
|
|
95
103
|
markerStart?: string;
|
|
96
104
|
markerMid?: string;
|
|
@@ -126,6 +134,12 @@ interface SvgGroupNode {
|
|
|
126
134
|
kind: 'group';
|
|
127
135
|
children: SvgNode[];
|
|
128
136
|
transform?: Matrix;
|
|
137
|
+
/** Clips the group's contents. Serializes to a `<clipPath>` def plus
|
|
138
|
+
* `clip-path="url(#id)"`, and lives in the same space as `children` —
|
|
139
|
+
* SVG applies the group's own `transform` to the clip as well.
|
|
140
|
+
* A `<clipPath>` of more than one shape parses back as no clip: SVG
|
|
141
|
+
* unions them and a `Path` holds one outline. */
|
|
142
|
+
clip?: Path;
|
|
129
143
|
opacity?: number;
|
|
130
144
|
/** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */
|
|
131
145
|
meta?: NamespaceMeta;
|
|
@@ -159,6 +173,10 @@ interface SvgTextNode {
|
|
|
159
173
|
runs?: StyledRun[];
|
|
160
174
|
/** Node-wide typography. Defaults applied at render time via `resolveTextStyle`. */
|
|
161
175
|
style?: TextStyle;
|
|
176
|
+
/** Where the laid-out text sits inside the box — `kit:text`'s
|
|
177
|
+
* `data.verticalAlign`. SVG text has no box to align in, so this rides in
|
|
178
|
+
* `data-weasel-vertical-align` and other readers draw the text top-aligned. */
|
|
179
|
+
verticalAlign?: TextVerticalAlign;
|
|
162
180
|
/**
|
|
163
181
|
* Node-wide glyph paint, the `FillStyle` / `Stroke` a kit text node holds
|
|
164
182
|
* in `data.fill` / `data.stroke`. Not `SvgPaint`, which is the path
|
|
@@ -186,6 +204,12 @@ interface SvgTextNode {
|
|
|
186
204
|
* a reference and only resolves when something downstream loads it.
|
|
187
205
|
*
|
|
188
206
|
* SVG's `preserveAspectRatio` is not modeled; the box is taken literally.
|
|
207
|
+
*
|
|
208
|
+
* With a `source` rect or a flip, the element is written as a `<g
|
|
209
|
+
* data-weasel-image>` holding a nested `<svg>` viewport at the box, whose
|
|
210
|
+
* `viewBox` is the source window over a unit-square `<image>` — plain SVG 1.1,
|
|
211
|
+
* which any reader crops and mirrors the same way, and which `parseSvg` reads
|
|
212
|
+
* back as one image node.
|
|
189
213
|
*/
|
|
190
214
|
interface SvgImageNode {
|
|
191
215
|
kind: 'image';
|
|
@@ -194,6 +218,20 @@ interface SvgImageNode {
|
|
|
194
218
|
y: number;
|
|
195
219
|
width: number;
|
|
196
220
|
height: number;
|
|
221
|
+
/** The part of the bitmap drawn into the box, as fractions of the bitmap's
|
|
222
|
+
* width and height from its top-left. Omitted draws the whole bitmap.
|
|
223
|
+
* Fractions rather than bitmap pixels because this package never decodes
|
|
224
|
+
* the image, so it cannot know its size. */
|
|
225
|
+
source?: {
|
|
226
|
+
x: number;
|
|
227
|
+
y: number;
|
|
228
|
+
width: number;
|
|
229
|
+
height: number;
|
|
230
|
+
};
|
|
231
|
+
/** Mirror the drawn region within the box, as `ImageDrawCommand` does. The
|
|
232
|
+
* box does not move. */
|
|
233
|
+
flipX?: boolean;
|
|
234
|
+
flipY?: boolean;
|
|
197
235
|
/** Element-level opacity (`opacity="..."`), 0..1. */
|
|
198
236
|
opacity?: number;
|
|
199
237
|
/** Element-level rotation in **radians**, pivoting around the unrotated
|
|
@@ -240,6 +278,13 @@ interface ParseResult {
|
|
|
240
278
|
height?: number;
|
|
241
279
|
/** Text content of the first `<title>` child of `<svg>`, when present. */
|
|
242
280
|
title?: string;
|
|
281
|
+
/**
|
|
282
|
+
* An entry for each document `<marker>` a stroke references under a key the
|
|
283
|
+
* marker registry does not know, keyed as the strokes in `nodes` now name
|
|
284
|
+
* them. Nothing draws them until they are registered (`registerMarker`),
|
|
285
|
+
* which `unpackSvgFiles` does.
|
|
286
|
+
*/
|
|
287
|
+
markers?: MarkerEntry[];
|
|
243
288
|
}
|
|
244
289
|
/** Options for {@link serializeSvg}. */
|
|
245
290
|
interface SerializeOptions {
|
|
@@ -254,9 +299,11 @@ interface SerializeOptions {
|
|
|
254
299
|
height: number;
|
|
255
300
|
};
|
|
256
301
|
/**
|
|
257
|
-
* Called for
|
|
258
|
-
*
|
|
259
|
-
* `TilePatternSpec
|
|
302
|
+
* Called for what the document cannot carry the way weasel draws it: a
|
|
303
|
+
* paint SVG cannot express (a pattern carrying a `TextureHandle` instead of
|
|
304
|
+
* a `TilePatternSpec`), a stroke aligned off its edge, text that wraps or
|
|
305
|
+
* sits lower than the top of its box. Each message is said once per call.
|
|
306
|
+
* Without this the loss is silent.
|
|
260
307
|
*/
|
|
261
308
|
onWarn?: (message: string) => void;
|
|
262
309
|
/** Emit `width="..."` on the root `<svg>`. */
|