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