@sv443-network/userutils 8.3.3 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,10 +30,7 @@ var __objRest = (source, exclude) => {
30
30
  }
31
31
  return target;
32
32
  };
33
- var __publicField = (obj, key, value) => {
34
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
35
- return value;
36
- };
33
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
37
34
  var __async = (__this, __arguments, generator) => {
38
35
  return new Promise((resolve, reject) => {
39
36
  var fulfilled = (value) => {
@@ -57,14 +54,17 @@ var __async = (__this, __arguments, generator) => {
57
54
 
58
55
  // lib/math.ts
59
56
  function clamp(value, min, max) {
57
+ if (typeof max !== "number") {
58
+ max = min;
59
+ min = 0;
60
+ }
60
61
  return Math.max(Math.min(value, max), min);
61
62
  }
62
63
  function mapRange(value, range1min, range1max, range2min, range2max) {
63
- if (typeof range2min === "undefined" || range2max === void 0) {
64
+ if (typeof range2min === "undefined" || typeof range2max === "undefined") {
64
65
  range2max = range1max;
65
- range2min = 0;
66
66
  range1max = range1min;
67
- range1min = 0;
67
+ range2min = range1min = 0;
68
68
  }
69
69
  if (Number(range1min) === 0 && Number(range2min) === 0)
70
70
  return value * (range2max / range1max);
@@ -78,7 +78,7 @@ function randRange(...args) {
78
78
  min = 0;
79
79
  [max] = args;
80
80
  } else
81
- throw new TypeError(`Wrong parameter(s) provided - expected: "number" and "number|undefined", got: "${typeof args[0]}" and "${typeof args[1]}"`);
81
+ throw new TypeError(`Wrong parameter(s) provided - expected (number, boolean|undefined) or (number, number, boolean|undefined) but got (${args.map((a) => typeof a).join(", ")}) instead`);
82
82
  if (typeof args[2] === "boolean")
83
83
  enhancedEntropy = args[2];
84
84
  else if (typeof args[1] === "boolean")
@@ -94,11 +94,19 @@ function randRange(...args) {
94
94
  crypto.getRandomValues(uintArr);
95
95
  return Number(Array.from(
96
96
  uintArr,
97
- (v) => Math.round(mapRange(v, 0, 255, min, max)).toString(10).substring(0, 1)
97
+ (v) => Math.round(mapRange(v, 0, 255, min, max)).toString(10)
98
98
  ).join(""));
99
99
  } else
100
100
  return Math.floor(Math.random() * (max - min + 1)) + min;
101
101
  }
102
+ function digitCount(num) {
103
+ num = Number(!["string", "number"].includes(typeof num) ? String(num) : num);
104
+ if (typeof num === "number" && isNaN(num))
105
+ return NaN;
106
+ return num === 0 ? 1 : Math.floor(
107
+ Math.log10(Math.abs(Number(num))) + 1
108
+ );
109
+ }
102
110
 
103
111
  // lib/array.ts
104
112
  function randomItem(array) {
@@ -106,14 +114,14 @@ function randomItem(array) {
106
114
  }
107
115
  function randomItemIndex(array) {
108
116
  if (array.length === 0)
109
- return [void 0, void 0];
117
+ return [undefined, undefined];
110
118
  const idx = randRange(array.length - 1);
111
119
  return [array[idx], idx];
112
120
  }
113
121
  function takeRandomItem(arr) {
114
122
  const [itm, idx] = randomItemIndex(arr);
115
- if (idx === void 0)
116
- return void 0;
123
+ if (idx === undefined)
124
+ return undefined;
117
125
  arr.splice(idx, 1);
118
126
  return itm;
119
127
  }
@@ -131,7 +139,7 @@ function randomizeArray(array) {
131
139
  // lib/colors.ts
132
140
  function hexToRgb(hex) {
133
141
  hex = (hex.startsWith("#") ? hex.slice(1) : hex).trim();
134
- const a = hex.length === 8 || hex.length === 4 ? parseInt(hex.slice(-(hex.length / 4)), 16) / (hex.length === 8 ? 255 : 15) : void 0;
142
+ const a = hex.length === 8 || hex.length === 4 ? parseInt(hex.slice(-(hex.length / 4)), 16) / (hex.length === 8 ? 255 : 15) : undefined;
135
143
  if (!isNaN(Number(a)))
136
144
  hex = hex.slice(0, -(hex.length / 4));
137
145
  if (hex.length === 3 || hex.length === 4)
@@ -140,7 +148,7 @@ function hexToRgb(hex) {
140
148
  const r = bigint >> 16 & 255;
141
149
  const g = bigint >> 8 & 255;
142
150
  const b = bigint & 255;
143
- return [clamp(r, 0, 255), clamp(g, 0, 255), clamp(b, 0, 255), typeof a === "number" ? clamp(a, 0, 1) : void 0];
151
+ return [clamp(r, 0, 255), clamp(g, 0, 255), clamp(b, 0, 255), typeof a === "number" ? clamp(a, 0, 1) : undefined];
144
152
  }
145
153
  function rgbToHex(red, green, blue, alpha, withHash = true, upperCase = false) {
146
154
  const toHexVal = (n) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, "0")[upperCase ? "toUpperCase" : "toLowerCase"]();
@@ -163,7 +171,7 @@ function darkenColor(color, percent, upperCase = false) {
163
171
  if (isHexCol)
164
172
  [r, g, b, a] = hexToRgb(color);
165
173
  else if (color.startsWith("rgb")) {
166
- const rgbValues = (_a = color.match(/\d+(\.\d+)?/g)) == null ? void 0 : _a.map(Number);
174
+ const rgbValues = (_a = color.match(/\d+(\.\d+)?/g)) == null ? undefined : _a.map(Number);
167
175
  if (!rgbValues)
168
176
  throw new Error("Invalid RGB/RGBA color format");
169
177
  [r, g, b, a] = rgbValues;
@@ -211,26 +219,32 @@ function preloadImages(srcUrls, rejects = false) {
211
219
  }));
212
220
  return Promise.allSettled(promises);
213
221
  }
214
- function openInNewTab(href, background) {
222
+ function openInNewTab(href, background, additionalProps) {
223
+ var _a;
215
224
  try {
216
- GM.openInTab(href, background);
225
+ (_a = GM.openInTab) == null ? void 0 : _a.call(GM, href, background);
217
226
  } catch (e) {
218
227
  const openElem = document.createElement("a");
219
- Object.assign(openElem, {
228
+ Object.assign(openElem, __spreadValues({
220
229
  className: "userutils-open-in-new-tab",
221
230
  target: "_blank",
222
231
  rel: "noopener noreferrer",
232
+ tabIndex: -1,
233
+ ariaHidden: "true",
223
234
  href
235
+ }, additionalProps));
236
+ Object.assign(openElem.style, {
237
+ display: "none",
238
+ pointerEvents: "none"
224
239
  });
225
- openElem.style.display = "none";
226
240
  document.body.appendChild(openElem);
227
241
  openElem.click();
228
- setTimeout(openElem.remove, 50);
242
+ setTimeout(openElem.remove, 0);
229
243
  }
230
244
  }
231
245
  function interceptEvent(eventObject, eventName, predicate = () => true) {
232
246
  var _a;
233
- if ((eventObject === window || eventObject === getUnsafeWindow()) && ((_a = GM == null ? void 0 : GM.info) == null ? void 0 : _a.scriptHandler) && GM.info.scriptHandler === "FireMonkey")
247
+ if ((eventObject === window || eventObject === getUnsafeWindow()) && ((_a = GM == null ? undefined : GM.info) == null ? undefined : _a.scriptHandler) && GM.info.scriptHandler === "FireMonkey")
234
248
  throw new Error("Intercepting window events is not supported on FireMonkey due to the isolated context the userscript runs in.");
235
249
  Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 100);
236
250
  if (isNaN(Error.stackTraceLimit))
@@ -238,7 +252,7 @@ function interceptEvent(eventObject, eventName, predicate = () => true) {
238
252
  (function(original) {
239
253
  eventObject.__proto__.addEventListener = function(...args) {
240
254
  var _a2, _b;
241
- const origListener = typeof args[1] === "function" ? args[1] : (_b = (_a2 = args[1]) == null ? void 0 : _a2.handleEvent) != null ? _b : () => void 0;
255
+ const origListener = typeof args[1] === "function" ? args[1] : (_b = (_a2 = args[1]) == null ? undefined : _a2.handleEvent) != null ? _b : () => undefined;
242
256
  args[1] = function(...a) {
243
257
  if (args[0] === eventName && predicate(Array.isArray(a) ? a[0] : a))
244
258
  return;
@@ -266,12 +280,12 @@ function observeElementProp(element, property, callback) {
266
280
  Object.defineProperty(element, property, {
267
281
  get: function() {
268
282
  var _a;
269
- return (_a = descriptor == null ? void 0 : descriptor.get) == null ? void 0 : _a.apply(this, arguments);
283
+ return (_a = descriptor == null ? undefined : descriptor.get) == null ? undefined : _a.apply(this, arguments);
270
284
  },
271
285
  set: function() {
272
286
  var _a;
273
287
  const oldValue = this[property];
274
- (_a = descriptor == null ? void 0 : descriptor.set) == null ? void 0 : _a.apply(this, arguments);
288
+ (_a = descriptor == null ? undefined : descriptor.set) == null ? undefined : _a.apply(this, arguments);
275
289
  const newValue = this[property];
276
290
  if (typeof callback === "function") {
277
291
  callback.bind(this, oldValue, newValue);
@@ -283,7 +297,7 @@ function observeElementProp(element, property, callback) {
283
297
  }
284
298
  function getSiblingsFrame(refElement, siblingAmount, refElementAlignment = "center-top", includeRef = true) {
285
299
  var _a, _b;
286
- const siblings = [...(_b = (_a = refElement.parentNode) == null ? void 0 : _a.childNodes) != null ? _b : []];
300
+ const siblings = [...(_b = (_a = refElement.parentNode) == null ? undefined : _a.childNodes) != null ? _b : []];
287
301
  const elemSiblIdx = siblings.indexOf(refElement);
288
302
  if (elemSiblIdx === -1)
289
303
  throw new Error("Element doesn't have a parent node");
@@ -305,12 +319,12 @@ function getSiblingsFrame(refElement, siblingAmount, refElementAlignment = "cent
305
319
  var ttPolicy;
306
320
  function setInnerHtmlUnsafe(element, html) {
307
321
  var _a, _b, _c;
308
- if (!ttPolicy && typeof ((_a = window == null ? void 0 : window.trustedTypes) == null ? void 0 : _a.createPolicy) === "function") {
322
+ if (!ttPolicy && typeof ((_a = window == null ? undefined : window.trustedTypes) == null ? undefined : _a.createPolicy) === "function") {
309
323
  ttPolicy = window.trustedTypes.createPolicy("_uu_set_innerhtml_unsafe", {
310
324
  createHTML: (unsafeHtml) => unsafeHtml
311
325
  });
312
326
  }
313
- element.innerHTML = (_c = (_b = ttPolicy == null ? void 0 : ttPolicy.createHTML) == null ? void 0 : _b.call(ttPolicy, html)) != null ? _c : html;
327
+ element.innerHTML = (_c = (_b = ttPolicy == null ? undefined : ttPolicy.createHTML) == null ? undefined : _b.call(ttPolicy, html)) != null ? _c : html;
314
328
  return element;
315
329
  }
316
330
 
@@ -386,8 +400,8 @@ var DataStore = class {
386
400
  * Creates an instance of DataStore to manage a sync & async database that is cached in memory and persistently saved across sessions.
387
401
  * Supports migrating data from older versions to newer ones and populating the cache with default data if no persistent data is found.
388
402
  *
389
- * ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue` if the storageMethod is left as the default of `"GM"`
390
- * ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
403
+ * - ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue` if the storageMethod is left as the default of `"GM"`
404
+ * - ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
391
405
  *
392
406
  * @template TData The type of the data that is saved in persistent storage for the currently set format version (will be automatically inferred from `defaultData` if not provided) - **This has to be a JSON-compatible object!** (no undefined, circular references, etc.)
393
407
  * @param options The options for this DataStore instance
@@ -494,7 +508,7 @@ var DataStore = class {
494
508
  * The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
495
509
  * Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
496
510
  *
497
- * ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
511
+ * - ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
498
512
  */
499
513
  deleteData() {
500
514
  return __async(this, null, function* () {
@@ -559,7 +573,7 @@ var DataStore = class {
559
573
  const data = yield this.getValue(`_uucfg-${id}`, JSON.stringify(this.defaultData));
560
574
  const fmtVer = Number(yield this.getValue(`_uucfgver-${id}`, NaN));
561
575
  const isEncoded = Boolean(yield this.getValue(`_uucfgenc-${id}`, false));
562
- if (data === void 0 || isNaN(fmtVer))
576
+ if (data === undefined || isNaN(fmtVer))
563
577
  return;
564
578
  const parsed = yield this.deserializeData(data, isEncoded);
565
579
  yield Promise.allSettled([
@@ -589,7 +603,7 @@ var DataStore = class {
589
603
  /** Deserializes the data using the optional this.decodeData() and returns it as a JSON object */
590
604
  deserializeData(data, useEncoding = true) {
591
605
  return __async(this, null, function* () {
592
- let decRes = this.encodingEnabled() && useEncoding ? this.decodeData(data) : void 0;
606
+ let decRes = this.encodingEnabled() && useEncoding ? this.decodeData(data) : undefined;
593
607
  if (decRes instanceof Promise)
594
608
  decRes = yield decRes;
595
609
  return JSON.parse(decRes != null ? decRes : data);
@@ -601,7 +615,7 @@ var DataStore = class {
601
615
  return JSON.parse(JSON.stringify(obj));
602
616
  }
603
617
  //#region storage
604
- /** Gets a value from persistent storage - can be overwritten in a subclass if you want to use something other than GM storage */
618
+ /** Gets a value from persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods */
605
619
  getValue(name, defaultValue) {
606
620
  return __async(this, null, function* () {
607
621
  var _a, _b;
@@ -616,7 +630,7 @@ var DataStore = class {
616
630
  });
617
631
  }
618
632
  /**
619
- * Sets a value in persistent storage - can be overwritten in a subclass if you want to use something other than GM storage.
633
+ * Sets a value in persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods.
620
634
  * The default storage engines will stringify all passed values like numbers or booleans, so be aware of that.
621
635
  */
622
636
  setValue(name, value) {
@@ -631,7 +645,7 @@ var DataStore = class {
631
645
  }
632
646
  });
633
647
  }
634
- /** Deletes a value from persistent storage - can be overwritten in a subclass if you want to use something other than GM storage */
648
+ /** Deletes a value from persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods */
635
649
  deleteValue(name) {
636
650
  return __async(this, null, function* () {
637
651
  switch (this.storageMethod) {
@@ -669,7 +683,7 @@ var DataStoreSerializer = class {
669
683
  serializeStore(storeInst) {
670
684
  return __async(this, null, function* () {
671
685
  const data = storeInst.encodingEnabled() ? yield storeInst.encodeData(JSON.stringify(storeInst.getData())) : JSON.stringify(storeInst.getData());
672
- const checksum = this.options.addChecksum ? yield this.calcChecksum(data) : void 0;
686
+ const checksum = this.options.addChecksum ? yield this.calcChecksum(data) : undefined;
673
687
  return {
674
688
  id: storeInst.id,
675
689
  data,
@@ -775,7 +789,7 @@ var NanoEmitter = class {
775
789
  let unsub;
776
790
  const onceProxy = (...args) => {
777
791
  unsub();
778
- cb == null ? void 0 : cb(...args);
792
+ cb == null ? undefined : cb(...args);
779
793
  resolve(args);
780
794
  };
781
795
  unsub = this.on(event, onceProxy);
@@ -797,6 +811,106 @@ var NanoEmitter = class {
797
811
  }
798
812
  };
799
813
 
814
+ // lib/Debouncer.ts
815
+ var Debouncer = class extends NanoEmitter {
816
+ /**
817
+ * Creates a new debouncer with the specified timeout and edge type.
818
+ * @param timeout Timeout in milliseconds between letting through calls - defaults to 200
819
+ * @param type The edge type to use for the debouncer - see {@linkcode DebouncerType} for details or [the documentation for an explanation and diagram](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#debouncer) - defaults to "immediate"
820
+ */
821
+ constructor(timeout = 200, type = "immediate") {
822
+ super();
823
+ this.timeout = timeout;
824
+ this.type = type;
825
+ /** All registered listener functions and the time they were attached */
826
+ __publicField(this, "listeners", []);
827
+ /** The currently active timeout */
828
+ __publicField(this, "activeTimeout");
829
+ /** The latest queued call */
830
+ __publicField(this, "queuedCall");
831
+ }
832
+ //#region listeners
833
+ /** Adds a listener function that will be called on timeout */
834
+ addListener(fn) {
835
+ this.listeners.push(fn);
836
+ }
837
+ /** Removes the listener with the specified function reference */
838
+ removeListener(fn) {
839
+ const idx = this.listeners.findIndex((l) => l === fn);
840
+ idx !== -1 && this.listeners.splice(idx, 1);
841
+ }
842
+ /** Removes all listeners */
843
+ removeAllListeners() {
844
+ this.listeners = [];
845
+ }
846
+ //#region timeout
847
+ /** Sets the timeout for the debouncer */
848
+ setTimeout(timeout) {
849
+ this.emit("change", this.timeout = timeout, this.type);
850
+ }
851
+ /** Returns the current timeout */
852
+ getTimeout() {
853
+ return this.timeout;
854
+ }
855
+ /** Whether the timeout is currently active, meaning any latest call to the {@linkcode call()} method will be queued */
856
+ isTimeoutActive() {
857
+ return typeof this.activeTimeout !== "undefined";
858
+ }
859
+ //#region type
860
+ /** Sets the edge type for the debouncer */
861
+ setType(type) {
862
+ this.emit("change", this.timeout, this.type = type);
863
+ }
864
+ /** Returns the current edge type */
865
+ getType() {
866
+ return this.type;
867
+ }
868
+ //#region call
869
+ /** Use this to call the debouncer with the specified arguments that will be passed to all listener functions registered with {@linkcode addListener()} */
870
+ call(...args) {
871
+ const cl = (...a) => {
872
+ this.queuedCall = undefined;
873
+ this.emit("call", ...a);
874
+ this.listeners.forEach((l) => l.apply(this, a));
875
+ };
876
+ const setRepeatTimeout = () => {
877
+ this.activeTimeout = setTimeout(() => {
878
+ if (this.queuedCall) {
879
+ this.queuedCall();
880
+ setRepeatTimeout();
881
+ } else
882
+ this.activeTimeout = undefined;
883
+ }, this.timeout);
884
+ };
885
+ switch (this.type) {
886
+ case "immediate":
887
+ if (typeof this.activeTimeout === "undefined") {
888
+ cl(...args);
889
+ setRepeatTimeout();
890
+ } else
891
+ this.queuedCall = () => cl(...args);
892
+ break;
893
+ case "idle":
894
+ if (this.activeTimeout)
895
+ clearTimeout(this.activeTimeout);
896
+ this.activeTimeout = setTimeout(() => {
897
+ cl(...args);
898
+ this.activeTimeout = undefined;
899
+ }, this.timeout);
900
+ break;
901
+ default:
902
+ throw new Error(`Invalid debouncer type: ${this.type}`);
903
+ }
904
+ }
905
+ };
906
+ function debounce(fn, timeout = 200, type = "immediate") {
907
+ const debouncer = new Debouncer(timeout, type);
908
+ debouncer.addListener(fn);
909
+ const func = (...args) => debouncer.call(...args);
910
+ func.debouncer = debouncer;
911
+ return func;
912
+ }
913
+
800
914
  // lib/Dialog.ts
801
915
  var defaultDialogCss = `.uu-no-select {
802
916
  user-select: none;
@@ -1014,7 +1128,7 @@ var Dialog = class _Dialog extends NanoEmitter {
1014
1128
  `#uu-style-dialog-${this.id}`
1015
1129
  ];
1016
1130
  for (const sel of clearSelectors)
1017
- (_a = document.querySelector(sel)) == null ? void 0 : _a.remove();
1131
+ (_a = document.querySelector(sel)) == null ? undefined : _a.remove();
1018
1132
  this.events.emit("clear");
1019
1133
  }
1020
1134
  /** Clears the DOM of the dialog and then renders it again */
@@ -1031,8 +1145,8 @@ var Dialog = class _Dialog extends NanoEmitter {
1031
1145
  open(e) {
1032
1146
  return __async(this, null, function* () {
1033
1147
  var _a;
1034
- e == null ? void 0 : e.preventDefault();
1035
- e == null ? void 0 : e.stopImmediatePropagation();
1148
+ e == null ? undefined : e.preventDefault();
1149
+ e == null ? undefined : e.stopImmediatePropagation();
1036
1150
  if (this.isOpen())
1037
1151
  return;
1038
1152
  this.dialogOpen = true;
@@ -1050,7 +1164,7 @@ var Dialog = class _Dialog extends NanoEmitter {
1050
1164
  openDialogs.unshift(this.id);
1051
1165
  for (const dialogId of openDialogs)
1052
1166
  if (dialogId !== this.id)
1053
- (_a = document.querySelector(`#uu-${dialogId}-dialog-bg`)) == null ? void 0 : _a.setAttribute("inert", "true");
1167
+ (_a = document.querySelector(`#uu-${dialogId}-dialog-bg`)) == null ? undefined : _a.setAttribute("inert", "true");
1054
1168
  document.body.classList.remove("uu-no-select");
1055
1169
  document.body.setAttribute("inert", "true");
1056
1170
  this.events.emit("open");
@@ -1060,8 +1174,8 @@ var Dialog = class _Dialog extends NanoEmitter {
1060
1174
  /** Closes the dialog - prevents default action and immediate propagation of the passed event */
1061
1175
  close(e) {
1062
1176
  var _a, _b;
1063
- e == null ? void 0 : e.preventDefault();
1064
- e == null ? void 0 : e.stopImmediatePropagation();
1177
+ e == null ? undefined : e.preventDefault();
1178
+ e == null ? undefined : e.stopImmediatePropagation();
1065
1179
  if (!this.isOpen())
1066
1180
  return;
1067
1181
  this.dialogOpen = false;
@@ -1074,7 +1188,7 @@ var Dialog = class _Dialog extends NanoEmitter {
1074
1188
  openDialogs.splice(openDialogs.indexOf(this.id), 1);
1075
1189
  exports.currentDialogId = (_a = openDialogs[0]) != null ? _a : null;
1076
1190
  if (exports.currentDialogId)
1077
- (_b = document.querySelector(`#uu-${exports.currentDialogId}-dialog-bg`)) == null ? void 0 : _b.removeAttribute("inert");
1191
+ (_b = document.querySelector(`#uu-${exports.currentDialogId}-dialog-bg`)) == null ? undefined : _b.removeAttribute("inert");
1078
1192
  if (openDialogs.length === 0) {
1079
1193
  document.body.classList.add("uu-no-select");
1080
1194
  document.body.removeAttribute("inert");
@@ -1118,7 +1232,7 @@ var Dialog = class _Dialog extends NanoEmitter {
1118
1232
  if (this.options.closeOnBgClick) {
1119
1233
  bgElem.addEventListener("click", (e) => {
1120
1234
  var _a;
1121
- if (this.isOpen() && ((_a = e.target) == null ? void 0 : _a.id) === `uu-${this.id}-dialog-bg`)
1235
+ if (this.isOpen() && ((_a = e.target) == null ? undefined : _a.id) === `uu-${this.id}-dialog-bg`)
1122
1236
  this.close(e);
1123
1237
  });
1124
1238
  }
@@ -1143,14 +1257,13 @@ var Dialog = class _Dialog extends NanoEmitter {
1143
1257
  if (interactionKeys.includes(e.key)) {
1144
1258
  preventDefault && e.preventDefault();
1145
1259
  stopPropagation && e.stopPropagation();
1146
- } else
1147
- return;
1260
+ } else return;
1148
1261
  } else if (e instanceof MouseEvent) {
1149
1262
  preventDefault && e.preventDefault();
1150
1263
  stopPropagation && e.stopPropagation();
1151
1264
  }
1152
- (listenerOpts == null ? void 0 : listenerOpts.once) && e.type === "keydown" && elem.removeEventListener("click", proxListener, listenerOpts);
1153
- (listenerOpts == null ? void 0 : listenerOpts.once) && e.type === "click" && elem.removeEventListener("keydown", proxListener, listenerOpts);
1265
+ (listenerOpts == null ? undefined : listenerOpts.once) && e.type === "keydown" && elem.removeEventListener("click", proxListener, listenerOpts);
1266
+ (listenerOpts == null ? undefined : listenerOpts.once) && e.type === "click" && elem.removeEventListener("keydown", proxListener, listenerOpts);
1154
1267
  listener(e);
1155
1268
  };
1156
1269
  elem.addEventListener("click", proxListener, listenerOpts);
@@ -1160,8 +1273,8 @@ var Dialog = class _Dialog extends NanoEmitter {
1160
1273
  getDialogContent() {
1161
1274
  return __async(this, null, function* () {
1162
1275
  var _a, _b, _c, _d;
1163
- const header = (_b = (_a = this.options).renderHeader) == null ? void 0 : _b.call(_a);
1164
- const footer = (_d = (_c = this.options).renderFooter) == null ? void 0 : _d.call(_c);
1276
+ const header = (_b = (_a = this.options).renderHeader) == null ? undefined : _b.call(_a);
1277
+ const footer = (_d = (_c = this.options).renderFooter) == null ? undefined : _d.call(_c);
1165
1278
  const dialogWrapperEl = document.createElement("div");
1166
1279
  dialogWrapperEl.id = `uu-${this.id}-dialog`;
1167
1280
  dialogWrapperEl.classList.add("uu-dialog");
@@ -1227,7 +1340,7 @@ function insertValues(input, ...values) {
1227
1340
  return input.replace(/%\d/gm, (match) => {
1228
1341
  var _a, _b;
1229
1342
  const argIndex = Number(match.substring(1)) - 1;
1230
- return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
1343
+ return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? undefined : _b.toString();
1231
1344
  });
1232
1345
  }
1233
1346
  function pauseFor(time) {
@@ -1235,27 +1348,13 @@ function pauseFor(time) {
1235
1348
  setTimeout(() => res(), time);
1236
1349
  });
1237
1350
  }
1238
- function debounce(func, timeout = 300, edge = "falling") {
1239
- let id;
1240
- return function(...args) {
1241
- if (edge === "rising") {
1242
- if (!id) {
1243
- func.apply(this, args);
1244
- id = setTimeout(() => id = void 0, timeout);
1245
- }
1246
- } else {
1247
- clearTimeout(id);
1248
- id = setTimeout(() => func.apply(this, args), timeout);
1249
- }
1250
- };
1251
- }
1252
1351
  function fetchAdvanced(_0) {
1253
1352
  return __async(this, arguments, function* (input, options = {}) {
1254
1353
  var _a;
1255
1354
  const { timeout = 1e4 } = options;
1256
1355
  const { signal, abort } = new AbortController();
1257
- (_a = options.signal) == null ? void 0 : _a.addEventListener("abort", abort);
1258
- let signalOpts = {}, id = void 0;
1356
+ (_a = options.signal) == null ? undefined : _a.addEventListener("abort", abort);
1357
+ let signalOpts = {}, id = undefined;
1259
1358
  if (timeout >= 0) {
1260
1359
  id = setTimeout(() => abort(), timeout);
1261
1360
  signalOpts = { signal };
@@ -1270,6 +1369,18 @@ function fetchAdvanced(_0) {
1270
1369
  }
1271
1370
  });
1272
1371
  }
1372
+ function consumeGen(valGen) {
1373
+ return __async(this, null, function* () {
1374
+ return yield typeof valGen === "function" ? valGen() : valGen;
1375
+ });
1376
+ }
1377
+ function consumeStringGen(strGen) {
1378
+ return __async(this, null, function* () {
1379
+ return typeof strGen === "string" ? strGen : String(
1380
+ typeof strGen === "function" ? yield strGen() : strGen
1381
+ );
1382
+ });
1383
+ }
1273
1384
 
1274
1385
  // lib/SelectorObserver.ts
1275
1386
  var domLoaded = false;
@@ -1286,12 +1397,12 @@ var SelectorObserver = class {
1286
1397
  this.listenerMap = /* @__PURE__ */ new Map();
1287
1398
  const _a = options, {
1288
1399
  defaultDebounce,
1289
- defaultDebounceEdge,
1400
+ defaultDebounceType,
1290
1401
  disableOnNoListeners,
1291
1402
  enableOnAddListener
1292
1403
  } = _a, observerOptions = __objRest(_a, [
1293
1404
  "defaultDebounce",
1294
- "defaultDebounceEdge",
1405
+ "defaultDebounceType",
1295
1406
  "disableOnNoListeners",
1296
1407
  "enableOnAddListener"
1297
1408
  ]);
@@ -1301,7 +1412,7 @@ var SelectorObserver = class {
1301
1412
  }, observerOptions);
1302
1413
  this.customOptions = {
1303
1414
  defaultDebounce: defaultDebounce != null ? defaultDebounce : 0,
1304
- defaultDebounceEdge: defaultDebounceEdge != null ? defaultDebounceEdge : "rising",
1415
+ defaultDebounceType: defaultDebounceType != null ? defaultDebounceType : "immediate",
1305
1416
  disableOnNoListeners: disableOnNoListeners != null ? disableOnNoListeners : false,
1306
1417
  enableOnAddListener: enableOnAddListener != null ? enableOnAddListener : true
1307
1418
  };
@@ -1345,7 +1456,7 @@ var SelectorObserver = class {
1345
1456
  this.removeListener(selector, options);
1346
1457
  }
1347
1458
  }
1348
- if (((_a = this.listenerMap.get(selector)) == null ? void 0 : _a.length) === 0)
1459
+ if (((_a = this.listenerMap.get(selector)) == null ? undefined : _a.length) === 0)
1349
1460
  this.listenerMap.delete(selector);
1350
1461
  if (this.listenerMap.size === 0 && this.customOptions.disableOnNoListeners)
1351
1462
  this.disable();
@@ -1371,7 +1482,7 @@ var SelectorObserver = class {
1371
1482
  options.listener = debounce(
1372
1483
  options.listener,
1373
1484
  options.debounce || this.customOptions.defaultDebounce,
1374
- options.debounceEdge || this.customOptions.defaultDebounceEdge
1485
+ options.debounceType || this.customOptions.defaultDebounceType
1375
1486
  );
1376
1487
  }
1377
1488
  if (this.listenerMap.has(selector))
@@ -1389,7 +1500,7 @@ var SelectorObserver = class {
1389
1500
  if (!this.enabled)
1390
1501
  return;
1391
1502
  this.enabled = false;
1392
- (_a = this.observer) == null ? void 0 : _a.disconnect();
1503
+ (_a = this.observer) == null ? undefined : _a.disconnect();
1393
1504
  }
1394
1505
  /**
1395
1506
  * Enables or reenables the observation of the child elements.
@@ -1402,7 +1513,7 @@ var SelectorObserver = class {
1402
1513
  if (this.enabled || !baseElement)
1403
1514
  return false;
1404
1515
  this.enabled = true;
1405
- (_a = this.observer) == null ? void 0 : _a.observe(baseElement, this.observerOptions);
1516
+ (_a = this.observer) == null ? undefined : _a.observe(baseElement, this.observerOptions);
1406
1517
  if (immediatelyCheckSelectors)
1407
1518
  this.checkAllSelectors();
1408
1519
  return true;
@@ -1449,38 +1560,169 @@ var SelectorObserver = class {
1449
1560
 
1450
1561
  // lib/translation.ts
1451
1562
  var trans = {};
1452
- var curLang;
1453
- var trLang = (language, key, ...args) => {
1454
- var _a;
1455
- if (!language)
1456
- return key;
1457
- const trText = (_a = trans[language]) == null ? void 0 : _a[key];
1458
- if (!trText)
1459
- return key;
1460
- if (args.length > 0 && trText.match(/%\d/)) {
1461
- return insertValues(trText, ...args);
1462
- }
1463
- return trText;
1464
- };
1465
- function tr(key, ...args) {
1466
- return trLang(curLang, key, ...args);
1563
+ var valTransforms = [];
1564
+ var fallbackLang;
1565
+ function translate(language, key, ...trArgs) {
1566
+ if (typeof language !== "string")
1567
+ language = fallbackLang != null ? fallbackLang : "";
1568
+ const trObj = trans[language];
1569
+ if (typeof language !== "string" || language.length === 0 || typeof trObj !== "object" || trObj === null)
1570
+ return fallbackLang ? translate(fallbackLang, key, ...trArgs) : key;
1571
+ const transformTrVal = (trKey, trValue) => {
1572
+ const tfs = valTransforms.filter(({ regex }) => new RegExp(regex).test(trValue));
1573
+ if (tfs.length === 0)
1574
+ return trValue;
1575
+ let retStr = String(trValue);
1576
+ for (const tf of tfs) {
1577
+ const re = new RegExp(tf.regex);
1578
+ const matches = [];
1579
+ let execRes;
1580
+ while ((execRes = re.exec(trValue)) !== null) {
1581
+ if (matches.some((m) => m[0] === (execRes == null ? undefined : execRes[0])))
1582
+ break;
1583
+ matches.push(execRes);
1584
+ }
1585
+ retStr = String(tf.fn({
1586
+ language,
1587
+ trValue,
1588
+ currentValue: retStr,
1589
+ matches,
1590
+ trKey,
1591
+ trArgs
1592
+ }));
1593
+ }
1594
+ return retStr;
1595
+ };
1596
+ const keyParts = key.split(".");
1597
+ let value = trObj;
1598
+ for (const part of keyParts) {
1599
+ if (typeof value !== "object" || value === null) {
1600
+ value = undefined;
1601
+ break;
1602
+ }
1603
+ value = value == null ? undefined : value[part];
1604
+ }
1605
+ if (typeof value === "string")
1606
+ return transformTrVal(key, value);
1607
+ value = trObj == null ? undefined : trObj[key];
1608
+ if (typeof value === "string")
1609
+ return transformTrVal(key, value);
1610
+ return fallbackLang ? translate(fallbackLang, key, ...trArgs) : key;
1467
1611
  }
1468
- tr.forLang = trLang;
1469
- tr.addLanguage = (language, translations) => {
1470
- trans[language] = translations;
1471
- };
1472
- tr.setLanguage = (language) => {
1473
- curLang = language;
1474
- };
1475
- tr.getLanguage = () => {
1476
- return curLang;
1612
+ function trFor(language, key, ...args) {
1613
+ const txt = translate(language, key, ...args);
1614
+ if (txt === key)
1615
+ return fallbackLang ? translate(fallbackLang, key, ...args) : key;
1616
+ return txt;
1617
+ }
1618
+ function useTr(language) {
1619
+ return (key, ...args) => translate(language, key, ...args);
1620
+ }
1621
+ function hasKey(language = fallbackLang != null ? fallbackLang : "", key) {
1622
+ return tr.for(language, key) !== key;
1623
+ }
1624
+ function addTranslations(language, translations) {
1625
+ trans[language] = JSON.parse(JSON.stringify(translations));
1626
+ }
1627
+ function getTranslations(language = fallbackLang != null ? fallbackLang : "") {
1628
+ return trans[language];
1629
+ }
1630
+ var deleteTranslations = (language) => {
1631
+ if (language in trans) {
1632
+ delete trans[language];
1633
+ return true;
1634
+ }
1635
+ return false;
1477
1636
  };
1478
- tr.getTranslations = (language) => {
1479
- return trans[language != null ? language : curLang];
1637
+ function setFallbackLanguage(fallbackLanguage) {
1638
+ fallbackLang = fallbackLanguage;
1639
+ }
1640
+ function getFallbackLanguage() {
1641
+ return fallbackLang;
1642
+ }
1643
+ function addTransform(transform) {
1644
+ const [pattern, fn] = transform;
1645
+ valTransforms.push({
1646
+ fn,
1647
+ regex: typeof pattern === "string" ? new RegExp(pattern, "gm") : pattern
1648
+ });
1649
+ }
1650
+ function deleteTransform(patternOrFn) {
1651
+ const idx = valTransforms.findIndex(
1652
+ (t) => typeof patternOrFn === "function" ? t.fn === patternOrFn : typeof patternOrFn === "string" ? t.regex.source === patternOrFn : t.regex === patternOrFn
1653
+ );
1654
+ if (idx !== -1) {
1655
+ valTransforms.splice(idx, 1);
1656
+ return true;
1657
+ }
1658
+ return false;
1659
+ }
1660
+ var templateLiteralTransform = [
1661
+ /\$\{([a-zA-Z0-9$_-]+)\}/gm,
1662
+ ({ matches, trArgs, trValue }) => {
1663
+ const patternStart = "${", patternEnd = "}", patternRegex = /\$\{.+\}/m;
1664
+ let str = String(trValue);
1665
+ const eachKeyInTrString = (keys) => keys.every((key) => trValue.includes(`${patternStart}${key}${patternEnd}`));
1666
+ const namedMapping = () => {
1667
+ var _a;
1668
+ if (!str.includes(patternStart) || typeof trArgs[0] === "undefined" || typeof trArgs[0] !== "object" || !eachKeyInTrString(Object.keys((_a = trArgs[0]) != null ? _a : {})))
1669
+ return;
1670
+ for (const match of matches) {
1671
+ const repl = match[1] !== undefined ? trArgs[0][match[1]] : undefined;
1672
+ if (typeof repl !== "undefined")
1673
+ str = str.replace(match[0], String(repl));
1674
+ }
1675
+ };
1676
+ const positionalMapping = () => {
1677
+ if (!patternRegex.test(str) || !trArgs[0])
1678
+ return;
1679
+ let matchNum = -1;
1680
+ for (const match of matches) {
1681
+ matchNum++;
1682
+ if (typeof trArgs[matchNum] !== "undefined")
1683
+ str = str.replace(match[0], String(trArgs[matchNum]));
1684
+ }
1685
+ };
1686
+ const isArgsObject = trArgs[0] && typeof trArgs[0] === "object" && trArgs[0] !== null && String(trArgs[0]).startsWith("[object");
1687
+ if (isArgsObject && eachKeyInTrString(Object.keys(trArgs[0])))
1688
+ namedMapping();
1689
+ else
1690
+ positionalMapping();
1691
+ return str;
1692
+ }
1693
+ ];
1694
+ var percentTransform = [
1695
+ /\$\{([a-zA-Z0-9$_-]+)\}/gm,
1696
+ ({ matches, trArgs, trValue }) => {
1697
+ let str = String(trValue);
1698
+ for (const match of matches) {
1699
+ const repl = match[1] !== undefined ? trArgs[0][match[1]] : undefined;
1700
+ if (typeof repl !== "undefined")
1701
+ str = str.replace(match[0], String(repl));
1702
+ }
1703
+ return str;
1704
+ }
1705
+ ];
1706
+ var tr = {
1707
+ for: (...params) => trFor(...params),
1708
+ use: (...params) => useTr(...params),
1709
+ hasKey: (language = fallbackLang != null ? fallbackLang : "", key) => hasKey(language, key),
1710
+ addTranslations,
1711
+ getTranslations,
1712
+ deleteTranslations,
1713
+ setFallbackLanguage,
1714
+ getFallbackLanguage,
1715
+ addTransform,
1716
+ deleteTransform,
1717
+ transforms: {
1718
+ templateLiteral: templateLiteralTransform,
1719
+ percent: percentTransform
1720
+ }
1480
1721
  };
1481
1722
 
1482
1723
  exports.DataStore = DataStore;
1483
1724
  exports.DataStoreSerializer = DataStoreSerializer;
1725
+ exports.Debouncer = Debouncer;
1484
1726
  exports.Dialog = Dialog;
1485
1727
  exports.NanoEmitter = NanoEmitter;
1486
1728
  exports.SelectorObserver = SelectorObserver;
@@ -1490,11 +1732,14 @@ exports.autoPlural = autoPlural;
1490
1732
  exports.clamp = clamp;
1491
1733
  exports.compress = compress;
1492
1734
  exports.computeHash = computeHash;
1735
+ exports.consumeGen = consumeGen;
1736
+ exports.consumeStringGen = consumeStringGen;
1493
1737
  exports.darkenColor = darkenColor;
1494
1738
  exports.debounce = debounce;
1495
1739
  exports.decompress = decompress;
1496
1740
  exports.defaultDialogCss = defaultDialogCss;
1497
1741
  exports.defaultStrings = defaultStrings;
1742
+ exports.digitCount = digitCount;
1498
1743
  exports.fetchAdvanced = fetchAdvanced;
1499
1744
  exports.getSiblingsFrame = getSiblingsFrame;
1500
1745
  exports.getUnsafeWindow = getUnsafeWindow;