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