@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.
@@ -7,8 +7,8 @@
7
7
 
8
8
  // ==UserLibrary==
9
9
  // @name UserUtils
10
- // @description Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, create persistent & synchronous data stores, modify the DOM more easily and more
11
- // @version 8.4.0
10
+ // @description Lightweight library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, create persistent & synchronous data stores, modify the DOM more easily and much more
11
+ // @version 9.0.0
12
12
  // @license MIT
13
13
  // @copyright Sv443 (https://github.com/Sv443)
14
14
 
@@ -112,7 +112,7 @@ var UserUtils = (function (exports) {
112
112
  crypto.getRandomValues(uintArr);
113
113
  return Number(Array.from(
114
114
  uintArr,
115
- (v) => Math.round(mapRange(v, 0, 255, min, max)).toString(10).substring(0, 1)
115
+ (v) => Math.round(mapRange(v, 0, 255, min, max)).toString(10)
116
116
  ).join(""));
117
117
  } else
118
118
  return Math.floor(Math.random() * (max - min + 1)) + min;
@@ -132,14 +132,14 @@ var UserUtils = (function (exports) {
132
132
  }
133
133
  function randomItemIndex(array) {
134
134
  if (array.length === 0)
135
- return [void 0, void 0];
135
+ return [undefined, undefined];
136
136
  const idx = randRange(array.length - 1);
137
137
  return [array[idx], idx];
138
138
  }
139
139
  function takeRandomItem(arr) {
140
140
  const [itm, idx] = randomItemIndex(arr);
141
- if (idx === void 0)
142
- return void 0;
141
+ if (idx === undefined)
142
+ return undefined;
143
143
  arr.splice(idx, 1);
144
144
  return itm;
145
145
  }
@@ -157,7 +157,7 @@ var UserUtils = (function (exports) {
157
157
  // lib/colors.ts
158
158
  function hexToRgb(hex) {
159
159
  hex = (hex.startsWith("#") ? hex.slice(1) : hex).trim();
160
- const a = hex.length === 8 || hex.length === 4 ? parseInt(hex.slice(-(hex.length / 4)), 16) / (hex.length === 8 ? 255 : 15) : void 0;
160
+ const a = hex.length === 8 || hex.length === 4 ? parseInt(hex.slice(-(hex.length / 4)), 16) / (hex.length === 8 ? 255 : 15) : undefined;
161
161
  if (!isNaN(Number(a)))
162
162
  hex = hex.slice(0, -(hex.length / 4));
163
163
  if (hex.length === 3 || hex.length === 4)
@@ -166,7 +166,7 @@ var UserUtils = (function (exports) {
166
166
  const r = bigint >> 16 & 255;
167
167
  const g = bigint >> 8 & 255;
168
168
  const b = bigint & 255;
169
- return [clamp(r, 0, 255), clamp(g, 0, 255), clamp(b, 0, 255), typeof a === "number" ? clamp(a, 0, 1) : void 0];
169
+ return [clamp(r, 0, 255), clamp(g, 0, 255), clamp(b, 0, 255), typeof a === "number" ? clamp(a, 0, 1) : undefined];
170
170
  }
171
171
  function rgbToHex(red, green, blue, alpha, withHash = true, upperCase = false) {
172
172
  const toHexVal = (n) => clamp(Math.round(n), 0, 255).toString(16).padStart(2, "0")[upperCase ? "toUpperCase" : "toLowerCase"]();
@@ -189,7 +189,7 @@ var UserUtils = (function (exports) {
189
189
  if (isHexCol)
190
190
  [r, g, b, a] = hexToRgb(color);
191
191
  else if (color.startsWith("rgb")) {
192
- const rgbValues = (_a = color.match(/\d+(\.\d+)?/g)) == null ? void 0 : _a.map(Number);
192
+ const rgbValues = (_a = color.match(/\d+(\.\d+)?/g)) == null ? undefined : _a.map(Number);
193
193
  if (!rgbValues)
194
194
  throw new Error("Invalid RGB/RGBA color format");
195
195
  [r, g, b, a] = rgbValues;
@@ -237,26 +237,32 @@ var UserUtils = (function (exports) {
237
237
  }));
238
238
  return Promise.allSettled(promises);
239
239
  }
240
- function openInNewTab(href, background) {
240
+ function openInNewTab(href, background, additionalProps) {
241
+ var _a;
241
242
  try {
242
- GM.openInTab(href, background);
243
+ (_a = GM.openInTab) == null ? void 0 : _a.call(GM, href, background);
243
244
  } catch (e) {
244
245
  const openElem = document.createElement("a");
245
- Object.assign(openElem, {
246
+ Object.assign(openElem, __spreadValues({
246
247
  className: "userutils-open-in-new-tab",
247
248
  target: "_blank",
248
249
  rel: "noopener noreferrer",
250
+ tabIndex: -1,
251
+ ariaHidden: "true",
249
252
  href
253
+ }, additionalProps));
254
+ Object.assign(openElem.style, {
255
+ display: "none",
256
+ pointerEvents: "none"
250
257
  });
251
- openElem.style.display = "none";
252
258
  document.body.appendChild(openElem);
253
259
  openElem.click();
254
- setTimeout(openElem.remove, 50);
260
+ setTimeout(openElem.remove, 0);
255
261
  }
256
262
  }
257
263
  function interceptEvent(eventObject, eventName, predicate = () => true) {
258
264
  var _a;
259
- if ((eventObject === window || eventObject === getUnsafeWindow()) && ((_a = GM == null ? void 0 : GM.info) == null ? void 0 : _a.scriptHandler) && GM.info.scriptHandler === "FireMonkey")
265
+ if ((eventObject === window || eventObject === getUnsafeWindow()) && ((_a = GM == null ? undefined : GM.info) == null ? undefined : _a.scriptHandler) && GM.info.scriptHandler === "FireMonkey")
260
266
  throw new Error("Intercepting window events is not supported on FireMonkey due to the isolated context the userscript runs in.");
261
267
  Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 100);
262
268
  if (isNaN(Error.stackTraceLimit))
@@ -264,7 +270,7 @@ var UserUtils = (function (exports) {
264
270
  (function(original) {
265
271
  eventObject.__proto__.addEventListener = function(...args) {
266
272
  var _a2, _b;
267
- const origListener = typeof args[1] === "function" ? args[1] : (_b = (_a2 = args[1]) == null ? void 0 : _a2.handleEvent) != null ? _b : () => void 0;
273
+ const origListener = typeof args[1] === "function" ? args[1] : (_b = (_a2 = args[1]) == null ? undefined : _a2.handleEvent) != null ? _b : () => undefined;
268
274
  args[1] = function(...a) {
269
275
  if (args[0] === eventName && predicate(Array.isArray(a) ? a[0] : a))
270
276
  return;
@@ -292,12 +298,12 @@ var UserUtils = (function (exports) {
292
298
  Object.defineProperty(element, property, {
293
299
  get: function() {
294
300
  var _a;
295
- return (_a = descriptor == null ? void 0 : descriptor.get) == null ? void 0 : _a.apply(this, arguments);
301
+ return (_a = descriptor == null ? undefined : descriptor.get) == null ? undefined : _a.apply(this, arguments);
296
302
  },
297
303
  set: function() {
298
304
  var _a;
299
305
  const oldValue = this[property];
300
- (_a = descriptor == null ? void 0 : descriptor.set) == null ? void 0 : _a.apply(this, arguments);
306
+ (_a = descriptor == null ? undefined : descriptor.set) == null ? undefined : _a.apply(this, arguments);
301
307
  const newValue = this[property];
302
308
  if (typeof callback === "function") {
303
309
  callback.bind(this, oldValue, newValue);
@@ -309,7 +315,7 @@ var UserUtils = (function (exports) {
309
315
  }
310
316
  function getSiblingsFrame(refElement, siblingAmount, refElementAlignment = "center-top", includeRef = true) {
311
317
  var _a, _b;
312
- const siblings = [...(_b = (_a = refElement.parentNode) == null ? void 0 : _a.childNodes) != null ? _b : []];
318
+ const siblings = [...(_b = (_a = refElement.parentNode) == null ? undefined : _a.childNodes) != null ? _b : []];
313
319
  const elemSiblIdx = siblings.indexOf(refElement);
314
320
  if (elemSiblIdx === -1)
315
321
  throw new Error("Element doesn't have a parent node");
@@ -331,12 +337,12 @@ var UserUtils = (function (exports) {
331
337
  var ttPolicy;
332
338
  function setInnerHtmlUnsafe(element, html) {
333
339
  var _a, _b, _c;
334
- if (!ttPolicy && typeof ((_a = window == null ? void 0 : window.trustedTypes) == null ? void 0 : _a.createPolicy) === "function") {
340
+ if (!ttPolicy && typeof ((_a = window == null ? undefined : window.trustedTypes) == null ? undefined : _a.createPolicy) === "function") {
335
341
  ttPolicy = window.trustedTypes.createPolicy("_uu_set_innerhtml_unsafe", {
336
342
  createHTML: (unsafeHtml) => unsafeHtml
337
343
  });
338
344
  }
339
- element.innerHTML = (_c = (_b = ttPolicy == null ? void 0 : ttPolicy.createHTML) == null ? void 0 : _b.call(ttPolicy, html)) != null ? _c : html;
345
+ element.innerHTML = (_c = (_b = ttPolicy == null ? undefined : ttPolicy.createHTML) == null ? undefined : _b.call(ttPolicy, html)) != null ? _c : html;
340
346
  return element;
341
347
  }
342
348
 
@@ -412,8 +418,8 @@ var UserUtils = (function (exports) {
412
418
  * Creates an instance of DataStore to manage a sync & async database that is cached in memory and persistently saved across sessions.
413
419
  * Supports migrating data from older versions to newer ones and populating the cache with default data if no persistent data is found.
414
420
  *
415
- * ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue` if the storageMethod is left as the default of `"GM"`
416
- * ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
421
+ * - ⚠️ Requires the directives `@grant GM.getValue` and `@grant GM.setValue` if the storageMethod is left as the default of `"GM"`
422
+ * - ⚠️ Make sure to call {@linkcode loadData()} at least once after creating an instance, or the returned data will be the same as `options.defaultData`
417
423
  *
418
424
  * @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.)
419
425
  * @param options The options for this DataStore instance
@@ -520,7 +526,7 @@ var UserUtils = (function (exports) {
520
526
  * The in-memory cache will be left untouched, so you may still access the data with {@linkcode getData()}
521
527
  * Calling {@linkcode loadData()} or {@linkcode setData()} after this method was called will recreate persistent storage with the cached or default data.
522
528
  *
523
- * ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
529
+ * - ⚠️ This requires the additional directive `@grant GM.deleteValue` if the storageMethod is left as the default of `"GM"`
524
530
  */
525
531
  deleteData() {
526
532
  return __async(this, null, function* () {
@@ -585,7 +591,7 @@ var UserUtils = (function (exports) {
585
591
  const data = yield this.getValue(`_uucfg-${id}`, JSON.stringify(this.defaultData));
586
592
  const fmtVer = Number(yield this.getValue(`_uucfgver-${id}`, NaN));
587
593
  const isEncoded = Boolean(yield this.getValue(`_uucfgenc-${id}`, false));
588
- if (data === void 0 || isNaN(fmtVer))
594
+ if (data === undefined || isNaN(fmtVer))
589
595
  return;
590
596
  const parsed = yield this.deserializeData(data, isEncoded);
591
597
  yield Promise.allSettled([
@@ -615,7 +621,7 @@ var UserUtils = (function (exports) {
615
621
  /** Deserializes the data using the optional this.decodeData() and returns it as a JSON object */
616
622
  deserializeData(data, useEncoding = true) {
617
623
  return __async(this, null, function* () {
618
- let decRes = this.encodingEnabled() && useEncoding ? this.decodeData(data) : void 0;
624
+ let decRes = this.encodingEnabled() && useEncoding ? this.decodeData(data) : undefined;
619
625
  if (decRes instanceof Promise)
620
626
  decRes = yield decRes;
621
627
  return JSON.parse(decRes != null ? decRes : data);
@@ -627,7 +633,7 @@ var UserUtils = (function (exports) {
627
633
  return JSON.parse(JSON.stringify(obj));
628
634
  }
629
635
  //#region storage
630
- /** Gets a value from persistent storage - can be overwritten in a subclass if you want to use something other than GM storage */
636
+ /** Gets a value from persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods */
631
637
  getValue(name, defaultValue) {
632
638
  return __async(this, null, function* () {
633
639
  var _a, _b;
@@ -642,7 +648,7 @@ var UserUtils = (function (exports) {
642
648
  });
643
649
  }
644
650
  /**
645
- * Sets a value in persistent storage - can be overwritten in a subclass if you want to use something other than GM storage.
651
+ * Sets a value in persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods.
646
652
  * The default storage engines will stringify all passed values like numbers or booleans, so be aware of that.
647
653
  */
648
654
  setValue(name, value) {
@@ -657,7 +663,7 @@ var UserUtils = (function (exports) {
657
663
  }
658
664
  });
659
665
  }
660
- /** Deletes a value from persistent storage - can be overwritten in a subclass if you want to use something other than GM storage */
666
+ /** Deletes a value from persistent storage - can be overwritten in a subclass if you want to use something other than the default storage methods */
661
667
  deleteValue(name) {
662
668
  return __async(this, null, function* () {
663
669
  switch (this.storageMethod) {
@@ -695,7 +701,7 @@ var UserUtils = (function (exports) {
695
701
  serializeStore(storeInst) {
696
702
  return __async(this, null, function* () {
697
703
  const data = storeInst.encodingEnabled() ? yield storeInst.encodeData(JSON.stringify(storeInst.getData())) : JSON.stringify(storeInst.getData());
698
- const checksum = this.options.addChecksum ? yield this.calcChecksum(data) : void 0;
704
+ const checksum = this.options.addChecksum ? yield this.calcChecksum(data) : undefined;
699
705
  return {
700
706
  id: storeInst.id,
701
707
  data,
@@ -787,7 +793,7 @@ Has: ${checksum}`);
787
793
  ((_a = this.events)[event] || (_a[event] = [])).push(cb);
788
794
  return () => {
789
795
  var _a2;
790
- this.events[event] = (_a2 = this.events[event]) == null ? void 0 : _a2.filter((i) => cb !== i);
796
+ this.events[event] = (_a2 = this.events[event]) == null ? undefined : _a2.filter((i) => cb !== i);
791
797
  };
792
798
  }
793
799
  });
@@ -821,7 +827,7 @@ Has: ${checksum}`);
821
827
  let unsub;
822
828
  const onceProxy = (...args) => {
823
829
  unsub();
824
- cb == null ? void 0 : cb(...args);
830
+ cb == null ? undefined : cb(...args);
825
831
  resolve(args);
826
832
  };
827
833
  unsub = this.on(event, onceProxy);
@@ -843,6 +849,106 @@ Has: ${checksum}`);
843
849
  }
844
850
  };
845
851
 
852
+ // lib/Debouncer.ts
853
+ var Debouncer = class extends NanoEmitter {
854
+ /**
855
+ * Creates a new debouncer with the specified timeout and edge type.
856
+ * @param timeout Timeout in milliseconds between letting through calls - defaults to 200
857
+ * @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"
858
+ */
859
+ constructor(timeout = 200, type = "immediate") {
860
+ super();
861
+ this.timeout = timeout;
862
+ this.type = type;
863
+ /** All registered listener functions and the time they were attached */
864
+ __publicField(this, "listeners", []);
865
+ /** The currently active timeout */
866
+ __publicField(this, "activeTimeout");
867
+ /** The latest queued call */
868
+ __publicField(this, "queuedCall");
869
+ }
870
+ //#region listeners
871
+ /** Adds a listener function that will be called on timeout */
872
+ addListener(fn) {
873
+ this.listeners.push(fn);
874
+ }
875
+ /** Removes the listener with the specified function reference */
876
+ removeListener(fn) {
877
+ const idx = this.listeners.findIndex((l) => l === fn);
878
+ idx !== -1 && this.listeners.splice(idx, 1);
879
+ }
880
+ /** Removes all listeners */
881
+ removeAllListeners() {
882
+ this.listeners = [];
883
+ }
884
+ //#region timeout
885
+ /** Sets the timeout for the debouncer */
886
+ setTimeout(timeout) {
887
+ this.emit("change", this.timeout = timeout, this.type);
888
+ }
889
+ /** Returns the current timeout */
890
+ getTimeout() {
891
+ return this.timeout;
892
+ }
893
+ /** Whether the timeout is currently active, meaning any latest call to the {@linkcode call()} method will be queued */
894
+ isTimeoutActive() {
895
+ return typeof this.activeTimeout !== "undefined";
896
+ }
897
+ //#region type
898
+ /** Sets the edge type for the debouncer */
899
+ setType(type) {
900
+ this.emit("change", this.timeout, this.type = type);
901
+ }
902
+ /** Returns the current edge type */
903
+ getType() {
904
+ return this.type;
905
+ }
906
+ //#region call
907
+ /** Use this to call the debouncer with the specified arguments that will be passed to all listener functions registered with {@linkcode addListener()} */
908
+ call(...args) {
909
+ const cl = (...a) => {
910
+ this.queuedCall = undefined;
911
+ this.emit("call", ...a);
912
+ this.listeners.forEach((l) => l.apply(this, a));
913
+ };
914
+ const setRepeatTimeout = () => {
915
+ this.activeTimeout = setTimeout(() => {
916
+ if (this.queuedCall) {
917
+ this.queuedCall();
918
+ setRepeatTimeout();
919
+ } else
920
+ this.activeTimeout = undefined;
921
+ }, this.timeout);
922
+ };
923
+ switch (this.type) {
924
+ case "immediate":
925
+ if (typeof this.activeTimeout === "undefined") {
926
+ cl(...args);
927
+ setRepeatTimeout();
928
+ } else
929
+ this.queuedCall = () => cl(...args);
930
+ break;
931
+ case "idle":
932
+ if (this.activeTimeout)
933
+ clearTimeout(this.activeTimeout);
934
+ this.activeTimeout = setTimeout(() => {
935
+ cl(...args);
936
+ this.activeTimeout = undefined;
937
+ }, this.timeout);
938
+ break;
939
+ default:
940
+ throw new Error(`Invalid debouncer type: ${this.type}`);
941
+ }
942
+ }
943
+ };
944
+ function debounce(fn, timeout = 200, type = "immediate") {
945
+ const debouncer = new Debouncer(timeout, type);
946
+ debouncer.addListener(fn);
947
+ const func = (...args) => debouncer.call(...args);
948
+ func.debouncer = debouncer;
949
+ return func;
950
+ }
951
+
846
952
  // lib/Dialog.ts
847
953
  var defaultDialogCss = `.uu-no-select {
848
954
  user-select: none;
@@ -1060,7 +1166,7 @@ Has: ${checksum}`);
1060
1166
  `#uu-style-dialog-${this.id}`
1061
1167
  ];
1062
1168
  for (const sel of clearSelectors)
1063
- (_a = document.querySelector(sel)) == null ? void 0 : _a.remove();
1169
+ (_a = document.querySelector(sel)) == null ? undefined : _a.remove();
1064
1170
  this.events.emit("clear");
1065
1171
  }
1066
1172
  /** Clears the DOM of the dialog and then renders it again */
@@ -1077,8 +1183,8 @@ Has: ${checksum}`);
1077
1183
  open(e) {
1078
1184
  return __async(this, null, function* () {
1079
1185
  var _a;
1080
- e == null ? void 0 : e.preventDefault();
1081
- e == null ? void 0 : e.stopImmediatePropagation();
1186
+ e == null ? undefined : e.preventDefault();
1187
+ e == null ? undefined : e.stopImmediatePropagation();
1082
1188
  if (this.isOpen())
1083
1189
  return;
1084
1190
  this.dialogOpen = true;
@@ -1096,7 +1202,7 @@ Has: ${checksum}`);
1096
1202
  openDialogs.unshift(this.id);
1097
1203
  for (const dialogId of openDialogs)
1098
1204
  if (dialogId !== this.id)
1099
- (_a = document.querySelector(`#uu-${dialogId}-dialog-bg`)) == null ? void 0 : _a.setAttribute("inert", "true");
1205
+ (_a = document.querySelector(`#uu-${dialogId}-dialog-bg`)) == null ? undefined : _a.setAttribute("inert", "true");
1100
1206
  document.body.classList.remove("uu-no-select");
1101
1207
  document.body.setAttribute("inert", "true");
1102
1208
  this.events.emit("open");
@@ -1106,8 +1212,8 @@ Has: ${checksum}`);
1106
1212
  /** Closes the dialog - prevents default action and immediate propagation of the passed event */
1107
1213
  close(e) {
1108
1214
  var _a, _b;
1109
- e == null ? void 0 : e.preventDefault();
1110
- e == null ? void 0 : e.stopImmediatePropagation();
1215
+ e == null ? undefined : e.preventDefault();
1216
+ e == null ? undefined : e.stopImmediatePropagation();
1111
1217
  if (!this.isOpen())
1112
1218
  return;
1113
1219
  this.dialogOpen = false;
@@ -1120,7 +1226,7 @@ Has: ${checksum}`);
1120
1226
  openDialogs.splice(openDialogs.indexOf(this.id), 1);
1121
1227
  exports.currentDialogId = (_a = openDialogs[0]) != null ? _a : null;
1122
1228
  if (exports.currentDialogId)
1123
- (_b = document.querySelector(`#uu-${exports.currentDialogId}-dialog-bg`)) == null ? void 0 : _b.removeAttribute("inert");
1229
+ (_b = document.querySelector(`#uu-${exports.currentDialogId}-dialog-bg`)) == null ? undefined : _b.removeAttribute("inert");
1124
1230
  if (openDialogs.length === 0) {
1125
1231
  document.body.classList.add("uu-no-select");
1126
1232
  document.body.removeAttribute("inert");
@@ -1164,7 +1270,7 @@ Has: ${checksum}`);
1164
1270
  if (this.options.closeOnBgClick) {
1165
1271
  bgElem.addEventListener("click", (e) => {
1166
1272
  var _a;
1167
- if (this.isOpen() && ((_a = e.target) == null ? void 0 : _a.id) === `uu-${this.id}-dialog-bg`)
1273
+ if (this.isOpen() && ((_a = e.target) == null ? undefined : _a.id) === `uu-${this.id}-dialog-bg`)
1168
1274
  this.close(e);
1169
1275
  });
1170
1276
  }
@@ -1194,8 +1300,8 @@ Has: ${checksum}`);
1194
1300
  preventDefault && e.preventDefault();
1195
1301
  stopPropagation && e.stopPropagation();
1196
1302
  }
1197
- (listenerOpts == null ? void 0 : listenerOpts.once) && e.type === "keydown" && elem.removeEventListener("click", proxListener, listenerOpts);
1198
- (listenerOpts == null ? void 0 : listenerOpts.once) && e.type === "click" && elem.removeEventListener("keydown", proxListener, listenerOpts);
1303
+ (listenerOpts == null ? undefined : listenerOpts.once) && e.type === "keydown" && elem.removeEventListener("click", proxListener, listenerOpts);
1304
+ (listenerOpts == null ? undefined : listenerOpts.once) && e.type === "click" && elem.removeEventListener("keydown", proxListener, listenerOpts);
1199
1305
  listener(e);
1200
1306
  };
1201
1307
  elem.addEventListener("click", proxListener, listenerOpts);
@@ -1205,8 +1311,8 @@ Has: ${checksum}`);
1205
1311
  getDialogContent() {
1206
1312
  return __async(this, null, function* () {
1207
1313
  var _a, _b, _c, _d;
1208
- const header = (_b = (_a = this.options).renderHeader) == null ? void 0 : _b.call(_a);
1209
- const footer = (_d = (_c = this.options).renderFooter) == null ? void 0 : _d.call(_c);
1314
+ const header = (_b = (_a = this.options).renderHeader) == null ? undefined : _b.call(_a);
1315
+ const footer = (_d = (_c = this.options).renderFooter) == null ? undefined : _d.call(_c);
1210
1316
  const dialogWrapperEl = document.createElement("div");
1211
1317
  dialogWrapperEl.id = `uu-${this.id}-dialog`;
1212
1318
  dialogWrapperEl.classList.add("uu-dialog");
@@ -1272,7 +1378,7 @@ Has: ${checksum}`);
1272
1378
  return input.replace(/%\d/gm, (match) => {
1273
1379
  var _a, _b;
1274
1380
  const argIndex = Number(match.substring(1)) - 1;
1275
- return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
1381
+ return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? undefined : _b.toString();
1276
1382
  });
1277
1383
  }
1278
1384
  function pauseFor(time) {
@@ -1280,27 +1386,13 @@ Has: ${checksum}`);
1280
1386
  setTimeout(() => res(), time);
1281
1387
  });
1282
1388
  }
1283
- function debounce(func, timeout = 300, edge = "falling") {
1284
- let id;
1285
- return function(...args) {
1286
- if (edge === "rising") {
1287
- if (!id) {
1288
- func.apply(this, args);
1289
- id = setTimeout(() => id = void 0, timeout);
1290
- }
1291
- } else {
1292
- clearTimeout(id);
1293
- id = setTimeout(() => func.apply(this, args), timeout);
1294
- }
1295
- };
1296
- }
1297
1389
  function fetchAdvanced(_0) {
1298
1390
  return __async(this, arguments, function* (input, options = {}) {
1299
1391
  var _a;
1300
1392
  const { timeout = 1e4 } = options;
1301
1393
  const { signal, abort } = new AbortController();
1302
- (_a = options.signal) == null ? void 0 : _a.addEventListener("abort", abort);
1303
- let signalOpts = {}, id = void 0;
1394
+ (_a = options.signal) == null ? undefined : _a.addEventListener("abort", abort);
1395
+ let signalOpts = {}, id = undefined;
1304
1396
  if (timeout >= 0) {
1305
1397
  id = setTimeout(() => abort(), timeout);
1306
1398
  signalOpts = { signal };
@@ -1343,12 +1435,12 @@ Has: ${checksum}`);
1343
1435
  this.listenerMap = /* @__PURE__ */ new Map();
1344
1436
  const _a = options, {
1345
1437
  defaultDebounce,
1346
- defaultDebounceEdge,
1438
+ defaultDebounceType,
1347
1439
  disableOnNoListeners,
1348
1440
  enableOnAddListener
1349
1441
  } = _a, observerOptions = __objRest(_a, [
1350
1442
  "defaultDebounce",
1351
- "defaultDebounceEdge",
1443
+ "defaultDebounceType",
1352
1444
  "disableOnNoListeners",
1353
1445
  "enableOnAddListener"
1354
1446
  ]);
@@ -1358,7 +1450,7 @@ Has: ${checksum}`);
1358
1450
  }, observerOptions);
1359
1451
  this.customOptions = {
1360
1452
  defaultDebounce: defaultDebounce != null ? defaultDebounce : 0,
1361
- defaultDebounceEdge: defaultDebounceEdge != null ? defaultDebounceEdge : "rising",
1453
+ defaultDebounceType: defaultDebounceType != null ? defaultDebounceType : "immediate",
1362
1454
  disableOnNoListeners: disableOnNoListeners != null ? disableOnNoListeners : false,
1363
1455
  enableOnAddListener: enableOnAddListener != null ? enableOnAddListener : true
1364
1456
  };
@@ -1402,7 +1494,7 @@ Has: ${checksum}`);
1402
1494
  this.removeListener(selector, options);
1403
1495
  }
1404
1496
  }
1405
- if (((_a = this.listenerMap.get(selector)) == null ? void 0 : _a.length) === 0)
1497
+ if (((_a = this.listenerMap.get(selector)) == null ? undefined : _a.length) === 0)
1406
1498
  this.listenerMap.delete(selector);
1407
1499
  if (this.listenerMap.size === 0 && this.customOptions.disableOnNoListeners)
1408
1500
  this.disable();
@@ -1428,7 +1520,7 @@ Has: ${checksum}`);
1428
1520
  options.listener = debounce(
1429
1521
  options.listener,
1430
1522
  options.debounce || this.customOptions.defaultDebounce,
1431
- options.debounceEdge || this.customOptions.defaultDebounceEdge
1523
+ options.debounceType || this.customOptions.defaultDebounceType
1432
1524
  );
1433
1525
  }
1434
1526
  if (this.listenerMap.has(selector))
@@ -1446,7 +1538,7 @@ Has: ${checksum}`);
1446
1538
  if (!this.enabled)
1447
1539
  return;
1448
1540
  this.enabled = false;
1449
- (_a = this.observer) == null ? void 0 : _a.disconnect();
1541
+ (_a = this.observer) == null ? undefined : _a.disconnect();
1450
1542
  }
1451
1543
  /**
1452
1544
  * Enables or reenables the observation of the child elements.
@@ -1459,7 +1551,7 @@ Has: ${checksum}`);
1459
1551
  if (this.enabled || !baseElement)
1460
1552
  return false;
1461
1553
  this.enabled = true;
1462
- (_a = this.observer) == null ? void 0 : _a.observe(baseElement, this.observerOptions);
1554
+ (_a = this.observer) == null ? undefined : _a.observe(baseElement, this.observerOptions);
1463
1555
  if (immediatelyCheckSelectors)
1464
1556
  this.checkAllSelectors();
1465
1557
  return true;
@@ -1506,43 +1598,169 @@ Has: ${checksum}`);
1506
1598
 
1507
1599
  // lib/translation.ts
1508
1600
  var trans = {};
1509
- var curLang = "";
1510
- function translate(language, key, ...args) {
1511
- var _a;
1512
- const trObj = (_a = trans[language]) == null ? void 0 : _a.data;
1513
- if (typeof language !== "string" || typeof trObj !== "object" || trObj === null)
1514
- return key;
1601
+ var valTransforms = [];
1602
+ var fallbackLang;
1603
+ function translate(language, key, ...trArgs) {
1604
+ if (typeof language !== "string")
1605
+ language = fallbackLang != null ? fallbackLang : "";
1606
+ const trObj = trans[language];
1607
+ if (typeof language !== "string" || language.length === 0 || typeof trObj !== "object" || trObj === null)
1608
+ return fallbackLang ? translate(fallbackLang, key, ...trArgs) : key;
1609
+ const transformTrVal = (trKey, trValue) => {
1610
+ const tfs = valTransforms.filter(({ regex }) => new RegExp(regex).test(trValue));
1611
+ if (tfs.length === 0)
1612
+ return trValue;
1613
+ let retStr = String(trValue);
1614
+ for (const tf of tfs) {
1615
+ const re = new RegExp(tf.regex);
1616
+ const matches = [];
1617
+ let execRes;
1618
+ while ((execRes = re.exec(trValue)) !== null) {
1619
+ if (matches.some((m) => m[0] === (execRes == null ? undefined : execRes[0])))
1620
+ break;
1621
+ matches.push(execRes);
1622
+ }
1623
+ retStr = String(tf.fn({
1624
+ language,
1625
+ trValue,
1626
+ currentValue: retStr,
1627
+ matches,
1628
+ trKey,
1629
+ trArgs
1630
+ }));
1631
+ }
1632
+ return retStr;
1633
+ };
1515
1634
  const keyParts = key.split(".");
1516
1635
  let value = trObj;
1517
1636
  for (const part of keyParts) {
1518
- if (typeof value !== "object" || value === null)
1637
+ if (typeof value !== "object" || value === null) {
1638
+ value = undefined;
1519
1639
  break;
1520
- value = value == null ? void 0 : value[part];
1640
+ }
1641
+ value = value == null ? undefined : value[part];
1521
1642
  }
1522
1643
  if (typeof value === "string")
1523
- return insertValues(value, args);
1524
- value = trObj == null ? void 0 : trObj[key];
1644
+ return transformTrVal(key, value);
1645
+ value = trObj == null ? undefined : trObj[key];
1525
1646
  if (typeof value === "string")
1526
- return insertValues(value, args);
1527
- return key;
1647
+ return transformTrVal(key, value);
1648
+ return fallbackLang ? translate(fallbackLang, key, ...trArgs) : key;
1528
1649
  }
1529
- var tr = (key, ...args) => translate(curLang, key, ...args);
1530
- tr.forLang = translate;
1531
- tr.addLanguage = (language, translations) => {
1532
- trans[language] = translations;
1533
- };
1534
- tr.setLanguage = (language) => {
1535
- curLang = language;
1536
- };
1537
- tr.getLanguage = () => {
1538
- return curLang;
1650
+ function trFor(language, key, ...args) {
1651
+ const txt = translate(language, key, ...args);
1652
+ if (txt === key)
1653
+ return fallbackLang ? translate(fallbackLang, key, ...args) : key;
1654
+ return txt;
1655
+ }
1656
+ function useTr(language) {
1657
+ return (key, ...args) => translate(language, key, ...args);
1658
+ }
1659
+ function hasKey(language = fallbackLang != null ? fallbackLang : "", key) {
1660
+ return tr.for(language, key) !== key;
1661
+ }
1662
+ function addTranslations(language, translations) {
1663
+ trans[language] = JSON.parse(JSON.stringify(translations));
1664
+ }
1665
+ function getTranslations(language = fallbackLang != null ? fallbackLang : "") {
1666
+ return trans[language];
1667
+ }
1668
+ var deleteTranslations = (language) => {
1669
+ if (language in trans) {
1670
+ delete trans[language];
1671
+ return true;
1672
+ }
1673
+ return false;
1539
1674
  };
1540
- tr.getTranslations = (language) => {
1541
- return trans[language != null ? language : curLang];
1675
+ function setFallbackLanguage(fallbackLanguage) {
1676
+ fallbackLang = fallbackLanguage;
1677
+ }
1678
+ function getFallbackLanguage() {
1679
+ return fallbackLang;
1680
+ }
1681
+ function addTransform(transform) {
1682
+ const [pattern, fn] = transform;
1683
+ valTransforms.push({
1684
+ fn,
1685
+ regex: typeof pattern === "string" ? new RegExp(pattern, "gm") : pattern
1686
+ });
1687
+ }
1688
+ function deleteTransform(patternOrFn) {
1689
+ const idx = valTransforms.findIndex(
1690
+ (t) => typeof patternOrFn === "function" ? t.fn === patternOrFn : typeof patternOrFn === "string" ? t.regex.source === patternOrFn : t.regex === patternOrFn
1691
+ );
1692
+ if (idx !== -1) {
1693
+ valTransforms.splice(idx, 1);
1694
+ return true;
1695
+ }
1696
+ return false;
1697
+ }
1698
+ var templateLiteralTransform = [
1699
+ /\$\{([a-zA-Z0-9$_-]+)\}/gm,
1700
+ ({ matches, trArgs, trValue }) => {
1701
+ const patternStart = "${", patternEnd = "}", patternRegex = /\$\{.+\}/m;
1702
+ let str = String(trValue);
1703
+ const eachKeyInTrString = (keys) => keys.every((key) => trValue.includes(`${patternStart}${key}${patternEnd}`));
1704
+ const namedMapping = () => {
1705
+ var _a;
1706
+ if (!str.includes(patternStart) || typeof trArgs[0] === "undefined" || typeof trArgs[0] !== "object" || !eachKeyInTrString(Object.keys((_a = trArgs[0]) != null ? _a : {})))
1707
+ return;
1708
+ for (const match of matches) {
1709
+ const repl = match[1] !== undefined ? trArgs[0][match[1]] : undefined;
1710
+ if (typeof repl !== "undefined")
1711
+ str = str.replace(match[0], String(repl));
1712
+ }
1713
+ };
1714
+ const positionalMapping = () => {
1715
+ if (!patternRegex.test(str) || !trArgs[0])
1716
+ return;
1717
+ let matchNum = -1;
1718
+ for (const match of matches) {
1719
+ matchNum++;
1720
+ if (typeof trArgs[matchNum] !== "undefined")
1721
+ str = str.replace(match[0], String(trArgs[matchNum]));
1722
+ }
1723
+ };
1724
+ const isArgsObject = trArgs[0] && typeof trArgs[0] === "object" && trArgs[0] !== null && String(trArgs[0]).startsWith("[object");
1725
+ if (isArgsObject && eachKeyInTrString(Object.keys(trArgs[0])))
1726
+ namedMapping();
1727
+ else
1728
+ positionalMapping();
1729
+ return str;
1730
+ }
1731
+ ];
1732
+ var percentTransform = [
1733
+ /\$\{([a-zA-Z0-9$_-]+)\}/gm,
1734
+ ({ matches, trArgs, trValue }) => {
1735
+ let str = String(trValue);
1736
+ for (const match of matches) {
1737
+ const repl = match[1] !== undefined ? trArgs[0][match[1]] : undefined;
1738
+ if (typeof repl !== "undefined")
1739
+ str = str.replace(match[0], String(repl));
1740
+ }
1741
+ return str;
1742
+ }
1743
+ ];
1744
+ var tr = {
1745
+ for: (...params) => trFor(...params),
1746
+ use: (...params) => useTr(...params),
1747
+ hasKey: (language = fallbackLang != null ? fallbackLang : "", key) => hasKey(language, key),
1748
+ addTranslations,
1749
+ getTranslations,
1750
+ deleteTranslations,
1751
+ setFallbackLanguage,
1752
+ getFallbackLanguage,
1753
+ addTransform,
1754
+ deleteTransform,
1755
+ transforms: {
1756
+ templateLiteral: templateLiteralTransform,
1757
+ percent: percentTransform
1758
+ }
1542
1759
  };
1543
1760
 
1544
1761
  exports.DataStore = DataStore;
1545
1762
  exports.DataStoreSerializer = DataStoreSerializer;
1763
+ exports.Debouncer = Debouncer;
1546
1764
  exports.Dialog = Dialog;
1547
1765
  exports.NanoEmitter = NanoEmitter;
1548
1766
  exports.SelectorObserver = SelectorObserver;