@weasel-js/svg 1.4.4 → 1.5.1
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 +53 -17
- package/dist/index.js +579 -121
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
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,4 @@
|
|
|
1
|
-
import { Path, FillStyle, StyledRun, TextStyle, Stroke, TilePatternSpec, IngestCtx } from '@weasel-js/core';
|
|
1
|
+
import { Path, FillStyle, StrokeAlign, StyledRun, TextStyle, TextVerticalAlign, Stroke, MarkerEntry, TilePatternSpec, IngestCtx } from '@weasel-js/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Public types for `@weasel-js/svg`. The package exposes a flat,
|
|
@@ -91,6 +91,10 @@ interface SvgStroke {
|
|
|
91
91
|
* attribute may render with longer miters than the source SVG intended.
|
|
92
92
|
*/
|
|
93
93
|
miterLimit?: number;
|
|
94
|
+
/** The kit stroke's `align`. SVG has no stroke alignment, so the serializer
|
|
95
|
+
* writes the stroke centered and says so through `onWarn`; the parser
|
|
96
|
+
* never sets it. */
|
|
97
|
+
align?: StrokeAlign;
|
|
94
98
|
/** `marker-start` / `marker-mid` / `marker-end`, as the bare `url(#id)` key. */
|
|
95
99
|
markerStart?: string;
|
|
96
100
|
markerMid?: string;
|
|
@@ -126,20 +130,16 @@ interface SvgGroupNode {
|
|
|
126
130
|
kind: 'group';
|
|
127
131
|
children: SvgNode[];
|
|
128
132
|
transform?: Matrix;
|
|
133
|
+
/** Clips the group's contents. Serializes to a `<clipPath>` def plus
|
|
134
|
+
* `clip-path="url(#id)"`, and lives in the same space as `children` —
|
|
135
|
+
* SVG applies the group's own `transform` to the clip as well.
|
|
136
|
+
* A `<clipPath>` of more than one shape parses back as no clip: SVG
|
|
137
|
+
* unions them and a `Path` holds one outline. */
|
|
138
|
+
clip?: Path;
|
|
129
139
|
opacity?: number;
|
|
130
140
|
/** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */
|
|
131
141
|
meta?: NamespaceMeta;
|
|
132
142
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Width given to an external `<text>` that carries no `data-weasel-width`:
|
|
135
|
-
* large enough that line wrapping never fires, since SVG text flows from a
|
|
136
|
-
* baseline and the source says nothing about a box.
|
|
137
|
-
*
|
|
138
|
-
* It is a wrap sentinel, not a measurement. Anything that treats a text
|
|
139
|
-
* node's width as geometry — a union AABB, a fit-clamp — has to recognize it
|
|
140
|
-
* and substitute an estimate, or one text node swamps the whole file.
|
|
141
|
-
*/
|
|
142
|
-
declare const UNBOUNDED_TEXT_WIDTH = 99999;
|
|
143
143
|
/**
|
|
144
144
|
* Text leaf node. Mirrors the kit's `TextPose` shape — a bounding box plus
|
|
145
145
|
* text content, optional rich-text `runs` (per-range styling), and an
|
|
@@ -150,9 +150,12 @@ declare const UNBOUNDED_TEXT_WIDTH = 99999;
|
|
|
150
150
|
* `dominant-baseline="text-before-edge"` so `y` is the top of the text
|
|
151
151
|
* box, plus `data-weasel-width` / `data-weasel-height` so weasel's
|
|
152
152
|
* explicit box dimensions round-trip losslessly. External SVG text
|
|
153
|
-
* (lacking the data-* attrs) imports with
|
|
154
|
-
*
|
|
153
|
+
* (lacking the data-* attrs) imports with the width the kit's text layout
|
|
154
|
+
* measures — an em-based estimate when no registered font can — and
|
|
155
155
|
* `height = fontSize * lineHeight * (lineCount || 1)`.
|
|
156
|
+
*
|
|
157
|
+
* `x` here is always the box's left edge. In the SVG it is the
|
|
158
|
+
* `text-anchor` point, and the parser and serializer convert between them.
|
|
156
159
|
*/
|
|
157
160
|
interface SvgTextNode {
|
|
158
161
|
kind: 'text';
|
|
@@ -166,6 +169,10 @@ interface SvgTextNode {
|
|
|
166
169
|
runs?: StyledRun[];
|
|
167
170
|
/** Node-wide typography. Defaults applied at render time via `resolveTextStyle`. */
|
|
168
171
|
style?: TextStyle;
|
|
172
|
+
/** Where the laid-out text sits inside the box — `kit:text`'s
|
|
173
|
+
* `data.verticalAlign`. SVG text has no box to align in, so this rides in
|
|
174
|
+
* `data-weasel-vertical-align` and other readers draw the text top-aligned. */
|
|
175
|
+
verticalAlign?: TextVerticalAlign;
|
|
169
176
|
/**
|
|
170
177
|
* Node-wide glyph paint, the `FillStyle` / `Stroke` a kit text node holds
|
|
171
178
|
* in `data.fill` / `data.stroke`. Not `SvgPaint`, which is the path
|
|
@@ -193,6 +200,12 @@ interface SvgTextNode {
|
|
|
193
200
|
* a reference and only resolves when something downstream loads it.
|
|
194
201
|
*
|
|
195
202
|
* SVG's `preserveAspectRatio` is not modeled; the box is taken literally.
|
|
203
|
+
*
|
|
204
|
+
* With a `source` rect or a flip, the element is written as a `<g
|
|
205
|
+
* data-weasel-image>` holding a nested `<svg>` viewport at the box, whose
|
|
206
|
+
* `viewBox` is the source window over a unit-square `<image>` — plain SVG 1.1,
|
|
207
|
+
* which any reader crops and mirrors the same way, and which `parseSvg` reads
|
|
208
|
+
* back as one image node.
|
|
196
209
|
*/
|
|
197
210
|
interface SvgImageNode {
|
|
198
211
|
kind: 'image';
|
|
@@ -201,6 +214,20 @@ interface SvgImageNode {
|
|
|
201
214
|
y: number;
|
|
202
215
|
width: number;
|
|
203
216
|
height: number;
|
|
217
|
+
/** The part of the bitmap drawn into the box, as fractions of the bitmap's
|
|
218
|
+
* width and height from its top-left. Omitted draws the whole bitmap.
|
|
219
|
+
* Fractions rather than bitmap pixels because this package never decodes
|
|
220
|
+
* the image, so it cannot know its size. */
|
|
221
|
+
source?: {
|
|
222
|
+
x: number;
|
|
223
|
+
y: number;
|
|
224
|
+
width: number;
|
|
225
|
+
height: number;
|
|
226
|
+
};
|
|
227
|
+
/** Mirror the drawn region within the box, as `ImageDrawCommand` does. The
|
|
228
|
+
* box does not move. */
|
|
229
|
+
flipX?: boolean;
|
|
230
|
+
flipY?: boolean;
|
|
204
231
|
/** Element-level opacity (`opacity="..."`), 0..1. */
|
|
205
232
|
opacity?: number;
|
|
206
233
|
/** Element-level rotation in **radians**, pivoting around the unrotated
|
|
@@ -247,6 +274,13 @@ interface ParseResult {
|
|
|
247
274
|
height?: number;
|
|
248
275
|
/** Text content of the first `<title>` child of `<svg>`, when present. */
|
|
249
276
|
title?: string;
|
|
277
|
+
/**
|
|
278
|
+
* An entry for each document `<marker>` a stroke references under a key the
|
|
279
|
+
* marker registry does not know, keyed as the strokes in `nodes` now name
|
|
280
|
+
* them. Nothing draws them until they are registered (`registerMarker`),
|
|
281
|
+
* which `unpackSvgFiles` does.
|
|
282
|
+
*/
|
|
283
|
+
markers?: MarkerEntry[];
|
|
250
284
|
}
|
|
251
285
|
/** Options for {@link serializeSvg}. */
|
|
252
286
|
interface SerializeOptions {
|
|
@@ -261,9 +295,11 @@ interface SerializeOptions {
|
|
|
261
295
|
height: number;
|
|
262
296
|
};
|
|
263
297
|
/**
|
|
264
|
-
* Called for
|
|
265
|
-
*
|
|
266
|
-
* `TilePatternSpec
|
|
298
|
+
* Called for what the document cannot carry the way weasel draws it: a
|
|
299
|
+
* paint SVG cannot express (a pattern carrying a `TextureHandle` instead of
|
|
300
|
+
* a `TilePatternSpec`), a stroke aligned off its edge, text that wraps or
|
|
301
|
+
* sits lower than the top of its box. Each message is said once per call.
|
|
302
|
+
* Without this the loss is silent.
|
|
267
303
|
*/
|
|
268
304
|
onWarn?: (message: string) => void;
|
|
269
305
|
/** Emit `width="..."` on the root `<svg>`. */
|
|
@@ -401,4 +437,4 @@ declare function svgNodesToKitDrafts(nodes: readonly SvgNode[], nextId: () => st
|
|
|
401
437
|
*/
|
|
402
438
|
declare function unpackSvgFiles(files: File[], ctx: IngestCtx): Promise<void>;
|
|
403
439
|
|
|
404
|
-
export { IDENTITY_MATRIX, type Matrix, type NamespaceMeta, type NamespacedElement, type ParseOptions, type ParseResult, type SerializeOptions, type SvgDraftBounds, type SvgGroupNode, type SvgImageNode, type SvgNode, type SvgPaint, type SvgPathNode, type SvgSceneDraft, type SvgStroke, type SvgTextNode,
|
|
440
|
+
export { IDENTITY_MATRIX, type Matrix, type NamespaceMeta, type NamespacedElement, type ParseOptions, type ParseResult, type SerializeOptions, type SvgDraftBounds, type SvgGroupNode, type SvgImageNode, type SvgNode, type SvgPaint, type SvgPathNode, type SvgSceneDraft, type SvgStroke, type SvgTextNode, parseSvg, serializeSvg, strokeDataFromSvg, svgNodesToKitDrafts, tilePreviewCssUrl, tilePreviewSvg, unpackSvgFiles };
|