@sv443-network/userutils 8.4.0 → 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
@@ -94,7 +94,7 @@ 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;
@@ -114,14 +114,14 @@ function randomItem(array) {
114
114
  }
115
115
  function randomItemIndex(array) {
116
116
  if (array.length === 0)
117
- return [void 0, void 0];
117
+ return [undefined, undefined];
118
118
  const idx = randRange(array.length - 1);
119
119
  return [array[idx], idx];
120
120
  }
121
121
  function takeRandomItem(arr) {
122
122
  const [itm, idx] = randomItemIndex(arr);
123
- if (idx === void 0)
124
- return void 0;
123
+ if (idx === undefined)
124
+ return undefined;
125
125
  arr.splice(idx, 1);
126
126
  return itm;
127
127
  }
@@ -139,7 +139,7 @@ function randomizeArray(array) {
139
139
  // lib/colors.ts
140
140
  function hexToRgb(hex) {
141
141
  hex = (hex.startsWith("#") ? hex.slice(1) : hex).trim();
142
- 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;
143
143
  if (!isNaN(Number(a)))
144
144
  hex = hex.slice(0, -(hex.length / 4));
145
145
  if (hex.length === 3 || hex.length === 4)
@@ -148,7 +148,7 @@ function hexToRgb(hex) {
148
148
  const r = bigint >> 16 & 255;
149
149
  const g = bigint >> 8 & 255;
150
150
  const b = bigint & 255;
151
- 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];
152
152
  }
153
153
  function rgbToHex(red, green, blue, alpha, withHash = true, upperCase = false) {
154
154
  const toHexVal = (n) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, "0")[upperCase ? "toUpperCase" : "toLowerCase"]();
@@ -171,7 +171,7 @@ function darkenColor(color, percent, upperCase = false) {
171
171
  if (isHexCol)
172
172
  [r, g, b, a] = hexToRgb(color);
173
173
  else if (color.startsWith("rgb")) {
174
- 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);
175
175
  if (!rgbValues)
176
176
  throw new Error("Invalid RGB/RGBA color format");
177
177
  [r, g, b, a] = rgbValues;
@@ -219,26 +219,32 @@ function preloadImages(srcUrls, rejects = false) {
219
219
  }));
220
220
  return Promise.allSettled(promises);
221
221
  }
222
- function openInNewTab(href, background) {
222
+ function openInNewTab(href, background, additionalProps) {
223
+ var _a;
223
224
  try {
224
- GM.openInTab(href, background);
225
+ (_a = GM.openInTab) == null ? void 0 : _a.call(GM, href, background);
225
226
  } catch (e) {
226
227
  const openElem = document.createElement("a");
227
- Object.assign(openElem, {
228
+ Object.assign(openElem, __spreadValues({
228
229
  className: "userutils-open-in-new-tab",
229
230
  target: "_blank",
230
231
  rel: "noopener noreferrer",
232
+ tabIndex: -1,
233
+ ariaHidden: "true",
231
234
  href
235
+ }, additionalProps));
236
+ Object.assign(openElem.style, {
237
+ display: "none",
238
+ pointerEvents: "none"
232
239
  });
233
- openElem.style.display = "none";
234
240
  document.body.appendChild(openElem);
235
241
  openElem.click();
236
- setTimeout(openElem.remove, 50);
242
+ setTimeout(openElem.remove, 0);
237
243
  }
238
244
  }
239
245
  function interceptEvent(eventObject, eventName, predicate = () => true) {
240
246
  var _a;
241
- 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")
242
248
  throw new Error("Intercepting window events is not supported on FireMonkey due to the isolated context the userscript runs in.");
243
249
  Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 100);
244
250
  if (isNaN(Error.stackTraceLimit))
@@ -246,7 +252,7 @@ function interceptEvent(eventObject, eventName, predicate = () => true) {
246
252
  (function(original) {
247
253
  eventObject.__proto__.addEventListener = function(...args) {
248
254
  var _a2, _b;
249
- 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;
250
256
  args[1] = function(...a) {
251
257
  if (args[0] === eventName && predicate(Array.isArray(a) ? a[0] : a))
252
258
  return;
@@ -274,12 +280,12 @@ function observeElementProp(element, property, callback) {
274
280
  Object.defineProperty(element, property, {
275
281
  get: function() {
276
282
  var _a;
277
- 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);
278
284
  },
279
285
  set: function() {
280
286
  var _a;
281
287
  const oldValue = this[property];
282
- (_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);
283
289
  const newValue = this[property];
284
290
  if (typeof callback === "function") {
285
291
  callback.bind(this, oldValue, newValue);
@@ -291,7 +297,7 @@ function observeElementProp(element, property, callback) {
291
297
  }
292
298
  function getSiblingsFrame(refElement, siblingAmount, refElementAlignment = "center-top", includeRef = true) {
293
299
  var _a, _b;
294
- 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 : []];
295
301
  const elemSiblIdx = siblings.indexOf(refElement);
296
302
  if (elemSiblIdx === -1)
297
303
  throw new Error("Element doesn't have a parent node");
@@ -313,12 +319,12 @@ function getSiblingsFrame(refElement, siblingAmount, refElementAlignment = "cent
313
319
  var ttPolicy;
314
320
  function setInnerHtmlUnsafe(element, html) {
315
321
  var _a, _b, _c;
316
- 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") {
317
323
  ttPolicy = window.trustedTypes.createPolicy("_uu_set_innerhtml_unsafe", {
318
324
  createHTML: (unsafeHtml) => unsafeHtml
319
325
  });
320
326
  }
321
- 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;
322
328
  return element;
323
329
  }
324
330
 
@@ -394,8 +400,8 @@ var DataStore = class {
394
400
  * Creates an instance of DataStore to manage a sync & async database that is cached in memory and persistently saved across sessions.
395
401
  * Supports migrating data from older versions to newer ones and populating the cache with default data if no persistent data is found.
396
402
  *
397
- * ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue` if the storageMethod is left as the default of `"GM"`
398
- * ⚠️ 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`
399
405
  *
400
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.)
401
407
  * @param options The options for this DataStore instance
@@ -502,7 +508,7 @@ var DataStore = class {
502
508
  * The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
503
509
  * Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
504
510
  *
505
- * ⚠️ 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"`
506
512
  */
507
513
  deleteData() {
508
514
  return __async(this, null, function* () {
@@ -567,7 +573,7 @@ var DataStore = class {
567
573
  const data = yield this.getValue(`_uucfg-${id}`, JSON.stringify(this.defaultData));
568
574
  const fmtVer = Number(yield this.getValue(`_uucfgver-${id}`, NaN));
569
575
  const isEncoded = Boolean(yield this.getValue(`_uucfgenc-${id}`, false));
570
- if (data === void 0 || isNaN(fmtVer))
576
+ if (data === undefined || isNaN(fmtVer))
571
577
  return;
572
578
  const parsed = yield this.deserializeData(data, isEncoded);
573
579
  yield Promise.allSettled([
@@ -597,7 +603,7 @@ var DataStore = class {
597
603
  /** Deserializes the data using the optional this.decodeData() and returns it as a JSON object */
598
604
  deserializeData(data, useEncoding = true) {
599
605
  return __async(this, null, function* () {
600
- let decRes = this.encodingEnabled() && useEncoding ? this.decodeData(data) : void 0;
606
+ let decRes = this.encodingEnabled() && useEncoding ? this.decodeData(data) : undefined;
601
607
  if (decRes instanceof Promise)
602
608
  decRes = yield decRes;
603
609
  return JSON.parse(decRes != null ? decRes : data);
@@ -609,7 +615,7 @@ var DataStore = class {
609
615
  return JSON.parse(JSON.stringify(obj));
610
616
  }
611
617
  //#region storage
612
- /** 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 */
613
619
  getValue(name, defaultValue) {
614
620
  return __async(this, null, function* () {
615
621
  var _a, _b;
@@ -624,7 +630,7 @@ var DataStore = class {
624
630
  });
625
631
  }
626
632
  /**
627
- * 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.
628
634
  * The default storage engines will stringify all passed values like numbers or booleans, so be aware of that.
629
635
  */
630
636
  setValue(name, value) {
@@ -639,7 +645,7 @@ var DataStore = class {
639
645
  }
640
646
  });
641
647
  }
642
- /** 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 */
643
649
  deleteValue(name) {
644
650
  return __async(this, null, function* () {
645
651
  switch (this.storageMethod) {
@@ -677,7 +683,7 @@ var DataStoreSerializer = class {
677
683
  serializeStore(storeInst) {
678
684
  return __async(this, null, function* () {
679
685
  const data = storeInst.encodingEnabled() ? yield storeInst.encodeData(JSON.stringify(storeInst.getData())) : JSON.stringify(storeInst.getData());
680
- const checksum = this.options.addChecksum ? yield this.calcChecksum(data) : void 0;
686
+ const checksum = this.options.addChecksum ? yield this.calcChecksum(data) : undefined;
681
687
  return {
682
688
  id: storeInst.id,
683
689
  data,
@@ -783,7 +789,7 @@ var NanoEmitter = class {
783
789
  let unsub;
784
790
  const onceProxy = (...args) => {
785
791
  unsub();
786
- cb == null ? void 0 : cb(...args);
792
+ cb == null ? undefined : cb(...args);
787
793
  resolve(args);
788
794
  };
789
795
  unsub = this.on(event, onceProxy);
@@ -805,6 +811,106 @@ var NanoEmitter = class {
805
811
  }
806
812
  };
807
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
+
808
914
  // lib/Dialog.ts
809
915
  var defaultDialogCss = `.uu-no-select {
810
916
  user-select: none;
@@ -1022,7 +1128,7 @@ var Dialog = class _Dialog extends NanoEmitter {
1022
1128
  `#uu-style-dialog-${this.id}`
1023
1129
  ];
1024
1130
  for (const sel of clearSelectors)
1025
- (_a = document.querySelector(sel)) == null ? void 0 : _a.remove();
1131
+ (_a = document.querySelector(sel)) == null ? undefined : _a.remove();
1026
1132
  this.events.emit("clear");
1027
1133
  }
1028
1134
  /** Clears the DOM of the dialog and then renders it again */
@@ -1039,8 +1145,8 @@ var Dialog = class _Dialog extends NanoEmitter {
1039
1145
  open(e) {
1040
1146
  return __async(this, null, function* () {
1041
1147
  var _a;
1042
- e == null ? void 0 : e.preventDefault();
1043
- e == null ? void 0 : e.stopImmediatePropagation();
1148
+ e == null ? undefined : e.preventDefault();
1149
+ e == null ? undefined : e.stopImmediatePropagation();
1044
1150
  if (this.isOpen())
1045
1151
  return;
1046
1152
  this.dialogOpen = true;
@@ -1058,7 +1164,7 @@ var Dialog = class _Dialog extends NanoEmitter {
1058
1164
  openDialogs.unshift(this.id);
1059
1165
  for (const dialogId of openDialogs)
1060
1166
  if (dialogId !== this.id)
1061
- (_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");
1062
1168
  document.body.classList.remove("uu-no-select");
1063
1169
  document.body.setAttribute("inert", "true");
1064
1170
  this.events.emit("open");
@@ -1068,8 +1174,8 @@ var Dialog = class _Dialog extends NanoEmitter {
1068
1174
  /** Closes the dialog - prevents default action and immediate propagation of the passed event */
1069
1175
  close(e) {
1070
1176
  var _a, _b;
1071
- e == null ? void 0 : e.preventDefault();
1072
- e == null ? void 0 : e.stopImmediatePropagation();
1177
+ e == null ? undefined : e.preventDefault();
1178
+ e == null ? undefined : e.stopImmediatePropagation();
1073
1179
  if (!this.isOpen())
1074
1180
  return;
1075
1181
  this.dialogOpen = false;
@@ -1082,7 +1188,7 @@ var Dialog = class _Dialog extends NanoEmitter {
1082
1188
  openDialogs.splice(openDialogs.indexOf(this.id), 1);
1083
1189
  exports.currentDialogId = (_a = openDialogs[0]) != null ? _a : null;
1084
1190
  if (exports.currentDialogId)
1085
- (_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");
1086
1192
  if (openDialogs.length === 0) {
1087
1193
  document.body.classList.add("uu-no-select");
1088
1194
  document.body.removeAttribute("inert");
@@ -1126,7 +1232,7 @@ var Dialog = class _Dialog extends NanoEmitter {
1126
1232
  if (this.options.closeOnBgClick) {
1127
1233
  bgElem.addEventListener("click", (e) => {
1128
1234
  var _a;
1129
- 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`)
1130
1236
  this.close(e);
1131
1237
  });
1132
1238
  }
@@ -1156,8 +1262,8 @@ var Dialog = class _Dialog extends NanoEmitter {
1156
1262
  preventDefault && e.preventDefault();
1157
1263
  stopPropagation && e.stopPropagation();
1158
1264
  }
1159
- (listenerOpts == null ? void 0 : listenerOpts.once) && e.type === "keydown" && elem.removeEventListener("click", proxListener, listenerOpts);
1160
- (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);
1161
1267
  listener(e);
1162
1268
  };
1163
1269
  elem.addEventListener("click", proxListener, listenerOpts);
@@ -1167,8 +1273,8 @@ var Dialog = class _Dialog extends NanoEmitter {
1167
1273
  getDialogContent() {
1168
1274
  return __async(this, null, function* () {
1169
1275
  var _a, _b, _c, _d;
1170
- const header = (_b = (_a = this.options).renderHeader) == null ? void 0 : _b.call(_a);
1171
- 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);
1172
1278
  const dialogWrapperEl = document.createElement("div");
1173
1279
  dialogWrapperEl.id = `uu-${this.id}-dialog`;
1174
1280
  dialogWrapperEl.classList.add("uu-dialog");
@@ -1234,7 +1340,7 @@ function insertValues(input, ...values) {
1234
1340
  return input.replace(/%\d/gm, (match) => {
1235
1341
  var _a, _b;
1236
1342
  const argIndex = Number(match.substring(1)) - 1;
1237
- 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();
1238
1344
  });
1239
1345
  }
1240
1346
  function pauseFor(time) {
@@ -1242,27 +1348,13 @@ function pauseFor(time) {
1242
1348
  setTimeout(() => res(), time);
1243
1349
  });
1244
1350
  }
1245
- function debounce(func, timeout = 300, edge = "falling") {
1246
- let id;
1247
- return function(...args) {
1248
- if (edge === "rising") {
1249
- if (!id) {
1250
- func.apply(this, args);
1251
- id = setTimeout(() => id = void 0, timeout);
1252
- }
1253
- } else {
1254
- clearTimeout(id);
1255
- id = setTimeout(() => func.apply(this, args), timeout);
1256
- }
1257
- };
1258
- }
1259
1351
  function fetchAdvanced(_0) {
1260
1352
  return __async(this, arguments, function* (input, options = {}) {
1261
1353
  var _a;
1262
1354
  const { timeout = 1e4 } = options;
1263
1355
  const { signal, abort } = new AbortController();
1264
- (_a = options.signal) == null ? void 0 : _a.addEventListener("abort", abort);
1265
- let signalOpts = {}, id = void 0;
1356
+ (_a = options.signal) == null ? undefined : _a.addEventListener("abort", abort);
1357
+ let signalOpts = {}, id = undefined;
1266
1358
  if (timeout >= 0) {
1267
1359
  id = setTimeout(() => abort(), timeout);
1268
1360
  signalOpts = { signal };
@@ -1305,12 +1397,12 @@ var SelectorObserver = class {
1305
1397
  this.listenerMap = /* @__PURE__ */ new Map();
1306
1398
  const _a = options, {
1307
1399
  defaultDebounce,
1308
- defaultDebounceEdge,
1400
+ defaultDebounceType,
1309
1401
  disableOnNoListeners,
1310
1402
  enableOnAddListener
1311
1403
  } = _a, observerOptions = __objRest(_a, [
1312
1404
  "defaultDebounce",
1313
- "defaultDebounceEdge",
1405
+ "defaultDebounceType",
1314
1406
  "disableOnNoListeners",
1315
1407
  "enableOnAddListener"
1316
1408
  ]);
@@ -1320,7 +1412,7 @@ var SelectorObserver = class {
1320
1412
  }, observerOptions);
1321
1413
  this.customOptions = {
1322
1414
  defaultDebounce: defaultDebounce != null ? defaultDebounce : 0,
1323
- defaultDebounceEdge: defaultDebounceEdge != null ? defaultDebounceEdge : "rising",
1415
+ defaultDebounceType: defaultDebounceType != null ? defaultDebounceType : "immediate",
1324
1416
  disableOnNoListeners: disableOnNoListeners != null ? disableOnNoListeners : false,
1325
1417
  enableOnAddListener: enableOnAddListener != null ? enableOnAddListener : true
1326
1418
  };
@@ -1364,7 +1456,7 @@ var SelectorObserver = class {
1364
1456
  this.removeListener(selector, options);
1365
1457
  }
1366
1458
  }
1367
- if (((_a = this.listenerMap.get(selector)) == null ? void 0 : _a.length) === 0)
1459
+ if (((_a = this.listenerMap.get(selector)) == null ? undefined : _a.length) === 0)
1368
1460
  this.listenerMap.delete(selector);
1369
1461
  if (this.listenerMap.size === 0 && this.customOptions.disableOnNoListeners)
1370
1462
  this.disable();
@@ -1390,7 +1482,7 @@ var SelectorObserver = class {
1390
1482
  options.listener = debounce(
1391
1483
  options.listener,
1392
1484
  options.debounce || this.customOptions.defaultDebounce,
1393
- options.debounceEdge || this.customOptions.defaultDebounceEdge
1485
+ options.debounceType || this.customOptions.defaultDebounceType
1394
1486
  );
1395
1487
  }
1396
1488
  if (this.listenerMap.has(selector))
@@ -1408,7 +1500,7 @@ var SelectorObserver = class {
1408
1500
  if (!this.enabled)
1409
1501
  return;
1410
1502
  this.enabled = false;
1411
- (_a = this.observer) == null ? void 0 : _a.disconnect();
1503
+ (_a = this.observer) == null ? undefined : _a.disconnect();
1412
1504
  }
1413
1505
  /**
1414
1506
  * Enables or reenables the observation of the child elements.
@@ -1421,7 +1513,7 @@ var SelectorObserver = class {
1421
1513
  if (this.enabled || !baseElement)
1422
1514
  return false;
1423
1515
  this.enabled = true;
1424
- (_a = this.observer) == null ? void 0 : _a.observe(baseElement, this.observerOptions);
1516
+ (_a = this.observer) == null ? undefined : _a.observe(baseElement, this.observerOptions);
1425
1517
  if (immediatelyCheckSelectors)
1426
1518
  this.checkAllSelectors();
1427
1519
  return true;
@@ -1468,43 +1560,169 @@ var SelectorObserver = class {
1468
1560
 
1469
1561
  // lib/translation.ts
1470
1562
  var trans = {};
1471
- var curLang = "";
1472
- function translate(language, key, ...args) {
1473
- var _a;
1474
- const trObj = (_a = trans[language]) == null ? void 0 : _a.data;
1475
- if (typeof language !== "string" || typeof trObj !== "object" || trObj === null)
1476
- return key;
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
+ };
1477
1596
  const keyParts = key.split(".");
1478
1597
  let value = trObj;
1479
1598
  for (const part of keyParts) {
1480
- if (typeof value !== "object" || value === null)
1599
+ if (typeof value !== "object" || value === null) {
1600
+ value = undefined;
1481
1601
  break;
1482
- value = value == null ? void 0 : value[part];
1602
+ }
1603
+ value = value == null ? undefined : value[part];
1483
1604
  }
1484
1605
  if (typeof value === "string")
1485
- return insertValues(value, args);
1486
- value = trObj == null ? void 0 : trObj[key];
1606
+ return transformTrVal(key, value);
1607
+ value = trObj == null ? undefined : trObj[key];
1487
1608
  if (typeof value === "string")
1488
- return insertValues(value, args);
1489
- return key;
1609
+ return transformTrVal(key, value);
1610
+ return fallbackLang ? translate(fallbackLang, key, ...trArgs) : key;
1490
1611
  }
1491
- var tr = (key, ...args) => translate(curLang, key, ...args);
1492
- tr.forLang = translate;
1493
- tr.addLanguage = (language, translations) => {
1494
- trans[language] = translations;
1495
- };
1496
- tr.setLanguage = (language) => {
1497
- curLang = language;
1498
- };
1499
- tr.getLanguage = () => {
1500
- 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;
1501
1636
  };
1502
- tr.getTranslations = (language) => {
1503
- 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
+ }
1504
1721
  };
1505
1722
 
1506
1723
  exports.DataStore = DataStore;
1507
1724
  exports.DataStoreSerializer = DataStoreSerializer;
1725
+ exports.Debouncer = Debouncer;
1508
1726
  exports.Dialog = Dialog;
1509
1727
  exports.NanoEmitter = NanoEmitter;
1510
1728
  exports.SelectorObserver = SelectorObserver;