@weasel-js/svg 1.7.0 → 1.7.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 CHANGED
@@ -66,6 +66,14 @@ That cuts both ways on import: a `fill="url(#mesh1) #c04a3f"` from Inkscape,
66
66
  whose mesh gradients this package does not model, imports as flat `#c04a3f`
67
67
  rather than as a dropped fill.
68
68
 
69
+ `serializeSvg` is synchronous, so a kind loaded on demand (`mesh-gradient`, or
70
+ one declared with `registerPaintKindLoader`) that has not landed yet has no
71
+ `toSvg` to call, and its def is left out with a warning. `await warmSvg(nodes)`
72
+ first loads the kinds those nodes paint with, and the faces a sub- or
73
+ superscript run with its own `baselineShift` takes its size from — nothing
74
+ else, so an unrelated kind that fails to load cannot fail the export.
75
+ `svgNeeds(nodes)` lists the same things without loading them.
76
+
69
77
  ### A gradient's blend space
70
78
 
71
79
  A gradient's `interpolate` — `'oklab'` or `'oklch'` — has no SVG spelling
@@ -130,6 +138,22 @@ def, because a `userSpaceOnUse` size and an `orient="auto"` start both depend on
130
138
  the referencing stroke. `wzl:inset` restores the inset; without it the inset is
131
139
  0. A reference to a marker neither registered nor defined warns and is dropped.
132
140
 
141
+ ## Stylesheets
142
+
143
+ `<style>` rules cascade with the presentation attributes and `style=""`. A parse
144
+ is one static render, so `@media` and `<style media>` are answered once, against
145
+ a fixed environment: a `screen` whose viewport is the root's `width`/`height`
146
+ (else its `viewBox`, else 300 × 150), `prefers-color-scheme: light`, and no
147
+ hover or pointer. Pass `parseSvg(svg, { media: { prefersColorScheme: 'dark',
148
+ width: 1200 } })` to render for different media; `evaluateMediaQuery` answers a
149
+ query against the same environment.
150
+
151
+ `@supports` asks whether this parser honors a declaration, not whether a browser
152
+ parses it: `(fill: red)` holds, `(display: grid)` and `(clip-path: url(#c))` do
153
+ not, because nothing reads them from a stylesheet. `@import` is not fetched, and
154
+ each one is reported in `warnings`. Rules inside `@layer`, `@container` and
155
+ other at-rules are skipped.
156
+
133
157
  ## Raster images
134
158
 
135
159
  `<image>` parses to an `SvgImageNode` holding the `href` verbatim — an
package/dist/index.d.ts CHANGED
@@ -1,5 +1,44 @@
1
1
  import { Mat3 } from '@weasel-js/geom';
2
- import { Path, FillStyle, ScreenLength, StrokeAlign, MarkerRef, StyledRun, TextStyle, TextVerticalAlign, Stroke, MarkerEntry, TilePatternSpec, ImageNodeData, IngestCtx } from '@weasel-js/core';
2
+ import { Path, FillStyle, ScreenLength, StrokeAlign, MarkerRef, StyledRun, TextStyle, TextVerticalAlign, Stroke, MarkerEntry, RenderNeeds, TilePatternSpec, ImageNodeData, IngestCtx } from '@weasel-js/core';
3
+
4
+ /**
5
+ * Media Queries 4 evaluation against a fixed environment.
6
+ *
7
+ * A parse represents one static render, so `@media` and `<style media>` are
8
+ * answered once, against an {@link SvgMediaEnvironment}, rather than tracked
9
+ * as live conditions.
10
+ */
11
+ /** The media a parse is taken to be rendered on. */
12
+ interface SvgMediaEnvironment {
13
+ /** Media type; `all` always matches as well. */
14
+ readonly type: string;
15
+ /** Viewport width in CSS px. */
16
+ readonly width: number;
17
+ /** Viewport height in CSS px. */
18
+ readonly height: number;
19
+ /** Device pixels per CSS px. */
20
+ readonly resolution: number;
21
+ readonly prefersColorScheme: 'light' | 'dark';
22
+ readonly prefersReducedMotion: 'no-preference' | 'reduce';
23
+ /** Answers both `hover` and `any-hover`. */
24
+ readonly hover: 'none' | 'hover';
25
+ /** Answers both `pointer` and `any-pointer`. */
26
+ readonly pointer: 'none' | 'coarse' | 'fine';
27
+ /** How often the output can change once rendered. */
28
+ readonly update: 'none' | 'slow' | 'fast';
29
+ /** Bits per color component; 0 on a monochrome device. */
30
+ readonly color: number;
31
+ /** Bits per pixel of a monochrome device; 0 otherwise. */
32
+ readonly monochrome: number;
33
+ }
34
+ /** A static, light-scheme screen render with no pointer. Width and height are the replaced-element default. */
35
+ declare const DEFAULT_MEDIA_ENVIRONMENT: SvgMediaEnvironment;
36
+ /**
37
+ * Whether a media query list matches `env`. An empty list matches; a
38
+ * malformed query in the list is `not all`, leaving its neighbors intact; an
39
+ * unknown feature or value is unknown, which never matches, even under `not`.
40
+ */
41
+ declare function evaluateMediaQuery(list: string, env: SvgMediaEnvironment): boolean;
3
42
 
4
43
  /**
5
44
  * Public types for `@weasel-js/svg`. The package exposes a flat,
@@ -255,6 +294,14 @@ interface ParseOptions {
255
294
  * the structured `meta` bag; they are silently dropped at serialize time.
256
295
  */
257
296
  namespaces?: Record<string, string>;
297
+ /**
298
+ * The media `@media` rules and `<style media>` are evaluated against. A
299
+ * parse is one static render: by default a `screen` whose viewport is the
300
+ * root's `width` / `height` (else its `viewBox`, else 300 × 150), with a
301
+ * light color scheme and no hover or pointer. Fields given here replace
302
+ * those defaults.
303
+ */
304
+ media?: Partial<SvgMediaEnvironment>;
258
305
  }
259
306
  /** Output of {@link parseSvg}. */
260
307
  interface ParseResult {
@@ -352,12 +399,24 @@ interface SerializeOptions {
352
399
  declare function parseSvg(svg: string, opts?: ParseOptions): ParseResult;
353
400
 
354
401
  /**
355
- * Serialize a `SvgNode[]` tree to an SVG document string. Every leaf is
356
- * emitted as a `<path>` (even shapes that started as `<rect>` etc.) —
357
- * lossless geometry round-trip beats round-tripping the element-kind
358
- * label. Gradient paints are gathered into a single `<defs>` block.
402
+ * Map between SVG `<linearGradient>` / `<radialGradient>` elements and
403
+ * weasel's `FillStyle` gradient variants. Definitions are indexed by id
404
+ * wherever in the document they appear, and looked up when a `fill` /
405
+ * `stroke` attribute references one as `url(#id)`. On serialize, we
406
+ * emit a fresh `<defs>` block with stable generated ids.
359
407
  */
360
408
 
409
+ /** `true` when SVG has a paint server for this kind, so the reference needs no
410
+ * fallback color and the root needs no foreign namespace. */
411
+ /** Whether SVG has its own paint server for paint kind `kind`: solids, the
412
+ * linear and radial gradients, and patterns. Any other kind is written in
413
+ * weasel's namespace with a fallback color, which other renderers paint flat. */
414
+ declare function nativeSvgKind(kind: string): boolean;
415
+ /** Whether a gradient interpolating through `space` blends the same in every
416
+ * SVG renderer — only sRGB, the default. A perceptual space still exports,
417
+ * but renderers other than weasel blend it in sRGB. */
418
+ declare function nativeSvgSpace(space: string | null | undefined): boolean;
419
+
361
420
  /**
362
421
  * Walk the tree and produce an SVG document string. The root `<svg>`'s
363
422
  * `viewBox` is taken from `opts.viewBox` if supplied, otherwise computed
@@ -365,6 +424,23 @@ declare function parseSvg(svg: string, opts?: ParseOptions): ParseResult;
365
424
  */
366
425
  declare function serializeSvg(nodes: SvgNode[], opts?: SerializeOptions): string;
367
426
 
427
+ /**
428
+ * What `serializeSvg(nodes)` reads that loads on demand: the paint kind of
429
+ * every fill and stroke it writes as a paint server, and the face of every
430
+ * run whose script size it takes from font metrics. The kinds come from the
431
+ * serializer's own paint pre-pass, so the two cannot disagree. Registered
432
+ * kinds are included.
433
+ */
434
+ declare function svgNeeds(nodes: readonly SvgNode[]): RenderNeeds;
435
+ /**
436
+ * Load what {@link svgNeeds} lists, so a `serializeSvg(nodes)` issued after it
437
+ * resolves writes every paint server's def and every script size from the
438
+ * face it renders in. Only those load: a lazily registered kind or font the
439
+ * nodes do not use is never fetched, and cannot fail the export. A kind
440
+ * nothing registered is passed over; the export warns about it instead.
441
+ */
442
+ declare function warmSvg(nodes: readonly SvgNode[]): Promise<void>;
443
+
368
444
  /**
369
445
  * Map between SVG `<pattern>` elements and weasel's `pattern` `FillStyle`.
370
446
  * The counterpart to `gradients.ts` for the other paint-server kind.
@@ -393,23 +469,20 @@ declare function tilePreviewSvg(spec: TilePatternSpec, background?: string): str
393
469
  declare function tilePreviewCssUrl(spec: TilePatternSpec, background?: string): string;
394
470
 
395
471
  /**
396
- * Map between SVG `<linearGradient>` / `<radialGradient>` elements and
397
- * weasel's `FillStyle` gradient variants. Definitions are indexed by id
398
- * wherever in the document they appear, and looked up when a `fill` /
399
- * `stroke` attribute references one as `url(#id)`. On serialize, we
400
- * emit a fresh `<defs>` block with stable generated ids.
472
+ * `@supports` evaluation. A declaration test asks whether this parser would
473
+ * honor the declaration ({@link isDeclarationHonored}), not whether a browser
474
+ * could parse it — the answer decides whether the guarded rules apply here.
401
475
  */
402
-
403
- /** `true` when SVG has a paint server for this kind, so the reference needs no
404
- * fallback color and the root needs no foreign namespace. */
405
- /** Whether SVG has its own paint server for paint kind `kind`: solids, the
406
- * linear and radial gradients, and patterns. Any other kind is written in
407
- * weasel's namespace with a fallback color, which other renderers paint flat. */
408
- declare function nativeSvgKind(kind: string): boolean;
409
- /** Whether a gradient interpolating through `space` blends the same in every
410
- * SVG renderer — only sRGB, the default. A perceptual space still exports,
411
- * but renderers other than weasel blend it in sRGB. */
412
- declare function nativeSvgSpace(space: string | null | undefined): boolean;
476
+ interface SupportsOptions {
477
+ /** Answers `selector(…)`; without it every selector test is false. */
478
+ readonly selector?: (selector: string) => boolean;
479
+ }
480
+ /**
481
+ * Whether a `@supports` condition holds. `selector()` defers to
482
+ * `opts.selector`; any other function and any unrecognized parenthesized
483
+ * content is false, so `not` of one is true. A malformed condition is false.
484
+ */
485
+ declare function evaluateSupports(condition: string, opts?: SupportsOptions): boolean;
413
486
 
414
487
  /**
415
488
  * The kit-to-SVG direction: scene leaves back to `SvgNode`s, the inverse of
@@ -472,6 +545,7 @@ interface SvgKitTree<TId extends string = string> {
472
545
  childrenOf(id: TId): readonly TId[];
473
546
  get(id: TId): SvgKitTreeNode | undefined;
474
547
  }
548
+ /** Options for {@link svgNodesFromKit}. */
475
549
  interface SvgNodesFromKitOptions<TId extends string = string> {
476
550
  /** Walk these ids, in this order, instead of the tree's roots. */
477
551
  roots?: readonly TId[];
@@ -520,6 +594,7 @@ type SvgSceneDraft<TData = Record<string, unknown>> = {
520
594
  };
521
595
  /** A leaf `SvgNode`: everything but a group. */
522
596
  type SvgLeafNode = Exclude<SvgNode, SvgGroupNode>;
597
+ /** Options for {@link svgNodesToKitDrafts}. */
523
598
  interface SvgNodesToKitDraftsOptions<TData> {
524
599
  /** Lower a leaf yourself, from the kit data the default writes for it and
525
600
  * the node it came from — for data shaped other than the kit painters', or
@@ -570,4 +645,4 @@ declare function svgNodesToKitDrafts<TData = Record<string, unknown>>(input: Par
570
645
  */
571
646
  declare function unpackSvgFiles(files: File[], ctx: IngestCtx): Promise<void>;
572
647
 
573
- export { IDENTITY_MATRIX, type Matrix, type NamespaceMeta, type NamespacedElement, type ParseOptions, type ParseResult, type SerializeOptions, type SvgDraftBounds, type SvgGroupNode, type SvgImageNode, type SvgKitLeafData, type SvgKitPose, type SvgKitTree, type SvgKitTreeNode, type SvgLeafNode, type SvgNode, type SvgNodesFromKitOptions, type SvgNodesToKitDraftsOptions, type SvgPaint, type SvgPathNode, type SvgSceneDraft, type SvgStroke, type SvgTextNode, fillDataFromSvg, nativeSvgKind, nativeSvgSpace, parseSvg, serializeSvg, strokeDataFromSvg, svgImageFromKit, svgLeafFromKit, svgNodesFromKit, svgNodesToKitDrafts, svgPaintFromKit, svgStrokeFromKit, tilePreviewCssUrl, tilePreviewSvg, unpackSvgFiles };
648
+ export { DEFAULT_MEDIA_ENVIRONMENT, IDENTITY_MATRIX, type Matrix, type NamespaceMeta, type NamespacedElement, type ParseOptions, type ParseResult, type SerializeOptions, type SupportsOptions, type SvgDraftBounds, 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 };