@zumer/snapdom 1.9.12-dev.3 → 1.9.13

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/snapdom.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.1.9.12-dev.3
4
+ * v.1.9.12-dev.4
5
5
  * Author Juan Martin Muda
6
6
  * License MIT
7
7
  **/
@@ -664,8 +664,9 @@
664
664
  function isSafari() {
665
665
  const ua = typeof navigator !== "undefined" && navigator.userAgent ? navigator.userAgent : "";
666
666
  const isSafariUA = /^((?!chrome|android).)*safari/i.test(ua);
667
+ const isUIWebView = /AppleWebKit/i.test(ua) && /Mobile/i.test(ua) && !/Safari/i.test(ua);
667
668
  const isWeChatUA = /(MicroMessenger|wxwork|WeCom|WindowsWechat|MacWechat)/i.test(ua);
668
- return isSafariUA || isWeChatUA;
669
+ return isSafariUA || isUIWebView || isWeChatUA;
669
670
  }
670
671
 
671
672
  // src/modules/styles.js
@@ -857,6 +858,65 @@
857
858
  delete snap["block-size"];
858
859
  }
859
860
 
861
+ // src/modules/CSSVar.js
862
+ function resolveCSSVars(sourceEl, cloneEl) {
863
+ var _a, _b, _c;
864
+ if (!(sourceEl instanceof Element) || !(cloneEl instanceof Element)) return;
865
+ const styleAttr = (_a = sourceEl.getAttribute) == null ? void 0 : _a.call(sourceEl, "style");
866
+ let hasVar = !!(styleAttr && styleAttr.includes("var("));
867
+ if (!hasVar && ((_b = sourceEl.attributes) == null ? void 0 : _b.length)) {
868
+ const attrs = sourceEl.attributes;
869
+ for (let i = 0; i < attrs.length; i++) {
870
+ const a = attrs[i];
871
+ if (a && typeof a.value === "string" && a.value.includes("var(")) {
872
+ hasVar = true;
873
+ break;
874
+ }
875
+ }
876
+ }
877
+ if (!hasVar) return;
878
+ let cs;
879
+ try {
880
+ cs = getComputedStyle(sourceEl);
881
+ } catch (e) {
882
+ return;
883
+ }
884
+ const author = sourceEl.style;
885
+ if (author && author.length) {
886
+ for (let i = 0; i < author.length; i++) {
887
+ const prop = author[i];
888
+ const val = author.getPropertyValue(prop);
889
+ if (!val || !val.includes("var(")) continue;
890
+ const resolved = cs.getPropertyValue(prop);
891
+ if (resolved) {
892
+ try {
893
+ cloneEl.style.setProperty(prop, resolved.trim(), author.getPropertyPriority(prop));
894
+ } catch (e) {
895
+ }
896
+ }
897
+ }
898
+ }
899
+ if ((_c = sourceEl.attributes) == null ? void 0 : _c.length) {
900
+ const attrs = sourceEl.attributes;
901
+ for (let i = 0; i < attrs.length; i++) {
902
+ const a = attrs[i];
903
+ if (!a || typeof a.value !== "string" || !a.value.includes("var(")) continue;
904
+ const propName = a.name;
905
+ let resolved = "";
906
+ try {
907
+ resolved = cs.getPropertyValue(propName);
908
+ } catch (e) {
909
+ }
910
+ if (resolved) {
911
+ try {
912
+ cloneEl.style.setProperty(propName, resolved.trim());
913
+ } catch (e) {
914
+ }
915
+ }
916
+ }
917
+ }
918
+ }
919
+
860
920
  // src/core/clone.js
861
921
  function idleCallback(childList, callback, fast) {
862
922
  return Promise.all(childList.map((child) => {
@@ -878,7 +938,7 @@
878
938
  function addNotSlottedRightmost(sel) {
879
939
  sel = sel.trim();
880
940
  if (!sel) return sel;
881
- if (/\:not\(\s*\[data-sd-slotted\]\s*\)\s*$/.test(sel)) return sel;
941
+ if (/:not\(\s*\[data-sd-slotted\]\s*\)\s*$/.test(sel)) return sel;
882
942
  return `${sel}:not([data-sd-slotted])`;
883
943
  }
884
944
  function wrapWithScope(selectorList, scopeSelector, excludeSlotted = true) {
@@ -1174,7 +1234,7 @@
1174
1234
  inlineAllStyles(node, clone2, sessionCache, options);
1175
1235
  const placeholder = document.createElement("div");
1176
1236
  placeholder.textContent = node.getAttribute("data-placeholder-text") || "";
1177
- placeholder.style.cssText = `color:#666;font-size:12px;text-align:center;line-height:1.4;padding:0.5em;box-sizing:border-box;`;
1237
+ placeholder.style.cssText = "color:#666;font-size:12px;text-align:center;line-height:1.4;padding:0.5em;box-sizing:border-box;";
1178
1238
  clone2.appendChild(placeholder);
1179
1239
  return clone2;
1180
1240
  }
@@ -1191,6 +1251,7 @@
1191
1251
  let clone;
1192
1252
  try {
1193
1253
  clone = node.cloneNode(false);
1254
+ resolveCSSVars(node, clone);
1194
1255
  sessionCache.nodeMap.set(clone, node);
1195
1256
  if (node.tagName === "IMG") {
1196
1257
  freezeImgSrcset(node, clone);
@@ -1246,7 +1307,7 @@
1246
1307
  } else {
1247
1308
  deepClone(child, sessionCache, options).then((clonedChild) => {
1248
1309
  resolve(clonedChild || null);
1249
- }).catch((e) => {
1310
+ }).catch(() => {
1250
1311
  resolve(null);
1251
1312
  });
1252
1313
  }
@@ -1287,7 +1348,7 @@
1287
1348
  markSlottedSubtree(clonedChild);
1288
1349
  }
1289
1350
  resolve(clonedChild || null);
1290
- }).catch((e) => {
1351
+ }).catch(() => {
1291
1352
  resolve(null);
1292
1353
  });
1293
1354
  };
@@ -1302,7 +1363,7 @@
1302
1363
  if (clonedAssignedNodes.has(child)) return resolve(null);
1303
1364
  deepClone(child, sessionCache, options).then((clonedChild) => {
1304
1365
  resolve(clonedChild || null);
1305
- }).catch((e) => {
1366
+ }).catch(() => {
1306
1367
  resolve(null);
1307
1368
  });
1308
1369
  }
@@ -1367,7 +1428,10 @@
1367
1428
  return __async(this, null, function* () {
1368
1429
  fontFamily = fontFamily.replace(/^['"]+|['"]+$/g, "");
1369
1430
  const dpr = window.devicePixelRatio || 1;
1370
- yield document.fonts.ready;
1431
+ try {
1432
+ yield document.fonts.ready;
1433
+ } catch (e) {
1434
+ }
1371
1435
  const span = document.createElement("span");
1372
1436
  span.textContent = unicodeChar;
1373
1437
  span.style.position = "absolute";
@@ -1385,8 +1449,8 @@
1385
1449
  const height = Math.ceil(rect.height);
1386
1450
  document.body.removeChild(span);
1387
1451
  const canvas = document.createElement("canvas");
1388
- canvas.width = width * dpr;
1389
- canvas.height = height * dpr;
1452
+ canvas.width = Math.max(1, width * dpr);
1453
+ canvas.height = Math.max(1, height * dpr);
1390
1454
  const ctx = canvas.getContext("2d");
1391
1455
  ctx.scale(dpr, dpr);
1392
1456
  ctx.font = fontWeight ? `${fontWeight} ${fontSize}px "${fontFamily}"` : `${fontSize}px "${fontFamily}"`;
@@ -1506,6 +1570,313 @@
1506
1570
  }
1507
1571
  return out;
1508
1572
  }
1573
+ function rewriteRelativeUrls(cssText, baseHref) {
1574
+ if (!cssText) return cssText;
1575
+ return cssText.replace(
1576
+ /url\(\s*(['"]?)([^)'"]+)\1\s*\)/g,
1577
+ (m, q, u) => {
1578
+ const src = (u || "").trim();
1579
+ if (!src || /^data:|^blob:|^https?:|^file:|^about:/i.test(src)) return m;
1580
+ let abs = src;
1581
+ try {
1582
+ abs = new URL(src, baseHref || location.href).href;
1583
+ } catch (e) {
1584
+ }
1585
+ return `url("${abs}")`;
1586
+ }
1587
+ );
1588
+ }
1589
+ var IMPORT_ANY_RE = /@import\s+(?:url\(\s*(['"]?)([^)"']+)\1\s*\)|(['"])([^"']+)\3)([^;]*);/g;
1590
+ var MAX_IMPORT_DEPTH = 4;
1591
+ function inlineImportsAndRewrite(cssText, ownerHref, useProxy) {
1592
+ return __async(this, null, function* () {
1593
+ if (!cssText) return cssText;
1594
+ const visited = /* @__PURE__ */ new Set();
1595
+ function normalizeUrl(u, base) {
1596
+ try {
1597
+ return new URL(u, base || location.href).href;
1598
+ } catch (e) {
1599
+ return u;
1600
+ }
1601
+ }
1602
+ function resolveOnce(text, baseHref, depth = 0) {
1603
+ return __async(this, null, function* () {
1604
+ if (depth > MAX_IMPORT_DEPTH) {
1605
+ console.warn(`[snapDOM] @import depth exceeded (${MAX_IMPORT_DEPTH}) at ${baseHref}`);
1606
+ return text;
1607
+ }
1608
+ let out = "";
1609
+ let last = 0;
1610
+ let m;
1611
+ while (m = IMPORT_ANY_RE.exec(text)) {
1612
+ out += text.slice(last, m.index);
1613
+ last = IMPORT_ANY_RE.lastIndex;
1614
+ const rawUrl = (m[2] || m[4] || "").trim();
1615
+ const absUrl = normalizeUrl(rawUrl, baseHref);
1616
+ if (visited.has(absUrl)) {
1617
+ console.warn("[snapDOM] Skipping circular import");
1618
+ continue;
1619
+ }
1620
+ visited.add(absUrl);
1621
+ let imported = "";
1622
+ try {
1623
+ const r = yield snapFetch(absUrl, { as: "text", useProxy, silent: true });
1624
+ if (r.ok && typeof r.data === "string") imported = r.data;
1625
+ } catch (e) {
1626
+ }
1627
+ if (imported) {
1628
+ imported = rewriteRelativeUrls(imported, absUrl);
1629
+ imported = yield resolveOnce(imported, absUrl, depth + 1);
1630
+ out += `
1631
+ /* inlined: ${absUrl} */
1632
+ ${imported}
1633
+ `;
1634
+ } else {
1635
+ out += m[0];
1636
+ }
1637
+ }
1638
+ out += text.slice(last);
1639
+ return out;
1640
+ });
1641
+ }
1642
+ let rewritten = rewriteRelativeUrls(cssText, ownerHref || location.href);
1643
+ rewritten = yield resolveOnce(rewritten, ownerHref || location.href, 0);
1644
+ return rewritten;
1645
+ });
1646
+ }
1647
+ var URL_RE = /url\((["']?)([^"')]+)\1\)/g;
1648
+ var FACE_RE = /@font-face[^{}]*\{[^}]*\}/g;
1649
+ function parseUnicodeRange(ur) {
1650
+ if (!ur) return [];
1651
+ const ranges = [];
1652
+ const parts = ur.split(",").map((s) => s.trim()).filter(Boolean);
1653
+ for (const p of parts) {
1654
+ const m = p.match(/^U\+([0-9A-Fa-f?]+)(?:-([0-9A-Fa-f?]+))?$/);
1655
+ if (!m) continue;
1656
+ const a = m[1], b = m[2];
1657
+ const expand = (hex) => {
1658
+ if (!hex.includes("?")) return parseInt(hex, 16);
1659
+ const min = parseInt(hex.replace(/\?/g, "0"), 16);
1660
+ const max = parseInt(hex.replace(/\?/g, "F"), 16);
1661
+ return [min, max];
1662
+ };
1663
+ if (b) {
1664
+ const A = expand(a), B = expand(b);
1665
+ const min = Array.isArray(A) ? A[0] : A;
1666
+ const max = Array.isArray(B) ? B[1] : B;
1667
+ ranges.push([Math.min(min, max), Math.max(min, max)]);
1668
+ } else {
1669
+ const X = expand(a);
1670
+ if (Array.isArray(X)) ranges.push([X[0], X[1]]);
1671
+ else ranges.push([X, X]);
1672
+ }
1673
+ }
1674
+ return ranges;
1675
+ }
1676
+ function unicodeIntersects(used, ranges) {
1677
+ if (!ranges.length) return true;
1678
+ if (!used || used.size === 0) return true;
1679
+ for (const cp of used) {
1680
+ for (const [a, b] of ranges) if (cp >= a && cp <= b) return true;
1681
+ }
1682
+ return false;
1683
+ }
1684
+ function extractSrcUrls(srcValue, baseHref) {
1685
+ const urls = [];
1686
+ if (!srcValue) return urls;
1687
+ for (const m of srcValue.matchAll(URL_RE)) {
1688
+ let u = (m[2] || "").trim();
1689
+ if (!u || u.startsWith("data:")) continue;
1690
+ if (!/^https?:/i.test(u)) {
1691
+ try {
1692
+ u = new URL(u, baseHref || location.href).href;
1693
+ } catch (e) {
1694
+ }
1695
+ }
1696
+ urls.push(u);
1697
+ }
1698
+ return urls;
1699
+ }
1700
+ function inlineUrlsInCssBlock(cssBlock, baseHref, useProxy = "") {
1701
+ return __async(this, null, function* () {
1702
+ var _a, _b, _c, _d, _e;
1703
+ let out = cssBlock;
1704
+ for (const m of cssBlock.matchAll(URL_RE)) {
1705
+ const raw = extractURL(m[0]);
1706
+ if (!raw) continue;
1707
+ let abs = raw;
1708
+ if (!abs.startsWith("http") && !abs.startsWith("data:")) {
1709
+ try {
1710
+ abs = new URL(abs, baseHref || location.href).href;
1711
+ } catch (e) {
1712
+ }
1713
+ }
1714
+ if (isIconFont2(abs)) continue;
1715
+ if ((_a = cache.resource) == null ? void 0 : _a.has(abs)) {
1716
+ (_b = cache.font) == null ? void 0 : _b.add(abs);
1717
+ out = out.replace(m[0], `url(${cache.resource.get(abs)})`);
1718
+ continue;
1719
+ }
1720
+ if ((_c = cache.font) == null ? void 0 : _c.has(abs)) continue;
1721
+ try {
1722
+ const r = yield snapFetch(abs, { as: "dataURL", useProxy, silent: true });
1723
+ if (r.ok && typeof r.data === "string") {
1724
+ const b64 = r.data;
1725
+ (_d = cache.resource) == null ? void 0 : _d.set(abs, b64);
1726
+ (_e = cache.font) == null ? void 0 : _e.add(abs);
1727
+ out = out.replace(m[0], `url(${b64})`);
1728
+ }
1729
+ } catch (e) {
1730
+ console.warn("[snapDOM] Failed to fetch font resource:", abs);
1731
+ }
1732
+ }
1733
+ return out;
1734
+ });
1735
+ }
1736
+ function subsetFromRanges(ranges) {
1737
+ if (!ranges.length) return null;
1738
+ const hit = (a, b) => ranges.some(([x, y]) => !(y < a || x > b));
1739
+ const latin = hit(0, 255) || hit(305, 305);
1740
+ const latinExt = hit(256, 591) || hit(7680, 7935);
1741
+ const greek = hit(880, 1023);
1742
+ const cyr = hit(1024, 1279);
1743
+ const viet = hit(7840, 7929) || hit(258, 259) || hit(416, 417) || hit(431, 432);
1744
+ if (viet) return "vietnamese";
1745
+ if (cyr) return "cyrillic";
1746
+ if (greek) return "greek";
1747
+ if (latinExt) return "latin-ext";
1748
+ if (latin) return "latin";
1749
+ return null;
1750
+ }
1751
+ function buildSimpleExcluder(ex = {}) {
1752
+ const famSet = new Set((ex.families || []).map((s) => String(s).toLowerCase()));
1753
+ const domSet = new Set((ex.domains || []).map((s) => String(s).toLowerCase()));
1754
+ const subSet = new Set((ex.subsets || []).map((s) => String(s).toLowerCase()));
1755
+ return (meta, parsedRanges) => {
1756
+ if (famSet.size && famSet.has(meta.family.toLowerCase())) return true;
1757
+ if (domSet.size) {
1758
+ for (const u of meta.srcUrls) {
1759
+ try {
1760
+ if (domSet.has(new URL(u).host.toLowerCase())) return true;
1761
+ } catch (e) {
1762
+ }
1763
+ }
1764
+ }
1765
+ if (subSet.size) {
1766
+ const label = subsetFromRanges(parsedRanges);
1767
+ if (label && subSet.has(label)) return true;
1768
+ }
1769
+ return false;
1770
+ };
1771
+ }
1772
+ function dedupeFontFaces(cssText) {
1773
+ var _a, _b, _c, _d, _e, _f;
1774
+ if (!cssText) return cssText;
1775
+ const FACE_RE_G = /@font-face[^{}]*\{[^}]*\}/gi;
1776
+ const seen = /* @__PURE__ */ new Set();
1777
+ const out = [];
1778
+ for (const block of cssText.match(FACE_RE_G) || []) {
1779
+ const familyRaw = ((_a = block.match(/font-family:\s*([^;]+);/i)) == null ? void 0 : _a[1]) || "";
1780
+ const family = pickPrimaryFamily(familyRaw);
1781
+ const weightSpec = (((_b = block.match(/font-weight:\s*([^;]+);/i)) == null ? void 0 : _b[1]) || "400").trim();
1782
+ const styleSpec = (((_c = block.match(/font-style:\s*([^;]+);/i)) == null ? void 0 : _c[1]) || "normal").trim();
1783
+ const stretchSpec = (((_d = block.match(/font-stretch:\s*([^;]+);/i)) == null ? void 0 : _d[1]) || "100%").trim();
1784
+ const urange = (((_e = block.match(/unicode-range:\s*([^;]+);/i)) == null ? void 0 : _e[1]) || "").trim();
1785
+ const srcRaw = (((_f = block.match(/src\s*:\s*([^;]+);/i)) == null ? void 0 : _f[1]) || "").trim();
1786
+ const urls = extractSrcUrls(srcRaw, location.href);
1787
+ const srcPart = urls.length ? urls.map((u) => String(u).toLowerCase()).sort().join("|") : srcRaw.toLowerCase();
1788
+ const key = [
1789
+ String(family || "").toLowerCase(),
1790
+ weightSpec,
1791
+ styleSpec,
1792
+ stretchSpec,
1793
+ urange.toLowerCase(),
1794
+ srcPart
1795
+ ].join("|");
1796
+ if (!seen.has(key)) {
1797
+ seen.add(key);
1798
+ out.push(block);
1799
+ }
1800
+ }
1801
+ if (out.length === 0) return cssText;
1802
+ let i = 0;
1803
+ return cssText.replace(FACE_RE_G, () => out[i++] || "");
1804
+ }
1805
+ function buildFontsCacheKey(required, exclude, localFonts, useProxy) {
1806
+ const req = Array.from(required || []).sort().join("|");
1807
+ const ex = exclude ? JSON.stringify({
1808
+ families: (exclude.families || []).map((s) => String(s).toLowerCase()).sort(),
1809
+ domains: (exclude.domains || []).map((s) => String(s).toLowerCase()).sort(),
1810
+ subsets: (exclude.subsets || []).map((s) => String(s).toLowerCase()).sort()
1811
+ }) : "";
1812
+ const lf = (localFonts || []).map((f) => `${(f.family || "").toLowerCase()}::${f.weight || "normal"}::${f.style || "normal"}::${f.src || ""}`).sort().join("|");
1813
+ const px = useProxy || "";
1814
+ return `fonts-embed-css::req=${req}::ex=${ex}::lf=${lf}::px=${px}`;
1815
+ }
1816
+ function collectFacesFromSheet(sheet, baseHref, emitFace, ctx) {
1817
+ return __async(this, null, function* () {
1818
+ let rules;
1819
+ try {
1820
+ rules = sheet.cssRules || [];
1821
+ } catch (e) {
1822
+ return;
1823
+ }
1824
+ const normalizeUrl = (u, base) => {
1825
+ try {
1826
+ return new URL(u, base || location.href).href;
1827
+ } catch (e) {
1828
+ return u;
1829
+ }
1830
+ };
1831
+ for (const rule of rules) {
1832
+ if (rule.type === CSSRule.IMPORT_RULE && rule.styleSheet) {
1833
+ const childHref = rule.href ? normalizeUrl(rule.href, baseHref) : baseHref;
1834
+ if (ctx.depth >= MAX_IMPORT_DEPTH) {
1835
+ console.warn(`[snapDOM] CSSOM import depth exceeded (${MAX_IMPORT_DEPTH}) at ${childHref}`);
1836
+ continue;
1837
+ }
1838
+ if (childHref && ctx.visitedSheets.has(childHref)) {
1839
+ console.warn(`[snapDOM] Skipping circular CSSOM import: ${childHref}`);
1840
+ continue;
1841
+ }
1842
+ if (childHref) ctx.visitedSheets.add(childHref);
1843
+ const nextCtx = __spreadProps(__spreadValues({}, ctx), { depth: (ctx.depth || 0) + 1 });
1844
+ yield collectFacesFromSheet(rule.styleSheet, childHref, emitFace, nextCtx);
1845
+ continue;
1846
+ }
1847
+ if (rule.type === CSSRule.FONT_FACE_RULE) {
1848
+ const famRaw = (rule.style.getPropertyValue("font-family") || "").trim();
1849
+ const family = pickPrimaryFamily(famRaw);
1850
+ if (!family || isIconFont2(family)) continue;
1851
+ const weightSpec = (rule.style.getPropertyValue("font-weight") || "400").trim();
1852
+ const styleSpec = (rule.style.getPropertyValue("font-style") || "normal").trim();
1853
+ const stretchSpec = (rule.style.getPropertyValue("font-stretch") || "100%").trim();
1854
+ const srcRaw = (rule.style.getPropertyValue("src") || "").trim();
1855
+ const urange = (rule.style.getPropertyValue("unicode-range") || "").trim();
1856
+ if (!ctx.faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
1857
+ const ranges = parseUnicodeRange(urange);
1858
+ if (!unicodeIntersects(ctx.usedCodepoints, ranges)) continue;
1859
+ const meta = {
1860
+ family,
1861
+ weightSpec,
1862
+ styleSpec,
1863
+ stretchSpec,
1864
+ unicodeRange: urange,
1865
+ srcRaw,
1866
+ srcUrls: extractSrcUrls(srcRaw, baseHref || location.href),
1867
+ href: baseHref || location.href
1868
+ };
1869
+ if (ctx.simpleExcluder && ctx.simpleExcluder(meta, ranges)) continue;
1870
+ if (/url\(/i.test(srcRaw)) {
1871
+ const inlinedSrc = yield inlineUrlsInCssBlock(srcRaw, baseHref || location.href, ctx.useProxy);
1872
+ yield emitFace(`@font-face{font-family:${family};src:${inlinedSrc};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`);
1873
+ } else {
1874
+ yield emitFace(`@font-face{font-family:${family};src:${srcRaw};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`);
1875
+ }
1876
+ }
1877
+ }
1878
+ });
1879
+ }
1509
1880
  function embedCustomFonts() {
1510
1881
  return __async(this, arguments, function* ({
1511
1882
  required,
@@ -1525,9 +1896,6 @@
1525
1896
  arr.push({ w: parseInt(w, 10), s, st: parseInt(st, 10) });
1526
1897
  requiredIndex.set(fam, arr);
1527
1898
  }
1528
- const IMPORT_RE = /@import\s+url\(["']?([^"')]+)["']?\)/g;
1529
- const URL_RE = /url\((["']?)([^"')]+)\1\)/g;
1530
- const FACE_RE = /@font-face[^{}]*\{[^}]*\}/g;
1531
1899
  function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
1532
1900
  if (!requiredIndex.has(fam)) return false;
1533
1901
  const need = requiredIndex.get(fam);
@@ -1553,192 +1921,23 @@
1553
1921
  const sOk = styleOK(normStyle(r.s));
1554
1922
  const tOk = r.st >= ts.min && r.st <= ts.max;
1555
1923
  const nearWeight = Math.abs(faceSingleW - r.w) <= 300;
1556
- if (nearWeight && sOk && tOk) {
1557
- return true;
1558
- }
1559
- }
1560
- }
1561
- return false;
1562
- }
1563
- function parseUnicodeRange(ur) {
1564
- if (!ur) return [];
1565
- const ranges = [];
1566
- const parts = ur.split(",").map((s) => s.trim()).filter(Boolean);
1567
- for (const p of parts) {
1568
- const m = p.match(/^U\+([0-9A-Fa-f?]+)(?:-([0-9A-Fa-f?]+))?$/);
1569
- if (!m) continue;
1570
- const a = m[1], b = m[2];
1571
- const expand = (hex) => {
1572
- if (!hex.includes("?")) return parseInt(hex, 16);
1573
- const min = parseInt(hex.replace(/\?/g, "0"), 16);
1574
- const max = parseInt(hex.replace(/\?/g, "F"), 16);
1575
- return [min, max];
1576
- };
1577
- if (b) {
1578
- const A = expand(a), B = expand(b);
1579
- const min = Array.isArray(A) ? A[0] : A;
1580
- const max = Array.isArray(B) ? B[1] : B;
1581
- ranges.push([Math.min(min, max), Math.max(min, max)]);
1582
- } else {
1583
- const X = expand(a);
1584
- if (Array.isArray(X)) ranges.push([X[0], X[1]]);
1585
- else ranges.push([X, X]);
1924
+ if (nearWeight && sOk && tOk) return true;
1586
1925
  }
1587
1926
  }
1588
- return ranges;
1589
- }
1590
- function unicodeIntersects(used, ranges) {
1591
- if (!ranges.length) return true;
1592
- if (!used || used.size === 0) return true;
1593
- for (const cp of used) {
1594
- for (const [a, b] of ranges) if (cp >= a && cp <= b) return true;
1595
- }
1596
1927
  return false;
1597
1928
  }
1598
- function extractSrcUrls(srcValue, baseHref) {
1599
- const urls = [];
1600
- if (!srcValue) return urls;
1601
- for (const m of srcValue.matchAll(URL_RE)) {
1602
- let u = (m[2] || "").trim();
1603
- if (!u || u.startsWith("data:")) continue;
1604
- if (!/^https?:/i.test(u)) {
1605
- try {
1606
- u = new URL(u, baseHref || location.href).href;
1607
- } catch (e) {
1608
- }
1609
- }
1610
- urls.push(u);
1611
- }
1612
- return urls;
1613
- }
1614
- function inlineUrlsInCssBlock(cssBlock, baseHref) {
1615
- return __async(this, null, function* () {
1616
- var _a2, _b2, _c2, _d2, _e2;
1617
- let out = cssBlock;
1618
- for (const m of cssBlock.matchAll(URL_RE)) {
1619
- const raw = extractURL(m[0]);
1620
- if (!raw) continue;
1621
- let abs = raw;
1622
- if (!abs.startsWith("http") && !abs.startsWith("data:")) {
1623
- try {
1624
- abs = new URL(abs, baseHref || location.href).href;
1625
- } catch (e) {
1626
- }
1627
- }
1628
- if (isIconFont2(abs)) continue;
1629
- if ((_a2 = cache.resource) == null ? void 0 : _a2.has(abs)) {
1630
- (_b2 = cache.font) == null ? void 0 : _b2.add(abs);
1631
- out = out.replace(m[0], `url(${cache.resource.get(abs)})`);
1632
- continue;
1633
- }
1634
- if ((_c2 = cache.font) == null ? void 0 : _c2.has(abs)) continue;
1635
- try {
1636
- const r = yield snapFetch(abs, { as: "dataURL", useProxy, silent: true });
1637
- if (r.ok && typeof r.data === "string") {
1638
- const b64 = r.data;
1639
- (_d2 = cache.resource) == null ? void 0 : _d2.set(abs, b64);
1640
- (_e2 = cache.font) == null ? void 0 : _e2.add(abs);
1641
- out = out.replace(m[0], `url(${b64})`);
1642
- }
1643
- } catch (e) {
1644
- console.warn("[snapDOM] Failed to fetch font resource:", abs);
1645
- }
1646
- }
1647
- return out;
1648
- });
1649
- }
1650
- function subsetFromRanges(ranges) {
1651
- if (!ranges.length) return null;
1652
- const hit = (a, b) => ranges.some(([x, y]) => !(y < a || x > b));
1653
- const latin = hit(0, 255) || hit(305, 305);
1654
- const latinExt = hit(256, 591) || hit(7680, 7935);
1655
- const greek = hit(880, 1023);
1656
- const cyr = hit(1024, 1279);
1657
- const viet = hit(7840, 7929) || hit(258, 259) || hit(416, 417) || hit(431, 432);
1658
- if (viet) return "vietnamese";
1659
- if (cyr) return "cyrillic";
1660
- if (greek) return "greek";
1661
- if (latinExt) return "latin-ext";
1662
- if (latin) return "latin";
1663
- return null;
1664
- }
1665
- function buildSimpleExcluder(ex = {}) {
1666
- const famSet = new Set((ex.families || []).map((s) => String(s).toLowerCase()));
1667
- const domSet = new Set((ex.domains || []).map((s) => String(s).toLowerCase()));
1668
- const subSet = new Set((ex.subsets || []).map((s) => String(s).toLowerCase()));
1669
- return (meta, parsedRanges) => {
1670
- if (famSet.size && famSet.has(meta.family.toLowerCase())) return true;
1671
- if (domSet.size) {
1672
- for (const u of meta.srcUrls) {
1673
- try {
1674
- if (domSet.has(new URL(u).host.toLowerCase())) return true;
1675
- } catch (e) {
1676
- }
1677
- }
1678
- }
1679
- if (subSet.size) {
1680
- const label = subsetFromRanges(parsedRanges);
1681
- if (label && subSet.has(label)) return true;
1682
- }
1683
- return false;
1684
- };
1685
- }
1686
1929
  const simpleExcluder = buildSimpleExcluder(exclude);
1687
- function dedupeFontFaces(cssText) {
1688
- var _a2, _b2, _c2, _d2, _e2, _f2;
1689
- if (!cssText) return cssText;
1690
- const FACE_RE2 = /@font-face[^{}]*\{[^}]*\}/gi;
1691
- const seen = /* @__PURE__ */ new Set();
1692
- const out = [];
1693
- for (const block of cssText.match(FACE_RE2) || []) {
1694
- const familyRaw = ((_a2 = block.match(/font-family:\s*([^;]+);/i)) == null ? void 0 : _a2[1]) || "";
1695
- const family = pickPrimaryFamily(familyRaw);
1696
- const weightSpec = (((_b2 = block.match(/font-weight:\s*([^;]+);/i)) == null ? void 0 : _b2[1]) || "400").trim();
1697
- const styleSpec = (((_c2 = block.match(/font-style:\s*([^;]+);/i)) == null ? void 0 : _c2[1]) || "normal").trim();
1698
- const stretchSpec = (((_d2 = block.match(/font-stretch:\s*([^;]+);/i)) == null ? void 0 : _d2[1]) || "100%").trim();
1699
- const urange = (((_e2 = block.match(/unicode-range:\s*([^;]+);/i)) == null ? void 0 : _e2[1]) || "").trim();
1700
- const srcRaw = (((_f2 = block.match(/src\s*:\s*([^;]+);/i)) == null ? void 0 : _f2[1]) || "").trim();
1701
- const urls = extractSrcUrls(srcRaw, location.href);
1702
- const srcPart = urls.length ? urls.map((u) => String(u).toLowerCase()).sort().join("|") : srcRaw.toLowerCase();
1703
- const key = [
1704
- String(family || "").toLowerCase(),
1705
- weightSpec,
1706
- styleSpec,
1707
- stretchSpec,
1708
- urange.toLowerCase(),
1709
- srcPart
1710
- ].join("|");
1711
- if (!seen.has(key)) {
1712
- seen.add(key);
1713
- out.push(block);
1714
- }
1715
- }
1716
- if (out.length === 0) return cssText;
1717
- let i = 0;
1718
- return cssText.replace(FACE_RE2, () => out[i++] || "");
1719
- }
1720
- function buildFontsCacheKey() {
1721
- const req = Array.from(required || []).sort().join("|");
1722
- const ex = exclude ? JSON.stringify({
1723
- families: (exclude.families || []).map((s) => String(s).toLowerCase()).sort(),
1724
- domains: (exclude.domains || []).map((s) => String(s).toLowerCase()).sort(),
1725
- subsets: (exclude.subsets || []).map((s) => String(s).toLowerCase()).sort()
1726
- }) : "";
1727
- const lf = (localFonts || []).map((f) => `${(f.family || "").toLowerCase()}::${f.weight || "normal"}::${f.style || "normal"}::${f.src || ""}`).sort().join("|");
1728
- const px = useProxy || "";
1729
- return `fonts-embed-css::req=${req}::ex=${ex}::lf=${lf}::px=${px}`;
1730
- }
1731
- const cacheKey = buildFontsCacheKey();
1930
+ const cacheKey = buildFontsCacheKey(required, exclude, localFonts, useProxy);
1732
1931
  if ((_a = cache.resource) == null ? void 0 : _a.has(cacheKey)) {
1733
- const css = cache.resource.get(cacheKey);
1734
- return css;
1932
+ return cache.resource.get(cacheKey);
1735
1933
  }
1736
1934
  const requiredFamilies = familiesFromRequired(required);
1737
1935
  const importUrls = [];
1936
+ const IMPORT_ANY_RE_LOCAL = IMPORT_ANY_RE;
1738
1937
  for (const styleTag of document.querySelectorAll("style")) {
1739
1938
  const cssText = styleTag.textContent || "";
1740
- for (const m of cssText.matchAll(IMPORT_RE)) {
1741
- const u = m[1];
1939
+ for (const m of cssText.matchAll(IMPORT_ANY_RE_LOCAL)) {
1940
+ const u = (m[2] || m[4] || "").trim();
1742
1941
  if (!u || isIconFont2(u)) continue;
1743
1942
  const hasLink = !!document.querySelector(`link[rel="stylesheet"][href="${u}"]`);
1744
1943
  if (!hasLink) importUrls.push(u);
@@ -1785,65 +1984,53 @@
1785
1984
  cssText = res.data;
1786
1985
  if (isIconFont2(link.href)) continue;
1787
1986
  }
1987
+ cssText = yield inlineImportsAndRewrite(cssText, link.href, useProxy);
1788
1988
  let facesOut = "";
1789
1989
  for (const face of cssText.match(FACE_RE) || []) {
1790
1990
  const famRaw = (((_b = face.match(/font-family:\s*([^;]+);/i)) == null ? void 0 : _b[1]) || "").trim();
1791
1991
  const family = pickPrimaryFamily(famRaw);
1792
- if (!family || isIconFont2(family)) {
1793
- continue;
1794
- }
1992
+ if (!family || isIconFont2(family)) continue;
1795
1993
  const weightSpec = (((_c = face.match(/font-weight:\s*([^;]+);/i)) == null ? void 0 : _c[1]) || "400").trim();
1796
1994
  const styleSpec = (((_d = face.match(/font-style:\s*([^;]+);/i)) == null ? void 0 : _d[1]) || "normal").trim();
1797
1995
  const stretchSpec = (((_e = face.match(/font-stretch:\s*([^;]+);/i)) == null ? void 0 : _e[1]) || "100%").trim();
1798
1996
  const urange = (((_f = face.match(/unicode-range:\s*([^;]+);/i)) == null ? void 0 : _f[1]) || "").trim();
1799
1997
  const srcRaw = (((_g = face.match(/src\s*:\s*([^;]+);/i)) == null ? void 0 : _g[1]) || "").trim();
1800
1998
  const srcUrls = extractSrcUrls(srcRaw, link.href);
1801
- if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) {
1802
- continue;
1803
- }
1999
+ if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
1804
2000
  const ranges = parseUnicodeRange(urange);
1805
- if (!unicodeIntersects(usedCodepoints, ranges)) {
1806
- continue;
1807
- }
2001
+ if (!unicodeIntersects(usedCodepoints, ranges)) continue;
1808
2002
  const meta = { family, weightSpec, styleSpec, stretchSpec, unicodeRange: urange, srcRaw, srcUrls, href: link.href };
1809
- if (exclude && simpleExcluder(meta, ranges)) {
1810
- continue;
1811
- }
1812
- const newFace = /url\(/i.test(srcRaw) ? yield inlineUrlsInCssBlock(face, link.href) : face;
1813
- facesOut += newFace + "";
2003
+ if (exclude && simpleExcluder(meta, ranges)) continue;
2004
+ const newFace = /url\(/i.test(srcRaw) ? yield inlineUrlsInCssBlock(face, link.href, useProxy) : face;
2005
+ facesOut += newFace;
1814
2006
  }
1815
- if (facesOut.trim()) finalCSS += facesOut + "";
2007
+ if (facesOut.trim()) finalCSS += facesOut;
1816
2008
  } catch (e) {
1817
- console.warn("[snapdom] Failed to process stylesheet:", link.href);
2009
+ console.warn("[snapDOM] Failed to process stylesheet:", link.href);
1818
2010
  }
1819
2011
  }
2012
+ const ctx = {
2013
+ requiredIndex,
2014
+ usedCodepoints,
2015
+ faceMatchesRequired,
2016
+ simpleExcluder: exclude ? buildSimpleExcluder(exclude) : null,
2017
+ useProxy,
2018
+ visitedSheets: /* @__PURE__ */ new Set(),
2019
+ depth: 0
2020
+ };
1820
2021
  for (const sheet of document.styleSheets) {
2022
+ if (sheet.href && linkNodes.some((l) => l.href === sheet.href)) continue;
1821
2023
  try {
1822
- if (sheet.href && linkNodes.some((l) => l.href === sheet.href)) continue;
1823
- const rules = sheet.cssRules || [];
1824
- for (const rule of rules) {
1825
- if (rule.type !== CSSRule.FONT_FACE_RULE) continue;
1826
- const famRaw = (rule.style.getPropertyValue("font-family") || "").trim();
1827
- const family = pickPrimaryFamily(famRaw);
1828
- if (!family || isIconFont2(family)) continue;
1829
- const weightSpec = (rule.style.getPropertyValue("font-weight") || "400").trim();
1830
- const styleSpec = (rule.style.getPropertyValue("font-style") || "normal").trim();
1831
- const stretchSpec = (rule.style.getPropertyValue("font-stretch") || "100%").trim();
1832
- const srcRaw = (rule.style.getPropertyValue("src") || "").trim();
1833
- const urange = (rule.style.getPropertyValue("unicode-range") || "").trim();
1834
- const srcUrls = extractSrcUrls(srcRaw, sheet.href || location.href);
1835
- if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
1836
- const ranges = parseUnicodeRange(urange);
1837
- if (!unicodeIntersects(usedCodepoints, ranges)) continue;
1838
- const meta = { family, weightSpec, styleSpec, stretchSpec, unicodeRange: urange, srcRaw, srcUrls, href: sheet.href || location.href };
1839
- if (exclude && simpleExcluder(meta, ranges)) continue;
1840
- if (/url\(/i.test(srcRaw)) {
1841
- const inlinedSrc = yield inlineUrlsInCssBlock(srcRaw, sheet.href || location.href);
1842
- finalCSS += `@font-face{font-family:${family};src:${inlinedSrc};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`;
1843
- } else {
1844
- finalCSS += `@font-face{font-family:${family};src:${srcRaw};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`;
1845
- }
1846
- }
2024
+ const rootHref = sheet.href || location.href;
2025
+ if (rootHref) ctx.visitedSheets.add(rootHref);
2026
+ yield collectFacesFromSheet(
2027
+ sheet,
2028
+ rootHref,
2029
+ (faceCss) => __async(null, null, function* () {
2030
+ finalCSS += faceCss;
2031
+ }),
2032
+ ctx
2033
+ );
1847
2034
  } catch (e) {
1848
2035
  }
1849
2036
  }
@@ -1872,7 +2059,7 @@
1872
2059
  continue;
1873
2060
  }
1874
2061
  } catch (e) {
1875
- console.warn("[snapdom] Failed to fetch dynamic font src:", f._snapdomSrc);
2062
+ console.warn("[snapDOM] Failed to fetch dynamic font src:", f._snapdomSrc);
1876
2063
  continue;
1877
2064
  }
1878
2065
  }
@@ -1907,7 +2094,7 @@
1907
2094
  continue;
1908
2095
  }
1909
2096
  } catch (e) {
1910
- console.warn("[snapdom] Failed to fetch localFonts src:", src);
2097
+ console.warn("[snapDOM] Failed to fetch localFonts src:", src);
1911
2098
  continue;
1912
2099
  }
1913
2100
  }
@@ -1998,7 +2185,7 @@
1998
2185
  if (fams.length === 0) return;
1999
2186
  const warmupOnce = () => {
2000
2187
  const container = document.createElement("div");
2001
- container.style.cssText = `position: absolute !important;left: -9999px !important;top: 0 !important;opacity: 0 !important;pointer-events: none !important;contain: layout size style;`;
2188
+ container.style.cssText = "position:absolute!important;left:-9999px!important;top:0!important;opacity:0!important;pointer-events:none!important;contain:layout size style;";
2002
2189
  for (const fam of fams) {
2003
2190
  const span = document.createElement("span");
2004
2191
  span.textContent = "AaBbGg1234\xC1\xC9\xCD\xD3\xDA\xE7\xF1\u2014\u221E";
@@ -2359,9 +2546,6 @@
2359
2546
  const fontSize = parseInt(style.fontSize) || 32;
2360
2547
  const fontWeight = parseInt(style.fontWeight) || false;
2361
2548
  const color = style.color || "#000";
2362
- const display = style.display;
2363
- const width = parseFloat(style.width);
2364
- const height = parseFloat(style.height);
2365
2549
  const borderStyle = style.borderStyle;
2366
2550
  const borderWidth = parseFloat(style.borderWidth);
2367
2551
  const transform = style.transform;
@@ -2369,14 +2553,13 @@
2369
2553
  const hasExplicitContent = rawContent !== "none" && cleanContent !== "";
2370
2554
  const hasBg = bg && bg !== "none";
2371
2555
  const hasBgColor = bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)";
2372
- const hasBox2 = display !== "inline" && (width > 0 || height > 0);
2373
2556
  const hasBorder = borderStyle && borderStyle !== "none" && borderWidth > 0;
2374
2557
  const hasTransform = transform && transform !== "none";
2375
- const shouldRender = hasExplicitContent || hasBg || hasBgColor || hasBox2 || hasBorder || hasTransform;
2558
+ const shouldRender = hasExplicitContent || hasBg || hasBgColor || hasBorder || hasTransform;
2376
2559
  if (!shouldRender) {
2377
2560
  if (incs && incs.length && source.parentElement) {
2378
2561
  const map = __siblingCounters.get(source.parentElement) || /* @__PURE__ */ new Map();
2379
- for (const { name, num } of incs) {
2562
+ for (const { name } of incs) {
2380
2563
  if (!name) continue;
2381
2564
  const baseWithSibs = withSiblingOverrides(source, counterCtx);
2382
2565
  const derived = deriveCounterCtxForPseudo(source, getComputedStyle(source, pseudo), baseWithSibs);
@@ -2390,6 +2573,7 @@
2390
2573
  const pseudoEl = document.createElement("span");
2391
2574
  pseudoEl.dataset.snapdomPseudo = pseudo;
2392
2575
  pseudoEl.style.verticalAlign = "middle";
2576
+ pseudoEl.style.pointerEvents = "none";
2393
2577
  const snapshot = snapshotComputedStyle(style);
2394
2578
  const key = getStyleKey(snapshot, "span");
2395
2579
  sessionCache.styleMap.set(pseudoEl, key);
@@ -2416,6 +2600,10 @@
2416
2600
  } else if (!isIconFont22 && hasExplicitContent) {
2417
2601
  pseudoEl.textContent = cleanContent;
2418
2602
  }
2603
+ pseudoEl.style.background = "none";
2604
+ if ("mask" in pseudoEl.style) {
2605
+ pseudoEl.style.mask = "none";
2606
+ }
2419
2607
  if (hasBg) {
2420
2608
  try {
2421
2609
  const bgSplits = splitBackgroundImage(bg);
@@ -2427,7 +2615,7 @@
2427
2615
  }
2428
2616
  if (hasBgColor) pseudoEl.style.backgroundColor = bgColor;
2429
2617
  const hasContent2 = pseudoEl.childNodes.length > 0 || ((_a = pseudoEl.textContent) == null ? void 0 : _a.trim()) !== "";
2430
- const hasVisibleBox = hasContent2 || hasBg || hasBgColor || hasBox2 || hasBorder || hasTransform;
2618
+ const hasVisibleBox = hasContent2 || hasBg || hasBgColor || hasBorder || hasTransform;
2431
2619
  if (incs && incs.length && source.parentElement) {
2432
2620
  const map = __siblingCounters.get(source.parentElement) || /* @__PURE__ */ new Map();
2433
2621
  const baseWithSibs = withSiblingOverrides(source, counterCtx);
@@ -2507,6 +2695,103 @@
2507
2695
  });
2508
2696
  }
2509
2697
 
2698
+ // src/modules/changeCSS.js
2699
+ function freezeSticky(originalRoot, cloneRoot) {
2700
+ var _a;
2701
+ if (!originalRoot || !cloneRoot) return;
2702
+ const scrollTop = originalRoot.scrollTop || 0;
2703
+ if (!scrollTop) return;
2704
+ if (getComputedStyle(cloneRoot).position === "static") {
2705
+ cloneRoot.style.position = "relative";
2706
+ }
2707
+ const rootRect = originalRoot.getBoundingClientRect();
2708
+ const viewportH = originalRoot.clientHeight;
2709
+ const PH_ATTR = "data-snap-ph";
2710
+ const walker = document.createTreeWalker(originalRoot, NodeFilter.SHOW_ELEMENT);
2711
+ while (walker.nextNode()) {
2712
+ const el = (
2713
+ /** @type {HTMLElement} */
2714
+ walker.currentNode
2715
+ );
2716
+ const cs = getComputedStyle(el);
2717
+ const pos = cs.position;
2718
+ if (pos !== "sticky" && pos !== "-webkit-sticky") continue;
2719
+ const topInit = _toPx(cs.top);
2720
+ const bottomInit = _toPx(cs.bottom);
2721
+ if (topInit == null && bottomInit == null) continue;
2722
+ const path = _pathOf(el, originalRoot);
2723
+ const cloneEl = _findByPathIgnoringPlaceholders(cloneRoot, path, PH_ATTR);
2724
+ if (!cloneEl) continue;
2725
+ const elRect = el.getBoundingClientRect();
2726
+ const widthPx = elRect.width;
2727
+ const heightPx = elRect.height;
2728
+ const leftPx = elRect.left - rootRect.left;
2729
+ if (!(widthPx > 0 && heightPx > 0)) continue;
2730
+ if (!Number.isFinite(leftPx)) continue;
2731
+ const topAbsPx = topInit != null ? topInit + scrollTop : scrollTop + (viewportH - heightPx - /** bottomInit non-null */
2732
+ bottomInit);
2733
+ if (!Number.isFinite(topAbsPx)) continue;
2734
+ const zParsed = Number.parseInt(cs.zIndex, 10);
2735
+ const hasZ = Number.isFinite(zParsed);
2736
+ const overlayZ = hasZ ? Math.max(zParsed, 1) + 1 : 2;
2737
+ const placeholderZ = hasZ ? zParsed - 1 : 0;
2738
+ const ph = cloneEl.cloneNode(false);
2739
+ ph.setAttribute(PH_ATTR, "1");
2740
+ ph.style.position = "sticky";
2741
+ ph.style.left = `${leftPx}px`;
2742
+ ph.style.top = `${topAbsPx}px`;
2743
+ ph.style.width = `${widthPx}px`;
2744
+ ph.style.height = `${heightPx}px`;
2745
+ ph.style.visibility = "hidden";
2746
+ ph.style.zIndex = String(placeholderZ);
2747
+ ph.style.overflow = "hidden";
2748
+ ph.style.background = "transparent";
2749
+ ph.style.boxShadow = "none";
2750
+ ph.style.filter = "none";
2751
+ (_a = cloneEl.parentElement) == null ? void 0 : _a.insertBefore(ph, cloneEl);
2752
+ cloneEl.style.position = "absolute";
2753
+ cloneEl.style.left = `${leftPx}px`;
2754
+ cloneEl.style.top = `${topAbsPx}px`;
2755
+ cloneEl.style.bottom = "auto";
2756
+ cloneEl.style.zIndex = String(overlayZ);
2757
+ cloneEl.style.pointerEvents = "none";
2758
+ }
2759
+ }
2760
+ function _toPx(v) {
2761
+ if (!v || v === "auto") return null;
2762
+ const n = Number.parseFloat(v);
2763
+ return Number.isFinite(n) ? n : null;
2764
+ }
2765
+ function _pathOf(el, root) {
2766
+ const path = [];
2767
+ for (let cur = el; cur && cur !== root; ) {
2768
+ const p = cur.parentElement;
2769
+ if (!p) break;
2770
+ path.push(Array.prototype.indexOf.call(p.children, cur));
2771
+ cur = p;
2772
+ }
2773
+ return path.reverse();
2774
+ }
2775
+ function _findByPathIgnoringPlaceholders(root, path, phAttr) {
2776
+ let cur = root;
2777
+ for (let i = 0; i < path.length; i++) {
2778
+ const kids = _childrenWithoutPlaceholders(cur, phAttr);
2779
+ cur = /** @type {HTMLElement|undefined} */
2780
+ kids[path[i]];
2781
+ if (!cur) return null;
2782
+ }
2783
+ return cur instanceof HTMLElement ? cur : null;
2784
+ }
2785
+ function _childrenWithoutPlaceholders(el, phAttr) {
2786
+ const out = [];
2787
+ const ch = el.children;
2788
+ for (let i = 0; i < ch.length; i++) {
2789
+ const c = ch[i];
2790
+ if (!c.hasAttribute(phAttr)) out.push(c);
2791
+ }
2792
+ return out;
2793
+ }
2794
+
2510
2795
  // src/core/prepare.js
2511
2796
  function prepareClone(_0) {
2512
2797
  return __async(this, arguments, function* (element, options = {}) {
@@ -2583,6 +2868,8 @@
2583
2868
  cloneNode.appendChild(inner);
2584
2869
  }
2585
2870
  }
2871
+ const contentRoot = clone instanceof HTMLElement && clone.firstElementChild instanceof HTMLElement ? clone.firstElementChild : clone;
2872
+ freezeSticky(element, contentRoot);
2586
2873
  if (element === sessionCache.nodeMap.get(clone)) {
2587
2874
  const computed = sessionCache.styleCache.get(element) || window.getComputedStyle(element);
2588
2875
  sessionCache.styleCache.set(element, computed);
@@ -2974,19 +3261,50 @@
2974
3261
  }
2975
3262
 
2976
3263
  // src/core/capture.js
3264
+ function stripRootShadows(originalEl, cloneRoot) {
3265
+ if (!originalEl || !cloneRoot || !cloneRoot.style) return;
3266
+ const cs = getComputedStyle(originalEl);
3267
+ try {
3268
+ cloneRoot.style.boxShadow = "none";
3269
+ } catch (e) {
3270
+ }
3271
+ try {
3272
+ cloneRoot.style.textShadow = "none";
3273
+ } catch (e) {
3274
+ }
3275
+ try {
3276
+ cloneRoot.style.outline = "none";
3277
+ } catch (e) {
3278
+ }
3279
+ const f = cs.filter || "";
3280
+ const cleaned = f.replace(/\bblur\([^()]*\)\s*/gi, "").replace(/\bdrop-shadow\([^()]*\)\s*/gi, "").trim().replace(/\s+/g, " ");
3281
+ try {
3282
+ cloneRoot.style.filter = cleaned.length ? cleaned : "none";
3283
+ } catch (e) {
3284
+ }
3285
+ }
2977
3286
  function captureDOM(element, options) {
2978
3287
  return __async(this, null, function* () {
2979
3288
  if (!element) throw new Error("Element cannot be null or undefined");
2980
3289
  applyCachePolicy(options.cache);
2981
3290
  const fast = options.fast;
3291
+ const straighten = !!options.straighten;
3292
+ const noShadows = !!options.noShadows;
2982
3293
  let clone, classCSS, styleCache;
2983
3294
  let fontsCSS = "";
2984
3295
  let baseCSS = "";
2985
3296
  let dataURL;
2986
3297
  let svgString;
3298
+ let rootTransform2D = null;
2987
3299
  const undoClamp = lineClamp(element);
2988
3300
  try {
2989
3301
  ({ clone, classCSS, styleCache } = yield prepareClone(element, options));
3302
+ if (straighten && clone) {
3303
+ rootTransform2D = normalizeRootTransforms(element, clone);
3304
+ }
3305
+ if (noShadows && clone) {
3306
+ stripRootShadows(element, clone);
3307
+ }
2990
3308
  } finally {
2991
3309
  undoClamp();
2992
3310
  }
@@ -3011,7 +3329,7 @@
3011
3329
  const families = new Set(
3012
3330
  Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
3013
3331
  );
3014
- yield ensureFontsReady(families, 2);
3332
+ yield ensureFontsReady(families, 1);
3015
3333
  }
3016
3334
  fontsCSS = yield embedCustomFonts({
3017
3335
  required,
@@ -3060,61 +3378,7 @@
3060
3378
  b = Math.max(b, extY + Math.max(oy, 0));
3061
3379
  t = Math.max(t, extY + Math.max(-oy, 0));
3062
3380
  }
3063
- return {
3064
- bleed: { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b), left: Math.ceil(l) },
3065
- has: found
3066
- };
3067
- }
3068
- function parseBoxShadow(cs) {
3069
- var _a;
3070
- const v = cs.boxShadow || "";
3071
- if (!v || v === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
3072
- const parts = v.split(/\),(?=(?:[^()]*\([^()]*\))*[^()]*$)/).map((s) => s.trim());
3073
- let t = 0, r = 0, b2 = 0, l = 0;
3074
- for (const part of parts) {
3075
- const nums = ((_a = part.match(/-?\d+(\.\d+)?px/g)) == null ? void 0 : _a.map((n) => parseFloat(n))) || [];
3076
- if (nums.length < 2) continue;
3077
- const [ox2, oy2, blur = 0, spread = 0] = nums;
3078
- const extX = Math.abs(ox2) + blur + spread;
3079
- const extY = Math.abs(oy2) + blur + spread;
3080
- r = Math.max(r, extX + Math.max(ox2, 0));
3081
- l = Math.max(l, extX + Math.max(-ox2, 0));
3082
- b2 = Math.max(b2, extY + Math.max(oy2, 0));
3083
- t = Math.max(t, extY + Math.max(-oy2, 0));
3084
- }
3085
- return { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b2), left: Math.ceil(l) };
3086
- }
3087
- function parseFilterBlur(cs) {
3088
- const m = (cs.filter || "").match(/blur\(\s*([0-9.]+)px\s*\)/);
3089
- const b2 = m ? Math.ceil(parseFloat(m[1]) || 0) : 0;
3090
- return { top: b2, right: b2, bottom: b2, left: b2 };
3091
- }
3092
- function parseOutline(cs) {
3093
- if ((cs.outlineStyle || "none") === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
3094
- const w2 = Math.ceil(parseFloat(cs.outlineWidth || "0") || 0);
3095
- return { top: w2, right: w2, bottom: w2, left: w2 };
3096
- }
3097
- function bboxWithOriginFull(w2, h2, M, ox2, oy2) {
3098
- const a2 = M.a, b2 = M.b, c2 = M.c, d2 = M.d, e2 = M.e || 0, f2 = M.f || 0;
3099
- function pt(x, y) {
3100
- let X = x - ox2, Y = y - oy2;
3101
- let X2 = a2 * X + c2 * Y, Y2 = b2 * X + d2 * Y;
3102
- X2 += ox2 + e2;
3103
- Y2 += oy2 + f2;
3104
- return [X2, Y2];
3105
- }
3106
- const P = [pt(0, 0), pt(w2, 0), pt(0, h2), pt(w2, h2)];
3107
- let minX2 = Infinity, minY2 = Infinity, maxX2 = -Infinity, maxY2 = -Infinity;
3108
- for (const [X, Y] of P) {
3109
- if (X < minX2) minX2 = X;
3110
- if (Y < minY2) minY2 = Y;
3111
- if (X > maxX2) maxX2 = X;
3112
- if (Y > maxY2) maxY2 = Y;
3113
- }
3114
- return { minX: minX2, minY: minY2, maxX: maxX2, maxY: maxY2, width: maxX2 - minX2, height: maxY2 - minY2 };
3115
- }
3116
- function hasTFBBox(el) {
3117
- return hasBBoxAffectingTransform(el);
3381
+ return { bleed: { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b), left: Math.ceil(l) }, has: found };
3118
3382
  }
3119
3383
  const rect = element.getBoundingClientRect();
3120
3384
  const w0 = Math.max(1, Math.ceil(element.offsetWidth || parseFloat(csEl.width) || rect.width || 1));
@@ -3143,28 +3407,38 @@
3143
3407
  h = h0;
3144
3408
  }
3145
3409
  let minX = 0, minY = 0, maxX = w0, maxY = h0;
3146
- if (hasTFBBox(element)) {
3147
- const baseTransform2 = csEl.transform && csEl.transform !== "none" ? csEl.transform : "";
3148
- const ind2 = readIndividualTransforms(element);
3149
- const TOTAL = readTotalTransformMatrix({
3150
- baseTransform: baseTransform2,
3151
- rotate: ind2.rotate || "0deg",
3152
- scale: ind2.scale,
3153
- translate: ind2.translate
3154
- });
3155
- const { ox: ox2, oy: oy2 } = parseTransformOriginPx(csEl, w0, h0);
3156
- const M = TOTAL.is2D ? TOTAL : new DOMMatrix(TOTAL.toString());
3157
- const bb = bboxWithOriginFull(w0, h0, M, ox2, oy2);
3158
- minX = bb.minX;
3159
- minY = bb.minY;
3160
- maxX = bb.maxX;
3161
- maxY = bb.maxY;
3410
+ if (straighten && rootTransform2D && Number.isFinite(rootTransform2D.a)) {
3411
+ const M2 = { a: rootTransform2D.a, b: rootTransform2D.b || 0, c: rootTransform2D.c || 0, d: rootTransform2D.d || 1, e: 0, f: 0 };
3412
+ const bb2 = bboxWithOriginFull(w0, h0, M2, 0, 0);
3413
+ minX = bb2.minX;
3414
+ minY = bb2.minY;
3415
+ maxX = bb2.maxX;
3416
+ maxY = bb2.maxY;
3417
+ } else {
3418
+ const useTFBBox = !straighten && hasTFBBox(element);
3419
+ if (useTFBBox) {
3420
+ const baseTransform2 = csEl.transform && csEl.transform !== "none" ? csEl.transform : "";
3421
+ const ind2 = readIndividualTransforms(element);
3422
+ const TOTAL = readTotalTransformMatrix({
3423
+ baseTransform: baseTransform2,
3424
+ rotate: ind2.rotate || "0deg",
3425
+ scale: ind2.scale,
3426
+ translate: ind2.translate
3427
+ });
3428
+ const { ox: ox2, oy: oy2 } = parseTransformOriginPx(csEl, w0, h0);
3429
+ const M = TOTAL.is2D ? TOTAL : new DOMMatrix(TOTAL.toString());
3430
+ const bb = bboxWithOriginFull(w0, h0, M, ox2, oy2);
3431
+ minX = bb.minX;
3432
+ minY = bb.minY;
3433
+ maxX = bb.maxX;
3434
+ maxY = bb.maxY;
3435
+ }
3162
3436
  }
3163
3437
  const bleedShadow = parseBoxShadow(csEl);
3164
3438
  const bleedBlur = parseFilterBlur(csEl);
3165
3439
  const bleedOutline = parseOutline(csEl);
3166
3440
  const drop = parseFilterDropShadows(csEl);
3167
- const bleed = {
3441
+ const bleed = noShadows ? { top: 0, right: 0, bottom: 0, left: 0 } : {
3168
3442
  top: bleedShadow.top + bleedBlur.top + bleedOutline.top + drop.bleed.top,
3169
3443
  right: bleedShadow.right + bleedBlur.right + bleedOutline.right + drop.bleed.right,
3170
3444
  bottom: bleedShadow.bottom + bleedBlur.bottom + bleedOutline.bottom + drop.bleed.bottom,
@@ -3179,7 +3453,9 @@
3179
3453
  const outW = Math.max(1, Math.round(vbW0 * (hasW || hasH ? w / w0 : 1)));
3180
3454
  const outH = Math.max(1, Math.round(vbH0 * (hasH || hasW ? h / h0 : 1)));
3181
3455
  const svgNS = "http://www.w3.org/2000/svg";
3182
- const pad = isSafari() ? 1 : 0;
3456
+ const basePad = isSafari() ? 1 : 0;
3457
+ const extraPad = straighten ? 1 : 0;
3458
+ const pad = basePad + extraPad;
3183
3459
  const fo = document.createElementNS(svgNS, "foreignObject");
3184
3460
  const vbMinX = Math.floor(minX);
3185
3461
  const vbMinY = Math.floor(minY);
@@ -3204,20 +3480,7 @@
3204
3480
  const vbW = vbW0 + pad * 2;
3205
3481
  const vbH = vbH0 + pad * 2;
3206
3482
  const wantsSize = hasW || hasH;
3207
- options.meta = {
3208
- w0,
3209
- // ancho natural del elemento
3210
- h0,
3211
- // alto natural
3212
- vbW,
3213
- // ancho del viewBox
3214
- vbH,
3215
- // alto del viewBox
3216
- targetW: w,
3217
- // ancho deseado según options.width
3218
- targetH: h
3219
- // alto deseado según options.height
3220
- };
3483
+ options.meta = { w0, h0, vbW, vbH, targetW: w, targetH: h };
3221
3484
  const svgOutW = isSafari() && wantsSize ? vbW : outW + pad * 2;
3222
3485
  const svgOutH = isSafari() && wantsSize ? vbH : outH + pad * 2;
3223
3486
  const svgHeader = `<svg xmlns="${svgNS}" width="${svgOutW}" height="${svgOutH}" viewBox="0 0 ${vbW} ${vbH}">`;
@@ -3232,6 +3495,116 @@
3232
3495
  return dataURL;
3233
3496
  });
3234
3497
  }
3498
+ function normalizeRootTransforms(originalEl, cloneRoot) {
3499
+ if (!originalEl || !cloneRoot || !cloneRoot.style) return null;
3500
+ const cs = getComputedStyle(originalEl);
3501
+ try {
3502
+ cloneRoot.style.transformOrigin = "0 0";
3503
+ } catch (e) {
3504
+ }
3505
+ try {
3506
+ if ("translate" in cloneRoot.style) cloneRoot.style.translate = "none";
3507
+ if ("rotate" in cloneRoot.style) cloneRoot.style.rotate = "none";
3508
+ } catch (e) {
3509
+ }
3510
+ const tr = cs.transform || "none";
3511
+ if (!tr || tr === "none") {
3512
+ try {
3513
+ const M = matrixFromComputed(originalEl);
3514
+ if (M.a === 1 && M.b === 0 && M.c === 0 && M.d === 1) {
3515
+ cloneRoot.style.transform = "none";
3516
+ return { a: 1, b: 0, c: 0, d: 1 };
3517
+ }
3518
+ } catch (e) {
3519
+ }
3520
+ }
3521
+ const m2d = tr.match(/^matrix\(\s*([^)]+)\)$/i);
3522
+ if (m2d) {
3523
+ const nums = m2d[1].split(",").map((v) => parseFloat(v.trim()));
3524
+ if (nums.length === 6 && nums.every(Number.isFinite)) {
3525
+ const [a, b, c, d] = nums;
3526
+ const scaleX = Math.sqrt(a * a + b * b) || 0;
3527
+ let a1 = 0, b1 = 0, shear = 0, c2 = 0, d2 = 0, scaleY = 0;
3528
+ if (scaleX > 0) {
3529
+ a1 = a / scaleX;
3530
+ b1 = b / scaleX;
3531
+ shear = a1 * c + b1 * d;
3532
+ c2 = c - a1 * shear;
3533
+ d2 = d - b1 * shear;
3534
+ scaleY = Math.sqrt(c2 * c2 + d2 * d2) || 0;
3535
+ if (scaleY > 0) shear = shear / scaleY;
3536
+ else shear = 0;
3537
+ }
3538
+ const aP = scaleX;
3539
+ const bP = 0;
3540
+ const cP = shear * scaleY;
3541
+ const dP = scaleY;
3542
+ try {
3543
+ cloneRoot.style.transform = `matrix(${aP}, ${bP}, ${cP}, ${dP}, 0, 0)`;
3544
+ } catch (e) {
3545
+ }
3546
+ return { a: aP, b: bP, c: cP, d: dP };
3547
+ }
3548
+ }
3549
+ try {
3550
+ const legacy = String(tr).trim();
3551
+ cloneRoot.style.transform = legacy + " translate(0px, 0px) rotate(0deg)";
3552
+ return null;
3553
+ } catch (e) {
3554
+ return null;
3555
+ }
3556
+ }
3557
+ function parseBoxShadow(cs) {
3558
+ var _a;
3559
+ const v = cs.boxShadow || "";
3560
+ if (!v || v === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
3561
+ const parts = v.split(/\),(?=(?:[^()]*\([^()]*\))*[^()]*$)/).map((s) => s.trim());
3562
+ let t = 0, r = 0, b2 = 0, l = 0;
3563
+ for (const part of parts) {
3564
+ const nums = ((_a = part.match(/-?\d+(\.\d+)?px/g)) == null ? void 0 : _a.map((n) => parseFloat(n))) || [];
3565
+ if (nums.length < 2) continue;
3566
+ const [ox2, oy2, blur = 0, spread = 0] = nums;
3567
+ const extX = Math.abs(ox2) + blur + spread;
3568
+ const extY = Math.abs(oy2) + blur + spread;
3569
+ r = Math.max(r, extX + Math.max(ox2, 0));
3570
+ l = Math.max(l, extX + Math.max(-ox2, 0));
3571
+ b2 = Math.max(b2, extY + Math.max(oy2, 0));
3572
+ t = Math.max(t, extY + Math.max(-oy2, 0));
3573
+ }
3574
+ return { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b2), left: Math.ceil(l) };
3575
+ }
3576
+ function parseFilterBlur(cs) {
3577
+ const m = (cs.filter || "").match(/blur\(\s*([0-9.]+)px\s*\)/);
3578
+ const b2 = m ? Math.ceil(parseFloat(m[1]) || 0) : 0;
3579
+ return { top: b2, right: b2, bottom: b2, left: b2 };
3580
+ }
3581
+ function parseOutline(cs) {
3582
+ if ((cs.outlineStyle || "none") === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
3583
+ const w2 = Math.ceil(parseFloat(cs.outlineWidth || "0") || 0);
3584
+ return { top: w2, right: w2, bottom: w2, left: w2 };
3585
+ }
3586
+ function bboxWithOriginFull(w2, h2, M, ox2, oy2) {
3587
+ const a2 = M.a, b2 = M.b, c2 = M.c, d2 = M.d, e2 = M.e || 0, f2 = M.f || 0;
3588
+ function pt(x, y) {
3589
+ let X = x - ox2, Y = y - oy2;
3590
+ let X2 = a2 * X + c2 * Y, Y2 = b2 * X + d2 * Y;
3591
+ X2 += ox2 + e2;
3592
+ Y2 += oy2 + f2;
3593
+ return [X2, Y2];
3594
+ }
3595
+ const P = [pt(0, 0), pt(w2, 0), pt(0, h2), pt(w2, h2)];
3596
+ let minX2 = Infinity, minY2 = Infinity, maxX2 = -Infinity, maxY2 = -Infinity;
3597
+ for (const [X, Y] of P) {
3598
+ if (X < minX2) minX2 = X;
3599
+ if (Y < minY2) minY2 = Y;
3600
+ if (X > maxX2) maxX2 = X;
3601
+ if (Y > maxY2) maxY2 = Y;
3602
+ }
3603
+ return { minX: minX2, minY: minY2, maxX: maxX2, maxY: maxY2, width: maxX2 - minX2, height: maxY2 - minY2 };
3604
+ }
3605
+ function hasTFBBox(el) {
3606
+ return hasBBoxAffectingTransform(el);
3607
+ }
3235
3608
  function matrixFromComputed(el) {
3236
3609
  const tr = getComputedStyle(el).transform;
3237
3610
  if (!tr || tr === "none") return new DOMMatrix();
@@ -3373,7 +3746,7 @@
3373
3746
  return "soft";
3374
3747
  }
3375
3748
  function createContext(options = {}) {
3376
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
3749
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
3377
3750
  const resolvedFormat = (_a = options.format) != null ? _a : "png";
3378
3751
  const cachePolicy = normalizeCachePolicy(options.cache);
3379
3752
  return {
@@ -3386,20 +3759,20 @@
3386
3759
  excludeMode: (_f = options.excludeMode) != null ? _f : "hide",
3387
3760
  filter: (_g = options.filter) != null ? _g : null,
3388
3761
  filterMode: (_h = options.filterMode) != null ? _h : "hide",
3762
+ // Placeholders
3389
3763
  placeholders: options.placeholders !== false,
3390
3764
  // default true
3391
- // Fuentes
3765
+ // Fonts
3392
3766
  embedFonts: (_i = options.embedFonts) != null ? _i : false,
3393
3767
  iconFonts: Array.isArray(options.iconFonts) ? options.iconFonts : options.iconFonts ? [options.iconFonts] : [],
3394
3768
  localFonts: Array.isArray(options.localFonts) ? options.localFonts : [],
3395
3769
  excludeFonts: (_j = options.excludeFonts) != null ? _j : void 0,
3396
3770
  fallbackURL: (_k = options.fallbackURL) != null ? _k : void 0,
3397
- /** Cache policy (disabled|full|auto|soft). Default: "soft" */
3398
3771
  /** @type {CachePolicy} */
3399
3772
  cache: cachePolicy,
3400
- // Red
3773
+ // Network
3401
3774
  useProxy: typeof options.useProxy === "string" ? options.useProxy : "",
3402
- // Salida
3775
+ // Output
3403
3776
  width: (_l = options.width) != null ? _l : null,
3404
3777
  height: (_m = options.height) != null ? _m : null,
3405
3778
  format: resolvedFormat,
@@ -3407,8 +3780,11 @@
3407
3780
  quality: (_o = options.quality) != null ? _o : 0.92,
3408
3781
  dpr: (_p = options.dpr) != null ? _p : window.devicePixelRatio || 1,
3409
3782
  backgroundColor: (_q = options.backgroundColor) != null ? _q : ["jpg", "jpeg", "webp"].includes(resolvedFormat) ? "#ffffff" : null,
3410
- filename: (_r = options.filename) != null ? _r : "snapDOM"
3411
- // Plugins (reservado para futura activación)
3783
+ filename: (_r = options.filename) != null ? _r : "snapDOM",
3784
+ // NEW flags (user-friendly)
3785
+ straighten: (_s = options.straighten) != null ? _s : false,
3786
+ noShadows: (_t = options.noShadows) != null ? _t : false
3787
+ // Plugins (reservado)
3412
3788
  // plugins: normalizePlugins(...),
3413
3789
  };
3414
3790
  }
@@ -3603,9 +3979,20 @@
3603
3979
  const k = height / Math.max(1, refH);
3604
3980
  img.style.height = `${height}px`;
3605
3981
  img.style.width = `${Math.round(refW * k)}px`;
3606
- } else if (scale !== 1) {
3607
- img.style.width = `${Math.round(img.naturalWidth * scale)}px`;
3608
- img.style.height = `${Math.round(img.naturalHeight * scale)}px`;
3982
+ } else {
3983
+ const cssW = Math.round(img.naturalWidth * scale);
3984
+ const cssH = Math.round(img.naturalHeight * scale);
3985
+ img.style.width = `${cssW}px`;
3986
+ img.style.height = `${cssH}px`;
3987
+ if (typeof url === "string" && url.startsWith("data:image/svg+xml")) {
3988
+ try {
3989
+ const decoded = decodeURIComponent(url.split(",")[1]);
3990
+ const patched = decoded.replace(/width="[^"]*"/, `width="${cssW}"`).replace(/height="[^"]*"/, `height="${cssH}"`);
3991
+ url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(patched)}`;
3992
+ img.src = url;
3993
+ } catch (e) {
3994
+ }
3995
+ }
3609
3996
  }
3610
3997
  return img;
3611
3998
  });
@@ -3667,7 +4054,7 @@
3667
4054
  yield safariWarmup(element, userOptions);
3668
4055
  console.log("Iteraci\xF3n n\xFAmero:", i);
3669
4056
  _safariWarmup = false;
3670
- } catch (error) {
4057
+ } catch (e) {
3671
4058
  }
3672
4059
  }
3673
4060
  }
@@ -3675,7 +4062,7 @@
3675
4062
  if (!context.snap) {
3676
4063
  context.snap = {
3677
4064
  toPng: (el, opts) => snapdom.toPng(el, opts),
3678
- toImg: (el, opts) => snapdom.toImg(el, opts)
4065
+ toSvg: (el, opts) => snapdom.toSvg(el, opts)
3679
4066
  };
3680
4067
  }
3681
4068
  return snapdom.capture(element, context, INTERNAL_TOKEN);
@@ -3698,6 +4085,7 @@
3698
4085
  url,
3699
4086
  toRaw: () => url,
3700
4087
  toImg: (opts) => toImg(url, ensureContext(opts)),
4088
+ toSvg: (opts) => toImg(url, ensureContext(opts)),
3701
4089
  toCanvas: (opts) => toCanvas(url, ensureContext(opts)),
3702
4090
  toBlob: (opts) => toBlob(url, ensureContext(opts)),
3703
4091
  toPng: withFormat("png"),
@@ -3708,6 +4096,7 @@
3708
4096
  });
3709
4097
  snapdom.toRaw = (el, options) => snapdom(el, options).then((result) => result.toRaw());
3710
4098
  snapdom.toImg = (el, options) => snapdom(el, options).then((result) => result.toImg());
4099
+ snapdom.toSvg = (el, options) => snapdom(el, options).then((result) => result.toSvg());
3711
4100
  snapdom.toCanvas = (el, options) => snapdom(el, options).then((result) => result.toCanvas());
3712
4101
  snapdom.toBlob = (el, options) => snapdom(el, options).then((result) => result.toBlob());
3713
4102
  snapdom.toPng = (el, options) => snapdom(el, __spreadProps(__spreadValues({}, options), { format: "png" })).then((result) => result.toPng());
@@ -3849,7 +4238,7 @@
3849
4238
  const families = new Set(
3850
4239
  Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
3851
4240
  );
3852
- yield ensureFontsReady(families, 2);
4241
+ yield ensureFontsReady(families, 3);
3853
4242
  }
3854
4243
  yield embedCustomFonts({
3855
4244
  required,