tiny-essentials 1.21.10 → 1.22.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 (40) hide show
  1. package/.vscode/extensions.json +30 -0
  2. package/.vscode/settings.json +53 -0
  3. package/LICENSE +160 -669
  4. package/dist/v1/TinyBasicsEs.min.js +1 -1
  5. package/dist/v1/TinyDragger.min.js +1 -1
  6. package/dist/v1/TinyElementObserver.min.js +1 -0
  7. package/dist/v1/TinyEssentials.min.js +1 -1
  8. package/dist/v1/TinyHtml.min.js +1 -1
  9. package/dist/v1/TinySmartScroller.min.js +1 -1
  10. package/dist/v1/TinyUploadClicker.min.js +1 -1
  11. package/dist/v1/basics/array.cjs +12 -0
  12. package/dist/v1/basics/array.d.mts +9 -0
  13. package/dist/v1/basics/array.mjs +10 -0
  14. package/dist/v1/basics/index.cjs +2 -0
  15. package/dist/v1/basics/index.d.mts +3 -1
  16. package/dist/v1/basics/index.mjs +3 -3
  17. package/dist/v1/basics/text.cjs +44 -9
  18. package/dist/v1/basics/text.d.mts +14 -2
  19. package/dist/v1/basics/text.mjs +38 -9
  20. package/dist/v1/build/TinyElementObserver.cjs +7 -0
  21. package/dist/v1/build/TinyElementObserver.d.mts +3 -0
  22. package/dist/v1/build/TinyElementObserver.mjs +2 -0
  23. package/dist/v1/index.cjs +4 -0
  24. package/dist/v1/index.d.mts +4 -1
  25. package/dist/v1/index.mjs +4 -3
  26. package/dist/v1/libs/TinyElementObserver.cjs +292 -0
  27. package/dist/v1/libs/TinyElementObserver.d.mts +154 -0
  28. package/dist/v1/libs/TinyElementObserver.mjs +266 -0
  29. package/dist/v1/libs/TinyGamepad.d.mts +1 -1
  30. package/dist/v1/libs/TinyHtml.cjs +1418 -131
  31. package/dist/v1/libs/TinyHtml.d.mts +513 -12
  32. package/dist/v1/libs/TinyHtml.mjs +1129 -14
  33. package/dist/v1/libs/TinyInventory.d.mts +1 -1
  34. package/dist/v1/libs/UltraRandomMsgGen.d.mts +7 -7
  35. package/docs/v1/README.md +1 -0
  36. package/docs/v1/basics/array.md +20 -0
  37. package/docs/v1/basics/text.md +38 -7
  38. package/docs/v1/libs/TinyElementObserver.md +107 -0
  39. package/docs/v1/libs/TinyHtml.md +797 -3
  40. package/package.json +2 -2
@@ -0,0 +1,292 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Callback type used for element mutation detectors.
5
+ *
6
+ * @callback ElementDetectorsFn
7
+ * @param {MutationRecord} mutation - Single mutation record being processed.
8
+ * @param {number} index - Index of the current mutation in the batch.
9
+ * @param {MutationRecord[]} mutations - Full list of mutation records from the observer callback.
10
+ * @returns {void}
11
+ */
12
+
13
+ /**
14
+ * TinyElementObserver
15
+ *
16
+ * A utility class for tracking DOM element mutations.
17
+ * It leverages the native MutationObserver API, providing a higher-level abstraction
18
+ * with a system of configurable detectors that can dispatch custom events or run custom logic.
19
+ */
20
+ class TinyElementObserver {
21
+ /** @type {Element|undefined} */
22
+ #el;
23
+
24
+ /**
25
+ * Get the current element being observed.
26
+ * @returns {Element|undefined} The DOM element being tracked, or `undefined` if none is set.
27
+ */
28
+ get el() {
29
+ return this.#el;
30
+ }
31
+
32
+ /**
33
+ * Set the target element to be observed.
34
+ * Can only be set once.
35
+ *
36
+ * @param {Element|undefined} el - The DOM element to observe.
37
+ * @throws {Error} If the element is already defined.
38
+ * @throws {TypeError} If the provided value is not an Element.
39
+ */
40
+ set el(el) {
41
+ if (this.#el)
42
+ throw new Error('The observed element has already been set and cannot be reassigned.');
43
+ if (typeof el !== 'undefined' && !(el instanceof Element))
44
+ throw new TypeError('The observed element must be a valid DOM Element.');
45
+ this.#el = el;
46
+ }
47
+
48
+ /**
49
+ * Configuration settings for the MutationObserver instance.
50
+ *
51
+ * @type {MutationObserverInit}
52
+ */
53
+ #settings = {};
54
+
55
+ /**
56
+ * Get the observer settings.
57
+ * @returns {MutationObserverInit}
58
+ */
59
+ get settings() {
60
+ return this.#settings;
61
+ }
62
+
63
+ /**
64
+ * Set the observer settings.
65
+ * @param {MutationObserverInit} settings
66
+ */
67
+ set settings(settings) {
68
+ if (typeof settings !== 'object' || settings === null)
69
+ throw new TypeError('settings must be a non-null object.');
70
+ this.#settings = settings;
71
+ }
72
+
73
+ /**
74
+ * Internal MutationObserver instance that tracks DOM attribute changes.
75
+ * @type {MutationObserver|null}
76
+ */
77
+ #observer = null;
78
+
79
+ /**
80
+ * Get the current MutationObserver instance.
81
+ * @returns {MutationObserver|null}
82
+ */
83
+ get observer() {
84
+ return this.#observer;
85
+ }
86
+
87
+ /**
88
+ * List of detectors executed on observed mutations.
89
+ * Each detector is a tuple:
90
+ * - name: string identifier
91
+ * - handler: function processing MutationRecords
92
+ *
93
+ * @type {Array<[string, ElementDetectorsFn]>}
94
+ */
95
+ #detectors = [];
96
+
97
+ /**
98
+ * Get the element detectors.
99
+ * @returns {Array<[string, ElementDetectorsFn]>}
100
+ */
101
+ get detectors() {
102
+ return this.#detectors.map((item) => [item[0], item[1]]);
103
+ }
104
+
105
+ /**
106
+ * Set the element detectors.
107
+ * @param {Array<[string, ElementDetectorsFn]>} detectors
108
+ */
109
+ set detectors(detectors) {
110
+ if (!Array.isArray(detectors)) throw new TypeError('detectors must be an array.');
111
+
112
+ /** @type {Array<[string, ElementDetectorsFn]>} */
113
+ const values = [];
114
+ for (const [name, fn] of detectors) {
115
+ if (typeof name !== 'string') throw new TypeError('Detector name must be a string.');
116
+ if (typeof fn !== 'function')
117
+ throw new TypeError(`Detector handler for "${name}" must be a function.`);
118
+ values.push([name, fn]);
119
+ }
120
+ this.#detectors = values;
121
+ }
122
+
123
+ /**
124
+ * Returns true if a MutationObserver is currently active.
125
+ * @returns {boolean}
126
+ */
127
+ get isActive() {
128
+ return !!this.#observer;
129
+ }
130
+
131
+ /**
132
+ * Get the number of registered detectors.
133
+ *
134
+ * @returns {number} Total count of detectors.
135
+ */
136
+ get size() {
137
+ return this.#detectors.length;
138
+ }
139
+
140
+ /**
141
+ * Create a new TinyElementObserver instance.
142
+ *
143
+ * @param {Object} [settings={}] - Configuration object.
144
+ * @param {Element} [settings.el] - Optional DOM element to observe from the start.
145
+ * @param {Array<[string, ElementDetectorsFn]>} [settings.initDetectors=[]] - Optional initial detectors to register.
146
+ * @param {MutationObserverInit} [settings.initCfg] - Optional MutationObserver configuration.
147
+ */
148
+ constructor({ el, initDetectors = [], initCfg = {} } = {}) {
149
+ this.el = el;
150
+ if (initDetectors.length) this.detectors = initDetectors;
151
+ if (initCfg) this.settings = initCfg;
152
+ }
153
+
154
+ /**
155
+ * Remove all registered detectors.
156
+ * After calling this, no mutation events will be processed
157
+ * until new detectors are added again.
158
+ */
159
+ clear() {
160
+ this.#detectors = [];
161
+ }
162
+
163
+ /**
164
+ * Start tracking DOM mutations on the defined element.
165
+ *
166
+ * @throws {Error} If no element has been set to observe.
167
+ */
168
+ start() {
169
+ if (!this.#el) throw new Error('Cannot start observation: no target element has been set.');
170
+ if (this.#observer) return;
171
+ this.#observer = new MutationObserver((mutations) => {
172
+ mutations.forEach((value, index, array) =>
173
+ this.#detectors.forEach((item) => item[1](value, index, array)),
174
+ );
175
+ });
176
+
177
+ this.#observer.observe(this.#el, this.#settings);
178
+ }
179
+
180
+ /**
181
+ * Stop tracking changes.
182
+ */
183
+ stop() {
184
+ if (!this.#observer) return;
185
+ this.#observer.disconnect();
186
+ this.#observer = null;
187
+ }
188
+
189
+ // ================= Detectors Editor =================
190
+
191
+ /**
192
+ * Add a detector to the end of the array.
193
+ * @param {string} name
194
+ * @param {ElementDetectorsFn} handler
195
+ */
196
+ add(name, handler) {
197
+ this.#validateDetector(name, handler);
198
+ this.#detectors.push([name, handler]);
199
+ }
200
+
201
+ /**
202
+ * Add a detector to the start of the array.
203
+ * @param {string} name
204
+ * @param {ElementDetectorsFn} handler
205
+ */
206
+ insertAtStart(name, handler) {
207
+ this.#validateDetector(name, handler);
208
+ this.#detectors.unshift([name, handler]);
209
+ }
210
+
211
+ /**
212
+ * Insert a detector at a specific index.
213
+ * @param {number} index
214
+ * @param {string} name
215
+ * @param {ElementDetectorsFn} handler
216
+ * @param {'before'|'after'} position - Position relative to the index
217
+ */
218
+ insertAt(index, name, handler, position = 'after') {
219
+ this.#validateDetector(name, handler);
220
+ if (typeof index !== 'number' || index < 0 || index >= this.#detectors.length)
221
+ throw new RangeError('Invalid index for insertDetectorAt.');
222
+ const insertIndex = position === 'before' ? index : index + 1;
223
+ this.#detectors.splice(insertIndex, 0, [name, handler]);
224
+ }
225
+
226
+ /**
227
+ * Remove a detector at a specific index.
228
+ * @param {number} index
229
+ */
230
+ removeAt(index) {
231
+ if (typeof index !== 'number' || index < 0 || index >= this.#detectors.length)
232
+ throw new RangeError('Invalid index for removeDetectorAt.');
233
+ this.#detectors.splice(index, 1);
234
+ }
235
+
236
+ /**
237
+ * Remove detectors relative to a specific index.
238
+ * @param {number} index - Reference index
239
+ * @param {number} before - Number of items before the index to remove
240
+ * @param {number} after - Number of items after the index to remove
241
+ */
242
+ removeAround(index, before = 0, after = 0) {
243
+ if (typeof index !== 'number' || index < 0 || index >= this.#detectors.length)
244
+ throw new RangeError('Invalid index for removeDetectorsAround.');
245
+ const start = Math.max(0, index - before);
246
+ const deleteCount = before + 1 + after;
247
+ this.#detectors.splice(start, deleteCount);
248
+ }
249
+
250
+ /**
251
+ * Check if a detector exists at a specific index.
252
+ * @param {number} index
253
+ * @returns {boolean}
254
+ */
255
+ isIndexUsed(index) {
256
+ return index >= 0 && index < this.#detectors.length;
257
+ }
258
+
259
+ /**
260
+ * Check if a handler function already exists in the array.
261
+ * @param {ElementDetectorsFn} handler
262
+ * @returns {boolean}
263
+ */
264
+ hasHandler(handler) {
265
+ if (typeof handler !== 'function') throw new TypeError('Handler must be a function.');
266
+ return this.#detectors.some(([_, fn]) => fn === handler);
267
+ }
268
+
269
+ /**
270
+ * Internal validation for detector entries.
271
+ * @param {string} name
272
+ * @param {ElementDetectorsFn} handler
273
+ */
274
+ #validateDetector(name, handler) {
275
+ if (typeof name !== 'string' || !name.trim())
276
+ throw new TypeError('Detector name must be a non-empty string.');
277
+ if (typeof handler !== 'function')
278
+ throw new TypeError(`Detector handler for "${name}" must be a function.`);
279
+ }
280
+
281
+ /**
282
+ * Completely destroy this observer instance.
283
+ * Stops the MutationObserver (if active) and clears all detectors,
284
+ * leaving the instance unusable until reconfigured.
285
+ */
286
+ destroy() {
287
+ this.stop();
288
+ this.clear();
289
+ }
290
+ }
291
+
292
+ module.exports = TinyElementObserver;
@@ -0,0 +1,154 @@
1
+ export default TinyElementObserver;
2
+ /**
3
+ * Callback type used for element mutation detectors.
4
+ */
5
+ export type ElementDetectorsFn = (mutation: MutationRecord, index: number, mutations: MutationRecord[]) => void;
6
+ /**
7
+ * Callback type used for element mutation detectors.
8
+ *
9
+ * @callback ElementDetectorsFn
10
+ * @param {MutationRecord} mutation - Single mutation record being processed.
11
+ * @param {number} index - Index of the current mutation in the batch.
12
+ * @param {MutationRecord[]} mutations - Full list of mutation records from the observer callback.
13
+ * @returns {void}
14
+ */
15
+ /**
16
+ * TinyElementObserver
17
+ *
18
+ * A utility class for tracking DOM element mutations.
19
+ * It leverages the native MutationObserver API, providing a higher-level abstraction
20
+ * with a system of configurable detectors that can dispatch custom events or run custom logic.
21
+ */
22
+ declare class TinyElementObserver {
23
+ /**
24
+ * Create a new TinyElementObserver instance.
25
+ *
26
+ * @param {Object} [settings={}] - Configuration object.
27
+ * @param {Element} [settings.el] - Optional DOM element to observe from the start.
28
+ * @param {Array<[string, ElementDetectorsFn]>} [settings.initDetectors=[]] - Optional initial detectors to register.
29
+ * @param {MutationObserverInit} [settings.initCfg] - Optional MutationObserver configuration.
30
+ */
31
+ constructor({ el, initDetectors, initCfg }?: {
32
+ el?: Element | undefined;
33
+ initDetectors?: [string, ElementDetectorsFn][] | undefined;
34
+ initCfg?: MutationObserverInit | undefined;
35
+ });
36
+ /**
37
+ * Set the target element to be observed.
38
+ * Can only be set once.
39
+ *
40
+ * @param {Element|undefined} el - The DOM element to observe.
41
+ * @throws {Error} If the element is already defined.
42
+ * @throws {TypeError} If the provided value is not an Element.
43
+ */
44
+ set el(el: Element | undefined);
45
+ /**
46
+ * Get the current element being observed.
47
+ * @returns {Element|undefined} The DOM element being tracked, or `undefined` if none is set.
48
+ */
49
+ get el(): Element | undefined;
50
+ /**
51
+ * Set the observer settings.
52
+ * @param {MutationObserverInit} settings
53
+ */
54
+ set settings(settings: MutationObserverInit);
55
+ /**
56
+ * Get the observer settings.
57
+ * @returns {MutationObserverInit}
58
+ */
59
+ get settings(): MutationObserverInit;
60
+ /**
61
+ * Get the current MutationObserver instance.
62
+ * @returns {MutationObserver|null}
63
+ */
64
+ get observer(): MutationObserver | null;
65
+ /**
66
+ * Set the element detectors.
67
+ * @param {Array<[string, ElementDetectorsFn]>} detectors
68
+ */
69
+ set detectors(detectors: Array<[string, ElementDetectorsFn]>);
70
+ /**
71
+ * Get the element detectors.
72
+ * @returns {Array<[string, ElementDetectorsFn]>}
73
+ */
74
+ get detectors(): Array<[string, ElementDetectorsFn]>;
75
+ /**
76
+ * Returns true if a MutationObserver is currently active.
77
+ * @returns {boolean}
78
+ */
79
+ get isActive(): boolean;
80
+ /**
81
+ * Get the number of registered detectors.
82
+ *
83
+ * @returns {number} Total count of detectors.
84
+ */
85
+ get size(): number;
86
+ /**
87
+ * Remove all registered detectors.
88
+ * After calling this, no mutation events will be processed
89
+ * until new detectors are added again.
90
+ */
91
+ clear(): void;
92
+ /**
93
+ * Start tracking DOM mutations on the defined element.
94
+ *
95
+ * @throws {Error} If no element has been set to observe.
96
+ */
97
+ start(): void;
98
+ /**
99
+ * Stop tracking changes.
100
+ */
101
+ stop(): void;
102
+ /**
103
+ * Add a detector to the end of the array.
104
+ * @param {string} name
105
+ * @param {ElementDetectorsFn} handler
106
+ */
107
+ add(name: string, handler: ElementDetectorsFn): void;
108
+ /**
109
+ * Add a detector to the start of the array.
110
+ * @param {string} name
111
+ * @param {ElementDetectorsFn} handler
112
+ */
113
+ insertAtStart(name: string, handler: ElementDetectorsFn): void;
114
+ /**
115
+ * Insert a detector at a specific index.
116
+ * @param {number} index
117
+ * @param {string} name
118
+ * @param {ElementDetectorsFn} handler
119
+ * @param {'before'|'after'} position - Position relative to the index
120
+ */
121
+ insertAt(index: number, name: string, handler: ElementDetectorsFn, position?: "before" | "after"): void;
122
+ /**
123
+ * Remove a detector at a specific index.
124
+ * @param {number} index
125
+ */
126
+ removeAt(index: number): void;
127
+ /**
128
+ * Remove detectors relative to a specific index.
129
+ * @param {number} index - Reference index
130
+ * @param {number} before - Number of items before the index to remove
131
+ * @param {number} after - Number of items after the index to remove
132
+ */
133
+ removeAround(index: number, before?: number, after?: number): void;
134
+ /**
135
+ * Check if a detector exists at a specific index.
136
+ * @param {number} index
137
+ * @returns {boolean}
138
+ */
139
+ isIndexUsed(index: number): boolean;
140
+ /**
141
+ * Check if a handler function already exists in the array.
142
+ * @param {ElementDetectorsFn} handler
143
+ * @returns {boolean}
144
+ */
145
+ hasHandler(handler: ElementDetectorsFn): boolean;
146
+ /**
147
+ * Completely destroy this observer instance.
148
+ * Stops the MutationObserver (if active) and clears all detectors,
149
+ * leaving the instance unusable until reconfigured.
150
+ */
151
+ destroy(): void;
152
+ #private;
153
+ }
154
+ //# sourceMappingURL=TinyElementObserver.d.mts.map
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Callback type used for element mutation detectors.
3
+ *
4
+ * @callback ElementDetectorsFn
5
+ * @param {MutationRecord} mutation - Single mutation record being processed.
6
+ * @param {number} index - Index of the current mutation in the batch.
7
+ * @param {MutationRecord[]} mutations - Full list of mutation records from the observer callback.
8
+ * @returns {void}
9
+ */
10
+ /**
11
+ * TinyElementObserver
12
+ *
13
+ * A utility class for tracking DOM element mutations.
14
+ * It leverages the native MutationObserver API, providing a higher-level abstraction
15
+ * with a system of configurable detectors that can dispatch custom events or run custom logic.
16
+ */
17
+ class TinyElementObserver {
18
+ /** @type {Element|undefined} */
19
+ #el;
20
+ /**
21
+ * Get the current element being observed.
22
+ * @returns {Element|undefined} The DOM element being tracked, or `undefined` if none is set.
23
+ */
24
+ get el() {
25
+ return this.#el;
26
+ }
27
+ /**
28
+ * Set the target element to be observed.
29
+ * Can only be set once.
30
+ *
31
+ * @param {Element|undefined} el - The DOM element to observe.
32
+ * @throws {Error} If the element is already defined.
33
+ * @throws {TypeError} If the provided value is not an Element.
34
+ */
35
+ set el(el) {
36
+ if (this.#el)
37
+ throw new Error('The observed element has already been set and cannot be reassigned.');
38
+ if (typeof el !== 'undefined' && !(el instanceof Element))
39
+ throw new TypeError('The observed element must be a valid DOM Element.');
40
+ this.#el = el;
41
+ }
42
+ /**
43
+ * Configuration settings for the MutationObserver instance.
44
+ *
45
+ * @type {MutationObserverInit}
46
+ */
47
+ #settings = {};
48
+ /**
49
+ * Get the observer settings.
50
+ * @returns {MutationObserverInit}
51
+ */
52
+ get settings() {
53
+ return this.#settings;
54
+ }
55
+ /**
56
+ * Set the observer settings.
57
+ * @param {MutationObserverInit} settings
58
+ */
59
+ set settings(settings) {
60
+ if (typeof settings !== 'object' || settings === null)
61
+ throw new TypeError('settings must be a non-null object.');
62
+ this.#settings = settings;
63
+ }
64
+ /**
65
+ * Internal MutationObserver instance that tracks DOM attribute changes.
66
+ * @type {MutationObserver|null}
67
+ */
68
+ #observer = null;
69
+ /**
70
+ * Get the current MutationObserver instance.
71
+ * @returns {MutationObserver|null}
72
+ */
73
+ get observer() {
74
+ return this.#observer;
75
+ }
76
+ /**
77
+ * List of detectors executed on observed mutations.
78
+ * Each detector is a tuple:
79
+ * - name: string identifier
80
+ * - handler: function processing MutationRecords
81
+ *
82
+ * @type {Array<[string, ElementDetectorsFn]>}
83
+ */
84
+ #detectors = [];
85
+ /**
86
+ * Get the element detectors.
87
+ * @returns {Array<[string, ElementDetectorsFn]>}
88
+ */
89
+ get detectors() {
90
+ return this.#detectors.map((item) => [item[0], item[1]]);
91
+ }
92
+ /**
93
+ * Set the element detectors.
94
+ * @param {Array<[string, ElementDetectorsFn]>} detectors
95
+ */
96
+ set detectors(detectors) {
97
+ if (!Array.isArray(detectors))
98
+ throw new TypeError('detectors must be an array.');
99
+ /** @type {Array<[string, ElementDetectorsFn]>} */
100
+ const values = [];
101
+ for (const [name, fn] of detectors) {
102
+ if (typeof name !== 'string')
103
+ throw new TypeError('Detector name must be a string.');
104
+ if (typeof fn !== 'function')
105
+ throw new TypeError(`Detector handler for "${name}" must be a function.`);
106
+ values.push([name, fn]);
107
+ }
108
+ this.#detectors = values;
109
+ }
110
+ /**
111
+ * Returns true if a MutationObserver is currently active.
112
+ * @returns {boolean}
113
+ */
114
+ get isActive() {
115
+ return !!this.#observer;
116
+ }
117
+ /**
118
+ * Get the number of registered detectors.
119
+ *
120
+ * @returns {number} Total count of detectors.
121
+ */
122
+ get size() {
123
+ return this.#detectors.length;
124
+ }
125
+ /**
126
+ * Create a new TinyElementObserver instance.
127
+ *
128
+ * @param {Object} [settings={}] - Configuration object.
129
+ * @param {Element} [settings.el] - Optional DOM element to observe from the start.
130
+ * @param {Array<[string, ElementDetectorsFn]>} [settings.initDetectors=[]] - Optional initial detectors to register.
131
+ * @param {MutationObserverInit} [settings.initCfg] - Optional MutationObserver configuration.
132
+ */
133
+ constructor({ el, initDetectors = [], initCfg = {} } = {}) {
134
+ this.el = el;
135
+ if (initDetectors.length)
136
+ this.detectors = initDetectors;
137
+ if (initCfg)
138
+ this.settings = initCfg;
139
+ }
140
+ /**
141
+ * Remove all registered detectors.
142
+ * After calling this, no mutation events will be processed
143
+ * until new detectors are added again.
144
+ */
145
+ clear() {
146
+ this.#detectors = [];
147
+ }
148
+ /**
149
+ * Start tracking DOM mutations on the defined element.
150
+ *
151
+ * @throws {Error} If no element has been set to observe.
152
+ */
153
+ start() {
154
+ if (!this.#el)
155
+ throw new Error('Cannot start observation: no target element has been set.');
156
+ if (this.#observer)
157
+ return;
158
+ this.#observer = new MutationObserver((mutations) => {
159
+ mutations.forEach((value, index, array) => this.#detectors.forEach((item) => item[1](value, index, array)));
160
+ });
161
+ this.#observer.observe(this.#el, this.#settings);
162
+ }
163
+ /**
164
+ * Stop tracking changes.
165
+ */
166
+ stop() {
167
+ if (!this.#observer)
168
+ return;
169
+ this.#observer.disconnect();
170
+ this.#observer = null;
171
+ }
172
+ // ================= Detectors Editor =================
173
+ /**
174
+ * Add a detector to the end of the array.
175
+ * @param {string} name
176
+ * @param {ElementDetectorsFn} handler
177
+ */
178
+ add(name, handler) {
179
+ this.#validateDetector(name, handler);
180
+ this.#detectors.push([name, handler]);
181
+ }
182
+ /**
183
+ * Add a detector to the start of the array.
184
+ * @param {string} name
185
+ * @param {ElementDetectorsFn} handler
186
+ */
187
+ insertAtStart(name, handler) {
188
+ this.#validateDetector(name, handler);
189
+ this.#detectors.unshift([name, handler]);
190
+ }
191
+ /**
192
+ * Insert a detector at a specific index.
193
+ * @param {number} index
194
+ * @param {string} name
195
+ * @param {ElementDetectorsFn} handler
196
+ * @param {'before'|'after'} position - Position relative to the index
197
+ */
198
+ insertAt(index, name, handler, position = 'after') {
199
+ this.#validateDetector(name, handler);
200
+ if (typeof index !== 'number' || index < 0 || index >= this.#detectors.length)
201
+ throw new RangeError('Invalid index for insertDetectorAt.');
202
+ const insertIndex = position === 'before' ? index : index + 1;
203
+ this.#detectors.splice(insertIndex, 0, [name, handler]);
204
+ }
205
+ /**
206
+ * Remove a detector at a specific index.
207
+ * @param {number} index
208
+ */
209
+ removeAt(index) {
210
+ if (typeof index !== 'number' || index < 0 || index >= this.#detectors.length)
211
+ throw new RangeError('Invalid index for removeDetectorAt.');
212
+ this.#detectors.splice(index, 1);
213
+ }
214
+ /**
215
+ * Remove detectors relative to a specific index.
216
+ * @param {number} index - Reference index
217
+ * @param {number} before - Number of items before the index to remove
218
+ * @param {number} after - Number of items after the index to remove
219
+ */
220
+ removeAround(index, before = 0, after = 0) {
221
+ if (typeof index !== 'number' || index < 0 || index >= this.#detectors.length)
222
+ throw new RangeError('Invalid index for removeDetectorsAround.');
223
+ const start = Math.max(0, index - before);
224
+ const deleteCount = before + 1 + after;
225
+ this.#detectors.splice(start, deleteCount);
226
+ }
227
+ /**
228
+ * Check if a detector exists at a specific index.
229
+ * @param {number} index
230
+ * @returns {boolean}
231
+ */
232
+ isIndexUsed(index) {
233
+ return index >= 0 && index < this.#detectors.length;
234
+ }
235
+ /**
236
+ * Check if a handler function already exists in the array.
237
+ * @param {ElementDetectorsFn} handler
238
+ * @returns {boolean}
239
+ */
240
+ hasHandler(handler) {
241
+ if (typeof handler !== 'function')
242
+ throw new TypeError('Handler must be a function.');
243
+ return this.#detectors.some(([_, fn]) => fn === handler);
244
+ }
245
+ /**
246
+ * Internal validation for detector entries.
247
+ * @param {string} name
248
+ * @param {ElementDetectorsFn} handler
249
+ */
250
+ #validateDetector(name, handler) {
251
+ if (typeof name !== 'string' || !name.trim())
252
+ throw new TypeError('Detector name must be a non-empty string.');
253
+ if (typeof handler !== 'function')
254
+ throw new TypeError(`Detector handler for "${name}" must be a function.`);
255
+ }
256
+ /**
257
+ * Completely destroy this observer instance.
258
+ * Stops the MutationObserver (if active) and clears all detectors,
259
+ * leaving the instance unusable until reconfigured.
260
+ */
261
+ destroy() {
262
+ this.stop();
263
+ this.clear();
264
+ }
265
+ }
266
+ export default TinyElementObserver;