@weasel-js/svg 1.10.1 → 1.11.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 +18 -0
- package/dist/index.d.ts +65 -13
- package/dist/index.js +301 -114
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -37,6 +37,16 @@ answer, and the alternative is unrepresentable anyway (see above). It only
|
|
|
37
37
|
shows up on foreign SVG that sets decoration on a group and cancels it on a
|
|
38
38
|
child.
|
|
39
39
|
|
|
40
|
+
**SVG text does not wrap.** By default a `<text>` is written one line per
|
|
41
|
+
hard break, pitched at the node's font size times its line height, and a
|
|
42
|
+
wrapping or justified node keeps that only in `data-weasel-*` attributes for
|
|
43
|
+
weasel's own reader. Pass `serializeSvg(nodes, { textLayout: layoutTextPose })`
|
|
44
|
+
to write the lines the renderer draws instead: each line is a `<tspan>` at the
|
|
45
|
+
layout's `x` and baseline `y`, each word of a line the layout justified gets
|
|
46
|
+
its own `x`, and a line holding a larger run sits where the renderer puts it.
|
|
47
|
+
The layout measures with the registered fonts, so `await warmSvg(nodes, {
|
|
48
|
+
textLayout })` first; a node no face could measure is written the default way.
|
|
49
|
+
|
|
40
50
|
## Paints SVG cannot express
|
|
41
51
|
|
|
42
52
|
SVG has `<linearGradient>`, `<radialGradient>` and `<pattern>` and nothing
|
|
@@ -173,6 +183,14 @@ writes a `kit:image` leaf back as an `SvgImageNode`.
|
|
|
173
183
|
in (a non-`none` value warns) and written back as `none`, so a source file
|
|
174
184
|
that relied on letterboxing imports stretched.
|
|
175
185
|
|
|
186
|
+
## Writing XML by hand
|
|
187
|
+
|
|
188
|
+
`escapeAttr(s)` and `escapeText(s)` are the escaping this package writes XML
|
|
189
|
+
with, for a caller writing its own. Both drop the characters XML 1.0 cannot
|
|
190
|
+
hold, even as references, and turn a vertical tab or form feed into a line
|
|
191
|
+
break. `escapeAttr` also writes tabs and line breaks as references, since a
|
|
192
|
+
parser reads a literal one in an attribute as a space.
|
|
193
|
+
|
|
176
194
|
## License
|
|
177
195
|
|
|
178
196
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Affine } from '@weasel-js/geom';
|
|
2
|
-
|
|
2
|
+
export { pathToD as serializePathD } from '@weasel-js/geom';
|
|
3
|
+
import { Path, Paint, ScreenLength, StrokeAlign, MarkerRef, VertexWidth, StrokeNib, StyledRun, TextStyle, TextVerticalAlign, Fill, Stroke, PoseLinear, MarkerEntry, TextPoseLayout, RenderNeeds, TilePatternSpec, ImageNodeData, IngestCtx } from '@weasel-js/core';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Media Queries 4 evaluation against a fixed environment.
|
|
@@ -125,6 +126,13 @@ interface SvgStroke {
|
|
|
125
126
|
markerStart?: MarkerRef;
|
|
126
127
|
markerMid?: MarkerRef;
|
|
127
128
|
markerEnd?: MarkerRef;
|
|
129
|
+
/** The kit stroke's `vertexWidths` and `nib`. SVG has no variable width, so
|
|
130
|
+
* the serializer writes such a stroke's outline as a filled shape after the
|
|
131
|
+
* path, and keeps these in the private namespace for the parser. An entry
|
|
132
|
+
* of `vertexWidths`, or one side of a pair, that is not a number of zero or
|
|
133
|
+
* more takes `width`. */
|
|
134
|
+
vertexWidths?: VertexWidth[];
|
|
135
|
+
nib?: StrokeNib;
|
|
128
136
|
}
|
|
129
137
|
/**
|
|
130
138
|
* Leaf node: a path geometry plus fill/stroke. Other shapes (`<rect>`,
|
|
@@ -372,6 +380,18 @@ interface SerializeOptions {
|
|
|
372
380
|
* line, since whitespace inside it is content.
|
|
373
381
|
*/
|
|
374
382
|
pretty?: boolean;
|
|
383
|
+
/**
|
|
384
|
+
* The lines a text node lays out into — pass core's `layoutTextPose`, the
|
|
385
|
+
* layout the renderer draws with. With it, each line is written as a
|
|
386
|
+
* `<tspan>` at the layout's own `x` and baseline `y`, a justified line
|
|
387
|
+
* gives each word its own `x`, and a line holding a larger run is pitched
|
|
388
|
+
* as the renderer pitches it, so a reader that cannot wrap draws the lines
|
|
389
|
+
* where weasel does. A node it returns nothing for, or lays out to zero
|
|
390
|
+
* width because no face could measure it, is written without it: one line
|
|
391
|
+
* per hard break, at the node's own pitch. Fonts it reads must have loaded;
|
|
392
|
+
* `warmSvg(nodes, { textLayout })` loads them.
|
|
393
|
+
*/
|
|
394
|
+
textLayout?: (node: SvgTextNode) => TextPoseLayout | null | undefined;
|
|
375
395
|
}
|
|
376
396
|
|
|
377
397
|
/**
|
|
@@ -421,22 +441,38 @@ declare function nativeSvgSpace(space: string | null | undefined): boolean;
|
|
|
421
441
|
*/
|
|
422
442
|
declare function serializeSvg(nodes: SvgNode[], opts?: SerializeOptions): string;
|
|
423
443
|
|
|
444
|
+
/**
|
|
445
|
+
* Escaping for the XML this package writes by hand.
|
|
446
|
+
*
|
|
447
|
+
* XML 1.0 cannot hold most C0 controls, U+FFFE, U+FFFF, or half a surrogate
|
|
448
|
+
* pair, even as character references, and a parser rejects the whole
|
|
449
|
+
* document over one. A vertical tab or form feed is a line break where text
|
|
450
|
+
* comes from (a word processor's clipboard), so those become `\n`; the rest
|
|
451
|
+
* are dropped.
|
|
452
|
+
*/
|
|
453
|
+
/** A parser turns a literal tab or line break in an attribute value into a
|
|
454
|
+
* space, so those are written as character references. */
|
|
455
|
+
declare function escapeAttr(s: string): string;
|
|
456
|
+
/** A literal carriage return in content is read back as a newline. */
|
|
457
|
+
declare function escapeText(s: string): string;
|
|
458
|
+
|
|
424
459
|
/**
|
|
425
460
|
* What `serializeSvg(nodes)` reads that loads on demand: the paint kind of
|
|
426
461
|
* every fill and stroke it writes as a paint server, and the face of every
|
|
427
462
|
* run whose script size it takes from font metrics. The kinds come from the
|
|
428
463
|
* serializer's own paint pre-pass, so the two cannot disagree. Registered
|
|
429
|
-
* kinds are included.
|
|
464
|
+
* kinds are included. Given the `textLayout` the export will run, every face
|
|
465
|
+
* a text node is set in, which that layout measures with.
|
|
430
466
|
*/
|
|
431
|
-
declare function svgNeeds(nodes: readonly SvgNode[]): RenderNeeds;
|
|
467
|
+
declare function svgNeeds(nodes: readonly SvgNode[], opts?: Pick<SerializeOptions, 'textLayout'>): RenderNeeds;
|
|
432
468
|
/**
|
|
433
|
-
* Load what {@link svgNeeds} lists, so a `serializeSvg(nodes)` issued
|
|
434
|
-
* resolves writes every paint server's def and every script size
|
|
435
|
-
* face it renders in. Only those load: a lazily registered kind or font the
|
|
469
|
+
* Load what {@link svgNeeds} lists, so a `serializeSvg(nodes, opts)` issued
|
|
470
|
+
* after it resolves writes every paint server's def, and every script size and
|
|
471
|
+
* laid-out line from the face it renders in. Only those load: a lazily registered kind or font the
|
|
436
472
|
* nodes do not use is never fetched, and cannot fail the export. A kind
|
|
437
473
|
* nothing registered is passed over; the export warns about it instead.
|
|
438
474
|
*/
|
|
439
|
-
declare function warmSvg(nodes: readonly SvgNode[]): Promise<void>;
|
|
475
|
+
declare function warmSvg(nodes: readonly SvgNode[], opts?: Pick<SerializeOptions, 'textLayout'>): Promise<void>;
|
|
440
476
|
|
|
441
477
|
/**
|
|
442
478
|
* Map between SVG `<pattern>` elements and weasel's pattern paints.
|
|
@@ -502,6 +538,12 @@ interface SvgKitLeafData {
|
|
|
502
538
|
style?: TextStyle;
|
|
503
539
|
runs?: readonly StyledRun[];
|
|
504
540
|
verticalAlign?: TextVerticalAlign;
|
|
541
|
+
/** A text node's paint over its whole box, under the glyphs. */
|
|
542
|
+
background?: Fill | null;
|
|
543
|
+
/** A text node's inset from its box to its text, on every side. */
|
|
544
|
+
padding?: number;
|
|
545
|
+
/** `'clip'` cuts a text node's text at its box. */
|
|
546
|
+
overflow?: 'visible' | 'clip';
|
|
505
547
|
image?: ImageNodeData['image'];
|
|
506
548
|
}
|
|
507
549
|
/** A kit paint as an `SvgPaint`. `null` is `fill="none"`; a box-relative
|
|
@@ -517,19 +559,23 @@ declare function svgImageFromKit(image: ImageNodeData['image'], pose: SvgKitPose
|
|
|
517
559
|
/**
|
|
518
560
|
* Write one leaf as the `SvgNode` its built-in painter draws — image, text or
|
|
519
561
|
* path, in the order the painters claim a node. `null` for data none of them
|
|
520
|
-
* draws.
|
|
562
|
+
* draws. A text node with a `background` is a group: the box, then the text.
|
|
563
|
+
* One that clips is a group clipped to its box as it is drawn, turned with it.
|
|
521
564
|
*
|
|
522
565
|
* A path with no `fill` takes `kit:path`'s fallback: the default shape fill
|
|
523
566
|
* when it has no stroke, and no fill when it has one. Under a pose `transform`
|
|
524
567
|
* its stroke width takes the uniform part of the stretch, as `parseSvg` reads
|
|
525
568
|
* a stroke under a skewed element.
|
|
526
569
|
*/
|
|
527
|
-
declare function svgLeafFromKit(data: SvgKitLeafData, pose: SvgKitPose): SvgPathNode | SvgTextNode | SvgImageNode | null;
|
|
570
|
+
declare function svgLeafFromKit(data: SvgKitLeafData, pose: SvgKitPose): SvgPathNode | SvgTextNode | SvgImageNode | SvgGroupNode | null;
|
|
528
571
|
/** One node as {@link svgNodesFromKit} reads it. */
|
|
529
572
|
interface SvgKitTreeNode {
|
|
530
573
|
kind: string;
|
|
531
574
|
data: unknown;
|
|
532
575
|
pose: SvgKitPose;
|
|
576
|
+
/** The kit's `SceneNode.hidden`: written with `display="none"`, which
|
|
577
|
+
* `parseSvg(…, { keepHidden: true })` reads back as `hidden`. */
|
|
578
|
+
hidden?: boolean;
|
|
533
579
|
/** A container's copies, as the kit's `ContainerNode.copiesFromPose`
|
|
534
580
|
* draws them: each is written as a transformed group of its children. */
|
|
535
581
|
copiesFromPose?(pose: SvgKitPose, node: never): readonly Matrix[] | null;
|
|
@@ -556,7 +602,7 @@ interface SvgNodesFromKitOptions<TId extends string = string> {
|
|
|
556
602
|
* Walk a scene's container tree into `SvgNode`s ready for `serializeSvg`:
|
|
557
603
|
* every `container` becomes a group of its children, in z-order, and every
|
|
558
604
|
* leaf goes through {@link svgLeafFromKit} unless `options.leaf` says
|
|
559
|
-
* otherwise.
|
|
605
|
+
* otherwise. A hidden node is written hidden, with its subtree as it is.
|
|
560
606
|
*/
|
|
561
607
|
declare function svgNodesFromKit<TId extends string>(tree: SvgKitTree<TId>, options?: SvgNodesFromKitOptions<TId>): SvgNode[];
|
|
562
608
|
|
|
@@ -611,6 +657,10 @@ interface SvgNodesToKitDraftsOptions<TData> {
|
|
|
611
657
|
pose: SvgDraftPose;
|
|
612
658
|
data: SvgKitLeafData;
|
|
613
659
|
}, source: SvgLeafNode): TData | null;
|
|
660
|
+
/** Keep a group that draws nothing, which is otherwise dropped — for one
|
|
661
|
+
* whose metadata means something with no children under it. It is drafted
|
|
662
|
+
* with its clip's box, or a zero box at the origin. */
|
|
663
|
+
keepEmpty?(source: SvgGroupNode): boolean;
|
|
614
664
|
}
|
|
615
665
|
/** Lower an `SvgPaint` onto the paint of the `kit:path` painter's
|
|
616
666
|
* `data.fill` — a `Paint`, or `null` for SVG's `fill="none"` (the painter
|
|
@@ -628,7 +678,8 @@ declare function strokeDataFromSvg(stroke: SvgStroke | undefined, box: SvgDraftB
|
|
|
628
678
|
* Walk an `SvgNode[]` tree and emit a flat, parent-before-child list of
|
|
629
679
|
* {@link SvgSceneDraft}s. Each `<g>` becomes a container whose pose is the
|
|
630
680
|
* union AABB of its descendants, or its clip's box when it has one; leaves
|
|
631
|
-
* carry kit-painter-native data. Empty groups are dropped
|
|
681
|
+
* carry kit-painter-native data. Empty groups are dropped unless
|
|
682
|
+
* `options.keepEmpty` keeps them, and so is a group holding only those.
|
|
632
683
|
*
|
|
633
684
|
* Handed a whole `ParseResult`, it also registers the document's markers
|
|
634
685
|
* (`parsed.markers`), without which the strokes naming them draw bare.
|
|
@@ -646,9 +697,10 @@ declare function svgNodesToKitDrafts<TData = Record<string, unknown>>(input: Par
|
|
|
646
697
|
* Each file is fit-clamped to 90% of the visible viewport and centered on the
|
|
647
698
|
* drop point (or the viewport center), with later files cascading by a fixed
|
|
648
699
|
* offset. A multi-root file is wrapped in one container so it arrives as a
|
|
649
|
-
* single selectable unit.
|
|
700
|
+
* single selectable unit. Content the file hides arrives hidden
|
|
701
|
+
* (`SceneNode.hidden`) rather than being left out. A file that fails to parse, or parses to nothing,
|
|
650
702
|
* is skipped with a `console.warn`.
|
|
651
703
|
*/
|
|
652
704
|
declare function unpackSvgFiles(files: File[], ctx: IngestCtx): Promise<void>;
|
|
653
705
|
|
|
654
|
-
export { DEFAULT_MEDIA_ENVIRONMENT, IDENTITY_MATRIX, type Matrix, type NamespaceMeta, type NamespacedElement, type ParseOptions, type ParseResult, type SerializeOptions, type SupportsOptions, type SvgDraftBounds, type SvgDraftPose, type SvgGroupNode, type SvgImageNode, type SvgKitLeafData, type SvgKitPose, type SvgKitTree, type SvgKitTreeNode, type SvgLeafNode, type SvgMediaEnvironment, type SvgNode, type SvgNodesFromKitOptions, type SvgNodesToKitDraftsOptions, type SvgPaint, type SvgPathNode, type SvgSceneDraft, type SvgStroke, type SvgTextNode, evaluateMediaQuery, evaluateSupports, fillDataFromSvg, nativeSvgKind, nativeSvgSpace, parseSvg, serializeSvg, strokeDataFromSvg, svgImageFromKit, svgLeafFromKit, svgNeeds, svgNodesFromKit, svgNodesToKitDrafts, svgPaintFromKit, svgStrokeFromKit, tilePreviewCssUrl, tilePreviewSvg, unpackSvgFiles, warmSvg };
|
|
706
|
+
export { DEFAULT_MEDIA_ENVIRONMENT, IDENTITY_MATRIX, type Matrix, type NamespaceMeta, type NamespacedElement, type ParseOptions, type ParseResult, type SerializeOptions, type SupportsOptions, type SvgDraftBounds, type SvgDraftPose, type SvgGroupNode, type SvgImageNode, type SvgKitLeafData, type SvgKitPose, type SvgKitTree, type SvgKitTreeNode, type SvgLeafNode, type SvgMediaEnvironment, type SvgNode, type SvgNodesFromKitOptions, type SvgNodesToKitDraftsOptions, type SvgPaint, type SvgPathNode, type SvgSceneDraft, type SvgStroke, type SvgTextNode, escapeAttr, escapeText, evaluateMediaQuery, evaluateSupports, fillDataFromSvg, nativeSvgKind, nativeSvgSpace, parseSvg, serializeSvg, strokeDataFromSvg, svgImageFromKit, svgLeafFromKit, svgNeeds, svgNodesFromKit, svgNodesToKitDrafts, svgPaintFromKit, svgStrokeFromKit, tilePreviewCssUrl, tilePreviewSvg, unpackSvgFiles, warmSvg };
|