@weasel-js/svg 1.10.1 → 1.11.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 +10 -0
- package/dist/index.d.ts +63 -13
- package/dist/index.js +286 -74
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { identity, multiply, invert, splitByClosure, fillsOpenSubpaths, rotateAboutPoint, hasOpenSubpath, splitSubpaths } from '@weasel-js/geom';
|
|
2
|
-
import { isTileKind, boundsOfPath, transformPath, isSolidPaint, warmFonts, warmPaintKinds, isPaintKindKnown, solid, fillToBoundsFrame, getMarker, registerMarker, dwarn, unionAABB, createInsertOp, fillInPoseFrame, DEFAULT_SHAPE_FILL, pathInPoseFrame, poseLinearOf, poseFrameOf,
|
|
2
|
+
import { resolveCorners, PATH_M, PATH_L, PATH_C, PATH_Q, PATH_Z, isTileKind, boundsOfPath, transformPath, isSolidPaint, warmFonts, warmPaintKinds, isPaintKindKnown, solid, fillToBoundsFrame, getMarker, registerMarker, dwarn, unionAABB, createInsertOp, fillInPoseFrame, pathThroughPoseFrame, DEFAULT_SHAPE_FILL, pathInPoseFrame, poseLinearOf, poseFrameOf, DEFAULT_TEXT_STYLE, resolveScreenLength, pathFromD, isPatternPaint, resolveTextStyle, strokeToPath, toRuns, resolveRunFace, parseColor, rgbaToHex, layoutRuns, resolveRuns, resolveAlign, PathBuilder, scaleVertexWidth, getPaintKind, resolveMarkerSize, paragraphDirection, scriptMetricsFor, vertexHalfWidths, isTilePaint, tileSpecOf } from '@weasel-js/core';
|
|
3
3
|
import { tileGeometry } from '@weasel-js/core/patterns-builtin';
|
|
4
4
|
|
|
5
5
|
// src/types.ts
|
|
@@ -177,9 +177,11 @@ function scaleLength(v, scale) {
|
|
|
177
177
|
return typeof v === "number" ? v * scale : v;
|
|
178
178
|
}
|
|
179
179
|
function scaleStroke(stroke, scale) {
|
|
180
|
-
const { width: width2 } = stroke;
|
|
181
|
-
if (scale === 1
|
|
182
|
-
const
|
|
180
|
+
const { width: width2, vertexWidths } = stroke;
|
|
181
|
+
if (scale === 1) return stroke;
|
|
182
|
+
const scaledVertices = vertexWidths ? { vertexWidths: vertexWidths.map((n) => scaleVertexWidth(n, scale)) } : {};
|
|
183
|
+
if (typeof width2 === "object") return vertexWidths ? { ...stroke, ...scaledVertices } : stroke;
|
|
184
|
+
const out = { ...stroke, ...scaledVertices };
|
|
183
185
|
if (width2 !== void 0) out.width = width2 * scale;
|
|
184
186
|
if (out.dash) out.dash = out.dash.map((n) => n * scale);
|
|
185
187
|
return out;
|
|
@@ -1381,7 +1383,8 @@ function readPattern(el, onWarn) {
|
|
|
1381
1383
|
if (!isIdentity([m[0], m[1], m[2], m[3], 0, 0])) paint.transform = [m[0], m[1], m[2], m[3]];
|
|
1382
1384
|
return paint;
|
|
1383
1385
|
}
|
|
1384
|
-
function serializePathD(
|
|
1386
|
+
function serializePathD(given) {
|
|
1387
|
+
const path = resolveCorners(given);
|
|
1385
1388
|
if (path.kind === "rect") {
|
|
1386
1389
|
const { x, y, width: width2, height: height2 } = path;
|
|
1387
1390
|
return `M${trimNumber(x)} ${trimNumber(y)}h${trimNumber(width2)}v${trimNumber(height2)}h${trimNumber(-width2)}Z`;
|
|
@@ -2096,6 +2099,97 @@ function coreStroke(stroke) {
|
|
|
2096
2099
|
if (stroke.markerEnd) out.markerEnd = stroke.markerEnd;
|
|
2097
2100
|
return out;
|
|
2098
2101
|
}
|
|
2102
|
+
var VERTEX_WIDTHS = "vertex-widths";
|
|
2103
|
+
var NIB = "nib";
|
|
2104
|
+
var WIDTH = "stroke-width";
|
|
2105
|
+
var ROLE = "role";
|
|
2106
|
+
var OUTLINE = "stroke-outline";
|
|
2107
|
+
var GROUP = "stroke-group";
|
|
2108
|
+
var MARKER_ATTR = /^(marker-(?:start|mid|end))=/;
|
|
2109
|
+
var UNSET = "-";
|
|
2110
|
+
var SIDES = "/";
|
|
2111
|
+
function attrOf(el, name) {
|
|
2112
|
+
return el.getAttributeNS(WEASEL_NS, name) ?? el.getAttribute(`${WEASEL_NS_PREFIX}:${name}`);
|
|
2113
|
+
}
|
|
2114
|
+
function hasVariableWidth(stroke) {
|
|
2115
|
+
return (stroke?.vertexWidths?.length ?? 0) > 0 || stroke?.nib !== void 0;
|
|
2116
|
+
}
|
|
2117
|
+
function writesVariableWidth(nodes) {
|
|
2118
|
+
return nodes.some((n) => n.kind === "group" ? writesVariableWidth(n.children) : n.kind === "path" && hasVariableWidth(n.stroke));
|
|
2119
|
+
}
|
|
2120
|
+
function widthToken(entry) {
|
|
2121
|
+
const { left, right } = vertexHalfWidths(entry, NaN);
|
|
2122
|
+
const side = (v) => Number.isNaN(v) ? UNSET : trimNumber(v);
|
|
2123
|
+
if (typeof entry === "number") return Number.isNaN(left) ? UNSET : trimNumber(left + right);
|
|
2124
|
+
return Number.isNaN(left) && Number.isNaN(right) ? UNSET : `${side(left)}${SIDES}${side(right)}`;
|
|
2125
|
+
}
|
|
2126
|
+
function widthOfToken(token) {
|
|
2127
|
+
const side = (v) => v === UNSET ? NaN : Number(v);
|
|
2128
|
+
if (!token.includes(SIDES)) return side(token);
|
|
2129
|
+
const [left, right] = token.split(SIDES);
|
|
2130
|
+
return { left: side(left), right: side(right) };
|
|
2131
|
+
}
|
|
2132
|
+
function variableWidthAttrs(stroke, strokeAttrs) {
|
|
2133
|
+
const width2 = typeof stroke.width === "number" ? stroke.width : stroke.width.px;
|
|
2134
|
+
const out = [
|
|
2135
|
+
...strokeAttrs.map((a) => a.startsWith("stroke-width=") ? 'stroke-width="0"' : MARKER_ATTR.test(a) ? `${WEASEL_NS_PREFIX}:${a}` : a),
|
|
2136
|
+
`${WEASEL_NS_PREFIX}:${WIDTH}="${trimNumber(width2)}"`
|
|
2137
|
+
];
|
|
2138
|
+
if (stroke.vertexWidths?.length) {
|
|
2139
|
+
const list = stroke.vertexWidths.map(widthToken).join(" ");
|
|
2140
|
+
out.push(`${WEASEL_NS_PREFIX}:${VERTEX_WIDTHS}="${list}"`);
|
|
2141
|
+
}
|
|
2142
|
+
if (stroke.nib) {
|
|
2143
|
+
out.push(`${WEASEL_NS_PREFIX}:${NIB}="${String(stroke.nib.angle)} ${String(stroke.nib.ratio)}"`);
|
|
2144
|
+
}
|
|
2145
|
+
return out;
|
|
2146
|
+
}
|
|
2147
|
+
function strokeOutlineXml(path, stroke, fillAttrs, transform) {
|
|
2148
|
+
const kit = {
|
|
2149
|
+
width: stroke.width,
|
|
2150
|
+
...stroke.vertexWidths ? { vertexWidths: stroke.vertexWidths } : {},
|
|
2151
|
+
...stroke.nib ? { nib: stroke.nib } : {},
|
|
2152
|
+
...stroke.cap ? { cap: stroke.cap } : {},
|
|
2153
|
+
...stroke.join ? { join: stroke.join } : {},
|
|
2154
|
+
...stroke.dash ? { dash: stroke.dash } : {},
|
|
2155
|
+
...stroke.miterLimit != null ? { miterLimit: stroke.miterLimit } : {},
|
|
2156
|
+
...stroke.align ? { align: stroke.align } : {},
|
|
2157
|
+
...stroke.markerStart ? { markerStart: stroke.markerStart } : {},
|
|
2158
|
+
...stroke.markerMid ? { markerMid: stroke.markerMid } : {},
|
|
2159
|
+
...stroke.markerEnd ? { markerEnd: stroke.markerEnd } : {}
|
|
2160
|
+
};
|
|
2161
|
+
const outline = strokeToPath(path, kit);
|
|
2162
|
+
const attrs = [`d="${serializePathD(outline)}"`, ...fillAttrs, 'stroke="none"'];
|
|
2163
|
+
if (transform) attrs.push(transform);
|
|
2164
|
+
attrs.push(`${WEASEL_NS_PREFIX}:${ROLE}="${OUTLINE}"`);
|
|
2165
|
+
return `<path ${attrs.join(" ")}/>`;
|
|
2166
|
+
}
|
|
2167
|
+
function strokeGroupXml(opacity, inner) {
|
|
2168
|
+
return `<g ${opacity} ${WEASEL_NS_PREFIX}:${ROLE}="${GROUP}">${inner}</g>`;
|
|
2169
|
+
}
|
|
2170
|
+
function unwrapStrokeGroup(el, node) {
|
|
2171
|
+
if (attrOf(el, ROLE) !== GROUP || !node || Array.isArray(node) || node.kind !== "group") return node;
|
|
2172
|
+
const [only] = node.children;
|
|
2173
|
+
if (node.children.length !== 1 || only.kind !== "path") return node;
|
|
2174
|
+
return node.opacity != null ? { ...only, opacity: node.opacity * (only.opacity ?? 1) } : only;
|
|
2175
|
+
}
|
|
2176
|
+
function isStrokeOutline(el) {
|
|
2177
|
+
return attrOf(el, ROLE) === OUTLINE;
|
|
2178
|
+
}
|
|
2179
|
+
function withVariableWidth(el, stroke) {
|
|
2180
|
+
const width2 = parseFloat(attrOf(el, WIDTH) ?? "");
|
|
2181
|
+
if (!stroke || !Number.isFinite(width2)) return stroke;
|
|
2182
|
+
const out = { ...stroke, width: typeof stroke.width === "number" ? width2 : { px: width2 } };
|
|
2183
|
+
const list = attrOf(el, VERTEX_WIDTHS);
|
|
2184
|
+
if (list) out.vertexWidths = list.trim().split(/\s+/).map(widthOfToken);
|
|
2185
|
+
const [angle, ratio] = (attrOf(el, NIB) ?? "").trim().split(/\s+/).map(Number);
|
|
2186
|
+
if (Number.isFinite(angle) && Number.isFinite(ratio)) out.nib = { angle, ratio };
|
|
2187
|
+
for (const [attr, field] of [["marker-start", "markerStart"], ["marker-mid", "markerMid"], ["marker-end", "markerEnd"]]) {
|
|
2188
|
+
const id = /^url\(\s*#([^)\s]+)\s*\)$/.exec(attrOf(el, attr)?.trim() ?? "")?.[1];
|
|
2189
|
+
if (id) out[field] = id;
|
|
2190
|
+
}
|
|
2191
|
+
return out;
|
|
2192
|
+
}
|
|
2099
2193
|
var near = (v, target) => Math.abs(v - target) <= 1e-9;
|
|
2100
2194
|
function placeBox(box, m, stretch) {
|
|
2101
2195
|
const [a, b, c, d] = m;
|
|
@@ -2239,6 +2333,7 @@ function anchorOffset(style, width2, text) {
|
|
|
2239
2333
|
|
|
2240
2334
|
// src/tspanLines.ts
|
|
2241
2335
|
var LINES_ATTR = "data-weasel-lines";
|
|
2336
|
+
var LINE_HEIGHT_ATTR = "data-weasel-line-height";
|
|
2242
2337
|
var statesLines = (tspan) => tspan.hasAttribute(LINES_ATTR);
|
|
2243
2338
|
function linesXml(pieces, x, pitch) {
|
|
2244
2339
|
let out = "";
|
|
@@ -2286,9 +2381,9 @@ var LineTracker = class {
|
|
|
2286
2381
|
const dy = readLength(tspan, "dy", "y", 0, this.onWarn);
|
|
2287
2382
|
this.at = (y != null ? readLength(tspan, "y", "y", from, this.onWarn) : from) + dy;
|
|
2288
2383
|
if (!tspan.hasAttribute("x") || !(movedY || dy !== 0)) return 0;
|
|
2289
|
-
const stated = Number(tspan.getAttribute(LINES_ATTR));
|
|
2290
|
-
const lines = Number.isInteger(stated) && stated
|
|
2291
|
-
if (afterText && this.at > from) this.pitches.push((this.at - from) / lines);
|
|
2384
|
+
const stated = Number(tspan.getAttribute(LINES_ATTR) ?? NaN);
|
|
2385
|
+
const lines = Number.isInteger(stated) && stated >= 0 ? stated : 1;
|
|
2386
|
+
if (afterText && lines > 0 && this.at > from) this.pitches.push((this.at - from) / lines);
|
|
2292
2387
|
return lines;
|
|
2293
2388
|
}
|
|
2294
2389
|
/**
|
|
@@ -2347,6 +2442,76 @@ function joinLines(lines, leading = 0) {
|
|
|
2347
2442
|
}
|
|
2348
2443
|
return out;
|
|
2349
2444
|
}
|
|
2445
|
+
|
|
2446
|
+
// src/laidLines.ts
|
|
2447
|
+
var LAID_ATTR = "data-weasel-layout";
|
|
2448
|
+
function layoutMeasured(layout, text) {
|
|
2449
|
+
return layout.laid.bounds.width > 0 || text.trim() === "";
|
|
2450
|
+
}
|
|
2451
|
+
function anchorX(cells, { anchor, rtl }) {
|
|
2452
|
+
const left = Math.min(...cells.map((c) => c.x));
|
|
2453
|
+
const right = Math.max(...cells.map((c) => c.x + c.advance));
|
|
2454
|
+
if (anchor === "middle") return (left + right) / 2;
|
|
2455
|
+
return anchor === "start" === !rtl ? left : right;
|
|
2456
|
+
}
|
|
2457
|
+
function wordStarts(text, start, end) {
|
|
2458
|
+
const out = [start];
|
|
2459
|
+
for (let i = start + 1; i < end; i++) {
|
|
2460
|
+
if (!/\s/.test(text[i]) && /\s/.test(text[i - 1])) out.push(i);
|
|
2461
|
+
}
|
|
2462
|
+
return out;
|
|
2463
|
+
}
|
|
2464
|
+
function rangeXml(pieces, offsets, start, end, lead) {
|
|
2465
|
+
let out = "";
|
|
2466
|
+
let first = true;
|
|
2467
|
+
pieces.forEach((piece, k) => {
|
|
2468
|
+
const from = Math.max(start, offsets[k]);
|
|
2469
|
+
const to = Math.min(end, offsets[k] + piece.text.length);
|
|
2470
|
+
if (from >= to) return;
|
|
2471
|
+
const text = piece.text.slice(from - offsets[k], to - offsets[k]);
|
|
2472
|
+
const attrs = [...piece.attrs ?? [], ...first ? lead : []];
|
|
2473
|
+
first = false;
|
|
2474
|
+
out += piece.attrs === null && attrs.length === 0 ? escapeText(text) : `<tspan${attrs.map((a) => ` ${a}`).join("")}>${escapeText(text)}</tspan>`;
|
|
2475
|
+
});
|
|
2476
|
+
return out;
|
|
2477
|
+
}
|
|
2478
|
+
var HARD_BREAKS = /\r\n|[\n\v\f\r\u0085\u2028\u2029]/g;
|
|
2479
|
+
var breaksIn = (text) => text.match(HARD_BREAKS)?.length ?? 0;
|
|
2480
|
+
function laidLinesXml(pieces, layout, anchor) {
|
|
2481
|
+
const text = pieces.map((p) => p.text).join("");
|
|
2482
|
+
const offsets = [];
|
|
2483
|
+
pieces.reduce((at, p) => {
|
|
2484
|
+
offsets.push(at);
|
|
2485
|
+
return at + p.text.length;
|
|
2486
|
+
}, 0);
|
|
2487
|
+
const px = (x) => `x="${trimNumber(layout.x + x)}"`;
|
|
2488
|
+
const py = (line) => `y="${trimNumber(layout.y + line.baselineY)}"`;
|
|
2489
|
+
let out = "";
|
|
2490
|
+
let wrote = false;
|
|
2491
|
+
let prevEnd = 0;
|
|
2492
|
+
const count = (lines) => {
|
|
2493
|
+
const stated = lines !== 1 || !wrote ? [`${LINES_ATTR}="${lines}"`] : [];
|
|
2494
|
+
wrote = true;
|
|
2495
|
+
return stated;
|
|
2496
|
+
};
|
|
2497
|
+
for (const line of layout.laid.lines) {
|
|
2498
|
+
if (line.cells.length === 0) continue;
|
|
2499
|
+
const start = Math.min(...line.cells.map((c) => c.srcIndex));
|
|
2500
|
+
const stepped = breaksIn(text.slice(prevEnd, start));
|
|
2501
|
+
prevEnd = line.srcEnd;
|
|
2502
|
+
const starts = line.justified ? wordStarts(text, start, line.srcEnd) : [start];
|
|
2503
|
+
starts.forEach((from, k) => {
|
|
2504
|
+
const to = starts[k + 1] ?? line.srcEnd;
|
|
2505
|
+
const cells = line.cells.filter((c) => c.srcIndex >= from && c.srcIndex < to);
|
|
2506
|
+
const lead = [px(anchorX(cells, anchor)), ...k === 0 ? [py(line), ...count(stepped)] : []];
|
|
2507
|
+
out += rangeXml(pieces, offsets, from, to, lead);
|
|
2508
|
+
});
|
|
2509
|
+
}
|
|
2510
|
+
const trailing = breaksIn(text.slice(prevEnd));
|
|
2511
|
+
const last = layout.laid.lines[layout.laid.lines.length - 1];
|
|
2512
|
+
if (trailing > 0 && last) out += `<tspan ${[px(last.x0), py(last), ...count(trailing)].join(" ")}></tspan>`;
|
|
2513
|
+
return out;
|
|
2514
|
+
}
|
|
2350
2515
|
var COLLAPSIBLE = /^\s|\s$|\s\s|[\n\t\r]/;
|
|
2351
2516
|
function readDx(el, onWarn) {
|
|
2352
2517
|
const raw = el.getAttribute("dx")?.trim();
|
|
@@ -2455,6 +2620,10 @@ function laidOutWidth(runs, style, plain) {
|
|
|
2455
2620
|
const longest = plain.split("\n").reduce((max, line) => Math.max(max, line.length), 0);
|
|
2456
2621
|
return longest * resolved.fontSize * ESTIMATED_GLYPH_ADVANCE_EM;
|
|
2457
2622
|
}
|
|
2623
|
+
function numberAttr(el, name) {
|
|
2624
|
+
const n = parseFloat(el.getAttribute(name) ?? "");
|
|
2625
|
+
return Number.isFinite(n) ? n : void 0;
|
|
2626
|
+
}
|
|
2458
2627
|
function placeTextNode(node, m, onWarn) {
|
|
2459
2628
|
const cx = node.x + node.width / 2;
|
|
2460
2629
|
const cy = node.y + node.height / 2;
|
|
@@ -2496,13 +2665,14 @@ function parseTextElement(el, ctm, style, gradients, onWarn) {
|
|
|
2496
2665
|
const textPaint = readTextPaint(leafStyle, gradients, onWarn, isNonScalingStroke(el));
|
|
2497
2666
|
const fontSize = resolveScreenLength(textStyle.fontSize ?? 16, 1);
|
|
2498
2667
|
const dominantBaseline = el.getAttribute("dominant-baseline");
|
|
2499
|
-
const
|
|
2668
|
+
const laid = el.hasAttribute(LAID_ATTR);
|
|
2669
|
+
const explicitTopAnchor = laid || dominantBaseline === "text-before-edge" || dominantBaseline === "hanging";
|
|
2500
2670
|
const topY = explicitTopAnchor ? ay : ay - fontSize;
|
|
2501
2671
|
const inheritedShift = ownValue(el, "baseline-shift", onWarn) ?? {};
|
|
2502
2672
|
const tracker = new LineTracker(el, onWarn);
|
|
2503
2673
|
const { runs, lead } = readRuns(el, tracker, inheritedShift, textStyle.letterSpacing, gradients, leafStyle, onWarn);
|
|
2504
2674
|
const plain = runs.map((r) => r.text).join("");
|
|
2505
|
-
const pitched = tracker.lineHeight(fontSize);
|
|
2675
|
+
const pitched = laid ? numberAttr(el, LINE_HEIGHT_ATTR) : tracker.lineHeight(fontSize);
|
|
2506
2676
|
if (pitched !== void 0) textStyle.lineHeight = pitched;
|
|
2507
2677
|
const lineHeight = textStyle.lineHeight ?? DEFAULT_LINE_HEIGHT;
|
|
2508
2678
|
const dataW = num2(el.getAttribute("data-weasel-width"), NaN);
|
|
@@ -3017,10 +3187,10 @@ function parseChildren(parent, ctm, style, gradients, clips, onWarn, uriToPrefix
|
|
|
3017
3187
|
for (let i = 0; i < parent.children.length; i++) {
|
|
3018
3188
|
const el = parent.children[i];
|
|
3019
3189
|
const ns = el.namespaceURI;
|
|
3020
|
-
if (ns && ns !== "http://www.w3.org/2000/svg") continue;
|
|
3190
|
+
if (ns && ns !== "http://www.w3.org/2000/svg" || isStrokeOutline(el)) continue;
|
|
3021
3191
|
const hidden = isHiddenElement(el, style);
|
|
3022
3192
|
if (hidden && !keepHidden) continue;
|
|
3023
|
-
const node = parseElement(el, ctm, style, gradients, clips, onWarn, uriToPrefix, keepHidden);
|
|
3193
|
+
const node = unwrapStrokeGroup(el, parseElement(el, ctm, style, gradients, clips, onWarn, uriToPrefix, keepHidden));
|
|
3024
3194
|
if (!node) continue;
|
|
3025
3195
|
const parsed = Array.isArray(node) ? node : [node];
|
|
3026
3196
|
if (hidden) for (const n of parsed) n.hidden = true;
|
|
@@ -3113,7 +3283,7 @@ function parseElement(el, ctm, style, gradients, clips, onWarn, uriToPrefix, kee
|
|
|
3113
3283
|
}
|
|
3114
3284
|
const leafStyle = deriveStyle(style, el);
|
|
3115
3285
|
const fill = paintThroughMatrix(readPaint2(leafStyle, "fill", "#000000", gradients, onWarn), baked);
|
|
3116
|
-
const ownStroke = readStroke(leafStyle, gradients, onWarn, isNonScalingStroke(el));
|
|
3286
|
+
const ownStroke = withVariableWidth(el, readStroke(leafStyle, gradients, onWarn, isNonScalingStroke(el)));
|
|
3117
3287
|
const stroke = ownStroke && strokeThroughMatrix(ownStroke, baked);
|
|
3118
3288
|
if (stroke && typeof stroke.width === "number" && isNonUniform(baked)) {
|
|
3119
3289
|
onWarn(`<${tag}> stroke sits under a skew or non-uniform scale; its width takes the uniform part only`);
|
|
@@ -3292,6 +3462,12 @@ function paintAttrs(paint, name, registry, includeOpacity = true) {
|
|
|
3292
3462
|
if (includeOpacity) out.push(...opacityAttr(`${name}-opacity`, svgPaintOpacity(paint)));
|
|
3293
3463
|
return out;
|
|
3294
3464
|
}
|
|
3465
|
+
function strokePaintAsFillAttrs(stroke, registry) {
|
|
3466
|
+
return [
|
|
3467
|
+
...paintAttrs(stroke.paint, "fill", registry, false),
|
|
3468
|
+
...opacityAttr("fill-opacity", stroke.opacity ?? svgPaintOpacity(stroke.paint))
|
|
3469
|
+
];
|
|
3470
|
+
}
|
|
3295
3471
|
function svgPaintOpacity(paint) {
|
|
3296
3472
|
if (paint.kind === "solid") return paint.opacity;
|
|
3297
3473
|
return paint.kind === "gradient" ? paint.paint.opacity : void 0;
|
|
@@ -3361,12 +3537,13 @@ function strokeAttrsFor(stroke, registry, warn) {
|
|
|
3361
3537
|
}
|
|
3362
3538
|
return attrs;
|
|
3363
3539
|
}
|
|
3364
|
-
function textXml(node, registry, namespaces, warn) {
|
|
3540
|
+
function textXml(node, registry, namespaces, warn, given) {
|
|
3541
|
+
const layout = given && layoutMeasured(given, node.text) ? given : null;
|
|
3365
3542
|
const x = node.x + anchorOffset(node.style, node.width, node.text);
|
|
3366
3543
|
const attrs = [
|
|
3367
3544
|
`x="${trimNumber(x)}"`,
|
|
3368
3545
|
`y="${trimNumber(node.y)}"`,
|
|
3369
|
-
`dominant-baseline="text-before-edge"`,
|
|
3546
|
+
layout ? `${LAID_ATTR}="lines"` : `dominant-baseline="text-before-edge"`,
|
|
3370
3547
|
// SVG's default whitespace handling would collapse indentation and runs
|
|
3371
3548
|
// of spaces away on re-import.
|
|
3372
3549
|
`xml:space="preserve"`,
|
|
@@ -3381,9 +3558,10 @@ function textXml(node, registry, namespaces, warn) {
|
|
|
3381
3558
|
if (style?.fontVariantCaps === "small-caps") attrs.push('font-variant="small-caps"');
|
|
3382
3559
|
const direction = svgDirection(style, node.text);
|
|
3383
3560
|
if (direction === "rtl" || style?.direction === "ltr") attrs.push(`direction="${direction}"`);
|
|
3561
|
+
let anchor = "start";
|
|
3384
3562
|
if (style?.align != null || direction === "rtl") {
|
|
3385
3563
|
const align = style?.align ?? "left";
|
|
3386
|
-
|
|
3564
|
+
anchor = align === "center" ? "middle" : align === "start" || align === "justify" ? "start" : align === "end" ? "end" : align === "left" === (direction === "ltr") ? "start" : "end";
|
|
3387
3565
|
if (anchor !== "start") attrs.push(`text-anchor="${anchor}"`);
|
|
3388
3566
|
if (align === "justify") attrs.push('data-weasel-align="justify"');
|
|
3389
3567
|
}
|
|
@@ -3398,13 +3576,14 @@ function textXml(node, registry, namespaces, warn) {
|
|
|
3398
3576
|
}
|
|
3399
3577
|
if (style?.wrap) {
|
|
3400
3578
|
attrs.push('data-weasel-wrap="true"');
|
|
3401
|
-
warn("text that wraps at its box width is written unwrapped: SVG text does not wrap, so other readers draw one line per hard break (weasel reads the wrap back)");
|
|
3579
|
+
if (!layout) warn("text that wraps at its box width is written unwrapped: SVG text does not wrap, so other readers draw one line per hard break (weasel reads the wrap back)");
|
|
3402
3580
|
}
|
|
3403
3581
|
if (style?.tabSize != null) attrs.push(`data-weasel-tab-size="${trimNumber(style.tabSize)}"`);
|
|
3404
3582
|
if (node.verticalAlign && node.verticalAlign !== "top") {
|
|
3405
3583
|
attrs.push(`data-weasel-vertical-align="${node.verticalAlign}"`);
|
|
3406
|
-
warn(`text aligned to the ${node.verticalAlign} of its box is written top-aligned: SVG text has no box, so other readers draw it at the top (weasel reads the alignment back)`);
|
|
3584
|
+
if (!layout) warn(`text aligned to the ${node.verticalAlign} of its box is written top-aligned: SVG text has no box, so other readers draw it at the top (weasel reads the alignment back)`);
|
|
3407
3585
|
}
|
|
3586
|
+
if (layout && style?.lineHeight != null) attrs.push(`${LINE_HEIGHT_ATTR}="${trimNumber(style.lineHeight)}"`);
|
|
3408
3587
|
if (node.fill !== void 0) {
|
|
3409
3588
|
const paint = node.fill?.paint;
|
|
3410
3589
|
if (!paint) attrs.push('fill="none"');
|
|
@@ -3421,7 +3600,7 @@ function textXml(node, registry, namespaces, warn) {
|
|
|
3421
3600
|
if (frame) attrs.push(frame);
|
|
3422
3601
|
const pieces = node.runs && node.runs.length > 0 ? node.runs.map((r) => ({ text: r.text, attrs: runAttrs(r, style, registry, warn) })) : [{ text: node.text, attrs: null }];
|
|
3423
3602
|
const resolved = resolveTextStyle(style);
|
|
3424
|
-
const body = linesXml(pieces, x, resolved.fontSize * resolved.lineHeight);
|
|
3603
|
+
const body = layout ? laidLinesXml(pieces, layout, { anchor, rtl: direction === "rtl" }) : linesXml(pieces, x, resolved.fontSize * resolved.lineHeight);
|
|
3425
3604
|
const metaAttrs = metaAttrsXml(node.meta, namespaces);
|
|
3426
3605
|
const metaEls = metaElementsXml(node.meta, namespaces);
|
|
3427
3606
|
return `<text ${attrs.join(" ")}${metaAttrs}>${body}${metaEls}</text>`;
|
|
@@ -3518,7 +3697,7 @@ function serializeSvg(nodes, opts = {}) {
|
|
|
3518
3697
|
const vb = `${trimNumber(bounds.x)} ${trimNumber(bounds.y)} ${trimNumber(bounds.width)} ${trimNumber(bounds.height)}`;
|
|
3519
3698
|
const namespaces = opts.namespaces ?? {};
|
|
3520
3699
|
const rootAttrs = [`xmlns="http://www.w3.org/2000/svg"`];
|
|
3521
|
-
if (registry.usesPrivateNamespace() && namespaces[WEASEL_NS_PREFIX] == null) {
|
|
3700
|
+
if ((registry.usesPrivateNamespace() || writesVariableWidth(nodes)) && namespaces[WEASEL_NS_PREFIX] == null) {
|
|
3522
3701
|
rootAttrs.push(`xmlns:${WEASEL_NS_PREFIX}="${WEASEL_NS}"`);
|
|
3523
3702
|
}
|
|
3524
3703
|
for (const [prefix, uri] of Object.entries(namespaces)) {
|
|
@@ -3544,7 +3723,7 @@ function serializeSvg(nodes, opts = {}) {
|
|
|
3544
3723
|
said.add(m);
|
|
3545
3724
|
opts.onWarn(m);
|
|
3546
3725
|
};
|
|
3547
|
-
const bodyXml = nodes.map((n) => nodeXml(n, registry, namespaces, warn)).join("");
|
|
3726
|
+
const bodyXml = nodes.map((n) => nodeXml(n, registry, namespaces, warn, opts.textLayout)).join("");
|
|
3548
3727
|
const titleXml = opts.title && opts.title.length > 0 ? `<title>${escapeText(opts.title)}</title>` : "";
|
|
3549
3728
|
const xml = `<svg ${rootAttrs.join(" ")}>${titleXml}${defsXml}${docMetaXml}${bodyXml}</svg>`;
|
|
3550
3729
|
return opts.pretty ? prettyXml(xml) : xml;
|
|
@@ -3578,16 +3757,17 @@ function registerMarkers(stroke, registry) {
|
|
|
3578
3757
|
if (ref !== void 0) registry.markerId(ref);
|
|
3579
3758
|
}
|
|
3580
3759
|
}
|
|
3581
|
-
function nodeXml(node, registry, namespaces, warn) {
|
|
3582
|
-
const xml = kindXml(node, registry, namespaces, warn);
|
|
3583
|
-
|
|
3760
|
+
function nodeXml(node, registry, namespaces, warn, layoutOf) {
|
|
3761
|
+
const xml = kindXml(node, registry, namespaces, warn, layoutOf);
|
|
3762
|
+
if (!node.hidden) return xml;
|
|
3763
|
+
return xml.replace(/^<[\w:]+/, (open) => `${open} display="none"`).replace(/<path (?=[^>]*:role="stroke-outline")/, '<path display="none" ');
|
|
3584
3764
|
}
|
|
3585
|
-
function kindXml(node, registry, namespaces, warn) {
|
|
3586
|
-
if (node.kind === "group") return groupXml(node, registry, namespaces, warn);
|
|
3587
|
-
if (node.kind === "text") return textXml(node, registry, namespaces, warn);
|
|
3765
|
+
function kindXml(node, registry, namespaces, warn, layoutOf) {
|
|
3766
|
+
if (node.kind === "group") return groupXml(node, registry, namespaces, warn, layoutOf);
|
|
3767
|
+
if (node.kind === "text") return textXml(node, registry, namespaces, warn, layoutOf?.(node));
|
|
3588
3768
|
if (node.kind === "image") return imageXml(node, namespaces);
|
|
3589
3769
|
const drawn = pathAsSvgDraws(node);
|
|
3590
|
-
return drawn.kind === "group" ? groupXml(drawn, registry, namespaces, warn) : pathXml(drawn, registry, namespaces, warn);
|
|
3770
|
+
return drawn.kind === "group" ? groupXml(drawn, registry, namespaces, warn, layoutOf) : pathXml(drawn, registry, namespaces, warn);
|
|
3591
3771
|
}
|
|
3592
3772
|
function imageXml(node, namespaces) {
|
|
3593
3773
|
const box = `x="${trimNumber(node.x)}" y="${trimNumber(node.y)}" width="${trimNumber(node.width)}" height="${trimNumber(node.height)}"`;
|
|
@@ -3611,7 +3791,7 @@ function imageXml(node, namespaces) {
|
|
|
3611
3791
|
const head = ['<g data-weasel-image="true"', ...outer].join(" ");
|
|
3612
3792
|
return `${head}${metaAttrs}><svg ${box} viewBox="${viewBox}" preserveAspectRatio="none"><image ${href} x="0" y="0" width="1" height="1" preserveAspectRatio="none"${flip}/></svg>${metaEls}</g>`;
|
|
3613
3793
|
}
|
|
3614
|
-
function groupXml(node, registry, namespaces, warn) {
|
|
3794
|
+
function groupXml(node, registry, namespaces, warn, layoutOf) {
|
|
3615
3795
|
const attrs = [];
|
|
3616
3796
|
if (node.transform) {
|
|
3617
3797
|
const m = formatMatrix(node.transform);
|
|
@@ -3625,7 +3805,7 @@ function groupXml(node, registry, namespaces, warn) {
|
|
|
3625
3805
|
}
|
|
3626
3806
|
const metaAttrs = metaAttrsXml(node.meta, namespaces);
|
|
3627
3807
|
const head = attrs.length > 0 ? `<g ${attrs.join(" ")}${metaAttrs}>` : `<g${metaAttrs}>`;
|
|
3628
|
-
const body = node.children.map((c) => nodeXml(c, registry, namespaces, warn)).join("");
|
|
3808
|
+
const body = node.children.map((c) => nodeXml(c, registry, namespaces, warn, layoutOf)).join("");
|
|
3629
3809
|
return `${head}${body}${metaElementsXml(node.meta, namespaces)}</g>`;
|
|
3630
3810
|
}
|
|
3631
3811
|
function pathXml(node, registry, namespaces, warn) {
|
|
@@ -3635,40 +3815,46 @@ function pathXml(node, registry, namespaces, warn) {
|
|
|
3635
3815
|
if (node.path.kind === "polygon" && node.path.fillRule === "evenodd") {
|
|
3636
3816
|
attrs.push(`fill-rule="evenodd"`);
|
|
3637
3817
|
}
|
|
3818
|
+
const varies = hasVariableWidth(node.stroke);
|
|
3638
3819
|
if (node.stroke) {
|
|
3639
|
-
const strokeAttrs = strokeAttrsFor(node.stroke, registry,
|
|
3640
|
-
|
|
3820
|
+
const strokeAttrs = strokeAttrsFor(node.stroke, registry, varies ? () => {
|
|
3821
|
+
} : warn);
|
|
3822
|
+
for (const a of varies ? variableWidthAttrs(node.stroke, strokeAttrs) : strokeAttrs) attrs.push(a);
|
|
3641
3823
|
} else {
|
|
3642
3824
|
attrs.push('stroke="none"');
|
|
3643
3825
|
}
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
if (
|
|
3648
|
-
const b = pathBounds(node.path);
|
|
3649
|
-
const cx = b.minX + (b.maxX - b.minX) / 2;
|
|
3650
|
-
const cy = b.minY + (b.maxY - b.minY) / 2;
|
|
3651
|
-
const deg = node.rotation * 180 / Math.PI;
|
|
3652
|
-
attrs.push(`transform="rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})"`);
|
|
3653
|
-
}
|
|
3826
|
+
const opacity = node.opacity != null && node.opacity !== 1 ? `opacity="${trimNumber(node.opacity)}"` : null;
|
|
3827
|
+
if (opacity && !varies) attrs.push(opacity);
|
|
3828
|
+
const transform = rotationAttr(node);
|
|
3829
|
+
if (transform) attrs.push(transform);
|
|
3654
3830
|
const metaAttrs = metaAttrsXml(node.meta, namespaces);
|
|
3655
3831
|
const metaEls = metaElementsXml(node.meta, namespaces);
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
return
|
|
3832
|
+
const xml = metaEls ? `<path ${attrs.join(" ")}${metaAttrs}>${metaEls}</path>` : `<path ${attrs.join(" ")}${metaAttrs}/>`;
|
|
3833
|
+
if (!varies) return xml;
|
|
3834
|
+
const both = xml + strokeOutlineXml(node.path, node.stroke, strokePaintAsFillAttrs(node.stroke, registry), transform);
|
|
3835
|
+
return opacity ? strokeGroupXml(opacity, both) : both;
|
|
3836
|
+
}
|
|
3837
|
+
function rotationAttr(node) {
|
|
3838
|
+
if (node.rotation == null || node.rotation === 0) return null;
|
|
3839
|
+
const b = pathBounds(node.path);
|
|
3840
|
+
const cx = b.minX + (b.maxX - b.minX) / 2;
|
|
3841
|
+
const cy = b.minY + (b.maxY - b.minY) / 2;
|
|
3842
|
+
const deg = node.rotation * 180 / Math.PI;
|
|
3843
|
+
return `transform="rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})"`;
|
|
3660
3844
|
}
|
|
3661
|
-
function svgNeeds(nodes) {
|
|
3845
|
+
function svgNeeds(nodes, opts = {}) {
|
|
3662
3846
|
const registry = new PaintServerRegistry();
|
|
3663
3847
|
registerPaintServers(nodes, registry);
|
|
3664
3848
|
const fonts = /* @__PURE__ */ new Map();
|
|
3849
|
+
const add = (face) => fonts.set(`${face.family}|${face.weight}|${face.style}`, face);
|
|
3665
3850
|
const walk = (list) => {
|
|
3666
3851
|
for (const n of list) {
|
|
3667
3852
|
if (n.kind === "group") walk(n.children);
|
|
3668
3853
|
else if (n.kind === "text") {
|
|
3854
|
+
if (opts.textLayout) layoutFaces(n).forEach(add);
|
|
3669
3855
|
for (const run of n.runs ?? []) {
|
|
3670
3856
|
const face = scriptSizeFace(run, n.style);
|
|
3671
|
-
if (face)
|
|
3857
|
+
if (face) add(face);
|
|
3672
3858
|
}
|
|
3673
3859
|
}
|
|
3674
3860
|
}
|
|
@@ -3676,8 +3862,15 @@ function svgNeeds(nodes) {
|
|
|
3676
3862
|
walk(nodes);
|
|
3677
3863
|
return { fonts: [...fonts.values()], paintKinds: registry.paintKinds() };
|
|
3678
3864
|
}
|
|
3679
|
-
function
|
|
3680
|
-
const
|
|
3865
|
+
function layoutFaces(node) {
|
|
3866
|
+
const style = resolveTextStyle(node.style);
|
|
3867
|
+
return toRuns(node.runs && node.runs.length > 0 ? node.runs : node.text).map((run) => {
|
|
3868
|
+
const face = resolveRunFace(run, style);
|
|
3869
|
+
return { family: face.fontFamily, weight: face.fontWeight, style: face.fontStyle };
|
|
3870
|
+
});
|
|
3871
|
+
}
|
|
3872
|
+
function warmSvg(nodes, opts = {}) {
|
|
3873
|
+
const needs = svgNeeds(nodes, opts);
|
|
3681
3874
|
return Promise.all([
|
|
3682
3875
|
warmFonts(needs.fonts),
|
|
3683
3876
|
warmPaintKinds(needs.paintKinds.filter(isPaintKindKnown))
|
|
@@ -3730,7 +3923,9 @@ function strokeDataFromSvg(stroke, box) {
|
|
|
3730
3923
|
...stroke.miterLimit !== void 0 ? { miterLimit: stroke.miterLimit } : {},
|
|
3731
3924
|
...stroke.markerStart !== void 0 ? { markerStart: stroke.markerStart } : {},
|
|
3732
3925
|
...stroke.markerMid !== void 0 ? { markerMid: stroke.markerMid } : {},
|
|
3733
|
-
...stroke.markerEnd !== void 0 ? { markerEnd: stroke.markerEnd } : {}
|
|
3926
|
+
...stroke.markerEnd !== void 0 ? { markerEnd: stroke.markerEnd } : {},
|
|
3927
|
+
...stroke.vertexWidths !== void 0 ? { vertexWidths: stroke.vertexWidths } : {},
|
|
3928
|
+
...stroke.nib !== void 0 ? { nib: stroke.nib } : {}
|
|
3734
3929
|
};
|
|
3735
3930
|
}
|
|
3736
3931
|
function fillInBoxFrame(fill, box) {
|
|
@@ -3773,9 +3968,12 @@ function svgNodesToKitDrafts(input, nextId, options = {}) {
|
|
|
3773
3968
|
...n.hidden ? { hidden: true } : {}
|
|
3774
3969
|
};
|
|
3775
3970
|
drafts.push(draft);
|
|
3971
|
+
const at = drafts.length - 1;
|
|
3776
3972
|
const acc = unionAABB(n.children.map((c) => visit(c, draft.id, k)));
|
|
3777
3973
|
if (!acc) {
|
|
3778
|
-
drafts.
|
|
3974
|
+
const kept = drafts.length > at + 1 || (options.keepEmpty?.(n) ?? false);
|
|
3975
|
+
if (!kept) drafts.splice(at, 1);
|
|
3976
|
+
else if (n.clip) draft.pose = boxOfPath(n.clip);
|
|
3779
3977
|
return null;
|
|
3780
3978
|
}
|
|
3781
3979
|
draft.pose = n.clip ? boxOfPath(n.clip) : acc;
|
|
@@ -3859,7 +4057,7 @@ async function unpackSvgFiles(files, ctx) {
|
|
|
3859
4057
|
for (const file of files) {
|
|
3860
4058
|
try {
|
|
3861
4059
|
const text = await readFileText(file);
|
|
3862
|
-
const parsed = parseSvg(text);
|
|
4060
|
+
const parsed = parseSvg(text, { keepHidden: true });
|
|
3863
4061
|
for (const w of parsed.warnings) dwarn("ingest", `svg "${file.name}":`, w);
|
|
3864
4062
|
let drafts = svgNodesToKitDrafts(parsed, () => ctx.scene.mintId());
|
|
3865
4063
|
if (drafts.length === 0) {
|
|
@@ -3904,7 +4102,8 @@ async function unpackSvgFiles(files, ctx) {
|
|
|
3904
4102
|
layer,
|
|
3905
4103
|
pose: place(d.pose),
|
|
3906
4104
|
data: d.kind === "leaf" ? scaleLeafData(d.data, scale) : d.data,
|
|
3907
|
-
parent: d.parentId
|
|
4105
|
+
parent: d.parentId,
|
|
4106
|
+
...d.hidden ? { hidden: true } : {}
|
|
3908
4107
|
},
|
|
3909
4108
|
label: "Insert SVG"
|
|
3910
4109
|
})
|
|
@@ -3939,7 +4138,9 @@ function svgStrokeFromKit(stroke, box) {
|
|
|
3939
4138
|
...stroke.align !== void 0 ? { align: stroke.align } : {},
|
|
3940
4139
|
...stroke.markerStart !== void 0 ? { markerStart: stroke.markerStart } : {},
|
|
3941
4140
|
...stroke.markerMid !== void 0 ? { markerMid: stroke.markerMid } : {},
|
|
3942
|
-
...stroke.markerEnd !== void 0 ? { markerEnd: stroke.markerEnd } : {}
|
|
4141
|
+
...stroke.markerEnd !== void 0 ? { markerEnd: stroke.markerEnd } : {},
|
|
4142
|
+
...stroke.vertexWidths?.length ? { vertexWidths: stroke.vertexWidths } : {},
|
|
4143
|
+
...stroke.nib ? { nib: stroke.nib } : {}
|
|
3943
4144
|
};
|
|
3944
4145
|
}
|
|
3945
4146
|
function svgImageFromKit(image, pose) {
|
|
@@ -3973,22 +4174,12 @@ function runInPoseFrame(run, box) {
|
|
|
3973
4174
|
function svgLeafFromKit(data, pose) {
|
|
3974
4175
|
if (data.image) return svgImageFromKit(data.image, pose);
|
|
3975
4176
|
if (data.text != null) {
|
|
3976
|
-
const
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
text: data.text
|
|
3983
|
-
};
|
|
3984
|
-
if (data.style) node2.style = data.style;
|
|
3985
|
-
if (data.runs) node2.runs = data.runs.map((r) => runInPoseFrame(r, pose));
|
|
3986
|
-
if (data.verticalAlign) node2.verticalAlign = data.verticalAlign;
|
|
3987
|
-
if (data.fill !== void 0) node2.fill = data.fill && mapFillPaint(data.fill, (p) => fillInPoseFrame(p, pose));
|
|
3988
|
-
if (data.stroke) node2.stroke = strokeInPoseFrame(data.stroke, pose);
|
|
3989
|
-
if (pose.rotation) node2.rotation = pose.rotation;
|
|
3990
|
-
if (pose.transform) node2.transform = pose.transform;
|
|
3991
|
-
return node2;
|
|
4177
|
+
const text = svgTextFromKit({ ...data, text: data.text }, pose);
|
|
4178
|
+
const boxPath = { kind: "rect", x: pose.x, y: pose.y, width: pose.width, height: pose.height };
|
|
4179
|
+
const clip = data.overflow === "clip" ? { clip: pathThroughPoseFrame(boxPath, pose) } : {};
|
|
4180
|
+
if (!data.background?.paint) return clip.clip ? { kind: "group", children: [text], ...clip } : text;
|
|
4181
|
+
const box = svgLeafFromKit({ path: boxPath, fill: data.background }, pose);
|
|
4182
|
+
return { kind: "group", children: [box, text], ...clip };
|
|
3992
4183
|
}
|
|
3993
4184
|
if (!data.path) return null;
|
|
3994
4185
|
const stroke = svgStrokeFromKit(data.stroke, pose);
|
|
@@ -4007,12 +4198,33 @@ function svgLeafFromKit(data, pose) {
|
|
|
4007
4198
|
} else if (pose.rotation) node.rotation = pose.rotation;
|
|
4008
4199
|
return node;
|
|
4009
4200
|
}
|
|
4201
|
+
function svgTextFromKit(data, pose) {
|
|
4202
|
+
const pad = Math.max(0, Math.min(data.padding ?? 0, pose.width / 2, pose.height / 2));
|
|
4203
|
+
const node = {
|
|
4204
|
+
kind: "text",
|
|
4205
|
+
x: pose.x + pad,
|
|
4206
|
+
y: pose.y + pad,
|
|
4207
|
+
width: pose.width - 2 * pad,
|
|
4208
|
+
height: pose.height - 2 * pad,
|
|
4209
|
+
text: data.text
|
|
4210
|
+
};
|
|
4211
|
+
if (data.style) node.style = data.style;
|
|
4212
|
+
if (data.runs) node.runs = data.runs.map((r) => runInPoseFrame(r, pose));
|
|
4213
|
+
if (data.verticalAlign) node.verticalAlign = data.verticalAlign;
|
|
4214
|
+
if (data.fill !== void 0) node.fill = data.fill && mapFillPaint(data.fill, (p) => fillInPoseFrame(p, pose));
|
|
4215
|
+
if (data.stroke) node.stroke = strokeInPoseFrame(data.stroke, pose);
|
|
4216
|
+
if (pose.rotation) node.rotation = pose.rotation;
|
|
4217
|
+
if (pose.transform) node.transform = pose.transform;
|
|
4218
|
+
return node;
|
|
4219
|
+
}
|
|
4010
4220
|
function svgNodesFromKit(tree, options = {}) {
|
|
4011
4221
|
const { include, leaf, group } = options;
|
|
4012
4222
|
const emit = (id) => {
|
|
4013
|
-
if (include && !include(id)) return null;
|
|
4014
4223
|
const node = tree.get(id);
|
|
4015
|
-
|
|
4224
|
+
const out2 = node && (!include || include(id)) ? lower(id, node) : null;
|
|
4225
|
+
return out2 && node?.hidden === true ? { ...out2, hidden: true } : out2;
|
|
4226
|
+
};
|
|
4227
|
+
const lower = (id, node) => {
|
|
4016
4228
|
if (node.kind === "container") {
|
|
4017
4229
|
const emitChildren = () => {
|
|
4018
4230
|
const children = [];
|
|
@@ -4045,6 +4257,6 @@ function svgNodesFromKit(tree, options = {}) {
|
|
|
4045
4257
|
return out;
|
|
4046
4258
|
}
|
|
4047
4259
|
|
|
4048
|
-
export { DEFAULT_MEDIA_ENVIRONMENT, IDENTITY_MATRIX, evaluateMediaQuery, evaluateSupports, fillDataFromSvg, nativeSvgKind, nativeSvgSpace, parseSvg, serializeSvg, strokeDataFromSvg, svgImageFromKit, svgLeafFromKit, svgNeeds, svgNodesFromKit, svgNodesToKitDrafts, svgPaintFromKit, svgStrokeFromKit, tilePreviewCssUrl, tilePreviewSvg, unpackSvgFiles, warmSvg };
|
|
4260
|
+
export { DEFAULT_MEDIA_ENVIRONMENT, IDENTITY_MATRIX, evaluateMediaQuery, evaluateSupports, fillDataFromSvg, nativeSvgKind, nativeSvgSpace, parseSvg, serializePathD, serializeSvg, strokeDataFromSvg, svgImageFromKit, svgLeafFromKit, svgNeeds, svgNodesFromKit, svgNodesToKitDrafts, svgPaintFromKit, svgStrokeFromKit, tilePreviewCssUrl, tilePreviewSvg, unpackSvgFiles, warmSvg };
|
|
4049
4261
|
//# sourceMappingURL=index.js.map
|
|
4050
4262
|
//# sourceMappingURL=index.js.map
|