@zumer/snapdom 1.9.11 → 1.9.12-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/snapdom.js +201 -61
- package/dist/snapdom.min.js +4 -4
- package/dist/snapdom.min.mjs +4 -4
- package/dist/snapdom.mjs +185 -46
- package/package.json +1 -1
- package/types/snapdom.d.ts +15 -0
package/README.md
CHANGED
|
@@ -202,7 +202,9 @@ All capture methods accept an `options` object:
|
|
|
202
202
|
| `useProxy` | string | `''` | Proxy base for CORS fallbacks |
|
|
203
203
|
| `type` | string | `svg` | Default Blob type (`svg`\|`png`\|`jpg`\|`webp`) |
|
|
204
204
|
| `exclude` | string[] | - | CSS selectors to exclude |
|
|
205
|
+
| `excludeMode` | string | 'visuallyHide' | Controls how `exclude` works with nodes |
|
|
205
206
|
| `filter` | function | - | Custom predicate `(el) => boolean` |
|
|
207
|
+
| `filterMode` | string | 'visuallyHide' | Controls how `filter` works with nodes |
|
|
206
208
|
| `cache` | string | `"soft"` | Control internal caches: `disabled`, `soft`, `auto`, `full` |
|
|
207
209
|
| `defaultImageUrl` | string \| function | - | Fallback image when an `<img>` fails. If a function is provided, it receives `{ width?, height?, src?, element }` and must return a URL (string or Promise<string>). Useful for placeholder services (e.g. `https://placehold.co/{width}x{height}`) |
|
|
208
210
|
|
|
@@ -304,7 +306,9 @@ await snapdom.toPng(el, {
|
|
|
304
306
|
### Filtering nodes: `exclude` vs `filter`
|
|
305
307
|
|
|
306
308
|
* `exclude`: remove by **selector**.
|
|
309
|
+
* `excludeMode`: `visuallyHide` applies `visibility:hidden` CSS rule on excluded nodes and the layout remains as the original. `remove` do not clone excluded nodes at all.
|
|
307
310
|
* `filter`: advanced predicate per element (return `false` to drop).
|
|
311
|
+
* `filterMode`: `visuallyHide` applies `visibility:hidden` CSS rule on filtered nodes and the layout remains as the original. `remove` do not clone filtered nodes at all.
|
|
308
312
|
|
|
309
313
|
**Example: filter out elements with `display:none`:**
|
|
310
314
|
```js
|
|
@@ -345,7 +349,7 @@ await preCache({
|
|
|
345
349
|
|
|
346
350
|
### Cache control
|
|
347
351
|
|
|
348
|
-
SnapDOM maintains internal caches for images, backgrounds, resources, styles, and fonts.
|
|
352
|
+
SnapDOM maintains internal caches for images, backgrounds, resources, styles, and fonts.
|
|
349
353
|
You can control how they are cleared between captures using the `cache` option:
|
|
350
354
|
|
|
351
355
|
| Mode | Description |
|
|
@@ -382,7 +386,7 @@ Values are **average capture time (ms)** → lower is better.
|
|
|
382
386
|
|
|
383
387
|
### Simple elements
|
|
384
388
|
|
|
385
|
-
| Scenario | SnapDOM
|
|
389
|
+
| Scenario | SnapDOM current | SnapDOM v1.9.9 | html2canvas | html-to-image |
|
|
386
390
|
| ------------------------ | --------------- | -------------- | ----------- | ------------- |
|
|
387
391
|
| Small (200×100) | **0.5 ms** | 0.8 ms | 67.7 ms | 3.1 ms |
|
|
388
392
|
| Modal (400×300) | **0.5 ms** | 0.8 ms | 75.5 ms | 3.6 ms |
|
|
@@ -394,7 +398,7 @@ Values are **average capture time (ms)** → lower is better.
|
|
|
394
398
|
|
|
395
399
|
### Complex elements
|
|
396
400
|
|
|
397
|
-
| Scenario | SnapDOM
|
|
401
|
+
| Scenario | SnapDOM current | SnapDOM v1.9.9 | html2canvas | html-to-image |
|
|
398
402
|
| ------------------------ | --------------- | -------------- | ----------- | ------------- |
|
|
399
403
|
| Small (200×100) | **1.6 ms** | 3.3 ms | 68.0 ms | 14.3 ms |
|
|
400
404
|
| Modal (400×300) | **2.9 ms** | 6.8 ms | 87.5 ms | 34.8 ms |
|
package/dist/snapdom.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
3
|
* snapdom
|
|
4
|
-
* v.1.9.
|
|
4
|
+
* v.1.9.12-dev.0
|
|
5
5
|
* Author Juan Martin Muda
|
|
6
6
|
* License MIT
|
|
7
7
|
**/
|
|
@@ -167,10 +167,25 @@
|
|
|
167
167
|
var _inflight = /* @__PURE__ */ new Map();
|
|
168
168
|
var _errorCache = /* @__PURE__ */ new Map();
|
|
169
169
|
function isSpecialURL(url) {
|
|
170
|
-
return /^data:|^blob:|^about:blank
|
|
170
|
+
return /^data:|^blob:|^about:blank$/i.test(url);
|
|
171
|
+
}
|
|
172
|
+
function isAlreadyProxied(url, useProxy) {
|
|
173
|
+
try {
|
|
174
|
+
const baseHref = typeof location !== "undefined" && location.href ? location.href : "http://localhost/";
|
|
175
|
+
const proxyBaseRaw = useProxy.includes("{url}") ? useProxy.split("{url}")[0] : useProxy;
|
|
176
|
+
const proxyBase = new URL(proxyBaseRaw || ".", baseHref);
|
|
177
|
+
const u = new URL(url, baseHref);
|
|
178
|
+
if (u.origin === proxyBase.origin) return true;
|
|
179
|
+
const sp = u.searchParams;
|
|
180
|
+
if (sp && (sp.has("url") || sp.has("target"))) return true;
|
|
181
|
+
} catch (e) {
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
171
184
|
}
|
|
172
185
|
function shouldProxy(url, useProxy) {
|
|
173
|
-
if (!useProxy
|
|
186
|
+
if (!useProxy) return false;
|
|
187
|
+
if (isSpecialURL(url)) return false;
|
|
188
|
+
if (isAlreadyProxied(url, useProxy)) return false;
|
|
174
189
|
try {
|
|
175
190
|
const base = typeof location !== "undefined" && location.href ? location.href : "http://localhost/";
|
|
176
191
|
const u = new URL(url, base);
|
|
@@ -181,8 +196,19 @@
|
|
|
181
196
|
}
|
|
182
197
|
function applyProxy(url, useProxy) {
|
|
183
198
|
if (!useProxy) return url;
|
|
184
|
-
if (useProxy.includes("{url}"))
|
|
185
|
-
|
|
199
|
+
if (useProxy.includes("{url}")) {
|
|
200
|
+
return useProxy.replace("{urlRaw}", safeEncodeURI(url)).replace("{url}", encodeURIComponent(url));
|
|
201
|
+
}
|
|
202
|
+
if (/[?&]url=?$/.test(useProxy)) {
|
|
203
|
+
return `${useProxy}${encodeURIComponent(url)}`;
|
|
204
|
+
}
|
|
205
|
+
if (useProxy.endsWith("?")) {
|
|
206
|
+
return `${useProxy}url=${encodeURIComponent(url)}`;
|
|
207
|
+
}
|
|
208
|
+
if (useProxy.endsWith("/")) {
|
|
209
|
+
return `${useProxy}${safeEncodeURI(url)}`;
|
|
210
|
+
}
|
|
211
|
+
const sep = useProxy.includes("?") ? "&" : "?";
|
|
186
212
|
return `${useProxy}${sep}url=${encodeURIComponent(url)}`;
|
|
187
213
|
}
|
|
188
214
|
function blobToDataURL(blob) {
|
|
@@ -212,6 +238,65 @@
|
|
|
212
238
|
const errorTTL = (_c = options.errorTTL) != null ? _c : 8e3;
|
|
213
239
|
const headers = options.headers || {};
|
|
214
240
|
const silent = !!options.silent;
|
|
241
|
+
if (/^data:/i.test(url)) {
|
|
242
|
+
try {
|
|
243
|
+
if (as === "text") {
|
|
244
|
+
return { ok: true, data: String(url), status: 200, url, fromCache: false };
|
|
245
|
+
}
|
|
246
|
+
if (as === "dataURL") {
|
|
247
|
+
return {
|
|
248
|
+
ok: true,
|
|
249
|
+
data: String(url),
|
|
250
|
+
status: 200,
|
|
251
|
+
url,
|
|
252
|
+
fromCache: false,
|
|
253
|
+
mime: String(url).slice(5).split(";")[0] || ""
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
const [, meta = "", data = ""] = String(url).match(/^data:([^,]*),(.*)$/) || [];
|
|
257
|
+
const isBase64 = /;base64/i.test(meta);
|
|
258
|
+
const bin = isBase64 ? atob(data) : decodeURIComponent(data);
|
|
259
|
+
const bytes = new Uint8Array([...bin].map((c) => c.charCodeAt(0)));
|
|
260
|
+
const b = new Blob([bytes], { type: (meta || "").split(";")[0] || "" });
|
|
261
|
+
return { ok: true, data: b, status: 200, url, fromCache: false, mime: b.type || "" };
|
|
262
|
+
} catch (e2) {
|
|
263
|
+
return { ok: false, data: null, status: 0, url, fromCache: false, reason: "special_url_error" };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (/^blob:/i.test(url)) {
|
|
267
|
+
try {
|
|
268
|
+
const resp = yield fetch(url);
|
|
269
|
+
if (!resp.ok) {
|
|
270
|
+
return { ok: false, data: null, status: resp.status, url, fromCache: false, reason: "http_error" };
|
|
271
|
+
}
|
|
272
|
+
const blob = yield resp.blob();
|
|
273
|
+
const mime = blob.type || resp.headers.get("content-type") || "";
|
|
274
|
+
if (as === "dataURL") {
|
|
275
|
+
const dataURL = yield blobToDataURL(blob);
|
|
276
|
+
return { ok: true, data: dataURL, status: resp.status, url, fromCache: false, mime };
|
|
277
|
+
}
|
|
278
|
+
if (as === "text") {
|
|
279
|
+
const text = yield blob.text();
|
|
280
|
+
return { ok: true, data: text, status: resp.status, url, fromCache: false, mime };
|
|
281
|
+
}
|
|
282
|
+
return { ok: true, data: blob, status: resp.status, url, fromCache: false, mime };
|
|
283
|
+
} catch (e2) {
|
|
284
|
+
return { ok: false, data: null, status: 0, url, fromCache: false, reason: "network" };
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (/^about:blank$/i.test(url)) {
|
|
288
|
+
if (as === "dataURL") {
|
|
289
|
+
return {
|
|
290
|
+
ok: true,
|
|
291
|
+
data: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==",
|
|
292
|
+
status: 200,
|
|
293
|
+
url,
|
|
294
|
+
fromCache: false,
|
|
295
|
+
mime: "image/png"
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return { ok: true, data: as === "text" ? "" : new Blob([]), status: 200, url, fromCache: false };
|
|
299
|
+
}
|
|
215
300
|
const key = makeKey(url, { as, timeout, useProxy, errorTTL });
|
|
216
301
|
const e = _errorCache.get(key);
|
|
217
302
|
if (e && e.until > Date.now()) {
|
|
@@ -241,7 +326,7 @@
|
|
|
241
326
|
const resp = yield fetch(finalURL, { signal: ctrl.signal, credentials: cred, headers });
|
|
242
327
|
if (!resp.ok) {
|
|
243
328
|
const result = { ok: false, data: null, status: resp.status, url: finalURL, fromCache: false, reason: "http_error" };
|
|
244
|
-
_errorCache.set(key, { until: Date.now() + errorTTL, result });
|
|
329
|
+
if (errorTTL > 0) _errorCache.set(key, { until: Date.now() + errorTTL, result });
|
|
245
330
|
if (!silent) {
|
|
246
331
|
const short = `${resp.status} ${resp.statusText || ""}`.trim();
|
|
247
332
|
snapLogger.warnOnce(
|
|
@@ -266,7 +351,9 @@
|
|
|
266
351
|
} catch (err) {
|
|
267
352
|
const reason = err && typeof err === "object" && "name" in err && err.name === "AbortError" ? String(err.message || "").includes("timeout") ? "timeout" : "abort" : "network";
|
|
268
353
|
const result = { ok: false, data: null, status: 0, url: finalURL, fromCache: false, reason };
|
|
269
|
-
|
|
354
|
+
if (!/^blob:/i.test(url) && errorTTL > 0) {
|
|
355
|
+
_errorCache.set(key, { until: Date.now() + errorTTL, result });
|
|
356
|
+
}
|
|
270
357
|
if (!silent) {
|
|
271
358
|
const k = `${reason}:${as}:${new URL(url, (_b2 = location == null ? void 0 : location.href) != null ? _b2 : "http://localhost/").origin}`;
|
|
272
359
|
const tips = reason === "timeout" ? `Timeout after ${timeout}ms. Consider increasing timeout or using a proxy for ${url}` : reason === "abort" ? `Request aborted while fetching ${as} ${url}` : `Network/CORS issue while fetching ${as} ${url}. A proxy may be required`;
|
|
@@ -956,19 +1043,27 @@
|
|
|
956
1043
|
return node.cloneNode(true);
|
|
957
1044
|
}
|
|
958
1045
|
if (node.getAttribute("data-capture") === "exclude") {
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1046
|
+
if (options.excludeMode === "visuallyHide") {
|
|
1047
|
+
const spacer = document.createElement("div");
|
|
1048
|
+
const rect = node.getBoundingClientRect();
|
|
1049
|
+
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
|
|
1050
|
+
return spacer;
|
|
1051
|
+
} else if (options.excludeMode === "remove") {
|
|
1052
|
+
return null;
|
|
1053
|
+
}
|
|
963
1054
|
}
|
|
964
1055
|
if (options.exclude && Array.isArray(options.exclude)) {
|
|
965
1056
|
for (const selector of options.exclude) {
|
|
966
1057
|
try {
|
|
967
1058
|
if ((_a = node.matches) == null ? void 0 : _a.call(node, selector)) {
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1059
|
+
if (options.excludeMode === "visuallyHide") {
|
|
1060
|
+
const spacer = document.createElement("div");
|
|
1061
|
+
const rect = node.getBoundingClientRect();
|
|
1062
|
+
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
|
|
1063
|
+
return spacer;
|
|
1064
|
+
} else if (options.excludeMode === "remove") {
|
|
1065
|
+
return null;
|
|
1066
|
+
}
|
|
972
1067
|
}
|
|
973
1068
|
} catch (err) {
|
|
974
1069
|
console.warn(`Invalid selector in exclude option: ${selector}`, err);
|
|
@@ -978,10 +1073,14 @@
|
|
|
978
1073
|
if (typeof options.filter === "function") {
|
|
979
1074
|
try {
|
|
980
1075
|
if (!options.filter(node)) {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1076
|
+
if (options.filterMode === "visuallyHide") {
|
|
1077
|
+
const spacer = document.createElement("div");
|
|
1078
|
+
const rect = node.getBoundingClientRect();
|
|
1079
|
+
spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
|
|
1080
|
+
return spacer;
|
|
1081
|
+
} else if (options.filterMode === "remove") {
|
|
1082
|
+
return null;
|
|
1083
|
+
}
|
|
985
1084
|
}
|
|
986
1085
|
} catch (err) {
|
|
987
1086
|
console.warn("Error in filter function:", err);
|
|
@@ -2480,7 +2579,7 @@
|
|
|
2480
2579
|
const families = new Set(
|
|
2481
2580
|
Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
|
|
2482
2581
|
);
|
|
2483
|
-
yield ensureFontsReady(families,
|
|
2582
|
+
yield ensureFontsReady(families, 2);
|
|
2484
2583
|
}
|
|
2485
2584
|
fontsCSS = yield embedCustomFonts({
|
|
2486
2585
|
required,
|
|
@@ -2749,7 +2848,7 @@
|
|
|
2749
2848
|
return "soft";
|
|
2750
2849
|
}
|
|
2751
2850
|
function createContext(options = {}) {
|
|
2752
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
2851
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
|
|
2753
2852
|
const resolvedFormat = (_a = options.format) != null ? _a : "png";
|
|
2754
2853
|
const cachePolicy = normalizeCachePolicy(options.cache);
|
|
2755
2854
|
return {
|
|
@@ -2759,29 +2858,31 @@
|
|
|
2759
2858
|
scale: (_d = options.scale) != null ? _d : 1,
|
|
2760
2859
|
// DOM filters
|
|
2761
2860
|
exclude: (_e = options.exclude) != null ? _e : [],
|
|
2762
|
-
|
|
2861
|
+
excludeMode: (_f = options.excludeMode) != null ? _f : "visuallyHide",
|
|
2862
|
+
filter: (_g = options.filter) != null ? _g : null,
|
|
2863
|
+
filterMode: (_h = options.filterMode) != null ? _h : "visuallyHide",
|
|
2763
2864
|
placeholders: options.placeholders !== false,
|
|
2764
2865
|
// default true
|
|
2765
2866
|
// Fuentes
|
|
2766
|
-
embedFonts: (
|
|
2867
|
+
embedFonts: (_i = options.embedFonts) != null ? _i : false,
|
|
2767
2868
|
iconFonts: Array.isArray(options.iconFonts) ? options.iconFonts : options.iconFonts ? [options.iconFonts] : [],
|
|
2768
2869
|
localFonts: Array.isArray(options.localFonts) ? options.localFonts : [],
|
|
2769
|
-
excludeFonts: (
|
|
2770
|
-
defaultImageUrl: (
|
|
2870
|
+
excludeFonts: (_j = options.excludeFonts) != null ? _j : void 0,
|
|
2871
|
+
defaultImageUrl: (_k = options.defaultImageUrl) != null ? _k : void 0,
|
|
2771
2872
|
/** Cache policy (disabled|full|auto|soft). Default: "soft" */
|
|
2772
2873
|
/** @type {CachePolicy} */
|
|
2773
2874
|
cache: cachePolicy,
|
|
2774
2875
|
// Red
|
|
2775
2876
|
useProxy: typeof options.useProxy === "string" ? options.useProxy : "",
|
|
2776
2877
|
// Salida
|
|
2777
|
-
width: (
|
|
2778
|
-
height: (
|
|
2878
|
+
width: (_l = options.width) != null ? _l : null,
|
|
2879
|
+
height: (_m = options.height) != null ? _m : null,
|
|
2779
2880
|
format: resolvedFormat,
|
|
2780
|
-
type: (
|
|
2781
|
-
quality: (
|
|
2782
|
-
dpr: (
|
|
2783
|
-
backgroundColor: (
|
|
2784
|
-
filename: (
|
|
2881
|
+
type: (_n = options.type) != null ? _n : "svg",
|
|
2882
|
+
quality: (_o = options.quality) != null ? _o : 0.92,
|
|
2883
|
+
dpr: (_p = options.dpr) != null ? _p : window.devicePixelRatio || 1,
|
|
2884
|
+
backgroundColor: (_q = options.backgroundColor) != null ? _q : ["jpg", "jpeg", "webp"].includes(resolvedFormat) ? "#ffffff" : null,
|
|
2885
|
+
filename: (_r = options.filename) != null ? _r : "snapDOM"
|
|
2785
2886
|
// Plugins (reservado para futura activación)
|
|
2786
2887
|
// plugins: normalizePlugins(...),
|
|
2787
2888
|
};
|
|
@@ -2805,24 +2906,12 @@
|
|
|
2805
2906
|
function toCanvas(url, options) {
|
|
2806
2907
|
return __async(this, null, function* () {
|
|
2807
2908
|
const { scale, dpr } = options;
|
|
2808
|
-
const safari = isSafari();
|
|
2809
2909
|
const img = new Image();
|
|
2810
2910
|
img.crossOrigin = "anonymous";
|
|
2811
2911
|
img.loading = "eager";
|
|
2812
2912
|
img.decoding = "sync";
|
|
2813
2913
|
img.src = url;
|
|
2814
|
-
let tempSlot = null;
|
|
2815
|
-
if (safari) {
|
|
2816
|
-
tempSlot = document.createElement("div");
|
|
2817
|
-
tempSlot.setAttribute("aria-hidden", "true");
|
|
2818
|
-
tempSlot.style.cssText = "position:absolute;left:-99999px;top:0;width:0;height:0;overflow:hidden;opacity:0;pointer-events:none;contain:size layout style;";
|
|
2819
|
-
document.body.appendChild(tempSlot);
|
|
2820
|
-
tempSlot.appendChild(img);
|
|
2821
|
-
}
|
|
2822
2914
|
yield img.decode();
|
|
2823
|
-
if (safari) {
|
|
2824
|
-
yield new Promise((r) => setTimeout(r, 100));
|
|
2825
|
-
}
|
|
2826
2915
|
const width = img.naturalWidth * scale;
|
|
2827
2916
|
const height = img.naturalHeight * scale;
|
|
2828
2917
|
const canvas = document.createElement("canvas");
|
|
@@ -2833,12 +2922,6 @@
|
|
|
2833
2922
|
const ctx = canvas.getContext("2d");
|
|
2834
2923
|
if (dpr !== 1) ctx.scale(dpr, dpr);
|
|
2835
2924
|
ctx.drawImage(img, 0, 0, width, height);
|
|
2836
|
-
if (tempSlot && tempSlot.parentNode) {
|
|
2837
|
-
try {
|
|
2838
|
-
tempSlot.parentNode.removeChild(tempSlot);
|
|
2839
|
-
} catch (e) {
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
2925
|
return canvas;
|
|
2843
2926
|
});
|
|
2844
2927
|
}
|
|
@@ -2901,9 +2984,20 @@
|
|
|
2901
2984
|
|
|
2902
2985
|
// src/api/snapdom.js
|
|
2903
2986
|
var INTERNAL_TOKEN = Symbol("snapdom.internal");
|
|
2987
|
+
var _safariWarmup = false;
|
|
2904
2988
|
function snapdom(element, userOptions) {
|
|
2905
2989
|
return __async(this, null, function* () {
|
|
2906
2990
|
if (!element) throw new Error("Element cannot be null or undefined");
|
|
2991
|
+
if (isSafari()) {
|
|
2992
|
+
for (let i = 0; i < 3; i++) {
|
|
2993
|
+
try {
|
|
2994
|
+
yield safariWarmup(element, userOptions);
|
|
2995
|
+
console.log("Iteraci\xF3n n\xFAmero:", i);
|
|
2996
|
+
_safariWarmup = false;
|
|
2997
|
+
} catch (error) {
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
2907
3001
|
const context = createContext(userOptions);
|
|
2908
3002
|
if (context.iconFonts && context.iconFonts.length > 0) extendIconFonts(context.iconFonts);
|
|
2909
3003
|
if (!context.snap) {
|
|
@@ -2948,26 +3042,68 @@
|
|
|
2948
3042
|
snapdom.toJpg = (el, options) => snapdom(el, __spreadProps(__spreadValues({}, options), { format: "jpeg" })).then((result) => result.toJpg());
|
|
2949
3043
|
snapdom.toWebp = (el, options) => snapdom(el, __spreadProps(__spreadValues({}, options), { format: "webp" })).then((result) => result.toWebp());
|
|
2950
3044
|
snapdom.download = (el, options) => snapdom(el, options).then((result) => result.download());
|
|
3045
|
+
function safariWarmup(element, baseOptions) {
|
|
3046
|
+
return __async(this, null, function* () {
|
|
3047
|
+
if (_safariWarmup) return;
|
|
3048
|
+
const preflight = __spreadProps(__spreadValues({}, baseOptions), {
|
|
3049
|
+
fast: true,
|
|
3050
|
+
embedFonts: true,
|
|
3051
|
+
scale: 0.2
|
|
3052
|
+
});
|
|
3053
|
+
let url;
|
|
3054
|
+
try {
|
|
3055
|
+
url = yield captureDOM(element, preflight);
|
|
3056
|
+
} catch (e) {
|
|
3057
|
+
return;
|
|
3058
|
+
}
|
|
3059
|
+
yield new Promise((resolve) => {
|
|
3060
|
+
const img = new Image();
|
|
3061
|
+
img.decoding = "sync";
|
|
3062
|
+
img.loading = "eager";
|
|
3063
|
+
img.style.position = "fixed";
|
|
3064
|
+
img.style.left = 0;
|
|
3065
|
+
img.style.top = 0;
|
|
3066
|
+
img.style.width = "10px";
|
|
3067
|
+
img.style.height = "10px";
|
|
3068
|
+
img.style.opacity = "0.01";
|
|
3069
|
+
img.style.transform = "translateZ(10px)";
|
|
3070
|
+
img.style.willChange = "transform,opacity;";
|
|
3071
|
+
img.src = url;
|
|
3072
|
+
const cleanup = () => __async(null, null, function* () {
|
|
3073
|
+
yield new Promise((r) => setTimeout(r, 100));
|
|
3074
|
+
if (img && img.parentNode) img.parentNode.removeChild(img);
|
|
3075
|
+
_safariWarmup = true;
|
|
3076
|
+
resolve();
|
|
3077
|
+
});
|
|
3078
|
+
document.body.appendChild(img);
|
|
3079
|
+
cleanup();
|
|
3080
|
+
});
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
2951
3083
|
|
|
2952
3084
|
// src/api/preCache.js
|
|
2953
3085
|
function preCache() {
|
|
2954
3086
|
return __async(this, arguments, function* (root = document, options = {}) {
|
|
2955
|
-
var _a;
|
|
3087
|
+
var _a, _b, _c, _d;
|
|
2956
3088
|
const {
|
|
2957
3089
|
embedFonts = true,
|
|
2958
|
-
cacheOpt = "full",
|
|
2959
3090
|
useProxy = ""
|
|
2960
3091
|
} = options;
|
|
2961
|
-
|
|
3092
|
+
const cacheMode = (_b = (_a = options.cache) != null ? _a : options.cacheOpt) != null ? _b : "full";
|
|
3093
|
+
applyCachePolicy(cacheMode);
|
|
2962
3094
|
try {
|
|
2963
|
-
yield document.fonts.ready;
|
|
3095
|
+
yield (_c = document.fonts) == null ? void 0 : _c.ready;
|
|
3096
|
+
} catch (e) {
|
|
3097
|
+
}
|
|
3098
|
+
try {
|
|
3099
|
+
precacheCommonTags();
|
|
2964
3100
|
} catch (e) {
|
|
2965
3101
|
}
|
|
2966
|
-
precacheCommonTags();
|
|
2967
3102
|
cache.session = cache.session || {};
|
|
2968
3103
|
if (!cache.session.styleCache) {
|
|
2969
3104
|
cache.session.styleCache = /* @__PURE__ */ new WeakMap();
|
|
2970
3105
|
}
|
|
3106
|
+
cache.image = cache.image || /* @__PURE__ */ new Map();
|
|
2971
3107
|
try {
|
|
2972
3108
|
yield inlineBackgroundImages(
|
|
2973
3109
|
root,
|
|
@@ -2988,12 +3124,15 @@
|
|
|
2988
3124
|
}
|
|
2989
3125
|
const promises = [];
|
|
2990
3126
|
for (const img of imgEls) {
|
|
2991
|
-
const src = img == null ? void 0 : img.src;
|
|
3127
|
+
const src = (img == null ? void 0 : img.currentSrc) || (img == null ? void 0 : img.src);
|
|
2992
3128
|
if (!src) continue;
|
|
2993
3129
|
if (!cache.image.has(src)) {
|
|
2994
|
-
const p = Promise.resolve().then(() =>
|
|
2995
|
-
|
|
2996
|
-
|
|
3130
|
+
const p = Promise.resolve().then(() => __async(null, null, function* () {
|
|
3131
|
+
const res = yield snapFetch(src, { as: "dataURL", useProxy });
|
|
3132
|
+
if ((res == null ? void 0 : res.ok) && typeof res.data === "string") {
|
|
3133
|
+
cache.image.set(src, res.data);
|
|
3134
|
+
}
|
|
3135
|
+
})).catch(() => {
|
|
2997
3136
|
});
|
|
2998
3137
|
promises.push(p);
|
|
2999
3138
|
}
|
|
@@ -3019,7 +3158,8 @@
|
|
|
3019
3158
|
try {
|
|
3020
3159
|
const required = collectUsedFontVariants(root);
|
|
3021
3160
|
const usedCodepoints = collectUsedCodepoints(root);
|
|
3022
|
-
|
|
3161
|
+
const safari = typeof isSafari === "function" ? isSafari() : !!isSafari;
|
|
3162
|
+
if (safari) {
|
|
3023
3163
|
const families = new Set(
|
|
3024
3164
|
Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
|
|
3025
3165
|
);
|
|
@@ -3030,7 +3170,7 @@
|
|
|
3030
3170
|
usedCodepoints,
|
|
3031
3171
|
exclude: options.excludeFonts,
|
|
3032
3172
|
localFonts: options.localFonts,
|
|
3033
|
-
useProxy: (
|
|
3173
|
+
useProxy: (_d = options.useProxy) != null ? _d : useProxy
|
|
3034
3174
|
});
|
|
3035
3175
|
} catch (e) {
|
|
3036
3176
|
}
|