tiny-essentials 1.13.1 β†’ 1.13.2

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.
@@ -252,11 +252,112 @@ const getHtmlElPadding = (el) => {
252
252
  return { x, y, left, right, top, bottom };
253
253
  };
254
254
 
255
+ /**
256
+ * Installs a script that toggles CSS classes on a given element
257
+ * based on the page's visibility or focus state.
258
+ *
259
+ * @param {Object} [settings={}]
260
+ * @param {HTMLElement} [settings.element=document.body] - The element to receive visibility classes.
261
+ * @param {string} [settings.hiddenClass='windowHidden'] - CSS class applied when the page is hidden.
262
+ * @param {string} [settings.visibleClass='windowVisible'] - CSS class applied when the page is visible.
263
+ * @returns {() => void} Function that removes all installed event listeners.
264
+ */
265
+ function installWindowHiddenScript({
266
+ element = document.body,
267
+ hiddenClass = 'windowHidden',
268
+ visibleClass = 'windowVisible',
269
+ } = {}) {
270
+ const removeClass = () => {
271
+ element.classList.remove(hiddenClass);
272
+ element.classList.remove(visibleClass);
273
+ };
274
+
275
+ /** @type {string|null} */
276
+ let hiddenProp = null;
277
+ /** @type {(this: any, evt: Event) => void} */
278
+ let handler;
279
+
280
+ const visibilityEvents = [
281
+ 'visibilitychange',
282
+ 'mozvisibilitychange',
283
+ 'webkitvisibilitychange',
284
+ 'msvisibilitychange',
285
+ ];
286
+
287
+ const visibilityProps = ['hidden', 'mozHidden', 'webkitHidden', 'msHidden'];
288
+
289
+ for (let i = 0; i < visibilityProps.length; i++) {
290
+ if (visibilityProps[i] in document) {
291
+ hiddenProp = visibilityProps[i];
292
+ break;
293
+ }
294
+ }
295
+
296
+ handler = function (evt) {
297
+ removeClass();
298
+
299
+ const type = evt?.type;
300
+ // @ts-ignore
301
+ const isHidden = hiddenProp && document[hiddenProp];
302
+
303
+ const visibleEvents = ['focus', 'focusin', 'pageshow'];
304
+ const hiddenEvents = ['blur', 'focusout', 'pagehide'];
305
+
306
+ if (visibleEvents.includes(type)) {
307
+ element.classList.add(visibleClass);
308
+ } else if (hiddenEvents.includes(type)) {
309
+ element.classList.add(hiddenClass);
310
+ } else {
311
+ element.classList.add(isHidden ? hiddenClass : visibleClass);
312
+ }
313
+ };
314
+
315
+ /** @type {() => void} */
316
+ let uninstall = () => {};
317
+
318
+ if (hiddenProp) {
319
+ const eventType = visibilityEvents[visibilityProps.indexOf(hiddenProp)];
320
+ document.addEventListener(eventType, handler);
321
+ window.addEventListener('focus', handler);
322
+ window.addEventListener('blur', handler);
323
+
324
+ uninstall = () => {
325
+ document.removeEventListener(eventType, handler);
326
+ window.removeEventListener('focus', handler);
327
+ window.removeEventListener('blur', handler);
328
+ removeClass();
329
+ };
330
+ } else if ('onfocusin' in document) {
331
+ // Fallback for IE9 and older
332
+ // @ts-ignore
333
+ document.onfocusin = document.onfocusout = handler;
334
+ uninstall = () => {
335
+ // @ts-ignore
336
+ document.onfocusin = document.onfocusout = null;
337
+ removeClass();
338
+ };
339
+ } else {
340
+ // Last resort fallback
341
+ window.onpageshow = window.onpagehide = window.onfocus = window.onblur = handler;
342
+ uninstall = () => {
343
+ window.onpageshow = window.onpagehide = window.onfocus = window.onblur = null;
344
+ removeClass();
345
+ };
346
+ }
347
+
348
+ // @ts-ignore
349
+ const simulatedEvent = new Event(hiddenProp && document[hiddenProp] ? 'blur' : 'focus');
350
+ handler(simulatedEvent);
351
+
352
+ return uninstall;
353
+ }
354
+
255
355
  exports.areHtmlElsColliding = areHtmlElsColliding;
256
356
  exports.fetchJson = fetchJson;
257
357
  exports.getHtmlElBorders = getHtmlElBorders;
258
358
  exports.getHtmlElBordersWidth = getHtmlElBordersWidth;
259
359
  exports.getHtmlElMargin = getHtmlElMargin;
260
360
  exports.getHtmlElPadding = getHtmlElPadding;
361
+ exports.installWindowHiddenScript = installWindowHiddenScript;
261
362
  exports.readJsonBlob = readJsonBlob;
262
363
  exports.saveJsonFile = saveJsonFile;
@@ -42,6 +42,21 @@ export function fetchJson(url: string, { method, body, timeout, retries, headers
42
42
  headers?: Headers | Record<string, any> | undefined;
43
43
  signal?: AbortSignal | null | undefined;
44
44
  }): Promise<any>;
45
+ /**
46
+ * Installs a script that toggles CSS classes on a given element
47
+ * based on the page's visibility or focus state.
48
+ *
49
+ * @param {Object} [settings={}]
50
+ * @param {HTMLElement} [settings.element=document.body] - The element to receive visibility classes.
51
+ * @param {string} [settings.hiddenClass='windowHidden'] - CSS class applied when the page is hidden.
52
+ * @param {string} [settings.visibleClass='windowVisible'] - CSS class applied when the page is visible.
53
+ * @returns {() => void} Function that removes all installed event listeners.
54
+ */
55
+ export function installWindowHiddenScript({ element, hiddenClass, visibleClass, }?: {
56
+ element?: HTMLElement | undefined;
57
+ hiddenClass?: string | undefined;
58
+ visibleClass?: string | undefined;
59
+ }): () => void;
45
60
  export function getHtmlElBordersWidth(el: Element): HtmlElBoxSides;
46
61
  export function getHtmlElBorders(el: Element): HtmlElBoxSides;
47
62
  export function getHtmlElMargin(el: Element): HtmlElBoxSides;
@@ -206,3 +206,89 @@ export const getHtmlElPadding = (el) => {
206
206
  const y = top + bottom;
207
207
  return { x, y, left, right, top, bottom };
208
208
  };
209
+ /**
210
+ * Installs a script that toggles CSS classes on a given element
211
+ * based on the page's visibility or focus state.
212
+ *
213
+ * @param {Object} [settings={}]
214
+ * @param {HTMLElement} [settings.element=document.body] - The element to receive visibility classes.
215
+ * @param {string} [settings.hiddenClass='windowHidden'] - CSS class applied when the page is hidden.
216
+ * @param {string} [settings.visibleClass='windowVisible'] - CSS class applied when the page is visible.
217
+ * @returns {() => void} Function that removes all installed event listeners.
218
+ */
219
+ export function installWindowHiddenScript({ element = document.body, hiddenClass = 'windowHidden', visibleClass = 'windowVisible', } = {}) {
220
+ const removeClass = () => {
221
+ element.classList.remove(hiddenClass);
222
+ element.classList.remove(visibleClass);
223
+ };
224
+ /** @type {string|null} */
225
+ let hiddenProp = null;
226
+ /** @type {(this: any, evt: Event) => void} */
227
+ let handler;
228
+ const visibilityEvents = [
229
+ 'visibilitychange',
230
+ 'mozvisibilitychange',
231
+ 'webkitvisibilitychange',
232
+ 'msvisibilitychange',
233
+ ];
234
+ const visibilityProps = ['hidden', 'mozHidden', 'webkitHidden', 'msHidden'];
235
+ for (let i = 0; i < visibilityProps.length; i++) {
236
+ if (visibilityProps[i] in document) {
237
+ hiddenProp = visibilityProps[i];
238
+ break;
239
+ }
240
+ }
241
+ handler = function (evt) {
242
+ removeClass();
243
+ const type = evt?.type;
244
+ // @ts-ignore
245
+ const isHidden = hiddenProp && document[hiddenProp];
246
+ const visibleEvents = ['focus', 'focusin', 'pageshow'];
247
+ const hiddenEvents = ['blur', 'focusout', 'pagehide'];
248
+ if (visibleEvents.includes(type)) {
249
+ element.classList.add(visibleClass);
250
+ }
251
+ else if (hiddenEvents.includes(type)) {
252
+ element.classList.add(hiddenClass);
253
+ }
254
+ else {
255
+ element.classList.add(isHidden ? hiddenClass : visibleClass);
256
+ }
257
+ };
258
+ /** @type {() => void} */
259
+ let uninstall = () => { };
260
+ if (hiddenProp) {
261
+ const eventType = visibilityEvents[visibilityProps.indexOf(hiddenProp)];
262
+ document.addEventListener(eventType, handler);
263
+ window.addEventListener('focus', handler);
264
+ window.addEventListener('blur', handler);
265
+ uninstall = () => {
266
+ document.removeEventListener(eventType, handler);
267
+ window.removeEventListener('focus', handler);
268
+ window.removeEventListener('blur', handler);
269
+ removeClass();
270
+ };
271
+ }
272
+ else if ('onfocusin' in document) {
273
+ // Fallback for IE9 and older
274
+ // @ts-ignore
275
+ document.onfocusin = document.onfocusout = handler;
276
+ uninstall = () => {
277
+ // @ts-ignore
278
+ document.onfocusin = document.onfocusout = null;
279
+ removeClass();
280
+ };
281
+ }
282
+ else {
283
+ // Last resort fallback
284
+ window.onpageshow = window.onpagehide = window.onfocus = window.onblur = handler;
285
+ uninstall = () => {
286
+ window.onpageshow = window.onpagehide = window.onfocus = window.onblur = null;
287
+ removeClass();
288
+ };
289
+ }
290
+ // @ts-ignore
291
+ const simulatedEvent = new Event(hiddenProp && document[hiddenProp] ? 'blur' : 'focus');
292
+ handler(simulatedEvent);
293
+ return uninstall;
294
+ }
@@ -25,6 +25,7 @@ exports.getHtmlElBorders = html.getHtmlElBorders;
25
25
  exports.getHtmlElBordersWidth = html.getHtmlElBordersWidth;
26
26
  exports.getHtmlElMargin = html.getHtmlElMargin;
27
27
  exports.getHtmlElPadding = html.getHtmlElPadding;
28
+ exports.installWindowHiddenScript = html.installWindowHiddenScript;
28
29
  exports.readJsonBlob = html.readJsonBlob;
29
30
  exports.saveJsonFile = html.saveJsonFile;
30
31
  exports.cloneObjTypeOrder = objFilter.cloneObjTypeOrder;
@@ -1,3 +1,4 @@
1
+ import { installWindowHiddenScript } from './html.mjs';
1
2
  import { genFibonacciSeq } from './simpleMath.mjs';
2
3
  import { getHtmlElBorders } from './html.mjs';
3
4
  import { getHtmlElBordersWidth } from './html.mjs';
@@ -34,5 +35,5 @@ import { getTimeDuration } from './clock.mjs';
34
35
  import { shuffleArray } from './array.mjs';
35
36
  import { toTitleCase } from './text.mjs';
36
37
  import { toTitleCaseLowerFirst } from './text.mjs';
37
- export { genFibonacciSeq, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, fetchJson, readJsonBlob, saveJsonFile, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, areHtmlElsColliding, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst };
38
+ export { installWindowHiddenScript, genFibonacciSeq, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, fetchJson, readJsonBlob, saveJsonFile, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, areHtmlElsColliding, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst };
38
39
  //# sourceMappingURL=index.d.mts.map
@@ -2,9 +2,9 @@ import arraySortPositions from '../../legacy/libs/arraySortPositions.mjs';
2
2
  import asyncReplace from '../../legacy/libs/replaceAsync.mjs';
3
3
  import { shuffleArray } from './array.mjs';
4
4
  import { formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration } from './clock.mjs';
5
- import { areHtmlElsColliding, readJsonBlob, saveJsonFile, fetchJson, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, } from './html.mjs';
5
+ import { areHtmlElsColliding, readJsonBlob, saveJsonFile, fetchJson, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, installWindowHiddenScript, } from './html.mjs';
6
6
  import { countObj, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, objType, isJsonObject, } from './objFilter.mjs';
7
7
  import { documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, } from './fullScreen.mjs';
8
8
  import { formatBytes, genFibonacciSeq, getAge, getSimplePerc, ruleOfThree } from './simpleMath.mjs';
9
9
  import { addAiMarkerShortcut, toTitleCase, toTitleCaseLowerFirst } from './text.mjs';
10
- export { genFibonacciSeq, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, fetchJson, readJsonBlob, saveJsonFile, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, areHtmlElsColliding, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
10
+ export { installWindowHiddenScript, genFibonacciSeq, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, fetchJson, readJsonBlob, saveJsonFile, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, areHtmlElsColliding, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
package/dist/v1/index.cjs CHANGED
@@ -64,6 +64,7 @@ exports.getHtmlElBorders = html.getHtmlElBorders;
64
64
  exports.getHtmlElBordersWidth = html.getHtmlElBordersWidth;
65
65
  exports.getHtmlElMargin = html.getHtmlElMargin;
66
66
  exports.getHtmlElPadding = html.getHtmlElPadding;
67
+ exports.installWindowHiddenScript = html.installWindowHiddenScript;
67
68
  exports.readJsonBlob = html.readJsonBlob;
68
69
  exports.saveJsonFile = html.saveJsonFile;
69
70
  exports.TinyDragDropDetector = TinyDragDropDetector;
@@ -7,6 +7,7 @@ import TinyRateLimiter from './libs/TinyRateLimiter.mjs';
7
7
  import ColorSafeStringify from './libs/ColorSafeStringify.mjs';
8
8
  import TinyPromiseQueue from './libs/TinyPromiseQueue.mjs';
9
9
  import TinyLevelUp from '../legacy/libs/userLevel.mjs';
10
+ import { installWindowHiddenScript } from './basics/html.mjs';
10
11
  import { genFibonacciSeq } from './basics/simpleMath.mjs';
11
12
  import { isDirEmptyAsync } from './fileManager/asyncFuncs.mjs';
12
13
  import { fileSizeAsync } from './fileManager/asyncFuncs.mjs';
@@ -72,5 +73,5 @@ import { getTimeDuration } from './basics/clock.mjs';
72
73
  import { shuffleArray } from './basics/array.mjs';
73
74
  import { toTitleCase } from './basics/text.mjs';
74
75
  import { toTitleCaseLowerFirst } from './basics/text.mjs';
75
- export { TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, getLatestBackupPath, fetchJson, readJsonBlob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, areHtmlElsColliding, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst };
76
+ export { TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, getLatestBackupPath, fetchJson, readJsonBlob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, areHtmlElsColliding, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst };
76
77
  //# sourceMappingURL=index.d.mts.map
package/dist/v1/index.mjs CHANGED
@@ -12,10 +12,10 @@ import TinyPromiseQueue from './libs/TinyPromiseQueue.mjs';
12
12
  import TinyRateLimiter from './libs/TinyRateLimiter.mjs';
13
13
  import TinyNotifyCenter from './libs/TinyNotifyCenter.mjs';
14
14
  import TinyToastNotify from './libs/TinyToastNotify.mjs';
15
- import { areHtmlElsColliding, readJsonBlob, saveJsonFile, fetchJson, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, } from './basics/html.mjs';
15
+ import { areHtmlElsColliding, readJsonBlob, saveJsonFile, fetchJson, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, installWindowHiddenScript, } from './basics/html.mjs';
16
16
  import TinyDragDropDetector from './libs/TinyDragDropDetector.mjs';
17
17
  import { readJsonFile, writeJsonFile, ensureDirectory, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, getLatestBackupPath, } from './fileManager/normalFuncs.mjs';
18
18
  import { listFilesAsync, listDirsAsync, clearDirectoryAsync, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, } from './fileManager/asyncFuncs.mjs';
19
19
  import TinyDragger from './libs/TinyDragger.mjs';
20
20
  import TinyDomReadyManager from './libs/TinyDomReadyManager.mjs';
21
- export { TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, getLatestBackupPath, fetchJson, readJsonBlob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, areHtmlElsColliding, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
21
+ export { TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getHtmlElBorders, getHtmlElBordersWidth, getHtmlElMargin, getHtmlElPadding, getLatestBackupPath, fetchJson, readJsonBlob, saveJsonFile, readJsonFile, writeJsonFile, ensureDirectory, clearDirectoryAsync, clearDirectory, fileExists, dirExists, isDirEmpty, ensureCopyFile, tryDeleteFile, writeTextFile, listFiles, listDirs, fileSize, dirSize, backupFile, restoreLatestBackup, renameFileBatch, renameFileRegex, renameFileAddPrefixSuffix, renameFileNormalizeCase, renameFilePadNumbers, documentIsFullScreen, isScreenFilled, requestFullScreen, exitFullScreen, isFullScreenMode, onFullScreenChange, offFullScreenChange, areHtmlElsColliding, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
@@ -1,4 +1,4 @@
1
- ## πŸš€ `areHtmlElsColliding()`
1
+ ### πŸš€ `areHtmlElsColliding()`
2
2
 
3
3
  Check if two DOM elements are **colliding on the screen**! Perfect for games, draggable elements, UI interactions, and more.
4
4
 
@@ -13,7 +13,7 @@ It compares the bounding rectangles of both elements:
13
13
 
14
14
  ---
15
15
 
16
- ## 🧠 Syntax
16
+ #### 🧠 Syntax
17
17
 
18
18
  ```javascript
19
19
  areHtmlElsColliding(elem1, elem2);
@@ -21,7 +21,7 @@ areHtmlElsColliding(elem1, elem2);
21
21
 
22
22
  ---
23
23
 
24
- ## 🎯 Parameters
24
+ #### 🎯 Parameters
25
25
 
26
26
  | Parameter | Type | Description |
27
27
  | --------- | --------- | ----------------------- |
@@ -30,7 +30,7 @@ areHtmlElsColliding(elem1, elem2);
30
30
 
31
31
  ---
32
32
 
33
- ## πŸ” Return
33
+ #### πŸ” Return
34
34
 
35
35
  | Type | Description |
36
36
  | --------- | ------------------------------------------------------------------ |
@@ -38,7 +38,7 @@ areHtmlElsColliding(elem1, elem2);
38
38
 
39
39
  ---
40
40
 
41
- ## πŸ“¦ Example
41
+ #### πŸ“¦ Example
42
42
 
43
43
  ```javascript
44
44
  const box1 = document.getElementById('box1');
@@ -53,31 +53,31 @@ if (areHtmlElsColliding(box1, box2)) {
53
53
 
54
54
  ---
55
55
 
56
- ## 🚧 Limitations
56
+ #### 🚧 Limitations
57
57
 
58
58
  * Only works with **axis-aligned elements** (rectangular shapes).
59
59
  * Does not handle rotated elements or complex shapes.
60
60
 
61
61
  ---
62
62
 
63
- ## πŸ“– `readJsonBlob(file: File): Promise<any>`
63
+ ### πŸ“– `readJsonBlob(file: File): Promise<any>`
64
64
 
65
65
  Reads and parses a JSON file using the [`FileReader`](https://developer.mozilla.org/en-US/docs/Web/API/FileReader) API.
66
66
 
67
- ### πŸ“₯ Parameters
67
+ #### πŸ“₯ Parameters
68
68
 
69
69
  * `file` *(File)*: The file object selected by the user (e.g., from an `<input type="file">` element).
70
70
 
71
- ### πŸ“€ Returns
71
+ #### πŸ“€ Returns
72
72
 
73
73
  * `Promise<any>`: Resolves with the parsed JSON object, or rejects with an error if the content is invalid.
74
74
 
75
- ### ⚠️ Throws
75
+ #### ⚠️ Throws
76
76
 
77
77
  * An error if the content is not valid JSON.
78
78
  * An error if the file can't be read.
79
79
 
80
- ### πŸ§ͺ Example
80
+ #### πŸ§ͺ Example
81
81
 
82
82
  ```js
83
83
  const input = document.querySelector('input[type="file"]');
@@ -93,36 +93,36 @@ input.addEventListener('change', async () => {
93
93
 
94
94
  ---
95
95
 
96
- ## πŸ’Ύ `saveJsonFile(filename: string, data: any, spaces: number = 2): void`
96
+ ### πŸ’Ύ `saveJsonFile(filename: string, data: any, spaces: number = 2): void`
97
97
 
98
98
  Converts a JavaScript object to JSON and triggers a download in the browser.
99
99
 
100
- ### πŸ“₯ Parameters
100
+ #### πŸ“₯ Parameters
101
101
 
102
102
  * `filename` *(string)*: The name of the file to save (e.g., `"data.json"`).
103
103
  * `data` *(any)*: The JavaScript object to convert to JSON.
104
104
  * `spaces` *(number)* *(optional)*: Indentation level for formatting the JSON string. Default is `2`.
105
105
 
106
- ### πŸ“€ Returns
106
+ #### πŸ“€ Returns
107
107
 
108
108
  * `void`
109
109
 
110
- ### πŸ“‚ Behavior
110
+ #### πŸ“‚ Behavior
111
111
 
112
112
  Creates a temporary `<a>` element, downloads the file, and cleans up the URL.
113
113
 
114
- ### πŸ§ͺ Example
114
+ #### πŸ§ͺ Example
115
115
 
116
116
  ```js
117
117
  const data = { name: 'Yasmin', type: 'dev' };
118
118
  saveJsonFile('yasmin.json', data);
119
119
  ```
120
120
 
121
- ## 🌐 `fetchJson(url, options?): Promise<any>`
121
+ ### 🌐 `fetchJson(url, options?): Promise<any>`
122
122
 
123
123
  Loads and parses a JSON from a remote URL using the Fetch API, with support for custom HTTP methods, retries, timeouts, headers, and even external abort controllers.
124
124
 
125
- ### πŸ“₯ Parameters
125
+ #### πŸ“₯ Parameters
126
126
 
127
127
  * `url` *(string)*: The full URL to fetch JSON from (must start with `http://`, `https://`, `/`, `./`, or `../`).
128
128
  * `options` *(object)* *(optional)*:
@@ -134,7 +134,7 @@ Loads and parses a JSON from a remote URL using the Fetch API, with support for
134
134
  * `headers` *(object)*: Additional headers to include in the request.
135
135
  * `body` *(object)*: Request body. If the value is a plain object, it will be automatically stringified as JSON.
136
136
 
137
- #### `signal` (`AbortSignal` | `null`) β€” *optional*
137
+ ##### `signal` (`AbortSignal` | `null`) β€” *optional*
138
138
 
139
139
  Custom abort signal. If set:
140
140
 
@@ -142,21 +142,21 @@ Custom abort signal. If set:
142
142
  * Retry logic is **disabled**
143
143
  * Abortion is handled externally
144
144
 
145
- ### πŸ“€ Returns
145
+ #### πŸ“€ Returns
146
146
 
147
147
  * `Promise<any>`: Resolves with the parsed JSON data.
148
148
 
149
- ### ⚠️ Throws
149
+ #### ⚠️ Throws
150
150
 
151
151
  * `Error` if the fetch fails or exceeds the timeout
152
152
  * `Error` if the response is not `application/json`
153
153
  * `Error` if the result is not a plain JSON object
154
154
 
155
- ## 🧠 Tip
155
+ #### 🧠 Tip
156
156
 
157
157
  If you pass your own `signal`, this disables both `timeout` and `retries`. Use it when you're managing cancellation manually (e.g. in UI components or async workflows).
158
158
 
159
- ### πŸ§ͺ Example
159
+ #### πŸ§ͺ Example
160
160
 
161
161
  ```js
162
162
  const controller = new AbortController();
@@ -241,3 +241,106 @@ getHtmlElPadding(el: Element): HtmlElBoxSides
241
241
 
242
242
  * `el`: The target DOM element.
243
243
  * **Returns**: Padding values for all sides and summed horizontal (`x`) and vertical (`y`) values.
244
+
245
+ ---
246
+
247
+ ### πŸ“„ `installWindowHiddenScript`
248
+
249
+ Automatically toggles CSS classes on a given element based on the browser window or tab **visibility** and **focus** state.
250
+
251
+ Perfect for UI states like dimming, pausing animations, or showing "away" statuses.
252
+
253
+ ---
254
+
255
+ #### 🧠 Features
256
+
257
+ * βœ… Adds or removes custom CSS classes depending on page visibility or focus
258
+ * βœ… Supports modern and legacy browsers (including IE9)
259
+ * βœ… Automatically dispatches an initial state check on load
260
+ * βœ… Returns a cleanup function to remove all listeners
261
+
262
+ ---
263
+
264
+ #### πŸ§ͺ Usage
265
+
266
+ ```js
267
+ import { installWindowHiddenScript } from 'tiny-essentials';
268
+
269
+ const uninstall = installWindowHiddenScript({
270
+ element: document.getElementById('app'),
271
+ hiddenClass: 'is-hidden',
272
+ visibleClass: 'is-visible',
273
+ });
274
+
275
+ // To remove all listeners later
276
+ uninstall();
277
+ ```
278
+
279
+ ---
280
+
281
+ #### βš™οΈ Options
282
+
283
+ | Option | Type | Default | Description |
284
+ | -------------- | ------------- | ----------------- | ----------------------------------------------------------------- |
285
+ | `element` | `HTMLElement` | `document.body` | The element to which the visibility classes will be applied |
286
+ | `hiddenClass` | `string` | `'windowHidden'` | Class name to apply when the window is **not visible or blurred** |
287
+ | `visibleClass` | `string` | `'windowVisible'` | Class name to apply when the window is **visible or focused** |
288
+
289
+ ---
290
+
291
+ #### πŸ”„ Return Value
292
+
293
+ ```ts
294
+ () => void
295
+ ```
296
+
297
+ Returns a function that, when called, will:
298
+
299
+ * 🧹 Remove all attached event listeners
300
+ * ❌ Remove both visibility classes from the target element
301
+
302
+ ---
303
+
304
+ #### 🚦 Events Supported
305
+
306
+ The script handles multiple events depending on browser support:
307
+
308
+ * `visibilitychange`, `webkitvisibilitychange`, `mozvisibilitychange`, `msvisibilitychange`
309
+ * `focus`, `blur`, `focusin`, `focusout`
310
+ * `pageshow`, `pagehide`
311
+ * IE fallback: `onfocusin`, `onfocusout`
312
+
313
+ ---
314
+
315
+ #### πŸ” Initial Trigger
316
+
317
+ Immediately after installation, the script simulates a `focus` or `blur` event based on the current visibility state to **ensure the classes are applied from the start**.
318
+
319
+ ---
320
+
321
+ #### 🧯 Uninstalling
322
+
323
+ Don’t forget to call the returned function if you dynamically load/unload components or scripts:
324
+
325
+ ```js
326
+ const stopWatching = installWindowHiddenScript(...);
327
+ stopWatching(); // later
328
+ ```
329
+
330
+ ---
331
+
332
+ #### 🎨 CSS Example
333
+
334
+ ```css
335
+ .windowVisible {
336
+ opacity: 1;
337
+ pointer-events: auto;
338
+ transition: opacity 0.3s ease;
339
+ }
340
+
341
+ .windowHidden {
342
+ opacity: 0.4;
343
+ pointer-events: none;
344
+ transition: opacity 0.3s ease;
345
+ }
346
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-essentials",
3
- "version": "1.13.1",
3
+ "version": "1.13.2",
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",