tiny-essentials 1.22.15 → 1.23.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.
@@ -0,0 +1 @@
1
+ (()=>{"use strict";var e={d:(t,s)=>{for(var n in s)e.o(s,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:s[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{TinyLoadingScreen:()=>s});const s=class{#e=null;get overlay(){return this.#e}#t=null;get messageElement(){return this.#t}#s;get container(){return this.#s}#n={fadeIn:null,fadeOut:null,zIndex:9999};get options(){return{...this.#n}}set options(e){if("object"!=typeof e||null===e)throw new TypeError("options must be an object");if(void 0!==e.fadeIn&&null!==e.fadeIn&&("number"!=typeof e.fadeIn||e.fadeIn<0))throw new TypeError("fadeIn must be a non-negative number or null");if(void 0!==e.fadeOut&&null!==e.fadeOut&&("number"!=typeof e.fadeOut||e.fadeOut<0))throw new TypeError("fadeOut must be a non-negative number or null");if(void 0!==e.zIndex&&("number"!=typeof e.zIndex||!Number.isInteger(e.zIndex)))throw new TypeError("zIndex must be an integer number");this.#n={fadeIn:e.fadeIn??null,fadeOut:e.fadeOut??null,zIndex:e.zIndex??9999}}#a="none";get status(){return this.#a}#i="";get defaultMessage(){return this.#i}set defaultMessage(e){if("string"!=typeof e&&!(e instanceof HTMLElement))throw new TypeError("defaultMessage must be a string or an HTMLElement");this.#i=e}#o=null;get message(){return this.#o}#l=!1;get allowHtmlText(){return this.#l}set allowHtmlText(e){if("boolean"!=typeof e)throw new TypeError("allowHtmlText must be a boolean");this.#l=e}#r=null;get fadeInTimeout(){return null!==this.#r}#u=null;get fadeOutTimeout(){return null!==this.#u}get visible(){return!!this.#e}#d=null;get onChange(){return this.#d}set onChange(e){if(null!==e&&"function"!=typeof e)throw new TypeError("onChange must be a function or null");this.#d=e}_emitChange(){"function"==typeof this.#d&&this.#d(this.#a)}constructor(e=document.body){if(!(e instanceof HTMLElement))throw new TypeError("container must be an HTMLElement");this.#s=e}_updateMessage(e=this.#i){if(!this.#t)throw new Error("messageElement is not initialized");if("string"!=typeof e&&!(e instanceof HTMLElement))throw new TypeError("message must be a string or an HTMLElement");if(this.#o=e,"string"==typeof e)this.#l?this.#t.innerHTML=e:this.#t.textContent=e;else{if(!this.#l)throw new Error("HTMLElement messages require allowHtmlText = true");this.#t.textContent="",this.#t.appendChild(e)}}_removeOldClasses(){this.#e?.classList.remove("active"),this.#e?.classList.remove("fadeIn"),this.#e?.classList.remove("fadeOut")}start(e=this.#i){if("string"!=typeof e&&!(e instanceof HTMLElement))throw new TypeError("message must be a string or an HTMLElement");if(!this.#e){this.#e=document.createElement("div"),this.#e.classList.add("loading-overlay"),this.#e.style.zIndex=String(this.#n.zIndex);const t=document.createElement("div");t.classList.add("loading-container");const s=document.createElement("div");s.classList.add("loading-content");const n=document.createElement("div");n.classList.add("loading-spinner"),this.#t=document.createElement("div"),this.#t.classList.add("loading-message"),s.appendChild(n),s.appendChild(this.#t),t.appendChild(s),this.#e.appendChild(t),this.#s.appendChild(this.#e),this._removeOldClasses(),this.#a="fadeIn",this.#e.classList.add("fadeIn"),this._emitChange();const a=()=>{this._removeOldClasses(),this.#r=null,this.#a="active",this.#e?.classList.add("active"),this._emitChange()};return"number"==typeof this.#n.fadeIn?(this.#r&&clearTimeout(this.#r),this.#r=setTimeout(a,this.#n.fadeIn)):a(),this._updateMessage(e),!0}return this.#t&&this._updateMessage(e),!1}update(e=this.#i){if("string"!=typeof e&&!(e instanceof HTMLElement))throw new TypeError("message must be a string or an HTMLElement");return!!this.#t&&(this._updateMessage(e),!0)}stop(){if(this.#e){this._removeOldClasses(),this.#a="fadeOut",this.#e.classList.add("fadeOut"),this._emitChange();const e=()=>{this._removeOldClasses(),this.#u=null,this.#a="none",this.#e?.remove(),this.#e=null,this.#t=null,this.#o=null,this._emitChange()};return"number"==typeof this.#n.fadeOut?(this.#u&&clearTimeout(this.#u),this.#u=setTimeout(e,this.#n.fadeOut)):e(),!0}return!1}};window.TinyLoadingScreen=t.TinyLoadingScreen})();
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ var TinyLoadingScreen = require('../libs/TinyLoadingScreen.cjs');
4
+
5
+
6
+
7
+ exports.TinyLoadingScreen = TinyLoadingScreen;
@@ -0,0 +1,3 @@
1
+ export { TinyLoadingScreen };
2
+ import TinyLoadingScreen from '../libs/TinyLoadingScreen.mjs';
3
+ //# sourceMappingURL=TinyLoadingScreen.d.mts.map
@@ -0,0 +1,2 @@
1
+ import TinyLoadingScreen from '../libs/TinyLoadingScreen.mjs';
2
+ export { TinyLoadingScreen };
@@ -0,0 +1 @@
1
+ .loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.6);display:absolute;justify-content:center;align-items:center;z-index:9999}.loading-overlay .loading-container{height:100%;width:100%;display:flex;align-items:center}.loading-overlay .loading-content{text-align:center;color:#fff;font-family:Arial,sans-serif;margin:auto}.loading-overlay .loading-spinner{position:relative;border:4px solid hsla(0,0%,100%,.3);border-top:4px solid #fff;border-radius:50%;width:50px;height:50px;margin:0 auto 15px;animation:spin 1s linear infinite}.loading-overlay .loading-spinner::after{content:"";position:absolute;top:50%;left:50%;width:20px;height:20px;transform:translate(-50%, -50%);border-radius:50%;background:rgba(0,0,0,0);pointer-events:none}.loading-overlay .loading-message{font-size:1.2em}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
package/dist/v1/index.cjs CHANGED
@@ -47,6 +47,7 @@ var TinyI18 = require('./libs/TinyI18.cjs');
47
47
  var TinyNeedBar = require('./libs/TinyNeedBar.cjs');
48
48
  var TinySimpleDice = require('./libs/TinySimpleDice.cjs');
49
49
  var TinyElementObserver = require('./libs/TinyElementObserver.cjs');
50
+ var TinyLoadingScreen = require('./libs/TinyLoadingScreen.cjs');
50
51
 
51
52
 
52
53
 
@@ -173,3 +174,4 @@ exports.TinyI18 = TinyI18;
173
174
  exports.TinyNeedBar = TinyNeedBar;
174
175
  exports.TinySimpleDice = TinySimpleDice;
175
176
  exports.TinyElementObserver = TinyElementObserver;
177
+ exports.TinyLoadingScreen = TinyLoadingScreen;
@@ -1,3 +1,4 @@
1
+ import TinyLoadingScreen from './libs/TinyLoadingScreen.mjs';
1
2
  import TinyElementObserver from './libs/TinyElementObserver.mjs';
2
3
  import TinySimpleDice from './libs/TinySimpleDice.mjs';
3
4
  import TinyNeedBar from './libs/TinyNeedBar.mjs';
@@ -121,5 +122,5 @@ import { getTimeDuration } from './basics/clock.mjs';
121
122
  import { shuffleArray } from './basics/array.mjs';
122
123
  import { toTitleCase } from './basics/text.mjs';
123
124
  import { toTitleCaseLowerFirst } from './basics/text.mjs';
124
- export { TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyEvents, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, diffArrayList, diffStrings, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, 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, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst };
125
+ export { TinyLoadingScreen, TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyEvents, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, diffArrayList, diffStrings, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, 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, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst };
125
126
  //# sourceMappingURL=index.d.mts.map
package/dist/v1/index.mjs CHANGED
@@ -45,4 +45,5 @@ import TinyI18 from './libs/TinyI18.mjs';
45
45
  import TinyNeedBar from './libs/TinyNeedBar.mjs';
46
46
  import TinySimpleDice from './libs/TinySimpleDice.mjs';
47
47
  import TinyElementObserver from './libs/TinyElementObserver.mjs';
48
- export { TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyEvents, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, diffArrayList, diffStrings, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, 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, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
48
+ import TinyLoadingScreen from './libs/TinyLoadingScreen.mjs';
49
+ export { TinyLoadingScreen, TinyElementObserver, TinySimpleDice, TinyNeedBar, TinyI18, TinyCookieConsent, TinyInventory, TinyInventoryTrader, TinyArrayPaginator, TinyAdvancedRaffle, TinyDayNightCycle, TinyGamepad, TinyTextarea, TinyNewWinEvents, TinyIframeEvents, TinyLocalStorage, TinyEvents, TinyTimeout, TinyColorConverter, TinyClipboard, TinyTextRangeEditor, TinySmartScroller, UltraRandomMsgGen, TinyAfterScrollWatcher, TinyHtml, TinyNotifications, TinyDomReadyManager, TinyDragger, TinyDragDropDetector, TinyToastNotify, TinyNotifyCenter, TinyRateLimiter, ColorSafeStringify, TinyPromiseQueue, TinyLevelUp, diffArrayList, diffStrings, breakdownDuration, calculateMarketcap, compareMarketcap, getPercentage, areElsCollTop, areElsCollBottom, areElsCollLeft, areElsCollRight, areElsCollPerfTop, areElsCollPerfBottom, areElsCollPerfLeft, areElsCollPerfRight, areElsColliding, areElsPerfColliding, getElsColliding, getElsPerfColliding, getElsCollOverlap, getElsCollOverlapPos, getRectCenter, getElsRelativeCenterOffset, getElsCollDirDepth, getElsCollDetails, safeTextTrim, installWindowHiddenScript, genFibonacciSeq, isDirEmptyAsync, fileSizeAsync, dirSizeAsync, listFilesAsync, listDirsAsync, getLatestBackupPath, fetchJson, fetchText, readJsonBlob, readFileBlob, readBase64Blob, 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, isJsonObject, arraySortPositions, formatBytes, addAiMarkerShortcut, extendObjType, reorderObjTypeOrder, cloneObjTypeOrder, countObj, checkObj, objType, ruleOfThree, getSimplePerc, asyncReplace, getAge, formatCustomTimer, formatDayTimer, formatTimer, getTimeDuration, shuffleArray, toTitleCase, toTitleCaseLowerFirst, };
@@ -3738,19 +3738,19 @@ class TinyHtml {
3738
3738
  /** @type {string} */
3739
3739
  #mainDisplay = '';
3740
3740
 
3741
- /**
3742
- * Gets the current display value.
3743
- * @returns {string}
3744
- */
3741
+ /**
3742
+ * Gets the current display value.
3743
+ * @returns {string}
3744
+ */
3745
3745
  get mainDisplay() {
3746
3746
  return this.#mainDisplay;
3747
3747
  }
3748
3748
 
3749
- /**
3750
- * Sets the display value.
3751
- * @param {string} value
3752
- * @throws {TypeError} If the value is not a string.
3753
- */
3749
+ /**
3750
+ * Sets the display value.
3751
+ * @param {string} value
3752
+ * @throws {TypeError} If the value is not a string.
3753
+ */
3754
3754
  set mainDisplay(value) {
3755
3755
  if (typeof value !== 'string') throw new TypeError('mainDisplay must be a string.');
3756
3756
  this.#mainDisplay = value;
@@ -3759,19 +3759,19 @@ class TinyHtml {
3759
3759
  /** @type {string} */
3760
3760
  static #defaultDisplay = 'block';
3761
3761
 
3762
- /**
3763
- * Gets the default display value.
3764
- * @returns {string}
3765
- */
3762
+ /**
3763
+ * Gets the default display value.
3764
+ * @returns {string}
3765
+ */
3766
3766
  static get defaultDisplay() {
3767
3767
  return TinyHtml.#defaultDisplay;
3768
3768
  }
3769
3769
 
3770
- /**
3771
- * Sets the default display value.
3772
- * @param {string} value
3773
- * @throws {TypeError} If the value is not a string.
3774
- */
3770
+ /**
3771
+ * Sets the default display value.
3772
+ * @param {string} value
3773
+ * @throws {TypeError} If the value is not a string.
3774
+ */
3775
3775
  static set defaultDisplay(value) {
3776
3776
  if (typeof value !== 'string') throw new TypeError('defaultDisplay must be a string.');
3777
3777
  TinyHtml.#defaultDisplay = value;
@@ -0,0 +1,365 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Represents the possible states of the loading screen.
5
+ * - `'none'` → Not visible
6
+ * - `'fadeIn'` → Appearing with fade-in animation
7
+ * - `'active'` → Fully visible and active
8
+ * - `'fadeOut'` → Disappearing with fade-out animation
9
+ * @typedef {'none'|'active'|'fadeIn'|'fadeOut'} LoadingStatus
10
+ */
11
+
12
+ /**
13
+ * Configuration options for the loading screen.
14
+ * @typedef {Object} LoadingSettings
15
+ * @property {number|null} fadeIn - Duration of fade-in animation in milliseconds, or `null` to disable.
16
+ * @property {number|null} fadeOut - Duration of fade-out animation in milliseconds, or `null` to disable.
17
+ * @property {number} zIndex - CSS z-index of the overlay element.
18
+ */
19
+
20
+ /**
21
+ * TinyLoadingScreen
22
+ *
23
+ * A lightweight, fully-configurable loading overlay component that can be appended to any HTMLElement.
24
+ *
25
+ * Key features:
26
+ * - Configurable fadeIn/fadeOut durations (milliseconds) and zIndex.
27
+ * - Accepts string or HTMLElement messages.
28
+ * - Optionally allows HTML inside string messages when `allowHtmlText` is enabled.
29
+ * - Exposes `overlay`, `messageElement`, `status`, `options` and helpers for testing and integration.
30
+ *
31
+ * @class
32
+ */
33
+ class TinyLoadingScreen {
34
+ /** @type {HTMLDivElement|null} Overlay container element */
35
+ #overlay = null;
36
+
37
+ /** @returns {HTMLDivElement|null} The overlay element if active, otherwise `null`. */
38
+ get overlay() {
39
+ return this.#overlay;
40
+ }
41
+
42
+ /** @type {HTMLDivElement|null} Element containing the loading message */
43
+ #messageElement = null;
44
+
45
+ /** @returns {HTMLDivElement|null} The element used to render the message, or `null` if inactive. */
46
+ get messageElement() {
47
+ return this.#messageElement;
48
+ }
49
+
50
+ /** @type {HTMLElement} Container where the overlay will be attached */
51
+ #container;
52
+
53
+ /** @returns {HTMLElement} The container element that holds the overlay. */
54
+ get container() {
55
+ return this.#container;
56
+ }
57
+
58
+ /** @type {LoadingSettings} Internal configuration */
59
+ #options = { fadeIn: null, fadeOut: null, zIndex: 9999 };
60
+
61
+ /** @returns {LoadingSettings} A copy of the current configuration options. */
62
+ get options() {
63
+ return { ...this.#options };
64
+ }
65
+
66
+ /**
67
+ * Updates the loading screen options.
68
+ * @param {Partial<LoadingSettings>} value - New configuration values.
69
+ * @throws {TypeError} If any option has an invalid type or value.
70
+ */
71
+ set options(value) {
72
+ if (typeof value !== 'object' || value === null)
73
+ throw new TypeError('options must be an object');
74
+ if (
75
+ typeof value.fadeIn !== 'undefined' &&
76
+ value.fadeIn !== null &&
77
+ (typeof value.fadeIn !== 'number' || value.fadeIn < 0)
78
+ )
79
+ throw new TypeError('fadeIn must be a non-negative number or null');
80
+ if (
81
+ typeof value.fadeOut !== 'undefined' &&
82
+ value.fadeOut !== null &&
83
+ (typeof value.fadeOut !== 'number' || value.fadeOut < 0)
84
+ )
85
+ throw new TypeError('fadeOut must be a non-negative number or null');
86
+ if (
87
+ typeof value.zIndex !== 'undefined' &&
88
+ (typeof value.zIndex !== 'number' || !Number.isInteger(value.zIndex))
89
+ )
90
+ throw new TypeError('zIndex must be an integer number');
91
+
92
+ this.#options = {
93
+ fadeIn: value.fadeIn ?? null,
94
+ fadeOut: value.fadeOut ?? null,
95
+ zIndex: value.zIndex ?? 9999,
96
+ };
97
+ }
98
+
99
+ /** @type {LoadingStatus} Current status of the loading screen */
100
+ #status = 'none';
101
+
102
+ /** @returns {LoadingStatus} The current loading screen status. */
103
+ get status() {
104
+ return this.#status;
105
+ }
106
+
107
+ /** @type {string|HTMLElement} Default message shown when no custom message is provided */
108
+ #defaultMessage = '';
109
+
110
+ /** @returns {string|HTMLElement} The default message. */
111
+ get defaultMessage() {
112
+ return this.#defaultMessage;
113
+ }
114
+
115
+ /**
116
+ * @param {string|HTMLElement} value - New default message.
117
+ * @throws {TypeError} If the value is neither a string nor an HTMLElement.
118
+ */
119
+ set defaultMessage(value) {
120
+ if (typeof value !== 'string' && !(value instanceof HTMLElement))
121
+ throw new TypeError('defaultMessage must be a string or an HTMLElement');
122
+ this.#defaultMessage = value;
123
+ }
124
+
125
+ /** @type {string|HTMLElement|null} Current active message */
126
+ #message = null;
127
+
128
+ /** @returns {string|HTMLElement|null} The currently displayed message. */
129
+ get message() {
130
+ return this.#message;
131
+ }
132
+
133
+ /** @type {boolean} Whether HTML is allowed in string messages */
134
+ #allowHtmlText = false;
135
+
136
+ /** @returns {boolean} True if HTML is allowed inside string messages. */
137
+ get allowHtmlText() {
138
+ return this.#allowHtmlText;
139
+ }
140
+
141
+ /**
142
+ * Enables or disables HTML rendering in string messages.
143
+ * @param {boolean} value - Whether to allow HTML.
144
+ * @throws {TypeError} If value is not a boolean.
145
+ */
146
+ set allowHtmlText(value) {
147
+ if (typeof value !== 'boolean') throw new TypeError('allowHtmlText must be a boolean');
148
+ this.#allowHtmlText = value;
149
+ }
150
+
151
+ /** @type {NodeJS.Timeout|null} Timeout handler for fadeIn */
152
+ #fadeInTimeout = null;
153
+
154
+ /** @returns {boolean} Whether a fadeIn timeout is currently pending. */
155
+ get fadeInTimeout() {
156
+ return this.#fadeInTimeout !== null;
157
+ }
158
+
159
+ /** @type {NodeJS.Timeout|null} Timeout handler for fadeOut */
160
+ #fadeOutTimeout = null;
161
+
162
+ /** @returns {boolean} Whether a fadeOut timeout is currently pending. */
163
+ get fadeOutTimeout() {
164
+ return this.#fadeOutTimeout !== null;
165
+ }
166
+
167
+ /** @returns {boolean} True if the overlay is currently visible. */
168
+ get visible() {
169
+ return !!this.#overlay;
170
+ }
171
+
172
+ /**
173
+ * Optional callback fired whenever the loading screen status changes.
174
+ * @type {((status: LoadingStatus) => void) | null}
175
+ */
176
+ #onChange = null;
177
+
178
+ /**
179
+ * Returns the current status-change callback.
180
+ * @returns {((status: LoadingStatus) => void) | null}
181
+ */
182
+ get onChange() {
183
+ return this.#onChange;
184
+ }
185
+
186
+ /**
187
+ * Sets the status-change callback.
188
+ * @param {((status: LoadingStatus) => void) | null} value
189
+ * @throws {TypeError} If value is neither a function nor null.
190
+ */
191
+ set onChange(value) {
192
+ if (value !== null && typeof value !== 'function') {
193
+ throw new TypeError('onChange must be a function or null');
194
+ }
195
+ this.#onChange = value;
196
+ }
197
+
198
+ /**
199
+ * Internal helper to emit the onChange callback.
200
+ * @private
201
+ */
202
+ _emitChange() {
203
+ if (typeof this.#onChange === 'function') this.#onChange(this.#status);
204
+ }
205
+
206
+ /**
207
+ * Creates a new TinyLoadingScreen instance.
208
+ * @param {HTMLElement} [container=document.body] - The container element where the overlay should be appended.
209
+ * @throws {TypeError} If container is not an HTMLElement.
210
+ */
211
+ constructor(container = document.body) {
212
+ if (!(container instanceof HTMLElement))
213
+ throw new TypeError('container must be an HTMLElement');
214
+ this.#container = container;
215
+ }
216
+
217
+ /**
218
+ * Internal helper to update the displayed message.
219
+ * @param {string|HTMLElement} [message=this.#defaultMessage] - The new message.
220
+ * @throws {TypeError} If the message is not a string or HTMLElement.
221
+ * @throws {Error} If trying to use HTMLElement without allowHtmlText enabled.
222
+ * @private
223
+ */
224
+ _updateMessage(message = this.#defaultMessage) {
225
+ if (!this.#messageElement) throw new Error('messageElement is not initialized');
226
+ if (typeof message !== 'string' && !(message instanceof HTMLElement))
227
+ throw new TypeError('message must be a string or an HTMLElement');
228
+
229
+ this.#message = message;
230
+
231
+ if (typeof message === 'string') {
232
+ if (!this.#allowHtmlText) this.#messageElement.textContent = message;
233
+ else this.#messageElement.innerHTML = message;
234
+ } else {
235
+ if (!this.#allowHtmlText)
236
+ throw new Error('HTMLElement messages require allowHtmlText = true');
237
+ this.#messageElement.textContent = '';
238
+ this.#messageElement.appendChild(message);
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Removes all status-related CSS classes (`active`, `fadeIn`, `fadeOut`)
244
+ * from the overlay element, if it exists.
245
+ *
246
+ * @private
247
+ * @returns {void}
248
+ */
249
+ _removeOldClasses() {
250
+ this.#overlay?.classList.remove('active');
251
+ this.#overlay?.classList.remove('fadeIn');
252
+ this.#overlay?.classList.remove('fadeOut');
253
+ }
254
+
255
+ /**
256
+ * Starts the loading screen or updates its message if already active.
257
+ * @param {string|HTMLElement} [message=this.#defaultMessage] - Message to display.
258
+ * @returns {boolean} `true` if the overlay was created, `false` if only the message was updated.
259
+ * @throws {TypeError} If message is not a string or HTMLElement.
260
+ */
261
+ start(message = this.#defaultMessage) {
262
+ if (typeof message !== 'string' && !(message instanceof HTMLElement))
263
+ throw new TypeError('message must be a string or an HTMLElement');
264
+
265
+ if (!this.#overlay) {
266
+ this.#overlay = document.createElement('div');
267
+ this.#overlay.classList.add('loading-overlay');
268
+ this.#overlay.style.zIndex = String(this.#options.zIndex);
269
+
270
+ const contentBase = document.createElement('div');
271
+ contentBase.classList.add('loading-container');
272
+
273
+ const content = document.createElement('div');
274
+ content.classList.add('loading-content');
275
+
276
+ const spinner = document.createElement('div');
277
+ spinner.classList.add('loading-spinner');
278
+
279
+ this.#messageElement = document.createElement('div');
280
+ this.#messageElement.classList.add('loading-message');
281
+
282
+ content.appendChild(spinner);
283
+ content.appendChild(this.#messageElement);
284
+ contentBase.appendChild(content);
285
+ this.#overlay.appendChild(contentBase);
286
+ this.#container.appendChild(this.#overlay);
287
+
288
+ // trigger fade in
289
+ this._removeOldClasses();
290
+ this.#status = 'fadeIn';
291
+ this.#overlay.classList.add('fadeIn');
292
+ this._emitChange();
293
+ const fadeIn = () => {
294
+ this._removeOldClasses();
295
+ this.#fadeInTimeout = null;
296
+ this.#status = 'active';
297
+ this.#overlay?.classList.add('active');
298
+ this._emitChange();
299
+ };
300
+
301
+ if (typeof this.#options.fadeIn === 'number') {
302
+ if (this.#fadeInTimeout) clearTimeout(this.#fadeInTimeout);
303
+ this.#fadeInTimeout = setTimeout(fadeIn, this.#options.fadeIn);
304
+ } else fadeIn();
305
+
306
+ this._updateMessage(message);
307
+ return true;
308
+ }
309
+
310
+ if (this.#messageElement) this._updateMessage(message);
311
+ return false;
312
+ }
313
+
314
+ /**
315
+ * Updates the loading screen with a new message.
316
+ * @param {string|HTMLElement} [message=this.#defaultMessage] - The new message.
317
+ * @returns {boolean} `true` if the message was updated, `false` if overlay is not active.
318
+ * @throws {TypeError} If message is not a string or HTMLElement.
319
+ */
320
+ update(message = this.#defaultMessage) {
321
+ if (typeof message !== 'string' && !(message instanceof HTMLElement))
322
+ throw new TypeError('message must be a string or an HTMLElement');
323
+
324
+ if (this.#messageElement) {
325
+ this._updateMessage(message);
326
+ return true;
327
+ }
328
+ return false;
329
+ }
330
+
331
+ /**
332
+ * Stops and removes the loading screen.
333
+ * @returns {boolean} `true` if the overlay was removed, `false` if not active.
334
+ */
335
+ stop() {
336
+ if (this.#overlay) {
337
+ this._removeOldClasses();
338
+ this.#status = 'fadeOut';
339
+ this.#overlay.classList.add('fadeOut');
340
+ this._emitChange();
341
+
342
+ // trigger fade out
343
+ const fadeOut = () => {
344
+ this._removeOldClasses();
345
+ this.#fadeOutTimeout = null;
346
+ this.#status = 'none';
347
+ this.#overlay?.remove();
348
+ this.#overlay = null;
349
+ this.#messageElement = null;
350
+ this.#message = null;
351
+ this._emitChange();
352
+ };
353
+
354
+ if (typeof this.#options.fadeOut === 'number') {
355
+ if (this.#fadeOutTimeout) clearTimeout(this.#fadeOutTimeout);
356
+ this.#fadeOutTimeout = setTimeout(fadeOut, this.#options.fadeOut);
357
+ } else fadeOut();
358
+
359
+ return true;
360
+ }
361
+ return false;
362
+ }
363
+ }
364
+
365
+ module.exports = TinyLoadingScreen;
@@ -0,0 +1,154 @@
1
+ export default TinyLoadingScreen;
2
+ /**
3
+ * Represents the possible states of the loading screen.
4
+ * - `'none'` → Not visible
5
+ * - `'fadeIn'` → Appearing with fade-in animation
6
+ * - `'active'` → Fully visible and active
7
+ * - `'fadeOut'` → Disappearing with fade-out animation
8
+ */
9
+ export type LoadingStatus = "none" | "active" | "fadeIn" | "fadeOut";
10
+ /**
11
+ * Configuration options for the loading screen.
12
+ */
13
+ export type LoadingSettings = {
14
+ /**
15
+ * - Duration of fade-in animation in milliseconds, or `null` to disable.
16
+ */
17
+ fadeIn: number | null;
18
+ /**
19
+ * - Duration of fade-out animation in milliseconds, or `null` to disable.
20
+ */
21
+ fadeOut: number | null;
22
+ /**
23
+ * - CSS z-index of the overlay element.
24
+ */
25
+ zIndex: number;
26
+ };
27
+ /**
28
+ * Represents the possible states of the loading screen.
29
+ * - `'none'` → Not visible
30
+ * - `'fadeIn'` → Appearing with fade-in animation
31
+ * - `'active'` → Fully visible and active
32
+ * - `'fadeOut'` → Disappearing with fade-out animation
33
+ * @typedef {'none'|'active'|'fadeIn'|'fadeOut'} LoadingStatus
34
+ */
35
+ /**
36
+ * Configuration options for the loading screen.
37
+ * @typedef {Object} LoadingSettings
38
+ * @property {number|null} fadeIn - Duration of fade-in animation in milliseconds, or `null` to disable.
39
+ * @property {number|null} fadeOut - Duration of fade-out animation in milliseconds, or `null` to disable.
40
+ * @property {number} zIndex - CSS z-index of the overlay element.
41
+ */
42
+ /**
43
+ * TinyLoadingScreen
44
+ *
45
+ * A lightweight, fully-configurable loading overlay component that can be appended to any HTMLElement.
46
+ *
47
+ * Key features:
48
+ * - Configurable fadeIn/fadeOut durations (milliseconds) and zIndex.
49
+ * - Accepts string or HTMLElement messages.
50
+ * - Optionally allows HTML inside string messages when `allowHtmlText` is enabled.
51
+ * - Exposes `overlay`, `messageElement`, `status`, `options` and helpers for testing and integration.
52
+ *
53
+ * @class
54
+ */
55
+ declare class TinyLoadingScreen {
56
+ /**
57
+ * Creates a new TinyLoadingScreen instance.
58
+ * @param {HTMLElement} [container=document.body] - The container element where the overlay should be appended.
59
+ * @throws {TypeError} If container is not an HTMLElement.
60
+ */
61
+ constructor(container?: HTMLElement);
62
+ /** @returns {HTMLDivElement|null} The overlay element if active, otherwise `null`. */
63
+ get overlay(): HTMLDivElement | null;
64
+ /** @returns {HTMLDivElement|null} The element used to render the message, or `null` if inactive. */
65
+ get messageElement(): HTMLDivElement | null;
66
+ /** @returns {HTMLElement} The container element that holds the overlay. */
67
+ get container(): HTMLElement;
68
+ /**
69
+ * Updates the loading screen options.
70
+ * @param {Partial<LoadingSettings>} value - New configuration values.
71
+ * @throws {TypeError} If any option has an invalid type or value.
72
+ */
73
+ set options(value: Partial<LoadingSettings>);
74
+ /** @returns {LoadingSettings} A copy of the current configuration options. */
75
+ get options(): LoadingSettings;
76
+ /** @returns {LoadingStatus} The current loading screen status. */
77
+ get status(): LoadingStatus;
78
+ /**
79
+ * @param {string|HTMLElement} value - New default message.
80
+ * @throws {TypeError} If the value is neither a string nor an HTMLElement.
81
+ */
82
+ set defaultMessage(value: string | HTMLElement);
83
+ /** @returns {string|HTMLElement} The default message. */
84
+ get defaultMessage(): string | HTMLElement;
85
+ /** @returns {string|HTMLElement|null} The currently displayed message. */
86
+ get message(): string | HTMLElement | null;
87
+ /**
88
+ * Enables or disables HTML rendering in string messages.
89
+ * @param {boolean} value - Whether to allow HTML.
90
+ * @throws {TypeError} If value is not a boolean.
91
+ */
92
+ set allowHtmlText(value: boolean);
93
+ /** @returns {boolean} True if HTML is allowed inside string messages. */
94
+ get allowHtmlText(): boolean;
95
+ /** @returns {boolean} Whether a fadeIn timeout is currently pending. */
96
+ get fadeInTimeout(): boolean;
97
+ /** @returns {boolean} Whether a fadeOut timeout is currently pending. */
98
+ get fadeOutTimeout(): boolean;
99
+ /** @returns {boolean} True if the overlay is currently visible. */
100
+ get visible(): boolean;
101
+ /**
102
+ * Sets the status-change callback.
103
+ * @param {((status: LoadingStatus) => void) | null} value
104
+ * @throws {TypeError} If value is neither a function nor null.
105
+ */
106
+ set onChange(value: ((status: LoadingStatus) => void) | null);
107
+ /**
108
+ * Returns the current status-change callback.
109
+ * @returns {((status: LoadingStatus) => void) | null}
110
+ */
111
+ get onChange(): ((status: LoadingStatus) => void) | null;
112
+ /**
113
+ * Internal helper to emit the onChange callback.
114
+ * @private
115
+ */
116
+ private _emitChange;
117
+ /**
118
+ * Internal helper to update the displayed message.
119
+ * @param {string|HTMLElement} [message=this.#defaultMessage] - The new message.
120
+ * @throws {TypeError} If the message is not a string or HTMLElement.
121
+ * @throws {Error} If trying to use HTMLElement without allowHtmlText enabled.
122
+ * @private
123
+ */
124
+ private _updateMessage;
125
+ /**
126
+ * Removes all status-related CSS classes (`active`, `fadeIn`, `fadeOut`)
127
+ * from the overlay element, if it exists.
128
+ *
129
+ * @private
130
+ * @returns {void}
131
+ */
132
+ private _removeOldClasses;
133
+ /**
134
+ * Starts the loading screen or updates its message if already active.
135
+ * @param {string|HTMLElement} [message=this.#defaultMessage] - Message to display.
136
+ * @returns {boolean} `true` if the overlay was created, `false` if only the message was updated.
137
+ * @throws {TypeError} If message is not a string or HTMLElement.
138
+ */
139
+ start(message?: string | HTMLElement): boolean;
140
+ /**
141
+ * Updates the loading screen with a new message.
142
+ * @param {string|HTMLElement} [message=this.#defaultMessage] - The new message.
143
+ * @returns {boolean} `true` if the message was updated, `false` if overlay is not active.
144
+ * @throws {TypeError} If message is not a string or HTMLElement.
145
+ */
146
+ update(message?: string | HTMLElement): boolean;
147
+ /**
148
+ * Stops and removes the loading screen.
149
+ * @returns {boolean} `true` if the overlay was removed, `false` if not active.
150
+ */
151
+ stop(): boolean;
152
+ #private;
153
+ }
154
+ //# sourceMappingURL=TinyLoadingScreen.d.mts.map