tiny-essentials 1.19.3 → 1.20.1

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 (57) hide show
  1. package/dist/v1/TinyBasicsEs.min.js +1 -1
  2. package/dist/v1/TinyDragger.min.js +1 -1
  3. package/dist/v1/TinyEssentials.min.js +1 -1
  4. package/dist/v1/TinyHtml.min.js +1 -1
  5. package/dist/v1/TinyIframeEvents.min.js +1 -0
  6. package/dist/v1/TinyNewWinEvents.min.js +1 -0
  7. package/dist/v1/TinySmartScroller.min.js +1 -1
  8. package/dist/v1/TinyUploadClicker.min.js +1 -1
  9. package/dist/v1/build/TinyIframeEvents.cjs +7 -0
  10. package/dist/v1/build/TinyIframeEvents.d.mts +3 -0
  11. package/dist/v1/build/TinyIframeEvents.mjs +2 -0
  12. package/dist/v1/build/TinyNewWinEvents.cjs +7 -0
  13. package/dist/v1/build/TinyNewWinEvents.d.mts +3 -0
  14. package/dist/v1/build/TinyNewWinEvents.mjs +2 -0
  15. package/dist/v1/index.cjs +4 -0
  16. package/dist/v1/index.d.mts +3 -1
  17. package/dist/v1/index.mjs +3 -1
  18. package/dist/v1/libs/TinyDragger.cjs +1 -1
  19. package/dist/v1/libs/TinyDragger.mjs +1 -1
  20. package/dist/v1/libs/TinyHtml.cjs +292 -103
  21. package/dist/v1/libs/TinyHtml.d.mts +142 -39
  22. package/dist/v1/libs/TinyHtml.mjs +266 -94
  23. package/dist/v1/libs/TinyIframeEvents.cjs +410 -0
  24. package/dist/v1/libs/TinyIframeEvents.d.mts +193 -0
  25. package/dist/v1/libs/TinyIframeEvents.mjs +348 -0
  26. package/dist/v1/libs/TinyNewWinEvents.cjs +488 -0
  27. package/dist/v1/libs/TinyNewWinEvents.d.mts +241 -0
  28. package/dist/v1/libs/TinyNewWinEvents.mjs +437 -0
  29. package/docs/v1/README.md +2 -0
  30. package/docs/v1/libs/TinyHtml.md +128 -6
  31. package/docs/v1/libs/TinyIframeEvents.md +149 -0
  32. package/docs/v1/libs/TinyNewWinEvents.md +186 -0
  33. package/docs/v1/libs/TinyNotifyCenter.md +1 -1
  34. package/package.json +1 -1
  35. package/dist/v1/ColorSafeStringify.js +0 -235
  36. package/dist/v1/TinyAfterScrollWatcher.js +0 -219
  37. package/dist/v1/TinyBasicsEs.js +0 -9334
  38. package/dist/v1/TinyClipboard.js +0 -459
  39. package/dist/v1/TinyColorConverter.js +0 -617
  40. package/dist/v1/TinyDomReadyManager.js +0 -213
  41. package/dist/v1/TinyDragDropDetector.js +0 -307
  42. package/dist/v1/TinyDragger.js +0 -6569
  43. package/dist/v1/TinyEssentials.js +0 -19893
  44. package/dist/v1/TinyEvents.js +0 -402
  45. package/dist/v1/TinyHtml.js +0 -5545
  46. package/dist/v1/TinyLevelUp.js +0 -291
  47. package/dist/v1/TinyLocalStorage.js +0 -1440
  48. package/dist/v1/TinyNotifications.js +0 -408
  49. package/dist/v1/TinyNotifyCenter.js +0 -493
  50. package/dist/v1/TinyPromiseQueue.js +0 -299
  51. package/dist/v1/TinyRateLimiter.js +0 -611
  52. package/dist/v1/TinySmartScroller.js +0 -7039
  53. package/dist/v1/TinyTextRangeEditor.js +0 -497
  54. package/dist/v1/TinyTimeout.js +0 -233
  55. package/dist/v1/TinyToastNotify.js +0 -441
  56. package/dist/v1/TinyUploadClicker.js +0 -13456
  57. package/dist/v1/UltraRandomMsgGen.js +0 -995
@@ -199,11 +199,39 @@ const __elemCollision = {
199
199
  class TinyHtml {
200
200
  /** @typedef {import('../basics/collision.mjs').ObjRect} ObjRect */
201
201
  static Utils = { ...TinyCollision };
202
+ /**
203
+ * Creates a new TinyHtml element from a tag name and optional attributes.
204
+ *
205
+ * You can alias this method for convenience:
206
+ * ```js
207
+ * const createElement = TinyHtml.createFrom;
208
+ * const myDiv = createElement('div', { class: 'box' });
209
+ * ```
210
+ *
211
+ * @param {string} tagName - The HTML tag name (e.g., 'div', 'span', 'button').
212
+ * @param {Record<string, string|null>} [attrs] - Optional key-value pairs representing HTML attributes.
213
+ * If the value is `null`, the attribute will still be set with an empty value.
214
+ * @returns {TinyHtml} - A new instance of TinyHtml representing the created element.
215
+ * @throws {TypeError} - If `tagName` is not a string, or `attrs` is not a plain object when defined.
216
+ */
217
+ static createFrom(tagName, attrs) {
218
+ if (typeof tagName !== 'string')
219
+ throw new TypeError('The "tagName" must be a string.');
220
+ if (typeof attrs !== 'undefined' && typeof attrs !== 'object')
221
+ throw new TypeError('The "attrs" must be a object.');
222
+ const elem = TinyHtml.createElement(tagName);
223
+ if (typeof attrs === 'object') {
224
+ for (const attrName in attrs) {
225
+ elem.setAttr(attrName, attrs[attrName]);
226
+ }
227
+ }
228
+ return elem;
229
+ }
202
230
  /**
203
231
  * Creates a new DOM element with the specified tag name and options, then wraps it in a TinyHtml instance.
204
232
  *
205
233
  * @param {string} tagName - The tag name of the element to create (e.g., 'div', 'span').
206
- * @param {ElementCreationOptions} ops - Optional settings for creating the element.
234
+ * @param {ElementCreationOptions} [ops] - Optional settings for creating the element.
207
235
  * @returns {TinyHtml} A TinyHtml instance wrapping the newly created DOM element.
208
236
  * @throws {TypeError} If tagName is not a string or ops is not an object.
209
237
  */
@@ -246,7 +274,7 @@ class TinyHtml {
246
274
  }
247
275
  template.innerHTML = htmlString;
248
276
  if (!(template.content.firstChild instanceof Element))
249
- throw new Error('');
277
+ throw new Error('The HTML string must contain a valid HTML element.');
250
278
  return new TinyHtml(template.content.firstChild);
251
279
  }
252
280
  /**
@@ -276,17 +304,16 @@ class TinyHtml {
276
304
  *
277
305
  * @param {string} selector - A valid CSS selector string.
278
306
  * @param {Document|Element} elem - Target element.
279
- * @returns {TinyHtml[]} An array of TinyHtml instances wrapping the matched elements.
307
+ * @returns {TinyHtml} An array of TinyHtml instances wrapping the matched elements.
280
308
  */
281
309
  static queryAll(selector, elem = document) {
282
- const newEls = elem.querySelectorAll(selector);
283
- return TinyHtml.toTinyElm([...newEls]);
310
+ return new TinyHtml(elem.querySelectorAll(selector));
284
311
  }
285
312
  /**
286
313
  * Queries the element for all elements matching the CSS selector and wraps them in TinyHtml instances.
287
314
  *
288
315
  * @param {string} selector - A valid CSS selector string.
289
- * @returns {TinyHtml[]} An array of TinyHtml instances wrapping the matched elements.
316
+ * @returns {TinyHtml} An array of TinyHtml instances wrapping the matched elements.
290
317
  */
291
318
  querySelectorAll(selector) {
292
319
  return TinyHtml.queryAll(selector, TinyHtml._preElem(this, 'queryAll'));
@@ -308,17 +335,16 @@ class TinyHtml {
308
335
  *
309
336
  * @param {string} selector - The class name to search for.
310
337
  * @param {Document|Element} elem - Target element.
311
- * @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
338
+ * @returns {TinyHtml} An array of TinyHtml instances wrapping the found elements.
312
339
  */
313
340
  static getByClassName(selector, elem = document) {
314
- const newEls = elem.getElementsByClassName(selector);
315
- return TinyHtml.toTinyElm([...newEls]);
341
+ return new TinyHtml(elem.getElementsByClassName(selector));
316
342
  }
317
343
  /**
318
344
  * Retrieves all elements with the specified class name and wraps them in TinyHtml instances.
319
345
  *
320
346
  * @param {string} selector - The class name to search for.
321
- * @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
347
+ * @returns {TinyHtml} An array of TinyHtml instances wrapping the found elements.
322
348
  */
323
349
  getElementsByClassName(selector) {
324
350
  return TinyHtml.getByClassName(selector, TinyHtml._preElem(this, 'getByClassName'));
@@ -327,11 +353,10 @@ class TinyHtml {
327
353
  * Retrieves all elements with the specified name attribute and wraps them in TinyHtml instances.
328
354
  *
329
355
  * @param {string} selector - The name attribute to search for.
330
- * @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
356
+ * @returns {TinyHtml} An array of TinyHtml instances wrapping the found elements.
331
357
  */
332
358
  static getByName(selector) {
333
- const newEls = document.getElementsByName(selector);
334
- return TinyHtml.toTinyElm([...newEls]);
359
+ return new TinyHtml(document.getElementsByName(selector));
335
360
  }
336
361
  /**
337
362
  * Retrieves all elements with the specified local tag name within the given namespace URI,
@@ -340,11 +365,10 @@ class TinyHtml {
340
365
  * @param {string} localName - The local name (tag) of the elements to search for.
341
366
  * @param {string|null} [namespaceURI='http://www.w3.org/1999/xhtml'] - The namespace URI to search within.
342
367
  * @param {Document|Element} elem - Target element.
343
- * @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
368
+ * @returns {TinyHtml} An array of TinyHtml instances wrapping the found elements.
344
369
  */
345
370
  static getByTagNameNS(localName, namespaceURI = 'http://www.w3.org/1999/xhtml', elem = document) {
346
- const newEls = elem.getElementsByTagNameNS(namespaceURI, localName);
347
- return TinyHtml.toTinyElm([...newEls]);
371
+ return new TinyHtml(elem.getElementsByTagNameNS(namespaceURI, localName));
348
372
  }
349
373
  /**
350
374
  * Retrieves all elements with the specified local tag name within the given namespace URI,
@@ -352,7 +376,7 @@ class TinyHtml {
352
376
  *
353
377
  * @param {string} localName - The local name (tag) of the elements to search for.
354
378
  * @param {string|null} [namespaceURI='http://www.w3.org/1999/xhtml'] - The namespace URI to search within.
355
- * @returns {TinyHtml[]} An array of TinyHtml instances wrapping the found elements.
379
+ * @returns {TinyHtml} An array of TinyHtml instances wrapping the found elements.
356
380
  */
357
381
  getElementsByTagNameNS(localName, namespaceURI = 'http://www.w3.org/1999/xhtml') {
358
382
  return TinyHtml.getByTagNameNS(localName, namespaceURI, TinyHtml._preElem(this, 'getByTagNameNS'));
@@ -361,81 +385,146 @@ class TinyHtml {
361
385
  /**
362
386
  * Returns the current target held by this instance.
363
387
  *
388
+ * @param {number} index - The index of the element to retrieve.
364
389
  * @returns {ConstructorElValues} - The instance's target element.
365
390
  */
366
- get() {
367
- return this.#el;
391
+ get(index) {
392
+ if (typeof index !== 'number')
393
+ throw new TypeError('The index must be a number.');
394
+ if (!this.#el[index])
395
+ throw new Error(`No element found at index ${index}.`);
396
+ return this.#el[index];
397
+ }
398
+ /**
399
+ * Extracts a single DOM element from the internal list at the specified index.
400
+ *
401
+ * @param {number} index - The index of the element to extract.
402
+ * @returns {TinyHtml} A new TinyHtml instance wrapping the extracted element.
403
+ */
404
+ extract(index) {
405
+ if (typeof index !== 'number')
406
+ throw new TypeError('The index must be a number.');
407
+ if (!this.#el[index])
408
+ throw new Error(`Cannot extract: no element exists at index ${index}.`);
409
+ return new TinyHtml(this.#el[index]);
410
+ }
411
+ /**
412
+ * Checks whether the element exists at the given index.
413
+ *
414
+ * @param {number} index - The index to check.
415
+ * @returns {boolean} - True if the element exists; otherwise, false.
416
+ */
417
+ exists(index) {
418
+ if (typeof index !== 'number')
419
+ throw new TypeError('The index must be a number.');
420
+ if (!this.#el[index])
421
+ return false;
422
+ return true;
423
+ }
424
+ /**
425
+ * Returns the current targets held by this instance.
426
+ *
427
+ * @returns {ConstructorElValues[]} - The instance's targets element.
428
+ */
429
+ getAll() {
430
+ return [...this.#el];
368
431
  }
369
432
  /**
370
433
  * Returns the current Element held by this instance.
371
434
  *
372
435
  * @param {string} where - The method name or context calling this.
436
+ * @param {number} index - The index of the element to retrieve.
373
437
  * @returns {ConstructorElValues} - The instance's element.
374
438
  * @readonly
375
439
  */
376
- _getElement(where) {
377
- if (!(this.#el instanceof Element) &&
378
- !(this.#el instanceof Window) &&
379
- !(this.#el instanceof Document))
440
+ _getElement(where, index) {
441
+ if (!(this.#el[index] instanceof Element) &&
442
+ !(this.#el[index] instanceof Window) &&
443
+ !(this.#el[index] instanceof Document))
444
+ throw new Error(`[TinyHtml] Invalid Element in ${where}().`);
445
+ return this.#el[index];
446
+ }
447
+ /**
448
+ * Returns the current Elements held by this instance.
449
+ *
450
+ * @param {string} where - The method name or context calling this.
451
+ * @returns {ConstructorElValues[]} - The instance's elements.
452
+ * @readonly
453
+ */
454
+ _getElements(where) {
455
+ if (!this.#el.every((el) => el instanceof Element || el instanceof Window || el instanceof Document))
380
456
  throw new Error(`[TinyHtml] Invalid Element in ${where}().`);
381
- return this.#el;
457
+ return [...this.#el];
382
458
  }
383
459
  //////////////////////////////////////////////////////
384
460
  /**
385
- * @param {TinyElement|EventTarget|null|(TinyElement|EventTarget|null)[]} elems
386
- * @param {string} where
387
- * @param {any[]} TheTinyElements
388
- * @param {string[]} elemName
389
- * @returns {any[]}
461
+ * Prepares and validates multiple elements against allowed types.
462
+ *
463
+ * @param {TinyElement | EventTarget | null | (TinyElement | EventTarget | null)[]} elems - The input elements to validate.
464
+ * @param {string} where - The method name or context calling this.
465
+ * @param {any[]} TheTinyElements - The list of allowed constructors (e.g., Element, Document).
466
+ * @param {string[]} elemName - The list of expected element names for error reporting.
467
+ * @returns {any[]} - A flat array of validated elements.
468
+ * @throws {Error} - If any element is not an instance of one of the allowed types.
390
469
  * @readonly
391
470
  */
392
471
  static _preElemsTemplate(elems, where, TheTinyElements, elemName) {
393
472
  /** @param {(TinyElement|EventTarget|null)[]} item */
394
- const checkElement = (item) => item.map((elem) => {
395
- const result = elem instanceof TinyHtml ? elem._getElement(where) : elem;
396
- let allowed = false;
397
- for (const TheTinyElement of TheTinyElements) {
398
- if (result instanceof TheTinyElement) {
399
- allowed = true;
400
- break;
473
+ const checkElement = (item) => {
474
+ /** @type {any[]} */
475
+ const results = [];
476
+ item.map((elem) => (elem instanceof TinyHtml ? elem._getElements(where) : [elem]).map((result) => {
477
+ let allowed = false;
478
+ for (const TheTinyElement of TheTinyElements) {
479
+ if (result instanceof TheTinyElement) {
480
+ allowed = true;
481
+ break;
482
+ }
401
483
  }
402
- }
403
- if (!allowed)
404
- throw new Error(`[TinyHtml] Invalid element of the list "${elemName.join(',')}" in ${where}().`);
405
- return result;
406
- });
484
+ if (!allowed)
485
+ throw new Error(`[TinyHtml] Invalid element of the list "${elemName.join(',')}" in ${where}().`);
486
+ results.push(result);
487
+ return result;
488
+ }));
489
+ return results;
490
+ };
407
491
  if (!Array.isArray(elems))
408
492
  return checkElement([elems]);
409
493
  return checkElement(elems);
410
494
  }
411
495
  /**
412
- * @param {TinyElement|EventTarget|null|(TinyElement|EventTarget|null)[]} elems
413
- * @param {string} where
414
- * @param {any[]} TheTinyElements
415
- * @param {string[]} elemName
416
- * @param {boolean} [canNull=false]
417
- * @returns {any}
496
+ * Prepares and validates a single element against allowed types.
497
+ *
498
+ * @param {TinyElement | EventTarget | null | (TinyElement | EventTarget | null)[]} elems - The input element or list to validate.
499
+ * @param {string} where - The method name or context calling this.
500
+ * @param {any[]} TheTinyElements - The list of allowed constructors (e.g., Element, Document).
501
+ * @param {string[]} elemName - The list of expected element names for error reporting.
502
+ * @param {boolean} [canNull=false] - Whether `null` is allowed as a valid value.
503
+ * @returns {any} - The validated element or `null` if allowed.
504
+ * @throws {Error} - If the element is not valid or if multiple elements are provided.
418
505
  * @readonly
419
506
  */
420
507
  static _preElemTemplate(elems, where, TheTinyElements, elemName, canNull = false) {
421
508
  /** @param {(TinyElement|EventTarget|null)[]} item */
422
509
  const checkElement = (item) => {
423
510
  const elem = item[0];
424
- let result = elem instanceof TinyHtml ? elem._getElement(where) : elem;
511
+ const result = elem instanceof TinyHtml ? elem._getElements(where) : [elem];
512
+ if (result.length > 1)
513
+ throw new Error(`[TinyHtml] Invalid element amount in ${where}() (Received ${result.length}/1).`);
425
514
  let allowed = false;
426
515
  for (const TheTinyElement of TheTinyElements) {
427
- if (result instanceof TheTinyElement) {
516
+ if (result[0] instanceof TheTinyElement) {
428
517
  allowed = true;
429
518
  break;
430
519
  }
431
520
  }
432
- if (canNull && (result === null || typeof result === 'undefined')) {
433
- result = null;
521
+ if (canNull && (result[0] === null || typeof result[0] === 'undefined')) {
522
+ result[0] = null;
434
523
  allowed = true;
435
524
  }
436
525
  if (!allowed)
437
526
  throw new Error(`[TinyHtml] Invalid element of the list "${elemName.join(',')}" in ${where}().`);
438
- return result;
527
+ return result[0];
439
528
  };
440
529
  if (!Array.isArray(elems))
441
530
  return checkElement([elems]);
@@ -689,8 +778,13 @@ class TinyHtml {
689
778
  */
690
779
  static fromTinyElm(elems) {
691
780
  /** @param {TinyElement[]} item */
692
- const checkElement = (item) => item.map((elem) =>
693
- /** @type {Element} */ (elem instanceof TinyHtml ? elem._getElement('fromTinyElm') : elem));
781
+ const checkElement = (item) => {
782
+ /** @type {Element[]} */
783
+ const result = [];
784
+ item.map((elem) =>
785
+ /** @type {Element[]} */ (elem instanceof TinyHtml ? elem._getElements('fromTinyElm') : [elem]).map((elem) => result.push(elem)));
786
+ return result;
787
+ };
694
788
  if (!Array.isArray(elems))
695
789
  return checkElement([elems]);
696
790
  return checkElement(elems);
@@ -1452,7 +1546,7 @@ class TinyHtml {
1452
1546
  const targ = TinyHtml._preNodeElem(target, 'insertBefore');
1453
1547
  const childNode = TinyHtml._preNodeElemWithNull(child, 'insertBefore');
1454
1548
  if (!targ.parentNode)
1455
- throw new Error('');
1549
+ throw new Error('The target element has no parent node to insert before.');
1456
1550
  targ.parentNode.insertBefore(elem, childNode || targ);
1457
1551
  return el;
1458
1552
  }
@@ -1479,7 +1573,7 @@ class TinyHtml {
1479
1573
  const targ = TinyHtml._preNodeElem(target, 'insertBefore');
1480
1574
  const childNode = TinyHtml._preNodeElemWithNull(child, 'insertBefore');
1481
1575
  if (!targ.parentNode)
1482
- throw new Error('');
1576
+ throw new Error('The target element has no parent node to insert after.');
1483
1577
  targ.parentNode.insertBefore(elem, childNode || targ.nextSibling);
1484
1578
  return el;
1485
1579
  }
@@ -1526,23 +1620,40 @@ class TinyHtml {
1526
1620
  //////////////////////////////////////////////////////
1527
1621
  /**
1528
1622
  * The target HTML element for instance-level operations.
1529
- * @type {ConstructorElValues}
1623
+ * @type {ConstructorElValues[]}
1530
1624
  */
1531
1625
  #el;
1532
1626
  /**
1533
1627
  * Creates an instance of TinyHtml for a specific Element.
1534
1628
  * Useful when you want to operate repeatedly on the same element using instance methods.
1535
- * @param {ConstructorElValues} el - The element to wrap and manipulate.
1629
+ * @param {ConstructorElValues|ConstructorElValues[]|NodeListOf<Element>|HTMLCollectionOf<Element>|NodeListOf<HTMLElement>} el - The element to wrap and manipulate.
1536
1630
  */
1537
1631
  constructor(el) {
1538
1632
  if (el instanceof TinyHtml)
1539
1633
  throw new Error(`[TinyHtml] You are trying to put a TinyHtml inside another TinyHtml in constructor.`);
1540
- if (!(el instanceof Element) &&
1541
- !(el instanceof Window) &&
1542
- !(el instanceof Document) &&
1543
- !(el instanceof Text))
1544
- throw new Error(`[TinyHtml] Invalid Target in constructor.`);
1545
- this.#el = el;
1634
+ /** @param {any[]} els */
1635
+ const elCheck = (els) => {
1636
+ if (!els.every((el) => el instanceof Element ||
1637
+ el instanceof Window ||
1638
+ el instanceof Document ||
1639
+ el instanceof Text))
1640
+ throw new Error(`[TinyHtml] Invalid Target in constructor.`);
1641
+ };
1642
+ if (Array.isArray(el)) {
1643
+ elCheck(el);
1644
+ this.#el = el;
1645
+ }
1646
+ else if (el instanceof NodeList || el instanceof HTMLCollection) {
1647
+ const els = [...el];
1648
+ elCheck(els);
1649
+ this.#el = els;
1650
+ }
1651
+ else {
1652
+ const els = [el];
1653
+ elCheck(els);
1654
+ // @ts-ignore
1655
+ this.#el = els;
1656
+ }
1546
1657
  }
1547
1658
  /**
1548
1659
  * Checks whether the given object is a window.
@@ -1932,7 +2043,13 @@ class TinyHtml {
1932
2043
  msTransform: '-ms-transform',
1933
2044
  msTransition: '-ms-transition',
1934
2045
  };
1935
- /** @type {Record<string | symbol, string>} */
2046
+ /**
2047
+ * Public proxy to manage camelCase ➝ kebab-case CSS property aliasing.
2048
+ *
2049
+ * Modifying this object ensures that the reverse mapping in `cssPropRevAliases` is updated accordingly.
2050
+ *
2051
+ * @type {Record<string | symbol, string>}
2052
+ */
1936
2053
  static cssPropAliases = new Proxy(TinyHtml.#cssPropAliases, {
1937
2054
  set(target, camelCaseKey, kebabValue) {
1938
2055
  target[camelCaseKey] = kebabValue;
@@ -1941,7 +2058,13 @@ class TinyHtml {
1941
2058
  return true;
1942
2059
  },
1943
2060
  });
1944
- /** @type {Record<string | symbol, string>} */
2061
+ /**
2062
+ * Reverse map of `cssPropAliases`, mapping kebab-case back to camelCase CSS property names.
2063
+ *
2064
+ * This enables consistent bidirectional lookups of style properties.
2065
+ *
2066
+ * @type {Record<string | symbol, string>}
2067
+ */
1945
2068
  static cssPropRevAliases = Object.fromEntries(Object.entries(TinyHtml.#cssPropAliases).map(([camel, kebab]) => [kebab, camel]));
1946
2069
  /**
1947
2070
  * Converts a camelCase string to kebab-case
@@ -3410,7 +3533,7 @@ class TinyHtml {
3410
3533
  throw new TypeError('The "type" must be a string.');
3411
3534
  if (typeof where !== 'string')
3412
3535
  throw new TypeError('The "where" must be a string.');
3413
- if (!(elem instanceof HTMLInputElement))
3536
+ if (!(elem instanceof HTMLInputElement) && !(elem instanceof HTMLTextAreaElement))
3414
3537
  throw new Error(`Provided element is not an HTMLInputElement in ${where}().`);
3415
3538
  if (typeof TinyHtml._valTypes[type] !== 'function')
3416
3539
  throw new Error(`No handler found for type "${type}" in ${where}().`);
@@ -3923,13 +4046,70 @@ class TinyHtml {
3923
4046
  }
3924
4047
  ///////////////////////////////////////////////////////////////
3925
4048
  /**
3926
- * Property name normalization similar to jQuery's propFix.
3927
- * @readonly
4049
+ * Internal property name normalization map (similar to jQuery's `propFix`).
4050
+ * Maps attribute-like names to their JavaScript DOM property equivalents.
4051
+ *
4052
+ * Example: `'for'` ➝ `'htmlFor'`, `'class'` ➝ `'className'`.
4053
+ *
4054
+ * ⚠️ Do not modify this object directly. Use `TinyHtml.propFix` to ensure reverse mapping (`attrFix`) remains in sync.
4055
+ *
4056
+ * @type {Record<string | symbol, string>}
3928
4057
  */
3929
- static _propFix = {
4058
+ static #propFix = {
3930
4059
  for: 'htmlFor',
3931
4060
  class: 'className',
3932
4061
  };
4062
+ /**
4063
+ * Public proxy for normalized DOM property names.
4064
+ *
4065
+ * Setting a new entry here will also automatically update the reverse map in `TinyHtml.attrFix`.
4066
+ *
4067
+ * @type {Record<string | symbol, string>}
4068
+ */
4069
+ static propFix = new Proxy(TinyHtml.#propFix, {
4070
+ set(target, val1, val2) {
4071
+ target[val1] = val2;
4072
+ // @ts-ignore
4073
+ TinyHtml.attrFix[val2] = val1;
4074
+ return true;
4075
+ },
4076
+ });
4077
+ /**
4078
+ * Reverse map of `propFix`, mapping property names back to their attribute equivalents.
4079
+ *
4080
+ * Used when converting DOM property names into HTML attribute names.
4081
+ *
4082
+ * @type {Record<string | symbol, string>}
4083
+ */
4084
+ static attrFix = Object.fromEntries(Object.entries(TinyHtml.#propFix).map(([val1, val2]) => [val2, val1]));
4085
+ /**
4086
+ * Normalizes an attribute name to its corresponding DOM property name.
4087
+ *
4088
+ * Example: `'class'` ➝ `'className'`, `'for'` ➝ `'htmlFor'`.
4089
+ * If the name is not mapped, it returns the original name.
4090
+ *
4091
+ * @param {string} name - The attribute name to normalize.
4092
+ * @returns {string} - The corresponding property name.
4093
+ */
4094
+ static getPropName(name) {
4095
+ // @ts-ignore
4096
+ const propName = typeof TinyHtml.propFix[name] === 'string' ? TinyHtml.propFix[name] : name;
4097
+ return propName;
4098
+ }
4099
+ /**
4100
+ * Converts a DOM property name back to its corresponding attribute name.
4101
+ *
4102
+ * Example: `'className'` ➝ `'class'`, `'htmlFor'` ➝ `'for'`.
4103
+ * If the name is not mapped, it returns the original name.
4104
+ *
4105
+ * @param {string} name - The property name to convert.
4106
+ * @returns {string} - The corresponding attribute name.
4107
+ */
4108
+ static getAttrName(name) {
4109
+ // @ts-ignore
4110
+ const propName = typeof TinyHtml.attrFix[name] === 'string' ? TinyHtml.attrFix[name] : name;
4111
+ return propName;
4112
+ }
3933
4113
  /**
3934
4114
  * Get an attribute on an element.
3935
4115
  * @param {TinyElement} el
@@ -3940,7 +4120,7 @@ class TinyHtml {
3940
4120
  if (typeof name !== 'string')
3941
4121
  throw new TypeError('The "name" must be a string.');
3942
4122
  const elem = TinyHtml._preElem(el, 'attr');
3943
- return elem.getAttribute(name);
4123
+ return elem.getAttribute(TinyHtml.getAttrName(name));
3944
4124
  }
3945
4125
  /**
3946
4126
  * Get an attribute on an element.
@@ -3964,9 +4144,9 @@ class TinyHtml {
3964
4144
  throw new TypeError('The "value" must be a string.');
3965
4145
  TinyHtml._preElems(el, 'setAttr').forEach((elem) => {
3966
4146
  if (value === null)
3967
- elem.removeAttribute(name);
4147
+ elem.removeAttribute(TinyHtml.getAttrName(name));
3968
4148
  else
3969
- elem.setAttribute(name, value);
4149
+ elem.setAttribute(TinyHtml.getAttrName(name), value);
3970
4150
  });
3971
4151
  return el;
3972
4152
  }
@@ -3988,7 +4168,7 @@ class TinyHtml {
3988
4168
  static removeAttr(el, name) {
3989
4169
  if (typeof name !== 'string')
3990
4170
  throw new TypeError('The "name" must be a string.');
3991
- TinyHtml._preElems(el, 'removeAttr').forEach((elem) => elem.removeAttribute(name));
4171
+ TinyHtml._preElems(el, 'removeAttr').forEach((elem) => elem.removeAttribute(TinyHtml.getAttrName(name)));
3992
4172
  return el;
3993
4173
  }
3994
4174
  /**
@@ -4009,7 +4189,7 @@ class TinyHtml {
4009
4189
  if (typeof name !== 'string')
4010
4190
  throw new TypeError('The "name" must be a string.');
4011
4191
  const elem = TinyHtml._preElem(el, 'hasAttr');
4012
- return elem.hasAttribute(name);
4192
+ return elem.hasAttribute(TinyHtml.getAttrName(name));
4013
4193
  }
4014
4194
  /**
4015
4195
  * Check if an attribute exists on an element.
@@ -4030,9 +4210,7 @@ class TinyHtml {
4030
4210
  throw new TypeError('The "name" must be a string.');
4031
4211
  const elem = TinyHtml._preElem(el, 'hasProp');
4032
4212
  // @ts-ignore
4033
- const propName = TinyHtml._propFix[name] || name;
4034
- // @ts-ignore
4035
- return !!elem[propName];
4213
+ return !!elem[TinyHtml.getPropName(name)];
4036
4214
  }
4037
4215
  /**
4038
4216
  * Check if a property exists.
@@ -4053,9 +4231,7 @@ class TinyHtml {
4053
4231
  throw new TypeError('The "name" must be a string.');
4054
4232
  TinyHtml._preElems(el, 'addProp').forEach((elem) => {
4055
4233
  // @ts-ignore
4056
- name = TinyHtml._propFix[name] || name;
4057
- // @ts-ignore
4058
- elem[name] = true;
4234
+ elem[TinyHtml.getPropName(name)] = true;
4059
4235
  });
4060
4236
  return el;
4061
4237
  }
@@ -4078,9 +4254,7 @@ class TinyHtml {
4078
4254
  throw new TypeError('The "name" must be a string.');
4079
4255
  TinyHtml._preElems(el, 'removeProp').forEach((elem) => {
4080
4256
  // @ts-ignore
4081
- name = TinyHtml._propFix[name] || name;
4082
- // @ts-ignore
4083
- elem[name] = false;
4257
+ elem[TinyHtml.getPropName(name)] = false;
4084
4258
  });
4085
4259
  return el;
4086
4260
  }
@@ -4105,9 +4279,7 @@ class TinyHtml {
4105
4279
  throw new TypeError('The "force" must be a boolean.');
4106
4280
  TinyHtml._preElems(el, 'toggleProp').forEach((elem) => {
4107
4281
  // @ts-ignore
4108
- const propName = TinyHtml._propFix[name] || name;
4109
- // @ts-ignore
4110
- const shouldEnable = force === undefined ? !elem[propName] : force;
4282
+ const shouldEnable = force === undefined ? !elem[TinyHtml.getPropName(name)] : force;
4111
4283
  // @ts-ignore
4112
4284
  if (shouldEnable)
4113
4285
  TinyHtml.addProp(elem, name);
@@ -4200,20 +4372,20 @@ class TinyHtml {
4200
4372
  result[name] = rect[name];
4201
4373
  }
4202
4374
  if (typeof extraRect !== 'object' || extraRect === null || Array.isArray(extraRect))
4203
- throw new Error('');
4375
+ throw new Error('extraRect must be a non-null object.');
4204
4376
  const { height = 0, width = 0, top = 0, bottom = 0, left = 0, right = 0 } = extraRect;
4205
4377
  if (typeof height !== 'number')
4206
- throw new Error('');
4378
+ throw new Error('extraRect.height must be a number.');
4207
4379
  if (typeof width !== 'number')
4208
- throw new Error('');
4380
+ throw new Error('extraRect.width must be a number.');
4209
4381
  if (typeof top !== 'number')
4210
- throw new Error('');
4382
+ throw new Error('extraRect.top must be a number.');
4211
4383
  if (typeof bottom !== 'number')
4212
- throw new Error('');
4384
+ throw new Error('extraRect.bottom must be a number.');
4213
4385
  if (typeof left !== 'number')
4214
- throw new Error('');
4386
+ throw new Error('extraRect.left must be a number.');
4215
4387
  if (typeof right !== 'number')
4216
- throw new Error('');
4388
+ throw new Error('extraRect.right must be a number.');
4217
4389
  // @ts-ignore
4218
4390
  result.height += height;
4219
4391
  // @ts-ignore