@weasel-js/svg 1.11.1 → 1.13.0-rc.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/README.md +5 -2
- package/dist/index.d.ts +119 -36
- package/dist/index.js +326 -127
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -105,13 +105,16 @@ drafts the kit's built-in path, text and image painters draw, and registers
|
|
|
105
105
|
the document's markers. Containers carry no opacity, so an element or group
|
|
106
106
|
`opacity` is multiplied into the paints of the leaves under it. `nextId` is
|
|
107
107
|
handed the node each id is for, and `options.leaf` maps each leaf's kit data
|
|
108
|
-
into data of your own shape, from the source node's metadata too.
|
|
108
|
+
into data of your own shape, from the source node's metadata too. `options.mark`
|
|
109
|
+
says which `<g>`s are marks with children, as the export's `mark` decorator
|
|
110
|
+
tagged them.
|
|
109
111
|
|
|
110
112
|
`svgNodesFromKit(scene)` goes the other way: containers become groups, and
|
|
111
113
|
each leaf is written the way its painter draws it, with the pose baked into
|
|
112
114
|
the geometry and box-relative paints resolved into that box. Hand
|
|
113
115
|
`serializeSvg` the result. Options pick the roots, skip nodes (a hidden
|
|
114
|
-
layer), replace a leaf's lowering or decorate a group
|
|
116
|
+
layer), replace a leaf's lowering, or decorate a group or a mark with children
|
|
117
|
+
so the import can tell the two apart. The per-leaf pieces are
|
|
115
118
|
public too: `svgLeafFromKit`, `svgPaintFromKit`, `svgStrokeFromKit`,
|
|
116
119
|
`svgImageFromKit`.
|
|
117
120
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +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,
|
|
3
|
+
import { Path, Paint, ScreenLength, StrokeAlign, MarkerRef, VertexWidth, StrokeNib, StyledRun, TextStyle, TextVerticalAlign, Fill, Stroke, PoseLinear, MarkerEntry, TextPoseLayout, RenderNeeds, TilePatternSpec, IngestCtx, Inherit, ImageNodeData, NodeClip } from '@weasel-js/core';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Media Queries 4 evaluation against a fixed environment.
|
|
@@ -134,6 +134,17 @@ interface SvgStroke {
|
|
|
134
134
|
vertexWidths?: VertexWidth[];
|
|
135
135
|
nib?: StrokeNib;
|
|
136
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Which of a node's paints its own element sets none of, so that it takes the
|
|
139
|
+
* paint of the enclosing `<g>` that does. Its `fill` and `stroke` still hold
|
|
140
|
+
* what that resolves to.
|
|
141
|
+
*/
|
|
142
|
+
interface SvgInherits {
|
|
143
|
+
fill?: true;
|
|
144
|
+
/** Set only when the element sets no `stroke-*` or `marker-*` property
|
|
145
|
+
* either: the stroke is taken whole. */
|
|
146
|
+
stroke?: true;
|
|
147
|
+
}
|
|
137
148
|
/**
|
|
138
149
|
* Leaf node: a path geometry plus fill/stroke. Other shapes (`<rect>`,
|
|
139
150
|
* `<ellipse>`, etc.) are lowered to this on parse.
|
|
@@ -143,6 +154,7 @@ interface SvgPathNode {
|
|
|
143
154
|
path: Path;
|
|
144
155
|
fill: SvgPaint;
|
|
145
156
|
stroke?: SvgStroke;
|
|
157
|
+
inherits?: SvgInherits;
|
|
146
158
|
/** Element-level opacity (`opacity="..."`), 0..1. */
|
|
147
159
|
opacity?: number;
|
|
148
160
|
/** Element-level rotation in **radians**, pivoting around the AABB
|
|
@@ -172,6 +184,12 @@ interface SvgGroupNode {
|
|
|
172
184
|
* unions them and a `Path` holds one outline. */
|
|
173
185
|
clip?: Path;
|
|
174
186
|
opacity?: number;
|
|
187
|
+
/** The fill its children take when they set none — written as the group's
|
|
188
|
+
* own `fill`. Absent when neither it nor an enclosing group sets one. */
|
|
189
|
+
fill?: SvgPaint;
|
|
190
|
+
/** As `fill`, for the stroke; absent too when the one in effect is none. */
|
|
191
|
+
stroke?: SvgStroke;
|
|
192
|
+
inherits?: SvgInherits;
|
|
175
193
|
/** Kept by `ParseOptions.keepHidden` from content SVG does not render:
|
|
176
194
|
* `display="none"` here, or a leaf under `visibility="hidden"`. Written
|
|
177
195
|
* back as `display="none"`. */
|
|
@@ -218,6 +236,7 @@ interface SvgTextNode {
|
|
|
218
236
|
*/
|
|
219
237
|
fill?: Fill | null;
|
|
220
238
|
stroke?: Stroke;
|
|
239
|
+
inherits?: SvgInherits;
|
|
221
240
|
/** Element-level opacity (`opacity="..."`), 0..1. */
|
|
222
241
|
opacity?: number;
|
|
223
242
|
/** Element-level rotation in **radians**, pivoting around the unrotated
|
|
@@ -491,6 +510,21 @@ declare function tilePreviewSvg(spec: TilePatternSpec, background?: string): str
|
|
|
491
510
|
/** `tilePreviewSvg` packed as a `url(...)` value for CSS `background-image`. */
|
|
492
511
|
declare function tilePreviewCssUrl(spec: TilePatternSpec, background?: string): string;
|
|
493
512
|
|
|
513
|
+
/** CSS Selectors 4 specificity. */
|
|
514
|
+
/** A selector's specificity as (ids, classes, types). */
|
|
515
|
+
type Specificity = readonly [number, number, number];
|
|
516
|
+
/** Negative when `a` is less specific than `b`, positive when more, 0 when equal. */
|
|
517
|
+
declare function compareSpecificity(a: Specificity, b: Specificity): number;
|
|
518
|
+
/** CSS Selectors 4 specificity of one complex selector (no comma list). */
|
|
519
|
+
declare function specificity(selector: string): Specificity;
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Split `s` on `sep` wherever it sits outside strings and (), [] nesting.
|
|
523
|
+
* With `dropBlocks`, a `{…}` block at depth zero is discarded along with the
|
|
524
|
+
* prelude before it, back to the previous separator.
|
|
525
|
+
*/
|
|
526
|
+
declare function splitTopLevel(s: string, sep: string, dropBlocks?: boolean): string[];
|
|
527
|
+
|
|
494
528
|
/**
|
|
495
529
|
* `@supports` evaluation. A declaration test asks whether this parser would
|
|
496
530
|
* honor the declaration ({@link isDeclarationHonored}), not whether a browser
|
|
@@ -508,6 +542,19 @@ interface SupportsOptions {
|
|
|
508
542
|
*/
|
|
509
543
|
declare function evaluateSupports(condition: string, opts?: SupportsOptions): boolean;
|
|
510
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Parse each file and insert its node tree, one undo step per file. Pass it
|
|
547
|
+
* as `<SceneCanvas ingestion={{ svg: { unpack: unpackSvgFiles } }}>`.
|
|
548
|
+
*
|
|
549
|
+
* Each file is fit-clamped to 90% of the visible viewport and centered on the
|
|
550
|
+
* drop point (or the viewport center), with later files cascading by a fixed
|
|
551
|
+
* offset. A multi-root file is wrapped in one container so it arrives as a
|
|
552
|
+
* single selectable unit. Content the file hides arrives hidden
|
|
553
|
+
* (`SceneNode.hidden`) rather than being left out. A file that fails to parse, or parses to nothing,
|
|
554
|
+
* is skipped with a `console.warn`.
|
|
555
|
+
*/
|
|
556
|
+
declare function unpackSvgFiles(files: File[], ctx: IngestCtx): Promise<void>;
|
|
557
|
+
|
|
511
558
|
/**
|
|
512
559
|
* The kit-to-SVG direction: scene leaves back to `SvgNode`s, the inverse of
|
|
513
560
|
* `svgNodesToKitDrafts`. Each leaf is written as the built-in painter that
|
|
@@ -532,8 +579,9 @@ interface SvgKitPose {
|
|
|
532
579
|
* `svgNodesToKitDrafts` writes. */
|
|
533
580
|
interface SvgKitLeafData {
|
|
534
581
|
path?: Path;
|
|
535
|
-
|
|
536
|
-
|
|
582
|
+
/** `'inherit'` takes the enclosing container's. */
|
|
583
|
+
fill?: Fill | Inherit | null;
|
|
584
|
+
stroke?: Stroke | Inherit | null;
|
|
537
585
|
text?: string;
|
|
538
586
|
style?: TextStyle;
|
|
539
587
|
runs?: readonly StyledRun[];
|
|
@@ -552,7 +600,7 @@ interface SvgKitLeafData {
|
|
|
552
600
|
declare function svgPaintFromKit(fill: Paint | null, box: SvgKitPose): SvgPaint;
|
|
553
601
|
/** A kit `Stroke` as an `SvgStroke` — the inverse of `strokeDataFromSvg`.
|
|
554
602
|
* One with no paint or no width draws nothing and is written as no stroke. */
|
|
555
|
-
declare function svgStrokeFromKit(
|
|
603
|
+
declare function svgStrokeFromKit(raw: Stroke | null | undefined, box: SvgKitPose): SvgStroke | undefined;
|
|
556
604
|
/** Write a `kit:image` leaf as an `SvgImageNode` — the inverse of the image
|
|
557
605
|
* arm of `svgNodesToKitDrafts`. The pose is the image's box. */
|
|
558
606
|
declare function svgImageFromKit(image: ImageNodeData['image'], pose: SvgKitPose): SvgImageNode;
|
|
@@ -562,10 +610,12 @@ declare function svgImageFromKit(image: ImageNodeData['image'], pose: SvgKitPose
|
|
|
562
610
|
* draws. A text node with a `background` is a group: the box, then the text.
|
|
563
611
|
* One that clips is a group clipped to its box as it is drawn, turned with it.
|
|
564
612
|
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
613
|
+
* An `'inherit'` fill or stroke is none here, with no container to read;
|
|
614
|
+
* {@link svgNodesFromKit} resolves it first.
|
|
615
|
+
*
|
|
616
|
+
* A fill or stroke that paints nothing is written `none`. Under a pose
|
|
617
|
+
* `transform` a stroke's width takes the uniform part of the stretch, as
|
|
618
|
+
* `parseSvg` reads a stroke under a skewed element.
|
|
569
619
|
*/
|
|
570
620
|
declare function svgLeafFromKit(data: SvgKitLeafData, pose: SvgKitPose): SvgPathNode | SvgTextNode | SvgImageNode | SvgGroupNode | null;
|
|
571
621
|
/** One node as {@link svgNodesFromKit} reads it. */
|
|
@@ -576,8 +626,11 @@ interface SvgKitTreeNode {
|
|
|
576
626
|
/** The kit's `SceneNode.hidden`: written with `display="none"`, which
|
|
577
627
|
* `parseSvg(…, { keepHidden: true })` reads back as `hidden`. */
|
|
578
628
|
hidden?: boolean;
|
|
579
|
-
/**
|
|
580
|
-
*
|
|
629
|
+
/** The kit's `SceneNode.clip`: `'outline'` writes the node's children
|
|
630
|
+
* clipped to its outline, as core's `clipOutline` reads it. */
|
|
631
|
+
clip?: NodeClip;
|
|
632
|
+
/** The node's copies, as the kit's `SceneNode.copiesFromPose` draws them:
|
|
633
|
+
* each is written as a transformed group of its children. */
|
|
581
634
|
copiesFromPose?(pose: SvgKitPose, node: never): readonly Matrix[] | null;
|
|
582
635
|
}
|
|
583
636
|
/** The read side of a scene that {@link svgNodesFromKit} walks. A kit
|
|
@@ -593,18 +646,37 @@ interface SvgNodesFromKitOptions<TId extends string = string> {
|
|
|
593
646
|
roots?: readonly TId[];
|
|
594
647
|
/** `false` leaves a node out, with everything under it — a hidden layer. */
|
|
595
648
|
include?(id: TId): boolean;
|
|
596
|
-
/** Lower a leaf yourself; `null` leaves it out. Defaults to {@link svgLeafFromKit}.
|
|
597
|
-
|
|
598
|
-
|
|
649
|
+
/** Lower a leaf yourself; `null` leaves it out. Defaults to {@link svgLeafFromKit}.
|
|
650
|
+
* `inherited` is what the leaf's `'inherit'` fields resolve to; write those
|
|
651
|
+
* as these, and the walk marks the result as inheriting where SVG's
|
|
652
|
+
* cascade can carry them. */
|
|
653
|
+
leaf?(id: TId, node: SvgKitTreeNode, inherited: SvgKitInherited): SvgNode | null;
|
|
654
|
+
/** Decorate the `<g>` written for a scene group, e.g. with `meta`. */
|
|
599
655
|
group?(id: TId, group: SvgGroupNode): SvgGroupNode;
|
|
656
|
+
/** Decorate the `<g>` written for a mark with children, so a reader can
|
|
657
|
+
* tell it from a group: `svgNodesToKitDrafts`'s `mark` option reads one
|
|
658
|
+
* back. Given, the `<g>` holds the mark's own element, then one `<g>` of its
|
|
659
|
+
* children carrying the mark's clip, then a transformed `<g>` of that for
|
|
660
|
+
* each copy; a mark whose children are all left out holds its own element
|
|
661
|
+
* alone. Not called for a mark whose own element is itself a group, or that
|
|
662
|
+
* draws nothing. */
|
|
663
|
+
mark?(id: TId, group: SvgGroupNode): SvgGroupNode;
|
|
600
664
|
}
|
|
601
665
|
/**
|
|
602
|
-
* Walk a scene's
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
* otherwise
|
|
666
|
+
* Walk a scene's tree into `SvgNode`s ready for `serializeSvg`: a group
|
|
667
|
+
* becomes a `<g>` of its children, in z-order, drawing nothing of its own; a
|
|
668
|
+
* mark is written by {@link svgLeafFromKit} unless `options.leaf` says
|
|
669
|
+
* otherwise, and a mark with children is a `<g>` holding that element and then
|
|
670
|
+
* its children, or one `<g>` of them when `options.mark` decorates it. A hidden
|
|
671
|
+
* node is written hidden, with its subtree as it is.
|
|
606
672
|
*/
|
|
607
673
|
declare function svgNodesFromKit<TId extends string>(tree: SvgKitTree<TId>, options?: SvgNodesFromKitOptions<TId>): SvgNode[];
|
|
674
|
+
/** What a leaf's `'inherit'` fill and stroke resolve to — its nearest
|
|
675
|
+
* enclosing container's; `null` for none. */
|
|
676
|
+
interface SvgKitInherited {
|
|
677
|
+
fill: Fill | null;
|
|
678
|
+
stroke: Stroke | null;
|
|
679
|
+
}
|
|
608
680
|
|
|
609
681
|
/** Axis-aligned box, in the coordinate space of the SVG being unpacked. Used
|
|
610
682
|
* for the bounds a draft occupies before it becomes a scene node. */
|
|
@@ -620,30 +692,45 @@ type SvgDraftPose = SvgDraftBounds & {
|
|
|
620
692
|
transform?: PoseLinear;
|
|
621
693
|
};
|
|
622
694
|
|
|
695
|
+
/**
|
|
696
|
+
* Parse an SVG file into **native scene nodes** — path/text leaves under
|
|
697
|
+
* containers that mirror the source `<g>` structure — instead of the default
|
|
698
|
+
* single embedded-image node.
|
|
699
|
+
*
|
|
700
|
+
* Leaf data targets the kit's built-in painters. Poses are absolute AABBs, and
|
|
701
|
+
* the renderer rebases stored geometry into the pose box, so placement and
|
|
702
|
+
* fit-clamping operate on poses alone and never rewrite path coordinates.
|
|
703
|
+
* Stroke widths, dashes, font sizes, and letter spacing live in data, so
|
|
704
|
+
* they take the clamp separately.
|
|
705
|
+
*/
|
|
706
|
+
|
|
623
707
|
/**
|
|
624
708
|
* One node the unpack wants the scene to materialize, in parent-before-child
|
|
625
709
|
* order (a draft's `parentId` always names an earlier draft, or `null` for
|
|
626
710
|
* roots). `hidden` is the source node's, for the caller to map onto whatever
|
|
627
711
|
* it hides a node with.
|
|
628
712
|
*
|
|
629
|
-
* A
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
* rather than its children's.
|
|
713
|
+
* A group's `data` is empty unless its `<g>` is clipped. A clipped one declares
|
|
714
|
+
* `clip: 'outline'` and holds the clip as an unpainted path,
|
|
715
|
+
* `{ path, fill: null }`, which is the outline a group clips to; its `pose` is
|
|
716
|
+
* the clip's box rather than its children's. A mark declares a clip only when
|
|
717
|
+
* it is read from a `<g>` `options.mark` claims.
|
|
633
718
|
*/
|
|
634
719
|
type SvgSceneDraft<TData = Record<string, unknown>> = {
|
|
635
|
-
kind: '
|
|
720
|
+
kind: 'group';
|
|
636
721
|
id: string;
|
|
637
722
|
parentId: string | null;
|
|
638
723
|
pose: SvgDraftPose;
|
|
639
724
|
data: SvgKitLeafData;
|
|
725
|
+
clip?: NodeClip;
|
|
640
726
|
hidden?: true;
|
|
641
727
|
} | {
|
|
642
|
-
kind: '
|
|
728
|
+
kind: 'mark';
|
|
643
729
|
id: string;
|
|
644
730
|
parentId: string | null;
|
|
645
731
|
pose: SvgDraftPose;
|
|
646
732
|
data: TData;
|
|
733
|
+
clip?: NodeClip;
|
|
647
734
|
hidden?: true;
|
|
648
735
|
};
|
|
649
736
|
/** A leaf `SvgNode`: everything but a group. */
|
|
@@ -661,6 +748,14 @@ interface SvgNodesToKitDraftsOptions<TData> {
|
|
|
661
748
|
* whose metadata means something with no children under it. It is drafted
|
|
662
749
|
* with its clip's box, or a zero box at the origin. */
|
|
663
750
|
keepEmpty?(source: SvgGroupNode): boolean;
|
|
751
|
+
/** Whether a `<g>` is a mark with children, as `svgNodesFromKit`'s `mark`
|
|
752
|
+
* option writes one: its first element is drafted as the mark, the
|
|
753
|
+
* children of the `<g>` after it as the mark's, hidden where that `<g>` is,
|
|
754
|
+
* with its clip as the mark's `clip: 'outline'`, and anything after that,
|
|
755
|
+
* such as baked copies, as the mark's further children. A clip on the
|
|
756
|
+
* claimed `<g>` itself clips the mark as a group around it. A `<g>` whose
|
|
757
|
+
* first element is a group, or whose second is not, is a group. */
|
|
758
|
+
mark?(source: SvgGroupNode): boolean;
|
|
664
759
|
}
|
|
665
760
|
/** Lower an `SvgPaint` onto the paint of the `kit:path` painter's
|
|
666
761
|
* `data.fill` — a `Paint`, or `null` for SVG's `fill="none"` (the painter
|
|
@@ -690,17 +785,5 @@ declare function strokeDataFromSvg(stroke: SvgStroke | undefined, box: SvgDraftB
|
|
|
690
785
|
* data; a group whose leaves it all leaves out is dropped like an empty one.
|
|
691
786
|
*/
|
|
692
787
|
declare function svgNodesToKitDrafts<TData = Record<string, unknown>>(input: ParseResult | readonly SvgNode[], nextId: (source: SvgNode) => string, options?: SvgNodesToKitDraftsOptions<TData>): SvgSceneDraft<TData>[];
|
|
693
|
-
/**
|
|
694
|
-
* Parse each file and insert its node tree, one undo step per file. Pass it
|
|
695
|
-
* as `<SceneCanvas ingestion={{ svg: { unpack: unpackSvgFiles } }}>`.
|
|
696
|
-
*
|
|
697
|
-
* Each file is fit-clamped to 90% of the visible viewport and centered on the
|
|
698
|
-
* drop point (or the viewport center), with later files cascading by a fixed
|
|
699
|
-
* offset. A multi-root file is wrapped in one container so it arrives as a
|
|
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,
|
|
702
|
-
* is skipped with a `console.warn`.
|
|
703
|
-
*/
|
|
704
|
-
declare function unpackSvgFiles(files: File[], ctx: IngestCtx): Promise<void>;
|
|
705
788
|
|
|
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 };
|
|
789
|
+
export { DEFAULT_MEDIA_ENVIRONMENT, IDENTITY_MATRIX, type Matrix, type NamespaceMeta, type NamespacedElement, type ParseOptions, type ParseResult, type SerializeOptions, type Specificity, 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, compareSpecificity, escapeAttr, escapeText, evaluateMediaQuery, evaluateSupports, fillDataFromSvg, nativeSvgKind, nativeSvgSpace, parseSvg, serializeSvg, specificity, splitTopLevel, strokeDataFromSvg, svgImageFromKit, svgLeafFromKit, svgNeeds, svgNodesFromKit, svgNodesToKitDrafts, svgPaintFromKit, svgStrokeFromKit, tilePreviewCssUrl, tilePreviewSvg, unpackSvgFiles, warmSvg };
|