tiny-essentials 1.20.2 โ 1.20.3
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.
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinySmartScroller.min.js +1 -1
- package/dist/v1/TinyTextarea.min.js +1 -0
- package/dist/v1/basics/index.mjs +1 -1
- package/dist/v1/build/TinyTextarea.cjs +7 -0
- package/dist/v1/build/TinyTextarea.d.mts +3 -0
- package/dist/v1/build/TinyTextarea.mjs +2 -0
- package/dist/v1/index.cjs +2 -0
- package/dist/v1/index.d.mts +2 -1
- package/dist/v1/index.mjs +2 -1
- package/dist/v1/libs/TinySmartScroller.cjs +87 -0
- package/dist/v1/libs/TinySmartScroller.d.mts +52 -0
- package/dist/v1/libs/TinySmartScroller.mjs +76 -0
- package/dist/v1/libs/TinyTextarea.cjs +230 -0
- package/dist/v1/libs/TinyTextarea.d.mts +128 -0
- package/dist/v1/libs/TinyTextarea.mjs +198 -0
- package/docs/v1/README.md +1 -0
- package/docs/v1/libs/TinySmartScroller.md +4 -4
- package/docs/v1/libs/TinyTextarea.md +156 -0
- package/package.json +1 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} OnInputInfo
|
|
3
|
+
* @property {number} breakLines - Total number of `\n` line breaks in the textarea value.
|
|
4
|
+
* @property {number} height - Final calculated height (in pixels) applied to the textarea.
|
|
5
|
+
* @property {number} scrollHeight - Internal scrollHeight before limiting.
|
|
6
|
+
* @property {number} maxHeight - Maximum allowed height before scrolling is forced.
|
|
7
|
+
* @property {number} lineHeight - Height of one line of text, computed from CSS.
|
|
8
|
+
* @property {number} maxRows - Maximum number of visible rows allowed.
|
|
9
|
+
* @property {number} rows - Effective number of visual rows being used.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* A lightweight utility class that automatically adjusts the height of a `<textarea>`
|
|
13
|
+
* element based on its content. It prevents scrollbars by expanding vertically as needed,
|
|
14
|
+
* up to a configurable maximum number of visible rows.
|
|
15
|
+
*
|
|
16
|
+
* Features:
|
|
17
|
+
* - Automatically resizes the textarea as the user types
|
|
18
|
+
* - Prevents vertical scrollbars until a maximum row limit is reached
|
|
19
|
+
* - Supports additional height padding
|
|
20
|
+
* - Provides real-time callbacks for input and resize events
|
|
21
|
+
* - Allows manual refresh and cleanup of behavior
|
|
22
|
+
*
|
|
23
|
+
* Ideal for chat inputs, note editors, or any form where dynamic space usage
|
|
24
|
+
* is preferred without relying on scrollbars too early.
|
|
25
|
+
*
|
|
26
|
+
* @class
|
|
27
|
+
* @beta
|
|
28
|
+
*/
|
|
29
|
+
class TinyTextarea {
|
|
30
|
+
#lineHeight;
|
|
31
|
+
#maxRows;
|
|
32
|
+
#extraHeight;
|
|
33
|
+
#lastKnownHeight = 0;
|
|
34
|
+
#lastKnownRows = 0;
|
|
35
|
+
/** @type {HTMLTextAreaElement} */
|
|
36
|
+
#textarea;
|
|
37
|
+
/**
|
|
38
|
+
* @type {((info: OnInputInfo) => void) | null}
|
|
39
|
+
*/
|
|
40
|
+
#onResize = null;
|
|
41
|
+
/**
|
|
42
|
+
* @type {((info: OnInputInfo) => void) | null}
|
|
43
|
+
*/
|
|
44
|
+
#onInput = null;
|
|
45
|
+
/**
|
|
46
|
+
* Returns the computed line height in pixels.
|
|
47
|
+
* @returns {number}
|
|
48
|
+
*/
|
|
49
|
+
get lineHeight() {
|
|
50
|
+
return this.#lineHeight;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns the maximum number of rows allowed.
|
|
54
|
+
* @returns {number}
|
|
55
|
+
*/
|
|
56
|
+
get maxRows() {
|
|
57
|
+
return this.#maxRows - 1;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns the additional height added to the textarea.
|
|
61
|
+
* @returns {number}
|
|
62
|
+
*/
|
|
63
|
+
get extraHeight() {
|
|
64
|
+
return this.#extraHeight;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Returns the most recently applied height.
|
|
68
|
+
* @returns {number}
|
|
69
|
+
*/
|
|
70
|
+
get currentHeight() {
|
|
71
|
+
return this.#lastKnownHeight;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns the most recently calculated row count.
|
|
75
|
+
* @returns {number}
|
|
76
|
+
*/
|
|
77
|
+
get currentRows() {
|
|
78
|
+
return this.#lastKnownRows;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Returns the original textarea element managed by this instance.
|
|
82
|
+
* @returns {HTMLTextAreaElement}
|
|
83
|
+
*/
|
|
84
|
+
get textarea() {
|
|
85
|
+
return this.#textarea;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Creates a new TinyTextarea instance.
|
|
89
|
+
*
|
|
90
|
+
* @param {HTMLTextAreaElement} textarea - The `<textarea>` element to enhance.
|
|
91
|
+
* @param {Object} [options={}] - Optional configuration parameters.
|
|
92
|
+
* @param {number} [options.maxRows] - Maximum number of visible rows before scrolling.
|
|
93
|
+
* @param {number} [options.extraHeight] - Additional pixels to add to final height.
|
|
94
|
+
* @param {(info: OnInputInfo) => void} [options.onResize] - Callback when the number of rows changes.
|
|
95
|
+
* @param {(info: OnInputInfo) => void} [options.onInput] - Callback on every input event.
|
|
96
|
+
* @throws {Error} If `textarea` is not a valid `<textarea>` element.
|
|
97
|
+
* @throws {TypeError} If provided options are of invalid types.
|
|
98
|
+
*/
|
|
99
|
+
constructor(textarea, options = {}) {
|
|
100
|
+
if (!(textarea instanceof HTMLTextAreaElement))
|
|
101
|
+
throw new Error('TinyTextarea: Provided element is not a <textarea>.');
|
|
102
|
+
if (typeof options !== 'object' || options === null)
|
|
103
|
+
throw new TypeError('TinyTextarea: Options must be an object if provided.');
|
|
104
|
+
if ('maxRows' in options && typeof options.maxRows !== 'number')
|
|
105
|
+
throw new TypeError('TinyTextarea: `maxRows` must be a number.');
|
|
106
|
+
if ('extraHeight' in options && typeof options.extraHeight !== 'number')
|
|
107
|
+
throw new TypeError('TinyTextarea: `extraHeight` must be a number.');
|
|
108
|
+
if ('onResize' in options && typeof options.onResize !== 'function')
|
|
109
|
+
throw new TypeError('TinyTextarea: `onResize` must be a function.');
|
|
110
|
+
if ('onInput' in options && typeof options.onInput !== 'function')
|
|
111
|
+
throw new TypeError('TinyTextarea: `onInput` must be a function.');
|
|
112
|
+
this.#textarea = textarea;
|
|
113
|
+
this.#maxRows = (options.maxRows ?? 5) + 1;
|
|
114
|
+
this.#extraHeight = options.extraHeight ?? 0;
|
|
115
|
+
this.#onResize = options.onResize ?? null;
|
|
116
|
+
this.#onInput = options.onInput ?? null;
|
|
117
|
+
this.#lineHeight = this.#getLineHeight();
|
|
118
|
+
textarea.style.overflowY = 'hidden';
|
|
119
|
+
textarea.style.resize = 'none';
|
|
120
|
+
this._handleInput = () => this.#resize();
|
|
121
|
+
textarea.addEventListener('input', this._handleInput);
|
|
122
|
+
this.#resize();
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Automatically resize the textarea based on its content and notify listeners.
|
|
126
|
+
* Triggers `onResize` if the number of rows has changed.
|
|
127
|
+
* Always triggers `onInput`.
|
|
128
|
+
*/
|
|
129
|
+
#resize() {
|
|
130
|
+
this.#textarea.style.height = 'auto';
|
|
131
|
+
const style = window.getComputedStyle(this.#textarea);
|
|
132
|
+
const paddingTop = parseFloat(style.paddingTop) || 0;
|
|
133
|
+
const paddingBottom = parseFloat(style.paddingBottom) || 0;
|
|
134
|
+
const breakLines = (this.#textarea.value.match(/\n/g) || []).length;
|
|
135
|
+
const scrollHeight = this.#textarea.scrollHeight;
|
|
136
|
+
const maxHeight = this.#lineHeight * this.#maxRows;
|
|
137
|
+
const newHeight = Math.ceil(Math.min(scrollHeight, maxHeight) - paddingTop - paddingBottom + this.#extraHeight);
|
|
138
|
+
// const rows = Math.round(newHeight / this.#lineHeight);
|
|
139
|
+
const maxRows = this.#maxRows - 1;
|
|
140
|
+
const rows = breakLines < maxRows ? breakLines + 1 : maxRows;
|
|
141
|
+
this.#textarea.style.height = `${newHeight}px`;
|
|
142
|
+
this.#textarea.style.overflowY = scrollHeight > maxHeight ? 'auto' : 'hidden';
|
|
143
|
+
this.#lastKnownHeight = newHeight;
|
|
144
|
+
const info = {
|
|
145
|
+
breakLines,
|
|
146
|
+
rows,
|
|
147
|
+
height: newHeight,
|
|
148
|
+
scrollHeight,
|
|
149
|
+
maxHeight,
|
|
150
|
+
lineHeight: this.#lineHeight,
|
|
151
|
+
maxRows,
|
|
152
|
+
};
|
|
153
|
+
if (rows !== this.#lastKnownRows) {
|
|
154
|
+
this.#lastKnownRows = rows;
|
|
155
|
+
if (typeof this.#onResize === 'function') {
|
|
156
|
+
this.#onResize({ ...info });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (typeof this.#onInput === 'function') {
|
|
160
|
+
this.#onInput(info);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Computes the current line height from the textarea's computed styles.
|
|
165
|
+
* Falls back to `fontSize * 1.2` if lineHeight is not a number.
|
|
166
|
+
* @returns {number} - The computed line height in pixels.
|
|
167
|
+
*/
|
|
168
|
+
#getLineHeight() {
|
|
169
|
+
const style = window.getComputedStyle(this.#textarea);
|
|
170
|
+
const line = parseFloat(style.lineHeight);
|
|
171
|
+
if (!Number.isNaN(line))
|
|
172
|
+
return line;
|
|
173
|
+
return parseFloat(style.fontSize) * 1.2;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Returns the latest height and row count of the textarea.
|
|
177
|
+
* @returns {{ height: number, rows: number }} - Last known resize state.
|
|
178
|
+
*/
|
|
179
|
+
getData() {
|
|
180
|
+
return {
|
|
181
|
+
rows: this.#lastKnownRows,
|
|
182
|
+
height: this.#lastKnownHeight,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Manually trigger a resize check.
|
|
187
|
+
*/
|
|
188
|
+
refresh() {
|
|
189
|
+
this.#resize();
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Cleans up internal listeners and disables dynamic behavior.
|
|
193
|
+
*/
|
|
194
|
+
destroy() {
|
|
195
|
+
this.#textarea.removeEventListener('input', this._handleInput);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export default TinyTextarea;
|
package/docs/v1/README.md
CHANGED
|
@@ -46,6 +46,7 @@ This folder contains the core scripts we have worked on so far. Each file is a m
|
|
|
46
46
|
- ๐ฆ **[TinyLocalStorage](./libs/TinyLocalStorage.md)** โ A tiny wrapper for `localStorage` with full support for objects, arrays, `Map`, `Set`, and typed value helpers like string, number, and boolean.
|
|
47
47
|
- ๐ผ๏ธ **[TinyIframeEvents](./libs/TinyIframeEvents.md)** โ A structured `postMessage`-based event router for secure and reliable communication between a parent window and its embedded iframe. Supports directional filtering, origin enforcement, payload transport, and listener lifecycle.
|
|
48
48
|
- ๐ช **[TinyNewWinEvents](./libs/TinyNewWinEvents.md)** โ A smart, route-based `postMessage` system for structured communication between a main window and a popup (`window.open`). Includes queueing, origin enforcement, and lifecycle tracking.
|
|
49
|
+
- โจ **[TinyTextarea](./libs/TinyTextarea.md)** โ A minimal auto-expanding `<textarea>` manager with configurable row limits, extra height padding, and real-time resize/input event hooks.
|
|
49
50
|
|
|
50
51
|
### 3. **`fileManager/`**
|
|
51
52
|
* ๐ **[Main](./fileManager/main.md)** โ A Node.js file/directory utility module with support for JSON, backups, renaming, size analysis, and more.
|
|
@@ -442,19 +442,19 @@ Scrolls the target all the way to the top immediately.
|
|
|
442
442
|
|
|
443
443
|
## ๐งญ Scroll Position Status
|
|
444
444
|
|
|
445
|
-
### ๐ `
|
|
445
|
+
### ๐ `isAtCustomBottom()`
|
|
446
446
|
|
|
447
447
|
Returns `true` if the user is within the custom boundary of the bottom.
|
|
448
448
|
|
|
449
|
-
### ๐ `
|
|
449
|
+
### ๐ `isAtCustomTop()`
|
|
450
450
|
|
|
451
451
|
Returns `true` if the user is within the custom boundary of the top.
|
|
452
452
|
|
|
453
|
-
### ๐งจ `
|
|
453
|
+
### ๐งจ `isAtBottom()`
|
|
454
454
|
|
|
455
455
|
Returns `true` if user is currently scrolled to the actual bottom.
|
|
456
456
|
|
|
457
|
-
### ๐งท `
|
|
457
|
+
### ๐งท `isAtTop()`
|
|
458
458
|
|
|
459
459
|
Returns `true` if user is currently scrolled to the actual top.
|
|
460
460
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# โจ `TinyTextarea`
|
|
2
|
+
|
|
3
|
+
A lightweight JavaScript utility for automatically resizing `<textarea>` elements as users type โ without ugly scrollbars!
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ๐ฆ Features
|
|
8
|
+
|
|
9
|
+
* ๐ **Auto-resizing**: Grows or shrinks with the content
|
|
10
|
+
* ๐ซ **No scrollbars** (until limit): Prevents `overflow-y` unless needed
|
|
11
|
+
* ๐ง **Configurable**: Set `maxRows`, `extraHeight`, and hooks
|
|
12
|
+
* ๐ก **Live events**: Hooks for `onInput` and `onResize`
|
|
13
|
+
* ๐งผ **Clean lifecycle**: Includes `.refresh()` and `.destroy()`
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## ๐ Usage
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import TinyTextarea from './TinyTextarea.js';
|
|
21
|
+
|
|
22
|
+
const textarea = document.querySelector('textarea');
|
|
23
|
+
|
|
24
|
+
const autoResize = new TinyTextarea(textarea, {
|
|
25
|
+
maxRows: 8,
|
|
26
|
+
extraHeight: 0,
|
|
27
|
+
onResize: (info) => console.log('Resized:', info),
|
|
28
|
+
onInput: (info) => console.log('Input event:', info),
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
To stop behavior and clean up:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
autoResize.destroy();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ๐ง Constructor
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
new TinyTextarea(textarea, options?);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Parameters
|
|
47
|
+
|
|
48
|
+
| Name | Type | Description |
|
|
49
|
+
| --------------------- | ----------------------------- | ----------------------------------------------------- |
|
|
50
|
+
| `textarea` | `HTMLTextAreaElement` | The `<textarea>` element to be managed. |
|
|
51
|
+
| `options` | `Object` *(optional)* | Configuration options. |
|
|
52
|
+
| `options.maxRows` | `number` | Max number of visible rows before scrollbars appear. |
|
|
53
|
+
| `options.extraHeight` | `number` | Extra height (in px) to add on top of computed value. |
|
|
54
|
+
| `options.onResize` | `(info: OnInputInfo) => void` | Called when number of visible rows changes. |
|
|
55
|
+
| `options.onInput` | `(info: OnInputInfo) => void` | Called on every `input` event. |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## ๐ API
|
|
60
|
+
|
|
61
|
+
### `.getData() โ { height, rows }`
|
|
62
|
+
|
|
63
|
+
Returns the last known height and number of visible rows.
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
const { height, rows } = autoResize.getData();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### `.refresh()`
|
|
72
|
+
|
|
73
|
+
Forces a manual recalculation and resize of the `<textarea>`.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
autoResize.refresh();
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### `.destroy()`
|
|
82
|
+
|
|
83
|
+
Cleans up listeners and disables resizing behavior. Use this if you remove the element or want to stop automatic behavior.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
autoResize.destroy();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### ๐ Getters
|
|
92
|
+
|
|
93
|
+
TinyTextarea exposes several readonly properties to let you inspect the current configuration and state of the managed `<textarea>`.
|
|
94
|
+
|
|
95
|
+
#### ๐ `lineHeight: number`
|
|
96
|
+
|
|
97
|
+
Returns the height in pixels of a single line of text in the textarea, computed from its current CSS styles.
|
|
98
|
+
Useful for calculating exact space usage or aligning UI elements.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
#### ๐ `maxRows: number`
|
|
103
|
+
|
|
104
|
+
Returns the maximum number of visible text rows allowed before the textarea begins to scroll.
|
|
105
|
+
This value reflects the limit set via `options.maxRows`.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
#### โ `extraHeight: number`
|
|
110
|
+
|
|
111
|
+
Returns the number of extra pixels added to the calculated height of the textarea.
|
|
112
|
+
This is useful for custom padding or visual adjustments.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
#### ๐ `currentHeight: number`
|
|
117
|
+
|
|
118
|
+
Returns the most recently applied height (in pixels) that was set on the `<textarea>` after resizing.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
#### ๐ `currentRows: number`
|
|
123
|
+
|
|
124
|
+
Returns the most recent number of visible text rows that the textarea is currently using.
|
|
125
|
+
This value is calculated dynamically and may change as the user types.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
#### ๐งฉ `textarea: HTMLTextAreaElement`
|
|
130
|
+
|
|
131
|
+
Returns the original `<textarea>` DOM element that was enhanced by this instance.
|
|
132
|
+
You can use this for direct styling, value changes, or other DOM-level operations.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## ๐ค Event Payload: `OnInputInfo`
|
|
137
|
+
|
|
138
|
+
Whenever `onResize` or `onInput` is triggered, the following object is passed:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
{
|
|
142
|
+
breakLines: number; // Total number of '\n' in the textarea
|
|
143
|
+
height: number; // Final computed height (px)
|
|
144
|
+
scrollHeight: number; // Natural scrollHeight of textarea
|
|
145
|
+
maxHeight: number; // Max height before scrollbars show
|
|
146
|
+
lineHeight: number; // Height of one line of text
|
|
147
|
+
maxRows: number; // Maximum number of visible rows allowed
|
|
148
|
+
rows: number; // Final calculated number of rows used
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## ๐งช Beta Notice
|
|
155
|
+
|
|
156
|
+
> ๐งช This library is currently marked as `@beta`. The API is stable but may be adjusted slightly during updates.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-essentials",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.3",
|
|
4
4
|
"description": "Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "npm run test:mjs && npm run test:cjs && npm run test:js",
|