tiny-essentials 1.21.0 → 1.21.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 t={d:(e,r)=>{for(var i in r)t.o(r,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:r[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{TinyNeedBar:()=>i});class r{#t=new Map;#e;#r;#i;get factors(){const t={};for(let[e,r]of this.#t.entries())t[e]={...r};return t}get currentPercent(){return this.#r/this.#e*100}set maxValue(t){this.#e=t,this.#r=Math.min(this.#r,t)}get maxValue(){return this.#e}get currentValue(){return this.#r}set infiniteValue(t){this.#i=t,this.#r=Math.max(0,t),this.#r=Math.min(this.#r,this.#e)}get infiniteValue(){return this.#i}constructor(t=100,e=1,r=1){this.#e=t,this.setFactor("main",e,r),this.#r=t,this.#i=t}getFactor(t){const e=this.#t.get(t);if(!e)throw new Error(`Factor with key "${t}" not found.`);return{...e}}hasFactor(t){return this.#t.has(t)}setFactor(t,e,r=1){this.#t.set(t,{amount:e,multiplier:r})}removeFactor(t){this.#t.delete(t)}tick(){let t=0;for(let[e,r]of this.#t.entries())t+=r.amount*r.multiplier;const e=this.#i;return this.#i-=t,this.#r=Math.max(0,this.#r-t),{prevValue:e,removedTotal:t,removedPercent:t/this.#e*100,currentPercent:this.currentPercent,remainingValue:this.#r,infiniteRemaining:this.#i}}toJSON(){return{maxValue:this.#e,currentValue:this.#r,infiniteValue:this.#i,factors:this.factors}}static fromJSON(t){const e=new r(t.maxValue,0,0);e.infiniteValue=t.infiniteValue,e.#t.clear();for(const[r,i]of Object.entries(t.factors))e.setFactor(r,i.amount,i.multiplier);return e}clone(){return r.fromJSON(this.toJSON())}clearFactors(){this.#t.clear()}}const i=r;window.TinyNeedBar=e.TinyNeedBar})();
@@ -144,17 +144,7 @@ function formatCustomTimer(totalSeconds, level = 'seconds', format = '{time}') {
144
144
  parts.seconds = remaining;
145
145
  }
146
146
 
147
- // Calculate total
148
- const totalMap = {
149
- seconds: include.seconds ? totalSeconds : NaN,
150
- minutes: include.minutes ? totalSeconds / 60 : NaN,
151
- hours: include.hours ? totalSeconds / 3600 : NaN,
152
- days: include.days ? totalSeconds / 86400 : NaN,
153
- months: include.months ? parts.years * 12 + parts.months + (parts.days || 0) / 30 : NaN,
154
- years: include.years ? parts.years + (parts.months || 0) / 12 + (parts.days || 0) / 365 : NaN,
155
- };
156
-
157
- parts.total = +(totalMap[level] || 0).toFixed(2).replace(/\.00$/, '');
147
+ parts.total = +totalSeconds.toFixed(2).replace(/\.00$/, '');
158
148
 
159
149
  /**
160
150
  * Pads a number to ensure it is at least two digits long, using leading zeros if necessary.
@@ -211,6 +201,132 @@ function formatDayTimer(seconds) {
211
201
  return formatCustomTimer(seconds, 'days', '{days}d {hours}:{minutes}:{seconds}');
212
202
  }
213
203
 
204
+ /**
205
+ * Breaks down a duration in milliseconds into its time components.
206
+ *
207
+ * @param {number} totalMs - The total duration in milliseconds.
208
+ * @param {'milliseconds'|'seconds'|'minutes'|'hours'|'days'|'months'|'years'} [level='milliseconds'] - The highest level to calculate and display.
209
+ * @returns {{
210
+ * years: number|NaN,
211
+ * months: number|NaN,
212
+ * days: number|NaN,
213
+ * hours: number|NaN,
214
+ * minutes: number|NaN,
215
+ * seconds: number|NaN,
216
+ * milliseconds: number|NaN,
217
+ * total: number|NaN
218
+ * }}
219
+ */
220
+ function breakdownDuration(totalMs, level = 'milliseconds') {
221
+ totalMs = Math.max(0, Math.floor(totalMs));
222
+
223
+ const levels = ['milliseconds', 'seconds', 'minutes', 'hours', 'days', 'months', 'years'];
224
+ const index = levels.indexOf(level);
225
+
226
+ const include = {
227
+ years: index >= 6,
228
+ months: index >= 5,
229
+ days: index >= 4,
230
+ hours: index >= 3,
231
+ minutes: index >= 2,
232
+ seconds: index >= 1,
233
+ milliseconds: index >= 0,
234
+ };
235
+
236
+ const parts = {
237
+ years: include.years ? 0 : NaN,
238
+ months: include.months ? 0 : NaN,
239
+ days: include.days ? 0 : NaN,
240
+ hours: include.hours ? 0 : NaN,
241
+ minutes: include.minutes ? 0 : NaN,
242
+ seconds: include.seconds ? 0 : NaN,
243
+ milliseconds: include.milliseconds ? 0 : NaN,
244
+ total: NaN,
245
+ };
246
+
247
+ let remaining = totalMs;
248
+
249
+ if (include.years || include.months || include.days) {
250
+ const baseDate = new Date(1980, 0, 1);
251
+ const targetDate = new Date(baseDate.getTime() + remaining);
252
+ const workingDate = new Date(baseDate);
253
+
254
+ // Years
255
+ if (include.years) {
256
+ while (
257
+ new Date(
258
+ workingDate.getFullYear() + 1,
259
+ workingDate.getMonth(),
260
+ workingDate.getDate(),
261
+ ).getTime() <= targetDate.getTime()
262
+ ) {
263
+ workingDate.setFullYear(workingDate.getFullYear() + 1);
264
+ parts.years++;
265
+ }
266
+ }
267
+
268
+ // Months
269
+ if (include.months) {
270
+ while (
271
+ new Date(
272
+ workingDate.getFullYear(),
273
+ workingDate.getMonth() + 1,
274
+ workingDate.getDate(),
275
+ ).getTime() <= targetDate.getTime()
276
+ ) {
277
+ workingDate.setMonth(workingDate.getMonth() + 1);
278
+ parts.months++;
279
+ }
280
+ }
281
+
282
+ // Days
283
+ if (include.days) {
284
+ while (
285
+ new Date(
286
+ workingDate.getFullYear(),
287
+ workingDate.getMonth(),
288
+ workingDate.getDate() + 1,
289
+ ).getTime() <= targetDate.getTime()
290
+ ) {
291
+ workingDate.setDate(workingDate.getDate() + 1);
292
+ parts.days++;
293
+ }
294
+ }
295
+
296
+ remaining = targetDate.getTime() - workingDate.getTime();
297
+ }
298
+
299
+ if (include.hours) {
300
+ parts.hours = Math.floor(remaining / 3600000);
301
+ remaining %= 3600000;
302
+ }
303
+
304
+ if (include.minutes) {
305
+ parts.minutes = Math.floor(remaining / 60000);
306
+ remaining %= 60000;
307
+ }
308
+
309
+ if (include.seconds) {
310
+ parts.seconds = Math.floor(remaining / 1000);
311
+ remaining %= 1000;
312
+ }
313
+
314
+ if (include.milliseconds) {
315
+ parts.milliseconds = remaining;
316
+ }
317
+
318
+ // Totals
319
+ ({
320
+ months: include.months ? parts.years * 12 + parts.months + (parts.days || 0) / 30 : NaN,
321
+ years: include.years ? parts.years + (parts.months || 0) / 12 + (parts.days || 0) / 365 : NaN,
322
+ });
323
+
324
+ parts.total = +totalMs;
325
+
326
+ return parts;
327
+ }
328
+
329
+ exports.breakdownDuration = breakdownDuration;
214
330
  exports.formatCustomTimer = formatCustomTimer;
215
331
  exports.formatDayTimer = formatDayTimer;
216
332
  exports.formatTimer = formatTimer;
@@ -35,4 +35,30 @@ export function formatTimer(seconds: number): string;
35
35
  * @returns {string} The formatted timer string in "Xd HH:MM:SS" format.
36
36
  */
37
37
  export function formatDayTimer(seconds: number): string;
38
+ /**
39
+ * Breaks down a duration in milliseconds into its time components.
40
+ *
41
+ * @param {number} totalMs - The total duration in milliseconds.
42
+ * @param {'milliseconds'|'seconds'|'minutes'|'hours'|'days'|'months'|'years'} [level='milliseconds'] - The highest level to calculate and display.
43
+ * @returns {{
44
+ * years: number|NaN,
45
+ * months: number|NaN,
46
+ * days: number|NaN,
47
+ * hours: number|NaN,
48
+ * minutes: number|NaN,
49
+ * seconds: number|NaN,
50
+ * milliseconds: number|NaN,
51
+ * total: number|NaN
52
+ * }}
53
+ */
54
+ export function breakdownDuration(totalMs: number, level?: "milliseconds" | "seconds" | "minutes" | "hours" | "days" | "months" | "years"): {
55
+ years: number | number;
56
+ months: number | number;
57
+ days: number | number;
58
+ hours: number | number;
59
+ minutes: number | number;
60
+ seconds: number | number;
61
+ milliseconds: number | number;
62
+ total: number | number;
63
+ };
38
64
  //# sourceMappingURL=clock.d.mts.map
@@ -117,7 +117,7 @@ export function formatCustomTimer(totalSeconds, level = 'seconds', format = '{ti
117
117
  months: include.months ? parts.years * 12 + parts.months + (parts.days || 0) / 30 : NaN,
118
118
  years: include.years ? parts.years + (parts.months || 0) / 12 + (parts.days || 0) / 365 : NaN,
119
119
  };
120
- parts.total = +(totalMap[level] || 0).toFixed(2).replace(/\.00$/, '');
120
+ parts.total = +totalSeconds.toFixed(2).replace(/\.00$/, '');
121
121
  /**
122
122
  * Pads a number to ensure it is at least two digits long, using leading zeros if necessary.
123
123
  *
@@ -168,3 +168,98 @@ export function formatTimer(seconds) {
168
168
  export function formatDayTimer(seconds) {
169
169
  return formatCustomTimer(seconds, 'days', '{days}d {hours}:{minutes}:{seconds}');
170
170
  }
171
+ /**
172
+ * Breaks down a duration in milliseconds into its time components.
173
+ *
174
+ * @param {number} totalMs - The total duration in milliseconds.
175
+ * @param {'milliseconds'|'seconds'|'minutes'|'hours'|'days'|'months'|'years'} [level='milliseconds'] - The highest level to calculate and display.
176
+ * @returns {{
177
+ * years: number|NaN,
178
+ * months: number|NaN,
179
+ * days: number|NaN,
180
+ * hours: number|NaN,
181
+ * minutes: number|NaN,
182
+ * seconds: number|NaN,
183
+ * milliseconds: number|NaN,
184
+ * total: number|NaN
185
+ * }}
186
+ */
187
+ export function breakdownDuration(totalMs, level = 'milliseconds') {
188
+ totalMs = Math.max(0, Math.floor(totalMs));
189
+ const levels = ['milliseconds', 'seconds', 'minutes', 'hours', 'days', 'months', 'years'];
190
+ const index = levels.indexOf(level);
191
+ const include = {
192
+ years: index >= 6,
193
+ months: index >= 5,
194
+ days: index >= 4,
195
+ hours: index >= 3,
196
+ minutes: index >= 2,
197
+ seconds: index >= 1,
198
+ milliseconds: index >= 0,
199
+ };
200
+ const parts = {
201
+ years: include.years ? 0 : NaN,
202
+ months: include.months ? 0 : NaN,
203
+ days: include.days ? 0 : NaN,
204
+ hours: include.hours ? 0 : NaN,
205
+ minutes: include.minutes ? 0 : NaN,
206
+ seconds: include.seconds ? 0 : NaN,
207
+ milliseconds: include.milliseconds ? 0 : NaN,
208
+ total: NaN,
209
+ };
210
+ let remaining = totalMs;
211
+ if (include.years || include.months || include.days) {
212
+ const baseDate = new Date(1980, 0, 1);
213
+ const targetDate = new Date(baseDate.getTime() + remaining);
214
+ const workingDate = new Date(baseDate);
215
+ // Years
216
+ if (include.years) {
217
+ while (new Date(workingDate.getFullYear() + 1, workingDate.getMonth(), workingDate.getDate()).getTime() <= targetDate.getTime()) {
218
+ workingDate.setFullYear(workingDate.getFullYear() + 1);
219
+ parts.years++;
220
+ }
221
+ }
222
+ // Months
223
+ if (include.months) {
224
+ while (new Date(workingDate.getFullYear(), workingDate.getMonth() + 1, workingDate.getDate()).getTime() <= targetDate.getTime()) {
225
+ workingDate.setMonth(workingDate.getMonth() + 1);
226
+ parts.months++;
227
+ }
228
+ }
229
+ // Days
230
+ if (include.days) {
231
+ while (new Date(workingDate.getFullYear(), workingDate.getMonth(), workingDate.getDate() + 1).getTime() <= targetDate.getTime()) {
232
+ workingDate.setDate(workingDate.getDate() + 1);
233
+ parts.days++;
234
+ }
235
+ }
236
+ remaining = targetDate.getTime() - workingDate.getTime();
237
+ }
238
+ if (include.hours) {
239
+ parts.hours = Math.floor(remaining / 3600000);
240
+ remaining %= 3600000;
241
+ }
242
+ if (include.minutes) {
243
+ parts.minutes = Math.floor(remaining / 60000);
244
+ remaining %= 60000;
245
+ }
246
+ if (include.seconds) {
247
+ parts.seconds = Math.floor(remaining / 1000);
248
+ remaining %= 1000;
249
+ }
250
+ if (include.milliseconds) {
251
+ parts.milliseconds = remaining;
252
+ }
253
+ // Totals
254
+ const totalMap = {
255
+ milliseconds: include.milliseconds ? totalMs : NaN,
256
+ seconds: include.seconds ? totalMs / 1000 : NaN,
257
+ minutes: include.minutes ? totalMs / 60000 : NaN,
258
+ hours: include.hours ? totalMs / 3600000 : NaN,
259
+ days: include.days ? totalMs / 86400000 : NaN,
260
+ months: include.months ? parts.years * 12 + parts.months + (parts.days || 0) / 30 : NaN,
261
+ years: include.years ? parts.years + (parts.months || 0) / 12 + (parts.days || 0) / 365 : NaN,
262
+ };
263
+ parts.total = +totalMs;
264
+ return parts;
265
+ }
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ var TinyNeedBar = require('../libs/TinyNeedBar.cjs');
4
+
5
+
6
+
7
+ exports.TinyNeedBar = TinyNeedBar;
@@ -0,0 +1,3 @@
1
+ export { TinyNeedBar };
2
+ import TinyNeedBar from '../libs/TinyNeedBar.mjs';
3
+ //# sourceMappingURL=TinyNeedBar.d.mts.map
@@ -0,0 +1,2 @@
1
+ import TinyNeedBar from '../libs/TinyNeedBar.mjs';
2
+ export { TinyNeedBar };
package/dist/v1/index.cjs CHANGED
@@ -44,6 +44,7 @@ var TinyInventory = require('./libs/TinyInventory.cjs');
44
44
  var TinyInventoryTrader = require('./libs/TinyInventoryTrader.cjs');
45
45
  var TinyCookieConsent = require('./libs/TinyCookieConsent.cjs');
46
46
  var TinyI18 = require('./libs/TinyI18.cjs');
47
+ var TinyNeedBar = require('./libs/TinyNeedBar.cjs');
47
48
 
48
49
 
49
50
 
@@ -164,3 +165,4 @@ exports.TinyInventory = TinyInventory;
164
165
  exports.TinyInventoryTrader = TinyInventoryTrader;
165
166
  exports.TinyCookieConsent = TinyCookieConsent;
166
167
  exports.TinyI18 = TinyI18;
168
+ exports.TinyNeedBar = TinyNeedBar;
@@ -1,3 +1,4 @@
1
+ import TinyNeedBar from './libs/TinyNeedBar.mjs';
1
2
  import TinyI18 from './libs/TinyI18.mjs';
2
3
  import TinyCookieConsent from './libs/TinyCookieConsent.mjs';
3
4
  import TinyInventory from './libs/TinyInventory.mjs';
@@ -115,5 +116,5 @@ import { getTimeDuration } from './basics/clock.mjs';
115
116
  import { shuffleArray } from './basics/array.mjs';
116
117
  import { toTitleCase } from './basics/text.mjs';
117
118
  import { toTitleCaseLowerFirst } from './basics/text.mjs';
118
- export { 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, 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 };
119
+ export { 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, 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 };
119
120
  //# sourceMappingURL=index.d.mts.map
package/dist/v1/index.mjs CHANGED
@@ -42,4 +42,5 @@ import TinyInventory from './libs/TinyInventory.mjs';
42
42
  import TinyInventoryTrader from './libs/TinyInventoryTrader.mjs';
43
43
  import TinyCookieConsent from './libs/TinyCookieConsent.mjs';
44
44
  import TinyI18 from './libs/TinyI18.mjs';
45
- export { 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, 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, };
45
+ import TinyNeedBar from './libs/TinyNeedBar.mjs';
46
+ export { 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, 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, };
@@ -0,0 +1,272 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @typedef {Object} TickResult
5
+ * @property {number} prevValue - Infinite value before applying decay.
6
+ * @property {number} removedTotal - Total amount removed this tick.
7
+ * @property {number} removedPercent - Percentage of max removed this tick.
8
+ * @property {number} currentPercent - Current percentage relative to max.
9
+ * @property {number} remainingValue - Current clamped value (≥ 0).
10
+ * @property {number} infiniteRemaining - Current infinite value (can be negative).
11
+ */
12
+
13
+ /**
14
+ * Represents a decay factor applied to the need bar.
15
+ *
16
+ * - `amount`: base value reduced per tick.
17
+ * - `multiplier`: multiplier applied to the amount.
18
+ *
19
+ * @typedef {Object} BarFactor
20
+ * @property {number} amount - Base reduction value per tick.
21
+ * @property {number} multiplier - Multiplier applied to the amount.
22
+ */
23
+
24
+ /**
25
+ * Represents the serialized state of a TinyNeedBar instance.
26
+ *
27
+ * This object is typically produced by {@link TinyNeedBar#toJSON} and
28
+ * can be used to recreate an instance via {@link TinyNeedBar.fromJSON}.
29
+ *
30
+ * @typedef {Object} SerializedData
31
+ * @property {number} maxValue - Maximum value of the bar at the moment of serialization.
32
+ * @property {number} currentValue - Current clamped value (never below 0).
33
+ * @property {number} infiniteValue - Infinite value (can go negative).
34
+ * @property {Record<string, BarFactor>} factors - Active decay factors indexed by their keys.
35
+ */
36
+
37
+ /**
38
+ * A utility class to simulate a "need bar" system.
39
+ *
40
+ * The bar decreases over time according to defined factors (each with an amount and multiplier).
41
+ * - The **main factor** controls the base decay per tick.
42
+ * - Additional factors can be added dynamically.
43
+ *
44
+ * The system tracks two values:
45
+ * - `currentValue` → cannot go below zero.
46
+ * - `infiniteValue` → can decrease infinitely into negative numbers.
47
+ */
48
+ class TinyNeedBar {
49
+ /**
50
+ * Stores all factors that influence decay.
51
+ * Each entry contains an amount and a multiplier.
52
+ * @type {Map<string, BarFactor>}
53
+ */
54
+ #factors = new Map();
55
+
56
+ /** Maximum value of the bar. @type {number} */
57
+ #maxValue;
58
+
59
+ /** Current clamped value of the bar (never below 0). @type {number} */
60
+ #currentValue;
61
+
62
+ /** Current "infinite" value of the bar (can go negative). @type {number} */
63
+ #infiniteValue;
64
+
65
+ /**
66
+ * Returns a snapshot of all currently active factors.
67
+ * Each factor is returned as a plain object to prevent direct mutation of the internal map.
68
+ *
69
+ * @returns {Record<string, BarFactor>} A record of all factors indexed by their key.
70
+ */
71
+ get factors() {
72
+ /** @type {Record<string, BarFactor>} */
73
+ const factors = {};
74
+ for (let [name, factor] of this.#factors.entries()) {
75
+ factors[name] = { ...factor };
76
+ }
77
+ return factors;
78
+ }
79
+
80
+ /**
81
+ * Returns the current percentage of the bar relative to the maximum value.
82
+ *
83
+ * @returns {number} Percentage from `0` to `100`.
84
+ */
85
+ get currentPercent() {
86
+ return (this.#currentValue / this.#maxValue) * 100;
87
+ }
88
+
89
+ /**
90
+ * Updates the maximum possible value of the bar.
91
+ * Ensures `currentValue` never exceeds the new maximum.
92
+ *
93
+ * @param {number} value - New maximum value.
94
+ */
95
+ set maxValue(value) {
96
+ this.#maxValue = value;
97
+ this.#currentValue = Math.min(this.#currentValue, value);
98
+ }
99
+
100
+ /**
101
+ * Returns the maximum possible value of the bar.
102
+ *
103
+ * @returns {number} The maximum value.
104
+ */
105
+ get maxValue() {
106
+ return this.#maxValue;
107
+ }
108
+
109
+ /**
110
+ * Returns the current clamped value of the bar.
111
+ * This value will never be below `0`.
112
+ *
113
+ * @returns {number} Current value (≥ 0).
114
+ */
115
+ get currentValue() {
116
+ return this.#currentValue;
117
+ }
118
+
119
+ /**
120
+ * Updates the infinite value of the bar.
121
+ * Automatically recalculates the `currentValue` (never below 0).
122
+ *
123
+ * @param {number} value - New infinite value.
124
+ */
125
+ set infiniteValue(value) {
126
+ this.#infiniteValue = value;
127
+ this.#currentValue = Math.max(0, value);
128
+ this.#currentValue = Math.min(this.#currentValue, this.#maxValue);
129
+ }
130
+
131
+ /**
132
+ * Returns the current infinite value of the bar.
133
+ * Unlike `currentValue`, this one can go below zero.
134
+ *
135
+ * @returns {number} Current infinite value.
136
+ */
137
+ get infiniteValue() {
138
+ return this.#infiniteValue;
139
+ }
140
+
141
+ /**
142
+ * Creates a new need bar instance.
143
+ *
144
+ * @param {number} [maxValue=100] - Maximum value of the bar.
145
+ * @param {number} [baseDecay=1] - Base amount reduced each tick.
146
+ * @param {number} [baseDecayMulti=1] - Multiplier applied to the base decay.
147
+ */
148
+ constructor(maxValue = 100, baseDecay = 1, baseDecayMulti = 1) {
149
+ this.#maxValue = maxValue;
150
+ this.setFactor('main', baseDecay, baseDecayMulti);
151
+
152
+ this.#currentValue = maxValue;
153
+ this.#infiniteValue = maxValue;
154
+ }
155
+
156
+ /**
157
+ * Retrieves a specific factor by its key.
158
+ *
159
+ * @param {string} key - The unique key of the factor.
160
+ * @returns {BarFactor} The requested factor object.
161
+ * @throws {Error} If the factor does not exist.
162
+ */
163
+ getFactor(key) {
164
+ const result = this.#factors.get(key);
165
+ if (!result) throw new Error(`Factor with key "${key}" not found.`);
166
+ return { ...result };
167
+ }
168
+
169
+ /**
170
+ * Checks if a specific factor exists by key.
171
+ *
172
+ * @param {string} key - The factor key to check.
173
+ * @returns {boolean} `true` if the factor exists, otherwise `false`.
174
+ */
175
+ hasFactor(key) {
176
+ return this.#factors.has(key);
177
+ }
178
+
179
+ /**
180
+ * Defines or updates a decay factor.
181
+ *
182
+ * @param {string} key - Unique identifier for the factor.
183
+ * @param {number} amount - Amount reduced per tick.
184
+ * @param {number} [multiplier=1] - Multiplier applied to the amount.
185
+ */
186
+ setFactor(key, amount, multiplier = 1) {
187
+ this.#factors.set(key, { amount, multiplier });
188
+ }
189
+
190
+ /**
191
+ * Removes a decay factor by its key.
192
+ *
193
+ * @param {string} key - The factor key to remove.
194
+ */
195
+ removeFactor(key) {
196
+ this.#factors.delete(key);
197
+ }
198
+
199
+ /**
200
+ * Executes one tick of decay, applying all active factors.
201
+ *
202
+ * @returns {TickResult}
203
+ */
204
+ tick() {
205
+ let removedTotal = 0;
206
+
207
+ for (let [_, factor] of this.#factors.entries()) {
208
+ removedTotal += factor.amount * factor.multiplier;
209
+ }
210
+
211
+ const prevValue = this.#infiniteValue;
212
+ this.#infiniteValue -= removedTotal;
213
+ this.#currentValue = Math.max(0, this.#currentValue - removedTotal);
214
+
215
+ const removedPercent = (removedTotal / this.#maxValue) * 100;
216
+
217
+ return {
218
+ prevValue,
219
+ removedTotal,
220
+ removedPercent,
221
+ currentPercent: this.currentPercent,
222
+ remainingValue: this.#currentValue,
223
+ infiniteRemaining: this.#infiniteValue,
224
+ };
225
+ }
226
+
227
+ /**
228
+ * Serializes the current state of the need bar.
229
+ * @returns {SerializedData}
230
+ */
231
+ toJSON() {
232
+ return {
233
+ maxValue: this.#maxValue,
234
+ currentValue: this.#currentValue,
235
+ infiniteValue: this.#infiniteValue,
236
+ factors: this.factors,
237
+ };
238
+ }
239
+
240
+ /**
241
+ * Restores a need bar from a serialized object.
242
+ * @param {SerializedData} data
243
+ * @returns {TinyNeedBar}
244
+ */
245
+ static fromJSON(data) {
246
+ const bar = new TinyNeedBar(data.maxValue, 0, 0);
247
+ bar.infiniteValue = data.infiniteValue;
248
+ bar.#factors.clear();
249
+ for (const [key, factor] of Object.entries(data.factors)) {
250
+ bar.setFactor(key, factor.amount, factor.multiplier);
251
+ }
252
+
253
+ return bar;
254
+ }
255
+
256
+ /**
257
+ * Creates a deep clone of this need bar.
258
+ * @returns {TinyNeedBar}
259
+ */
260
+ clone() {
261
+ return TinyNeedBar.fromJSON(this.toJSON());
262
+ }
263
+
264
+ /**
265
+ * Clear the factors map, clearing all factor data.
266
+ */
267
+ clearFactors() {
268
+ this.#factors.clear();
269
+ }
270
+ }
271
+
272
+ module.exports = TinyNeedBar;