@zumer/snapdom 1.9.10 → 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 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 v1.9.10 | SnapDOM v1.9.9 | html2canvas | html-to-image |
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 v1.9.10 | SnapDOM v1.9.9 | html2canvas | html-to-image |
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 |
@@ -480,6 +484,7 @@ For detailed contribution guidelines, please see [CONTRIBUTING](https://github.c
480
484
  <!-- CONTRIBUTORS:START -->
481
485
  <p>
482
486
  <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>
487
+ <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>
483
488
  <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>
484
489
  <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>
485
490
  <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>
@@ -492,6 +497,7 @@ For detailed contribution guidelines, please see [CONTRIBUTING](https://github.c
492
497
  <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>
493
498
  <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>
494
499
  <a href="https://github.com/jhbae200" title="jhbae200"><img src="https://avatars.githubusercontent.com/u/20170610?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="jhbae200"/></a>
500
+ <a href="https://github.com/xiaobai-web715" title="xiaobai-web715"><img src="https://avatars.githubusercontent.com/u/81091224?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="xiaobai-web715"/></a>
495
501
  <a href="https://github.com/miusuncle" title="miusuncle"><img src="https://avatars.githubusercontent.com/u/7549857?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="miusuncle"/></a>
496
502
  <a href="https://github.com/rbbydotdev" title="rbbydotdev"><img src="https://avatars.githubusercontent.com/u/101137670?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="rbbydotdev"/></a>
497
503
  <a href="https://github.com/zhanghaotian2018" title="zhanghaotian2018"><img src="https://avatars.githubusercontent.com/u/169218899?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="zhanghaotian2018"/></a>
package/dist/snapdom.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.1.9.10
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$/.test(url);
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 || isSpecialURL(url)) return false;
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}")) return useProxy.replace("{url}", encodeURIComponent(url));
185
- const sep = useProxy.endsWith("?") ? "" : useProxy.includes("?") ? "&" : "?";
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
- _errorCache.set(key, { until: Date.now() + errorTTL, result });
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`;
@@ -721,22 +808,14 @@
721
808
  return Promise.all(childList.map((child) => {
722
809
  return new Promise((resolve) => {
723
810
  function deal() {
724
- idle(
725
- (deadline) => {
726
- if (deadline instanceof IdleDeadline) {
727
- if (deadline.timeRemaining()) {
728
- callback(child, resolve);
729
- } else {
730
- deal();
731
- }
732
- } else {
733
- callback(child, resolve);
734
- }
735
- },
736
- {
737
- fast
811
+ idle((deadline) => {
812
+ const hasIdleBudget = deadline && typeof deadline.timeRemaining === "function" ? deadline.timeRemaining() > 0 : true;
813
+ if (hasIdleBudget) {
814
+ callback(child, resolve);
815
+ } else {
816
+ deal();
738
817
  }
739
- );
818
+ }, { fast });
740
819
  }
741
820
  deal();
742
821
  });
@@ -964,19 +1043,27 @@
964
1043
  return node.cloneNode(true);
965
1044
  }
966
1045
  if (node.getAttribute("data-capture") === "exclude") {
967
- const spacer = document.createElement("div");
968
- const rect = node.getBoundingClientRect();
969
- spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
970
- return spacer;
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
+ }
971
1054
  }
972
1055
  if (options.exclude && Array.isArray(options.exclude)) {
973
1056
  for (const selector of options.exclude) {
974
1057
  try {
975
1058
  if ((_a = node.matches) == null ? void 0 : _a.call(node, selector)) {
976
- const spacer = document.createElement("div");
977
- const rect = node.getBoundingClientRect();
978
- spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
979
- return spacer;
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
+ }
980
1067
  }
981
1068
  } catch (err) {
982
1069
  console.warn(`Invalid selector in exclude option: ${selector}`, err);
@@ -986,10 +1073,14 @@
986
1073
  if (typeof options.filter === "function") {
987
1074
  try {
988
1075
  if (!options.filter(node)) {
989
- const spacer = document.createElement("div");
990
- const rect = node.getBoundingClientRect();
991
- spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
992
- return spacer;
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
+ }
993
1084
  }
994
1085
  } catch (err) {
995
1086
  console.warn("Error in filter function:", err);
@@ -1843,7 +1934,7 @@
1843
1934
  }
1844
1935
  return used;
1845
1936
  }
1846
- function ensureFontsReady(families, warmupRepetitions = 1) {
1937
+ function ensureFontsReady(families, warmupRepetitions = 2) {
1847
1938
  return __async(this, null, function* () {
1848
1939
  try {
1849
1940
  yield document.fonts.ready;
@@ -2757,7 +2848,7 @@
2757
2848
  return "soft";
2758
2849
  }
2759
2850
  function createContext(options = {}) {
2760
- 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;
2761
2852
  const resolvedFormat = (_a = options.format) != null ? _a : "png";
2762
2853
  const cachePolicy = normalizeCachePolicy(options.cache);
2763
2854
  return {
@@ -2767,29 +2858,31 @@
2767
2858
  scale: (_d = options.scale) != null ? _d : 1,
2768
2859
  // DOM filters
2769
2860
  exclude: (_e = options.exclude) != null ? _e : [],
2770
- filter: (_f = options.filter) != null ? _f : null,
2861
+ excludeMode: (_f = options.excludeMode) != null ? _f : "visuallyHide",
2862
+ filter: (_g = options.filter) != null ? _g : null,
2863
+ filterMode: (_h = options.filterMode) != null ? _h : "visuallyHide",
2771
2864
  placeholders: options.placeholders !== false,
2772
2865
  // default true
2773
2866
  // Fuentes
2774
- embedFonts: (_g = options.embedFonts) != null ? _g : false,
2867
+ embedFonts: (_i = options.embedFonts) != null ? _i : false,
2775
2868
  iconFonts: Array.isArray(options.iconFonts) ? options.iconFonts : options.iconFonts ? [options.iconFonts] : [],
2776
2869
  localFonts: Array.isArray(options.localFonts) ? options.localFonts : [],
2777
- excludeFonts: (_h = options.excludeFonts) != null ? _h : void 0,
2778
- defaultImageUrl: (_i = options.defaultImageUrl) != null ? _i : void 0,
2870
+ excludeFonts: (_j = options.excludeFonts) != null ? _j : void 0,
2871
+ defaultImageUrl: (_k = options.defaultImageUrl) != null ? _k : void 0,
2779
2872
  /** Cache policy (disabled|full|auto|soft). Default: "soft" */
2780
2873
  /** @type {CachePolicy} */
2781
2874
  cache: cachePolicy,
2782
2875
  // Red
2783
2876
  useProxy: typeof options.useProxy === "string" ? options.useProxy : "",
2784
2877
  // Salida
2785
- width: (_j = options.width) != null ? _j : null,
2786
- height: (_k = options.height) != null ? _k : null,
2878
+ width: (_l = options.width) != null ? _l : null,
2879
+ height: (_m = options.height) != null ? _m : null,
2787
2880
  format: resolvedFormat,
2788
- type: (_l = options.type) != null ? _l : "svg",
2789
- quality: (_m = options.quality) != null ? _m : 0.92,
2790
- dpr: (_n = options.dpr) != null ? _n : window.devicePixelRatio || 1,
2791
- backgroundColor: (_o = options.backgroundColor) != null ? _o : ["jpg", "jpeg", "webp"].includes(resolvedFormat) ? "#ffffff" : null,
2792
- filename: (_p = options.filename) != null ? _p : "snapDOM"
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"
2793
2886
  // Plugins (reservado para futura activación)
2794
2887
  // plugins: normalizePlugins(...),
2795
2888
  };
@@ -2813,24 +2906,12 @@
2813
2906
  function toCanvas(url, options) {
2814
2907
  return __async(this, null, function* () {
2815
2908
  const { scale, dpr } = options;
2816
- const safari = isSafari();
2817
2909
  const img = new Image();
2818
2910
  img.crossOrigin = "anonymous";
2819
2911
  img.loading = "eager";
2820
2912
  img.decoding = "sync";
2821
2913
  img.src = url;
2822
- let tempSlot = null;
2823
- if (safari) {
2824
- tempSlot = document.createElement("div");
2825
- tempSlot.setAttribute("aria-hidden", "true");
2826
- tempSlot.style.cssText = "position:absolute;left:-99999px;top:0;width:0;height:0;overflow:hidden;opacity:0;pointer-events:none;contain:size layout style;";
2827
- document.body.appendChild(tempSlot);
2828
- tempSlot.appendChild(img);
2829
- }
2830
2914
  yield img.decode();
2831
- if (safari) {
2832
- yield new Promise((r) => setTimeout(r, 100));
2833
- }
2834
2915
  const width = img.naturalWidth * scale;
2835
2916
  const height = img.naturalHeight * scale;
2836
2917
  const canvas = document.createElement("canvas");
@@ -2841,12 +2922,6 @@
2841
2922
  const ctx = canvas.getContext("2d");
2842
2923
  if (dpr !== 1) ctx.scale(dpr, dpr);
2843
2924
  ctx.drawImage(img, 0, 0, width, height);
2844
- if (tempSlot && tempSlot.parentNode) {
2845
- try {
2846
- tempSlot.parentNode.removeChild(tempSlot);
2847
- } catch (e) {
2848
- }
2849
- }
2850
2925
  return canvas;
2851
2926
  });
2852
2927
  }
@@ -2909,9 +2984,20 @@
2909
2984
 
2910
2985
  // src/api/snapdom.js
2911
2986
  var INTERNAL_TOKEN = Symbol("snapdom.internal");
2987
+ var _safariWarmup = false;
2912
2988
  function snapdom(element, userOptions) {
2913
2989
  return __async(this, null, function* () {
2914
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
+ }
2915
3001
  const context = createContext(userOptions);
2916
3002
  if (context.iconFonts && context.iconFonts.length > 0) extendIconFonts(context.iconFonts);
2917
3003
  if (!context.snap) {
@@ -2956,26 +3042,68 @@
2956
3042
  snapdom.toJpg = (el, options) => snapdom(el, __spreadProps(__spreadValues({}, options), { format: "jpeg" })).then((result) => result.toJpg());
2957
3043
  snapdom.toWebp = (el, options) => snapdom(el, __spreadProps(__spreadValues({}, options), { format: "webp" })).then((result) => result.toWebp());
2958
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
+ }
2959
3083
 
2960
3084
  // src/api/preCache.js
2961
3085
  function preCache() {
2962
3086
  return __async(this, arguments, function* (root = document, options = {}) {
2963
- var _a;
3087
+ var _a, _b, _c, _d;
2964
3088
  const {
2965
3089
  embedFonts = true,
2966
- cacheOpt = "full",
2967
3090
  useProxy = ""
2968
3091
  } = options;
2969
- applyCachePolicy(cacheOpt);
3092
+ const cacheMode = (_b = (_a = options.cache) != null ? _a : options.cacheOpt) != null ? _b : "full";
3093
+ applyCachePolicy(cacheMode);
2970
3094
  try {
2971
- yield document.fonts.ready;
3095
+ yield (_c = document.fonts) == null ? void 0 : _c.ready;
3096
+ } catch (e) {
3097
+ }
3098
+ try {
3099
+ precacheCommonTags();
2972
3100
  } catch (e) {
2973
3101
  }
2974
- precacheCommonTags();
2975
3102
  cache.session = cache.session || {};
2976
3103
  if (!cache.session.styleCache) {
2977
3104
  cache.session.styleCache = /* @__PURE__ */ new WeakMap();
2978
3105
  }
3106
+ cache.image = cache.image || /* @__PURE__ */ new Map();
2979
3107
  try {
2980
3108
  yield inlineBackgroundImages(
2981
3109
  root,
@@ -2996,12 +3124,15 @@
2996
3124
  }
2997
3125
  const promises = [];
2998
3126
  for (const img of imgEls) {
2999
- const src = img == null ? void 0 : img.src;
3127
+ const src = (img == null ? void 0 : img.currentSrc) || (img == null ? void 0 : img.src);
3000
3128
  if (!src) continue;
3001
3129
  if (!cache.image.has(src)) {
3002
- const p = Promise.resolve().then(() => snapFetch(src, { as: "dataURL", useProxy })).then((dataURL) => {
3003
- cache.image.set(src, dataURL);
3004
- }).catch(() => {
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(() => {
3005
3136
  });
3006
3137
  promises.push(p);
3007
3138
  }
@@ -3027,7 +3158,8 @@
3027
3158
  try {
3028
3159
  const required = collectUsedFontVariants(root);
3029
3160
  const usedCodepoints = collectUsedCodepoints(root);
3030
- if (typeof isSafari === "function" ? isSafari() : !!isSafari) {
3161
+ const safari = typeof isSafari === "function" ? isSafari() : !!isSafari;
3162
+ if (safari) {
3031
3163
  const families = new Set(
3032
3164
  Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
3033
3165
  );
@@ -3038,7 +3170,7 @@
3038
3170
  usedCodepoints,
3039
3171
  exclude: options.excludeFonts,
3040
3172
  localFonts: options.localFonts,
3041
- useProxy: (_a = options.useProxy) != null ? _a : useProxy
3173
+ useProxy: (_d = options.useProxy) != null ? _d : useProxy
3042
3174
  });
3043
3175
  } catch (e) {
3044
3176
  }