@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/README.md +58 -27
- package/dist/snapdom.js +729 -340
- package/dist/snapdom.min.js +7 -4
- package/dist/snapdom.min.mjs +8 -5
- package/dist/snapdom.mjs +716 -335
- package/package.json +7 -2
- package/types/snapdom.d.ts +19 -1
package/dist/snapdom.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
3
|
* snapdom
|
|
4
|
-
* v.1.9.12-dev.
|
|
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 (
|
|
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 =
|
|
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((
|
|
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((
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1741
|
-
const u = m[
|
|
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
|
-
|
|
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("[
|
|
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
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
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("[
|
|
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("[
|
|
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 =
|
|
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 ||
|
|
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
|
|
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 ||
|
|
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,
|
|
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 (
|
|
3147
|
-
const
|
|
3148
|
-
const
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
3773
|
+
// Network
|
|
3401
3774
|
useProxy: typeof options.useProxy === "string" ? options.useProxy : "",
|
|
3402
|
-
//
|
|
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
|
-
//
|
|
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
|
|
3607
|
-
|
|
3608
|
-
|
|
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 (
|
|
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
|
-
|
|
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,
|
|
4241
|
+
yield ensureFontsReady(families, 3);
|
|
3853
4242
|
}
|
|
3854
4243
|
yield embedCustomFonts({
|
|
3855
4244
|
required,
|