jj 2.2.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 (93) 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 +1505 -445
  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 -12
  40. package/lib/index.js +13 -12
  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 +90 -2
  52. package/lib/util.js +106 -2
  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 -41
  59. package/lib/WC.js +0 -117
  60. package/lib/WC.js.map +0 -1
  61. package/lib/WD.d.ts +0 -8
  62. package/lib/WD.js +0 -17
  63. package/lib/WD.js.map +0 -1
  64. package/lib/WDF.d.ts +0 -9
  65. package/lib/WDF.js +0 -20
  66. package/lib/WDF.js.map +0 -1
  67. package/lib/WE.d.ts +0 -43
  68. package/lib/WE.js +0 -131
  69. package/lib/WE.js.map +0 -1
  70. package/lib/WHE.d.ts +0 -21
  71. package/lib/WHE.js +0 -75
  72. package/lib/WHE.js.map +0 -1
  73. package/lib/WN-mixin.d.ts +0 -9
  74. package/lib/WN-mixin.js +0 -59
  75. package/lib/WN-mixin.js.map +0 -1
  76. package/lib/WN.d.ts +0 -47
  77. package/lib/WN.js +0 -194
  78. package/lib/WN.js.map +0 -1
  79. package/lib/WSE.d.ts +0 -25
  80. package/lib/WSE.js +0 -84
  81. package/lib/WSE.js.map +0 -1
  82. package/lib/WSH.d.ts +0 -11
  83. package/lib/WSH.js +0 -29
  84. package/lib/WSH.js.map +0 -1
  85. package/lib/WT.d.ts +0 -12
  86. package/lib/WT.js +0 -39
  87. package/lib/WT.js.map +0 -1
  88. package/lib/fetch.d.ts +0 -31
  89. package/lib/fetch.js +0 -69
  90. package/lib/fetch.js.map +0 -1
  91. package/lib/h.d.ts +0 -3
  92. package/lib/h.js +0 -9
  93. package/lib/h.js.map +0 -1
package/lib/bundle.js CHANGED
@@ -1,18 +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
- async function cssToStyle(css) {
12
- const sheet = new CSSStyleSheet();
13
- return await sheet.replace(css);
14
- }
15
-
16
1
  // node_modules/jty/lib/misc.js
17
2
  function isDef(x) {
18
3
  return x !== void 0;
@@ -91,187 +76,458 @@ function isStr(x) {
91
76
  var { hasOwnProperty: hasOwnProperty2 } = Object;
92
77
  var { isArray: isArray2 } = Array;
93
78
 
94
- // src/WN.ts
95
- function isDDF(x) {
96
- return isA(x, Document) || 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();
93
+ }
94
+ function nextAnimationFrame() {
95
+ return new Promise((resolve) => requestAnimationFrame(resolve));
97
96
  }
98
- function isEDDF(x) {
99
- return isA(x, Element) || isDDF(x);
97
+ function sleep(ms = 0) {
98
+ return new Promise((resolve) => setTimeout(resolve, ms));
100
99
  }
101
- var WN = class _WN {
102
- static from(node) {
103
- return new _WN(node);
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})`);
104
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 {
105
137
  /**
106
- * 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.
107
147
  */
108
- static wrapAll(iterable) {
109
- return Array.from(iterable, _WN.wrap);
148
+ static from(node) {
149
+ return new _JJN(node);
110
150
  }
111
151
  /**
112
- * 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.
113
167
  */
114
- static unwrapAll(iterable) {
115
- return Array.from(iterable, _WN.unwrap);
116
- }
117
- static byId(id, throwIfNotFound = true) {
118
- const el = document.getElementById(id);
119
- if (el) {
120
- return _WN.wrap(el);
121
- }
122
- if (throwIfNotFound) {
123
- throw new TypeError(`Found no element with id ${id} in the document.`);
124
- }
125
- return null;
126
- }
127
- byId(id, throwIfNotFound = true) {
128
- if (!isStr(id)) {
129
- throw new TypeError(`Expected a string id. Got ${id} (${typeof id})`);
130
- }
131
- if (isA(this.ref, HTMLElement)) {
132
- return this.query(`#${id}`, throwIfNotFound);
133
- }
134
- if (!isDDF(this.ref)) {
135
- throw new TypeError(`Expected an Document or DocumentFragment. Got ${this.ref} (${typeof this.ref})`);
136
- }
137
- const el = this.ref.getElementById(id);
138
- if (el) {
139
- return _WN.wrap(el);
140
- }
141
- if (throwIfNotFound) {
142
- throw new TypeError(`Element with id ${id} not found`);
143
- }
144
- return null;
145
- }
146
- static byClass(className) {
147
- return _WN.wrapAll(document.getElementsByClassName(className));
148
- }
149
- static query(selector, throwIfNotFound = true) {
150
- const queryResult = document.querySelector(selector);
151
- if (queryResult) {
152
- return _WN.wrap(queryResult);
153
- }
154
- if (throwIfNotFound) {
155
- throw new TypeError(`Element with selector ${selector} not found`);
156
- }
157
- return null;
168
+ static wrap(raw) {
169
+ throw new ReferenceError(`The mixin is supposed to override this method.`);
158
170
  }
159
- query(selector, throwIfNotFound = true) {
160
- if (!isEDDF(this.ref)) {
161
- throw new TypeError(
162
- `Expected an Element, Document or DocumentFragment. Got ${this.ref} (${typeof this.ref})`
163
- );
164
- }
165
- const queryResult = this.ref.querySelector(selector);
166
- if (queryResult) {
167
- return _WN.wrap(queryResult);
168
- }
169
- if (throwIfNotFound) {
170
- throw new TypeError(`Element with selector ${selector} not found`);
171
- }
172
- 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.`);
173
189
  }
174
- static queryAll(selector) {
175
- 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);
176
203
  }
177
- queryAll(selector) {
178
- if (!isEDDF(this.ref)) {
179
- throw new TypeError(
180
- `Expected an Element, Document or DocumentFragment. Got ${this.ref} (${typeof this.ref})`
181
- );
182
- }
183
- 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);
184
217
  }
185
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
+ */
186
225
  constructor(ref) {
187
226
  if (!isA(ref, Node)) {
188
227
  throw new TypeError(`Expected a Node. Got ${ref} (${typeof ref})`);
189
228
  }
190
229
  this.#ref = ref;
191
230
  }
231
+ /**
232
+ * Gets the underlying DOM Node.
233
+ */
192
234
  get ref() {
193
235
  return this.#ref;
194
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
+ */
195
244
  clone(deep) {
196
- return _WN.wrap(this.ref.cloneNode(deep));
245
+ return _JJN.wrap(this.ref.cloneNode(deep));
197
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
+ */
198
255
  append(...children) {
199
- const nodes = _WN.unwrapAll(children);
200
- if (isEDDF(this.ref)) {
201
- this.ref.append(...nodes);
202
- } else {
203
- for (const node of nodes) {
204
- if (node) {
205
- this.ref.appendChild(node);
206
- }
256
+ const nodes = _JJN.unwrapAll(children);
257
+ const ref = this.ref;
258
+ for (const node of nodes) {
259
+ if (node) {
260
+ ref.appendChild(node);
207
261
  }
208
262
  }
209
263
  return this;
210
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
+ */
211
277
  mapAppend(array, mapFn) {
212
278
  return this.append(...array.map(mapFn));
213
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
+ */
214
287
  prepend(...children) {
215
- const nodes = _WN.unwrapAll(children);
216
- if (isEDDF(this.ref)) {
217
- this.ref.prepend(...nodes);
218
- } else {
219
- const first = this.ref.firstChild;
220
- for (const node of nodes) {
221
- if (node) {
222
- this.ref.insertBefore(node, first);
223
- }
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);
224
294
  }
225
295
  }
226
296
  return this;
227
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
+ */
228
310
  mapPrepend(array, mapFn) {
229
311
  return this.prepend(...array.map(mapFn));
230
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
+ */
231
334
  on(eventName, handler) {
232
335
  on(this.ref, eventName, handler);
233
336
  return this;
234
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
+ */
235
346
  off(eventName, handler) {
236
347
  off(this.ref, eventName, handler);
237
348
  return this;
238
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
+ */
239
356
  rm() {
240
357
  this.ref.parentNode?.removeChild(this.ref);
241
358
  return this;
242
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
+ */
243
366
  empty() {
244
- if (!isEDDF(this.ref)) {
245
- throw new TypeError(
246
- `Expected an Element, Document or DocumentFragment. Got ${this.ref} (${typeof this.ref})`
247
- );
367
+ const element = this.ref;
368
+ while (element.firstChild) {
369
+ element.removeChild(element.firstChild);
248
370
  }
249
- this.ref.replaceChildren();
250
371
  return this;
251
372
  }
252
373
  /**
253
- * Runs a function in the context of this WN instance.
374
+ * Runs a function in the context of this JJN instance.
254
375
  *
255
- * @param fn - The function to run. `this` inside the function will refer to this WN instance.
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.
256
390
  * @param args - Arguments to pass to the function.
257
391
  * @returns The return value of the function.
258
- * @remark if the function throws, `run()` doesn't swallow the exception.
259
- * So if you're expecting an error, make sure to wrap it in a `try..catch` block and handle the exception.
260
- * @remark if the function returns a promise, you can `await` on the response.
261
392
  */
262
393
  run(fn, ...args) {
263
394
  return fn.call(this, ...args);
264
395
  }
265
396
  };
266
397
 
267
- // src/WDF.ts
268
- var WDF = class _WDF 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
+ */
413
+ static from(text) {
414
+ if (!isA(text, Text)) {
415
+ throw new TypeError(`Expected a Text object. Got: ${text} (${typeof text})`);
416
+ }
417
+ return new _JJT(text);
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
+ */
430
+ constructor(ref) {
431
+ if (isStr(ref)) {
432
+ super(document.createTextNode(ref));
433
+ } else if (isA(ref, Text)) {
434
+ super(ref);
435
+ } else {
436
+ throw new TypeError(`Expected a Text. Got: ${ref} (${typeof ref})`);
437
+ }
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
+ */
445
+ getText() {
446
+ return this.ref.textContent ?? "";
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
+ */
461
+ setText(text) {
462
+ if (!isStr(text)) {
463
+ throw new TypeError(`Expected a string. Got: ${text} (${typeof text})`);
464
+ }
465
+ this.ref.textContent = text;
466
+ return this;
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
+ */
474
+ empty() {
475
+ return this.setText("");
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
+ */
488
+ addLines(...lines) {
489
+ return this.setText(lines.join("\n"));
490
+ }
491
+ };
492
+
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
+ */
269
508
  static from(ref) {
270
- return new _WDF(ref);
509
+ return new _JJDF(ref);
271
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
+ */
272
522
  static create() {
273
- return new _WDF(document.createDocumentFragment());
523
+ return new _JJDF(document.createDocumentFragment());
274
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
+ */
275
531
  constructor(ref) {
276
532
  if (!isA(ref, DocumentFragment)) {
277
533
  throw new TypeError(`Expected a DocumentFragment. Got ${ref} (${typeof ref})`);
@@ -280,51 +536,169 @@ var WDF = class _WDF extends WN {
280
536
  }
281
537
  };
282
538
 
283
- // src/WSH.ts
284
- var WSH = class _WSH extends WDF {
285
- static from(shadow) {
286
- 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);
287
554
  }
288
- constructor(shadow) {
289
- if (!isA(shadow, ShadowRoot)) {
290
- 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})`);
291
564
  }
292
- super(shadow);
565
+ super(shadowRoot);
293
566
  }
294
- 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() {
295
574
  return this.ref.innerHTML;
296
575
  }
297
- 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) {
298
590
  this.ref.innerHTML = value;
299
591
  return this;
300
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
+ */
301
607
  addStyleSheets(...styleSheets) {
302
608
  this.ref.adoptedStyleSheets.push(...styleSheets);
303
609
  return this;
304
610
  }
305
611
  };
306
612
 
307
- // src/WE.ts
308
- 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
+ */
309
626
  static from(ref) {
310
- return new _WE(ref);
627
+ return new _JJE(ref);
311
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
+ */
312
635
  constructor(ref) {
313
636
  if (!isA(ref, Element)) {
314
- throw new TypeError(`Expected a Element. Got: ${ref} (${typeof ref})`);
637
+ throw new TypeError(`Expected an Element. Got: ${ref} (${typeof ref})`);
315
638
  }
316
639
  super(ref);
317
640
  }
318
- getAttr(name) {
319
- return this.ref.getAttribute(name);
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
+ */
665
+ getAttr(name) {
666
+ return this.ref.getAttribute(name);
320
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
+ */
321
675
  hasAttr(name) {
322
676
  return this.ref.hasAttribute(name);
323
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
+ */
324
686
  setAttr(name, value) {
325
687
  this.ref.setAttribute(name, value);
326
688
  return this;
327
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
+ */
328
702
  setAttrs(obj) {
329
703
  if (!isObj(obj)) {
330
704
  throw new TypeError(`Expected an object. Got: ${obj} (${typeof obj})`);
@@ -334,125 +708,384 @@ var WE = class _WE extends WN {
334
708
  }
335
709
  return this;
336
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
+ */
337
718
  rmAttr(name) {
338
719
  return this.rmAttrs(name);
339
720
  }
721
+ /**
722
+ * Removes multiple attributes.
723
+ *
724
+ * @param names - The names of the attributes to remove.
725
+ * @returns This instance for chaining.
726
+ */
340
727
  rmAttrs(...names) {
341
728
  for (const name of names) {
342
729
  this.ref.removeAttribute(name);
343
730
  }
344
731
  return this;
345
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
+ */
346
748
  getAria(name) {
347
749
  return this.ref.getAttribute(`aria-${name}`);
348
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
+ */
349
757
  hasAria(name) {
350
758
  return this.ref.hasAttribute(`aria-${name}`);
351
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
+ */
352
772
  setAria(name, value) {
353
773
  this.ref.setAttribute(`aria-${name}`, value);
354
774
  return this;
355
775
  }
776
+ /**
777
+ * Removes an ARIA attribute.
778
+ *
779
+ * @param name - The ARIA attribute suffix.
780
+ * @returns This instance for chaining.
781
+ */
356
782
  rmAria(name) {
357
783
  this.ref.removeAttribute(`aria-${name}`);
358
784
  return this;
359
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
+ */
360
824
  addClass(...classNames) {
361
825
  this.ref.classList.add(...classNames);
362
826
  return this;
363
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
+ */
364
836
  rmClasses(...classNames) {
365
837
  this.ref.classList.remove(...classNames);
366
838
  return this;
367
839
  }
368
- rmClass(className) {
369
- return this.rmClasses(className);
370
- }
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
+ */
371
848
  hasClass(className) {
372
849
  return this.ref.classList.contains(className);
373
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
+ */
374
859
  toggleClass(className) {
375
860
  this.ref.classList.toggle(className);
376
861
  return this;
377
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
+ */
378
883
  onClick(handler) {
379
884
  return this.on("click", handler);
380
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
+ */
381
893
  hide() {
382
894
  return this.setAttr("hidden", "").setAttr("aria-hidden", "true");
383
895
  }
896
+ /**
897
+ * Shows the element by removing the `hidden` and `aria-hidden` attributes.
898
+ *
899
+ * @returns This instance for chaining.
900
+ */
384
901
  show() {
385
902
  return this.rmAttrs("hidden", "aria-hidden");
386
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
+ */
387
911
  disable() {
388
912
  return this.setAttr("disabled", "").setAttr("aria-disabled", "true");
389
913
  }
914
+ /**
915
+ * Enables the element by removing the `disabled` and `aria-disabled` attributes.
916
+ *
917
+ * @returns This instance for chaining.
918
+ */
390
919
  enable() {
391
920
  return this.rmAttrs("disabled", "aria-disabled");
392
921
  }
922
+ /**
923
+ * Gets the title attribute.
924
+ *
925
+ * @returns The title, or null if not set.
926
+ */
393
927
  getTitle() {
394
928
  return this.getAttr("title");
395
929
  }
930
+ /**
931
+ * Sets the title attribute.
932
+ *
933
+ * @param title - The title to set.
934
+ * @returns This instance for chaining.
935
+ */
396
936
  setTitle(title) {
397
937
  return this.setAttr("title", title);
398
938
  }
939
+ /**
940
+ * Sets the id attribute.
941
+ *
942
+ * @param id - The id to set.
943
+ * @returns This instance for chaining.
944
+ */
399
945
  setId(id) {
400
946
  return this.setAttr("id", id);
401
947
  }
948
+ /**
949
+ * Gets the id attribute.
950
+ *
951
+ * @returns The id, or null if not set.
952
+ */
402
953
  getId() {
403
954
  return this.getAttr("id");
404
955
  }
405
- 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() {
406
963
  return this.ref.innerHTML;
407
964
  }
408
- 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) {
409
973
  this.ref.innerHTML = html;
410
974
  return this;
411
975
  }
412
976
  /**
413
- * 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
+ *
414
979
  * @remarks
980
+ * We prevent FOUC by assigning the template and CSS in one go.
415
981
  * **Note:** You can't attach a shadow root to every type of element. There are some that can't have a
416
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}
417
990
  */
418
- initShadow(mode = "open", html, ...styleSheets) {
991
+ initShadow(mode = "open", config) {
419
992
  const shadowRoot = this.ref.shadowRoot ?? this.ref.attachShadow({ mode });
420
- if (html) {
421
- shadowRoot.innerHTML = html;
422
- }
423
- if (styleSheets.length) {
424
- 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
+ }
425
1001
  }
426
1002
  return this;
427
1003
  }
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
+ */
428
1009
  get shadow() {
429
- return this.ref.shadowRoot ? new WSH(this.ref.shadowRoot) : null;
1010
+ return this.ref.shadowRoot ? new JJSR(this.ref.shadowRoot) : null;
430
1011
  }
431
1012
  };
432
1013
 
433
- // src/WHE.ts
434
- 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
+ */
435
1027
  static from(ref) {
436
- return new _WHE(ref);
1028
+ return new _JJHE(ref);
437
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
+ */
438
1045
  static fromTag(tagName, options) {
439
1046
  if (!isStr(tagName)) {
440
1047
  throw new TypeError(`Expected a string for tagName. Got: ${tagName} (${typeof tagName})`);
441
1048
  }
442
- return new _WHE(document.createElement(tagName, options));
1049
+ return new _JJHE(document.createElement(tagName, options));
443
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
+ */
444
1057
  constructor(ref) {
445
1058
  if (!isA(ref, HTMLElement)) {
446
- throw new TypeError(`Expected a HTMLElement. Got ${ref} (${typeof ref})`);
1059
+ throw new TypeError(`Expected an HTMLElement. Got ${ref} (${typeof ref})`);
447
1060
  }
448
1061
  super(ref);
449
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
+ */
450
1070
  getValue() {
451
1071
  if (!hasProp(this.ref, "value")) {
452
1072
  throw new Error("Element does not have a value property");
453
1073
  }
454
1074
  return this.ref.value;
455
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
+ */
456
1089
  setValue(value) {
457
1090
  if (!hasProp(this.ref, "value")) {
458
1091
  throw new Error("Element does not have a value property");
@@ -460,205 +1093,207 @@ var WHE = class _WHE extends WE {
460
1093
  this.ref.value = value;
461
1094
  return this;
462
1095
  }
463
- getData(name) {
464
- return this.ref.dataset[name];
465
- }
466
- hasData(name) {
467
- return hasProp(this.ref.dataset, name);
468
- }
469
- setData(name, value) {
470
- this.ref.dataset[name] = value;
471
- return this;
472
- }
473
- setDataObj(obj) {
474
- for (const [name, value] of Object.entries(obj)) {
475
- this.setData(name, value);
476
- }
477
- return this;
478
- }
479
- rmData(name) {
480
- delete this.ref.dataset[name];
481
- return this;
482
- }
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
+ */
483
1102
  focus() {
484
1103
  this.ref.focus();
485
1104
  return this;
486
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
+ */
487
1112
  click() {
488
1113
  this.ref.click();
489
1114
  return this;
490
1115
  }
491
- empty() {
492
- this.ref.innerText = "";
493
- return this;
494
- }
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
+ */
495
1122
  getText() {
496
1123
  return this.ref.innerText;
497
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
+ */
498
1132
  setText(text) {
499
1133
  this.ref.innerText = text;
500
1134
  return this;
501
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
+ }
502
1165
  };
503
1166
 
504
- // src/fetch.ts
505
- async function fetchText(url, mime = "text/*") {
506
- if (!isStr(mime)) {
507
- 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);
508
1184
  }
509
- const response = await fetch(url, { headers: { Accept: mime } });
510
- if (!response.ok) {
511
- 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);
512
1208
  }
513
- return response.text();
514
- }
515
- async function fetchHtml(url) {
516
- return await fetchText(url, "text/html");
517
- }
518
- async function fetchCss(url) {
519
- return await fetchText(url, "text/css");
520
- }
521
- async function fetchStyle(url) {
522
- return await cssToStyle(await fetchCss(url));
523
- }
524
- function addLinkPre(href, rel, as = "fetch") {
525
- if (!isStr(href)) {
526
- if (!isA(href, URL)) {
527
- throw new TypeError(`Expected a string or URL. Got ${href} (${typeof href})`);
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})`);
528
1218
  }
529
- href = href.toString();
1219
+ super(ref);
530
1220
  }
531
- if (["prefetch", "preload"].includes(rel)) {
532
- throw new RangeError(`rel should be one of 'prefetch' or 'preload'. Got ${rel} (${typeof rel})`);
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 ?? "";
533
1229
  }
534
- if (["fetch", "style", "script"].includes(as)) {
535
- throw new RangeError(`as should be one of 'fetch' or 'style'. Got ${as} (${typeof as})`);
536
- }
537
- const link = WHE.fromTag("link").setAttrs({
538
- rel,
539
- href,
540
- as
541
- });
542
- document.head.append(link.ref);
543
- return link;
544
- }
545
-
546
- // src/case.ts
547
- function pas2keb(str) {
548
- if (typeof str !== "string") {
549
- throw new TypeError(`Expected a string. Got ${str} (${typeof str})`);
550
- }
551
- if (/[^a-zA-Z0-9_]/.test(str)) {
552
- throw new TypeError(`Invalid characters in string. Only alphanumeric and underscores are allowed. Got: ${str}`);
553
- }
554
- return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
555
- }
556
- function keb2pas(str) {
557
- if (typeof str !== "string") {
558
- throw new TypeError(`Expected a string. Got ${str} (${typeof str})`);
559
- }
560
- 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')
561
- (str.length > 0 ? str.charAt(0).toUpperCase() + str.slice(1) : "");
562
- }
563
- function keb2cam(str) {
564
- if (typeof str !== "string") {
565
- throw new TypeError(`Expected a string. Got ${str} (${typeof str})`);
566
- }
567
- return str.replace(/^-+|-+$/g, "").replace(/-+([a-z])/g, (g, c) => c.toUpperCase());
568
- }
569
-
570
- // src/WT.ts
571
- var WT = class _WT extends WN {
572
- static from(text) {
573
- if (!isA(text, Text)) {
574
- throw new TypeError(`Expected a Text object. Got: ${text} (${typeof text})`);
575
- }
576
- return new _WT(text);
577
- }
578
- constructor(ref) {
579
- if (isStr(ref)) {
580
- super(document.createTextNode(ref));
581
- } else if (isA(ref, Text)) {
582
- super(ref);
583
- }
584
- throw new TypeError(`Expected a Text. Got: ${ref} (${typeof ref})`);
585
- }
586
- getText() {
587
- return this.ref.textContent;
588
- }
589
- setText(text) {
590
- if (!isStr(text)) {
591
- throw new TypeError(`Expected a string. Got: ${text} (${typeof text})`);
592
- }
593
- this.ref.textContent = text;
594
- return this;
595
- }
596
- empty() {
597
- return this.setText("");
598
- }
599
- addLines(...lines) {
600
- return this.setText(lines.join("\n"));
601
- }
602
- };
603
-
604
- // src/WSE.ts
605
- var WSE = class _WSE extends WE {
606
- static from(ref) {
607
- return new _WSE(ref);
608
- }
609
- static fromTag(tagName, options) {
610
- if (!isStr(tagName)) {
611
- throw new TypeError(`Expected a string for tagName. Got: ${tagName} (${typeof tagName})`);
612
- }
613
- const element = document.createElementNS("http://www.w3.org/2000/svg", tagName, options);
614
- return new _WSE(element);
615
- }
616
- constructor(ref) {
617
- if (!isA(ref, SVGElement)) {
618
- throw new TypeError(`Expected a SVGElement. Got ${ref} (${typeof ref})`);
619
- }
620
- super(ref);
621
- }
622
- getText() {
623
- return this.ref.textContent ?? "";
624
- }
625
- setText(text) {
626
- this.ref.textContent = text;
627
- return this;
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;
628
1240
  }
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
+ */
629
1247
  empty() {
630
1248
  this.ref.textContent = "";
631
1249
  return this;
632
1250
  }
633
- getData(name) {
634
- return this.ref.dataset[name];
635
- }
636
- hasData(name) {
637
- return hasProp(this.ref.dataset, name);
638
- }
639
- setData(name, value) {
640
- this.ref.dataset[name] = value;
641
- return this;
642
- }
643
- setDataObj(obj) {
644
- for (const [name, value] of Object.entries(obj)) {
645
- this.setData(name, value);
646
- }
647
- return this;
648
- }
649
- rmData(name) {
650
- delete this.ref.dataset[name];
651
- return this;
652
- }
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
+ */
653
1258
  setFill(value) {
654
1259
  return this.setAttr("fill", value);
655
1260
  }
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
+ */
656
1268
  setStroke(value) {
657
1269
  return this.setAttr("stroke", value);
658
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
+ */
659
1278
  setStrokeWidth(value) {
660
1279
  return this.setAttr("stroke-width", String(value));
661
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
+ */
662
1297
  setViewBox(p1, p2, p3, p4) {
663
1298
  if (typeof p1 === "number" && p2 !== void 0 && p3 !== void 0 && p4 !== void 0) {
664
1299
  return this.setAttr("viewBox", `${p1} ${p2} ${p3} ${p4}`);
@@ -666,162 +1301,161 @@ var WSE = class _WSE extends WE {
666
1301
  const value = p1;
667
1302
  return this.setAttr("viewBox", Array.isArray(value) ? value.join(" ") : value);
668
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
+ */
669
1311
  setWidth(value) {
670
1312
  return this.setAttr("width", String(value));
671
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
+ */
672
1321
  setHeight(value) {
673
1322
  return this.setAttr("height", String(value));
674
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
+ */
675
1331
  setD(value) {
676
1332
  return this.setAttr("d", Array.isArray(value) ? value.join(" ") : value);
677
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
+ */
678
1341
  setTransform(value) {
679
1342
  return this.setAttr("transform", value);
680
1343
  }
681
1344
  };
682
1345
 
683
- // src/WD.ts
684
- var WD = class _WD extends WN {
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
+ */
685
1360
  static from(ref) {
686
- return new _WD(ref);
1361
+ return new _JJD(ref);
687
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
+ */
688
1369
  constructor(ref) {
689
1370
  if (!isA(ref, Document)) {
690
1371
  throw new TypeError(`Expected a Document. Got ${ref} (${typeof ref})`);
691
1372
  }
692
1373
  super(ref);
693
1374
  }
694
- };
695
-
696
- // src/WC.ts
697
- async function processTemplateConfig(template) {
698
- if (isFn(template)) {
699
- template = await template();
700
- }
701
- template = await template;
702
- if (!isDef(template) || isStr(template)) {
703
- return template;
704
- }
705
- if (isA(template, WHE)) {
706
- return template.getHtml();
707
- }
708
- if (isA(template, HTMLElement)) {
709
- return template.outerHTML;
710
- }
711
- throw new TypeError(`Expected a string, WHE or HTMLElement. Got ${template} (${typeof template})`);
712
- }
713
- function normalizeStyles(styles) {
714
- if (isDef(styles)) {
715
- return isArr(styles) ? styles : [styles];
716
- }
717
- return [];
718
- }
719
- async function processStyleConfig(styleConfig) {
720
- if (isFn(styleConfig)) {
721
- styleConfig = await styleConfig();
722
- }
723
- styleConfig = await styleConfig;
724
- if (isA(styleConfig, CSSStyleSheet)) {
725
- return styleConfig;
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);
726
1383
  }
727
- if (isStr(styleConfig)) {
728
- return await cssToStyle(styleConfig);
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);
729
1392
  }
730
- throw new TypeError(`Expected a css string or CSSStyleSheet. Got ${styleConfig} (${typeof styleConfig})`);
731
- }
732
- async function processConfig(jjConfig) {
733
- if (!isObj(jjConfig)) {
734
- throw new TypeError(`Expected an static jj config object. Got ${jjConfig} (${typeof jjConfig})`);
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;
735
1408
  }
736
- const { template: templateConfig, styles: stylesConfig } = jjConfig;
737
- const [template, ...styles] = await Promise.all([
738
- processTemplateConfig(templateConfig),
739
- ...normalizeStyles(stylesConfig).map(processStyleConfig)
740
- ]);
741
- return { template, styles };
742
- }
743
- var WC = class extends HTMLElement {
744
- static async register() {
745
- if (!isObj(this.jj)) {
746
- throw new Error(`static jj object is missing from the extending class. Got ${this.jj} (${typeof this.jj})`);
747
- }
748
- const { name } = this.jj;
749
- if (!isStr(name)) {
750
- throw new TypeError(`Expected a string name. Got ${name} (${typeof name})`);
751
- }
752
- if (!customElements.get(name)) {
753
- customElements.define(name, this);
754
- await customElements.whenDefined(name);
755
- }
756
- }
757
- async connectedCallback() {
758
- const classRef = this.constructor;
759
- const jj = classRef.jj;
760
- if (!isObj(jj)) {
761
- throw new TypeError(`static jj object is missing from the extending class. Got ${jj} (${typeof jj})`);
762
- }
763
- if (!classRef._jjCache) {
764
- classRef._jjCache = processConfig(classRef.jj);
765
- }
766
- const { template, styles } = await classRef._jjCache;
767
- const { templateMode } = jj;
768
- this.jjRoot = WHE.from(this).initShadow(templateMode, template, ...styles);
769
- }
770
- /**
771
- * The class that extends this one should define
772
- * `static observedAttributes[]` containing kebab-based attribute names (all lower case)
773
- * @param name kebab-case and in lower case exactly as it appears in `observedAttributes`
774
- * @param oldValue
775
- * @param newValue
776
- * @returns true if it tried to set the attribute; otherwise false
777
- */
778
- attributeChangedCallback(name, oldValue, newValue) {
779
- if (oldValue !== newValue) {
780
- const observedAttributes = this.constructor.observedAttributes;
781
- if (isArr(observedAttributes) && observedAttributes.includes(name)) {
782
- const kebabName = keb2cam(name);
783
- if (hasProp(this, kebabName)) {
784
- this[kebabName] = newValue;
785
- return true;
786
- }
787
- }
788
- }
789
- return false;
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;
790
1417
  }
791
1418
  };
792
1419
 
793
- // src/WN-mixin.ts
794
- WN.wrap = (raw) => {
1420
+ // src/mixins.ts
1421
+ var { wrapAll, unwrapAll } = JJN;
1422
+ function wrap(raw) {
795
1423
  if (isStr(raw)) {
796
- return WT.from(document.createTextNode(raw));
1424
+ return JJT.from(document.createTextNode(raw));
797
1425
  }
798
1426
  if (!isObj(raw)) {
799
1427
  throw new TypeError(`Expected an object to wrap. Got ${raw} (${typeof raw})`);
800
1428
  }
801
- if (isA(raw, WN)) {
1429
+ if (isA(raw, JJN)) {
802
1430
  return raw;
803
1431
  }
804
1432
  if (isA(raw, HTMLElement)) {
805
- return WHE.from(raw);
1433
+ return JJHE.from(raw);
1434
+ }
1435
+ if (isA(raw, SVGElement)) {
1436
+ return JJSE.from(raw);
806
1437
  }
807
1438
  if (isA(raw, Element)) {
808
- return WE.from(raw);
1439
+ return JJE.from(raw);
809
1440
  }
810
1441
  if (isA(raw, ShadowRoot)) {
811
- return WSH.from(raw);
1442
+ return JJSR.from(raw);
812
1443
  }
813
1444
  if (isA(raw, DocumentFragment)) {
814
- return WDF.from(raw);
1445
+ return JJDF.from(raw);
1446
+ }
1447
+ if (isA(raw, Document)) {
1448
+ return JJD.from(raw);
815
1449
  }
816
1450
  if (isA(raw, Text)) {
817
- return WT.from(raw);
1451
+ return JJT.from(raw);
818
1452
  }
819
1453
  if (isA(raw, Node)) {
820
- return WN.from(raw);
1454
+ return JJN.from(raw);
821
1455
  }
822
- throw new TypeError(`Only Frag or DocumentFragment can be wrapped. Got ${raw} (${typeof raw})`);
823
- };
824
- WN.unwrap = (obj) => {
1456
+ throw new TypeError(`Expected a Node to wrap. Got ${raw} (${typeof raw})`);
1457
+ }
1458
+ function unwrap(obj) {
825
1459
  if (isStr(obj)) {
826
1460
  return document.createTextNode(obj);
827
1461
  }
@@ -831,42 +1465,468 @@ WN.unwrap = (obj) => {
831
1465
  if (isA(obj, Node)) {
832
1466
  return obj;
833
1467
  }
834
- if (isA(obj, WN)) {
1468
+ if (isA(obj, JJN)) {
835
1469
  return obj.ref;
836
1470
  }
837
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
+ }
838
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
+ }
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);
839
1685
 
840
- // src/h.ts
1686
+ // src/helpers.ts
841
1687
  function h(tagName, attributes, ...children) {
842
- const ret = WHE.fromTag(tagName).append(...children);
1688
+ const ret = JJHE.fromTag(tagName).append(...children);
843
1689
  if (attributes) {
844
1690
  ret.setAttrs(attributes);
845
1691
  }
846
1692
  return ret;
847
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
+ }
848
1895
  export {
849
- WC,
850
- WD,
851
- WDF,
852
- WE,
853
- WHE,
854
- WN,
855
- WSE,
856
- WSH,
857
- WT,
1896
+ JJD,
1897
+ JJDF,
1898
+ JJE,
1899
+ JJHE,
1900
+ JJN,
1901
+ JJSE,
1902
+ JJSR,
1903
+ JJT,
1904
+ ShadowMaster,
858
1905
  addLinkPre,
1906
+ attr2prop,
1907
+ byClass,
1908
+ byId,
1909
+ createLinkPre,
859
1910
  cssToStyle,
860
1911
  fetchCss,
861
1912
  fetchHtml,
862
1913
  fetchStyle,
863
1914
  fetchText,
1915
+ fileExt,
864
1916
  h,
865
1917
  keb2cam,
866
1918
  keb2pas,
867
1919
  nextAnimationFrame,
868
1920
  off,
869
1921
  on,
870
- pas2keb
1922
+ pas2keb,
1923
+ query,
1924
+ queryAll,
1925
+ registerComponent,
1926
+ sleep,
1927
+ unwrap,
1928
+ unwrapAll,
1929
+ wrap,
1930
+ wrapAll
871
1931
  };
872
1932
  //# sourceMappingURL=bundle.js.map