tiny-essentials 1.20.2 → 1.21.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 (123) hide show
  1. package/README.md +13 -11
  2. package/dist/_/numbers.cjs +136 -0
  3. package/dist/_/numbers.d.mts +24 -0
  4. package/dist/_/numbers.mjs +102 -0
  5. package/dist/v1/TinyAdvancedRaffle.min.js +1 -0
  6. package/dist/v1/TinyArrayPaginator.min.js +1 -0
  7. package/dist/v1/TinyBasicsEs.min.js +1 -1
  8. package/dist/v1/TinyCookieConsent.min.js +1 -0
  9. package/dist/v1/TinyDayNightCycle.min.js +1 -0
  10. package/dist/v1/TinyEssentials.min.js +1 -1
  11. package/dist/v1/TinyGamepad.min.js +1 -0
  12. package/dist/v1/TinyI18.min.js +1 -0
  13. package/dist/v1/TinyInventory.min.js +1 -0
  14. package/dist/v1/TinyInventoryTrader.min.js +1 -0
  15. package/dist/v1/TinyLocalStorage.min.js +1 -1
  16. package/dist/v1/TinyRateLimiter.min.js +1 -1
  17. package/dist/v1/TinySmartScroller.min.js +1 -1
  18. package/dist/v1/TinyTextarea.min.js +1 -0
  19. package/dist/v1/TinyToastNotify.min.js +1 -1
  20. package/dist/v1/TinyUploadClicker.min.js +1 -1
  21. package/dist/v1/basics/array.cjs +21 -0
  22. package/dist/v1/basics/array.d.mts +8 -0
  23. package/dist/v1/basics/array.mjs +18 -0
  24. package/dist/v1/basics/index.cjs +2 -8
  25. package/dist/v1/basics/index.d.mts +3 -8
  26. package/dist/v1/basics/index.mjs +2 -3
  27. package/dist/v1/basics/simpleMath.cjs +46 -0
  28. package/dist/v1/basics/simpleMath.d.mts +27 -0
  29. package/dist/v1/basics/simpleMath.mjs +42 -0
  30. package/dist/v1/build/TinyAdvancedRaffle.cjs +7 -0
  31. package/dist/v1/build/TinyAdvancedRaffle.d.mts +3 -0
  32. package/dist/v1/build/TinyAdvancedRaffle.mjs +2 -0
  33. package/dist/v1/build/TinyArrayPaginator.cjs +7 -0
  34. package/dist/v1/build/TinyArrayPaginator.d.mts +3 -0
  35. package/dist/v1/build/TinyArrayPaginator.mjs +2 -0
  36. package/dist/v1/build/TinyCookieConsent.cjs +7 -0
  37. package/dist/v1/build/TinyCookieConsent.d.mts +3 -0
  38. package/dist/v1/build/TinyCookieConsent.mjs +2 -0
  39. package/dist/v1/build/TinyDayNightCycle.cjs +7 -0
  40. package/dist/v1/build/TinyDayNightCycle.d.mts +3 -0
  41. package/dist/v1/build/TinyDayNightCycle.mjs +2 -0
  42. package/dist/v1/build/TinyGamepad.cjs +7 -0
  43. package/dist/v1/build/TinyGamepad.d.mts +3 -0
  44. package/dist/v1/build/TinyGamepad.mjs +2 -0
  45. package/dist/v1/build/TinyI18.cjs +7 -0
  46. package/dist/v1/build/TinyI18.d.mts +3 -0
  47. package/dist/v1/build/TinyI18.mjs +2 -0
  48. package/dist/v1/build/TinyInventory.cjs +7 -0
  49. package/dist/v1/build/TinyInventory.d.mts +3 -0
  50. package/dist/v1/build/TinyInventory.mjs +2 -0
  51. package/dist/v1/build/TinyInventoryTrader.cjs +7 -0
  52. package/dist/v1/build/TinyInventoryTrader.d.mts +3 -0
  53. package/dist/v1/build/TinyInventoryTrader.mjs +2 -0
  54. package/dist/v1/build/TinyTextarea.cjs +7 -0
  55. package/dist/v1/build/TinyTextarea.d.mts +3 -0
  56. package/dist/v1/build/TinyTextarea.mjs +2 -0
  57. package/dist/v1/css/TinyCookieConsent.min.css +1 -0
  58. package/dist/v1/index.cjs +20 -8
  59. package/dist/v1/index.d.mts +12 -8
  60. package/dist/v1/index.mjs +11 -3
  61. package/dist/v1/libs/TinyAdvancedRaffle.cjs +1654 -0
  62. package/dist/v1/libs/TinyAdvancedRaffle.d.mts +851 -0
  63. package/dist/v1/libs/TinyAdvancedRaffle.mjs +1477 -0
  64. package/dist/v1/libs/TinyArrayPaginator.cjs +132 -0
  65. package/dist/v1/libs/TinyArrayPaginator.d.mts +78 -0
  66. package/dist/v1/libs/TinyArrayPaginator.mjs +119 -0
  67. package/dist/v1/libs/TinyCookieConsent.cjs +278 -0
  68. package/dist/v1/libs/TinyCookieConsent.d.mts +142 -0
  69. package/dist/v1/libs/TinyCookieConsent.mjs +248 -0
  70. package/dist/v1/libs/TinyDayNightCycle.cjs +1389 -0
  71. package/dist/v1/libs/TinyDayNightCycle.d.mts +673 -0
  72. package/dist/v1/libs/TinyDayNightCycle.mjs +1232 -0
  73. package/dist/v1/libs/TinyGamepad.cjs +2690 -0
  74. package/dist/v1/libs/TinyGamepad.d.mts +1286 -0
  75. package/dist/v1/libs/TinyGamepad.mjs +2386 -0
  76. package/dist/v1/libs/TinyHtml.d.mts +2 -2
  77. package/dist/v1/libs/TinyI18.cjs +946 -0
  78. package/dist/v1/libs/TinyI18.d.mts +418 -0
  79. package/dist/v1/libs/TinyI18.mjs +873 -0
  80. package/dist/v1/libs/TinyInventory.cjs +1788 -0
  81. package/dist/v1/libs/TinyInventory.d.mts +871 -0
  82. package/dist/v1/libs/TinyInventory.mjs +1650 -0
  83. package/dist/v1/libs/TinyInventoryTrader.cjs +242 -0
  84. package/dist/v1/libs/TinyInventoryTrader.d.mts +95 -0
  85. package/dist/v1/libs/TinyInventoryTrader.mjs +212 -0
  86. package/dist/v1/libs/TinyLocalStorage.cjs +14 -1
  87. package/dist/v1/libs/TinyLocalStorage.mjs +8 -1
  88. package/dist/v1/libs/TinyRateLimiter.cjs +0 -13
  89. package/dist/v1/libs/TinyRateLimiter.d.mts +0 -8
  90. package/dist/v1/libs/TinyRateLimiter.mjs +0 -12
  91. package/dist/v1/libs/TinySmartScroller.cjs +51 -15
  92. package/dist/v1/libs/TinySmartScroller.d.mts +28 -12
  93. package/dist/v1/libs/TinySmartScroller.mjs +44 -14
  94. package/dist/v1/libs/TinyTextarea.cjs +230 -0
  95. package/dist/v1/libs/TinyTextarea.d.mts +128 -0
  96. package/dist/v1/libs/TinyTextarea.mjs +198 -0
  97. package/dist/v1/libs/TinyToastNotify.cjs +2 -2
  98. package/dist/v1/libs/TinyToastNotify.mjs +2 -2
  99. package/dist/v1/libs/TinyUploadClicker.cjs +1 -1
  100. package/docs/v1/Ai-Tips.md +51 -0
  101. package/docs/v1/Personal-Ai-Prompts(portuguese).md +134 -0
  102. package/docs/v1/Personal-Ai-Prompts.md +113 -0
  103. package/docs/v1/README.md +24 -0
  104. package/docs/v1/basics/array.md +17 -0
  105. package/docs/v1/basics/simpleMath.md +73 -0
  106. package/docs/v1/libs/TinyAdvancedRaffle.md +674 -0
  107. package/docs/v1/libs/TinyArrayPaginator.md +150 -0
  108. package/docs/v1/libs/TinyCookieConsent.md +152 -0
  109. package/docs/v1/libs/TinyDayNightCycle.md +711 -0
  110. package/docs/v1/libs/TinyGamepad.md +980 -0
  111. package/docs/v1/libs/TinyI18.md +515 -0
  112. package/docs/v1/libs/TinyInventory.md +777 -0
  113. package/docs/v1/libs/TinyInventoryTrader.md +114 -0
  114. package/docs/v1/libs/TinySmartScroller.md +4 -4
  115. package/docs/v1/libs/TinyTextarea.md +156 -0
  116. package/package.json +7 -5
  117. package/dist/v1/basics/html_deprecated.cjs +0 -124
  118. package/dist/v1/basics/html_deprecated.d.mts +0 -40
  119. package/dist/v1/basics/html_deprecated.mjs +0 -97
  120. package/dist/v1/css/TinyDraggerExample.css +0 -21
  121. package/dist/v1/css/TinyNotify.css +0 -350
  122. package/dist/v1/css/aiMarker.css +0 -4
  123. package/docs/v1/basics/html_deprecated.md +0 -127
@@ -275,6 +275,11 @@ class TinySmartScroller {
275
275
  /** @type {null|EventListenerOrEventListenerObject} */
276
276
  #handler = null;
277
277
 
278
+ #isPastAtBottom = false;
279
+ #isPastAtTop = false;
280
+ #isPastAtCustomTop = false;
281
+ #isPastAtCustomBottom = false;
282
+
278
283
  #isAtBottom = false;
279
284
  #isAtTop = false;
280
285
  #isAtCustomTop = false;
@@ -596,17 +601,6 @@ class TinySmartScroller {
596
601
  return results;
597
602
  }
598
603
 
599
- /**
600
- * Emits a scroll-related event to all registered listeners.
601
- *
602
- * @param {string} event - Event name.
603
- * @param {*} [payload] - Optional event data payload.
604
- * @deprecated - Use emit() instead.
605
- */
606
- _emit(event, payload) {
607
- this.emit(event, payload);
608
- }
609
-
610
604
  /**
611
605
  * Handles scroll events, calculates position-related statuses, and emits appropriate events.
612
606
  */
@@ -639,6 +633,12 @@ class TinySmartScroller {
639
633
  else if (atCustomTop) atCustomResult = 'top';
640
634
  else if (atCustomBottom) atCustomResult = 'bottom';
641
635
 
636
+ this.#isPastAtTop = this.#isAtTop ?? false;
637
+ this.#isPastAtBottom = this.#isAtBottom ?? false;
638
+
639
+ this.#isPastAtCustomTop = this.#isAtCustomTop ?? false;
640
+ this.#isPastAtCustomBottom = this.#isAtCustomBottom ?? false;
641
+
642
642
  this.#isAtTop = atTop;
643
643
  this.#isAtBottom = atBottom;
644
644
 
@@ -968,7 +968,7 @@ class TinySmartScroller {
968
968
  *
969
969
  * @returns {boolean}
970
970
  */
971
- isUserAtCustomBottom() {
971
+ isAtCustomBottom() {
972
972
  return this.#isAtCustomBottom;
973
973
  }
974
974
 
@@ -977,7 +977,7 @@ class TinySmartScroller {
977
977
  *
978
978
  * @returns {boolean}
979
979
  */
980
- isUserAtCustomTop() {
980
+ isAtCustomTop() {
981
981
  return this.#isAtCustomTop;
982
982
  }
983
983
 
@@ -986,7 +986,7 @@ class TinySmartScroller {
986
986
  *
987
987
  * @returns {boolean}
988
988
  */
989
- isUserAtBottom() {
989
+ isAtBottom() {
990
990
  return this.#isAtBottom;
991
991
  }
992
992
 
@@ -995,10 +995,46 @@ class TinySmartScroller {
995
995
  *
996
996
  * @returns {boolean}
997
997
  */
998
- isUserAtTop() {
998
+ isAtTop() {
999
999
  return this.#isAtTop;
1000
1000
  }
1001
1001
 
1002
+ /**
1003
+ * Returns true if the user has already passed beyond the bottom boundary at some point.
1004
+ *
1005
+ * @returns {boolean}
1006
+ */
1007
+ isPastAtBottom() {
1008
+ return this.#isPastAtBottom;
1009
+ }
1010
+
1011
+ /**
1012
+ * Returns true if the user has already passed beyond the top boundary at some point.
1013
+ *
1014
+ * @returns {boolean}
1015
+ */
1016
+ isPastAtTop() {
1017
+ return this.#isPastAtTop;
1018
+ }
1019
+
1020
+ /**
1021
+ * Returns true if the user has passed beyond the defined extra scroll boundary from the top at some point.
1022
+ *
1023
+ * @returns {boolean}
1024
+ */
1025
+ isPastAtCustomTop() {
1026
+ return this.#isPastAtCustomTop;
1027
+ }
1028
+
1029
+ /**
1030
+ * Returns true if the user has passed beyond the defined extra scroll boundary from the bottom at some point.
1031
+ *
1032
+ * @returns {boolean}
1033
+ */
1034
+ isPastAtCustomBottom() {
1035
+ return this.#isPastAtCustomBottom;
1036
+ }
1037
+
1002
1038
  /**
1003
1039
  * Returns true if automatic scrolling is currently paused.
1004
1040
  *
@@ -402,14 +402,6 @@ declare class TinySmartScroller {
402
402
  oldIsVisible: boolean;
403
403
  isVisible: boolean;
404
404
  }>;
405
- /**
406
- * Emits a scroll-related event to all registered listeners.
407
- *
408
- * @param {string} event - Event name.
409
- * @param {*} [payload] - Optional event data payload.
410
- * @deprecated - Use emit() instead.
411
- */
412
- _emit(event: string, payload?: any): void;
413
405
  /**
414
406
  * Handles scroll events, calculates position-related statuses, and emits appropriate events.
415
407
  */
@@ -515,25 +507,49 @@ declare class TinySmartScroller {
515
507
  *
516
508
  * @returns {boolean}
517
509
  */
518
- isUserAtCustomBottom(): boolean;
510
+ isAtCustomBottom(): boolean;
519
511
  /**
520
512
  * Checks if the user is within the defined extra scroll boundary from the top.
521
513
  *
522
514
  * @returns {boolean}
523
515
  */
524
- isUserAtCustomTop(): boolean;
516
+ isAtCustomTop(): boolean;
525
517
  /**
526
518
  * Returns true if the user is currently scrolled to the bottom of the element.
527
519
  *
528
520
  * @returns {boolean}
529
521
  */
530
- isUserAtBottom(): boolean;
522
+ isAtBottom(): boolean;
531
523
  /**
532
524
  * Returns true if the user is currently scrolled to the top of the element.
533
525
  *
534
526
  * @returns {boolean}
535
527
  */
536
- isUserAtTop(): boolean;
528
+ isAtTop(): boolean;
529
+ /**
530
+ * Returns true if the user has already passed beyond the bottom boundary at some point.
531
+ *
532
+ * @returns {boolean}
533
+ */
534
+ isPastAtBottom(): boolean;
535
+ /**
536
+ * Returns true if the user has already passed beyond the top boundary at some point.
537
+ *
538
+ * @returns {boolean}
539
+ */
540
+ isPastAtTop(): boolean;
541
+ /**
542
+ * Returns true if the user has passed beyond the defined extra scroll boundary from the top at some point.
543
+ *
544
+ * @returns {boolean}
545
+ */
546
+ isPastAtCustomTop(): boolean;
547
+ /**
548
+ * Returns true if the user has passed beyond the defined extra scroll boundary from the bottom at some point.
549
+ *
550
+ * @returns {boolean}
551
+ */
552
+ isPastAtCustomBottom(): boolean;
537
553
  /**
538
554
  * Returns true if automatic scrolling is currently paused.
539
555
  *
@@ -236,6 +236,10 @@ class TinySmartScroller {
236
236
  #loadTags = new Set(['IMG', 'IFRAME', 'VIDEO']);
237
237
  /** @type {null|EventListenerOrEventListenerObject} */
238
238
  #handler = null;
239
+ #isPastAtBottom = false;
240
+ #isPastAtTop = false;
241
+ #isPastAtCustomTop = false;
242
+ #isPastAtCustomBottom = false;
239
243
  #isAtBottom = false;
240
244
  #isAtTop = false;
241
245
  #isAtCustomTop = false;
@@ -507,16 +511,6 @@ class TinySmartScroller {
507
511
  });
508
512
  return results;
509
513
  }
510
- /**
511
- * Emits a scroll-related event to all registered listeners.
512
- *
513
- * @param {string} event - Event name.
514
- * @param {*} [payload] - Optional event data payload.
515
- * @deprecated - Use emit() instead.
516
- */
517
- _emit(event, payload) {
518
- this.emit(event, payload);
519
- }
520
514
  /**
521
515
  * Handles scroll events, calculates position-related statuses, and emits appropriate events.
522
516
  */
@@ -550,6 +544,10 @@ class TinySmartScroller {
550
544
  atCustomResult = 'top';
551
545
  else if (atCustomBottom)
552
546
  atCustomResult = 'bottom';
547
+ this.#isPastAtTop = this.#isAtTop ?? false;
548
+ this.#isPastAtBottom = this.#isAtBottom ?? false;
549
+ this.#isPastAtCustomTop = this.#isAtCustomTop ?? false;
550
+ this.#isPastAtCustomBottom = this.#isAtCustomBottom ?? false;
553
551
  this.#isAtTop = atTop;
554
552
  this.#isAtBottom = atBottom;
555
553
  this.#isAtCustomTop = atCustomTop;
@@ -840,7 +838,7 @@ class TinySmartScroller {
840
838
  *
841
839
  * @returns {boolean}
842
840
  */
843
- isUserAtCustomBottom() {
841
+ isAtCustomBottom() {
844
842
  return this.#isAtCustomBottom;
845
843
  }
846
844
  /**
@@ -848,7 +846,7 @@ class TinySmartScroller {
848
846
  *
849
847
  * @returns {boolean}
850
848
  */
851
- isUserAtCustomTop() {
849
+ isAtCustomTop() {
852
850
  return this.#isAtCustomTop;
853
851
  }
854
852
  /**
@@ -856,7 +854,7 @@ class TinySmartScroller {
856
854
  *
857
855
  * @returns {boolean}
858
856
  */
859
- isUserAtBottom() {
857
+ isAtBottom() {
860
858
  return this.#isAtBottom;
861
859
  }
862
860
  /**
@@ -864,9 +862,41 @@ class TinySmartScroller {
864
862
  *
865
863
  * @returns {boolean}
866
864
  */
867
- isUserAtTop() {
865
+ isAtTop() {
868
866
  return this.#isAtTop;
869
867
  }
868
+ /**
869
+ * Returns true if the user has already passed beyond the bottom boundary at some point.
870
+ *
871
+ * @returns {boolean}
872
+ */
873
+ isPastAtBottom() {
874
+ return this.#isPastAtBottom;
875
+ }
876
+ /**
877
+ * Returns true if the user has already passed beyond the top boundary at some point.
878
+ *
879
+ * @returns {boolean}
880
+ */
881
+ isPastAtTop() {
882
+ return this.#isPastAtTop;
883
+ }
884
+ /**
885
+ * Returns true if the user has passed beyond the defined extra scroll boundary from the top at some point.
886
+ *
887
+ * @returns {boolean}
888
+ */
889
+ isPastAtCustomTop() {
890
+ return this.#isPastAtCustomTop;
891
+ }
892
+ /**
893
+ * Returns true if the user has passed beyond the defined extra scroll boundary from the bottom at some point.
894
+ *
895
+ * @returns {boolean}
896
+ */
897
+ isPastAtCustomBottom() {
898
+ return this.#isPastAtCustomBottom;
899
+ }
870
900
  /**
871
901
  * Returns true if automatic scrolling is currently paused.
872
902
  *
@@ -0,0 +1,230 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @typedef {Object} OnInputInfo
5
+ * @property {number} breakLines - Total number of `\n` line breaks in the textarea value.
6
+ * @property {number} height - Final calculated height (in pixels) applied to the textarea.
7
+ * @property {number} scrollHeight - Internal scrollHeight before limiting.
8
+ * @property {number} maxHeight - Maximum allowed height before scrolling is forced.
9
+ * @property {number} lineHeight - Height of one line of text, computed from CSS.
10
+ * @property {number} maxRows - Maximum number of visible rows allowed.
11
+ * @property {number} rows - Effective number of visual rows being used.
12
+ */
13
+
14
+ /**
15
+ * A lightweight utility class that automatically adjusts the height of a `<textarea>`
16
+ * element based on its content. It prevents scrollbars by expanding vertically as needed,
17
+ * up to a configurable maximum number of visible rows.
18
+ *
19
+ * Features:
20
+ * - Automatically resizes the textarea as the user types
21
+ * - Prevents vertical scrollbars until a maximum row limit is reached
22
+ * - Supports additional height padding
23
+ * - Provides real-time callbacks for input and resize events
24
+ * - Allows manual refresh and cleanup of behavior
25
+ *
26
+ * Ideal for chat inputs, note editors, or any form where dynamic space usage
27
+ * is preferred without relying on scrollbars too early.
28
+ *
29
+ * @class
30
+ * @beta
31
+ */
32
+ class TinyTextarea {
33
+ #lineHeight;
34
+ #maxRows;
35
+ #extraHeight;
36
+
37
+ #lastKnownHeight = 0;
38
+ #lastKnownRows = 0;
39
+
40
+ /** @type {HTMLTextAreaElement} */
41
+ #textarea;
42
+
43
+ /**
44
+ * @type {((info: OnInputInfo) => void) | null}
45
+ */
46
+ #onResize = null;
47
+
48
+ /**
49
+ * @type {((info: OnInputInfo) => void) | null}
50
+ */
51
+ #onInput = null;
52
+
53
+ /**
54
+ * Returns the computed line height in pixels.
55
+ * @returns {number}
56
+ */
57
+ get lineHeight() {
58
+ return this.#lineHeight;
59
+ }
60
+
61
+ /**
62
+ * Returns the maximum number of rows allowed.
63
+ * @returns {number}
64
+ */
65
+ get maxRows() {
66
+ return this.#maxRows - 1;
67
+ }
68
+
69
+ /**
70
+ * Returns the additional height added to the textarea.
71
+ * @returns {number}
72
+ */
73
+ get extraHeight() {
74
+ return this.#extraHeight;
75
+ }
76
+
77
+ /**
78
+ * Returns the most recently applied height.
79
+ * @returns {number}
80
+ */
81
+ get currentHeight() {
82
+ return this.#lastKnownHeight;
83
+ }
84
+
85
+ /**
86
+ * Returns the most recently calculated row count.
87
+ * @returns {number}
88
+ */
89
+ get currentRows() {
90
+ return this.#lastKnownRows;
91
+ }
92
+
93
+ /**
94
+ * Returns the original textarea element managed by this instance.
95
+ * @returns {HTMLTextAreaElement}
96
+ */
97
+ get textarea() {
98
+ return this.#textarea;
99
+ }
100
+
101
+ /**
102
+ * Creates a new TinyTextarea instance.
103
+ *
104
+ * @param {HTMLTextAreaElement} textarea - The `<textarea>` element to enhance.
105
+ * @param {Object} [options={}] - Optional configuration parameters.
106
+ * @param {number} [options.maxRows] - Maximum number of visible rows before scrolling.
107
+ * @param {number} [options.extraHeight] - Additional pixels to add to final height.
108
+ * @param {(info: OnInputInfo) => void} [options.onResize] - Callback when the number of rows changes.
109
+ * @param {(info: OnInputInfo) => void} [options.onInput] - Callback on every input event.
110
+ * @throws {Error} If `textarea` is not a valid `<textarea>` element.
111
+ * @throws {TypeError} If provided options are of invalid types.
112
+ */
113
+ constructor(textarea, options = {}) {
114
+ if (!(textarea instanceof HTMLTextAreaElement))
115
+ throw new Error('TinyTextarea: Provided element is not a <textarea>.');
116
+ if (typeof options !== 'object' || options === null)
117
+ throw new TypeError('TinyTextarea: Options must be an object if provided.');
118
+ if ('maxRows' in options && typeof options.maxRows !== 'number')
119
+ throw new TypeError('TinyTextarea: `maxRows` must be a number.');
120
+ if ('extraHeight' in options && typeof options.extraHeight !== 'number')
121
+ throw new TypeError('TinyTextarea: `extraHeight` must be a number.');
122
+ if ('onResize' in options && typeof options.onResize !== 'function')
123
+ throw new TypeError('TinyTextarea: `onResize` must be a function.');
124
+ if ('onInput' in options && typeof options.onInput !== 'function')
125
+ throw new TypeError('TinyTextarea: `onInput` must be a function.');
126
+
127
+ this.#textarea = textarea;
128
+ this.#maxRows = (options.maxRows ?? 5) + 1;
129
+ this.#extraHeight = options.extraHeight ?? 0;
130
+ this.#onResize = options.onResize ?? null;
131
+ this.#onInput = options.onInput ?? null;
132
+
133
+ this.#lineHeight = this.#getLineHeight();
134
+
135
+ textarea.style.overflowY = 'hidden';
136
+ textarea.style.resize = 'none';
137
+
138
+ this._handleInput = () => this.#resize();
139
+ textarea.addEventListener('input', this._handleInput);
140
+ this.#resize();
141
+ }
142
+
143
+ /**
144
+ * Automatically resize the textarea based on its content and notify listeners.
145
+ * Triggers `onResize` if the number of rows has changed.
146
+ * Always triggers `onInput`.
147
+ */
148
+ #resize() {
149
+ this.#textarea.style.height = 'auto';
150
+
151
+ const style = window.getComputedStyle(this.#textarea);
152
+ const paddingTop = parseFloat(style.paddingTop) || 0;
153
+ const paddingBottom = parseFloat(style.paddingBottom) || 0;
154
+
155
+ const breakLines = (this.#textarea.value.match(/\n/g) || []).length;
156
+ const scrollHeight = this.#textarea.scrollHeight;
157
+ const maxHeight = this.#lineHeight * this.#maxRows;
158
+ const newHeight = Math.ceil(
159
+ Math.min(scrollHeight, maxHeight) - paddingTop - paddingBottom + this.#extraHeight,
160
+ );
161
+
162
+ // const rows = Math.round(newHeight / this.#lineHeight);
163
+ const maxRows = this.#maxRows - 1;
164
+ const rows = breakLines < maxRows ? breakLines + 1 : maxRows;
165
+
166
+ this.#textarea.style.height = `${newHeight}px`;
167
+ this.#textarea.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden';
168
+ this.#lastKnownHeight = newHeight;
169
+
170
+ const info = {
171
+ breakLines,
172
+ rows,
173
+ height: newHeight,
174
+ scrollHeight,
175
+ maxHeight,
176
+ lineHeight: this.#lineHeight,
177
+ maxRows,
178
+ };
179
+
180
+ if (rows !== this.#lastKnownRows) {
181
+ this.#lastKnownRows = rows;
182
+ if (typeof this.#onResize === 'function') {
183
+ this.#onResize({ ...info });
184
+ }
185
+ }
186
+
187
+ if (typeof this.#onInput === 'function') {
188
+ this.#onInput(info);
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Computes the current line height from the textarea's computed styles.
194
+ * Falls back to `fontSize * 1.2` if lineHeight is not a number.
195
+ * @returns {number} - The computed line height in pixels.
196
+ */
197
+ #getLineHeight() {
198
+ const style = window.getComputedStyle(this.#textarea);
199
+ const line = parseFloat(style.lineHeight);
200
+ if (!Number.isNaN(line)) return line;
201
+ return parseFloat(style.fontSize) * 1.2;
202
+ }
203
+
204
+ /**
205
+ * Returns the latest height and row count of the textarea.
206
+ * @returns {{ height: number, rows: number }} - Last known resize state.
207
+ */
208
+ getData() {
209
+ return {
210
+ rows: this.#lastKnownRows,
211
+ height: this.#lastKnownHeight,
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Manually trigger a resize check.
217
+ */
218
+ refresh() {
219
+ this.#resize();
220
+ }
221
+
222
+ /**
223
+ * Cleans up internal listeners and disables dynamic behavior.
224
+ */
225
+ destroy() {
226
+ this.#textarea.removeEventListener('input', this._handleInput);
227
+ }
228
+ }
229
+
230
+ module.exports = TinyTextarea;
@@ -0,0 +1,128 @@
1
+ export default TinyTextarea;
2
+ export type OnInputInfo = {
3
+ /**
4
+ * - Total number of `\n` line breaks in the textarea value.
5
+ */
6
+ breakLines: number;
7
+ /**
8
+ * - Final calculated height (in pixels) applied to the textarea.
9
+ */
10
+ height: number;
11
+ /**
12
+ * - Internal scrollHeight before limiting.
13
+ */
14
+ scrollHeight: number;
15
+ /**
16
+ * - Maximum allowed height before scrolling is forced.
17
+ */
18
+ maxHeight: number;
19
+ /**
20
+ * - Height of one line of text, computed from CSS.
21
+ */
22
+ lineHeight: number;
23
+ /**
24
+ * - Maximum number of visible rows allowed.
25
+ */
26
+ maxRows: number;
27
+ /**
28
+ * - Effective number of visual rows being used.
29
+ */
30
+ rows: number;
31
+ };
32
+ /**
33
+ * @typedef {Object} OnInputInfo
34
+ * @property {number} breakLines - Total number of `\n` line breaks in the textarea value.
35
+ * @property {number} height - Final calculated height (in pixels) applied to the textarea.
36
+ * @property {number} scrollHeight - Internal scrollHeight before limiting.
37
+ * @property {number} maxHeight - Maximum allowed height before scrolling is forced.
38
+ * @property {number} lineHeight - Height of one line of text, computed from CSS.
39
+ * @property {number} maxRows - Maximum number of visible rows allowed.
40
+ * @property {number} rows - Effective number of visual rows being used.
41
+ */
42
+ /**
43
+ * A lightweight utility class that automatically adjusts the height of a `<textarea>`
44
+ * element based on its content. It prevents scrollbars by expanding vertically as needed,
45
+ * up to a configurable maximum number of visible rows.
46
+ *
47
+ * Features:
48
+ * - Automatically resizes the textarea as the user types
49
+ * - Prevents vertical scrollbars until a maximum row limit is reached
50
+ * - Supports additional height padding
51
+ * - Provides real-time callbacks for input and resize events
52
+ * - Allows manual refresh and cleanup of behavior
53
+ *
54
+ * Ideal for chat inputs, note editors, or any form where dynamic space usage
55
+ * is preferred without relying on scrollbars too early.
56
+ *
57
+ * @class
58
+ * @beta
59
+ */
60
+ declare class TinyTextarea {
61
+ /**
62
+ * Creates a new TinyTextarea instance.
63
+ *
64
+ * @param {HTMLTextAreaElement} textarea - The `<textarea>` element to enhance.
65
+ * @param {Object} [options={}] - Optional configuration parameters.
66
+ * @param {number} [options.maxRows] - Maximum number of visible rows before scrolling.
67
+ * @param {number} [options.extraHeight] - Additional pixels to add to final height.
68
+ * @param {(info: OnInputInfo) => void} [options.onResize] - Callback when the number of rows changes.
69
+ * @param {(info: OnInputInfo) => void} [options.onInput] - Callback on every input event.
70
+ * @throws {Error} If `textarea` is not a valid `<textarea>` element.
71
+ * @throws {TypeError} If provided options are of invalid types.
72
+ */
73
+ constructor(textarea: HTMLTextAreaElement, options?: {
74
+ maxRows?: number | undefined;
75
+ extraHeight?: number | undefined;
76
+ onResize?: ((info: OnInputInfo) => void) | undefined;
77
+ onInput?: ((info: OnInputInfo) => void) | undefined;
78
+ });
79
+ /**
80
+ * Returns the computed line height in pixels.
81
+ * @returns {number}
82
+ */
83
+ get lineHeight(): number;
84
+ /**
85
+ * Returns the maximum number of rows allowed.
86
+ * @returns {number}
87
+ */
88
+ get maxRows(): number;
89
+ /**
90
+ * Returns the additional height added to the textarea.
91
+ * @returns {number}
92
+ */
93
+ get extraHeight(): number;
94
+ /**
95
+ * Returns the most recently applied height.
96
+ * @returns {number}
97
+ */
98
+ get currentHeight(): number;
99
+ /**
100
+ * Returns the most recently calculated row count.
101
+ * @returns {number}
102
+ */
103
+ get currentRows(): number;
104
+ /**
105
+ * Returns the original textarea element managed by this instance.
106
+ * @returns {HTMLTextAreaElement}
107
+ */
108
+ get textarea(): HTMLTextAreaElement;
109
+ _handleInput: () => void;
110
+ /**
111
+ * Returns the latest height and row count of the textarea.
112
+ * @returns {{ height: number, rows: number }} - Last known resize state.
113
+ */
114
+ getData(): {
115
+ height: number;
116
+ rows: number;
117
+ };
118
+ /**
119
+ * Manually trigger a resize check.
120
+ */
121
+ refresh(): void;
122
+ /**
123
+ * Cleans up internal listeners and disables dynamic behavior.
124
+ */
125
+ destroy(): void;
126
+ #private;
127
+ }
128
+ //# sourceMappingURL=TinyTextarea.d.mts.map