@kendawson-online/vantl 2.0.0 → 2.0.4

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
@@ -1,468 +1,256 @@
1
- # Vanilla JS Timeline
2
-
3
- A vanilla JavaScript app to create responsive horizontal and vertical timelines.
4
-
5
- Supports jQuery, external JSON configuration, color theming, HTML support, node images, and deep-linking via URL. Inspired by [timeline](https://github.com/squarechip/timeline) originally created by [Mike Collins](https://github.com/squarechip) in 2018.
6
-
7
- [Link to Screenshot]
8
-
9
- <br/>
10
-
11
- ## Features
12
-
13
- #### 🔘&nbsp; Create / load data via three methods (see Examples)
14
- - Directly via API using Javascript (e.g. jQuery)
15
- - Inline in HTML page using data-attributes
16
- - Externally via JSON configuration file
17
-
18
- #### 🔘&nbsp; Library agnostic. If jQuery is present it will register itself as a plugin.
19
-
20
- #### 🔘&nbsp; Color customization for nodes, timeline, and navigation buttons
21
-
22
- #### 🔘&nbsp; Image support (per-node) with fluid sizing
23
-
24
- #### 🔘&nbsp; Deep link to specific nodes via URL parameters
25
-
26
- #### 🔘&nbsp; Allows multiple independent timelines on a single page
27
-
28
- #### 🔘&nbsp; Auto-initialization when using JSON config
29
-
30
- #### 🔘&nbsp; Caches JSON data to local storage for faster loading
31
-
32
- #### 🔘&nbsp; Responsive layout switches based on screen size
33
-
34
- #### 🔘&nbsp; Small file size
35
-
36
- <br/>
37
-
38
- ### Examples:
39
-
40
- - Using Javascript (jQuery):
41
- &nbsp;&nbsp;[Horizontal](#) &nbsp;|&nbsp; [Vertical](#)
42
- - Using Inline HTML:
43
- &nbsp;&nbsp;[Horizontal Layout](#) &nbsp;|&nbsp; [Vertical Layout](#)
44
- - Using External JSON data:
45
- &nbsp;&nbsp;[Horizontal Layout](#) &nbsp;|&nbsp; [Vertical Layout](#)
46
- - Deep Linking to Nodes:
47
- &nbsp;&nbsp;[Horizontal Layout](#) &nbsp;|&nbsp; [Vertical Layout](#)
48
- - Using Multiple Timelines On A Page:
49
- &nbsp;&nbsp;[Horizontal Layout](#) &nbsp;|&nbsp; [Vertical Layout](#)
50
-
51
- <br/>
52
-
53
- ## Quick Start
54
-
55
- ### 1. Include required files in your page
56
- - Download code and load files locally:
57
- ```html
58
- <html>
59
- <head>
60
- <link href="src/css/timeline.css" rel="stylesheet" />
61
- </head>
62
- <body>
63
- <!-- [ timeline code goes here ] -->
64
- <script src="src/js/timeline.js"></script>
65
- </body>
66
- </html>
67
- ```
68
- - Load files via CDN links:
69
- ````html
70
- <html>
71
- <head>
72
- <link href="https://cdn.jsdelivr.net/gh/kendawson-online/vanillajs-timeline/src/css/timeline.css" rel="stylesheet">
73
- </head>
74
- <body>
75
- <!-- [ timeline code goes here ] -->
76
- <script src="https://cdn.jsdelivr.net/gh/kendawson-online/vanillajs-timeline/src/js/timeline.js"></script>
77
- </body>
78
- </html>
79
- ````
80
-
81
- ### 2. Choose a creation method
82
- - Javascript API (e.g. jQuery)
83
- - Inline HTML data-attributes
84
- - External JSON configuration file
85
-
86
- ### 3. Add timeline data
87
- - If you are using the vanilla JS/Jquery or data-attributes method, you need to add your timeline node data via regular HTML. If you are using the JSON method you can skip this step.
88
-
89
- ````html
90
- <div class="timeline">
91
- <div class="timeline__wrap">
92
- <div class="timeline__items">
93
- <div class="timeline__item">
94
- <div class="timeline__content">
95
- Content / markup here
96
- </div>
97
- </div>
98
- <div class="timeline__item">
99
- <div class="timeline__content">
100
- Content / markup here
101
- </div>
102
- </div>
103
- <div class="timeline__item">
104
- <div class="timeline__content">
105
- Content / markup here
106
- </div>
107
- </div>
108
- <div class="timeline__item">
109
- <div class="timeline__content">
110
- Content / markup here
111
- </div>
112
- </div>
113
- <div class="timeline__item">
114
- <div class="timeline__content">
115
- Content / markup here
116
- </div>
117
- </div>
118
- </div>
119
- </div>
120
- </div>
121
- ````
122
-
123
- - Add timeline nodes via [JSON config](demo/assets/data/sample1.json) file
124
-
125
- [Add More Explaination Text Here]
126
-
127
- - [Convert CSV or Spreadsheet](#) file to JSON [Link to server tool]
128
-
129
- [Add More Explaination Text Here]
130
-
131
- ### 4. Initialize the app
132
- - Using vanilla Javascript
133
- ````javascript
134
- timeline(document.querySelectorAll('.timeline'));
135
- ````
136
- - Using jQuery
137
- ````javascript
138
- jQuery('.timeline').timeline();
139
- ````
140
-
141
- <br/><br/>
142
-
143
- **NOTE: if you're using an external JSON file, you can skip step four. You don't have to manually initialize the app. Loading the JSON file automatically initializes the app for you.**
144
-
145
- <br/>
146
-
147
- ### Javascript API and data-attributes:
148
-
149
- 1. Using data-attributes will take priority over settings via the API.
150
-
151
- 2. Using an external JSON file will take priority over data-attributes and/or API settings.
152
-
153
- <br/><br/>
154
-
155
- # API Options:
156
-
157
- <br/>
158
-
159
- `mode`
160
-
161
- **Choose whether the timeline should be vertical or horizontal**
162
-
163
- JavaScript/jQuery
164
- ````js
165
- default: 'vertical'
166
- options: 'vertical', 'horizontal'
167
- ````
168
-
169
- Data attribute
170
- ````html
171
- <div class="timeline" data-mode="horizontal">
172
- ...
173
- </div>
174
- ````
175
-
176
- <br />
177
-
178
- ------
179
-
180
- <br />
181
-
182
- `minWidth`
183
-
184
- **When using the timeline in horizontal mode, define the minimum viewport width (px) to stay horizontal; below this it becomes vertical/mobile**
185
-
186
- JavaScript/jQuery
187
- ````javascript
188
- default: 600
189
- options: integer
190
- ````
191
-
192
- Data attribute
193
- ````html
194
- <div class="timeline" data-minwidth="600">
195
- ...
196
- </div>
197
- ````
198
-
199
- Notes:
200
- - Backwards compatibility: legacy `forceVerticalMode` (JS) and `data-force-vertical-mode` (HTML) are still accepted.
201
-
202
- <br />
203
-
204
- ------
205
-
206
- <br />
207
-
208
- `horizontalStartPosition`
209
-
210
- **When using the timeline in horizontal mode, define the vertical alignment of the first item**
211
-
212
- JavaScript/jQuery
213
- ````javascript
214
- default: 'top'
215
- options: 'bottom', 'top'
216
- ````
217
-
218
- Data attribute
219
- ````html
220
- <div class="timeline" data-horizontal-start-position="top">
221
- ...
222
- </div>
223
- ````
224
-
225
- <br />
226
-
227
- ------
228
-
229
- <br />
230
-
231
- `moveItems`
232
-
233
- **When using the timeline in horizontal mode, define how many items to move when clicking a navigation button**
234
-
235
- JavaScript/jQuery
236
- ````javascript
237
- default: 1
238
- options: integer
239
- ````
240
-
241
- Data attribute
242
- ````html
243
- <div class="timeline" data-move-items="1">
244
- ...
245
- </div>
246
- ````
247
-
248
- <br />
249
-
250
- ------
251
-
252
- <br />
253
-
254
-
255
- `rtlMode`
256
-
257
- **When using the timeline in horizontal mode, this defines whether the timeline should start from the right. This overrides the startIndex setting.**
258
-
259
- JavaScript/jQuery
260
- ````javascript
261
- default: false
262
- options: true / false
263
- ````
264
-
265
- Data attribute
266
- ````html
267
- <div class="timeline" data-rtl-mode="true">
268
- ...
269
- </div>
270
- ````
271
- <br />
272
-
273
- ------
274
-
275
- <br />
276
-
277
- `startIndex`
278
-
279
- **When using the timeline in horizontal mode, define which item the timeline should start at**
280
-
281
- JavaScript/jQuery
282
- ````javascript
283
- default: 0
284
- options: integer
285
- ````
286
-
287
- Data attribute
288
- ````html
289
- <div class="timeline" data-start-index="0">
290
- ...
291
- </div>
292
- ````
293
-
294
- <br />
295
-
296
- ------
297
-
298
- <br />
299
-
300
- `verticalStartPosition`
301
-
302
- **When using the timeline in vertical mode, define the alignment of the first item**
303
-
304
- JavaScript/jQuery
305
-
306
- ```javascript
307
- default: 'left'
308
- options: 'left', 'right'
309
- ```
310
-
311
- Data attribute
312
-
313
- ```html
314
- <div class="timeline" data-vertical-start-position="right">
315
- ...
316
- </div>
317
- ```
318
-
319
- <br />
320
-
321
- ------
322
-
323
- <br />
324
-
325
- `verticalTrigger`
326
-
327
- **When using the timeline in vertical mode, define the distance from the bottom of the screen, in percent or pixels, that the items slide into view**
328
-
329
- JavaScript/jQuery
330
-
331
- ```javascript
332
- default: '15%'
333
- options: percentage or pixel value e.g. '20%' or '150px'
334
- ```
335
-
336
- Data attribute
337
-
338
- ```html
339
- <div class="timeline" data-vertical-trigger="150px">
340
- ...
341
- </div>
342
- ```
343
-
344
- <br />
345
-
346
- ------
347
-
348
- <br />
349
-
350
- `visibleItems`
351
-
352
- **For horizontal mode: Controls the scrolling range and when navigation arrows appear. Note: With fixed-width timeline items, the actual number of visible items is determined by the container width**
353
-
354
- JavaScript/jQuery
355
-
356
- ```javascript
357
- default: 3
358
- options: integer
359
- ```
360
-
361
- Data attribute
362
-
363
- ```html
364
- <div class="timeline" data-visible-items="3">
365
- ...
366
- </div>
367
- ```
368
- <br />
369
-
370
- ------
371
-
372
- <br />
373
-
374
- `nodeColor`, `lineColor`, `navColor`
375
-
376
- **Set theme colors for nodes, center line, and navigation buttons (horizontal)**
377
-
378
- JavaScript/jQuery
379
-
380
- ```javascript
381
- // any subset can be provided
382
- jQuery('.timeline').timeline({
383
- nodeColor: '#2d6cdf',
384
- lineColor: '#2d6cdf',
385
- navColor: '#f2f2f2'
386
- });
387
- ```
388
-
389
- Data attributes (container)
390
-
391
- ```html
392
- <div class="timeline"
393
- data-node-color="#2d6cdf"
394
- data-line-color="#2d6cdf"
395
- data-nav-color="#f2f2f2">
396
- ...
397
- </div>
398
- ```
399
-
400
- JSON (top-level)
401
-
402
- ```json
403
- {
404
- "nodeColor": "#2d6cdf",
405
- "lineColor": "#2d6cdf",
406
- "navColor": "#f2f2f2"
407
- }
408
- ```
409
-
410
- Notes:
411
- - If only one of `nodeColor` or `lineColor` is set, it is used for both.
412
- - `navColor` automatically sets a contrasting border and arrow color.
413
-
414
- ------
415
-
416
- <br />
417
-
418
- Deep Linking and Node IDs
419
-
420
- **Link to a specific node by ID using `?timeline=<containerId>&id=<nodeId>`**
421
-
422
- - JSON nodes: set `id` on each node; the renderer adds `data-node-id` to items.
423
- - Inline markup: add `data-node-id` to each `.timeline__item` you want addressable.
424
- - On click modals: inline items can optionally declare `data-modal-title`, `data-modal-content`, `data-modal-image`, or `data-modal-html`. If absent, the library derives reasonable defaults from the markup (first heading, first paragraph, first image).
425
-
426
-
427
- ## Server Upload Workflow
428
-
429
- This repository includes a small PHP utility under the `server-tools/` folder that converts CSV / Excel / Google Sheets into the timeline JSON format used by the demo. The basic flow is:
430
-
431
- 1. Open `server-tools/upload.html` in a browser (or host the `server-tools/` folder on a PHP-capable host).
432
- 2. Upload a CSV or `.xls/.xlsx` file, or provide a public Google Sheets URL. The server runs `convert.php` to parse the sheet and produce JSON.
433
- 3. If conversion succeeds the JSON is saved to `server-tools/tmp/` with a unique filename and you are redirected to `server-tools/done.php` which shows a preview and a download link.
434
- 4. Temporary files are cleaned up automatically by `server-tools/cleanup_tmp.php` (24-hour TTL). Run that as a cron job on the server.
435
-
436
- Quick local test (from project root):
437
-
438
- ```bash
439
- php -S localhost:8000 -t .
440
- # then visit http://localhost:8000/server/upload.html
441
- ```
442
-
443
- Notes:
444
- - The converter will set a `lastupdated` timestamp in the JSON if none is provided — this integrates with the client's caching behavior.
445
- - Excel parsing requires `phpoffice/phpspreadsheet` (installed via Composer). `convert.php` auto-loads `vendor/autoload.php` if available in `server/` or project root.
446
-
447
- ## Security Notes (important)
448
-
449
- This upload utility is a convenience tool and not hardened for untrusted public hosting. If you plan to run it on a public server, consider the following safeguards:
450
-
451
- - Validate uploads: restrict accepted MIME types / extensions (`.csv`, `.xls`, `.xlsx`) and enforce a reasonable maximum file size.
452
- - Run file parsing in a controlled environment; avoid executing any uploaded content.
453
- - Store temporary files outside the web root or restrict direct listing/access; `server/done.php` only exposes the saved JSON filename.
454
- - Sanitize all filenames and never use user-supplied filenames for server paths without cleaning.
455
- - Limit rate and require authentication if the endpoint will be public to avoid abuse.
456
- - Use HTTPS to protect uploads in transit.
457
- - Keep Composer dependencies up-to-date and audit for security issues.
458
- - Consider additional input validation on fields extracted from the spreadsheet (e.g., URLs, image paths) before including them in output JSON.
459
-
460
-
461
- ## License & Credits
462
-
463
- This app is released under the [MIT License](LICENSE)
464
-
465
- The original `timeline` project was created by Mike Collins and was also released under the MIT License. His project can be found on GitHub here: [https://github.com/squarechip/timeline](https://github.com/squarechip/timeline)
466
-
467
-
468
- Last updated: Jan. 5, 2026
1
+ # Vantl - Vanilla (JS) Timeline
2
+
3
+ A lightweight, responsive timeline library created with vanilla Javascript for creating beautiful horizontal and vertical timelines with zero dependencies. Inspired by [timeline](https://github.com/squarechip/timeline) originally created by [squarechip](https://github.com/squarechip) in 2018.
4
+
5
+
6
+ ## Features
7
+
8
+ - ✨ **Zero dependencies** - Pure vanilla JavaScript (jQuery optional)
9
+ - 📱 **Fully responsive** - Auto-switches between horizontal/vertical layouts
10
+ - 🎨 **Customizable colors** - Theme nodes, lines, and navigation
11
+ - 🖼️ **Rich content** - Support for images, HTML, and modal popups
12
+ - 🔗 **Deep linking** - Link directly to specific timeline nodes via URL
13
+ - 📦 **Multiple layouts** - Vertical scroll or horizontal carousel modes
14
+ - 💾 **Smart caching** - LocalStorage caching for JSON data
15
+ - 🚀 **Auto-init** - Just add a data attribute to load from JSON
16
+ - 📏 **Small footprint** - Minified and tree-shakeable
17
+
18
+ ## Quick Start
19
+
20
+ ### Via CDN
21
+
22
+ ```html
23
+ <!DOCTYPE html>
24
+ <html>
25
+ <head>
26
+ <!-- timeline stylesheet -->
27
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@kendawson-online/vantl@2/src/css/timeline.css">
28
+ </head>
29
+ <body>
30
+
31
+ <!-- your timeline code here -->
32
+ <div id="timeline" class="timeline" data-json-config="/path/to/your/data.json"></div>
33
+
34
+ <!-- timeline Javascript -->
35
+ <script src="https://cdn.jsdelivr.net/npm/@kendawson-online/vantl@2/dist/timeline.min.js"></script>
36
+ </body>
37
+ </html>
38
+ ```
39
+
40
+ ### Via npm
41
+
42
+ ```bash
43
+ npm install @kendawson-online/vantl
44
+ ```
45
+
46
+ ```javascript
47
+ import { timeline } from '@kendawson-online/vantl';
48
+ import '@kendawson-online/vantl/src/css/timeline.css';
49
+
50
+ timeline(document.querySelectorAll('.timeline'), {
51
+ mode: 'vertical',
52
+ nodeColor: '#2d6cdf'
53
+ });
54
+ ```
55
+
56
+ ## Usage Examples
57
+
58
+ ### 1. Auto-Init with JSON (Easiest)
59
+
60
+ The timeline auto-initializes when you add a `data-json-config` attribute:
61
+
62
+ ```html
63
+ <div class="timeline" data-json-config="/path/to/timeline.json"></div>
64
+ ```
65
+
66
+ **JSON Format:**
67
+ ```json
68
+ {
69
+ "timelineName": "My Timeline",
70
+ "layoutMode": "vertical",
71
+ "lastupdated": "2026-01-08T20:15:34.873Z",
72
+ "nodes": [
73
+ {
74
+ "id": 1,
75
+ "title": "Event Title",
76
+ "content": "Event description...",
77
+ "image": "/path/to/image.jpg"
78
+ }
79
+ ]
80
+ }
81
+ ```
82
+
83
+ ### 2. Inline HTML with Data Attributes
84
+
85
+ ```html
86
+ <div class="timeline" data-mode="horizontal">
87
+ <div class="timeline__wrap">
88
+ <div class="timeline__items">
89
+ <div class="timeline__item">
90
+ <div class="timeline__content">
91
+ <h5>2001</h5>
92
+ <p>Lorem ipsum dolor sit amet, qui <a href="#">minim</a> labore adipisicing minim sint cillum sint consectetur cupidatat.</p>
93
+ </div>
94
+ </div>
95
+ <div class="timeline__item">
96
+ <div class="timeline__content">
97
+ <h5>2002</h5>
98
+ <p>Lorem ipsum <a href="#">dolor sit amet</a>, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.</p>
99
+ </div>
100
+ </div>
101
+ <div class="timeline__item">
102
+ <div class="timeline__content">
103
+ <h5>2003</h5>
104
+ <p>Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.</p>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <script>
112
+ timeline(document.querySelectorAll('.timeline'));
113
+ </script>
114
+ ```
115
+
116
+ ### 3. JavaScript API
117
+
118
+ ```javascript
119
+ // Vanilla JS
120
+ timeline(document.querySelectorAll('.timeline'), {
121
+ mode: 'horizontal',
122
+ visibleItems: 3,
123
+ });
124
+
125
+ // jQuery (if available)
126
+ $('.timeline').timeline({
127
+ mode: 'vertical',
128
+ verticalTrigger: '20%'
129
+ });
130
+ ```
131
+
132
+ ## API Options
133
+
134
+ All options can be set via JavaScript API, data attributes, or JSON config.
135
+
136
+ | Option | Type | Default | Description |
137
+ |--------|------|---------|-------------|
138
+ | `mode` | string | `'vertical'` | Layout mode: `'vertical'` or `'horizontal'` |
139
+ | `minWidth` | number | `600` | Min viewport width (px) to maintain horizontal mode |
140
+ | `visibleItems` | number | `3` | Number of items in horizontal viewport |
141
+ | `moveItems` | number | `1` | Items to scroll per navigation click (horizontal) |
142
+ | `startIndex` | number | `0` | Initial item index (horizontal mode) |
143
+ | `horizontalStartPosition` | string | `'top'` | First item alignment: `'top'` or `'bottom'` |
144
+ | `verticalStartPosition` | string | `'left'` | First item alignment: `'left'` or `'right'` |
145
+ | `verticalTrigger` | string | `'15%'` | Scroll trigger distance: percentage or px (e.g., `'20%'` or `'150px'`) |
146
+ | `rtlMode` | boolean | `false` | Right-to-left mode (horizontal) |
147
+ | `nodeColor` | string | — | Node circle color (hex/rgb/hsl) |
148
+ | `lineColor` | string | — | Center line color (hex/rgb/hsl) |
149
+ | `navColor` | string | | Navigation button color (hex/rgb/hsl) |
150
+
151
+ **Setting Options:**
152
+
153
+ ```javascript
154
+ // JavaScript
155
+ timeline(el, { mode: 'horizontal', nodeColor: '#2d6cdf' });
156
+ ```
157
+
158
+ ```html
159
+ <!-- Data attributes -->
160
+ <div class="timeline" data-mode="horizontal" data-node-color="#2d6cdf">
161
+ ```
162
+
163
+ ```json
164
+ // JSON
165
+ { "layoutMode": "horizontal", "nodeColor": "#2d6cdf" }
166
+ ```
167
+
168
+ ## Deep Linking
169
+
170
+ Link to a specific timeline node using URL parameters:
171
+
172
+ ```
173
+ https://example.com/page.html?timeline=myTimelineId&id=3
174
+ ```
175
+
176
+ - Add `id` attribute to timeline container
177
+ - Add `data-node-id` to each item you want to link to
178
+ - Works automatically with JSON-loaded timelines
179
+
180
+ ## Advanced Features
181
+
182
+ ### Custom Image Path
183
+
184
+ Override the auto-detected image path:
185
+
186
+ ```html
187
+ <script>
188
+ window.TimelineConfig = {
189
+ basePath: '/custom/path/to/images'
190
+ };
191
+ </script>
192
+ <script src="dist/timeline.min.js"></script>
193
+ ```
194
+
195
+ ### Modal Content
196
+
197
+ Each timeline item can display a modal popup on click:
198
+
199
+ ```html
200
+ <div class="timeline__item"
201
+ data-modal-title="Full Title"
202
+ data-modal-content="Extended description..."
203
+ data-modal-image="/img/large.jpg"
204
+ data-modal-html="<p>Custom HTML content</p>">
205
+ ...
206
+ </div>
207
+ ```
208
+
209
+ JSON items automatically support modals with the `title`, `content`, `image`, and `html` fields.
210
+
211
+ ### Programmatic Control
212
+
213
+ ```javascript
214
+ // Load from JSON programmatically
215
+ loadDataFromJson('/data/timeline.json', '#myTimeline');
216
+
217
+ // Clear cache
218
+ clearTimelineCache(); // Clear all
219
+ clearTimelineCache('timelineId'); // Clear specific
220
+
221
+ // Navigate to node (horizontal mode)
222
+ navigateTimelineToNodeIndex(containerElement, 5);
223
+
224
+ // Open modal
225
+ openTimelineModal(itemElement);
226
+
227
+ // Close modal
228
+ closeTimelineModal();
229
+ ```
230
+
231
+ ## Browser Support
232
+
233
+ - Chrome/Edge (2018+)
234
+ - Firefox (2018+)
235
+ - Safari (2018+)
236
+ - Requires: ES6, IntersectionObserver, CSS Custom Properties
237
+
238
+ ## Contributing
239
+
240
+ See [DEVELOPMENT.md](DEVELOPMENT.md) for build instructions and architecture overview.
241
+
242
+ ## License
243
+
244
+ MIT License - see [LICENSE](LICENSE) file for details.
245
+
246
+ ## Credits
247
+
248
+ Originally inspired by [timeline](https://github.com/squarechip/timeline) by [Mike Collins](https://github.com/squarechip) (2018).
249
+
250
+ Refactored and maintained by [Ken Dawson](https://github.com/kendawson-online) (2026).
251
+
252
+ ---
253
+
254
+ **Package:** [@kendawson-online/vantl](https://www.npmjs.com/package/@kendawson-online/vantl)
255
+ **Repository:** [github.com/kendawson-online/vantl](https://github.com/kendawson-online/vantl)
256
+ **CDN:** [cdn.jsdelivr.net/npm/@kendawson-online/vantl](https://cdn.jsdelivr.net/npm/@kendawson-online/vantl)