@zumer/snapdom 2.0.2 → 2.5.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.
Files changed (57) hide show
  1. package/README.md +135 -71
  2. package/dist/{modules/chunks/chunk-SSUBCN7X.js → plugins.mjs} +2 -2
  3. package/dist/preCache.mjs +10 -0
  4. package/dist/snapdom.js +8 -8
  5. package/dist/snapdom.mjs +8 -8
  6. package/package.json +6 -5
  7. package/dist/modules/chunks/chunk-3JLSSUO4.js +0 -7
  8. package/dist/modules/chunks/chunk-3PHM6WOF.js +0 -7
  9. package/dist/modules/chunks/chunk-3VYIPD3A.js +0 -7
  10. package/dist/modules/chunks/chunk-4E2QQYX5.js +0 -7
  11. package/dist/modules/chunks/chunk-4IERUYP4.js +0 -7
  12. package/dist/modules/chunks/chunk-4Z46XXMY.js +0 -10
  13. package/dist/modules/chunks/chunk-53XQJAU5.js +0 -7
  14. package/dist/modules/chunks/chunk-5ZWTRQ52.js +0 -10
  15. package/dist/modules/chunks/chunk-7427JF2H.js +0 -10
  16. package/dist/modules/chunks/chunk-ANSXOGKI.js +0 -7
  17. package/dist/modules/chunks/chunk-BF74J4A5.js +0 -8
  18. package/dist/modules/chunks/chunk-BUMT6T6O.js +0 -10
  19. package/dist/modules/chunks/chunk-CNTQFGEZ.js +0 -10
  20. package/dist/modules/chunks/chunk-CRBLWEX6.js +0 -10
  21. package/dist/modules/chunks/chunk-CS7DTJ7I.js +0 -7
  22. package/dist/modules/chunks/chunk-DTQFIIVX.js +0 -7
  23. package/dist/modules/chunks/chunk-EBDTZNMR.js +0 -7
  24. package/dist/modules/chunks/chunk-EVYDSB2B.js +0 -7
  25. package/dist/modules/chunks/chunk-EZMCZKDW.js +0 -7
  26. package/dist/modules/chunks/chunk-FQK3JDTN.js +0 -10
  27. package/dist/modules/chunks/chunk-FTKOXG2W.js +0 -7
  28. package/dist/modules/chunks/chunk-G4EP52KJ.js +0 -10
  29. package/dist/modules/chunks/chunk-GIYVHLCQ.js +0 -8
  30. package/dist/modules/chunks/chunk-GZX3IERM.js +0 -8
  31. package/dist/modules/chunks/chunk-LCE36WDF.js +0 -10
  32. package/dist/modules/chunks/chunk-MW6X4KTL.js +0 -7
  33. package/dist/modules/chunks/chunk-N2KKO64J.js +0 -10
  34. package/dist/modules/chunks/chunk-NM4NY5FQ.js +0 -7
  35. package/dist/modules/chunks/chunk-PZIG3IRP.js +0 -10
  36. package/dist/modules/chunks/chunk-Q2Z2CG2I.js +0 -7
  37. package/dist/modules/chunks/chunk-Q55H7S7M.js +0 -7
  38. package/dist/modules/chunks/chunk-QBJ6HQLA.js +0 -10
  39. package/dist/modules/chunks/chunk-RKOPBBFA.js +0 -10
  40. package/dist/modules/chunks/chunk-SMBRKOUP.js +0 -7
  41. package/dist/modules/chunks/chunk-T4JIPPZO.js +0 -7
  42. package/dist/modules/chunks/chunk-X6RBKLFD.js +0 -10
  43. package/dist/modules/chunks/chunk-Y7FY32AO.js +0 -7
  44. package/dist/modules/chunks/rasterize-34PCWURX.js +0 -7
  45. package/dist/modules/chunks/rasterize-JS5G2XHH.js +0 -7
  46. package/dist/modules/chunks/rasterize-WOXTJCMX.js +0 -7
  47. package/dist/modules/exporters/download.js +0 -7
  48. package/dist/modules/exporters/toBlob.js +0 -7
  49. package/dist/modules/exporters/toCanvas.js +0 -7
  50. package/dist/modules/exporters/toImg.js +0 -7
  51. package/dist/modules/exporters/toJpg.js +0 -7
  52. package/dist/modules/exporters/toPng.js +0 -7
  53. package/dist/modules/exporters/toSvg.js +0 -7
  54. package/dist/modules/exporters/toWebp.js +0 -7
  55. package/dist/modules/plugins.js +0 -7
  56. package/dist/modules/preCache.js +0 -7
  57. package/dist/modules/snapdom.js +0 -7
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  <img alt="NPM version" src="https://img.shields.io/npm/v/@zumer/snapdom?style=flat-square&label=Version">
10
10
  </a>
11
11
  <a href="https://www.npmjs.com/package/@zumer/snapdom">
12
- <img alt="NPM version" src="https://img.shields.io/npm/v/@zumer/snapdom/dev?style=flat-square&label=Dev">
12
+ <img alt="NPM weekly downloads" src="https://img.shields.io/npm/dw/@zumer/snapdom?style=flat-square&label=Downloads">
13
13
  </a>
14
14
  <a href="https://github.com/zumerlab/snapdom/graphs/contributors">
15
15
  <img alt="GitHub contributors" src="https://img.shields.io/github/contributors/zumerlab/snapdom?style=flat-square&label=Contributors">
@@ -50,21 +50,80 @@ It converts any DOM subtree into a self-contained representation that can be exp
50
50
  [https://snapdom.dev](https://snapdom.dev)
51
51
 
52
52
 
53
+ ## Quick Start
54
+
55
+ **Capture any DOM element to PNG in one line:**
56
+
57
+ ```js
58
+ import { snapdom } from '@zumer/snapdom';
59
+
60
+ const img = await snapdom.toPng(document.querySelector('#card'));
61
+ document.body.appendChild(img);
62
+ ```
63
+
64
+ **Reusable capture** (one clone, multiple exports):
65
+
66
+ ```js
67
+ const result = await snapdom(document.querySelector('#card'));
68
+ await result.toPng(); // → HTMLImageElement
69
+ await result.toSvg(); // → SVG as Image
70
+ await result.download({ format: 'jpg', filename: 'card.jpg' });
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Capture Flow
76
+
77
+ SnapDOM transforms your DOM element through these stages:
78
+
79
+ ```
80
+ DOM Element
81
+ ↓
82
+ Clone
83
+ ↓
84
+ Styles & Pseudo
85
+ ↓
86
+ Images & Backgrounds
87
+ ↓
88
+ Fonts
89
+ ↓
90
+ SVG foreignObject
91
+ ↓
92
+ data:image/svg+xml
93
+ ↓
94
+ toPng / toSvg / toBlob / download
95
+ ```
96
+
97
+ | Stage | What happens |
98
+ |-------|--------------|
99
+ | **Clone** | Deep clone with styles, Shadow DOM, iframes. Exclude/filter nodes. |
100
+ | **Styles & Pseudo** | Inline `::before`/`::after` as elements, resolve `counter()`/`counters()`. |
101
+ | **Images & Backgrounds** | Fetch and inline external images/backgrounds as data URLs. |
102
+ | **Fonts** | Embed `@font-face` (optional) and icon fonts. |
103
+ | **SVG** | Wrap clone in `<foreignObject>`, serialize to `data:image/svg+xml`. |
104
+ | **Export** | Convert SVG to PNG/JPG/WebP/Blob or trigger download. |
105
+
106
+ Plugin hooks: `beforeSnap` → `beforeClone` → `afterClone` → `beforeRender` → `afterRender` → `beforeExport` → `afterExport`.
107
+
108
+
53
109
  ## Table of Contents
54
110
 
111
+ - [Quick Start](#quick-start)
112
+ - [Capture Flow](#capture-flow)
55
113
  - [Installation](#installation)
56
114
  - [NPM / Yarn (stable)](#npm--yarn-stable)
57
115
  - [NPM / Yarn (dev builds)](#npm--yarn-dev-builds)
58
116
  - [CDN (stable)](#cdn-stable)
59
117
  - [CDN (dev builds)](#cdn-dev-builds)
60
- - [Build Outputs & Tree-Shaking](#build-outputs--tree-shaking)
61
- - [Basic usage](#basic-usage)
118
+ - [Build Outputs](#build-outputs--tree-shaking)
119
+ - [Usage](#usage)
62
120
  - [Reusable capture](#reusable-capture)
63
121
  - [One-step shortcuts](#one-step-shortcuts)
64
122
  - [API](#api)
65
123
  - [snapdom(el, options?)](#snapdomel-options)
66
124
  - [Shortcut methods](#shortcut-methods)
67
125
  - [Options](#options)
126
+ - [debug](#debug)
68
127
  - [Fallback image on `<img>` load failure](#fallback-image-on-img-load-failure)
69
128
  - [Dimensions (`scale`, `width`, `height`)](#dimensions-scale-width-height)
70
129
  - [Cross-Origin Images & Fonts (`useProxy`)](#cross-origin-images--fonts-useproxy)
@@ -144,68 +203,59 @@ yarn add @zumer/snapdom@dev
144
203
  </script>
145
204
  ```
146
205
 
147
- ## Build Outputs & Tree-Shaking
206
+ ## Build Outputs
148
207
 
149
- SnapDOM ships multiple build variants, but using it is simple.
150
-
151
- ### npm usage → ESM modular build (tree-shakeable)
152
-
153
- When you import SnapDOM in a project with a bundler:
208
+ | Variant | File | Use case |
209
+ |---------|------|----------|
210
+ | **ESM** (tree-shakeable) | `dist/snapdom.mjs` | Bundlers (Vite, webpack), `import` |
211
+ | **IIFE** (global) | `dist/snapdom.js` | Script tag, legacy `require` |
154
212
 
213
+ **Bundler (npm):**
155
214
  ```js
156
- import { snapdom } from '@zumer/snapdom';
157
- ```
158
-
159
- your environment automatically loads:
160
-
161
- ```sh
162
- dist/modules/snapdom.js
215
+ import { snapdom } from '@zumer/snapdom'; // → dist/snapdom.mjs
163
216
  ```
164
217
 
165
- This is the modular ESM build, enabling:
166
-
167
- - Tree-shaking
168
-
169
- - Code-splitting
170
-
171
- - Lazy loading of exporters (toPng, toJpg, toWebp, etc.)
172
-
173
- You do not need to configure anything; bundlers pick this build automatically.
174
-
175
- ### Script tag usage → Global build
176
-
218
+ **Script tag (CDN):**
177
219
  ```html
178
220
  <script src="https://unpkg.com/@zumer/snapdom/dist/snapdom.js"></script>
179
- <script>
180
- snapdom.toPng(document.body).then(img => {
181
- document.body.appendChild(img);
182
- });
183
- </script>
221
+ <script> snapdom.toPng(document.body).then(img => document.body.appendChild(img)); </script>
222
+ ```
223
+
224
+ **Subpath imports** (lighter bundle if you only need one):
225
+ ```js
226
+ import { preCache } from '@zumer/snapdom/preCache';
227
+ import { plugins } from '@zumer/snapdom/plugins';
184
228
  ```
185
229
 
186
- This loads the monolithic global build and exposes snapdom on window.
187
230
 
231
+ ## Usage
188
232
 
189
- ## Basic usage
233
+ | Pattern | When to use |
234
+ |---------|-------------|
235
+ | **Reusable** `snapdom(el)` | One clone → many exports (PNG + JPG + download). |
236
+ | **Shortcuts** `snapdom.toPng(el)` | Single export, less code. |
190
237
 
191
238
  ### Reusable capture
239
+
240
+ Capture once, export many times (no re-clone):
241
+
192
242
  ```js
193
243
  const el = document.querySelector('#target');
194
244
  const result = await snapdom(el);
195
245
 
196
246
  const img = await result.toPng();
197
247
  document.body.appendChild(img);
198
-
199
248
  await result.download({ format: 'jpg', filename: 'my-capture.jpg' });
200
249
  ```
201
250
 
202
251
  ### One-step shortcuts
252
+
253
+ Direct export when you need a single format:
254
+
203
255
  ```js
204
- const el = document.querySelector('#target');
205
256
  const png = await snapdom.toPng(el);
206
- document.body.appendChild(png);
207
-
208
257
  const blob = await snapdom.toBlob(el);
258
+ document.body.appendChild(png);
209
259
  ```
210
260
 
211
261
  ## API
@@ -282,6 +332,7 @@ All capture methods accept an `options` object:
282
332
 
283
333
  | Option | Type | Default | Description |
284
334
  | ----------------- | -------- | -------- | ----------------------------------------------- |
335
+ | `debug` | boolean | `false` | When `true`, logs suppressed errors to `console.warn` for troubleshooting |
285
336
  | `fast` | boolean | `true` | Skips small idle delays for faster results |
286
337
  | `embedFonts` | boolean | `false` | Inlines non-icon fonts (icon fonts always on) |
287
338
  | `localFonts` | array | `[]` | Local fonts `{ family, src, weight?, style? }` |
@@ -304,6 +355,16 @@ All capture methods accept an `options` object:
304
355
  | `outerTransforms` | boolean | `true` | When `false` removes `translate/rotate` but preserves `scale/skew`, producing a flat, reusable capture |
305
356
  | `outerShadows` | boolean | `false` | Do not expand the root’s bounding box for shadows/blur/outline, and strip those visual effects from the cloned root |
306
357
 
358
+ | `safariWarmupAttempts` | number | `3` | Safari only: iterations to prime font/decode (WebKit #219770). Use `1` if 3 causes lag |
359
+
360
+ ### debug
361
+
362
+ When `debug: true`, SnapDOM logs normally suppressed errors to `console.warn` (with the `[snapdom]` prefix). Useful for troubleshooting capture issues (canvas failures, blob resolution, style stripping, etc.) without noisy output in production.
363
+
364
+ ```js
365
+ await snapdom.toPng(el, { debug: true });
366
+ ```
367
+
307
368
  ### Fallback image on `<img>` load failure
308
369
 
309
370
  Provide a default image for failed `<img>` loads. You can pass a fixed URL or a callback that receives measured dimensions and returns a URL (handy to generate dynamic placeholders).
@@ -527,17 +588,19 @@ const out = await snapdom(element, {
527
588
 
528
589
  ### Plugin Lifecycle Hooks
529
590
 
530
- | Hook | Purpose |
531
- | ------------------------------ | ------------------------------------------------------------------------------------ |
532
- | `beforeSnap(context)` | Before any clone/style work. Ideal for adjusting global capture options. |
533
- | `beforeClone(context)` | Before DOM cloning. Can modify live DOM (use carefully). |
534
- | `afterClone(context)` | After the element subtree has been cloned. Safe to modify styles in the cloned tree. |
535
- | `beforeRender(context)` | Right before SVG/dataURL serialization. |
536
- | `afterRender(context)` | After serialization (you can inspect `context.svgString` or `context.dataURL`). |
537
- | `beforeExport(context)` | Before each export call (`toPng`, `toSvg`, etc.). |
538
- | `afterExport(context, result)` | After each export call — can transform the returned result. |
539
- | `afterSnap(context)` | Runs **once**, after the **first export** finishes. Perfect for cleanup. |
540
- | `defineExports(context)` | Returns a map of **custom exporters**, e.g. `{ pdf: async (ctx, opts) => Blob }`. |
591
+ Hooks run in capture order (see [Capture Flow](#capture-flow)):
592
+
593
+ | Hook | Stage | Purpose |
594
+ |------|-------|---------|
595
+ | `beforeSnap` | Start | Adjust options before any work. |
596
+ | `beforeClone` | Pre-clone | Before DOM clone (modify live DOM carefully). |
597
+ | `afterClone` | Post-clone | Modify cloned tree safely (e.g. inject overlay). |
598
+ | `beforeRender` | Pre-serialize | Right before SVG → data URL. |
599
+ | `afterRender` | Post-serialize | Inspect `context.svgString` / `context.dataURL`. |
600
+ | `beforeExport` | Per export | Before each `toPng`, `toSvg`, etc. |
601
+ | `afterExport` | Per export | Transform returned result. |
602
+ | `afterSnap` | Once | After first export; cleanup. |
603
+ | `defineExports` | Setup | Add custom exporters (e.g. `toPdf`). |
541
604
 
542
605
  > Returned values from `afterExport` are chained to the next plugin (transform pipeline).
543
606
 
@@ -546,7 +609,7 @@ const out = await snapdom(element, {
546
609
  Every hook receives a single `context` object that contains normalized capture state:
547
610
 
548
611
  * **Input & options:**
549
- `element`, `debug`, `fast`, `scale`, `dpr`, `width`, `height`, `backgroundColor`, `quality`, `useProxy`, `cache`, `outerTransforms`, `outerShadows`, `embedFonts`, `localFonts`, `iconFonts`, `excludeFonts`, `exclude`, `excludeMode`, `filter`, `filterMode`, `fallbackURL`.
612
+ `element`, `debug`, `fast`, `scale`, `dpr`, `width`, `height`, `backgroundColor`, `quality`, `useProxy`, `cache`, `outerTransforms`, `outerShadows`, `safariWarmupAttempts`, `embedFonts`, `localFonts`, `iconFonts`, `excludeFonts`, `exclude`, `excludeMode`, `filter`, `filterMode`, `fallbackURL`.
550
613
 
551
614
  * **Intermediate values (depending on stage):**
552
615
  `clone`, `classCSS`, `styleCache`, `fontsCSS`, `baseCSS`, `svgString`, `dataURL`.
@@ -716,6 +779,8 @@ export function myPlugin(options = {}) {
716
779
  * External images should be CORS-accessible (use `useProxy` option for handling CORS denied)
717
780
  * When WebP format is used on Safari, it will fallback to PNG rendering.
718
781
  * `@font-face` CSS rule is well supported, but if need to use JS `FontFace()`, see this workaround [`#43`](https://github.com/zumerlab/snapdom/issues/43)
782
+ * **Safari**: captures with `embedFonts` or background/mask images run slower due to [WebKit #219770](https://bugs.webkit.org/show_bug.cgi?id=219770) (font decode timing). SnapDOM does pre-captures + `drawImage` to prime the pipeline; configurable via `safariWarmupAttempts` (default 3).
783
+ * **Custom scrollbar styles** (`::-webkit-scrollbar`): Applied only when the element has *not* been scrolled. When scrolled, the viewport content is captured without the scrollbar.
719
784
 
720
785
 
721
786
  ## Performance Benchmarks
@@ -786,35 +851,30 @@ Feel free to share suggestions or feedback in [GitHub Discussions](https://githu
786
851
 
787
852
  ## Development
788
853
 
789
- To contribute or build snapDOM locally:
854
+ **Source layout:**
855
+ - `src/api/` – Public API (`snapdom`, `preCache`)
856
+ - `src/core/` – Capture pipeline, clone, prepare, plugins
857
+ - `src/modules/` – Images, fonts, pseudo-elements, backgrounds, SVG
858
+ - `src/exporters/` – toPng, toSvg, toBlob, etc.
859
+ - `dist/` – Build output (`snapdom.js`, `snapdom.mjs`, `preCache.mjs`, `plugins.mjs`)
790
860
 
861
+ **Build:**
791
862
  ```sh
792
- # Clone the repository
793
863
  git clone https://github.com/zumerlab/snapdom.git
794
864
  cd snapdom
795
-
796
- # Switch to dev branch
797
865
  git checkout dev
798
-
799
- # Install dependencies
800
866
  npm install
801
-
802
- # Compile the library (ESM, CJS, and minified versions)
803
867
  npm run compile
868
+ ```
804
869
 
805
- # Install playwright browsers (necessary for running tests)
806
- npx playwright install
807
-
808
- # Run tests
870
+ **Test:**
871
+ ```sh
872
+ npx playwright install # Required for browser tests
809
873
  npm test
810
-
811
- # Run Benchmarks
812
874
  npm run test:benchmark
813
875
  ```
814
876
 
815
- The main entry point is in `src/`, and output bundles are generated in the `dist/` folder.
816
-
817
- For detailed contribution guidelines, please see [CONTRIBUTING](https://github.com/zumerlab/snapdom/blob/main/CONTRIBUTING.md).
877
+ For detailed guidelines, see [CONTRIBUTING](https://github.com/zumerlab/snapdom/blob/main/CONTRIBUTING.md).
818
878
 
819
879
 
820
880
  ## Contributors
@@ -824,27 +884,31 @@ For detailed contribution guidelines, please see [CONTRIBUTING](https://github.c
824
884
  <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>
825
885
  <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>
826
886
  <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>
887
+ <a href="https://github.com/Amyuan23" title="Amyuan23"><img src="https://avatars.githubusercontent.com/u/25892910?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="Amyuan23"/></a>
888
+ <a href="https://github.com/airamhr9" title="airamhr9"><img src="https://avatars.githubusercontent.com/u/57371081?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="airamhr9"/></a>
889
+ <a href="https://github.com/FlavioLimaMindera" title="FlavioLimaMindera"><img src="https://avatars.githubusercontent.com/u/96424442?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="FlavioLimaMindera"/></a>
827
890
  <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>
828
891
  <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>
829
- <a href="https://github.com/Amyuan23" title="Amyuan23"><img src="https://avatars.githubusercontent.com/u/25892910?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="Amyuan23"/></a>
892
+ <a href="https://github.com/kohaiy" title="kohaiy"><img src="https://avatars.githubusercontent.com/u/15622127?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="kohaiy"/></a>
830
893
  <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>
831
894
  <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>
832
895
  <a href="https://github.com/CHOYSEN" title="CHOYSEN"><img src="https://avatars.githubusercontent.com/u/25995358?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="CHOYSEN"/></a>
833
896
  <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>
834
897
  <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>
835
898
  <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>
899
+ <a href="https://github.com/stypr" title="stypr"><img src="https://avatars.githubusercontent.com/u/6625978?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="stypr"/></a>
836
900
  <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>
837
901
  <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>
838
902
  <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>
839
903
  <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>
904
+ <a href="https://github.com/ZiuChen" title="ZiuChen"><img src="https://avatars.githubusercontent.com/u/64892985?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="ZiuChen"/></a>
840
905
  <a href="https://github.com/harshasiddartha" title="harshasiddartha"><img src="https://avatars.githubusercontent.com/u/147021873?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="harshasiddartha"/></a>
906
+ <a href="https://github.com/karasHou" title="karasHou"><img src="https://avatars.githubusercontent.com/u/27048083?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="karasHou"/></a>
841
907
  <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>
842
908
  <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>
843
909
  <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>
844
910
  <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>
845
911
  <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>
846
- <a href="https://github.com/kohaiy" title="kohaiy"><img src="https://avatars.githubusercontent.com/u/15622127?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="kohaiy"/></a>
847
- <a href="https://github.com/fu050409" title="fu050409"><img src="https://avatars.githubusercontent.com/u/46275354?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="fu050409"/></a>
848
912
  </p>
849
913
  <!-- CONTRIBUTORS:END -->
850
914
 
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * SnapDOM
3
- * v2.0.0
3
+ * v2.5.0
4
4
  * Author: Juan Martin Muda
5
5
  * License: MIT
6
6
  */
7
- var f=[];function c(n){if(!n)return null;if(Array.isArray(n)){let[t,o]=n;return typeof t=="function"?t(o):t}if(typeof n=="object"&&"plugin"in n){let{plugin:t,options:o}=n;return typeof t=="function"?t(o):t}return typeof n=="function"?n():n}function p(...n){let t=n.flat();for(let o of t){let i=c(o);i&&(f.some(r=>r&&r.name&&i.name&&r.name===i.name)||f.push(i))}}function l(n){return(n&&Array.isArray(n.plugins)?n.plugins:f)||f}async function g(n,t,o){let i=o,r=l(t);for(let u of r){let e=u&&typeof u[n]=="function"?u[n]:null;if(!e)continue;let s=await e(t,i);typeof s<"u"&&(i=s)}return i}async function y(n,t,o){let i=[],r=l(t);for(let u of r){let e=u&&typeof u[n]=="function"?u[n]:null;if(!e)continue;let s=await e(t,o);typeof s<"u"&&i.push(s)}return i}function m(){return f.slice()}function d(){f.length=0}function a(n){let t=[];if(Array.isArray(n))for(let o of n){let i=c(o);if(!i||!i.name)continue;let r=t.findIndex(u=>u&&u.name===i.name);r>=0&&t.splice(r,1),t.push(i)}for(let o of f)o&&o.name&&!t.some(i=>i.name===o.name)&&t.push(o);return Object.freeze(t)}function A(n,t,o=!1){return!n||n.plugins&&!o||(n.plugins=a(t)),n}function P(){return f.slice()}export{c as a,p as b,g as c,y as d,m as e,d as f,a as g,A as h,P as i};
7
+ var f=[];function c(n){if(!n)return null;if(Array.isArray(n)){let[t,o]=n;return typeof t=="function"?t(o):t}if(typeof n=="object"&&"plugin"in n){let{plugin:t,options:o}=n;return typeof t=="function"?t(o):t}return typeof n=="function"?n():n}function p(...n){let t=n.flat();for(let o of t){let i=c(o);i&&(f.some(r=>r&&r.name&&i.name&&r.name===i.name)||f.push(i))}}function l(n){return(n&&Array.isArray(n.plugins)?n.plugins:f)||f}async function g(n,t,o){let i=o,r=l(t);for(let u of r){let e=u&&typeof u[n]=="function"?u[n]:null;if(!e)continue;let s=await e(t,i);typeof s<"u"&&(i=s)}return i}async function y(n,t,o){let i=[],r=l(t);for(let u of r){let e=u&&typeof u[n]=="function"?u[n]:null;if(!e)continue;let s=await e(t,o);typeof s<"u"&&i.push(s)}return i}function m(){return f.slice()}function d(){f.length=0}function a(n){let t=[];if(Array.isArray(n))for(let o of n){let i=c(o);if(!i||!i.name)continue;let r=t.findIndex(u=>u&&u.name===i.name);r>=0&&t.splice(r,1),t.push(i)}for(let o of f)o&&o.name&&!t.some(i=>i.name===o.name)&&t.push(o);return Object.freeze(t)}function A(n,t,o=!1){return!n||n.plugins&&!o||(n.plugins=a(t)),n}function P(){return f.slice()}export{A as attachSessionPlugins,d as clearPlugins,P as getGlobalPlugins,a as mergePlugins,c as normalizePlugin,m as pluginsList,p as registerPlugins,y as runAll,g as runHook};
@@ -0,0 +1,10 @@
1
+ /*
2
+ * SnapDOM
3
+ * v2.5.0
4
+ * Author: Juan Martin Muda
5
+ * License: MIT
6
+ */
7
+ var L=class extends Map{constructor(e=100,...n){super(...n),this._maxSize=e}set(e,n){if(this.size>=this._maxSize&&!this.has(e)){let o=this.keys().next().value;o!==void 0&&this.delete(o)}return super.set(e,n)}},u={image:new L(100),background:new L(100),resource:new L(150),defaultStyle:new L(30),baseStyle:new L(50),computedStyle:new WeakMap,font:new Set,session:{styleMap:new Map,styleCache:new WeakMap,nodeMap:new Map}};function J(t="soft"){switch(u.session.__counterEpoch=(u.session.__counterEpoch||0)+1,t){case"auto":{u.session.styleMap=new Map,u.session.nodeMap=new Map;return}case"soft":{u.session.styleMap=new Map,u.session.nodeMap=new Map,u.session.styleCache=new WeakMap;return}case"full":return;case"disabled":{u.session.styleMap=new Map,u.session.nodeMap=new Map,u.session.styleCache=new WeakMap,u.computedStyle=new WeakMap,u.baseStyle=new L(50),u.defaultStyle=new L(30),u.image=new L(100),u.background=new L(100),u.resource=new L(150),u.font=new Set;return}default:{u.session.styleMap=new Map,u.session.nodeMap=new Map,u.session.styleCache=new WeakMap;return}}}function B(t){let e=t.match(/url\((['"]?)(.*?)(\1)\)/);if(!e)return null;let n=e[2].trim();return n.startsWith("#")?null:n}function v(t){if(/%[0-9A-Fa-f]{2}/.test(t))return t;try{return encodeURI(t)}catch{return t}}function Z(t,e){if(!t||/^(data|blob|about|#)/i.test(t.trim()))return t;try{let n=e||typeof document<"u"&&(document.baseURI||document.location?.href)||"http://localhost/";return new URL(t,n).href}catch{return t}}function yt(t="[snapDOM]",{ttlMs:e=5*6e4,maxEntries:n=12}={}){let o=new Map,a=0;function i(r,f,c){if(a>=n)return;let l=Date.now();(o.get(f)||0)>l||(o.set(f,l+e),a++,r==="warn"&&console&&console.warn?console.warn(`${t} ${c}`):console&&console.error&&console.error(`${t} ${c}`))}return{warnOnce(r,f){i("warn",r,f)},errorOnce(r,f){i("error",r,f)},reset(){o.clear(),a=0}}}var tt=yt("[snapDOM]",{ttlMs:3*6e4,maxEntries:10}),z=new Map,W=new Map;function wt(t){return/^data:|^blob:|^about:blank$/i.test(t)}function St(t,e){try{let n=typeof location<"u"&&location.href?location.href:"http://localhost/",o=e.includes("{url}")?e.split("{url}")[0]:e,a=new URL(o||".",n),i=new URL(t,n);if(i.origin===a.origin)return!0;let r=i.searchParams;if(r&&(r.has("url")||r.has("target")))return!0}catch{}return!1}function bt(t,e){if(!e||wt(t)||St(t,e))return!1;try{let n=typeof location<"u"&&location.href?location.href:"http://localhost/",o=new URL(t,n);return typeof location<"u"?o.origin!==location.origin:!0}catch{return!!e}}function Ct(t,e){if(!e)return t;if(e.includes("{url}"))return e.replace("{urlRaw}",v(t)).replace("{url}",encodeURIComponent(t));if(/[?&]url=?$/.test(e))return`${e}${encodeURIComponent(t)}`;if(e.endsWith("?"))return`${e}url=${encodeURIComponent(t)}`;if(e.endsWith("/"))return`${e}${v(t)}`;let n=e.includes("?")?"&":"?";return`${e}${n}url=${encodeURIComponent(t)}`}function et(t){return new Promise((e,n)=>{let o=new FileReader;o.onload=()=>e(String(o.result||"")),o.onerror=()=>n(new Error("read_failed")),o.readAsDataURL(t)})}function xt(t,e){return[e.as||"blob",e.timeout??3e3,e.useProxy||"",e.errorTTL??8e3,t].join("|")}async function M(t,e={}){let n=e.as??"blob",o=e.timeout??3e3,a=e.useProxy||"",i=e.errorTTL??8e3,r=e.headers||{},f=!!e.silent;if(/^data:/i.test(t))try{if(n==="text")return{ok:!0,data:String(t),status:200,url:t,fromCache:!1};if(n==="dataURL")return{ok:!0,data:String(t),status:200,url:t,fromCache:!1,mime:String(t).slice(5).split(";")[0]||""};let[,s="",d=""]=String(t).match(/^data:([^,]*),(.*)$/)||[],y=/;base64/i.test(s)?atob(d):decodeURIComponent(d),w=new Uint8Array([...y].map(A=>A.charCodeAt(0))),C=new Blob([w],{type:(s||"").split(";")[0]||""});return{ok:!0,data:C,status:200,url:t,fromCache:!1,mime:C.type||""}}catch{return{ok:!1,data:null,status:0,url:t,fromCache:!1,reason:"special_url_error"}}if(/^blob:/i.test(t))try{let s=await fetch(t);if(!s.ok)return{ok:!1,data:null,status:s.status,url:t,fromCache:!1,reason:"http_error"};let d=await s.blob(),g=d.type||s.headers.get("content-type")||"";return n==="dataURL"?{ok:!0,data:await et(d),status:s.status,url:t,fromCache:!1,mime:g}:n==="text"?{ok:!0,data:await d.text(),status:s.status,url:t,fromCache:!1,mime:g}:{ok:!0,data:d,status:s.status,url:t,fromCache:!1,mime:g}}catch{return{ok:!1,data:null,status:0,url:t,fromCache:!1,reason:"network"}}if(/^about:blank$/i.test(t))return n==="dataURL"?{ok:!0,data:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==",status:200,url:t,fromCache:!1,mime:"image/png"}:{ok:!0,data:n==="text"?"":new Blob([]),status:200,url:t,fromCache:!1};let c=xt(t,{as:n,timeout:o,useProxy:a,errorTTL:i}),l=W.get(c);if(l&&l.until>Date.now())return{...l.result,fromCache:!0};l&&W.delete(c);let m=z.get(c);if(m)return m;let p=bt(t,a)?Ct(t,a):t,S=e.credentials;if(!S)try{let s=typeof location<"u"&&location.href?location.href:"http://localhost/",d=new URL(t,s);S=typeof location<"u"&&d.origin===location.origin?"include":"omit"}catch{S="omit"}let b=new AbortController,x=setTimeout(()=>b.abort("timeout"),o),h=(async()=>{try{let s=await fetch(p,{signal:b.signal,credentials:S,headers:r});if(!s.ok){let y={ok:!1,data:null,status:s.status,url:p,fromCache:!1,reason:"http_error"};if(i>0&&W.set(c,{until:Date.now()+i,result:y}),!f){let w=`${s.status} ${s.statusText||""}`.trim();tt.warnOnce(`http:${s.status}:${n}:${new URL(t,location?.href??"http://localhost/").origin}`,`HTTP error ${w} while fetching ${n} ${t}`)}return e.onError&&e.onError(y),y}if(n==="text")return{ok:!0,data:await s.text(),status:s.status,url:p,fromCache:!1};let d=await s.blob(),g=d.type||s.headers.get("content-type")||"";return n==="dataURL"?{ok:!0,data:await et(d),status:s.status,url:p,fromCache:!1,mime:g}:{ok:!0,data:d,status:s.status,url:p,fromCache:!1,mime:g}}catch(s){let d=s&&typeof s=="object"&&"name"in s&&s.name==="AbortError"?String(s.message||"").includes("timeout")?"timeout":"abort":"network",g={ok:!1,data:null,status:0,url:p,fromCache:!1,reason:d};if(!/^blob:/i.test(t)&&i>0&&W.set(c,{until:Date.now()+i,result:g}),!f){let y=`${d}:${n}:${new URL(t,location?.href??"http://localhost/").origin}`,w=d==="timeout"?`Timeout after ${o}ms. Consider increasing timeout or using a proxy for ${t}`:d==="abort"?`Request aborted while fetching ${n} ${t}`:`Network/CORS issue while fetching ${n} ${t}. A proxy may be required`;tt.errorOnce(y,w)}return e.onError&&e.onError(g),g}finally{clearTimeout(x),z.delete(c)}})();return z.set(c,h),h}async function P(t,e={}){if(/^((repeating-)?(linear|radial|conic)-gradient)\(/i.test(t)||t.trim()==="none")return t;let o=B(t);if(!o)return t;let a=Z(o),i=v(a);if(u.background.has(i)){let r=u.background.get(i);return r?`url("${r}")`:"none"}try{let r=await M(i,{as:"dataURL",useProxy:e.useProxy});return r.ok?(u.background.set(i,r.data),`url("${r.data}")`):(u.background.set(i,null),"none")}catch{return u.background.set(i,null),"none"}}var nt=new Set(["meta","script","noscript","title","link","template"]),K=new Set(["meta","link","style","title","noscript","script","template","g","defs","use","marker","mask","clipPath","pattern","path","polygon","polyline","line","circle","ellipse","rect","filter","lineargradient","radialgradient","stop"]),At=["div","span","p","a","img","ul","li","button","input","select","textarea","label","section","article","header","footer","nav","main","aside","h1","h2","h3","h4","h5","h6","table","thead","tbody","tr","td","th"];function Y(){for(let t of At){let e=String(t).toLowerCase();nt.has(e)||K.has(e)||ot(e)}}function ot(t){if(t=String(t).toLowerCase(),K.has(t)){let i={};return u.defaultStyle.set(t,i),i}if(u.defaultStyle.has(t))return u.defaultStyle.get(t);let e=document.getElementById("snapdom-sandbox");e||(e=document.createElement("div"),e.id="snapdom-sandbox",e.setAttribute("data-snapdom-sandbox","true"),e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.left="-9999px",e.style.top="-9999px",e.style.width="0px",e.style.height="0px",e.style.overflow="hidden",document.body.appendChild(e));let n=document.createElement(t);n.style.all="initial",e.appendChild(n);let o=getComputedStyle(n),a={};for(let i of o){if(rt(i))continue;let r=o.getPropertyValue(i);a[i]=r}return e.removeChild(n),u.defaultStyle.set(t,a),a}var kt=/(?:^|-)(animation|transition)(?:-|$)/i,Rt=/^(--.+|view-timeline|scroll-timeline|animation-trigger|offset-|position-try|app-region|interactivity|overlay|view-transition|-webkit-locale|-webkit-user-(?:drag|modify)|-webkit-tap-highlight-color|-webkit-text-security)$/i,Lt=new Set(["cursor","pointer-events","touch-action","user-select","print-color-adjust","speak","reading-flow","reading-order","anchor-name","anchor-scope","container-name","container-type","timeline-scope"]);function rt(t){let e=String(t).toLowerCase();return!!(Lt.has(e)||Rt.test(e)||kt.test(e))}function $t(t){try{let e=t?.ownerDocument;if(!e)return typeof window<"u"?window:null;let n=e.defaultView;if(n&&typeof n.getComputedStyle=="function")return n;if(typeof window<"u"&&window.frames)for(let o=0;o<window.frames.length;o++)try{if(window.frames[o]?.document===e)return window.frames[o]}catch{}}catch{}return typeof window<"u"?window:null}function N(t,e=null){let n=()=>{let i={length:0,getPropertyValue:()=>"",item:()=>""};return i[Symbol.iterator]=function*(){},i};if(!(t instanceof Element)){let i=typeof window<"u"?window:null;if(i&&typeof i.getComputedStyle=="function")try{return i.getComputedStyle(t,e)||n()}catch{return n()}return n()}let o=u.computedStyle.get(t);o||(o=new Map,u.computedStyle.set(t,o));let a=o.get(e);if(!a){let i=$t(t),r=null;try{r=i&&typeof i.getComputedStyle=="function"?i.getComputedStyle(t,e):null}catch{}if(!r&&typeof window<"u"&&typeof window.getComputedStyle=="function")try{t.ownerDocument===document&&(r=window.getComputedStyle(t,e))}catch{}a=r||n(),o.set(e,a)}return a}function q(t){let e=[],n=0,o=0;for(let a=0;a<t.length;a++){let i=t[a];i==="("&&n++,i===")"&&n--,i===","&&n===0&&(e.push(t.slice(o,a).trim()),o=a+1)}return e.push(t.slice(o).trim()),e}function D(){if(typeof navigator>"u")return!1;let t=navigator.userAgent||"",e=t.toLowerCase(),n=e.includes("safari")&&!e.includes("chrome")&&!e.includes("crios")&&!e.includes("fxios")&&!e.includes("android"),o=/applewebkit/i.test(t),a=/mobile/i.test(t),i=!/safari/i.test(t),r=o&&a&&i,f=/(micromessenger|wxwork|wecom|windowswechat|macwechat)/i.test(t),c=/(baiduboxapp|baidubrowser|baidusearch|baiduboxlite)/i.test(e),l=/ipad|iphone|ipod/.test(e)&&o;return n||r||f||c||l}var Mt=[/font\s*awesome/i,/material\s*icons/i,/ionicons/i,/glyphicons/i,/feather/i,/bootstrap\s*icons/i,/remix\s*icons/i,/heroicons/i,/layui/i,/lucide/i],de=Object.assign({materialIconsFilled:"https://fonts.gstatic.com/s/materialicons/v48/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2",materialIconsOutlined:"https://fonts.gstatic.com/s/materialiconsoutlined/v110/gok-H7zzDkdnRel8-DQ6KAXJ69wP1tGnf4ZGhUcel5euIg.woff2",materialIconsRound:"https://fonts.gstatic.com/s/materialiconsround/v109/LDItaoyNOAY6Uewc665JcIzCKsKc_M9flwmPq_HTTw.woff2",materialIconsSharp:"https://fonts.gstatic.com/s/materialiconssharp/v110/oPWQ_lt5nv4pWNJpghLP75WiFR4kLh3kvmvRImcycg.woff2"},typeof window<"u"&&window.__SNAPDOM_ICON_FONTS__||{}),Et=[];function E(t){let e=typeof t=="string"?t:"",n=[...Mt,...Et];for(let o of n)if(o instanceof RegExp&&o.test(e))return!0;return!!(/icon/i.test(e)||/glyph/i.test(e)||/symbols/i.test(e)||/feather/i.test(e)||/fontawesome/i.test(e))}var _t=new Set(["serif","sans-serif","monospace","cursive","fantasy","system-ui","emoji","math","fangsong","ui-serif","ui-sans-serif","ui-monospace","ui-rounded"]),Ft=["katex","mathjax","mathml"];function X(t){if(!t)return"";for(let e of t.split(",")){let n=e.trim().replace(/^['"]+|['"]+$/g,"");if(n&&!_t.has(n.toLowerCase()))return n}return""}function V(t){let e=String(t??"400").trim().toLowerCase();if(e==="normal")return 400;if(e==="bold")return 700;let n=parseInt(e,10);return Number.isFinite(n)?Math.min(900,Math.max(100,n)):400}function j(t){let e=String(t??"normal").trim().toLowerCase();return e.startsWith("italic")?"italic":e.startsWith("oblique")?"oblique":"normal"}function Ut(t){let e=String(t??"100%").match(/(\d+(?:\.\d+)?)\s*%/);return e?Math.max(50,Math.min(200,parseFloat(e[1]))):100}function It(t){let e=String(t||"400").trim(),n=e.match(/^(\d{2,3})\s+(\d{2,3})$/);if(n){let a=V(n[1]),i=V(n[2]);return{min:Math.min(a,i),max:Math.max(a,i)}}let o=V(e);return{min:o,max:o}}function Ot(t){let e=String(t||"normal").trim().toLowerCase();return e==="italic"?{kind:"italic"}:e.startsWith("oblique")?{kind:"oblique"}:{kind:"normal"}}function Tt(t){let e=String(t||"100%").trim(),n=e.match(/(\d+(?:\.\d+)?)\s*%\s+(\d+(?:\.\d+)?)\s*%/);if(n){let i=parseFloat(n[1]),r=parseFloat(n[2]);return{min:Math.min(i,r),max:Math.max(i,r)}}let o=e.match(/(\d+(?:\.\d+)?)\s*%/),a=o?parseFloat(o[1]):100;return{min:a,max:a}}function vt(t){return!t||typeof t!="string"?"":t.replace(/\s+(variable|vf|v[0-9]+)$/i,"").trim().toLowerCase().replace(/\s+/g,"-")}function Pt(t,e,n=[]){if(!t)return!1;try{let o=new URL(t,location.href);if(o.origin===location.origin)return!0;let i=o.host.toLowerCase();if(["fonts.googleapis.com","fonts.gstatic.com","use.typekit.net","p.typekit.net","kit.fontawesome.com","use.fontawesome.com","cdn.jsdelivr.net","unpkg.com","cdnjs.cloudflare.com","esm.sh"].some(c=>i.endsWith(c))||n.some(c=>i===c.toLowerCase()||i.endsWith("."+c.toLowerCase())))return!0;let f=(o.pathname+o.search).toLowerCase();if(/\bfont(s)?\b/.test(f)||/\.woff2?(\b|$)/.test(f)||Ft.some(c=>f.includes(c)))return!0;for(let c of e){let l=c.toLowerCase().replace(/\s+/g,"+"),m=c.toLowerCase().replace(/\s+/g,"-"),p=vt(c);if(f.includes(l)||f.includes(m)||p&&f.includes(p))return!0}return!1}catch{return!1}}function Nt(t){let e=new Set;for(let n of t||[]){let o=String(n).split("__")[0]?.trim();o&&e.add(o)}return e}function st(t,e){return t&&t.replace(/url\(\s*(['"]?)([^)'"]+)\1\s*\)/g,(n,o,a)=>{let i=(a||"").trim();if(!i||/^data:|^blob:|^https?:|^file:|^about:/i.test(i))return n;let r=i;try{r=new URL(i,e||location.href).href}catch{}return`url("${r}")`})}var H=/@import\s+(?:url\(\s*(['"]?)([^)"']+)\1\s*\)|(['"])([^"']+)\3)([^;]*);/g,G=4;async function Dt(t,e,n){if(!t)return t;let o=new Set;function a(f,c){try{return new URL(f,c||location.href).href}catch{return f}}async function i(f,c,l=0){if(l>G)return console.warn(`[snapDOM] @import depth exceeded (${G}) at ${c}`),f;let m="",p=0,S;for(;S=H.exec(f);){m+=f.slice(p,S.index),p=H.lastIndex;let b=(S[2]||S[4]||"").trim(),x=a(b,c);if(o.has(x)){console.warn(`[snapDOM] Skipping circular @import: ${x}`);continue}o.add(x);let h="";try{let s=await M(x,{as:"text",useProxy:n,silent:!0});s.ok&&typeof s.data=="string"&&(h=s.data)}catch{}h?(h=st(h,x),h=await i(h,x,l+1),m+=`
8
+ /* inlined: ${x} */
9
+ ${h}
10
+ `):m+=S[0]}return m+=f.slice(p),m}let r=st(t,e||location.href);return r=await i(r,e||location.href,0),r}var it=/url\((["']?)([^"')]+)\1\)/g,Bt=/@font-face[^{}]*\{[^}]*\}/g;function ct(t){if(!t)return[];let e=[],n=t.split(",").map(o=>o.trim()).filter(Boolean);for(let o of n){let a=o.match(/^U\+([0-9A-Fa-f?]+)(?:-([0-9A-Fa-f?]+))?$/);if(!a)continue;let i=a[1],r=a[2],f=c=>{if(!c.includes("?"))return parseInt(c,16);let l=parseInt(c.replace(/\?/g,"0"),16),m=parseInt(c.replace(/\?/g,"F"),16);return[l,m]};if(r){let c=f(i),l=f(r),m=Array.isArray(c)?c[0]:c,p=Array.isArray(l)?l[1]:l;e.push([Math.min(m,p),Math.max(m,p)])}else{let c=f(i);Array.isArray(c)?e.push([c[0],c[1]]):e.push([c,c])}}return e}function lt(t,e){if(!e.length||!t||t.size===0)return!0;for(let n of t)for(let[o,a]of e)if(n>=o&&n<=a)return!0;return!1}function Q(t,e){let n=[];if(!t)return n;for(let o of t.matchAll(it)){let a=(o[2]||"").trim();if(!(!a||a.startsWith("data:"))){if(!/^https?:/i.test(a))try{a=new URL(a,e||location.href).href}catch{}n.push(a)}}return n}async function ft(t,e,n=""){let o=t;for(let a of t.matchAll(it)){let i=B(a[0]);if(!i)continue;let r=i;if(!r.startsWith("http")&&!r.startsWith("data:"))try{r=new URL(r,e||location.href).href}catch{}if(!E(r)){if(u.resource?.has(r)){u.font?.add(r),o=o.replace(a[0],`url(${u.resource.get(r)})`);continue}if(!u.font?.has(r))try{let f=await M(r,{as:"dataURL",useProxy:n,silent:!0});if(f.ok&&typeof f.data=="string"){let c=f.data;u.resource?.set(r,c),u.font?.add(r),o=o.replace(a[0],`url(${c})`)}}catch{console.warn("[snapDOM] Failed to fetch font resource:",r)}}}return o}function Wt(t){if(!t.length)return null;let e=(f,c)=>t.some(([l,m])=>!(m<f||l>c)),n=e(0,255)||e(305,305),o=e(256,591)||e(7680,7935),a=e(880,1023),i=e(1024,1279);return e(7840,7929)||e(258,259)||e(416,417)||e(431,432)?"vietnamese":i?"cyrillic":a?"greek":o?"latin-ext":n?"latin":null}function at(t={}){let e=new Set((t.families||[]).map(a=>String(a).toLowerCase())),n=new Set((t.domains||[]).map(a=>String(a).toLowerCase())),o=new Set((t.subsets||[]).map(a=>String(a).toLowerCase()));return(a,i)=>{if(e.size&&e.has(a.family.toLowerCase()))return!0;if(n.size)for(let r of a.srcUrls)try{if(n.has(new URL(r).host.toLowerCase()))return!0}catch{}if(o.size){let r=Wt(i);if(r&&o.has(r))return!0}return!1}}function qt(t){if(!t)return t;let e=/@font-face[^{}]*\{[^}]*\}/gi,n=new Set,o=[];for(let i of t.match(e)||[]){let r=i.match(/font-family:\s*([^;]+);/i)?.[1]||"",f=X(r),c=(i.match(/font-weight:\s*([^;]+);/i)?.[1]||"400").trim(),l=(i.match(/font-style:\s*([^;]+);/i)?.[1]||"normal").trim(),m=(i.match(/font-stretch:\s*([^;]+);/i)?.[1]||"100%").trim(),p=(i.match(/unicode-range:\s*([^;]+);/i)?.[1]||"").trim(),S=(i.match(/src\s*:\s*([^;}]+)[;}]/i)?.[1]||"").trim(),b=Q(S,location.href),x=b.length?b.map(s=>String(s).toLowerCase()).sort().join("|"):S.toLowerCase(),h=[String(f||"").toLowerCase(),c,l,m,p.toLowerCase(),x].join("|");n.has(h)||(n.add(h),o.push(i))}if(o.length===0)return t;let a=0;return t.replace(e,()=>o[a++]||"")}function Vt(t,e,n,o,a){let i=Array.from(t||[]).sort().join("|"),r=e?JSON.stringify({families:(e.families||[]).map(m=>String(m).toLowerCase()).sort(),domains:(e.domains||[]).map(m=>String(m).toLowerCase()).sort(),subsets:(e.subsets||[]).map(m=>String(m).toLowerCase()).sort()}):"",f=(n||[]).map(m=>`${(m.family||"").toLowerCase()}::${m.weight||"normal"}::${m.style||"normal"}::${m.src||""}`).sort().join("|"),c=o||"",l=(a||[]).map(m=>String(m).toLowerCase()).sort().join("|");return`fonts-embed-css::req=${i}::ex=${r}::lf=${f}::px=${c}::fd=${l}`}async function ut(t,e,n,o){let a;try{a=t.cssRules||[]}catch{return}let i=(r,f)=>{try{return new URL(r,f||location.href).href}catch{return r}};for(let r of a){if(r.type===CSSRule.IMPORT_RULE&&r.styleSheet){let f=r.href?i(r.href,e):e;if(o.depth>=G){console.warn(`[snapDOM] CSSOM import depth exceeded (${G}) at ${f}`);continue}if(f&&o.visitedSheets.has(f)){console.warn(`[snapDOM] Skipping circular CSSOM import: ${f}`);continue}f&&o.visitedSheets.add(f);let c={...o,depth:(o.depth||0)+1};await ut(r.styleSheet,f,n,c);continue}if(r.type===CSSRule.FONT_FACE_RULE){let f=(r.style.getPropertyValue("font-family")||"").trim(),c=X(f);if(!c||E(c))continue;let l=(r.style.getPropertyValue("font-weight")||"400").trim(),m=(r.style.getPropertyValue("font-style")||"normal").trim(),p=(r.style.getPropertyValue("font-stretch")||"100%").trim(),S=(r.style.getPropertyValue("src")||"").trim(),b=(r.style.getPropertyValue("unicode-range")||"").trim();if(!o.faceMatchesRequired(c,m,l,p))continue;let x=ct(b);if(!lt(o.usedCodepoints,x))continue;let h={family:c,weightSpec:l,styleSpec:m,stretchSpec:p,unicodeRange:b,srcRaw:S,srcUrls:Q(S,e||location.href),href:e||location.href};if(o.simpleExcluder&&o.simpleExcluder(h,x))continue;if(/url\(/i.test(S)){let s=await ft(S,e||location.href,o.useProxy);await n(`@font-face{font-family:${c};src:${s};font-style:${m};font-weight:${l};font-stretch:${p};${b?`unicode-range:${b};`:""}}`)}else await n(`@font-face{font-family:${c};src:${S};font-style:${m};font-weight:${l};font-stretch:${p};${b?`unicode-range:${b};`:""}}`)}}}async function mt({required:t,usedCodepoints:e,exclude:n=void 0,localFonts:o=[],useProxy:a="",fontStylesheetDomains:i=[]}={}){t instanceof Set||(t=new Set),e instanceof Set||(e=new Set);let r=new Map;for(let s of t){let[d,g,y,w]=String(s).split("__");if(!d)continue;let C=r.get(d)||[];C.push({w:parseInt(g,10),s:y,st:parseInt(w,10)}),r.set(d,C)}function f(s,d,g,y){if(!r.has(s))return!1;let w=r.get(s),C=It(g),A=Ot(d),R=Tt(y),F=C.min!==C.max,U=C.min,T=k=>A.kind==="normal"&&k==="normal"||A.kind!=="normal"&&(k==="italic"||k==="oblique"),I=!1;for(let k of w){let $=F?k.w>=C.min&&k.w<=C.max:k.w===U,_=T(j(k.s)),O=k.st>=R.min&&k.st<=R.max;if($&&_&&O){I=!0;break}}if(I)return!0;if(!F)for(let k of w){let $=T(j(k.s)),_=k.st>=R.min&&k.st<=R.max;if(Math.abs(U-k.w)<=300&&$&&_)return!0}if(!F&&A.kind==="normal"&&w.some($=>j($.s)!=="normal"))for(let $ of w){let _=Math.abs(U-$.w)<=300,O=$.st>=R.min&&$.st<=R.max;if(_&&O)return!0}return!1}let c=at(n),l=Vt(t,n,o,a,i);if(u.resource?.has(l))return u.resource.get(l);let m=Nt(t),p=[],S=H;for(let s of document.querySelectorAll("style")){let d=s.textContent||"";for(let g of d.matchAll(S)){let y=(g[2]||g[4]||"").trim();if(!y||E(y))continue;!!document.querySelector(`link[rel="stylesheet"][href="${y}"]`)||p.push(y)}}p.length&&await Promise.all(p.map(s=>new Promise(d=>{if(document.querySelector(`link[rel="stylesheet"][href="${s}"]`))return d(null);let g=document.createElement("link");g.rel="stylesheet",g.href=s,g.setAttribute("data-snapdom","injected-import"),g.onload=()=>d(g),g.onerror=()=>d(null),document.head.appendChild(g)})));let b="",x=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(s=>!!s.href);for(let s of x)try{if(E(s.href))continue;let d="",g=!1;try{g=new URL(s.href,location.href).origin===location.origin}catch{}if(!g){let w=Array.isArray(i)?i:[];if(!Pt(s.href,m,w))continue}if(g){let w=Array.from(document.styleSheets).find(C=>C.href===s.href);if(w)try{let C=w.cssRules||[];d=Array.from(C).map(A=>A.cssText).join("")}catch{}}if(!d){let w=await M(s.href,{as:"text",useProxy:a});if(w?.ok&&typeof w.data=="string"&&(d=w.data),E(s.href))continue}d=await Dt(d,s.href,a);let y="";for(let w of d.match(Bt)||[]){let C=(w.match(/font-family:\s*([^;]+);/i)?.[1]||"").trim(),A=X(C);if(!A||E(A))continue;let R=(w.match(/font-weight:\s*([^;]+);/i)?.[1]||"400").trim(),F=(w.match(/font-style:\s*([^;]+);/i)?.[1]||"normal").trim(),U=(w.match(/font-stretch:\s*([^;]+);/i)?.[1]||"100%").trim(),T=(w.match(/unicode-range:\s*([^;]+);/i)?.[1]||"").trim(),I=(w.match(/src\s*:\s*([^;}]+)[;}]/i)?.[1]||"").trim(),k=Q(I,s.href);if(!f(A,F,R,U))continue;let $=ct(T);if(!lt(e,$))continue;let _={family:A,weightSpec:R,styleSpec:F,stretchSpec:U,unicodeRange:T,srcRaw:I,srcUrls:k,href:s.href};if(n&&c(_,$))continue;let O=/url\(/i.test(I)?await ft(w,s.href,a):w;y+=O}y.trim()&&(b+=y)}catch{console.warn("[snapDOM] Failed to process stylesheet:",s.href)}let h={requiredIndex:r,usedCodepoints:e,faceMatchesRequired:f,simpleExcluder:n?at(n):null,useProxy:a,visitedSheets:new Set,depth:0};for(let s of document.styleSheets)if(!(s.href&&x.some(d=>d.href===s.href)))try{let d=s.href||location.origin+"/";d&&h.visitedSheets.add(d),await ut(s,d,async g=>{b+=g},h)}catch{}try{for(let s of document.fonts||[]){if(!s||!s.family||s.status!=="loaded"||!s._snapdomSrc)continue;let d=String(s.family).replace(/^['"]+|['"]+$/g,"");if(E(d)||!r.has(d)||n?.families&&n.families.some(y=>String(y).toLowerCase()===d.toLowerCase()))continue;let g=s._snapdomSrc;if(!String(g).startsWith("data:")){if(u.resource?.has(s._snapdomSrc))g=u.resource.get(s._snapdomSrc),u.font?.add(s._snapdomSrc);else if(!u.font?.has(s._snapdomSrc))try{let y=await M(s._snapdomSrc,{as:"dataURL",useProxy:a,silent:!0});if(y.ok&&typeof y.data=="string")g=y.data,u.resource?.set(s._snapdomSrc,g),u.font?.add(s._snapdomSrc);else continue}catch{console.warn("[snapDOM] Failed to fetch dynamic font src:",s._snapdomSrc);continue}}b+=`@font-face{font-family:'${d}';src:url(${g});font-style:${s.style||"normal"};font-weight:${s.weight||"normal"};}`}}catch{}for(let s of o){if(!s||typeof s!="object")continue;let d=String(s.family||"").replace(/^['"]+|['"]+$/g,"");if(!d||E(d)||!r.has(d)||n?.families&&n.families.some(R=>String(R).toLowerCase()===d.toLowerCase()))continue;let g=s.weight!=null?String(s.weight):"normal",y=s.style!=null?String(s.style):"normal",w=s.stretchPct!=null?`${s.stretchPct}%`:"100%",C=String(s.src||""),A=C;if(!A.startsWith("data:")){if(u.resource?.has(C))A=u.resource.get(C),u.font?.add(C);else if(!u.font?.has(C))try{let R=await M(C,{as:"dataURL",useProxy:a,silent:!0});if(R.ok&&typeof R.data=="string")A=R.data,u.resource?.set(C,A),u.font?.add(C);else continue}catch{console.warn("[snapDOM] Failed to fetch localFonts src:",C);continue}}b+=`@font-face{font-family:'${d}';src:url(${A});font-style:${y};font-weight:${g};font-stretch:${w};}`}return b&&(b=qt(b),u.resource?.set(l,b)),b}function dt(t){let e=new Set;if(!t)return e;let n=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT,null),o=r=>{let f=X(r.fontFamily);if(!f)return;let c=(l,m,p)=>`${f}__${V(l)}__${j(m)}__${Ut(p)}`;e.add(c(r.fontWeight,r.fontStyle,r.fontStretch))};o(getComputedStyle(t));let a=getComputedStyle(t,"::before");a&&a.content&&a.content!=="none"&&o(a);let i=getComputedStyle(t,"::after");for(i&&i.content&&i.content!=="none"&&o(i);n.nextNode();){let r=n.currentNode,f=getComputedStyle(r);o(f);let c=getComputedStyle(r,"::before");c&&c.content&&c.content!=="none"&&o(c);let l=getComputedStyle(r,"::after");l&&l.content&&l.content!=="none"&&o(l)}return e}function pt(t){let e=new Set,n=a=>{if(a)for(let i of a)e.add(i.codePointAt(0))},o=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,null);for(;o.nextNode();){let a=o.currentNode;if(a.nodeType===Node.TEXT_NODE)n(a.nodeValue||"");else if(a.nodeType===Node.ELEMENT_NODE){let i=a;for(let r of["::before","::after"]){let c=getComputedStyle(i,r)?.getPropertyValue("content");if(!(!c||c==="none"))if(/^"/.test(c)||/^'/.test(c))n(c.slice(1,-1));else{let l=c.match(/\\[0-9A-Fa-f]{1,6}/g);if(l)for(let m of l)try{e.add(parseInt(m.slice(1),16))}catch{}}}}}return e}async function ht(t,e=2){try{await document.fonts.ready}catch{}let n=Array.from(t||[]).filter(Boolean);if(n.length===0)return;let o=()=>{let a=document.createElement("div");a.style.cssText="position:absolute!important;left:-9999px!important;top:0!important;opacity:0!important;pointer-events:none!important;contain:layout size style;";for(let i of n){let r=document.createElement("span");r.textContent="AaBbGg1234\xC1\xC9\xCD\xD3\xDA\xE7\xF1\u2014\u221E",r.style.fontFamily=`"${i}"`,r.style.fontWeight="700",r.style.fontStyle="italic",r.style.fontSize="32px",r.style.lineHeight="1",r.style.whiteSpace="nowrap",r.style.margin="0",r.style.padding="0",a.appendChild(r)}document.body.appendChild(a),a.offsetWidth,document.body.removeChild(a)};for(let a=0;a<Math.max(1,e);a++)o(),await new Promise(i=>requestAnimationFrame(()=>requestAnimationFrame(i)))}async function gt(t,e,n,o={}){let a=[[t,e]],i=["background-image","mask","mask-image","-webkit-mask","-webkit-mask-image","mask-source","mask-box-image-source","mask-border-source","-webkit-mask-box-image-source","border-image","border-image-source"],r=["mask-position","mask-size","mask-repeat","-webkit-mask-position","-webkit-mask-size","-webkit-mask-repeat","mask-origin","mask-clip","-webkit-mask-origin","-webkit-mask-clip","-webkit-mask-position-x","-webkit-mask-position-y"],f=["background-position","background-position-x","background-position-y","background-size","background-repeat","background-origin","background-clip","background-attachment","background-blend-mode"],c=["border-image-slice","border-image-width","border-image-outset","border-image-repeat"];for(;a.length;){let[l,m]=a.shift();if(!m)continue;let p=n.get(l)||N(l);n.has(l)||n.set(l,p);let S=(()=>{let h=p.getPropertyValue("border-image"),s=p.getPropertyValue("border-image-source");return h&&h!=="none"||s&&s!=="none"})();for(let h of f){let s=p.getPropertyValue(h);s&&m.style.setProperty(h,s)}for(let h of i){let s=p.getPropertyValue(h);if(h==="background-image"&&(!s||s==="none")){let y=p.getPropertyValue("background");y&&/url\s*\(/.test(y)&&(s=q(y).find(w=>/url\s*\(/.test(w))||s)}if(!s||s==="none")continue;let d=q(s),g=await Promise.all(d.map(y=>P(y,o)));g.some(y=>y&&y!=="none"&&!/^url\(undefined/.test(y))&&m.style.setProperty(h,g.join(", "))}for(let h of r){let s=p.getPropertyValue(h);!s||s==="initial"||m.style.setProperty(h,s)}if(S)for(let h of c){let s=p.getPropertyValue(h);!s||s==="initial"||m.style.setProperty(h,s)}let b=l.shadowRoot?Array.from(l.shadowRoot.children).filter(h=>h.tagName!=="STYLE"):Array.from(l.children),x=Array.from(m.children).filter(h=>!(h.dataset?.snapdomPseudo||h.tagName==="STYLE"&&h.dataset?.sd));for(let h=0;h<Math.min(b.length,x.length);h++)a.push([b[h],x[h]])}}async function $e(t=document,e={}){let{embedFonts:n=!0,useProxy:o=""}=e,a=e.cache??e.cacheOpt??"full";J(a);try{await document.fonts?.ready}catch{}try{Y()}catch{}u.session=u.session||{},u.session.styleCache||(u.session.styleCache=new WeakMap),u.image=u.image||new L(100),u.background=u.background||new L(100);try{await gt(t,void 0,u.session.styleCache,{useProxy:o})}catch{}let i=[],r=[];try{if(t&&t.nodeType===1){let c=t.querySelectorAll?Array.from(t.querySelectorAll("*")):[];r=[t,...c],i=[],t.tagName==="IMG"&&t.getAttribute("src")&&i.push(t),i.push(...Array.from(t.querySelectorAll?.("img[src]")||[]))}else t?.querySelectorAll&&(i=Array.from(t.querySelectorAll("img[src]")),r=Array.from(t.querySelectorAll("*")))}catch{}let f=[];for(let c of i){let l=c?.currentSrc||c?.src;if(l&&!u.image.has(l)){let m=Promise.resolve().then(async()=>{let p=await M(l,{as:"dataURL",useProxy:o});p?.ok&&typeof p.data=="string"&&u.image.set(l,p.data)}).catch(()=>{});f.push(m)}}for(let c of r){let l="";try{l=c?.style?.backgroundImage||"",(!l||l==="none")&&(l=N(c).backgroundImage)}catch{}if(l&&l!=="none"){let m=l.match(/url\((?:[^()"']+|"(?:[^"]*)"|'(?:[^']*)')\)/gi)||[];for(let p of m){let S=Promise.resolve().then(()=>P(p,{...e,useProxy:o})).catch(()=>{});f.push(S)}}}if(n)try{let c=dt(t),l=pt(t);if(typeof D=="function"?D():!!D){let p=new Set(Array.from(c).map(S=>String(S).split("__")[0]).filter(Boolean));await ht(p,3)}await mt({required:c,usedCodepoints:l,exclude:e.excludeFonts,localFonts:e.localFonts,useProxy:e.useProxy??o,fontStylesheetDomains:e.fontStylesheetDomains})}catch{}await Promise.allSettled(f)}export{$e as preCache};