@zumer/snapdom 2.0.0-dev.1 → 2.0.0-dev.2
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 +5 -2
- package/dist/snapdom.js +289 -60
- package/dist/snapdom.min.js +7 -7
- package/dist/snapdom.min.mjs +6 -6
- package/dist/snapdom.mjs +283 -60
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
</a>
|
|
30
30
|
</p>
|
|
31
31
|
|
|
32
|
+
<p align="center">English | <a href="README_CN.md">简体中文</a></p>
|
|
33
|
+
|
|
32
34
|
# snapDOM
|
|
33
35
|
|
|
34
36
|
**snapDOM** is a fast and accurate DOM-to-image capture tool built for **Zumly**, a zoom-based view transition framework.
|
|
@@ -751,6 +753,7 @@ For detailed contribution guidelines, please see [CONTRIBUTING](https://github.c
|
|
|
751
753
|
<a href="https://github.com/tinchox5" title="tinchox5"><img src="https://avatars.githubusercontent.com/u/11557901?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="tinchox5"/></a>
|
|
752
754
|
<a href="https://github.com/Jarvis2018" title="Jarvis2018"><img src="https://avatars.githubusercontent.com/u/36788851?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="Jarvis2018"/></a>
|
|
753
755
|
<a href="https://github.com/tarwin" title="tarwin"><img src="https://avatars.githubusercontent.com/u/646149?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="tarwin"/></a>
|
|
756
|
+
<a href="https://github.com/jswhisperer" title="jswhisperer"><img src="https://avatars.githubusercontent.com/u/1177690?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="jswhisperer"/></a>
|
|
754
757
|
<a href="https://github.com/K1ender" title="K1ender"><img src="https://avatars.githubusercontent.com/u/146767945?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="K1ender"/></a>
|
|
755
758
|
<a href="https://github.com/17biubiu" title="17biubiu"><img src="https://avatars.githubusercontent.com/u/13295895?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="17biubiu"/></a>
|
|
756
759
|
<a href="https://github.com/av01d" title="av01d"><img src="https://avatars.githubusercontent.com/u/6247646?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="av01d"/></a>
|
|
@@ -758,7 +761,7 @@ For detailed contribution guidelines, please see [CONTRIBUTING](https://github.c
|
|
|
758
761
|
<a href="https://github.com/pedrocateexte" title="pedrocateexte"><img src="https://avatars.githubusercontent.com/u/207524750?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="pedrocateexte"/></a>
|
|
759
762
|
<a href="https://github.com/domialex" title="domialex"><img src="https://avatars.githubusercontent.com/u/4694217?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="domialex"/></a>
|
|
760
763
|
<a href="https://github.com/elliots" title="elliots"><img src="https://avatars.githubusercontent.com/u/622455?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="elliots"/></a>
|
|
761
|
-
<a href="https://github.com/
|
|
764
|
+
<a href="https://github.com/mon-jai" title="mon-jai"><img src="https://avatars.githubusercontent.com/u/91261297?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="mon-jai"/></a>
|
|
762
765
|
<a href="https://github.com/sharuzzaman" title="sharuzzaman"><img src="https://avatars.githubusercontent.com/u/7421941?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="sharuzzaman"/></a>
|
|
763
766
|
<a href="https://github.com/simon1uo" title="simon1uo"><img src="https://avatars.githubusercontent.com/u/60037549?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="simon1uo"/></a>
|
|
764
767
|
<a href="https://github.com/titoBouzout" title="titoBouzout"><img src="https://avatars.githubusercontent.com/u/64156?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="titoBouzout"/></a>
|
|
@@ -784,4 +787,4 @@ If you'd like to support this project too, you can [become a sponsor](https://gi
|
|
|
784
787
|
|
|
785
788
|
## License
|
|
786
789
|
|
|
787
|
-
MIT © Zumerlab
|
|
790
|
+
MIT © Zumerlab
|
package/dist/snapdom.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
3
|
* snapdom
|
|
4
|
-
* v.2.0.0-dev.
|
|
4
|
+
* v.2.0.0-dev.2
|
|
5
5
|
* Author Juan Martin Muda
|
|
6
6
|
* License MIT
|
|
7
7
|
**/
|
|
@@ -374,19 +374,6 @@
|
|
|
374
374
|
}
|
|
375
375
|
|
|
376
376
|
// src/utils/image.js
|
|
377
|
-
function createBackground(baseCanvas, backgroundColor) {
|
|
378
|
-
if (!backgroundColor || !baseCanvas.width || !baseCanvas.height) {
|
|
379
|
-
return baseCanvas;
|
|
380
|
-
}
|
|
381
|
-
const temp = document.createElement("canvas");
|
|
382
|
-
temp.width = baseCanvas.width;
|
|
383
|
-
temp.height = baseCanvas.height;
|
|
384
|
-
const ctx = temp.getContext("2d");
|
|
385
|
-
ctx.fillStyle = backgroundColor;
|
|
386
|
-
ctx.fillRect(0, 0, temp.width, temp.height);
|
|
387
|
-
ctx.drawImage(baseCanvas, 0, 0);
|
|
388
|
-
return temp;
|
|
389
|
-
}
|
|
390
377
|
function inlineSingleBackgroundEntry(_0) {
|
|
391
378
|
return __async(this, arguments, function* (entry, options = {}) {
|
|
392
379
|
const isGradient = /^((repeating-)?(linear|radial|conic)-gradient)\(/i.test(entry);
|
|
@@ -664,11 +651,20 @@
|
|
|
664
651
|
}
|
|
665
652
|
}
|
|
666
653
|
function isSafari() {
|
|
667
|
-
|
|
668
|
-
const
|
|
669
|
-
const
|
|
670
|
-
const
|
|
671
|
-
|
|
654
|
+
if (typeof navigator === "undefined") return false;
|
|
655
|
+
const ua = navigator.userAgent || "";
|
|
656
|
+
const uaLower = ua.toLowerCase();
|
|
657
|
+
const isSafariUA = uaLower.includes("safari") && !uaLower.includes("chrome") && !uaLower.includes("crios") && // Chrome on iOS
|
|
658
|
+
!uaLower.includes("fxios") && // Firefox on iOS
|
|
659
|
+
!uaLower.includes("android");
|
|
660
|
+
const isWebKit = /applewebkit/i.test(ua);
|
|
661
|
+
const isMobile = /mobile/i.test(ua);
|
|
662
|
+
const missingSafariToken = !/safari/i.test(ua);
|
|
663
|
+
const isUIWebView = isWebKit && isMobile && missingSafariToken;
|
|
664
|
+
const isWeChatUA = /(micromessenger|wxwork|wecom|windowswechat|macwechat)/i.test(ua);
|
|
665
|
+
const isBaiduUA = /(baiduboxapp|baidubrowser|baidusearch|baiduboxlite)/i.test(uaLower);
|
|
666
|
+
const isIOSWebKit = /ipad|iphone|ipod/.test(uaLower) && isWebKit;
|
|
667
|
+
return isSafariUA || isUIWebView || isWeChatUA || isBaiduUA || isIOSWebKit;
|
|
672
668
|
}
|
|
673
669
|
|
|
674
670
|
// src/modules/styles.js
|
|
@@ -714,6 +710,22 @@
|
|
|
714
710
|
}
|
|
715
711
|
out[prop] = val;
|
|
716
712
|
}
|
|
713
|
+
const EXTRA_TEXT_DECORATION_PROPS = [
|
|
714
|
+
"text-decoration-line",
|
|
715
|
+
"text-decoration-color",
|
|
716
|
+
"text-decoration-style",
|
|
717
|
+
"text-decoration-thickness",
|
|
718
|
+
"text-underline-offset",
|
|
719
|
+
"text-decoration-skip-ink"
|
|
720
|
+
];
|
|
721
|
+
for (const prop of EXTRA_TEXT_DECORATION_PROPS) {
|
|
722
|
+
if (out[prop]) continue;
|
|
723
|
+
try {
|
|
724
|
+
const v = style.getPropertyValue(prop);
|
|
725
|
+
if (v) out[prop] = v;
|
|
726
|
+
} catch (e) {
|
|
727
|
+
}
|
|
728
|
+
}
|
|
717
729
|
if (options.embedFonts) {
|
|
718
730
|
const EXTRA_FONT_PROPS = [
|
|
719
731
|
"font-feature-settings",
|
|
@@ -1482,17 +1494,19 @@
|
|
|
1482
1494
|
/layui/i,
|
|
1483
1495
|
/lucide/i
|
|
1484
1496
|
];
|
|
1497
|
+
var ICON_FONT_URLS = Object.assign({
|
|
1498
|
+
materialIconsFilled: "https://fonts.gstatic.com/s/materialicons/v48/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2",
|
|
1499
|
+
materialIconsOutlined: "https://fonts.gstatic.com/s/materialiconsoutlined/v110/gok-H7zzDkdnRel8-DQ6KAXJ69wP1tGnf4ZGhUcel5euIg.woff2",
|
|
1500
|
+
materialIconsRound: "https://fonts.gstatic.com/s/materialiconsround/v109/LDItaoyNOAY6Uewc665JcIzCKsKc_M9flwmPq_HTTw.woff2",
|
|
1501
|
+
materialIconsSharp: "https://fonts.gstatic.com/s/materialiconssharp/v110/oPWQ_lt5nv4pWNJpghLP75WiFR4kLh3kvmvRImcycg.woff2"
|
|
1502
|
+
}, typeof window !== "undefined" && window.__SNAPDOM_ICON_FONTS__ || {});
|
|
1485
1503
|
var userIconFonts = [];
|
|
1486
1504
|
function extendIconFonts(fonts) {
|
|
1487
1505
|
const list = Array.isArray(fonts) ? fonts : [fonts];
|
|
1488
1506
|
for (const f of list) {
|
|
1489
|
-
if (f instanceof RegExp)
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
userIconFonts.push(new RegExp(f, "i"));
|
|
1493
|
-
} else {
|
|
1494
|
-
console.warn("[snapdom] Ignored invalid iconFont value:", f);
|
|
1495
|
-
}
|
|
1507
|
+
if (f instanceof RegExp) userIconFonts.push(f);
|
|
1508
|
+
else if (typeof f === "string") userIconFonts.push(new RegExp(f, "i"));
|
|
1509
|
+
else console.warn("[snapdom] Ignored invalid iconFont value:", f);
|
|
1496
1510
|
}
|
|
1497
1511
|
}
|
|
1498
1512
|
function isIconFont2(input) {
|
|
@@ -1508,11 +1522,66 @@
|
|
|
1508
1522
|
const s = String(family).toLowerCase();
|
|
1509
1523
|
return /\bmaterial\s*icons\b/.test(s) || /\bmaterial\s*symbols\b/.test(s);
|
|
1510
1524
|
}
|
|
1525
|
+
var loadedCanvasFamilies = /* @__PURE__ */ new Map();
|
|
1526
|
+
function parseAxes(variation = "") {
|
|
1527
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
1528
|
+
const v = String(variation || "");
|
|
1529
|
+
const rx = /['"]?\s*([A-Za-z]{3,4})\s*['"]?\s*([+-]?\d+(?:\.\d+)?)\s*/g;
|
|
1530
|
+
let m;
|
|
1531
|
+
while (m = rx.exec(v)) out[m[1].toUpperCase()] = Number(m[2]);
|
|
1532
|
+
return out;
|
|
1533
|
+
}
|
|
1534
|
+
function ensureLigatureCanvasFont(cssFamily, className, axes) {
|
|
1535
|
+
return __async(this, null, function* () {
|
|
1536
|
+
var _a;
|
|
1537
|
+
const fam = String(cssFamily || "");
|
|
1538
|
+
const lowerFam = fam.toLowerCase();
|
|
1539
|
+
const cls = String(className || "").toLowerCase();
|
|
1540
|
+
if (/\bmaterial\s*icons\b/.test(lowerFam) && !/\bsymbols\b/.test(lowerFam)) {
|
|
1541
|
+
return { familyForMeasure: fam, familyForCanvas: fam };
|
|
1542
|
+
}
|
|
1543
|
+
const isSymbols = /\bmaterial\s*symbols\b/.test(lowerFam);
|
|
1544
|
+
if (!isSymbols) {
|
|
1545
|
+
return { familyForMeasure: fam, familyForCanvas: fam };
|
|
1546
|
+
}
|
|
1547
|
+
const FILL = axes && ((_a = axes.FILL) != null ? _a : axes.fill);
|
|
1548
|
+
let style = "outlined";
|
|
1549
|
+
if (/\brounded\b/.test(cls) || /\bround\b/.test(cls)) style = "rounded";
|
|
1550
|
+
else if (/\bsharp\b/.test(cls)) style = "sharp";
|
|
1551
|
+
else if (/\boutlined\b/.test(cls)) style = "outlined";
|
|
1552
|
+
const filled = FILL === 1;
|
|
1553
|
+
let pick = null;
|
|
1554
|
+
if (filled) {
|
|
1555
|
+
if (style === "outlined" && ICON_FONT_URLS.materialIconsFilled) {
|
|
1556
|
+
pick = { url: ICON_FONT_URLS.materialIconsFilled, alias: "snapdom-mi-filled" };
|
|
1557
|
+
} else if (style === "rounded" && ICON_FONT_URLS.materialIconsRound) {
|
|
1558
|
+
pick = { url: ICON_FONT_URLS.materialIconsRound, alias: "snapdom-mi-round" };
|
|
1559
|
+
} else if (style === "sharp" && ICON_FONT_URLS.materialIconsSharp) {
|
|
1560
|
+
pick = { url: ICON_FONT_URLS.materialIconsSharp, alias: "snapdom-mi-sharp" };
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
if (!pick) {
|
|
1564
|
+
return { familyForMeasure: fam, familyForCanvas: fam };
|
|
1565
|
+
}
|
|
1566
|
+
if (!loadedCanvasFamilies.has(pick.alias)) {
|
|
1567
|
+
try {
|
|
1568
|
+
const ff = new FontFace(pick.alias, `url(${pick.url})`, { style: "normal", weight: "400" });
|
|
1569
|
+
document.fonts.add(ff);
|
|
1570
|
+
yield ff.load();
|
|
1571
|
+
loadedCanvasFamilies.set(pick.alias, true);
|
|
1572
|
+
} catch (e) {
|
|
1573
|
+
return { familyForMeasure: fam, familyForCanvas: fam };
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
const quoted = `"${pick.alias}"`;
|
|
1577
|
+
return { familyForMeasure: quoted, familyForCanvas: quoted };
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1511
1580
|
function ensureMaterialFontsReady(family = "Material Icons", px = 24) {
|
|
1512
1581
|
return __async(this, null, function* () {
|
|
1513
1582
|
try {
|
|
1514
1583
|
yield Promise.all([
|
|
1515
|
-
document.fonts.load(`400 ${px}px "${family.replace(/["']/g, "")}"`),
|
|
1584
|
+
document.fonts.load(`400 ${px}px "${String(family).replace(/["']/g, "")}"`),
|
|
1516
1585
|
document.fonts.ready
|
|
1517
1586
|
]);
|
|
1518
1587
|
} catch (e) {
|
|
@@ -1522,10 +1591,8 @@
|
|
|
1522
1591
|
function resolvePaintColor(cs) {
|
|
1523
1592
|
var _a, _b;
|
|
1524
1593
|
let fill = ((_a = cs.getPropertyValue("-webkit-text-fill-color")) == null ? void 0 : _a.trim()) || "";
|
|
1525
|
-
const isTransparent = /rgba?\(\s*0\s*,\s*0\s*,\s*0\s*,\s*0\s*\)/i.test(fill);
|
|
1526
|
-
if (fill && !isTransparent && fill.toLowerCase() !== "currentcolor")
|
|
1527
|
-
return fill;
|
|
1528
|
-
}
|
|
1594
|
+
const isTransparent = /^transparent$/i.test(fill) || /rgba?\(\s*0\s*,\s*0\s*,\s*0\s*,\s*0\s*\)/i.test(fill);
|
|
1595
|
+
if (fill && !isTransparent && fill.toLowerCase() !== "currentcolor") return fill;
|
|
1529
1596
|
const c = (_b = cs.color) == null ? void 0 : _b.trim();
|
|
1530
1597
|
return c && c !== "inherit" ? c : "#000";
|
|
1531
1598
|
}
|
|
@@ -1535,18 +1602,21 @@
|
|
|
1535
1602
|
weight = "normal",
|
|
1536
1603
|
fontSize = 32,
|
|
1537
1604
|
color = "#000",
|
|
1538
|
-
variation = ""
|
|
1605
|
+
variation = "",
|
|
1606
|
+
className = ""
|
|
1539
1607
|
} = {}) {
|
|
1540
1608
|
const fam = String(family || "").replace(/^['"]+|['"]+$/g, "");
|
|
1541
1609
|
const dpr = window.devicePixelRatio || 1;
|
|
1542
|
-
|
|
1610
|
+
const axes = parseAxes(variation);
|
|
1611
|
+
const { familyForMeasure, familyForCanvas } = yield ensureLigatureCanvasFont(fam, className, axes);
|
|
1612
|
+
yield ensureMaterialFontsReady(familyForCanvas.replace(/^["']+|["']+$/g, ""), fontSize);
|
|
1543
1613
|
const span = document.createElement("span");
|
|
1544
1614
|
span.textContent = ligatureText;
|
|
1545
1615
|
span.style.position = "absolute";
|
|
1546
1616
|
span.style.visibility = "hidden";
|
|
1547
1617
|
span.style.left = "-99999px";
|
|
1548
1618
|
span.style.whiteSpace = "nowrap";
|
|
1549
|
-
span.style.fontFamily =
|
|
1619
|
+
span.style.fontFamily = familyForMeasure;
|
|
1550
1620
|
span.style.fontWeight = String(weight || "normal");
|
|
1551
1621
|
span.style.fontSize = `${fontSize}px`;
|
|
1552
1622
|
span.style.lineHeight = "1";
|
|
@@ -1554,7 +1624,6 @@
|
|
|
1554
1624
|
span.style.padding = "0";
|
|
1555
1625
|
span.style.fontFeatureSettings = "'liga' 1";
|
|
1556
1626
|
span.style.fontVariantLigatures = "normal";
|
|
1557
|
-
if (variation) span.style.fontVariationSettings = variation;
|
|
1558
1627
|
span.style.color = color;
|
|
1559
1628
|
document.body.appendChild(span);
|
|
1560
1629
|
const rect = span.getBoundingClientRect();
|
|
@@ -1566,7 +1635,7 @@
|
|
|
1566
1635
|
canvas.height = height * dpr;
|
|
1567
1636
|
const ctx = canvas.getContext("2d");
|
|
1568
1637
|
ctx.scale(dpr, dpr);
|
|
1569
|
-
ctx.font = `${weight ? `${weight} ` : ""}${fontSize}px
|
|
1638
|
+
ctx.font = `${weight ? `${weight} ` : ""}${fontSize}px ${familyForCanvas}`;
|
|
1570
1639
|
ctx.textAlign = "left";
|
|
1571
1640
|
ctx.textBaseline = "top";
|
|
1572
1641
|
ctx.fillStyle = color;
|
|
@@ -1596,21 +1665,23 @@
|
|
|
1596
1665
|
const el = cloneNodes[i];
|
|
1597
1666
|
const src = sourceNodes[i] || null;
|
|
1598
1667
|
try {
|
|
1599
|
-
const
|
|
1600
|
-
const family =
|
|
1668
|
+
const cs = src ? getComputedStyle(src) : getComputedStyle(el);
|
|
1669
|
+
const family = cs.fontFamily || "Material Icons";
|
|
1601
1670
|
if (!isMaterialFamily(family)) continue;
|
|
1602
1671
|
const text = (src || el).textContent.trim();
|
|
1603
1672
|
if (!text) continue;
|
|
1604
|
-
const size = parseInt(
|
|
1605
|
-
const weight =
|
|
1606
|
-
const color = resolvePaintColor(
|
|
1607
|
-
const variation =
|
|
1673
|
+
const size = parseInt(cs.fontSize, 10) || 24;
|
|
1674
|
+
const weight = cs.fontWeight && cs.fontWeight !== "normal" ? cs.fontWeight : "normal";
|
|
1675
|
+
const color = resolvePaintColor(cs);
|
|
1676
|
+
const variation = cs.fontVariationSettings && cs.fontVariationSettings !== "normal" ? cs.fontVariationSettings : "";
|
|
1677
|
+
const className = (src || el).className || "";
|
|
1608
1678
|
const { dataUrl, width, height } = yield materialIconToImage(text, {
|
|
1609
1679
|
family,
|
|
1610
1680
|
weight,
|
|
1611
1681
|
fontSize: size,
|
|
1612
1682
|
color,
|
|
1613
|
-
variation
|
|
1683
|
+
variation,
|
|
1684
|
+
className
|
|
1614
1685
|
});
|
|
1615
1686
|
el.textContent = "";
|
|
1616
1687
|
const img = el.ownerDocument.createElement("img");
|
|
@@ -1988,7 +2059,7 @@ ${imported}
|
|
|
1988
2059
|
const styleSpec = (((_c = block.match(/font-style:\s*([^;]+);/i)) == null ? void 0 : _c[1]) || "normal").trim();
|
|
1989
2060
|
const stretchSpec = (((_d = block.match(/font-stretch:\s*([^;]+);/i)) == null ? void 0 : _d[1]) || "100%").trim();
|
|
1990
2061
|
const urange = (((_e = block.match(/unicode-range:\s*([^;]+);/i)) == null ? void 0 : _e[1]) || "").trim();
|
|
1991
|
-
const srcRaw = (((_f = block.match(/src\s*:\s*([^;]+)
|
|
2062
|
+
const srcRaw = (((_f = block.match(/src\s*:\s*([^;}]+)[;}]/i)) == null ? void 0 : _f[1]) || "").trim();
|
|
1992
2063
|
const urls = extractSrcUrls(srcRaw, location.href);
|
|
1993
2064
|
const srcPart = urls.length ? urls.map((u) => String(u).toLowerCase()).sort().join("|") : srcRaw.toLowerCase();
|
|
1994
2065
|
const key = [
|
|
@@ -2200,7 +2271,7 @@ ${imported}
|
|
|
2200
2271
|
const styleSpec = (((_d = face.match(/font-style:\s*([^;]+);/i)) == null ? void 0 : _d[1]) || "normal").trim();
|
|
2201
2272
|
const stretchSpec = (((_e = face.match(/font-stretch:\s*([^;]+);/i)) == null ? void 0 : _e[1]) || "100%").trim();
|
|
2202
2273
|
const urange = (((_f = face.match(/unicode-range:\s*([^;]+);/i)) == null ? void 0 : _f[1]) || "").trim();
|
|
2203
|
-
const srcRaw = (((_g = face.match(/src\s*:\s*([^;]+)
|
|
2274
|
+
const srcRaw = (((_g = face.match(/src\s*:\s*([^;}]+)[;}]/i)) == null ? void 0 : _g[1]) || "").trim();
|
|
2204
2275
|
const srcUrls = extractSrcUrls(srcRaw, link.href);
|
|
2205
2276
|
if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
|
|
2206
2277
|
const ranges = parseUnicodeRange(urange);
|
|
@@ -3682,8 +3753,53 @@ ${imported}
|
|
|
3682
3753
|
} catch (e) {
|
|
3683
3754
|
}
|
|
3684
3755
|
}
|
|
3756
|
+
function removeAllComments(root) {
|
|
3757
|
+
const it = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);
|
|
3758
|
+
const toRemove = [];
|
|
3759
|
+
while (it.nextNode()) toRemove.push(it.currentNode);
|
|
3760
|
+
for (const n of toRemove) n.remove();
|
|
3761
|
+
}
|
|
3762
|
+
function sanitizeAttributesForXHTML(root, opts = {}) {
|
|
3763
|
+
const { stripFrameworkDirectives = true } = opts;
|
|
3764
|
+
const ALLOWED_PREFIXES = /* @__PURE__ */ new Set(["xml", "xlink"]);
|
|
3765
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
3766
|
+
while (walker.nextNode()) {
|
|
3767
|
+
const el = walker.currentNode;
|
|
3768
|
+
for (const attr of Array.from(el.attributes)) {
|
|
3769
|
+
const name = attr.name;
|
|
3770
|
+
if (name.includes("@")) {
|
|
3771
|
+
el.removeAttribute(name);
|
|
3772
|
+
continue;
|
|
3773
|
+
}
|
|
3774
|
+
if (name.includes(":")) {
|
|
3775
|
+
const prefix = name.split(":", 1)[0];
|
|
3776
|
+
if (!ALLOWED_PREFIXES.has(prefix)) {
|
|
3777
|
+
el.removeAttribute(name);
|
|
3778
|
+
continue;
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
if (!stripFrameworkDirectives) continue;
|
|
3782
|
+
if (name.startsWith("x-") || // Alpine
|
|
3783
|
+
name.startsWith("v-") || // Vue
|
|
3784
|
+
name.startsWith(":") || // Vue/Alpine shorthand
|
|
3785
|
+
name.startsWith("on:") || // Svelte
|
|
3786
|
+
name.startsWith("bind:") || // Svelte
|
|
3787
|
+
name.startsWith("let:") || // Svelte
|
|
3788
|
+
name.startsWith("class:")) {
|
|
3789
|
+
el.removeAttribute(name);
|
|
3790
|
+
continue;
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
function sanitizeCloneForXHTML(root, opts = {}) {
|
|
3796
|
+
if (!root) return;
|
|
3797
|
+
sanitizeAttributesForXHTML(root, opts);
|
|
3798
|
+
removeAllComments(root);
|
|
3799
|
+
}
|
|
3685
3800
|
function captureDOM(element, options) {
|
|
3686
3801
|
return __async(this, null, function* () {
|
|
3802
|
+
var _a;
|
|
3687
3803
|
if (!element) throw new Error("Element cannot be null or undefined");
|
|
3688
3804
|
applyCachePolicy(options.cache);
|
|
3689
3805
|
const fast = options.fast;
|
|
@@ -3712,6 +3828,14 @@ ${imported}
|
|
|
3712
3828
|
}
|
|
3713
3829
|
state = __spreadValues({ clone, classCSS, styleCache }, state);
|
|
3714
3830
|
yield runHook("afterClone", state);
|
|
3831
|
+
sanitizeCloneForXHTML(state.clone);
|
|
3832
|
+
if (((_a = state.options) == null ? void 0 : _a.excludeMode) === "remove") {
|
|
3833
|
+
try {
|
|
3834
|
+
shrinkAutoSizeBoxes(state.element, state.clone, state.styleCache);
|
|
3835
|
+
} catch (e) {
|
|
3836
|
+
console.warn("[snapdom] shrink pass failed:", e);
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3715
3839
|
try {
|
|
3716
3840
|
yield ligatureIconToImage(state.clone, state.element);
|
|
3717
3841
|
} catch (e) {
|
|
@@ -3767,10 +3891,18 @@ ${imported}
|
|
|
3767
3891
|
yield runHook("beforeRender", state);
|
|
3768
3892
|
yield new Promise((resolve) => {
|
|
3769
3893
|
idle(() => {
|
|
3894
|
+
var _a2;
|
|
3770
3895
|
const csEl = getComputedStyle(state.element);
|
|
3771
3896
|
const rect = state.element.getBoundingClientRect();
|
|
3772
|
-
|
|
3773
|
-
|
|
3897
|
+
let w0 = Math.max(1, limitDecimals(state.element.offsetWidth || parseFloat(csEl.width) || rect.width || 1));
|
|
3898
|
+
let h0 = Math.max(1, limitDecimals(state.element.offsetHeight || parseFloat(csEl.height) || rect.height || 1));
|
|
3899
|
+
if (((_a2 = state.options) == null ? void 0 : _a2.excludeMode) === "remove") {
|
|
3900
|
+
const hEst = estimateKeptHeight(state.element, state.options);
|
|
3901
|
+
const EPS = 1;
|
|
3902
|
+
if (Number.isFinite(hEst) && hEst > 0) {
|
|
3903
|
+
h0 = Math.max(1, Math.min(h0, limitDecimals(hEst + EPS)));
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3774
3906
|
const coerceNum = (v, def = NaN) => {
|
|
3775
3907
|
const n = typeof v === "string" ? parseFloat(v) : v;
|
|
3776
3908
|
return Number.isFinite(n) ? n : def;
|
|
@@ -3894,6 +4026,58 @@ ${imported}
|
|
|
3894
4026
|
return state.dataURL;
|
|
3895
4027
|
});
|
|
3896
4028
|
}
|
|
4029
|
+
function authorHasExplicitSize(el) {
|
|
4030
|
+
var _a;
|
|
4031
|
+
try {
|
|
4032
|
+
const s = ((_a = el.getAttribute) == null ? void 0 : _a.call(el, "style")) || "";
|
|
4033
|
+
return /\b(height|width|block-size|inline-size)\s*:/.test(s);
|
|
4034
|
+
} catch (e) {
|
|
4035
|
+
return false;
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
function isReplacedElement(el) {
|
|
4039
|
+
return el instanceof HTMLImageElement || el instanceof HTMLCanvasElement || el instanceof HTMLVideoElement || el instanceof HTMLIFrameElement || el instanceof SVGElement || el instanceof HTMLObjectElement || el instanceof HTMLEmbedElement;
|
|
4040
|
+
}
|
|
4041
|
+
function shouldShrinkBox(srcEl, cs) {
|
|
4042
|
+
if (!(srcEl instanceof Element)) return false;
|
|
4043
|
+
if (authorHasExplicitSize(srcEl)) return false;
|
|
4044
|
+
if (isReplacedElement(srcEl)) return false;
|
|
4045
|
+
const pos = cs.position;
|
|
4046
|
+
if (pos === "absolute" || pos === "fixed" || pos === "sticky") return false;
|
|
4047
|
+
const disp = cs.display || "";
|
|
4048
|
+
if (disp.includes("flex") || disp.includes("grid") || disp.startsWith("table")) return false;
|
|
4049
|
+
if (cs.transform && cs.transform !== "none") return false;
|
|
4050
|
+
return true;
|
|
4051
|
+
}
|
|
4052
|
+
function shrinkAutoSizeBoxes(sourceRoot, cloneRoot, styleCache = /* @__PURE__ */ new Map()) {
|
|
4053
|
+
function walk(src, cln) {
|
|
4054
|
+
if (!(src instanceof Element) || !(cln instanceof Element)) return;
|
|
4055
|
+
const lostKids = src.childElementCount > cln.childElementCount;
|
|
4056
|
+
const cs = styleCache.get(src) || getComputedStyle(src);
|
|
4057
|
+
if (!styleCache.has(src)) styleCache.set(src, cs);
|
|
4058
|
+
if (lostKids && shouldShrinkBox(src, cs)) {
|
|
4059
|
+
if (!cln.style.height) cln.style.height = "auto";
|
|
4060
|
+
if (!cln.style.width) cln.style.width = "auto";
|
|
4061
|
+
cln.style.removeProperty("block-size");
|
|
4062
|
+
cln.style.removeProperty("inline-size");
|
|
4063
|
+
if (!cln.style.minHeight) cln.style.minHeight = "0";
|
|
4064
|
+
if (!cln.style.minWidth) cln.style.minWidth = "0";
|
|
4065
|
+
if (!cln.style.maxHeight) cln.style.maxHeight = "none";
|
|
4066
|
+
if (!cln.style.maxWidth) cln.style.maxWidth = "none";
|
|
4067
|
+
const oy = cs.overflowY || cs.overflowBlock || "visible";
|
|
4068
|
+
const ox = cs.overflowX || cs.overflowInline || "visible";
|
|
4069
|
+
if (oy !== "visible" || ox !== "visible") {
|
|
4070
|
+
cln.style.overflow = "visible";
|
|
4071
|
+
}
|
|
4072
|
+
}
|
|
4073
|
+
const sKids = Array.from(src.children);
|
|
4074
|
+
const cKids = Array.from(cln.children);
|
|
4075
|
+
for (let i = 0; i < Math.min(sKids.length, cKids.length); i++) {
|
|
4076
|
+
walk(sKids[i], cKids[i]);
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4079
|
+
walk(sourceRoot, cloneRoot);
|
|
4080
|
+
}
|
|
3897
4081
|
var limitDecimals = (v, n = 3) => Number.isFinite(v) ? Math.round(v * __pow(10, n)) / __pow(10, n) : v;
|
|
3898
4082
|
function parseFilterDropShadows(cs) {
|
|
3899
4083
|
var _a;
|
|
@@ -4163,6 +4347,52 @@ ${imported}
|
|
|
4163
4347
|
host.removeChild(tmp);
|
|
4164
4348
|
return M;
|
|
4165
4349
|
}
|
|
4350
|
+
function isInNormalFlow(el) {
|
|
4351
|
+
const cs = getComputedStyle(el);
|
|
4352
|
+
if (cs.display === "none") return false;
|
|
4353
|
+
if (cs.position === "absolute" || cs.position === "fixed" || cs.position === "sticky") return false;
|
|
4354
|
+
if ((cs.cssFloat || cs.float || "none") !== "none") return false;
|
|
4355
|
+
if (cs.transform && cs.transform !== "none") return false;
|
|
4356
|
+
return true;
|
|
4357
|
+
}
|
|
4358
|
+
function willBeExcluded(el, options) {
|
|
4359
|
+
if (!(el instanceof Element)) return false;
|
|
4360
|
+
if (el.getAttribute("data-capture") === "exclude" && (options == null ? void 0 : options.excludeMode) === "remove") return true;
|
|
4361
|
+
if (Array.isArray(options == null ? void 0 : options.exclude)) {
|
|
4362
|
+
for (const sel of options.exclude) {
|
|
4363
|
+
try {
|
|
4364
|
+
if (el.matches(sel)) return options.excludeMode === "remove";
|
|
4365
|
+
} catch (e) {
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
}
|
|
4369
|
+
return false;
|
|
4370
|
+
}
|
|
4371
|
+
function estimateKeptHeight(container, options) {
|
|
4372
|
+
const csC = getComputedStyle(container);
|
|
4373
|
+
const rC = container.getBoundingClientRect();
|
|
4374
|
+
let minTop = Infinity;
|
|
4375
|
+
let maxBottom = -Infinity;
|
|
4376
|
+
let found = false;
|
|
4377
|
+
const kids = Array.from(container.children);
|
|
4378
|
+
for (const k of kids) {
|
|
4379
|
+
if (willBeExcluded(k, options)) continue;
|
|
4380
|
+
if (!isInNormalFlow(k)) continue;
|
|
4381
|
+
const rk = k.getBoundingClientRect();
|
|
4382
|
+
const top = rk.top - rC.top;
|
|
4383
|
+
const bottom = rk.bottom - rC.top;
|
|
4384
|
+
if (bottom <= top) continue;
|
|
4385
|
+
if (top < minTop) minTop = top;
|
|
4386
|
+
if (bottom > maxBottom) maxBottom = bottom;
|
|
4387
|
+
found = true;
|
|
4388
|
+
}
|
|
4389
|
+
const contentSpan = found ? Math.max(0, maxBottom - minTop) : 0;
|
|
4390
|
+
const bt = parseFloat(csC.borderTopWidth) || 0;
|
|
4391
|
+
const bb = parseFloat(csC.borderBottomWidth) || 0;
|
|
4392
|
+
const pt = parseFloat(csC.paddingTop) || 0;
|
|
4393
|
+
const pb = parseFloat(csC.paddingBottom) || 0;
|
|
4394
|
+
return bt + bb + pt + pb + contentSpan;
|
|
4395
|
+
}
|
|
4166
4396
|
|
|
4167
4397
|
// src/core/context.js
|
|
4168
4398
|
function normalizeCachePolicy(v) {
|
|
@@ -4321,7 +4551,7 @@ ${imported}
|
|
|
4321
4551
|
}
|
|
4322
4552
|
function toCanvas(url, options) {
|
|
4323
4553
|
return __async(this, null, function* () {
|
|
4324
|
-
let { width: optW, height: optH, scale = 1, dpr = 1, meta = {} } = options;
|
|
4554
|
+
let { width: optW, height: optH, scale = 1, dpr = 1, meta = {}, backgroundColor } = options;
|
|
4325
4555
|
url = maybeConvertBoxShadowForSafari(url);
|
|
4326
4556
|
const img = new Image();
|
|
4327
4557
|
img.loading = "eager";
|
|
@@ -4360,6 +4590,12 @@ ${imported}
|
|
|
4360
4590
|
canvas.style.height = `${outH}px`;
|
|
4361
4591
|
const ctx = canvas.getContext("2d");
|
|
4362
4592
|
if (dpr !== 1) ctx.scale(dpr, dpr);
|
|
4593
|
+
if (backgroundColor) {
|
|
4594
|
+
ctx.save();
|
|
4595
|
+
ctx.fillStyle = backgroundColor;
|
|
4596
|
+
ctx.fillRect(0, 0, outW, outH);
|
|
4597
|
+
ctx.restore();
|
|
4598
|
+
}
|
|
4363
4599
|
ctx.drawImage(img, 0, 0, outW, outH);
|
|
4364
4600
|
return canvas;
|
|
4365
4601
|
});
|
|
@@ -4369,12 +4605,11 @@ ${imported}
|
|
|
4369
4605
|
function rasterize(url, options) {
|
|
4370
4606
|
return __async(this, null, function* () {
|
|
4371
4607
|
const canvas = yield toCanvas(url, options);
|
|
4372
|
-
const finalCanvas = options.backgroundColor ? createBackground(canvas, options.backgroundColor) : canvas;
|
|
4373
4608
|
const img = new Image();
|
|
4374
|
-
img.src =
|
|
4609
|
+
img.src = canvas.toDataURL(`image/${options.format}`, options.quality);
|
|
4375
4610
|
yield img.decode();
|
|
4376
|
-
img.style.width = `${
|
|
4377
|
-
img.style.height = `${
|
|
4611
|
+
img.style.width = `${canvas.width / options.dpr}px`;
|
|
4612
|
+
img.style.height = `${canvas.height / options.dpr}px`;
|
|
4378
4613
|
return img;
|
|
4379
4614
|
});
|
|
4380
4615
|
}
|
|
@@ -4438,13 +4673,8 @@ ${imported}
|
|
|
4438
4673
|
return new Blob([svgText], { type: "image/svg+xml" });
|
|
4439
4674
|
}
|
|
4440
4675
|
const canvas = yield toCanvas(url, options);
|
|
4441
|
-
const finalCanvas = options.backgroundColor ? createBackground(canvas, options.backgroundColor) : canvas;
|
|
4442
4676
|
return new Promise(
|
|
4443
|
-
(resolve) =>
|
|
4444
|
-
(blob) => resolve(blob),
|
|
4445
|
-
`image/${type}`,
|
|
4446
|
-
options.quality
|
|
4447
|
-
)
|
|
4677
|
+
(resolve) => canvas.toBlob((blob) => resolve(blob), `image/${type}`, options.quality)
|
|
4448
4678
|
);
|
|
4449
4679
|
});
|
|
4450
4680
|
}
|
|
@@ -4464,9 +4694,8 @@ ${imported}
|
|
|
4464
4694
|
return;
|
|
4465
4695
|
}
|
|
4466
4696
|
const canvas = yield toCanvas(url, options);
|
|
4467
|
-
const finalCanvas = options.backgroundColor ? createBackground(canvas, options.backgroundColor) : canvas;
|
|
4468
4697
|
const a = document.createElement("a");
|
|
4469
|
-
a.href =
|
|
4698
|
+
a.href = canvas.toDataURL(`image/${options.format}`, options.quality);
|
|
4470
4699
|
a.download = options.filename;
|
|
4471
4700
|
a.click();
|
|
4472
4701
|
});
|