@zumer/snapdom 1.9.14 → 2.0.0-dev.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 +239 -7
- package/dist/snapdom.js +634 -222
- package/dist/snapdom.min.js +7 -7
- package/dist/snapdom.min.mjs +7 -7
- package/dist/snapdom.mjs +603 -218
- package/package.json +1 -1
- package/types/snapdom.d.ts +269 -176
package/dist/snapdom.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
3
|
* snapdom
|
|
4
|
-
* v.
|
|
4
|
+
* v.2.0.0-dev.0
|
|
5
5
|
* Author Juan Martin Muda
|
|
6
6
|
* License MIT
|
|
7
7
|
**/
|
|
@@ -23,6 +23,7 @@ var cache = {
|
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
25
|
function applyCachePolicy(policy = "soft") {
|
|
26
|
+
cache.session.__counterEpoch = (cache.session.__counterEpoch || 0) + 1;
|
|
26
27
|
switch (policy) {
|
|
27
28
|
case "auto": {
|
|
28
29
|
cache.session.styleMap = /* @__PURE__ */ new Map();
|
|
@@ -808,6 +809,27 @@ function stripHeightForWrappers(el, cs, snap) {
|
|
|
808
809
|
}
|
|
809
810
|
|
|
810
811
|
// src/modules/CSSVar.js
|
|
812
|
+
var KEY_PROPS = ["fill", "stroke", "color", "background-color", "stop-color"];
|
|
813
|
+
var __BASELINE_CACHE = /* @__PURE__ */ new Map();
|
|
814
|
+
function getBaselineComputed(tagName, ns) {
|
|
815
|
+
const key = ns + "::" + tagName.toLowerCase();
|
|
816
|
+
let entry = __BASELINE_CACHE.get(key);
|
|
817
|
+
if (entry) return entry;
|
|
818
|
+
const doc = document;
|
|
819
|
+
const el = ns === "http://www.w3.org/2000/svg" ? doc.createElementNS(ns, tagName) : doc.createElement(tagName);
|
|
820
|
+
const holder = doc.createElement("div");
|
|
821
|
+
holder.style.cssText = "position:absolute;left:-99999px;top:-99999px;contain:strict;display:block;";
|
|
822
|
+
holder.appendChild(el);
|
|
823
|
+
doc.documentElement.appendChild(holder);
|
|
824
|
+
const cs = getComputedStyle(el);
|
|
825
|
+
const base = {};
|
|
826
|
+
for (const p of KEY_PROPS) {
|
|
827
|
+
base[p] = cs.getPropertyValue(p) || "";
|
|
828
|
+
}
|
|
829
|
+
holder.remove();
|
|
830
|
+
__BASELINE_CACHE.set(key, base);
|
|
831
|
+
return base;
|
|
832
|
+
}
|
|
811
833
|
function resolveCSSVars(sourceEl, cloneEl) {
|
|
812
834
|
if (!(sourceEl instanceof Element) || !(cloneEl instanceof Element)) return;
|
|
813
835
|
const styleAttr = sourceEl.getAttribute?.("style");
|
|
@@ -822,42 +844,62 @@ function resolveCSSVars(sourceEl, cloneEl) {
|
|
|
822
844
|
}
|
|
823
845
|
}
|
|
824
846
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
847
|
+
let cs = null;
|
|
848
|
+
if (hasVar) {
|
|
849
|
+
try {
|
|
850
|
+
cs = getComputedStyle(sourceEl);
|
|
851
|
+
} catch {
|
|
852
|
+
}
|
|
831
853
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
854
|
+
if (hasVar) {
|
|
855
|
+
const author = sourceEl.style;
|
|
856
|
+
if (author && author.length) {
|
|
857
|
+
for (let i = 0; i < author.length; i++) {
|
|
858
|
+
const prop = author[i];
|
|
859
|
+
const val = author.getPropertyValue(prop);
|
|
860
|
+
if (!val || !val.includes("var(")) continue;
|
|
861
|
+
const resolved = cs && cs.getPropertyValue(prop);
|
|
862
|
+
if (resolved) {
|
|
863
|
+
try {
|
|
864
|
+
cloneEl.style.setProperty(prop, resolved.trim(), author.getPropertyPriority(prop));
|
|
865
|
+
} catch {
|
|
866
|
+
}
|
|
843
867
|
}
|
|
844
868
|
}
|
|
845
869
|
}
|
|
846
870
|
}
|
|
847
|
-
if (sourceEl.attributes?.length) {
|
|
871
|
+
if (hasVar && sourceEl.attributes?.length) {
|
|
848
872
|
const attrs = sourceEl.attributes;
|
|
849
873
|
for (let i = 0; i < attrs.length; i++) {
|
|
850
874
|
const a = attrs[i];
|
|
851
875
|
if (!a || typeof a.value !== "string" || !a.value.includes("var(")) continue;
|
|
852
876
|
const propName = a.name;
|
|
853
|
-
|
|
877
|
+
const resolved = cs && cs.getPropertyValue(propName);
|
|
878
|
+
if (resolved) {
|
|
879
|
+
try {
|
|
880
|
+
cloneEl.style.setProperty(propName, resolved.trim());
|
|
881
|
+
} catch {
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
if (!hasVar) {
|
|
887
|
+
if (!cs) {
|
|
854
888
|
try {
|
|
855
|
-
|
|
889
|
+
cs = getComputedStyle(sourceEl);
|
|
856
890
|
} catch {
|
|
891
|
+
cs = null;
|
|
857
892
|
}
|
|
858
|
-
|
|
893
|
+
}
|
|
894
|
+
if (!cs) return;
|
|
895
|
+
const ns = sourceEl.namespaceURI || "html";
|
|
896
|
+
const base = getBaselineComputed(sourceEl.tagName, ns);
|
|
897
|
+
for (const prop of KEY_PROPS) {
|
|
898
|
+
const v = cs.getPropertyValue(prop) || "";
|
|
899
|
+
const b = base[prop] || "";
|
|
900
|
+
if (v && v !== b) {
|
|
859
901
|
try {
|
|
860
|
-
cloneEl.style.setProperty(
|
|
902
|
+
cloneEl.style.setProperty(prop, v.trim());
|
|
861
903
|
} catch {
|
|
862
904
|
}
|
|
863
905
|
}
|
|
@@ -1180,11 +1222,50 @@ async function deepClone(node, sessionCache, options) {
|
|
|
1180
1222
|
return clone2;
|
|
1181
1223
|
}
|
|
1182
1224
|
if (node.tagName === "CANVAS") {
|
|
1183
|
-
|
|
1225
|
+
let url = "";
|
|
1226
|
+
try {
|
|
1227
|
+
const ctx = node.getContext("2d", { willReadFrequently: true });
|
|
1228
|
+
try {
|
|
1229
|
+
ctx && ctx.getImageData(0, 0, 1, 1);
|
|
1230
|
+
} catch {
|
|
1231
|
+
}
|
|
1232
|
+
await new Promise((r) => requestAnimationFrame(r));
|
|
1233
|
+
url = node.toDataURL("image/png");
|
|
1234
|
+
if (!url || url === "data:,") {
|
|
1235
|
+
try {
|
|
1236
|
+
ctx && ctx.getImageData(0, 0, 1, 1);
|
|
1237
|
+
} catch {
|
|
1238
|
+
}
|
|
1239
|
+
await new Promise((r) => requestAnimationFrame(r));
|
|
1240
|
+
url = node.toDataURL("image/png");
|
|
1241
|
+
if (!url || url === "data:,") {
|
|
1242
|
+
const scratch = document.createElement("canvas");
|
|
1243
|
+
scratch.width = node.width;
|
|
1244
|
+
scratch.height = node.height;
|
|
1245
|
+
const sctx = scratch.getContext("2d");
|
|
1246
|
+
if (sctx) {
|
|
1247
|
+
sctx.drawImage(node, 0, 0);
|
|
1248
|
+
url = scratch.toDataURL("image/png");
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
} catch {
|
|
1253
|
+
}
|
|
1184
1254
|
const img = document.createElement("img");
|
|
1185
|
-
|
|
1255
|
+
try {
|
|
1256
|
+
img.decoding = "sync";
|
|
1257
|
+
img.loading = "eager";
|
|
1258
|
+
} catch {
|
|
1259
|
+
}
|
|
1260
|
+
if (url) img.src = url;
|
|
1186
1261
|
img.width = node.width;
|
|
1187
1262
|
img.height = node.height;
|
|
1263
|
+
try {
|
|
1264
|
+
const cs = getComputedStyle(node);
|
|
1265
|
+
if (cs.width) img.style.width = cs.width;
|
|
1266
|
+
if (cs.height) img.style.height = cs.height;
|
|
1267
|
+
} catch {
|
|
1268
|
+
}
|
|
1188
1269
|
sessionCache.nodeMap.set(img, node);
|
|
1189
1270
|
inlineAllStyles(node, img, sessionCache, options);
|
|
1190
1271
|
return img;
|
|
@@ -2176,6 +2257,8 @@ function formatCounter(value, style) {
|
|
|
2176
2257
|
}
|
|
2177
2258
|
}
|
|
2178
2259
|
function buildCounterContext(root) {
|
|
2260
|
+
const getEpoch = () => cache?.session?.__counterEpoch ?? 0;
|
|
2261
|
+
let run = getEpoch();
|
|
2179
2262
|
const nodeCounters = /* @__PURE__ */ new WeakMap();
|
|
2180
2263
|
const rootEl = root instanceof Document ? root.documentElement : root;
|
|
2181
2264
|
const isLi = (el) => el && el.tagName === "LI";
|
|
@@ -2268,6 +2351,14 @@ function buildCounterContext(root) {
|
|
|
2268
2351
|
};
|
|
2269
2352
|
const empty = /* @__PURE__ */ new Map();
|
|
2270
2353
|
build(rootEl, empty, empty);
|
|
2354
|
+
function ensureFresh() {
|
|
2355
|
+
const now = getEpoch();
|
|
2356
|
+
if (now !== run) {
|
|
2357
|
+
run = now;
|
|
2358
|
+
const empty2 = /* @__PURE__ */ new Map();
|
|
2359
|
+
build(rootEl, empty2, empty2);
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2271
2362
|
return {
|
|
2272
2363
|
/**
|
|
2273
2364
|
* Get top value for counter name at given node.
|
|
@@ -2275,6 +2366,7 @@ function buildCounterContext(root) {
|
|
|
2275
2366
|
* @param {string} name
|
|
2276
2367
|
*/
|
|
2277
2368
|
get(node, name) {
|
|
2369
|
+
ensureFresh();
|
|
2278
2370
|
const s = nodeCounters.get(node)?.get(name);
|
|
2279
2371
|
return s && s.length ? s[s.length - 1] : 0;
|
|
2280
2372
|
},
|
|
@@ -2284,6 +2376,7 @@ function buildCounterContext(root) {
|
|
|
2284
2376
|
* @param {string} name
|
|
2285
2377
|
*/
|
|
2286
2378
|
getStack(node, name) {
|
|
2379
|
+
ensureFresh();
|
|
2287
2380
|
const s = nodeCounters.get(node)?.get(name);
|
|
2288
2381
|
return s ? s.slice() : [];
|
|
2289
2382
|
}
|
|
@@ -2317,8 +2410,8 @@ function resolveCountersInContent(raw, node, ctx) {
|
|
|
2317
2410
|
}
|
|
2318
2411
|
|
|
2319
2412
|
// src/modules/pseudo.js
|
|
2320
|
-
var counterCtx = null;
|
|
2321
2413
|
var __siblingCounters = /* @__PURE__ */ new WeakMap();
|
|
2414
|
+
var __pseudoEpoch = -1;
|
|
2322
2415
|
function unquoteDoubleStrings2(s) {
|
|
2323
2416
|
return (s || "").replace(/"([^"]*)"/g, "$1");
|
|
2324
2417
|
}
|
|
@@ -2415,12 +2508,19 @@ function resolvePseudoContentAndIncs(node, pseudo, baseCtx) {
|
|
|
2415
2508
|
}
|
|
2416
2509
|
async function inlinePseudoElements(source, clone, sessionCache, options) {
|
|
2417
2510
|
if (!(source instanceof Element) || !(clone instanceof Element)) return;
|
|
2418
|
-
|
|
2511
|
+
const epoch = cache?.session?.__counterEpoch ?? 0;
|
|
2512
|
+
if (__pseudoEpoch !== epoch) {
|
|
2513
|
+
__siblingCounters = /* @__PURE__ */ new WeakMap();
|
|
2514
|
+
if (sessionCache) sessionCache.__counterCtx = null;
|
|
2515
|
+
__pseudoEpoch = epoch;
|
|
2516
|
+
}
|
|
2517
|
+
if (!sessionCache.__counterCtx) {
|
|
2419
2518
|
try {
|
|
2420
|
-
|
|
2519
|
+
sessionCache.__counterCtx = buildCounterContext(source.ownerDocument || document);
|
|
2421
2520
|
} catch {
|
|
2422
2521
|
}
|
|
2423
2522
|
}
|
|
2523
|
+
const counterCtx = sessionCache.__counterCtx;
|
|
2424
2524
|
for (const pseudo of ["::before", "::after", "::first-letter"]) {
|
|
2425
2525
|
try {
|
|
2426
2526
|
const style = getStyle(source, pseudo);
|
|
@@ -2485,7 +2585,8 @@ async function inlinePseudoElements(source, clone, sessionCache, options) {
|
|
|
2485
2585
|
}
|
|
2486
2586
|
const pseudoEl = document.createElement("span");
|
|
2487
2587
|
pseudoEl.dataset.snapdomPseudo = pseudo;
|
|
2488
|
-
pseudoEl.style.
|
|
2588
|
+
pseudoEl.style.display = "inline";
|
|
2589
|
+
pseudoEl.style.verticalAlign = "baseline";
|
|
2489
2590
|
pseudoEl.style.pointerEvents = "none";
|
|
2490
2591
|
const snapshot = snapshotComputedStyle(style);
|
|
2491
2592
|
const key = getStyleKey(snapshot, "span");
|
|
@@ -2513,9 +2614,23 @@ async function inlinePseudoElements(source, clone, sessionCache, options) {
|
|
|
2513
2614
|
} else if (!isIconFont22 && hasExplicitContent) {
|
|
2514
2615
|
pseudoEl.textContent = cleanContent;
|
|
2515
2616
|
}
|
|
2516
|
-
pseudoEl.style.
|
|
2517
|
-
if ("
|
|
2518
|
-
|
|
2617
|
+
pseudoEl.style.backgroundImage = "none";
|
|
2618
|
+
if ("maskImage" in pseudoEl.style) pseudoEl.style.maskImage = "none";
|
|
2619
|
+
if ("webkitMaskImage" in pseudoEl.style) pseudoEl.style.webkitMaskImage = "none";
|
|
2620
|
+
try {
|
|
2621
|
+
pseudoEl.style.backgroundRepeat = style.backgroundRepeat;
|
|
2622
|
+
pseudoEl.style.backgroundSize = style.backgroundSize;
|
|
2623
|
+
if (style.backgroundPositionX && style.backgroundPositionY) {
|
|
2624
|
+
pseudoEl.style.backgroundPositionX = style.backgroundPositionX;
|
|
2625
|
+
pseudoEl.style.backgroundPositionY = style.backgroundPositionY;
|
|
2626
|
+
} else {
|
|
2627
|
+
pseudoEl.style.backgroundPosition = style.backgroundPosition;
|
|
2628
|
+
}
|
|
2629
|
+
pseudoEl.style.backgroundOrigin = style.backgroundOrigin;
|
|
2630
|
+
pseudoEl.style.backgroundClip = style.backgroundClip;
|
|
2631
|
+
pseudoEl.style.backgroundAttachment = style.backgroundAttachment;
|
|
2632
|
+
pseudoEl.style.backgroundBlendMode = style.backgroundBlendMode;
|
|
2633
|
+
} catch {
|
|
2519
2634
|
}
|
|
2520
2635
|
if (hasBg) {
|
|
2521
2636
|
try {
|
|
@@ -2558,53 +2673,113 @@ async function inlinePseudoElements(source, clone, sessionCache, options) {
|
|
|
2558
2673
|
}
|
|
2559
2674
|
|
|
2560
2675
|
// src/modules/svgDefs.js
|
|
2561
|
-
function inlineExternalDefsAndSymbols(
|
|
2562
|
-
if (!
|
|
2563
|
-
const
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2676
|
+
function inlineExternalDefsAndSymbols(element, lookupRoot) {
|
|
2677
|
+
if (!element || !(element instanceof Element)) return;
|
|
2678
|
+
const doc = element.ownerDocument || document;
|
|
2679
|
+
const searchRoot = lookupRoot || doc;
|
|
2680
|
+
const svgRoots = element instanceof SVGSVGElement ? [element] : Array.from(element.querySelectorAll("svg"));
|
|
2681
|
+
if (svgRoots.length === 0) return;
|
|
2682
|
+
const URL_ID_RE = /url\(\s*#([^)]+)\)/g;
|
|
2683
|
+
const URL_ATTRS = [
|
|
2684
|
+
"fill",
|
|
2685
|
+
"stroke",
|
|
2686
|
+
"filter",
|
|
2687
|
+
"clip-path",
|
|
2688
|
+
"mask",
|
|
2689
|
+
"marker",
|
|
2690
|
+
"marker-start",
|
|
2691
|
+
"marker-mid",
|
|
2692
|
+
"marker-end"
|
|
2693
|
+
];
|
|
2694
|
+
const cssEscape = (s) => window.CSS && CSS.escape ? CSS.escape(s) : s.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
|
|
2695
|
+
const globalExistingIds = new Set(
|
|
2696
|
+
Array.from(element.querySelectorAll("[id]")).map((n) => n.id)
|
|
2697
|
+
);
|
|
2698
|
+
const neededIds = /* @__PURE__ */ new Set();
|
|
2699
|
+
let sawAnyReference = false;
|
|
2700
|
+
const addUrlIdsFromValue = (val) => {
|
|
2701
|
+
if (!val) return;
|
|
2702
|
+
URL_ID_RE.lastIndex = 0;
|
|
2703
|
+
let m;
|
|
2704
|
+
while (m = URL_ID_RE.exec(val)) {
|
|
2705
|
+
sawAnyReference = true;
|
|
2706
|
+
const id = (m[1] || "").trim();
|
|
2707
|
+
if (id && !globalExistingIds.has(id)) neededIds.add(id);
|
|
2568
2708
|
}
|
|
2569
|
-
}
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
container.setAttribute("style", "position: absolute; width: 0; height: 0; overflow: hidden;");
|
|
2579
|
-
container.classList.add("inline-defs-container");
|
|
2580
|
-
rootElement.insertBefore(container, rootElement.firstChild);
|
|
2581
|
-
}
|
|
2582
|
-
const existingIds = /* @__PURE__ */ new Set();
|
|
2583
|
-
rootElement.querySelectorAll("symbol[id], defs > *[id]").forEach((el) => {
|
|
2584
|
-
existingIds.add(el.id);
|
|
2585
|
-
});
|
|
2586
|
-
usedIds.forEach((id) => {
|
|
2587
|
-
if (existingIds.has(id)) return;
|
|
2588
|
-
const symbol = globalSymbols.find((sym) => sym.id === id);
|
|
2589
|
-
if (symbol) {
|
|
2590
|
-
container.appendChild(symbol.cloneNode(true));
|
|
2591
|
-
existingIds.add(id);
|
|
2592
|
-
return;
|
|
2709
|
+
};
|
|
2710
|
+
const collectReferencesInSvg = (rootSvg) => {
|
|
2711
|
+
const uses = rootSvg.querySelectorAll('use[href^="#"], use[xlink\\:href^="#"]');
|
|
2712
|
+
for (const u of uses) {
|
|
2713
|
+
const href = u.getAttribute("href") || u.getAttribute("xlink:href");
|
|
2714
|
+
if (!href || !href.startsWith("#")) continue;
|
|
2715
|
+
sawAnyReference = true;
|
|
2716
|
+
const id = href.slice(1).trim();
|
|
2717
|
+
if (id && !globalExistingIds.has(id)) neededIds.add(id);
|
|
2593
2718
|
}
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2719
|
+
let query = '*[style*="url("],*[fill^="url("], *[stroke^="url("],*[filter^="url("], *[clip-path^="url("],*[mask^="url("],*[marker^="url("], *[marker-start^="url("],*[marker-mid^="url("], *[marker-end^="url("]';
|
|
2720
|
+
const candidates = rootSvg.querySelectorAll(query);
|
|
2721
|
+
for (const el of candidates) {
|
|
2722
|
+
addUrlIdsFromValue(el.getAttribute("style") || "");
|
|
2723
|
+
for (const a of URL_ATTRS) addUrlIdsFromValue(el.getAttribute(a));
|
|
2724
|
+
}
|
|
2725
|
+
};
|
|
2726
|
+
for (const svg of svgRoots) collectReferencesInSvg(svg);
|
|
2727
|
+
if (!sawAnyReference) return;
|
|
2728
|
+
let defsHost = element.querySelector("svg.inline-defs-container");
|
|
2729
|
+
if (!defsHost) {
|
|
2730
|
+
defsHost = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
2731
|
+
defsHost.classList.add("inline-defs-container");
|
|
2732
|
+
defsHost.setAttribute("aria-hidden", "true");
|
|
2733
|
+
defsHost.setAttribute("style", "position:absolute;width:0;height:0;overflow:hidden");
|
|
2734
|
+
element.insertBefore(defsHost, element.firstChild || null);
|
|
2735
|
+
}
|
|
2736
|
+
let localDefs = defsHost.querySelector("defs") || null;
|
|
2737
|
+
const findGlobalById = (id) => {
|
|
2738
|
+
if (!id) return null;
|
|
2739
|
+
if (globalExistingIds.has(id)) return null;
|
|
2740
|
+
const esc = cssEscape(id);
|
|
2741
|
+
const tryFind = (sel) => {
|
|
2742
|
+
const el = searchRoot.querySelector(sel);
|
|
2743
|
+
return el && !element.contains(el) ? el : null;
|
|
2744
|
+
};
|
|
2745
|
+
return tryFind(`svg defs > *#${esc}`) || tryFind(`svg > symbol#${esc}`) || tryFind(`*#${esc}`);
|
|
2746
|
+
};
|
|
2747
|
+
if (!neededIds.size) return;
|
|
2748
|
+
const queued = new Set(neededIds);
|
|
2749
|
+
const inlined = /* @__PURE__ */ new Set();
|
|
2750
|
+
while (queued.size) {
|
|
2751
|
+
const id = queued.values().next().value;
|
|
2752
|
+
queued.delete(id);
|
|
2753
|
+
if (!id || globalExistingIds.has(id) || inlined.has(id)) continue;
|
|
2754
|
+
const source = findGlobalById(id);
|
|
2755
|
+
if (!source) {
|
|
2756
|
+
inlined.add(id);
|
|
2757
|
+
continue;
|
|
2758
|
+
}
|
|
2759
|
+
if (!localDefs) {
|
|
2760
|
+
localDefs = doc.createElementNS("http://www.w3.org/2000/svg", "defs");
|
|
2761
|
+
defsHost.appendChild(localDefs);
|
|
2762
|
+
}
|
|
2763
|
+
const clone = source.cloneNode(true);
|
|
2764
|
+
if (!clone.id) clone.setAttribute("id", id);
|
|
2765
|
+
localDefs.appendChild(clone);
|
|
2766
|
+
inlined.add(id);
|
|
2767
|
+
globalExistingIds.add(id);
|
|
2768
|
+
const walk = [clone, ...clone.querySelectorAll("*")];
|
|
2769
|
+
for (const node of walk) {
|
|
2770
|
+
const h = node.getAttribute?.("href") || node.getAttribute?.("xlink:href");
|
|
2771
|
+
if (h && h.startsWith("#")) {
|
|
2772
|
+
const ref = h.slice(1).trim();
|
|
2773
|
+
if (ref && !globalExistingIds.has(ref) && !inlined.has(ref)) queued.add(ref);
|
|
2774
|
+
}
|
|
2775
|
+
const style = node.getAttribute?.("style") || "";
|
|
2776
|
+
if (style) addUrlIdsFromValue(style);
|
|
2777
|
+
for (const a of URL_ATTRS) {
|
|
2778
|
+
const v = node.getAttribute?.(a);
|
|
2779
|
+
if (v) addUrlIdsFromValue(v);
|
|
2605
2780
|
}
|
|
2606
2781
|
}
|
|
2607
|
-
}
|
|
2782
|
+
}
|
|
2608
2783
|
}
|
|
2609
2784
|
|
|
2610
2785
|
// src/modules/changeCSS.js
|
|
@@ -3050,6 +3225,17 @@ async function inlineBackgroundImages(source, clone, styleCache, options = {}) {
|
|
|
3050
3225
|
"-webkit-mask-position-x",
|
|
3051
3226
|
"-webkit-mask-position-y"
|
|
3052
3227
|
];
|
|
3228
|
+
const BG_LAYOUT_PROPS = [
|
|
3229
|
+
"background-position",
|
|
3230
|
+
"background-position-x",
|
|
3231
|
+
"background-position-y",
|
|
3232
|
+
"background-size",
|
|
3233
|
+
"background-repeat",
|
|
3234
|
+
"background-origin",
|
|
3235
|
+
"background-clip",
|
|
3236
|
+
"background-attachment",
|
|
3237
|
+
"background-blend-mode"
|
|
3238
|
+
];
|
|
3053
3239
|
const BORDER_AUX_PROPS = [
|
|
3054
3240
|
"border-image-slice",
|
|
3055
3241
|
"border-image-width",
|
|
@@ -3065,6 +3251,11 @@ async function inlineBackgroundImages(source, clone, styleCache, options = {}) {
|
|
|
3065
3251
|
const bis = style.getPropertyValue("border-image-source");
|
|
3066
3252
|
return bi && bi !== "none" || bis && bis !== "none";
|
|
3067
3253
|
})();
|
|
3254
|
+
for (const prop of BG_LAYOUT_PROPS) {
|
|
3255
|
+
const v = style.getPropertyValue(prop);
|
|
3256
|
+
if (!v) continue;
|
|
3257
|
+
cloneNode.style.setProperty(prop, v);
|
|
3258
|
+
}
|
|
3068
3259
|
for (const prop of URL_PROPS) {
|
|
3069
3260
|
const val = style.getPropertyValue(prop);
|
|
3070
3261
|
if (!val || val === "none") continue;
|
|
@@ -3089,7 +3280,7 @@ async function inlineBackgroundImages(source, clone, styleCache, options = {}) {
|
|
|
3089
3280
|
}
|
|
3090
3281
|
}
|
|
3091
3282
|
const sChildren = Array.from(srcNode.children);
|
|
3092
|
-
const cChildren = Array.from(cloneNode.children);
|
|
3283
|
+
const cChildren = Array.from(cloneNode.children).filter((el) => !(el.dataset && el.dataset.snapdomPseudo));
|
|
3093
3284
|
for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
|
|
3094
3285
|
queue.push([sChildren[i], cChildren[i]]);
|
|
3095
3286
|
}
|
|
@@ -3153,6 +3344,81 @@ function isPlainTextContainer(el) {
|
|
|
3153
3344
|
return Array.from(el.childNodes).some((n) => n.nodeType === Node.TEXT_NODE);
|
|
3154
3345
|
}
|
|
3155
3346
|
|
|
3347
|
+
// src/core/plugins.js
|
|
3348
|
+
var __plugins = [];
|
|
3349
|
+
function normalizePlugin(spec) {
|
|
3350
|
+
if (!spec) return null;
|
|
3351
|
+
if (Array.isArray(spec)) {
|
|
3352
|
+
const [factory, options] = spec;
|
|
3353
|
+
return typeof factory === "function" ? factory(options) : factory;
|
|
3354
|
+
}
|
|
3355
|
+
if (typeof spec === "object" && "plugin" in spec) {
|
|
3356
|
+
const { plugin, options } = spec;
|
|
3357
|
+
return typeof plugin === "function" ? plugin(options) : plugin;
|
|
3358
|
+
}
|
|
3359
|
+
if (typeof spec === "function") return spec();
|
|
3360
|
+
return spec;
|
|
3361
|
+
}
|
|
3362
|
+
function registerPlugins(...defs) {
|
|
3363
|
+
const flat = defs.flat();
|
|
3364
|
+
for (const d of flat) {
|
|
3365
|
+
const inst = normalizePlugin(d);
|
|
3366
|
+
if (!inst) continue;
|
|
3367
|
+
if (!__plugins.some((p) => p && p.name && inst.name && p.name === inst.name)) {
|
|
3368
|
+
__plugins.push(inst);
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
function getContextPlugins(context) {
|
|
3373
|
+
const arr = context && Array.isArray(context.plugins) ? context.plugins : __plugins;
|
|
3374
|
+
return arr || __plugins;
|
|
3375
|
+
}
|
|
3376
|
+
async function runHook(name, context, payload) {
|
|
3377
|
+
let acc = payload;
|
|
3378
|
+
const list = getContextPlugins(context);
|
|
3379
|
+
for (const p of list) {
|
|
3380
|
+
const fn = p && typeof p[name] === "function" ? p[name] : null;
|
|
3381
|
+
if (!fn) continue;
|
|
3382
|
+
const out = await fn(context, acc);
|
|
3383
|
+
if (typeof out !== "undefined") acc = out;
|
|
3384
|
+
}
|
|
3385
|
+
return acc;
|
|
3386
|
+
}
|
|
3387
|
+
async function runAll(name, context, payload) {
|
|
3388
|
+
const outs = [];
|
|
3389
|
+
const list = getContextPlugins(context);
|
|
3390
|
+
for (const p of list) {
|
|
3391
|
+
const fn = p && typeof p[name] === "function" ? p[name] : null;
|
|
3392
|
+
if (!fn) continue;
|
|
3393
|
+
const out = await fn(context, payload);
|
|
3394
|
+
if (typeof out !== "undefined") outs.push(out);
|
|
3395
|
+
}
|
|
3396
|
+
return outs;
|
|
3397
|
+
}
|
|
3398
|
+
function mergePlugins(localDefs) {
|
|
3399
|
+
const out = [];
|
|
3400
|
+
if (Array.isArray(localDefs)) {
|
|
3401
|
+
for (const d of localDefs) {
|
|
3402
|
+
const inst = normalizePlugin(d);
|
|
3403
|
+
if (!inst || !inst.name) continue;
|
|
3404
|
+
const i = out.findIndex((x) => x && x.name === inst.name);
|
|
3405
|
+
if (i >= 0) out.splice(i, 1);
|
|
3406
|
+
out.push(inst);
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
for (const g of __plugins) {
|
|
3410
|
+
if (g && g.name && !out.some((x) => x.name === g.name)) {
|
|
3411
|
+
out.push(g);
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
return Object.freeze(out);
|
|
3415
|
+
}
|
|
3416
|
+
function attachSessionPlugins(context, localDefs, force = false) {
|
|
3417
|
+
if (!context || context.plugins && !force) return context;
|
|
3418
|
+
context.plugins = mergePlugins(localDefs);
|
|
3419
|
+
return context;
|
|
3420
|
+
}
|
|
3421
|
+
|
|
3156
3422
|
// src/core/capture.js
|
|
3157
3423
|
function stripRootShadows(originalEl, cloneRoot) {
|
|
3158
3424
|
if (!originalEl || !cloneRoot || !cloneRoot.style) return;
|
|
@@ -3182,41 +3448,46 @@ async function captureDOM(element, options) {
|
|
|
3182
3448
|
const fast = options.fast;
|
|
3183
3449
|
const straighten = !!options.straighten;
|
|
3184
3450
|
const noShadows = !!options.noShadows;
|
|
3451
|
+
let state = { element, options, plugins: options.plugins };
|
|
3185
3452
|
let clone, classCSS, styleCache;
|
|
3186
3453
|
let fontsCSS = "";
|
|
3187
3454
|
let baseCSS = "";
|
|
3188
3455
|
let dataURL;
|
|
3189
3456
|
let svgString;
|
|
3190
3457
|
let rootTransform2D = null;
|
|
3191
|
-
|
|
3458
|
+
await runHook("beforeSnap", state);
|
|
3459
|
+
await runHook("beforeClone", state);
|
|
3460
|
+
const undoClamp = lineClamp(state.element);
|
|
3192
3461
|
try {
|
|
3193
|
-
({ clone, classCSS, styleCache } = await prepareClone(element, options));
|
|
3462
|
+
({ clone, classCSS, styleCache } = await prepareClone(state.element, state.options));
|
|
3194
3463
|
if (straighten && clone) {
|
|
3195
|
-
rootTransform2D = normalizeRootTransforms(element, clone);
|
|
3464
|
+
rootTransform2D = normalizeRootTransforms(state.element, state.clone);
|
|
3196
3465
|
}
|
|
3197
3466
|
if (noShadows && clone) {
|
|
3198
|
-
stripRootShadows(element, clone);
|
|
3467
|
+
stripRootShadows(state.element, state.clone);
|
|
3199
3468
|
}
|
|
3200
3469
|
} finally {
|
|
3201
3470
|
undoClamp();
|
|
3202
3471
|
}
|
|
3472
|
+
state = { clone, classCSS, styleCache, ...state };
|
|
3473
|
+
await runHook("afterClone", state);
|
|
3203
3474
|
await new Promise((resolve) => {
|
|
3204
3475
|
idle(async () => {
|
|
3205
|
-
await inlineImages(clone, options);
|
|
3476
|
+
await inlineImages(state.clone, state.options);
|
|
3206
3477
|
resolve();
|
|
3207
3478
|
}, { fast });
|
|
3208
3479
|
});
|
|
3209
3480
|
await new Promise((resolve) => {
|
|
3210
3481
|
idle(async () => {
|
|
3211
|
-
await inlineBackgroundImages(element, clone, styleCache, options);
|
|
3482
|
+
await inlineBackgroundImages(state.element, state.clone, state.styleCache, state.options);
|
|
3212
3483
|
resolve();
|
|
3213
3484
|
}, { fast });
|
|
3214
3485
|
});
|
|
3215
3486
|
if (options.embedFonts) {
|
|
3216
3487
|
await new Promise((resolve) => {
|
|
3217
3488
|
idle(async () => {
|
|
3218
|
-
const required = collectUsedFontVariants(element);
|
|
3219
|
-
const usedCodepoints = collectUsedCodepoints(element);
|
|
3489
|
+
const required = collectUsedFontVariants(state.element);
|
|
3490
|
+
const usedCodepoints = collectUsedCodepoints(state.element);
|
|
3220
3491
|
if (isSafari()) {
|
|
3221
3492
|
const families = new Set(
|
|
3222
3493
|
Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
|
|
@@ -3227,14 +3498,14 @@ async function captureDOM(element, options) {
|
|
|
3227
3498
|
required,
|
|
3228
3499
|
usedCodepoints,
|
|
3229
3500
|
preCached: false,
|
|
3230
|
-
exclude: options.excludeFonts,
|
|
3231
|
-
useProxy: options.useProxy
|
|
3501
|
+
exclude: state.options.excludeFonts,
|
|
3502
|
+
useProxy: state.options.useProxy
|
|
3232
3503
|
});
|
|
3233
3504
|
resolve();
|
|
3234
3505
|
}, { fast });
|
|
3235
3506
|
});
|
|
3236
3507
|
}
|
|
3237
|
-
const usedTags = collectUsedTagNames(clone).sort();
|
|
3508
|
+
const usedTags = collectUsedTagNames(state.clone).sort();
|
|
3238
3509
|
const tagKey = usedTags.join(",");
|
|
3239
3510
|
if (cache.baseStyle.has(tagKey)) {
|
|
3240
3511
|
baseCSS = cache.baseStyle.get(tagKey);
|
|
@@ -3247,69 +3518,57 @@ async function captureDOM(element, options) {
|
|
|
3247
3518
|
}, { fast });
|
|
3248
3519
|
});
|
|
3249
3520
|
}
|
|
3521
|
+
state = { fontsCSS, baseCSS, ...state };
|
|
3522
|
+
await runHook("beforeRender", state);
|
|
3250
3523
|
await new Promise((resolve) => {
|
|
3251
3524
|
idle(() => {
|
|
3252
|
-
const csEl = getComputedStyle(element);
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
return { bleed: { top: 0, right: 0, bottom: 0, left: 0 }, has: false };
|
|
3257
|
-
}
|
|
3258
|
-
const tokens = raw.match(/drop-shadow\((?:[^()]|\([^()]*\))*\)/gi) || [];
|
|
3259
|
-
let t = 0, r = 0, b = 0, l = 0;
|
|
3260
|
-
let found = false;
|
|
3261
|
-
for (const tok of tokens) {
|
|
3262
|
-
found = true;
|
|
3263
|
-
const nums = tok.match(/-?\d+(?:\.\d+)?px/gi)?.map((v) => parseFloat(v)) || [];
|
|
3264
|
-
const [ox = 0, oy = 0, blur = 0] = nums;
|
|
3265
|
-
const extX = Math.abs(ox) + blur;
|
|
3266
|
-
const extY = Math.abs(oy) + blur;
|
|
3267
|
-
r = Math.max(r, extX + Math.max(ox, 0));
|
|
3268
|
-
l = Math.max(l, extX + Math.max(-ox, 0));
|
|
3269
|
-
b = Math.max(b, extY + Math.max(oy, 0));
|
|
3270
|
-
t = Math.max(t, extY + Math.max(-oy, 0));
|
|
3271
|
-
}
|
|
3272
|
-
return { bleed: { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b), left: Math.ceil(l) }, has: found };
|
|
3273
|
-
}
|
|
3274
|
-
const rect = element.getBoundingClientRect();
|
|
3275
|
-
const w0 = Math.max(1, Math.ceil(element.offsetWidth || parseFloat(csEl.width) || rect.width || 1));
|
|
3276
|
-
const h0 = Math.max(1, Math.ceil(element.offsetHeight || parseFloat(csEl.height) || rect.height || 1));
|
|
3525
|
+
const csEl = getComputedStyle(state.element);
|
|
3526
|
+
const rect = state.element.getBoundingClientRect();
|
|
3527
|
+
const w0 = Math.max(1, limitDecimals(state.element.offsetWidth || parseFloat(csEl.width) || rect.width || 1));
|
|
3528
|
+
const h0 = Math.max(1, limitDecimals(state.element.offsetHeight || parseFloat(csEl.height) || rect.height || 1));
|
|
3277
3529
|
const coerceNum = (v, def = NaN) => {
|
|
3278
3530
|
const n = typeof v === "string" ? parseFloat(v) : v;
|
|
3279
3531
|
return Number.isFinite(n) ? n : def;
|
|
3280
3532
|
};
|
|
3281
|
-
const optW = coerceNum(options.width);
|
|
3282
|
-
const optH = coerceNum(options.height);
|
|
3533
|
+
const optW = coerceNum(state.options.width);
|
|
3534
|
+
const optH = coerceNum(state.options.height);
|
|
3283
3535
|
let w = w0, h = h0;
|
|
3284
3536
|
const hasW = Number.isFinite(optW);
|
|
3285
3537
|
const hasH = Number.isFinite(optH);
|
|
3286
3538
|
const aspect0 = h0 > 0 ? w0 / h0 : 1;
|
|
3287
3539
|
if (hasW && hasH) {
|
|
3288
|
-
w = Math.max(1,
|
|
3289
|
-
h = Math.max(1,
|
|
3540
|
+
w = Math.max(1, limitDecimals(optW));
|
|
3541
|
+
h = Math.max(1, limitDecimals(optH));
|
|
3290
3542
|
} else if (hasW) {
|
|
3291
|
-
w = Math.max(1,
|
|
3292
|
-
h = Math.max(1,
|
|
3543
|
+
w = Math.max(1, limitDecimals(optW));
|
|
3544
|
+
h = Math.max(1, limitDecimals(w / (aspect0 || 1)));
|
|
3293
3545
|
} else if (hasH) {
|
|
3294
|
-
h = Math.max(1,
|
|
3295
|
-
w = Math.max(1,
|
|
3546
|
+
h = Math.max(1, limitDecimals(optH));
|
|
3547
|
+
w = Math.max(1, limitDecimals(h * (aspect0 || 1)));
|
|
3296
3548
|
} else {
|
|
3297
3549
|
w = w0;
|
|
3298
3550
|
h = h0;
|
|
3299
3551
|
}
|
|
3300
3552
|
let minX = 0, minY = 0, maxX = w0, maxY = h0;
|
|
3301
3553
|
if (straighten && rootTransform2D && Number.isFinite(rootTransform2D.a)) {
|
|
3302
|
-
const M2 = {
|
|
3554
|
+
const M2 = {
|
|
3555
|
+
a: rootTransform2D.a,
|
|
3556
|
+
b: rootTransform2D.b || 0,
|
|
3557
|
+
c: rootTransform2D.c || 0,
|
|
3558
|
+
d: rootTransform2D.d || 1,
|
|
3559
|
+
e: 0,
|
|
3560
|
+
f: 0
|
|
3561
|
+
};
|
|
3303
3562
|
const bb2 = bboxWithOriginFull(w0, h0, M2, 0, 0);
|
|
3304
|
-
minX = bb2.minX;
|
|
3305
|
-
minY = bb2.minY;
|
|
3306
|
-
maxX = bb2.maxX;
|
|
3307
|
-
maxY = bb2.maxY;
|
|
3563
|
+
minX = limitDecimals(bb2.minX);
|
|
3564
|
+
minY = limitDecimals(bb2.minY);
|
|
3565
|
+
maxX = limitDecimals(bb2.maxX);
|
|
3566
|
+
maxY = limitDecimals(bb2.maxY);
|
|
3308
3567
|
} else {
|
|
3309
|
-
const useTFBBox = !straighten && hasTFBBox(element);
|
|
3568
|
+
const useTFBBox = !straighten && hasTFBBox(state.element);
|
|
3310
3569
|
if (useTFBBox) {
|
|
3311
3570
|
const baseTransform2 = csEl.transform && csEl.transform !== "none" ? csEl.transform : "";
|
|
3312
|
-
const ind2 = readIndividualTransforms(element);
|
|
3571
|
+
const ind2 = readIndividualTransforms(state.element);
|
|
3313
3572
|
const TOTAL = readTotalTransformMatrix({
|
|
3314
3573
|
baseTransform: baseTransform2,
|
|
3315
3574
|
rotate: ind2.rotate || "0deg",
|
|
@@ -3319,10 +3578,10 @@ async function captureDOM(element, options) {
|
|
|
3319
3578
|
const { ox: ox2, oy: oy2 } = parseTransformOriginPx(csEl, w0, h0);
|
|
3320
3579
|
const M = TOTAL.is2D ? TOTAL : new DOMMatrix(TOTAL.toString());
|
|
3321
3580
|
const bb = bboxWithOriginFull(w0, h0, M, ox2, oy2);
|
|
3322
|
-
minX = bb.minX;
|
|
3323
|
-
minY = bb.minY;
|
|
3324
|
-
maxX = bb.maxX;
|
|
3325
|
-
maxY = bb.maxY;
|
|
3581
|
+
minX = limitDecimals(bb.minX);
|
|
3582
|
+
minY = limitDecimals(bb.minY);
|
|
3583
|
+
maxX = limitDecimals(bb.maxX);
|
|
3584
|
+
maxY = limitDecimals(bb.maxY);
|
|
3326
3585
|
}
|
|
3327
3586
|
}
|
|
3328
3587
|
const bleedShadow = parseBoxShadow(csEl);
|
|
@@ -3330,60 +3589,94 @@ async function captureDOM(element, options) {
|
|
|
3330
3589
|
const bleedOutline = parseOutline(csEl);
|
|
3331
3590
|
const drop = parseFilterDropShadows(csEl);
|
|
3332
3591
|
const bleed = noShadows ? { top: 0, right: 0, bottom: 0, left: 0 } : {
|
|
3333
|
-
top: bleedShadow.top + bleedBlur.top + bleedOutline.top + drop.bleed.top,
|
|
3334
|
-
right: bleedShadow.right + bleedBlur.right + bleedOutline.right + drop.bleed.right,
|
|
3335
|
-
bottom: bleedShadow.bottom + bleedBlur.bottom + bleedOutline.bottom + drop.bleed.bottom,
|
|
3336
|
-
left: bleedShadow.left + bleedBlur.left + bleedOutline.left + drop.bleed.left
|
|
3592
|
+
top: limitDecimals(bleedShadow.top + bleedBlur.top + bleedOutline.top + drop.bleed.top),
|
|
3593
|
+
right: limitDecimals(bleedShadow.right + bleedBlur.right + bleedOutline.right + drop.bleed.right),
|
|
3594
|
+
bottom: limitDecimals(bleedShadow.bottom + bleedBlur.bottom + bleedOutline.bottom + drop.bleed.bottom),
|
|
3595
|
+
left: limitDecimals(bleedShadow.left + bleedBlur.left + bleedOutline.left + drop.bleed.left)
|
|
3337
3596
|
};
|
|
3338
|
-
minX
|
|
3339
|
-
minY
|
|
3340
|
-
maxX
|
|
3341
|
-
maxY
|
|
3342
|
-
const vbW0 = Math.max(1,
|
|
3343
|
-
const vbH0 = Math.max(1,
|
|
3344
|
-
const
|
|
3345
|
-
const
|
|
3597
|
+
minX = limitDecimals(minX - bleed.left);
|
|
3598
|
+
minY = limitDecimals(minY - bleed.top);
|
|
3599
|
+
maxX = limitDecimals(maxX + bleed.right);
|
|
3600
|
+
maxY = limitDecimals(maxY + bleed.bottom);
|
|
3601
|
+
const vbW0 = Math.max(1, limitDecimals(maxX - minX));
|
|
3602
|
+
const vbH0 = Math.max(1, limitDecimals(maxY - minY));
|
|
3603
|
+
const scaleW = hasW || hasH ? limitDecimals(w / w0) : 1;
|
|
3604
|
+
const scaleH = hasH || hasW ? limitDecimals(h / h0) : 1;
|
|
3605
|
+
const outW = Math.max(1, limitDecimals(vbW0 * scaleW));
|
|
3606
|
+
const outH = Math.max(1, limitDecimals(vbH0 * scaleH));
|
|
3346
3607
|
const svgNS = "http://www.w3.org/2000/svg";
|
|
3347
3608
|
const basePad = isSafari() ? 1 : 0;
|
|
3348
3609
|
const extraPad = straighten ? 1 : 0;
|
|
3349
|
-
const pad = basePad + extraPad;
|
|
3610
|
+
const pad = limitDecimals(basePad + extraPad);
|
|
3350
3611
|
const fo = document.createElementNS(svgNS, "foreignObject");
|
|
3351
|
-
const vbMinX =
|
|
3352
|
-
const vbMinY =
|
|
3353
|
-
fo.setAttribute("x", String(-(vbMinX - pad)));
|
|
3354
|
-
fo.setAttribute("y", String(-(vbMinY - pad)));
|
|
3355
|
-
fo.setAttribute("width", String(
|
|
3356
|
-
fo.setAttribute("height", String(
|
|
3612
|
+
const vbMinX = limitDecimals(minX);
|
|
3613
|
+
const vbMinY = limitDecimals(minY);
|
|
3614
|
+
fo.setAttribute("x", String(limitDecimals(-(vbMinX - pad))));
|
|
3615
|
+
fo.setAttribute("y", String(limitDecimals(-(vbMinY - pad))));
|
|
3616
|
+
fo.setAttribute("width", String(limitDecimals(w0 + pad * 2)));
|
|
3617
|
+
fo.setAttribute("height", String(limitDecimals(h0 + pad * 2)));
|
|
3357
3618
|
fo.style.overflow = "visible";
|
|
3358
3619
|
const styleTag = document.createElement("style");
|
|
3359
|
-
styleTag.textContent = baseCSS + fontsCSS + "svg{overflow:visible;} foreignObject{overflow:visible;}" + classCSS;
|
|
3620
|
+
styleTag.textContent = state.baseCSS + state.fontsCSS + "svg{overflow:visible;} foreignObject{overflow:visible;}" + state.classCSS;
|
|
3360
3621
|
fo.appendChild(styleTag);
|
|
3361
3622
|
const container = document.createElement("div");
|
|
3362
3623
|
container.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
|
|
3363
|
-
container.style.width = `${w0}px`;
|
|
3364
|
-
container.style.height = `${h0}px`;
|
|
3624
|
+
container.style.width = `${limitDecimals(w0)}px`;
|
|
3625
|
+
container.style.height = `${limitDecimals(h0)}px`;
|
|
3365
3626
|
container.style.overflow = "visible";
|
|
3366
|
-
clone.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
|
|
3367
|
-
container.appendChild(clone);
|
|
3627
|
+
state.clone.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
|
|
3628
|
+
container.appendChild(state.clone);
|
|
3368
3629
|
fo.appendChild(container);
|
|
3369
3630
|
const serializer = new XMLSerializer();
|
|
3370
3631
|
const foString = serializer.serializeToString(fo);
|
|
3371
|
-
const vbW = vbW0 + pad * 2;
|
|
3372
|
-
const vbH = vbH0 + pad * 2;
|
|
3632
|
+
const vbW = limitDecimals(vbW0 + pad * 2);
|
|
3633
|
+
const vbH = limitDecimals(vbH0 + pad * 2);
|
|
3373
3634
|
const wantsSize = hasW || hasH;
|
|
3374
3635
|
options.meta = { w0, h0, vbW, vbH, targetW: w, targetH: h };
|
|
3375
|
-
const svgOutW = isSafari() && wantsSize ? vbW : outW + pad * 2;
|
|
3376
|
-
const svgOutH = isSafari() && wantsSize ? vbH : outH + pad * 2;
|
|
3636
|
+
const svgOutW = isSafari() && wantsSize ? vbW : limitDecimals(outW + pad * 2);
|
|
3637
|
+
const svgOutH = isSafari() && wantsSize ? vbH : limitDecimals(outH + pad * 2);
|
|
3377
3638
|
const svgHeader = `<svg xmlns="${svgNS}" width="${svgOutW}" height="${svgOutH}" viewBox="0 0 ${vbW} ${vbH}">`;
|
|
3378
3639
|
const svgFooter = "</svg>";
|
|
3379
3640
|
svgString = svgHeader + foString + svgFooter;
|
|
3380
3641
|
dataURL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;
|
|
3642
|
+
state = { svgString, dataURL, ...state };
|
|
3381
3643
|
resolve();
|
|
3382
3644
|
}, { fast });
|
|
3383
3645
|
});
|
|
3646
|
+
await runHook("afterRender", state);
|
|
3384
3647
|
const sandbox = document.getElementById("snapdom-sandbox");
|
|
3385
3648
|
if (sandbox && sandbox.style.position === "absolute") sandbox.remove();
|
|
3386
|
-
return dataURL;
|
|
3649
|
+
return state.dataURL;
|
|
3650
|
+
}
|
|
3651
|
+
var limitDecimals = (v, n = 3) => Number.isFinite(v) ? Math.round(v * 10 ** n) / 10 ** n : v;
|
|
3652
|
+
function parseFilterDropShadows(cs) {
|
|
3653
|
+
const raw = `${cs.filter || ""} ${cs.webkitFilter || ""}`.trim();
|
|
3654
|
+
if (!raw || raw === "none") {
|
|
3655
|
+
return { bleed: { top: 0, right: 0, bottom: 0, left: 0 }, has: false };
|
|
3656
|
+
}
|
|
3657
|
+
const tokens = raw.match(/drop-shadow\((?:[^()]|\([^()]*\))*\)/gi) || [];
|
|
3658
|
+
let t = 0, r = 0, b = 0, l = 0;
|
|
3659
|
+
let found = false;
|
|
3660
|
+
for (const tok of tokens) {
|
|
3661
|
+
found = true;
|
|
3662
|
+
const nums = tok.match(/-?\d+(?:\.\d+)?px/gi)?.map((v) => parseFloat(v)) || [];
|
|
3663
|
+
const [ox = 0, oy = 0, blur = 0] = nums;
|
|
3664
|
+
const extX = Math.abs(ox) + blur;
|
|
3665
|
+
const extY = Math.abs(oy) + blur;
|
|
3666
|
+
r = Math.max(r, extX + Math.max(ox, 0));
|
|
3667
|
+
l = Math.max(l, extX + Math.max(-ox, 0));
|
|
3668
|
+
b = Math.max(b, extY + Math.max(oy, 0));
|
|
3669
|
+
t = Math.max(t, extY + Math.max(-oy, 0));
|
|
3670
|
+
}
|
|
3671
|
+
return {
|
|
3672
|
+
bleed: {
|
|
3673
|
+
top: limitDecimals(t),
|
|
3674
|
+
right: limitDecimals(r),
|
|
3675
|
+
bottom: limitDecimals(b),
|
|
3676
|
+
left: limitDecimals(l)
|
|
3677
|
+
},
|
|
3678
|
+
has: found
|
|
3679
|
+
};
|
|
3387
3680
|
}
|
|
3388
3681
|
function normalizeRootTransforms(originalEl, cloneRoot) {
|
|
3389
3682
|
if (!originalEl || !cloneRoot || !cloneRoot.style) return null;
|
|
@@ -3634,7 +3927,8 @@ function normalizeCachePolicy(v) {
|
|
|
3634
3927
|
return "soft";
|
|
3635
3928
|
}
|
|
3636
3929
|
function createContext(options = {}) {
|
|
3637
|
-
|
|
3930
|
+
let resolvedFormat = options.format ?? "png";
|
|
3931
|
+
if (resolvedFormat === "jpg") resolvedFormat = "jpeg";
|
|
3638
3932
|
const cachePolicy = normalizeCachePolicy(options.cache);
|
|
3639
3933
|
return {
|
|
3640
3934
|
// Debug & perf
|
|
@@ -3666,7 +3960,7 @@ function createContext(options = {}) {
|
|
|
3666
3960
|
type: options.type ?? "svg",
|
|
3667
3961
|
quality: options.quality ?? 0.92,
|
|
3668
3962
|
dpr: options.dpr ?? (window.devicePixelRatio || 1),
|
|
3669
|
-
backgroundColor: options.backgroundColor ?? (["
|
|
3963
|
+
backgroundColor: options.backgroundColor ?? (["jpeg", "webp"].includes(resolvedFormat) ? "#ffffff" : null),
|
|
3670
3964
|
filename: options.filename ?? "snapDOM",
|
|
3671
3965
|
// NEW flags (user-friendly)
|
|
3672
3966
|
straighten: options.straighten ?? false,
|
|
@@ -3797,20 +4091,20 @@ async function toCanvas(url, options) {
|
|
|
3797
4091
|
} else if (hasW) {
|
|
3798
4092
|
const k = optW / Math.max(1, refW);
|
|
3799
4093
|
outW = optW;
|
|
3800
|
-
outH =
|
|
4094
|
+
outH = refH * k;
|
|
3801
4095
|
} else if (hasH) {
|
|
3802
4096
|
const k = optH / Math.max(1, refH);
|
|
3803
4097
|
outH = optH;
|
|
3804
|
-
outW =
|
|
4098
|
+
outW = refW * k;
|
|
3805
4099
|
} else {
|
|
3806
4100
|
outW = natW;
|
|
3807
4101
|
outH = natH;
|
|
3808
4102
|
}
|
|
3809
|
-
outW =
|
|
3810
|
-
outH =
|
|
4103
|
+
outW = outW * scale;
|
|
4104
|
+
outH = outH * scale;
|
|
3811
4105
|
const canvas = document.createElement("canvas");
|
|
3812
|
-
canvas.width =
|
|
3813
|
-
canvas.height =
|
|
4106
|
+
canvas.width = outW * dpr;
|
|
4107
|
+
canvas.height = outH * dpr;
|
|
3814
4108
|
canvas.style.width = `${outW}px`;
|
|
3815
4109
|
canvas.style.height = `${outH}px`;
|
|
3816
4110
|
const ctx = canvas.getContext("2d");
|
|
@@ -3919,16 +4213,22 @@ async function download(url, options) {
|
|
|
3919
4213
|
}
|
|
3920
4214
|
|
|
3921
4215
|
// src/api/snapdom.js
|
|
4216
|
+
snapdom.plugins = (...defs) => {
|
|
4217
|
+
registerPlugins(...defs);
|
|
4218
|
+
return snapdom;
|
|
4219
|
+
};
|
|
3922
4220
|
var INTERNAL_TOKEN = Symbol("snapdom.internal");
|
|
4221
|
+
var INTERNAL_EXPORT_TOKEN = Symbol("snapdom.internal.silent");
|
|
3923
4222
|
var _safariWarmup = false;
|
|
3924
4223
|
async function snapdom(element, userOptions) {
|
|
3925
4224
|
if (!element) throw new Error("Element cannot be null or undefined");
|
|
3926
4225
|
const context = createContext(userOptions);
|
|
4226
|
+
attachSessionPlugins(context, userOptions && userOptions.plugins);
|
|
3927
4227
|
if (isSafari() && (context.embedFonts === true || hasBackgroundOrMask(element))) {
|
|
3928
4228
|
for (let i = 0; i < 3; i++) {
|
|
3929
4229
|
try {
|
|
3930
4230
|
await safariWarmup(element, userOptions);
|
|
3931
|
-
console.log("
|
|
4231
|
+
console.log("safariWarmup:", i);
|
|
3932
4232
|
_safariWarmup = false;
|
|
3933
4233
|
} catch {
|
|
3934
4234
|
}
|
|
@@ -3943,31 +4243,90 @@ async function snapdom(element, userOptions) {
|
|
|
3943
4243
|
}
|
|
3944
4244
|
return snapdom.capture(element, context, INTERNAL_TOKEN);
|
|
3945
4245
|
}
|
|
4246
|
+
snapdom.plugins = (...defs) => {
|
|
4247
|
+
registerPlugins(...defs);
|
|
4248
|
+
return snapdom;
|
|
4249
|
+
};
|
|
3946
4250
|
snapdom.capture = async (el, context, _token) => {
|
|
3947
4251
|
if (_token !== INTERNAL_TOKEN) throw new Error("[snapdom.capture] is internal. Use snapdom(...) instead.");
|
|
3948
4252
|
const url = await captureDOM(el, context);
|
|
3949
|
-
const
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
}
|
|
3957
|
-
|
|
4253
|
+
const coreExports = {
|
|
4254
|
+
img: async (ctx, opts) => toImg(url, { ...ctx, ...opts || {} }),
|
|
4255
|
+
svg: async (ctx, opts) => toImg(url, { ...ctx, ...opts || {} }),
|
|
4256
|
+
canvas: async (ctx, opts) => toCanvas(url, { ...ctx, ...opts || {} }),
|
|
4257
|
+
blob: async (ctx, opts) => toBlob(url, { ...ctx, ...opts || {} }),
|
|
4258
|
+
png: async (ctx, opts) => rasterize(url, { ...ctx, ...opts || {}, format: "png" }),
|
|
4259
|
+
jpeg: async (ctx, opts) => rasterize(url, { ...ctx, ...opts || {}, format: "jpeg" }),
|
|
4260
|
+
webp: async (ctx, opts) => rasterize(url, { ...ctx, ...opts || {}, format: "webp" }),
|
|
4261
|
+
download: async (ctx, opts) => download(url, { ...ctx, ...opts || {} })
|
|
3958
4262
|
};
|
|
3959
|
-
|
|
4263
|
+
const _pluginExports = {
|
|
4264
|
+
svg: (opts) => toImg(url, { ...context, ...opts || {}, [INTERNAL_EXPORT_TOKEN]: true }),
|
|
4265
|
+
canvas: (opts) => toCanvas(url, { ...context, ...opts || {}, [INTERNAL_EXPORT_TOKEN]: true }),
|
|
4266
|
+
png: (opts) => rasterize(url, { ...context, ...opts || {}, format: "png", [INTERNAL_EXPORT_TOKEN]: true }),
|
|
4267
|
+
jpeg: (opts) => rasterize(url, { ...context, ...opts || {}, format: "jpeg", [INTERNAL_EXPORT_TOKEN]: true }),
|
|
4268
|
+
jpg: (opts) => rasterize(url, { ...context, ...opts || {}, format: "jpeg", [INTERNAL_EXPORT_TOKEN]: true }),
|
|
4269
|
+
webp: (opts) => rasterize(url, { ...context, ...opts || {}, format: "webp", [INTERNAL_EXPORT_TOKEN]: true }),
|
|
4270
|
+
blob: (opts) => toBlob(url, { ...context, ...opts || {}, [INTERNAL_EXPORT_TOKEN]: true }),
|
|
4271
|
+
img: (opts) => toImg(url, { ...context, ...opts || {}, [INTERNAL_EXPORT_TOKEN]: true })
|
|
4272
|
+
};
|
|
4273
|
+
const _defineCtx = { ...context, export: { url }, exports: _pluginExports };
|
|
4274
|
+
const providedMaps = await runAll("defineExports", _defineCtx);
|
|
4275
|
+
const provided = Object.assign({}, ...providedMaps.filter((x) => x && typeof x === "object"));
|
|
4276
|
+
const exportsMap = { ...coreExports, ...provided };
|
|
4277
|
+
if (exportsMap.jpeg && !exportsMap.jpg) {
|
|
4278
|
+
exportsMap.jpg = (ctx, opts) => exportsMap.jpeg(ctx, opts);
|
|
4279
|
+
}
|
|
4280
|
+
function normalizeExportOptions(type, opts) {
|
|
4281
|
+
const next = { ...context, ...opts || {} };
|
|
4282
|
+
if (type === "jpeg" || type === "jpg") {
|
|
4283
|
+
const noBg = next.backgroundColor == null || next.backgroundColor === "transparent";
|
|
4284
|
+
if (noBg) next.backgroundColor = "#ffffff";
|
|
4285
|
+
}
|
|
4286
|
+
return next;
|
|
4287
|
+
}
|
|
4288
|
+
let afterSnapFired = false;
|
|
4289
|
+
let _exportQueue = Promise.resolve();
|
|
4290
|
+
async function runExport(type, opts) {
|
|
4291
|
+
const job = async () => {
|
|
4292
|
+
const work = exportsMap[type];
|
|
4293
|
+
if (!work) throw new Error(`[snapdom] Unknown export type: ${type}`);
|
|
4294
|
+
const nextOpts = normalizeExportOptions(type, opts);
|
|
4295
|
+
const ctx = { ...context, export: { type, options: nextOpts, url } };
|
|
4296
|
+
await runHook("beforeExport", ctx);
|
|
4297
|
+
const result2 = await work(ctx, nextOpts);
|
|
4298
|
+
await runHook("afterExport", ctx, result2);
|
|
4299
|
+
if (!afterSnapFired) {
|
|
4300
|
+
afterSnapFired = true;
|
|
4301
|
+
await runHook("afterSnap", context);
|
|
4302
|
+
}
|
|
4303
|
+
return result2;
|
|
4304
|
+
};
|
|
4305
|
+
return _exportQueue = _exportQueue.then(job);
|
|
4306
|
+
}
|
|
4307
|
+
const result = {
|
|
3960
4308
|
url,
|
|
3961
4309
|
toRaw: () => url,
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
4310
|
+
to: (type, opts) => runExport(type, opts),
|
|
4311
|
+
// Métodos “clásicos” que los tests esperan:
|
|
4312
|
+
toImg: (opts) => runExport("img", opts),
|
|
4313
|
+
toSvg: (opts) => runExport("svg", opts),
|
|
4314
|
+
toCanvas: (opts) => runExport("canvas", opts),
|
|
4315
|
+
toBlob: (opts) => runExport("blob", opts),
|
|
4316
|
+
toPng: (opts) => runExport("png", opts),
|
|
4317
|
+
toJpg: (opts) => runExport("jpg", opts),
|
|
4318
|
+
// ← alias requerido por los tests
|
|
4319
|
+
toWebp: (opts) => runExport("webp", opts),
|
|
4320
|
+
download: (opts) => runExport("download", opts)
|
|
4321
|
+
// ← método directo (no toDownload)
|
|
3970
4322
|
};
|
|
4323
|
+
for (const key of Object.keys(exportsMap)) {
|
|
4324
|
+
const helper = "to" + key.charAt(0).toUpperCase() + key.slice(1);
|
|
4325
|
+
if (!result[helper]) {
|
|
4326
|
+
result[helper] = (opts) => runExport(key, opts);
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
return result;
|
|
3971
4330
|
};
|
|
3972
4331
|
snapdom.toRaw = (el, options) => snapdom(el, options).then((result) => result.toRaw());
|
|
3973
4332
|
snapdom.toImg = (el, options) => snapdom(el, options).then((result) => result.toImg());
|
|
@@ -3990,30 +4349,47 @@ async function safariWarmup(element, baseOptions) {
|
|
|
3990
4349
|
try {
|
|
3991
4350
|
url = await captureDOM(element, preflight);
|
|
3992
4351
|
} catch {
|
|
3993
|
-
return;
|
|
3994
4352
|
}
|
|
3995
|
-
await new Promise((
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4353
|
+
await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
|
|
4354
|
+
if (url) {
|
|
4355
|
+
await new Promise((resolve) => {
|
|
4356
|
+
const img = new Image();
|
|
4357
|
+
try {
|
|
4358
|
+
img.decoding = "sync";
|
|
4359
|
+
img.loading = "eager";
|
|
4360
|
+
} catch {
|
|
4361
|
+
}
|
|
4362
|
+
img.style.cssText = "position:fixed;left:0px;top:0px;width:10px;height:10px;opacity:0.01;pointer-events:none;";
|
|
4363
|
+
img.src = url;
|
|
4364
|
+
document.body.appendChild(img);
|
|
4365
|
+
(async () => {
|
|
4366
|
+
try {
|
|
4367
|
+
if (typeof img.decode === "function") await img.decode();
|
|
4368
|
+
} catch {
|
|
4369
|
+
}
|
|
4370
|
+
const start = performance.now();
|
|
4371
|
+
while (!(img.complete && img.naturalWidth > 0) && performance.now() - start < 900) {
|
|
4372
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
4373
|
+
}
|
|
4374
|
+
await new Promise((r) => requestAnimationFrame(r));
|
|
4375
|
+
try {
|
|
4376
|
+
img.remove();
|
|
4377
|
+
} catch {
|
|
4378
|
+
}
|
|
4379
|
+
resolve();
|
|
4380
|
+
})();
|
|
4381
|
+
});
|
|
4382
|
+
}
|
|
4383
|
+
element.querySelectorAll("canvas").forEach((c) => {
|
|
4384
|
+
try {
|
|
4385
|
+
const ctx = c.getContext("2d", { willReadFrequently: true });
|
|
4386
|
+
if (ctx) {
|
|
4387
|
+
ctx.getImageData(0, 0, 1, 1);
|
|
4388
|
+
}
|
|
4389
|
+
} catch {
|
|
4390
|
+
}
|
|
4016
4391
|
});
|
|
4392
|
+
_safariWarmup = true;
|
|
4017
4393
|
}
|
|
4018
4394
|
function hasBackgroundOrMask(el) {
|
|
4019
4395
|
const walker = document.createTreeWalker(el, NodeFilter.SHOW_ELEMENT);
|
|
@@ -4026,6 +4402,7 @@ function hasBackgroundOrMask(el) {
|
|
|
4026
4402
|
const bg = cs.backgroundImage && cs.backgroundImage !== "none";
|
|
4027
4403
|
const mask = cs.maskImage && cs.maskImage !== "none" || cs.webkitMaskImage && cs.webkitMaskImage !== "none";
|
|
4028
4404
|
if (bg || mask) return true;
|
|
4405
|
+
if (node.tagName === "CANVAS") return true;
|
|
4029
4406
|
}
|
|
4030
4407
|
return false;
|
|
4031
4408
|
}
|
|
@@ -4051,6 +4428,7 @@ async function preCache(root = document, options = {}) {
|
|
|
4051
4428
|
cache.session.styleCache = /* @__PURE__ */ new WeakMap();
|
|
4052
4429
|
}
|
|
4053
4430
|
cache.image = cache.image || /* @__PURE__ */ new Map();
|
|
4431
|
+
cache.background = cache.background || /* @__PURE__ */ new Map();
|
|
4054
4432
|
try {
|
|
4055
4433
|
await inlineBackgroundImages(
|
|
4056
4434
|
root,
|
|
@@ -4063,7 +4441,13 @@ async function preCache(root = document, options = {}) {
|
|
|
4063
4441
|
}
|
|
4064
4442
|
let imgEls = [], allEls = [];
|
|
4065
4443
|
try {
|
|
4066
|
-
if (root
|
|
4444
|
+
if (root && root.nodeType === 1) {
|
|
4445
|
+
const descendants = root.querySelectorAll ? Array.from(root.querySelectorAll("*")) : [];
|
|
4446
|
+
allEls = [root, ...descendants];
|
|
4447
|
+
imgEls = [];
|
|
4448
|
+
if (root.tagName === "IMG" && root.getAttribute("src")) imgEls.push(root);
|
|
4449
|
+
imgEls.push(...Array.from(root.querySelectorAll?.("img[src]") || []));
|
|
4450
|
+
} else if (root?.querySelectorAll) {
|
|
4067
4451
|
imgEls = Array.from(root.querySelectorAll("img[src]"));
|
|
4068
4452
|
allEls = Array.from(root.querySelectorAll("*"));
|
|
4069
4453
|
}
|
|
@@ -4087,17 +4471,18 @@ async function preCache(root = document, options = {}) {
|
|
|
4087
4471
|
for (const el of allEls) {
|
|
4088
4472
|
let bg = "";
|
|
4089
4473
|
try {
|
|
4090
|
-
bg =
|
|
4474
|
+
bg = el?.style?.backgroundImage || "";
|
|
4475
|
+
if (!bg || bg === "none") {
|
|
4476
|
+
bg = getStyle(el).backgroundImage;
|
|
4477
|
+
}
|
|
4091
4478
|
} catch {
|
|
4092
4479
|
}
|
|
4093
4480
|
if (bg && bg !== "none") {
|
|
4094
|
-
const
|
|
4095
|
-
for (const entry of
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
promises.push(p);
|
|
4100
|
-
}
|
|
4481
|
+
const urlEntries = bg.match(/url\((?:[^()"']+|"(?:[^"]*)"|'(?:[^']*)')\)/gi) || [];
|
|
4482
|
+
for (const entry of urlEntries) {
|
|
4483
|
+
const p = Promise.resolve().then(() => inlineSingleBackgroundEntry(entry, { ...options, useProxy })).catch(() => {
|
|
4484
|
+
});
|
|
4485
|
+
promises.push(p);
|
|
4101
4486
|
}
|
|
4102
4487
|
}
|
|
4103
4488
|
}
|