jj 2.5.0 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +29 -2
  2. package/SKILL.md +667 -0
  3. package/lib/bundle.cjs +2031 -0
  4. package/lib/bundle.cjs.map +1 -0
  5. package/lib/bundle.d.cts +1782 -0
  6. package/lib/bundle.d.ts +1782 -1
  7. package/lib/bundle.global.js +1953 -0
  8. package/lib/bundle.global.js.map +1 -0
  9. package/lib/bundle.js +232 -230
  10. package/lib/bundle.js.map +1 -7
  11. package/lib/bundle.min.cjs +2 -0
  12. package/lib/bundle.min.cjs.map +1 -0
  13. package/lib/bundle.min.d.cts +1782 -0
  14. package/lib/bundle.min.d.ts +1782 -1
  15. package/lib/bundle.min.global.js +2 -0
  16. package/lib/bundle.min.global.js.map +1 -0
  17. package/lib/bundle.min.js +2 -1
  18. package/lib/bundle.min.js.map +1 -0
  19. package/package.json +8 -17
  20. package/lib/JJD.d.ts +0 -87
  21. package/lib/JJD.js +0 -119
  22. package/lib/JJD.js.map +0 -1
  23. package/lib/JJDF.d.ts +0 -74
  24. package/lib/JJDF.js +0 -98
  25. package/lib/JJDF.js.map +0 -1
  26. package/lib/JJE.d.ts +0 -299
  27. package/lib/JJE.js +0 -401
  28. package/lib/JJE.js.map +0 -1
  29. package/lib/JJET.d.ts +0 -79
  30. package/lib/JJET.js +0 -114
  31. package/lib/JJET.js.map +0 -1
  32. package/lib/JJEx.d.ts +0 -63
  33. package/lib/JJEx.js +0 -83
  34. package/lib/JJEx.js.map +0 -1
  35. package/lib/JJHE.d.ts +0 -109
  36. package/lib/JJHE.js +0 -136
  37. package/lib/JJHE.js.map +0 -1
  38. package/lib/JJN-wrap.d.ts +0 -1
  39. package/lib/JJN-wrap.js +0 -46
  40. package/lib/JJN-wrap.js.map +0 -1
  41. package/lib/JJN.d.ts +0 -126
  42. package/lib/JJN.js +0 -166
  43. package/lib/JJN.js.map +0 -1
  44. package/lib/JJNx.d.ts +0 -126
  45. package/lib/JJNx.js +0 -157
  46. package/lib/JJNx.js.map +0 -1
  47. package/lib/JJSE.d.ts +0 -170
  48. package/lib/JJSE.js +0 -217
  49. package/lib/JJSE.js.map +0 -1
  50. package/lib/JJSR.d.ts +0 -71
  51. package/lib/JJSR.js +0 -90
  52. package/lib/JJSR.js.map +0 -1
  53. package/lib/JJT.d.ts +0 -92
  54. package/lib/JJT.js +0 -116
  55. package/lib/JJT.js.map +0 -1
  56. package/lib/case.d.ts +0 -60
  57. package/lib/case.js +0 -92
  58. package/lib/case.js.map +0 -1
  59. package/lib/components.d.ts +0 -147
  60. package/lib/components.js +0 -287
  61. package/lib/components.js.map +0 -1
  62. package/lib/helpers.d.ts +0 -159
  63. package/lib/helpers.js +0 -233
  64. package/lib/helpers.js.map +0 -1
  65. package/lib/index.d.ts +0 -33
  66. package/lib/index.js +0 -35
  67. package/lib/index.js.map +0 -1
  68. package/lib/internal.d.ts +0 -30
  69. package/lib/internal.js +0 -35
  70. package/lib/internal.js.map +0 -1
  71. package/lib/types.d.ts +0 -65
  72. package/lib/types.js +0 -2
  73. package/lib/types.js.map +0 -1
  74. package/lib/util.d.ts +0 -68
  75. package/lib/util.js +0 -90
  76. package/lib/util.js.map +0 -1
  77. package/llms.txt +0 -214
@@ -0,0 +1,1953 @@
1
+ "use strict";
2
+ (() => {
3
+ var __typeError = (msg) => {
4
+ throw TypeError(msg);
5
+ };
6
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
7
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
8
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
9
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
10
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
11
+
12
+ // node_modules/jty/lib/misc.js
13
+ function isDef(x) {
14
+ return x !== void 0;
15
+ }
16
+ function isFn(x) {
17
+ return typeof x === "function";
18
+ }
19
+
20
+ // node_modules/jty/lib/number.js
21
+ var { isNaN, isFinite, isInteger } = Number;
22
+ function isNum(x) {
23
+ return typeof x === "number" && !isNaN(x);
24
+ }
25
+ function inRange(x, min, max) {
26
+ if (!isNum(x)) {
27
+ throw new TypeError(`inRange(): "x" must be a number. Got ${x} (${typeof x})`);
28
+ }
29
+ if (isDef(min)) {
30
+ if (!isNum(min)) {
31
+ throw new TypeError(`inRange(): "min" must be a number. Got ${min} (${typeof min})`);
32
+ }
33
+ if (isDef(max)) {
34
+ if (!isNum(max)) {
35
+ throw new TypeError(`inRange(): "max" must be a number. Got ${max} (${typeof max})`);
36
+ }
37
+ if (min > max) {
38
+ return max <= x && x <= min;
39
+ }
40
+ return min <= x && x <= max;
41
+ }
42
+ return x >= min;
43
+ } else if (isDef(max)) {
44
+ if (!isNum(max)) {
45
+ throw new TypeError(`inRange(): "max" must be a number. Got ${max} (${typeof max})`);
46
+ }
47
+ return x <= max;
48
+ }
49
+ throw new TypeError(`inRange(): expected at least min or max to be defined. Got min=${min} and max=${max}`);
50
+ }
51
+
52
+ // node_modules/jty/lib/array.js
53
+ var { isArray } = Array;
54
+ function isArr(x, minLen = 0, maxLen) {
55
+ return isArray(x) && inRange(x.length, minLen, maxLen);
56
+ }
57
+
58
+ // node_modules/jty/lib/object.js
59
+ var { hasOwnProperty } = Object;
60
+ function isObj(x) {
61
+ return Boolean(x) && typeof x === "object";
62
+ }
63
+ function isA(x, classConstructor) {
64
+ if (!isFn(classConstructor)) {
65
+ throw new TypeError(`Expected a constructor function. Got ${classConstructor} (${typeof classConstructor})`);
66
+ }
67
+ return x instanceof classConstructor;
68
+ }
69
+ function hasProp(x, ...propNames) {
70
+ if (!isObj(x)) {
71
+ return false;
72
+ }
73
+ for (let propName of propNames) {
74
+ if (!(propName in x)) {
75
+ return false;
76
+ }
77
+ }
78
+ return true;
79
+ }
80
+
81
+ // node_modules/jty/lib/string.js
82
+ function isStr(x) {
83
+ return typeof x === "string";
84
+ }
85
+
86
+ // node_modules/jty/lib/same.js
87
+ var { hasOwnProperty: hasOwnProperty2 } = Object;
88
+ var { isArray: isArray2 } = Array;
89
+
90
+ // src/internal.ts
91
+ function errMsg(varName, expected, received) {
92
+ return `Expected '${varName}' to be ${expected}. Got ${received} (${typeof received})`;
93
+ }
94
+ function typeErr(varName, expected, received) {
95
+ return new TypeError(errMsg(varName, expected, received));
96
+ }
97
+
98
+ // src/util.ts
99
+ function fileExt(path) {
100
+ if (!isStr(path)) {
101
+ throw typeErr("path", "a string", path);
102
+ }
103
+ const lastDotIndex = path.lastIndexOf(".");
104
+ if (lastDotIndex === -1) {
105
+ return "";
106
+ }
107
+ const ext = path.slice(lastDotIndex + 1);
108
+ if (ext.indexOf("/") !== -1) {
109
+ return "";
110
+ }
111
+ return ext.toLowerCase().trim();
112
+ }
113
+ function nextAnimationFrame() {
114
+ return new Promise((resolve) => requestAnimationFrame(resolve));
115
+ }
116
+ function sleep(ms = 0) {
117
+ return new Promise((resolve) => setTimeout(resolve, ms));
118
+ }
119
+ async function cssToStyle(css) {
120
+ const sheet = new CSSStyleSheet();
121
+ return await sheet.replace(css);
122
+ }
123
+
124
+ // src/case.ts
125
+ function pas2keb(str) {
126
+ if (!isStr(str)) {
127
+ throw typeErr("str", "a string", str);
128
+ }
129
+ if (/[^a-zA-Z0-9_]/.test(str)) {
130
+ throw new SyntaxError(errMsg("str", "alphanumeric characters and underscores", str));
131
+ }
132
+ return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
133
+ }
134
+ function keb2pas(str) {
135
+ if (!isStr(str)) {
136
+ throw typeErr("str", "a string", str);
137
+ }
138
+ return str.split("-").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("") || // Handle strings that were not kebab-case to begin with (e.g. 'single', 'camelCase')
139
+ (str.length > 0 ? str.charAt(0).toUpperCase() + str.slice(1) : "");
140
+ }
141
+ function keb2cam(str) {
142
+ if (!isStr(str)) {
143
+ throw typeErr("str", "a string", str);
144
+ }
145
+ return str.replace(/^-+|-+$/g, "").replace(/-+([a-z])/g, (g, c) => c.toUpperCase());
146
+ }
147
+
148
+ // src/wrappers/JJET.ts
149
+ var _ref, _boundHandlers, _JJET_instances, getBoundHandler_fn;
150
+ var _JJET = class _JJET {
151
+ /**
152
+ * Creates a JJET instance.
153
+ *
154
+ * @param ref - The EventTarget to wrap.
155
+ * @throws {TypeError} If `ref` is not an EventTarget.
156
+ */
157
+ constructor(ref) {
158
+ __privateAdd(this, _JJET_instances);
159
+ __privateAdd(this, _ref);
160
+ __privateAdd(this, _boundHandlers, /* @__PURE__ */ new WeakMap());
161
+ if (!isA(ref, EventTarget)) {
162
+ throw new TypeError(`JJET expects an EventTarget instance. Got ${ref} (${typeof ref}). `);
163
+ }
164
+ __privateSet(this, _ref, ref);
165
+ }
166
+ static from(ref) {
167
+ return new _JJET(ref);
168
+ }
169
+ /**
170
+ * Gets the underlying DOM object.
171
+ */
172
+ get ref() {
173
+ return __privateGet(this, _ref);
174
+ }
175
+ /**
176
+ * Adds an event listener.
177
+ *
178
+ * @remarks
179
+ * The handler is automatically bound to this JJET instance, so `this` inside the handler
180
+ * refers to the JJET instance, not the DOM element. To access the DOM element, use `this.ref`.
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * JJET.from(window).on('resize', function() {
185
+ * console.log(this) // JJET instance
186
+ * console.log(this.ref) // window object
187
+ * })
188
+ * ```
189
+ * @param eventName - The name of the event.
190
+ * @param handler - The event handler.
191
+ * @param options - Optional event listener options.
192
+ * @returns This instance for chaining.
193
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener | EventTarget.addEventListener}
194
+ */
195
+ on(eventName, handler, options) {
196
+ const boundHandler = __privateMethod(this, _JJET_instances, getBoundHandler_fn).call(this, handler);
197
+ this.ref.addEventListener(eventName, boundHandler, options);
198
+ return this;
199
+ }
200
+ /**
201
+ * Removes an event listener.
202
+ *
203
+ * @remarks
204
+ * Pass the same handler reference that was used in `on()` to properly remove the listener.
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * const handler = function() { console.log(this) }
209
+ * JJET.from(window).on('resize', handler)
210
+ * JJET.from(window).off('resize', handler)
211
+ * ```
212
+ * @param eventName - The name of the event.
213
+ * @param handler - The event handler.
214
+ * @param options - Optional event listener options or boolean.
215
+ * @returns This instance for chaining.
216
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener | EventTarget.removeEventListener}
217
+ */
218
+ off(eventName, handler, options) {
219
+ const boundHandler = __privateMethod(this, _JJET_instances, getBoundHandler_fn).call(this, handler);
220
+ this.ref.removeEventListener(eventName, boundHandler, options);
221
+ return this;
222
+ }
223
+ /**
224
+ * Dispatches an Event at the specified EventTarget.
225
+ *
226
+ * @param event - The Event object to dispatch.
227
+ * @returns This instance for chaining.
228
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent | EventTarget.dispatchEvent}
229
+ */
230
+ trigger(event) {
231
+ this.ref.dispatchEvent(event);
232
+ return this;
233
+ }
234
+ /**
235
+ * Runs a function in the context of this JJET instance.
236
+ *
237
+ * @example
238
+ * ```ts
239
+ * node.run(function() {
240
+ * console.log(this.ref)
241
+ * })
242
+ * ```
243
+ * @remarks
244
+ * If you want to access the current JJ* instance using `this` keyword, you SHOULD use a `function` not an arrow function.
245
+ * If the function throws, `run()` doesn't swallow the exception.
246
+ * So if you're expecting an error, make sure to wrap it in a `try..catch` block and handle the exception.
247
+ * If the function returns a promise, you can `await` on the response.
248
+ *
249
+ * @param fn - The function to run. `this` inside the function will refer to this JJET instance.
250
+ * @param args - Arguments to pass to the function.
251
+ * @returns The return value of the function.
252
+ */
253
+ run(fn, ...args) {
254
+ return fn.call(this, ...args);
255
+ }
256
+ };
257
+ _ref = new WeakMap();
258
+ _boundHandlers = new WeakMap();
259
+ _JJET_instances = new WeakSet();
260
+ /**
261
+ * Gets or creates a bound version of the handler.
262
+ *
263
+ * @remarks
264
+ * Bound handlers are cached in a WeakMap to ensure `off()` can properly remove listeners.
265
+ * When the original handler is garbage collected, the bound version is automatically removed.
266
+ *
267
+ * @param handler - The event handler to bind.
268
+ * @returns The bound handler, or null if the input is null.
269
+ */
270
+ getBoundHandler_fn = function(handler) {
271
+ if (handler === null) return null;
272
+ let bound = __privateGet(this, _boundHandlers).get(handler);
273
+ if (!bound) {
274
+ if (typeof handler === "function") {
275
+ bound = handler.bind(this);
276
+ } else {
277
+ bound = { handleEvent: handler.handleEvent.bind(this) };
278
+ }
279
+ __privateGet(this, _boundHandlers).set(handler, bound);
280
+ }
281
+ return bound;
282
+ };
283
+ var JJET = _JJET;
284
+
285
+ // src/wrappers/JJN-raw.ts
286
+ var JJN = class _JJN extends JJET {
287
+ /**
288
+ * Creates a JJN instance from a Node reference.
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * const node = JJN.from(document.createTextNode('hello'))
293
+ * ```
294
+ *
295
+ * @param node - The Node instance.
296
+ * @returns A new JJN instance.
297
+ */
298
+ static from(node) {
299
+ return new _JJN(node);
300
+ }
301
+ /**
302
+ * Checks if a value can be passed to the `wrap()` or `unwrap()` function.
303
+ *
304
+ * @remarks
305
+ * This is useful for filtering the array that is passed to `append()`, `prepend()` or `setChildren()`
306
+ *
307
+ * @param x an unknown value
308
+ * @returns true if `x` is a string, Node (or its descendents), JJN (or its descendents)
309
+ */
310
+ static isWrapable(x) {
311
+ return isStr(x) || isA(x, Node) || isA(x, _JJN);
312
+ }
313
+ /**
314
+ * Wraps a native DOM node or string into the most specific JJ wrapper available.
315
+ *
316
+ * @remarks
317
+ * This function acts as a factory, inspecting the input type and returning the appropriate
318
+ * subclass of `JJN` (e.g., `JJHE` for `HTMLElement`, `JJT` for `Text`).
319
+ *
320
+ * @example
321
+ * ```ts
322
+ * const bodyWrapper = JJN.wrap(document.body) // Returns JJHE
323
+ * const textWrapper = JJN.wrap('Hello') // Returns JJT wrapping a new Text node
324
+ * ```
325
+ *
326
+ * @param raw - The object to wrap. If it's already Wrapped, it'll be returned without any change. We don't double-wrap or clone it.
327
+ * @returns The most granular Wrapped subclass instance. If the input is already wrapped, it'll be returned as is without cloning.
328
+ * @throws {TypeError} If the input is not a Node, string, or JJ wrapper.
329
+ */
330
+ static wrap(raw) {
331
+ throw new ReferenceError(`The mixin is supposed to override this method.`);
332
+ }
333
+ /**
334
+ * Extracts the underlying native DOM node from a wrapper.
335
+ *
336
+ * @remarks
337
+ * If the input is already a native Node, it is returned as is.
338
+ * If the input is a string, a new Text node is created and returned.
339
+ *
340
+ * @example
341
+ * ```ts
342
+ * const rawElement = JJN.unwrap(myJJHE) // Returns HTMLElement
343
+ * ```
344
+ *
345
+ * @param obj - The object to unwrap.
346
+ * @returns The underlying DOM node.
347
+ * @throws {TypeError} If the input cannot be unwrapped.
348
+ */
349
+ static unwrap(obj) {
350
+ if (isStr(obj)) {
351
+ return document.createTextNode(obj);
352
+ }
353
+ if (!isObj(obj)) {
354
+ throw new TypeError(`JJN.unwrap() expects a string, DOM Node, or JJ wrapper. Got ${obj} (${typeof obj}). `);
355
+ }
356
+ if (isA(obj, Node)) {
357
+ return obj;
358
+ }
359
+ if (isA(obj, _JJN)) {
360
+ return obj.ref;
361
+ }
362
+ throw new TypeError(
363
+ `Could not unwrap ${obj} (${typeof obj}). Expected a string, Node, or JJ wrapper. Make sure you're passing a valid DOM element or JJ wrapper.`
364
+ );
365
+ }
366
+ /**
367
+ * Wraps an iterable object (e.g. an array of wrapped or DOM elements).
368
+ *
369
+ * @example
370
+ * ```ts
371
+ * const wrappedList = JJN.wrapAll(document.querySelectorAll('div'))
372
+ * ```
373
+ *
374
+ * @param iterable - The iterable to wrap.
375
+ * @returns An array of wrapped instances.
376
+ */
377
+ static wrapAll(iterable) {
378
+ return Array.from(iterable, _JJN.wrap);
379
+ }
380
+ /**
381
+ * Unwraps an iterable object (e.g. an array or HTMLCollection).
382
+ *
383
+ * @example
384
+ * ```ts
385
+ * const nodes = JJN.unwrapAll(wrappedList)
386
+ * ```
387
+ *
388
+ * @param iterable - The iterable to unwrap.
389
+ * @returns An array of native DOM nodes.
390
+ */
391
+ static unwrapAll(iterable) {
392
+ return Array.from(iterable, _JJN.unwrap);
393
+ }
394
+ /**
395
+ * Creates an instance of JJN.
396
+ *
397
+ * @param ref - The Node to wrap.
398
+ * @throws {TypeError} If `ref` is not a Node.
399
+ */
400
+ constructor(ref) {
401
+ if (!isA(ref, Node)) {
402
+ throw new TypeError(
403
+ `JJN expects a Node instance. Got ${ref} (${typeof ref}). Use JJN.from(node) with a DOM Node, or check that you're passing a valid DOM element.`
404
+ );
405
+ }
406
+ super(ref);
407
+ }
408
+ /**
409
+ * Clones the Node.
410
+ *
411
+ * @param deep - If true, clones the subtree.
412
+ * @returns A new wrapped instance of the clone.
413
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode | Node.cloneNode}
414
+ */
415
+ clone(deep) {
416
+ return _JJN.wrap(this.ref.cloneNode(deep));
417
+ }
418
+ /**
419
+ * Creates a Text node from a string and appends it to this Node.
420
+ *
421
+ * @remarks
422
+ * This method is overridden in JJT to append to the existing text content instead.
423
+ *
424
+ * @example
425
+ * ```ts
426
+ * el.addText('Hello ')
427
+ * el.addText('World')
428
+ * ```
429
+ *
430
+ * @param text - The text to add. If null or undefined, nothing is added.
431
+ * @returns This instance for chaining.
432
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode | document.createTextNode}
433
+ */
434
+ addText(text) {
435
+ if (text) {
436
+ this.ref.appendChild(document.createTextNode(text));
437
+ }
438
+ return this;
439
+ }
440
+ };
441
+
442
+ // src/wrappers/JJNx.ts
443
+ var JJNx = class extends JJN {
444
+ /**
445
+ * Finds the first element matching a selector within this Element.
446
+ *
447
+ * @example
448
+ * ```ts
449
+ * const span = el.find('span') // Returns null if not found
450
+ * const span = el.find('span', true) // Throws if not found
451
+ * ```
452
+ *
453
+ * @param selector - The CSS selector.
454
+ * @param required - Whether to throw an error if not found. Defaults to false.
455
+ * @returns The wrapped element, or null if not found and required is false.
456
+ * @throws {TypeError} If selector is not a string or element not found and required is true.
457
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector | Element.querySelector}
458
+ */
459
+ find(selector, required = false) {
460
+ const queryResult = this.ref.querySelector(selector);
461
+ if (queryResult) {
462
+ return JJN.wrap(queryResult);
463
+ }
464
+ if (required) {
465
+ throw new TypeError(`No element matched query "${selector}"`);
466
+ }
467
+ return null;
468
+ }
469
+ /**
470
+ * Finds all elements matching a selector within this Element.
471
+ *
472
+ * @example
473
+ * ```ts
474
+ * const items = el.findAll('li')
475
+ * ```
476
+ *
477
+ * @param selector - The CSS selector.
478
+ * @returns An array of wrapped elements.
479
+ * @throws {TypeError} If selector is not a string.
480
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll | Element.querySelectorAll}
481
+ */
482
+ findAll(selector) {
483
+ return JJN.wrapAll(this.ref.querySelectorAll(selector));
484
+ }
485
+ /**
486
+ * Appends children to this Element.
487
+ *
488
+ * @example
489
+ * ```ts
490
+ * el.addChild(h('span', null, 'hello'))
491
+ * ```
492
+ *
493
+ * @remarks
494
+ * To make template codes easier, this function ignores any child that is not possible to `wrap()` (e.g. undefined, null, false).
495
+ *
496
+ * @param children - The children to append.
497
+ * @returns This instance for chaining.
498
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/append | Element.append}
499
+ */
500
+ addChild(...children) {
501
+ const nodes = JJN.unwrapAll(children.filter(JJN.isWrapable));
502
+ this.ref.append(...nodes);
503
+ return this;
504
+ }
505
+ /**
506
+ * Prepends children to this Element.
507
+ *
508
+ * @example
509
+ * ```ts
510
+ * el.preChild(h('span', null, 'first'))
511
+ * ```
512
+ *
513
+ * @remarks
514
+ * To make template codes easier, this function ignores any child that is not possible to `wrap()` (e.g. undefined, null, false).
515
+ *
516
+ * @param children - The children to prepend.
517
+ * @returns This instance for chaining.
518
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/prepend | Element.prepend}
519
+ */
520
+ preChild(...children) {
521
+ const nodes = JJN.unwrapAll(children.filter(JJN.isWrapable));
522
+ this.ref.prepend(...nodes);
523
+ return this;
524
+ }
525
+ /**
526
+ * Maps an array to children and appends them.
527
+ *
528
+ * @example
529
+ * ```ts
530
+ * node.addChildMap(['a', 'b'], item => h('li', null, item))
531
+ * ```
532
+ *
533
+ * @remarks
534
+ * To make template codes easier, this function ignores any child that is not possible to `wrap()` (e.g. undefined, null, false).
535
+ *
536
+ * @param array - The source array.
537
+ * @param mapFn - The mapping function returning a Wrappable.
538
+ * @returns This instance for chaining.
539
+ */
540
+ addChildMap(array, mapFn) {
541
+ return this.addChild(...array.map(mapFn));
542
+ }
543
+ /**
544
+ * Maps an array to children and prepends them.
545
+ *
546
+ * @example
547
+ * ```ts
548
+ * node.preChildMap(['a', 'b'], item => JJHE.create('li').setText(item))
549
+ * ```
550
+ *
551
+ * @remarks
552
+ * To make template codes easier, this function ignores any child that is not possible to `wrap()` (e.g. undefined, null, false).
553
+ *
554
+ * @param array - The source array.
555
+ * @param mapFn - The mapping function.
556
+ * @returns This instance for chaining.
557
+ */
558
+ preChildMap(array, mapFn) {
559
+ return this.preChild(...array.map(mapFn));
560
+ }
561
+ /**
562
+ * Replaces the existing children of an Element with a specified new set of children.
563
+ *
564
+ * @remarks
565
+ * If no children are provided, it empties the Element.
566
+ * To make template codes easier, this function ignores any child that is not possible to `wrap()` (e.g. undefined, null, false).
567
+ *
568
+ * @example
569
+ * ```ts
570
+ * el.setChildren(h('p', null, 'New Content'))
571
+ * ```
572
+ * @param children - The children to replace with.
573
+ * @returns This instance for chaining.
574
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/replaceChildren | Element.replaceChildren}
575
+ */
576
+ setChildren(...children) {
577
+ const nodes = JJN.unwrapAll(children.filter(JJN.isWrapable));
578
+ this.ref.replaceChildren(...nodes);
579
+ return this;
580
+ }
581
+ /**
582
+ * Removes all children from this Element.
583
+ *
584
+ * @example
585
+ * ```ts
586
+ * el.empty()
587
+ * ```
588
+ *
589
+ * @returns This instance for chaining.
590
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/replaceChildren | Element.setChildren}
591
+ */
592
+ empty() {
593
+ this.setChildren();
594
+ return this;
595
+ }
596
+ };
597
+
598
+ // src/wrappers/JJDF.ts
599
+ var JJDF = class _JJDF extends JJNx {
600
+ /**
601
+ * Creates a JJDF instance from a DocumentFragment reference.
602
+ *
603
+ * @example
604
+ * ```ts
605
+ * const frag = JJDF.from(myFrag)
606
+ * ```
607
+ *
608
+ *
609
+ * @param ref - The DocumentFragment instance.
610
+ * @returns A new JJDF instance.
611
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment | DocumentFragment}
612
+ */
613
+ static from(ref) {
614
+ return new _JJDF(ref);
615
+ }
616
+ /**
617
+ * Creates a new empty JJDF instance (wraps a new DocumentFragment).
618
+ *
619
+ * @example
620
+ * ```ts
621
+ * const frag = JJDF.create()
622
+ * ```
623
+ *
624
+ * @returns A new JJDF instance.
625
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment | document.createDocumentFragment}
626
+ */
627
+ static create() {
628
+ return new _JJDF(document.createDocumentFragment());
629
+ }
630
+ /**
631
+ * Creates an instance of JJDF.
632
+ *
633
+ * @param ref - The DocumentFragment instance to wrap.
634
+ * @throws {TypeError} If `ref` is not a DocumentFragment.
635
+ */
636
+ constructor(ref) {
637
+ if (!isA(ref, DocumentFragment)) {
638
+ throw typeErr("ref", "a DocumentFragment", ref);
639
+ }
640
+ super(ref);
641
+ }
642
+ };
643
+
644
+ // src/wrappers/JJSR.ts
645
+ var JJSR = class _JJSR extends JJDF {
646
+ /**
647
+ * Creates a JJSR instance from a ShadowRoot reference.
648
+ *
649
+ * @example
650
+ * ```ts
651
+ * const shadow = JJSR.from(element.shadowRoot)
652
+ * ```
653
+ *
654
+ * @param shadowRoot - The ShadowRoot instance.
655
+ * @returns A new JJSR instance.
656
+ */
657
+ static from(shadowRoot) {
658
+ return new _JJSR(shadowRoot);
659
+ }
660
+ /**
661
+ * Creates an instance of JJSR.
662
+ *
663
+ * @param shadowRoot - The ShadowRoot to wrap.
664
+ * @throws {TypeError} If `shadowRoot` is not a ShadowRoot.
665
+ */
666
+ constructor(shadowRoot) {
667
+ if (!isA(shadowRoot, ShadowRoot)) {
668
+ throw new TypeError(
669
+ `JJSR expects a ShadowRoot instance. Got ${shadowRoot} (${typeof shadowRoot}). Access a shadow root using element.shadowRoot after calling element.attachShadow().`
670
+ );
671
+ }
672
+ super(shadowRoot);
673
+ }
674
+ /**
675
+ * Gets the inner HTML of the ShadowRoot.
676
+ *
677
+ * @returns The inner HTML string.
678
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML | Element.innerHTML}
679
+ */
680
+ getHTML() {
681
+ return this.ref.innerHTML;
682
+ }
683
+ /**
684
+ * Sets the inner HTML of the ShadowRoot.
685
+ *
686
+ * @example
687
+ * ```ts
688
+ * shadow.setHTML('<p>Hello</p>', true)
689
+ * ```
690
+ *
691
+ * @param html - The HTML string to set, or null/undefined to clear.
692
+ * @param unsafe - explicit opt-in to set innerHTML. must be true if html is provided.
693
+ * @returns This instance for chaining.
694
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML | Element.innerHTML}
695
+ */
696
+ setHTML(html, unsafe) {
697
+ if (html && unsafe !== true) {
698
+ throw new Error(
699
+ `Setting innerHTML is unsafe. Pass true as the second argument to confirm you know what you are doing.`
700
+ );
701
+ }
702
+ this.ref.innerHTML = html ?? "";
703
+ return this;
704
+ }
705
+ /**
706
+ * Adds constructed stylesheets to the ShadowRoot.
707
+ *
708
+ * @example
709
+ * ```ts
710
+ * const sheet = new CSSStyleSheet()
711
+ * sheet.replaceSync('p { color: red; }')
712
+ * shadow.addStyleSheets(sheet)
713
+ * ```
714
+ *
715
+ * @param styleSheets - The stylesheets to add.
716
+ * @returns This instance for chaining.
717
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/adoptedStyleSheets | ShadowRoot.adoptedStyleSheets}
718
+ */
719
+ addStyleSheets(...styleSheets) {
720
+ this.ref.adoptedStyleSheets.push(...styleSheets);
721
+ return this;
722
+ }
723
+ };
724
+
725
+ // src/wrappers/JJE.ts
726
+ var JJE = class _JJE extends JJNx {
727
+ /**
728
+ * Creates a JJE instance from an Element reference.
729
+ *
730
+ * @example
731
+ * ```ts
732
+ * const el = JJE.from(document.querySelector('.my-class'))
733
+ * ```
734
+ *
735
+ * @param ref - The Element instance.
736
+ * @returns A new JJE instance.
737
+ */
738
+ static from(ref) {
739
+ return new _JJE(ref);
740
+ }
741
+ /**
742
+ * Creates an instance of JJE.
743
+ *
744
+ * @param ref - The Element to wrap.
745
+ * @throws {TypeError} If `ref` is not an Element.
746
+ */
747
+ constructor(ref) {
748
+ if (!isA(ref, Element)) {
749
+ throw new TypeError(
750
+ `JJE expects an Element instance. Got ${ref} (${typeof ref}). Use JJE.from(element) with a DOM Element, or use the specific wrapper (JJHE for HTMLElement, JJSE for SVGElement).`
751
+ );
752
+ }
753
+ super(ref);
754
+ }
755
+ /**
756
+ * Gets the value of an attribute.
757
+ *
758
+ * @param name - The name of the attribute.
759
+ * @returns The attribute value, or null if not present.
760
+ * @throws {TypeError} If `name` is not a string.
761
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute | Element.getAttribute}
762
+ */
763
+ getAttr(name) {
764
+ if (!isStr(name)) {
765
+ throw typeErr("name", "a string", name);
766
+ }
767
+ return this.ref.getAttribute(name);
768
+ }
769
+ /**
770
+ * Checks if an attribute exists.
771
+ *
772
+ * @param name - The name of the attribute.
773
+ * @returns `true` if the attribute exists, otherwise `false`.
774
+ * @throws {TypeError} If `name` is not a string.
775
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute | Element.hasAttribute}
776
+ */
777
+ hasAttr(name) {
778
+ if (!isStr(name)) {
779
+ throw typeErr("name", "a string", name);
780
+ }
781
+ return this.ref.hasAttribute(name);
782
+ }
783
+ setAttr(nameOrObj, value) {
784
+ if (typeof nameOrObj === "string") {
785
+ this.ref.setAttribute(nameOrObj, value);
786
+ } else if (isObj(nameOrObj)) {
787
+ for (const [k, v] of Object.entries(nameOrObj)) {
788
+ this.ref.setAttribute(k, v);
789
+ }
790
+ } else {
791
+ throw typeErr("nameOrObj", "a string or object", nameOrObj);
792
+ }
793
+ return this;
794
+ }
795
+ /**
796
+ * Removes one or more attributes from the Element.
797
+ *
798
+ * @example
799
+ * ```ts
800
+ * el.rmAttr('disabled') // Remove single
801
+ * el.rmAttr('hidden', 'aria-hidden') // Remove multiple
802
+ * ```
803
+ *
804
+ * @param names - The name(s) of the attribute(s) to remove.
805
+ * @returns This instance for chaining.
806
+ * @throws {TypeError} If any name is not a string.
807
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute | Element.removeAttribute}
808
+ */
809
+ rmAttr(...names) {
810
+ for (const name of names) {
811
+ if (!isStr(name)) {
812
+ throw typeErr("name", "a string", name);
813
+ }
814
+ this.ref.removeAttribute(name);
815
+ }
816
+ return this;
817
+ }
818
+ /**
819
+ * Gets the value of an ARIA attribute.
820
+ *
821
+ * @remarks
822
+ * Automatically prepends `aria-` to the name.
823
+ *
824
+ * @example
825
+ * ```ts
826
+ * el.getAria('label') // gets 'aria-label'
827
+ * ```
828
+ *
829
+ * @param name - The ARIA attribute suffix (e.g., 'label' for 'aria-label').
830
+ * @returns The attribute value, or null if not present.
831
+ * @throws {TypeError} If `name` is not a string.
832
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes | ARIA Attributes}
833
+ */
834
+ getAria(name) {
835
+ if (!isStr(name)) {
836
+ throw typeErr("name", "a string", name);
837
+ }
838
+ return this.ref.getAttribute(`aria-${name}`);
839
+ }
840
+ /**
841
+ * Checks if an ARIA attribute exists.
842
+ *
843
+ * @param name - The ARIA attribute suffix.
844
+ * @returns `true` if the attribute exists.
845
+ * @throws {TypeError} If `name` is not a string.
846
+ */
847
+ hasAria(name) {
848
+ if (!isStr(name)) {
849
+ throw typeErr("name", "a string", name);
850
+ }
851
+ return this.ref.hasAttribute(`aria-${name}`);
852
+ }
853
+ setAria(nameOrObj, value) {
854
+ if (isStr(nameOrObj)) {
855
+ this.ref.setAttribute(`aria-${nameOrObj}`, value);
856
+ } else if (isObj(nameOrObj)) {
857
+ for (const [k, v] of Object.entries(nameOrObj)) {
858
+ this.ref.setAttribute(`aria-${k}`, v);
859
+ }
860
+ } else {
861
+ throw typeErr("nameOrObj", "a string or object", nameOrObj);
862
+ }
863
+ return this;
864
+ }
865
+ /**
866
+ * Removes one or more ARIA attributes from the Element.
867
+ *
868
+ * @example
869
+ * ```ts
870
+ * el.rmAria('hidden') // Remove single
871
+ * el.rmAria('label', 'hidden') // Remove multiple
872
+ * ```
873
+ *
874
+ * @param names - The ARIA attribute suffix(es) to remove.
875
+ * @returns This instance for chaining.
876
+ * @throws {TypeError} If any name is not a string.
877
+ */
878
+ rmAria(...names) {
879
+ for (const name of names) {
880
+ if (!isStr(name)) {
881
+ throw typeErr("name", "a string", name);
882
+ }
883
+ this.ref.removeAttribute(`aria-${name}`);
884
+ }
885
+ return this;
886
+ }
887
+ /**
888
+ * Gets the class attribute.
889
+ *
890
+ * @returns The class attribute value, or null if not present.
891
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/className | Element.className}
892
+ */
893
+ getClass() {
894
+ return this.getAttr("class");
895
+ }
896
+ setClass(classNameOrMap) {
897
+ if (typeof classNameOrMap === "string") {
898
+ return this.setAttr("class", classNameOrMap);
899
+ }
900
+ for (const [className, condition] of Object.entries(classNameOrMap)) {
901
+ if (condition) {
902
+ this.ref.classList.add(className);
903
+ } else {
904
+ this.ref.classList.remove(className);
905
+ }
906
+ }
907
+ return this;
908
+ }
909
+ /**
910
+ * Adds one or more classes to the Element.
911
+ *
912
+ * @example
913
+ * ```ts
914
+ * el.addClass('btn', 'btn-primary')
915
+ * ```
916
+ *
917
+ * @param classNames - The classes to add.
918
+ * @returns This instance for chaining.
919
+ * @throws {TypeError} If any class name is not a string.
920
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/classList | Element.classList}
921
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/add | DOMTokenList.add}
922
+ */
923
+ addClass(...classNames) {
924
+ for (const className of classNames) {
925
+ if (!isStr(className)) {
926
+ throw typeErr("className", "a string", className);
927
+ }
928
+ }
929
+ this.ref.classList.add(...classNames);
930
+ return this;
931
+ }
932
+ /**
933
+ * Removes one or more classes from the Element.
934
+ *
935
+ * @example
936
+ * ```ts
937
+ * el.rmClass('active') // Remove single
938
+ * el.rmClass('btn', 'btn-primary') // Remove multiple
939
+ * ```
940
+ *
941
+ * @param classNames - The classes to remove.
942
+ * @returns This instance for chaining.
943
+ * @throws {TypeError} If any class name is not a string.
944
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/classList | Element.classList}
945
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/remove | DOMTokenList.remove}
946
+ */
947
+ rmClass(...classNames) {
948
+ for (const className of classNames) {
949
+ if (!isStr(className)) {
950
+ throw typeErr("className", "a string", className);
951
+ }
952
+ }
953
+ this.ref.classList.remove(...classNames);
954
+ return this;
955
+ }
956
+ /**
957
+ * Checks if the Element has a specific class.
958
+ *
959
+ * @param className - The class to check for.
960
+ * @returns `true` if the element has the class.
961
+ * @throws {TypeError} If `className` is not a string.
962
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/classList | Element.classList}
963
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/contains | DOMTokenList.contains}
964
+ */
965
+ hasClass(className) {
966
+ if (!isStr(className)) {
967
+ throw typeErr("className", "a string", className);
968
+ }
969
+ return this.ref.classList.contains(className);
970
+ }
971
+ /**
972
+ * Toggles a class on the Element.
973
+ *
974
+ * @param className - The class to toggle.
975
+ * @returns This instance for chaining.
976
+ * @throws {TypeError} If `className` is not a string.
977
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/classList | Element.classList}
978
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle | DOMTokenList.toggle}
979
+ */
980
+ toggleClass(className) {
981
+ if (!isStr(className)) {
982
+ throw typeErr("className", "a string", className);
983
+ }
984
+ this.ref.classList.toggle(className);
985
+ return this;
986
+ }
987
+ /**
988
+ * Replaces a class with another one
989
+ *
990
+ * @remarks
991
+ * If the `oldClassName` doesn't exist, the `newClassName` isn't added
992
+ *
993
+ * @param oldClassName - The class name to remove
994
+ * @param newClassName - The class name to add
995
+ * @throws {TypeError} If either className is not a string.
996
+ */
997
+ replaceClass(oldClassName, newClassName) {
998
+ if (!isStr(oldClassName)) {
999
+ throw typeErr("oldClassName", "a string", oldClassName);
1000
+ }
1001
+ if (!isStr(newClassName)) {
1002
+ throw typeErr("newClassName", "a string", newClassName);
1003
+ }
1004
+ this.ref.classList.replace(oldClassName, newClassName);
1005
+ return this;
1006
+ }
1007
+ /**
1008
+ * Finds the closest ancestor (or self) that matches a CSS selector.
1009
+ *
1010
+ * @remarks
1011
+ * Returns `null` when no matching ancestor is found.
1012
+ *
1013
+ * @example
1014
+ * ```ts
1015
+ * const button = JJE.from(document.querySelector('button'))
1016
+ * const card = button.closest('.card')
1017
+ * if (card) {
1018
+ * card.addClass('has-action')
1019
+ * }
1020
+ * ```
1021
+ *
1022
+ * @param selector - The CSS selector to search for.
1023
+ * @returns A JJE wrapping the closest match, or null when none exists.
1024
+ * @throws {TypeError} If `selector` is not a string.
1025
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/closest | Element.closest}
1026
+ */
1027
+ closest(selector) {
1028
+ if (!isStr(selector)) {
1029
+ throw typeErr("selector", "a string", selector);
1030
+ }
1031
+ const match = this.ref.closest(selector);
1032
+ return match ? JJN.wrap(match) : null;
1033
+ }
1034
+ /**
1035
+
1036
+ * Hides the Element by setting the `hidden` attribute and `aria-hidden="true"`.
1037
+ *
1038
+ * @returns This instance for chaining.
1039
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hidden | hidden attribute}
1040
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden | aria-hidden}
1041
+ */
1042
+ hide() {
1043
+ return this.setAttr("hidden", "").setAttr("aria-hidden", "true");
1044
+ }
1045
+ /**
1046
+ * Shows the Element by removing the `hidden` and `aria-hidden` attributes.
1047
+ *
1048
+ * @returns This instance for chaining.
1049
+ */
1050
+ show() {
1051
+ return this.rmAttr("hidden", "aria-hidden");
1052
+ }
1053
+ /**
1054
+ * Disables the Element by setting the `disabled` attribute and `aria-disabled="true"`.
1055
+ *
1056
+ * @returns This instance for chaining.
1057
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled | disabled attribute}
1058
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled | aria-disabled}
1059
+ */
1060
+ disable() {
1061
+ return this.setAttr("disabled", "").setAttr("aria-disabled", "true");
1062
+ }
1063
+ /**
1064
+ * Enables the Element by removing the `disabled` and `aria-disabled` attributes.
1065
+ *
1066
+ * @returns This instance for chaining.
1067
+ */
1068
+ enable() {
1069
+ return this.rmAttr("disabled", "aria-disabled");
1070
+ }
1071
+ /**
1072
+ * Gets the inner HTML of the Element.
1073
+ *
1074
+ * @remarks
1075
+ * This method operates on `innerHTML`. The method name is kept short for convenience.
1076
+ *
1077
+ * @returns The inner HTML string.
1078
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML | Element.innerHTML}
1079
+ */
1080
+ getHTML() {
1081
+ return this.ref.innerHTML;
1082
+ }
1083
+ /**
1084
+ * Sets the inner HTML of the Element.
1085
+ *
1086
+ * @remarks
1087
+ * This method operates on `innerHTML`. The method name is kept short for convenience.
1088
+ * Pass an empty string, `null`, or `undefined` to clear the content.
1089
+ *
1090
+ * @param html - The HTML string to set, or null/undefined to clear.
1091
+ * @param unsafe - explicit opt-in to set innerHTML. must be true if html is provided.
1092
+ * @returns This instance for chaining.
1093
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML | Element.innerHTML}
1094
+ */
1095
+ setHTML(html, unsafe) {
1096
+ if (html && unsafe !== true) {
1097
+ throw new Error(
1098
+ `Setting innerHTML is unsafe. Pass true as the second argument to confirm you know what you are doing.`
1099
+ );
1100
+ }
1101
+ this.ref.innerHTML = html ?? "";
1102
+ return this;
1103
+ }
1104
+ /**
1105
+ * Attaches a Shadow DOM to the Element and optionally sets its content and styles.
1106
+ *
1107
+ * @remarks
1108
+ * We prevent FOUC by assigning the template and CSS in one go.
1109
+ * **Note:** You can't attach a shadow root to every type of element. There are some that can't have a
1110
+ * shadow DOM for security reasons (for example `<a>`).
1111
+ *
1112
+ * @param mode - The encapsulation mode ('open' or 'closed'). Defaults to 'open'.
1113
+ * @param config - Optional configuration object containing `template` (HTML string) and `styles` (array of CSSStyleSheet).
1114
+ * @returns This instance for chaining.
1115
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow | Element.attachShadow}
1116
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/adoptedStyleSheets | ShadowRoot.adoptedStyleSheets}
1117
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets | Document.adoptedStyleSheets}
1118
+ */
1119
+ initShadow(mode = "open", config) {
1120
+ const shadowRoot = this.ref.shadowRoot ?? this.ref.attachShadow({ mode });
1121
+ if (isObj(config)) {
1122
+ const { template, styles } = config;
1123
+ if (template) {
1124
+ if (isStr(template)) {
1125
+ shadowRoot.innerHTML = template;
1126
+ } else {
1127
+ shadowRoot.appendChild(template);
1128
+ }
1129
+ }
1130
+ if (isArr(styles) && styles.length) {
1131
+ shadowRoot.adoptedStyleSheets.push(...styles);
1132
+ }
1133
+ }
1134
+ return this;
1135
+ }
1136
+ /**
1137
+ * Gets a wrapper around the Element's Shadow Root, if it exists.
1138
+ *
1139
+ * @returns A JJSR instance wrapping the shadow root, or null if no shadow root exists.
1140
+ */
1141
+ get shadow() {
1142
+ return this.ref.shadowRoot ? new JJSR(this.ref.shadowRoot) : null;
1143
+ }
1144
+ };
1145
+
1146
+ // src/wrappers/JJEx.ts
1147
+ var JJEx = class extends JJE {
1148
+ /**
1149
+ * Gets a data attribute from the HTMLElement.
1150
+ *
1151
+ * @example
1152
+ * ```ts
1153
+ * const value = el.getData('my-key')
1154
+ * ```
1155
+ *
1156
+ * @param name - The data attribute name (in camelCase).
1157
+ * @returns The value of the attribute, or undefined if not set.
1158
+ * @throws {TypeError} If `name` is not a string.
1159
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset | HTMLElement.dataset}
1160
+ */
1161
+ getData(name) {
1162
+ if (!isStr(name)) {
1163
+ throw typeErr("name", "a string", name);
1164
+ }
1165
+ return this.ref.dataset[name];
1166
+ }
1167
+ /**
1168
+ * Checks if a data attribute exists on the HTMLElement.
1169
+ *
1170
+ * @example
1171
+ * ```ts
1172
+ * if (el.hasData('my-key')) {
1173
+ * // ...
1174
+ * }
1175
+ * ```
1176
+ *
1177
+ * @param name - The data attribute name (in camelCase).
1178
+ * @returns True if the attribute exists, false otherwise.
1179
+ * @throws {TypeError} If `name` is not a string.
1180
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset | HTMLElement.dataset}
1181
+ */
1182
+ hasData(name) {
1183
+ if (!isStr(name)) {
1184
+ throw typeErr("name", "a string", name);
1185
+ }
1186
+ return hasProp(this.ref.dataset, name);
1187
+ }
1188
+ setData(nameOrObj, value) {
1189
+ if (typeof nameOrObj === "string") {
1190
+ this.ref.dataset[nameOrObj] = value;
1191
+ } else if (isObj(nameOrObj)) {
1192
+ for (const [k, v] of Object.entries(nameOrObj)) {
1193
+ this.ref.dataset[k] = v;
1194
+ }
1195
+ } else {
1196
+ throw typeErr("nameOrObj", "a string or object", nameOrObj);
1197
+ }
1198
+ return this;
1199
+ }
1200
+ /**
1201
+ * Removes one or more data attributes from the HTMLElement.
1202
+ *
1203
+ * @example
1204
+ * ```ts
1205
+ * el.rmData('myKey') // Remove single
1206
+ * el.rmData('myKey', 'otherKey') // Remove multiple
1207
+ * ```
1208
+ *
1209
+ * @param names - The data attribute name(s) (in camelCase).
1210
+ * @returns This instance for chaining.
1211
+ * @throws {TypeError} If any name is not a string.
1212
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset | HTMLElement.dataset}
1213
+ */
1214
+ rmData(...names) {
1215
+ for (const name of names) {
1216
+ if (!isStr(name)) {
1217
+ throw typeErr("name", "a string", name);
1218
+ }
1219
+ delete this.ref.dataset[name];
1220
+ }
1221
+ return this;
1222
+ }
1223
+ };
1224
+
1225
+ // src/wrappers/JJHE.ts
1226
+ var JJHE = class _JJHE extends JJEx {
1227
+ /**
1228
+ * Creates a JJHE instance from an HTMLElement reference.
1229
+ *
1230
+ * @example
1231
+ * ```ts
1232
+ * const el = JJHE.from(document.getElementById('my-id')) // from an existing HTMLElement
1233
+ * const el = JJHE.from(new document.createElement('div')) // from a new HTMLElement
1234
+ * ```
1235
+ *
1236
+ * @param ref - The HTMLElement.
1237
+ * @returns A new JJHE instance.
1238
+ */
1239
+ static from(ref) {
1240
+ return new _JJHE(ref);
1241
+ }
1242
+ static create(tagName, options) {
1243
+ if (!isStr(tagName)) {
1244
+ throw typeErr("tagName", "a string like 'div' or 'button'", tagName);
1245
+ }
1246
+ return new _JJHE(document.createElement(tagName, options));
1247
+ }
1248
+ /**
1249
+ * Creates an instance of JJHE.
1250
+ *
1251
+ * @param ref - The HTMLElement to wrap.
1252
+ * @throws {TypeError} If `ref` is not an HTMLElement.
1253
+ */
1254
+ constructor(ref) {
1255
+ if (!isA(ref, HTMLElement)) {
1256
+ throw typeErr("ref", "an HTMLElement", ref);
1257
+ }
1258
+ super(ref);
1259
+ }
1260
+ /**
1261
+ * Gets the value property of the HTMLElement (e.g. for inputs).
1262
+ *
1263
+ * @returns The value.
1264
+ * @throws {Error} If the HTMLElement does not have a value property.
1265
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/value | HTMLInputElement.value}
1266
+ */
1267
+ getValue() {
1268
+ if (!hasProp(this.ref, "value")) {
1269
+ throw new ReferenceError(`${this.ref.tagName} has no value property.`);
1270
+ }
1271
+ return this.ref.value;
1272
+ }
1273
+ /**
1274
+ * Sets the value property of the HTMLElement.
1275
+ *
1276
+ * @example
1277
+ * ```ts
1278
+ * input.setValue('new value')
1279
+ * input.setValue(42) // Numbers are automatically converted
1280
+ * ```
1281
+ *
1282
+ * @param value - The value to set.
1283
+ * @returns This instance for chaining.
1284
+ * @throws {Error} If the HTMLElement does not have a value property.
1285
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/value | HTMLInputElement.value}
1286
+ */
1287
+ setValue(value) {
1288
+ if (!hasProp(this.ref, "value")) {
1289
+ throw new ReferenceError(`${this.ref.tagName} has no value property.`);
1290
+ }
1291
+ this.ref.value = value;
1292
+ return this;
1293
+ }
1294
+ /**
1295
+ * Focuses the HTMLElement.
1296
+ *
1297
+ * @returns This instance for chaining.
1298
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus | HTMLElement.focus}
1299
+ */
1300
+ focus() {
1301
+ this.ref.focus();
1302
+ return this;
1303
+ }
1304
+ /**
1305
+ * Clicks the HTMLElement.
1306
+ *
1307
+ * @returns This instance for chaining.
1308
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click | HTMLElement.click}
1309
+ */
1310
+ click() {
1311
+ this.ref.click();
1312
+ return this;
1313
+ }
1314
+ /**
1315
+ * Gets the inner text of the HTMLElement.
1316
+ *
1317
+ * @remarks
1318
+ * This method operates on `innerText`. The method name is kept short for convenience.
1319
+ *
1320
+ * @returns The inner text.
1321
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText | HTMLElement.innerText}
1322
+ */
1323
+ getText() {
1324
+ return this.ref.innerText;
1325
+ }
1326
+ /**
1327
+ * Sets the inner text of the HTMLElement.
1328
+ *
1329
+ * @remarks
1330
+ * This method operates on `innerText`. The method name is kept short for convenience.
1331
+ * Pass an empty string, `null`, or `undefined` to clear the content.
1332
+ * Numbers and booleans are automatically converted to strings.
1333
+ *
1334
+ * @param text - The text to set, or null/undefined to clear.
1335
+ * @returns This instance for chaining.
1336
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText | HTMLElement.innerText}
1337
+ */
1338
+ setText(text) {
1339
+ this.ref.innerText = text ?? "";
1340
+ return this;
1341
+ }
1342
+ };
1343
+
1344
+ // src/wrappers/JJT.ts
1345
+ var JJT = class _JJT extends JJN {
1346
+ /**
1347
+ * Creates a JJT instance from a Text node.
1348
+ *
1349
+ * @example
1350
+ * ```ts
1351
+ * const textNode = document.createTextNode('foo')
1352
+ * const text = JJT.from(textNode)
1353
+ * ```
1354
+ *
1355
+ * @param text - The Text node.
1356
+ * @returns A new JJT instance.
1357
+ * @throws {TypeError} If `text` is not a Text node.
1358
+ */
1359
+ static from(text) {
1360
+ return new _JJT(text);
1361
+ }
1362
+ static fromStr(text) {
1363
+ return new _JJT(document.createTextNode(text));
1364
+ }
1365
+ /**
1366
+ * Creates an instance of JJT.
1367
+ *
1368
+ * @example
1369
+ * ```ts
1370
+ * const text = new JJT('Hello World')
1371
+ * ```
1372
+ *
1373
+ * @param ref - The Text node or a string to create a Text node from.
1374
+ * @throws {TypeError} If `ref` is not a Text node or string.
1375
+ */
1376
+ constructor(ref) {
1377
+ if (!isA(ref, Text)) {
1378
+ throw new TypeError(
1379
+ `JJT expects a Text node. Got ${ref} (${typeof ref}). Create a Text node with JJT.fromStr() or document.createTextNode('text').`
1380
+ );
1381
+ }
1382
+ super(ref);
1383
+ }
1384
+ /**
1385
+ * Gets the text content of the Text node.
1386
+ *
1387
+ * @example
1388
+ * ```ts
1389
+ * const content = text.getText()
1390
+ * ```
1391
+ *
1392
+ * @returns The text content.
1393
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent | Node.textContent}
1394
+ */
1395
+ getText() {
1396
+ return this.ref.textContent;
1397
+ }
1398
+ /**
1399
+ * Sets the text content of the Text node.
1400
+ *
1401
+ * @example
1402
+ * ```ts
1403
+ * text.setText('New content')
1404
+ * ```
1405
+ *
1406
+ * @param text - The text to set. Set it to null or undefined to remove all text
1407
+ * @returns This instance for chaining.
1408
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent | Node.textContent}
1409
+ */
1410
+ setText(text) {
1411
+ this.ref.textContent = text ?? null;
1412
+ return this;
1413
+ }
1414
+ /**
1415
+ * Appends text to the existing content.
1416
+ *
1417
+ * @example
1418
+ * ```ts
1419
+ * text.setText('hello')
1420
+ * text.addText(' world')
1421
+ * console.log(text.getText()) // 'hello world'
1422
+ * ```
1423
+ *
1424
+ * @param text - The string to add to the existing contents. If null or undefined, nothing is added.
1425
+ * @returns This instance for chaining.
1426
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent | Node.textContent}
1427
+ */
1428
+ addText(text) {
1429
+ if (text != null) {
1430
+ this.ref.textContent += text;
1431
+ }
1432
+ return this;
1433
+ }
1434
+ /**
1435
+ * Clears the text content of the Text node.
1436
+ *
1437
+ * @example
1438
+ * ```ts
1439
+ * text.empty()
1440
+ * ```
1441
+ *
1442
+ * @returns This instance for chaining.
1443
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent | Node.textContent}
1444
+ */
1445
+ empty() {
1446
+ return this.setText("");
1447
+ }
1448
+ };
1449
+
1450
+ // src/wrappers/JJD.ts
1451
+ var JJD = class _JJD extends JJNx {
1452
+ /**
1453
+ * Creates a JJD instance from a Document reference.
1454
+ *
1455
+ * @example
1456
+ * ```ts
1457
+ * const doc = JJD.from(document)
1458
+ * ```
1459
+ *
1460
+ * @param ref - The Document instance.
1461
+ * @returns A new JJD instance.
1462
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Document | Document}
1463
+ */
1464
+ static from(ref) {
1465
+ return new _JJD(ref);
1466
+ }
1467
+ /**
1468
+ * Creates an instance of JJD.
1469
+ *
1470
+ * @param ref - The Document instance to wrap.
1471
+ * @throws {TypeError} If `ref` is not a Document.
1472
+ */
1473
+ constructor(ref) {
1474
+ if (!isA(ref, Document)) {
1475
+ throw new TypeError(`JJD expects a Document instance. Got ${ref} (${typeof ref}). `);
1476
+ }
1477
+ super(ref);
1478
+ }
1479
+ /**
1480
+ * Gets the `<head>` element of the document wrapped in a `JJHE` instance.
1481
+ *
1482
+ * @returns The wrapped head element.
1483
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/head | Document.head}
1484
+ */
1485
+ get head() {
1486
+ return JJHE.from(this.ref.head);
1487
+ }
1488
+ /**
1489
+ * Gets the `<body>` element of the document wrapped in a `JJHE` instance.
1490
+ *
1491
+ * @returns The wrapped body element.
1492
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/body | Document.body}
1493
+ */
1494
+ get body() {
1495
+ return JJHE.from(this.ref.body);
1496
+ }
1497
+ };
1498
+
1499
+ // src/wrappers/JJSE.ts
1500
+ var SVG_NAMESPACE_URI = "http://www.w3.org/2000/svg";
1501
+ var JJSE = class _JJSE extends JJEx {
1502
+ /**
1503
+ * Creates a JJSE instance from an SVGElement reference.
1504
+ *
1505
+ * @example
1506
+ * ```ts
1507
+ * const svg = JJSE.from(myCircle)
1508
+ * ```
1509
+ *
1510
+ * @param ref - The SVGElement.
1511
+ * @returns A new JJSE instance.
1512
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/SVGElement | SVGElement}
1513
+ */
1514
+ static from(ref) {
1515
+ return new _JJSE(ref);
1516
+ }
1517
+ /**
1518
+ * Creates a JJSE instance from a tag name (in the SVG namespace).
1519
+ *
1520
+ * @remarks
1521
+ * Automatically uses the correct SVG namespace URI: `http://www.w3.org/2000/svg`.
1522
+ *
1523
+ * @example
1524
+ * ```ts
1525
+ * const circle = JJSE.create('circle')
1526
+ * ```
1527
+ *
1528
+ * @param tagName - The tag name.
1529
+ * @param options - Element creation options.
1530
+ * @returns A new JJSE instance.
1531
+ * @throws {TypeError} If `tagName` is not a string.
1532
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS | document.createElementNS}
1533
+ */
1534
+ static create(tagName, options) {
1535
+ if (!isStr(tagName)) {
1536
+ throw typeErr("tagName", 'a string like "circle" or "path"', tagName);
1537
+ }
1538
+ const element = document.createElementNS(SVG_NAMESPACE_URI, tagName, options);
1539
+ return new _JJSE(element);
1540
+ }
1541
+ /**
1542
+ * Creates an instance of JJSE.
1543
+ *
1544
+ * @param ref - The SVGElement to wrap.
1545
+ * @throws {TypeError} If `ref` is not an SVGElement.
1546
+ */
1547
+ constructor(ref) {
1548
+ if (!isA(ref, SVGElement)) {
1549
+ throw typeErr("ref", "an SVGElement", ref);
1550
+ }
1551
+ super(ref);
1552
+ }
1553
+ /**
1554
+ * Gets the text content of the SVGElement.
1555
+ *
1556
+ * @remarks
1557
+ * This method operates on `textContent`. The method name is kept short for convenience.
1558
+ *
1559
+ * @example
1560
+ * ```ts
1561
+ * const text = svg.getText()
1562
+ * ```
1563
+ *
1564
+ * @returns The text content.
1565
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent | Node.textContent}
1566
+ */
1567
+ getText() {
1568
+ return this.ref.textContent ?? "";
1569
+ }
1570
+ /**
1571
+ * Sets the text content of the SVGElement.
1572
+ *
1573
+ * @remarks
1574
+ * This method operates on `textContent`. The method name is kept short for convenience.
1575
+ * Pass an empty string, `null`, or `undefined` to clear the content.
1576
+ * Numbers and booleans are automatically converted to strings.
1577
+ *
1578
+ * @example
1579
+ * ```ts
1580
+ * svg.setText('Hello SVG')
1581
+ * svg.setText(null) // Clear content
1582
+ * svg.setText(42) // Numbers are converted
1583
+ * ```
1584
+ *
1585
+ * @param text - The text to set, or null/undefined to clear.
1586
+ * @returns This instance for chaining.
1587
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent | Node.textContent}
1588
+ */
1589
+ setText(text) {
1590
+ this.ref.textContent = text ?? "";
1591
+ return this;
1592
+ }
1593
+ /**
1594
+ * Sets the fill attribute.
1595
+ *
1596
+ * @param value - The fill color/value.
1597
+ * @returns This instance for chaining.
1598
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill | fill}
1599
+ */
1600
+ setFill(value) {
1601
+ return this.setAttr("fill", value);
1602
+ }
1603
+ /**
1604
+ * Sets the stroke attribute.
1605
+ *
1606
+ * @param value - The stroke color/value.
1607
+ * @returns This instance for chaining.
1608
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke | stroke}
1609
+ */
1610
+ setStroke(value) {
1611
+ return this.setAttr("stroke", value);
1612
+ }
1613
+ /**
1614
+ * Sets the stroke-width attribute.
1615
+ *
1616
+ * @param value - The width.
1617
+ * @returns This instance for chaining.
1618
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-width | stroke-width}
1619
+ */
1620
+ setStrokeWidth(value) {
1621
+ return this.setAttr("stroke-width", String(value));
1622
+ }
1623
+ /**
1624
+ * Sets the viewBox attribute.
1625
+ *
1626
+ * @example
1627
+ * ```ts
1628
+ * svg.setViewBox(0, 0, 100, 100)
1629
+ * svg.setViewBox('0 0 100 100')
1630
+ * ```
1631
+ *
1632
+ * @param p1 - Min-x or string/array value.
1633
+ * @param p2 - Min-y.
1634
+ * @param p3 - Width.
1635
+ * @param p4 - Height.
1636
+ * @returns This instance for chaining.
1637
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox | viewBox}
1638
+ */
1639
+ setViewBox(p1, p2, p3, p4) {
1640
+ if (typeof p1 === "number" && p2 !== void 0 && p3 !== void 0 && p4 !== void 0) {
1641
+ return this.setAttr("viewBox", `${p1} ${p2} ${p3} ${p4}`);
1642
+ }
1643
+ const value = p1;
1644
+ return this.setAttr("viewBox", Array.isArray(value) ? value.join(" ") : value);
1645
+ }
1646
+ /**
1647
+ * Sets the width attribute.
1648
+ *
1649
+ * @param value - The width.
1650
+ * @returns This instance for chaining.
1651
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width | width}
1652
+ */
1653
+ setWidth(value) {
1654
+ return this.setAttr("width", String(value));
1655
+ }
1656
+ /**
1657
+ * Sets the height attribute.
1658
+ *
1659
+ * @param value - The height.
1660
+ * @returns This instance for chaining.
1661
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height | height}
1662
+ */
1663
+ setHeight(value) {
1664
+ return this.setAttr("height", String(value));
1665
+ }
1666
+ /**
1667
+ * Sets the d attribute (path data).
1668
+ *
1669
+ * @param value - The path data string or array of segments.
1670
+ * @returns This instance for chaining.
1671
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d | d}
1672
+ */
1673
+ setD(value) {
1674
+ return this.setAttr("d", Array.isArray(value) ? value.join(" ") : value);
1675
+ }
1676
+ /**
1677
+ * Sets the transform attribute.
1678
+ *
1679
+ * @param value - The transform string.
1680
+ * @returns This instance for chaining.
1681
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform | transform}
1682
+ */
1683
+ setTransform(value) {
1684
+ return this.setAttr("transform", value);
1685
+ }
1686
+ };
1687
+
1688
+ // src/wrappers/JJN.ts
1689
+ JJN.wrap = function wrap(raw) {
1690
+ if (isStr(raw)) {
1691
+ return JJT.fromStr(raw);
1692
+ }
1693
+ if (!isObj(raw)) {
1694
+ throw typeErr("raw", "an object", raw);
1695
+ }
1696
+ if (isA(raw, JJN)) {
1697
+ return raw;
1698
+ }
1699
+ if (isA(raw, HTMLElement)) {
1700
+ return JJHE.from(raw);
1701
+ }
1702
+ if (isA(raw, SVGElement)) {
1703
+ return JJSE.from(raw);
1704
+ }
1705
+ if (isA(raw, Element)) {
1706
+ return JJE.from(raw);
1707
+ }
1708
+ if (isA(raw, ShadowRoot)) {
1709
+ return JJSR.from(raw);
1710
+ }
1711
+ if (isA(raw, DocumentFragment)) {
1712
+ return JJDF.from(raw);
1713
+ }
1714
+ if (isA(raw, Document)) {
1715
+ return JJD.from(raw);
1716
+ }
1717
+ if (isA(raw, Text)) {
1718
+ return JJT.from(raw);
1719
+ }
1720
+ if (isA(raw, Node)) {
1721
+ return JJN.from(raw);
1722
+ }
1723
+ throw typeErr("raw", "a Node", raw);
1724
+ };
1725
+
1726
+ // src/helpers.ts
1727
+ function h(tagName, attributes, ...children) {
1728
+ const ret = JJHE.create(tagName).addChild(...children);
1729
+ if (attributes) {
1730
+ ret.setAttr(attributes);
1731
+ }
1732
+ return ret;
1733
+ }
1734
+ function linkAs(href) {
1735
+ switch (fileExt(href)) {
1736
+ case "html":
1737
+ case "htm":
1738
+ case "md":
1739
+ return "fetch";
1740
+ case "css":
1741
+ return "style";
1742
+ case "js":
1743
+ case "mjs":
1744
+ case "cjs":
1745
+ return "script";
1746
+ default:
1747
+ throw new Error(`No 'as' attribute was specified and we failed to guess it from the URL: ${href}`);
1748
+ }
1749
+ }
1750
+ function createLinkPre(href, rel, as) {
1751
+ if (!isStr(href)) {
1752
+ if (!isA(href, URL)) {
1753
+ throw typeErr("href", "a string or URL", href);
1754
+ }
1755
+ href = href.toString();
1756
+ }
1757
+ if (!["prefetch", "preload"].includes(rel)) {
1758
+ throw new RangeError(errMsg("rel", `'prefetch' or 'preload'`, rel));
1759
+ }
1760
+ if (!as) {
1761
+ as = linkAs(href);
1762
+ if (!as) {
1763
+ throw new Error(`Could not guess 'as' attribute from URL: ${href}`);
1764
+ }
1765
+ }
1766
+ if (!["fetch", "style", "script"].includes(as)) {
1767
+ throw new RangeError(errMsg("as", `'fetch', 'style', or 'script'`, as));
1768
+ }
1769
+ return JJHE.create("link").setAttr({
1770
+ href,
1771
+ rel,
1772
+ as
1773
+ });
1774
+ }
1775
+ function addLinkPre(...args) {
1776
+ const link = createLinkPre(...args);
1777
+ document.head.append(link.ref);
1778
+ return link;
1779
+ }
1780
+ async function fetchText(url, mime = "text/*") {
1781
+ if (!isStr(mime)) {
1782
+ throw typeErr("mime", "a string", mime);
1783
+ }
1784
+ const response = await fetch(url, { headers: { Accept: mime } });
1785
+ if (!response.ok) {
1786
+ throw new Error(`GET ${url} failed: ${response.status} ${response.statusText}`);
1787
+ }
1788
+ return response.text();
1789
+ }
1790
+ async function fetchHtml(url) {
1791
+ return await fetchText(url, "text/html");
1792
+ }
1793
+ async function fetchCss(url) {
1794
+ return await fetchText(url, "text/css");
1795
+ }
1796
+ async function fetchStyle(url) {
1797
+ return await cssToStyle(await fetchCss(url));
1798
+ }
1799
+
1800
+ // src/components.ts
1801
+ function attr2prop(instance, name, oldValue, newValue) {
1802
+ if (!isA(instance, HTMLElement)) {
1803
+ throw typeErr("instance", "an HTMLElement", instance);
1804
+ }
1805
+ if (oldValue !== newValue) {
1806
+ const propName = keb2cam(name);
1807
+ if (hasProp(instance, propName)) {
1808
+ instance[propName] = newValue;
1809
+ return true;
1810
+ }
1811
+ }
1812
+ return false;
1813
+ }
1814
+ async function registerComponent(name, constructor, options) {
1815
+ if (!isStr(name)) {
1816
+ throw typeErr("name", "a string", name);
1817
+ }
1818
+ if (!isFn(constructor)) {
1819
+ throw typeErr("constructor", "a function", constructor);
1820
+ }
1821
+ if (!customElements.get(name)) {
1822
+ customElements.define(name, constructor, options);
1823
+ await customElements.whenDefined(name);
1824
+ }
1825
+ }
1826
+
1827
+ // src/ShadowMaster.ts
1828
+ async function templatePromise(templateConfig) {
1829
+ if (templateConfig === void 0) {
1830
+ return void 0;
1831
+ }
1832
+ if (isFn(templateConfig)) {
1833
+ templateConfig = await templateConfig();
1834
+ }
1835
+ templateConfig = await templateConfig;
1836
+ if (isStr(templateConfig)) {
1837
+ return templateConfig;
1838
+ }
1839
+ if (isA(templateConfig, JJDF)) {
1840
+ return templateConfig.ref.cloneNode(true);
1841
+ }
1842
+ if (isA(templateConfig, DocumentFragment)) {
1843
+ return templateConfig.cloneNode(true);
1844
+ }
1845
+ if (isA(templateConfig, JJHE)) {
1846
+ if (templateConfig.ref instanceof HTMLTemplateElement) {
1847
+ return templateConfig.ref.content.cloneNode(true);
1848
+ }
1849
+ return templateConfig.ref.outerHTML;
1850
+ }
1851
+ if (isA(templateConfig, HTMLElement)) {
1852
+ return templateConfig instanceof HTMLTemplateElement ? templateConfig.content.cloneNode(true) : templateConfig.outerHTML;
1853
+ }
1854
+ throw typeErr("template", "a string, JJHE, JJDF, HTMLElement, or DocumentFragment", templateConfig);
1855
+ }
1856
+ async function stylePromise(styleConfig) {
1857
+ if (isFn(styleConfig)) {
1858
+ styleConfig = await styleConfig();
1859
+ }
1860
+ styleConfig = await styleConfig;
1861
+ if (isA(styleConfig, CSSStyleSheet)) {
1862
+ return styleConfig;
1863
+ }
1864
+ if (isStr(styleConfig)) {
1865
+ return await cssToStyle(styleConfig);
1866
+ }
1867
+ throw typeErr("style", "a CSS string or CSSStyleSheet", styleConfig);
1868
+ }
1869
+ function stylePromises(styleConfigs) {
1870
+ if (!isArr(styleConfigs)) {
1871
+ return [];
1872
+ }
1873
+ return styleConfigs.map(stylePromise);
1874
+ }
1875
+ async function resolveConfig(templateConfig, styleConfigs) {
1876
+ const [template, ...styles] = await Promise.all([templatePromise(templateConfig), ...stylePromises(styleConfigs)]);
1877
+ return { template, styles };
1878
+ }
1879
+ var _templateConfig, _stylesConfig, _normalizedConfig;
1880
+ var _ShadowMaster = class _ShadowMaster {
1881
+ constructor() {
1882
+ __privateAdd(this, _templateConfig);
1883
+ __privateAdd(this, _stylesConfig, []);
1884
+ __privateAdd(this, _normalizedConfig);
1885
+ }
1886
+ /**
1887
+ * Creates a new instance of ShadowMaster.
1888
+ *
1889
+ * @returns A new ShadowMaster instance.
1890
+ */
1891
+ static create() {
1892
+ return new _ShadowMaster();
1893
+ }
1894
+ /**
1895
+ * Sets the template configuration.
1896
+ *
1897
+ * @param templateConfig - The template configuration.
1898
+ * @returns The instance for chaining.
1899
+ *
1900
+ * @example
1901
+ * ```ts
1902
+ * // Accepts string, promise, or fetchHtml result
1903
+ * sm.setTemplate(fetchHtml('./template.html'))
1904
+ * ```
1905
+ */
1906
+ setTemplate(templateConfig) {
1907
+ __privateSet(this, _templateConfig, templateConfig);
1908
+ return this;
1909
+ }
1910
+ /**
1911
+ * Adds one or more style configurations.
1912
+ *
1913
+ * @param stylesConfig - Variable number of style configurations.
1914
+ * @returns The instance for chaining.
1915
+ *
1916
+ * @example
1917
+ * ```ts
1918
+ * sm.addStyles(
1919
+ * 'p { color: red; }',
1920
+ * fetchCss('./styles.css'),
1921
+ * () => fetchCss('../lazy-loaded-styles.css'),
1922
+ * )
1923
+ * ```
1924
+ */
1925
+ addStyles(...stylesConfig) {
1926
+ __privateGet(this, _stylesConfig).push(...stylesConfig);
1927
+ return this;
1928
+ }
1929
+ /**
1930
+ * Resolves the configuration to something that can be fed to `JJHE.initShadow()` function
1931
+ *
1932
+ * The result is cached, so subsequent calls return the same promise.
1933
+ * Note: Any changes made to the ShadowMaster instance (via setTemplate/addStyles)
1934
+ * after the first call to getResolved() will be ignored.
1935
+ *
1936
+ * @returns A promise resolving to the ShadowConfig.
1937
+ */
1938
+ async getResolved() {
1939
+ if (!__privateGet(this, _normalizedConfig)) {
1940
+ __privateSet(this, _normalizedConfig, resolveConfig(__privateGet(this, _templateConfig), __privateGet(this, _stylesConfig)));
1941
+ }
1942
+ return await __privateGet(this, _normalizedConfig);
1943
+ }
1944
+ };
1945
+ _templateConfig = new WeakMap();
1946
+ _stylesConfig = new WeakMap();
1947
+ _normalizedConfig = new WeakMap();
1948
+ var ShadowMaster = _ShadowMaster;
1949
+
1950
+ // src/index.ts
1951
+ var doc = JJD.from(document);
1952
+ })();
1953
+ //# sourceMappingURL=bundle.global.js.map