@weasel-js/svg 1.4.3 → 1.4.4
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/dist/index.d.ts +6 -1
- package/dist/index.js +54 -14
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -72,7 +72,12 @@ type SvgPaint = {
|
|
|
72
72
|
/** Stroke description: a paint plus structural line parameters. */
|
|
73
73
|
interface SvgStroke {
|
|
74
74
|
paint: SvgPaint;
|
|
75
|
-
width
|
|
75
|
+
/** 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
|
+
* and the same unit system as the kit's `Stroke.width`. */
|
|
78
|
+
width: number | {
|
|
79
|
+
px: number;
|
|
80
|
+
};
|
|
76
81
|
opacity?: number;
|
|
77
82
|
/** `stroke-linecap`. Default per SVG spec is `'butt'`. */
|
|
78
83
|
cap?: 'butt' | 'round' | 'square';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pathFromD, PATH_M, PATH_L, PATH_Z, boundsOfPath, getMarker, SCRIPT_METRICS, dwarn, createInsertOp, PathBuilder, parseColor, rgbaToHex, PATH_C, PATH_Q,
|
|
1
|
+
import { pathFromD, PATH_M, PATH_L, PATH_Z, boundsOfPath, getMarker, SCRIPT_METRICS, dwarn, createInsertOp, PathBuilder, parseColor, rgbaToHex, PATH_C, PATH_Q, solid, fillToBoundsFrame, resolveTextStyle, getPaintKind } from '@weasel-js/core';
|
|
2
2
|
import { tileGeometry } from '@weasel-js/core/patterns-builtin';
|
|
3
3
|
|
|
4
4
|
// src/parse.ts
|
|
@@ -879,7 +879,7 @@ function parseElement(el, ctm, style, gradients, onWarn, uriToPrefix) {
|
|
|
879
879
|
}
|
|
880
880
|
const leafStyle = deriveStyle(style, el);
|
|
881
881
|
const fill = readPaint(leafStyle, "fill", "#000000", gradients, onWarn);
|
|
882
|
-
const stroke = readStroke(leafStyle, gradients, onWarn);
|
|
882
|
+
const stroke = readStroke(leafStyle, gradients, onWarn, isNonScalingStroke(el));
|
|
883
883
|
const opacity = readOpacityAttr(el, "opacity");
|
|
884
884
|
const fillRuleRaw = leafStyle["fill-rule"] ?? null;
|
|
885
885
|
if (fillRuleRaw === "evenodd" && path.kind === "polygon") {
|
|
@@ -988,14 +988,14 @@ function readPaint(style, attr, defaultColor, gradients, onWarn) {
|
|
|
988
988
|
if (a != null) out.opacity = a;
|
|
989
989
|
return out;
|
|
990
990
|
}
|
|
991
|
-
function readStroke(style, gradients, onWarn) {
|
|
991
|
+
function readStroke(style, gradients, onWarn, nonScaling = false) {
|
|
992
992
|
const inheritedStroke = style["stroke"] ?? null;
|
|
993
993
|
const inheritedWidth = style["stroke-width"] ?? null;
|
|
994
994
|
if (inheritedStroke == null && inheritedWidth == null) return void 0;
|
|
995
995
|
const paint = readPaint(style, "stroke", "#000000", gradients, onWarn);
|
|
996
996
|
if (paint.kind === "none") return void 0;
|
|
997
|
-
const
|
|
998
|
-
const stroke = { paint, width };
|
|
997
|
+
const n = inheritedWidth != null ? parseFloat(inheritedWidth) : 1;
|
|
998
|
+
const stroke = { paint, width: nonScaling ? { px: n } : n };
|
|
999
999
|
const opacityRaw = style["stroke-opacity"] ?? null;
|
|
1000
1000
|
if (opacityRaw != null) {
|
|
1001
1001
|
const a = clamp01(parseFloat(opacityRaw));
|
|
@@ -1062,6 +1062,9 @@ var STROKE_KEYS = [
|
|
|
1062
1062
|
"marker-mid",
|
|
1063
1063
|
"marker-end"
|
|
1064
1064
|
];
|
|
1065
|
+
function isNonScalingStroke(el) {
|
|
1066
|
+
return ownProp(el, "vector-effect") === "non-scaling-stroke";
|
|
1067
|
+
}
|
|
1065
1068
|
function ownStrokeStyle(el) {
|
|
1066
1069
|
const out = {};
|
|
1067
1070
|
for (const k of STROKE_KEYS) {
|
|
@@ -1249,7 +1252,7 @@ function parseTextElement(el, ctm, style, gradients, onWarn) {
|
|
|
1249
1252
|
const ay = m[1] * rawX + m[3] * rawY + m[5];
|
|
1250
1253
|
const leafStyle = deriveStyle(style, el);
|
|
1251
1254
|
const textStyle = readTextStyle(leafStyle, onWarn);
|
|
1252
|
-
const textPaint = readTextPaint(leafStyle, gradients, onWarn);
|
|
1255
|
+
const textPaint = readTextPaint(leafStyle, gradients, onWarn, isNonScalingStroke(el));
|
|
1253
1256
|
const fontSize = textStyle.fontSize ?? 16;
|
|
1254
1257
|
const lineHeight = textStyle.lineHeight ?? 1.2;
|
|
1255
1258
|
const dominantBaseline = el.getAttribute("dominant-baseline");
|
|
@@ -1357,7 +1360,7 @@ function readTspanRun(el, gradients, style, onWarn) {
|
|
|
1357
1360
|
if (paint) run.fill = paint;
|
|
1358
1361
|
}
|
|
1359
1362
|
}
|
|
1360
|
-
const stroke = coreStroke(readStroke(ownStrokeStyle(el), gradients, onWarn));
|
|
1363
|
+
const stroke = coreStroke(readStroke(ownStrokeStyle(el), gradients, onWarn, isNonScalingStroke(el)));
|
|
1361
1364
|
if (stroke) run.stroke = stroke;
|
|
1362
1365
|
return run;
|
|
1363
1366
|
}
|
|
@@ -1394,7 +1397,7 @@ function readTextStyle(style, onWarn) {
|
|
|
1394
1397
|
if (decoration.overline) out.overline = true;
|
|
1395
1398
|
return out;
|
|
1396
1399
|
}
|
|
1397
|
-
function readTextPaint(style, gradients, onWarn) {
|
|
1400
|
+
function readTextPaint(style, gradients, onWarn, nonScalingStroke = false) {
|
|
1398
1401
|
const out = {};
|
|
1399
1402
|
const fillRaw = resolveCurrentColor(style["fill"] ?? null, style);
|
|
1400
1403
|
if (fillRaw) {
|
|
@@ -1408,7 +1411,7 @@ function readTextPaint(style, gradients, onWarn) {
|
|
|
1408
1411
|
out.fill = null;
|
|
1409
1412
|
}
|
|
1410
1413
|
}
|
|
1411
|
-
const stroke = coreStroke(readStroke(style, gradients, onWarn));
|
|
1414
|
+
const stroke = coreStroke(readStroke(style, gradients, onWarn, nonScalingStroke));
|
|
1412
1415
|
if (stroke) out.stroke = stroke;
|
|
1413
1416
|
return out;
|
|
1414
1417
|
}
|
|
@@ -1608,11 +1611,15 @@ function paintAttrs(paint, name, registry, includeOpacity = true) {
|
|
|
1608
1611
|
const id = registry.register(paint.paint);
|
|
1609
1612
|
return [`${name}="url(#${id})"`];
|
|
1610
1613
|
}
|
|
1614
|
+
function strokeWidthAttrs(width) {
|
|
1615
|
+
if (typeof width === "number") return [`stroke-width="${trimNumber(width)}"`];
|
|
1616
|
+
return [`stroke-width="${trimNumber(width.px)}"`, 'vector-effect="non-scaling-stroke"'];
|
|
1617
|
+
}
|
|
1611
1618
|
function coreStrokeAttrs(stroke, registry) {
|
|
1612
1619
|
const paint = stroke?.paint;
|
|
1613
1620
|
if (!stroke || !paint) return [];
|
|
1614
|
-
const width =
|
|
1615
|
-
if (!(width > 0)) return [];
|
|
1621
|
+
const width = stroke.width ?? 1;
|
|
1622
|
+
if (!((typeof width === "object" ? width.px : width) > 0)) return [];
|
|
1616
1623
|
const attrs = [];
|
|
1617
1624
|
if ("color" in paint) {
|
|
1618
1625
|
attrs.push(`stroke="${paint.color}"`);
|
|
@@ -1622,7 +1629,7 @@ function coreStrokeAttrs(stroke, registry) {
|
|
|
1622
1629
|
} else {
|
|
1623
1630
|
attrs.push(`stroke="url(#${registry.register(paint)})"`);
|
|
1624
1631
|
}
|
|
1625
|
-
attrs.push(
|
|
1632
|
+
attrs.push(...strokeWidthAttrs(width));
|
|
1626
1633
|
if (stroke.cap) attrs.push(`stroke-linecap="${stroke.cap}"`);
|
|
1627
1634
|
if (stroke.join) attrs.push(`stroke-linejoin="${stroke.join}"`);
|
|
1628
1635
|
if (stroke.dash && stroke.dash.length > 0) {
|
|
@@ -1645,7 +1652,7 @@ function coreStrokeAttrs(stroke, registry) {
|
|
|
1645
1652
|
}
|
|
1646
1653
|
function strokeAttrsFor(stroke, registry) {
|
|
1647
1654
|
const attrs = paintAttrs(stroke.paint, "stroke", registry, false);
|
|
1648
|
-
attrs.push(
|
|
1655
|
+
attrs.push(...strokeWidthAttrs(stroke.width));
|
|
1649
1656
|
const opacity = stroke.opacity ?? (stroke.paint.kind === "solid" ? stroke.paint.opacity : void 0);
|
|
1650
1657
|
if (opacity != null && opacity !== 1) {
|
|
1651
1658
|
attrs.push(`stroke-opacity="${trimNumber(opacity)}"`);
|
|
@@ -1860,6 +1867,21 @@ function strokeDataFromSvg(stroke, box) {
|
|
|
1860
1867
|
...stroke.markerEnd !== void 0 ? { markerEnd: stroke.markerEnd } : {}
|
|
1861
1868
|
};
|
|
1862
1869
|
}
|
|
1870
|
+
function fillInBoxFrame(fill, box) {
|
|
1871
|
+
const units = "units" in fill ? fill.units : void 0;
|
|
1872
|
+
return units === "world" ? fillToBoundsFrame(fill, box) : fill;
|
|
1873
|
+
}
|
|
1874
|
+
function runInBoxFrame(run, box) {
|
|
1875
|
+
const fill = run.fill ? fillInBoxFrame(run.fill, box) : run.fill;
|
|
1876
|
+
const stroke = run.stroke ? strokeInBoxFrame(run.stroke, box) : run.stroke;
|
|
1877
|
+
if (fill === run.fill && stroke === run.stroke) return run;
|
|
1878
|
+
return { ...run, ...fill ? { fill } : {}, ...stroke ? { stroke } : {} };
|
|
1879
|
+
}
|
|
1880
|
+
function strokeInBoxFrame(stroke, box) {
|
|
1881
|
+
if (!stroke.paint) return stroke;
|
|
1882
|
+
const paint = fillInBoxFrame(stroke.paint, box);
|
|
1883
|
+
return paint === stroke.paint ? stroke : { ...stroke, paint };
|
|
1884
|
+
}
|
|
1863
1885
|
function svgNodesToKitDrafts(nodes, nextId) {
|
|
1864
1886
|
const drafts = [];
|
|
1865
1887
|
const visit = (n, parentId) => {
|
|
@@ -1891,12 +1913,26 @@ function svgNodesToKitDrafts(nodes, nextId) {
|
|
|
1891
1913
|
height: n.height
|
|
1892
1914
|
};
|
|
1893
1915
|
if (n.rotation) pose2.rotation = n.rotation;
|
|
1916
|
+
const box = {
|
|
1917
|
+
x: pose2.x,
|
|
1918
|
+
y: pose2.y,
|
|
1919
|
+
width: pose2.width,
|
|
1920
|
+
height: pose2.height
|
|
1921
|
+
};
|
|
1894
1922
|
drafts.push({
|
|
1895
1923
|
kind: "leaf",
|
|
1896
1924
|
id: nextId(),
|
|
1897
1925
|
parentId,
|
|
1898
1926
|
pose: pose2,
|
|
1899
|
-
data: {
|
|
1927
|
+
data: {
|
|
1928
|
+
text: n.text,
|
|
1929
|
+
...n.style ? { style: n.style } : {},
|
|
1930
|
+
...n.runs ? { runs: n.runs.map((r) => runInBoxFrame(r, box)) } : {},
|
|
1931
|
+
// `!== undefined`, not a truthiness test: `null` is the document
|
|
1932
|
+
// saying `fill="none"`, and absent takes the painter's default.
|
|
1933
|
+
...n.fill !== void 0 ? { fill: n.fill === null ? null : fillInBoxFrame(n.fill, box) } : {},
|
|
1934
|
+
...n.stroke !== void 0 ? { stroke: strokeInBoxFrame(n.stroke, box) } : {}
|
|
1935
|
+
}
|
|
1900
1936
|
});
|
|
1901
1937
|
return pose2;
|
|
1902
1938
|
}
|
|
@@ -1948,8 +1984,12 @@ function textBoxWidth(n) {
|
|
|
1948
1984
|
function scaleTextData(data, scale) {
|
|
1949
1985
|
if (scale === 1 || typeof data.text !== "string") return data;
|
|
1950
1986
|
const style = data.style ?? {};
|
|
1987
|
+
const runs = data.runs;
|
|
1951
1988
|
return {
|
|
1952
1989
|
...data,
|
|
1990
|
+
...runs ? {
|
|
1991
|
+
runs: runs.map((r) => r.fontSize !== void 0 ? { ...r, fontSize: r.fontSize * scale } : r)
|
|
1992
|
+
} : {},
|
|
1953
1993
|
style: { ...style, fontSize: resolveTextStyle(style).fontSize * scale }
|
|
1954
1994
|
};
|
|
1955
1995
|
}
|