bc-deeplib 1.1.1 → 1.1.3

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/deeplib.js CHANGED
@@ -204,12 +204,27 @@ var BaseModule = class {
204
204
  static {
205
205
  __name(this, "BaseModule");
206
206
  }
207
+ /**
208
+ * An optional UI screen for configuring this module's settings.
209
+ * Subclasses can override this getter to provide a `Subscreen` instance.
210
+ * Modules with screens are automatically registered to the main menu.
211
+ */
207
212
  get settingsScreen() {
208
213
  return null;
209
214
  }
215
+ /**
216
+ * The storage key under which this module's settings will be saved.
217
+ * Defaults to the class name.
218
+ *
219
+ * Subclasses can override this if they require a custom storage key.
220
+ */
210
221
  get settingsStorage() {
211
222
  return this.constructor.name;
212
223
  }
224
+ /**
225
+ * Retrieves the current settings for this module.
226
+ * If no settings exist yet, registers default settings first.
227
+ */
213
228
  get settings() {
214
229
  const modName = ModSdkManager.ModInfo.name;
215
230
  if (!this.settingsStorage) return {};
@@ -219,6 +234,10 @@ var BaseModule = class {
219
234
  } else if (!modStorage.playerStorage[this.settingsStorage]) this.registerDefaultSettings();
220
235
  return modStorage.playerStorage[this.settingsStorage];
221
236
  }
237
+ /**
238
+ * Persists new settings for this module.
239
+ * Automatically initializes storage and defaults if they don't exist.
240
+ */
222
241
  set settings(value) {
223
242
  const modName = ModSdkManager.ModInfo.name;
224
243
  const storage = new ModStorage(modName);
@@ -229,31 +248,55 @@ var BaseModule = class {
229
248
  } else if (!storage.playerStorage[this.settingsStorage]) this.registerDefaultSettings();
230
249
  storage.playerStorage[this.settingsStorage] = value;
231
250
  }
251
+ /**
252
+ * Initializes the module.
253
+ * Default implementation registers default settings immediately.
254
+ * Subclasses can override to perform additional setup.
255
+ */
232
256
  init() {
233
257
  this.registerDefaultSettings();
234
258
  }
259
+ /**
260
+ * Registers default settings for this module in persistent storage.
261
+ * Only runs if a storage key and default settings are defined.
262
+ *
263
+ * If some settings already exist, they will be merged with defaults.
264
+ * Existing values will NOT be overwritten.
265
+ */
235
266
  registerDefaultSettings() {
236
267
  const storage = this.settingsStorage;
237
268
  const defaults = this.defaultSettings;
238
269
  if (!storage || !defaults) return;
239
270
  Player[ModSdkManager.ModInfo.name][storage] = Object.assign(defaults, Player[ModSdkManager.ModInfo.name][storage] ?? {});
240
271
  }
272
+ /**
273
+ * Provides default settings for this module.
274
+ * Subclasses should override this getter to return their defaults.
275
+ */
241
276
  get defaultSettings() {
242
277
  return null;
243
278
  }
279
+ /**
280
+ * Called when the module is loaded into the system.
281
+ * Subclasses should override to perform data loading or initialization.
282
+ */
244
283
  load() {
245
284
  }
285
+ /**
286
+ * By default doesn't get called each frame, only once when the module is loaded.
287
+ * Subclasses can override to implement runtime logic.
288
+ */
246
289
  run() {
247
290
  }
291
+ /**
292
+ * Called when the module is being removed.
293
+ * Subclasses can override to perform cleanup or save final state.
294
+ */
248
295
  unload() {
249
296
  }
250
297
  };
251
298
 
252
299
  // src/base/base_subscreen.ts
253
- function getCurrentSubscreen() {
254
- return GUI.instance && GUI.instance.currentSubscreen;
255
- }
256
- __name(getCurrentSubscreen, "getCurrentSubscreen");
257
300
  function setSubscreen(subscreen) {
258
301
  if (!GUI.instance) {
259
302
  throw new Error("Attempt to set subscreen before init");
@@ -266,38 +309,62 @@ var BaseSubscreen = class _BaseSubscreen {
266
309
  static {
267
310
  __name(this, "BaseSubscreen");
268
311
  }
312
+ /** Global registry of currently rendered elements and their definitions. */
269
313
  static currentElements = [];
314
+ /** Tracks the currently visible page number (1-based index). */
270
315
  static currentPage = 1;
316
+ /** Runtime options for this subscreen. */
271
317
  options;
318
+ /** Reference to the module this subscreen belongs to. */
272
319
  module;
273
320
  constructor(subscreenOptions, module) {
274
321
  if (module) this.module = module;
275
322
  this.options = subscreenOptions || {};
276
323
  }
324
+ /**
325
+ * Logical name of this subscreen.
326
+ * Used for localization key resolution in `load()`.
327
+ * Subclasses should override this with a meaningful identifier.
328
+ */
277
329
  get name() {
278
330
  return "UNKNOWN";
279
331
  }
332
+ /**
333
+ * Path to or Base64 data for an icon representing this subscreen.
334
+ * Defaults to empty string (no icon).
335
+ */
280
336
  get icon() {
281
337
  return "";
282
338
  }
283
- get subscreenName() {
284
- return this.constructor.name;
285
- }
339
+ /** Changes the currently active subscreen. */
286
340
  setSubscreen(screen) {
287
341
  return setSubscreen(screen);
288
342
  }
343
+ /** Gets this subscreen's settings object from its parent module. */
289
344
  get settings() {
290
345
  return this.module.settings;
291
346
  }
347
+ /** Updates this subscreen's settings in its parent module. */
292
348
  set settings(value) {
293
349
  this.module.settings = value;
294
350
  }
351
+ /**
352
+ * Defines the paginated layout of the subscreen's settings UI.
353
+ * Each element in the outer array is a page; each page contains `SettingElement`s.
354
+ *
355
+ * Subclasses should override to define their actual UI structure.
356
+ */
295
357
  get pageStructure() {
296
358
  return [[]];
297
359
  }
360
+ /** Gets the currently visible page's settings elements. */
298
361
  get currentPage() {
299
362
  return this.pageStructure[Math.min(_BaseSubscreen.currentPage - 1, this.pageStructure.length - 1)];
300
363
  }
364
+ /**
365
+ * Changes the visible page in a multi-page subscreen.
366
+ * Automatically wraps around when going past the first or last page.
367
+ */
301
368
  changePage(page, setLabel) {
302
369
  const totalPages = this.pageStructure.length;
303
370
  if (page > totalPages) page = 1;
@@ -306,6 +373,10 @@ var BaseSubscreen = class _BaseSubscreen {
306
373
  this.managePageElementsVisibility();
307
374
  setLabel(`${_BaseSubscreen.currentPage} of ${this.pageStructure.length}`);
308
375
  }
376
+ /**
377
+ * Updates the DOM to show only elements belonging to the current page.
378
+ * All elements on other pages are hidden.
379
+ */
309
380
  managePageElementsVisibility() {
310
381
  this.pageStructure.forEach((item, ix) => {
311
382
  if (ix != _BaseSubscreen.currentPage - 1) {
@@ -319,19 +390,30 @@ var BaseSubscreen = class _BaseSubscreen {
319
390
  }
320
391
  });
321
392
  }
393
+ /**
394
+ * Called when this subscreen is first displayed.
395
+ * Builds the layout, initializes navigation, and renders all settings elements.
396
+ *
397
+ * Handles:
398
+ * - Ensuring each module with a settings screen has its defaults loaded
399
+ * - Creating navigation menus and back/next page controls
400
+ * - Building and appending UI elements based on `pageStructure`
401
+ * - Setting up exit button and tooltip
402
+ * - Resetting to page 1
403
+ */
322
404
  load() {
323
405
  for (const module of modules()) {
324
406
  if (!module.settingsScreen) continue;
325
407
  if (!module.settings || !Object.keys(module.settings).length) module.registerDefaultSettings();
326
408
  }
327
409
  _BaseSubscreen.currentPage = 1;
328
- layoutElement.createSubscreenDiv();
329
- const settingsElement = layoutElement.createSettingsDiv();
330
- layoutElement.appendToSubscreenDiv(settingsElement);
410
+ layout.createSubscreen();
411
+ const settingsElement = layout.createSettingsDiv();
412
+ layout.appendToSubscreen(settingsElement);
331
413
  const menu = ElementMenu.Create("deeplib-nav-menu", []);
332
- layoutElement.appendToSubscreenDiv(menu);
414
+ layout.appendToSubscreen(menu);
333
415
  if (this.pageStructure.length > 1) {
334
- const backNext = advancedElement.createBackNext({
416
+ const backNext = advElement.createBackNext({
335
417
  id: "deeplib-page-back-next",
336
418
  next: /* @__PURE__ */ __name(({ setLabel }) => this.changePage(_BaseSubscreen.currentPage + 1, setLabel), "next"),
337
419
  initialNextTooltip: getText("settings.button.next_button_hint"),
@@ -341,13 +423,13 @@ var BaseSubscreen = class _BaseSubscreen {
341
423
  });
342
424
  ElementMenu.PrependItem(menu, backNext);
343
425
  }
344
- const subscreenTitle = advancedElement.createLabel({
426
+ const subscreenTitle = advElement.createLabel({
345
427
  id: "deeplib-subscreen-title",
346
428
  label: getText(`${this.name}.title`).replace("$ModVersion", ModSdkManager.ModInfo.version)
347
429
  });
348
- layoutElement.appendToSubscreenDiv(subscreenTitle);
430
+ layout.appendToSubscreen(subscreenTitle);
349
431
  if (this.name !== "mainmenu") {
350
- const exitButton = advancedElement.createButton({
432
+ const exitButton = advElement.createButton({
351
433
  id: "deeplib-exit",
352
434
  size: [90, 90],
353
435
  image: `${PUBLIC_URL}/dl_images/exit.svg`,
@@ -358,8 +440,8 @@ var BaseSubscreen = class _BaseSubscreen {
358
440
  });
359
441
  ElementMenu.AppendButton(menu, exitButton);
360
442
  }
361
- const tooltip = advancedElement.createTooltip();
362
- layoutElement.appendToSubscreenDiv(tooltip);
443
+ const tooltip = advElement.createTooltip();
444
+ layout.appendToSubscreen(tooltip);
363
445
  this.pageStructure.forEach(
364
446
  (s) => s.forEach((item) => {
365
447
  let element;
@@ -367,42 +449,59 @@ var BaseSubscreen = class _BaseSubscreen {
367
449
  case "text":
368
450
  case "number":
369
451
  case "color":
370
- element = advancedElement.createInput(item);
452
+ element = advElement.createInput(item);
371
453
  break;
372
454
  case "checkbox":
373
- element = advancedElement.createCheckbox(item);
455
+ element = advElement.createCheckbox(item);
374
456
  break;
375
457
  case "button":
376
- element = advancedElement.createButton(item);
458
+ element = advElement.createButton(item);
377
459
  break;
378
460
  case "label":
379
- element = advancedElement.createLabel(item);
461
+ element = advElement.createLabel(item);
380
462
  break;
381
463
  case "custom":
382
- element = advancedElement.createCustom(item);
464
+ element = advElement.createCustom(item);
383
465
  break;
384
466
  }
385
- layoutElement.appendToSettingsDiv(element);
467
+ layout.appendToSettingsDiv(element);
386
468
  })
387
469
  );
388
470
  this.managePageElementsVisibility();
389
471
  CharacterAppearanceForceUpCharacter = Player.MemberNumber ?? -1;
390
472
  }
473
+ /**
474
+ * Called each frame while this subscreen is active.
475
+ * Default behavior draws the player's character if `drawCharacter` is enabled.
476
+ */
391
477
  run() {
392
478
  if (this.options.drawCharacter) DrawCharacter(Player, 50, 50, 0.9, false);
393
479
  }
480
+ /**
481
+ * Handles mouse clicks *on canvas* while the subscreen is active.
482
+ * Default implementation is empty — subclasses may override.
483
+ */
394
484
  click() {
395
485
  }
486
+ /**
487
+ * Exits this subscreen, returning to the main menu.
488
+ * Also saves persistent storage changes.
489
+ * Called after the `unload`.
490
+ */
396
491
  exit() {
397
492
  CharacterAppearanceForceUpCharacter = -1;
398
493
  CharacterLoadCanvas(Player);
399
494
  setSubscreen("mainmenu");
400
495
  modStorage.save();
401
496
  }
497
+ /**
498
+ * Called when the window is resized.
499
+ * Also checks for overflow in the settings div and applies styling accordingly.
500
+ */
402
501
  resize(onLoad = false) {
403
502
  const offset = this.options.drawCharacter ? 0 : 380;
404
- const subscreen = layoutElement.getSubscreenDiv();
405
- const settingsDiv = layoutElement.getSettingsDiv();
503
+ const subscreen = layout.getSubscreen();
504
+ const settingsDiv = layout.getSettingsDiv();
406
505
  ElementSetPosition(subscreen || "", 0, 0);
407
506
  ElementSetSize(subscreen || "", 2e3, 1e3);
408
507
  ElementSetFontSize(subscreen || "", "auto");
@@ -417,8 +516,8 @@ var BaseSubscreen = class _BaseSubscreen {
417
516
  ElementSetSize("deeplib-subscreen-title", 800, 60);
418
517
  ElementSetPosition("deeplib-nav-menu", 1905, 75, "top-right");
419
518
  ElementSetSize("deeplib-nav-menu", null, 90);
420
- ElementSetPosition(advancedElement.getTooltip() || "", 250, 850);
421
- ElementSetSize(advancedElement.getTooltip() || "", 1500, 70);
519
+ ElementSetPosition(advElement.getTooltip() || "", 250, 850);
520
+ ElementSetSize(advElement.getTooltip() || "", 1500, 70);
422
521
  _BaseSubscreen.currentElements.forEach((item) => {
423
522
  const options = item[1];
424
523
  domUtil.autoSetPosition(options.id, options.position);
@@ -432,9 +531,14 @@ var BaseSubscreen = class _BaseSubscreen {
432
531
  }
433
532
  }
434
533
  }
534
+ /**
535
+ * Called when this subscreen is being removed.
536
+ * Resets the static element registry and removes the subscreen from the layout.
537
+ * Called before `exit`.
538
+ */
435
539
  unload() {
436
540
  _BaseSubscreen.currentElements = [];
437
- layoutElement.removeSubscreenDiv();
541
+ layout.removeSubscreen();
438
542
  }
439
543
  };
440
544
 
@@ -446,8 +550,8 @@ var styles_default = `.deeplib-subscreen,
446
550
  --deeplib-element-hover-color: var(--tmd-element-hover, cyan);
447
551
  --deeplib-blocked-color: var(--tmd-blocked, red);
448
552
  --deeplib-text-color: var(--tmd-text, black);
449
- --deeplib-icon-color: var(--tmd-accent, white);
450
- --deeplib-icon-hover-color: var(--tmd-accent-hover, cyan);
553
+ --deeplib-icon-color: var(--tmd-accent, black);
554
+ --deeplib-icon-hover-color: var(--tmd-accent-hover, black);
451
555
  --deeplib-border-color: var(--tmd-accent, black);
452
556
  --deeplib-border-width: min(0.2vh, 0.1vw);
453
557
  --deeplib-border-width: min(0.2dvh, 0.1dvw);
@@ -735,7 +839,7 @@ input[type=number] {
735
839
  height: 100dvh;
736
840
  background-color: rgba(0, 0, 0, 0.5);
737
841
  }
738
- /*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VSb290IjoiL21lZGlhL0Rlby9OVk1FL1N0dWZmL0NvZGUvQkMvQkMtRGVlcExpYi9zcmMvc3R5bGVzIiwic291cmNlcyI6WyJ2YXJzLnNjc3MiLCJidXR0b25zLnNjc3MiLCJlbGVtZW50cy5zY3NzIiwiaW5wdXRzLnNjc3MiLCJtZXNzYWdlcy5zY3NzIiwibW9kYWwuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQUFBO0VBRUU7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUNiRjtFQUNFO0VBQ0E7RUFDQTs7O0FBR0Y7QUFBQTtFQUVFOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFFQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7OztBQUdGO0VBQ0U7RUFDQTtFQUNBOzs7QUFHRjtFQUNFOzs7QUMzQ0Y7RUFDRTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTs7O0FBR0Y7RUFDRTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFNRTtFQUNBOztBQU5BO0VBQ0U7RUFDQTs7QUFPSjtFQUNFOzs7QUFJSjtFQUNFO0VBQ0E7RUFDQTs7O0FDdEZGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7O0FBSUY7RUFDRTtFQUNBO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBOzs7QUFHRjtBQUFBO0VBRUU7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBOzs7QUM3REY7RUFDRTtFQUNBOzs7QUFHRjtBQUFBO0VBRUU7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7O0FBR0Y7QUFBQTtFQUVFOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTs7O0FDN0JGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFO0VBQ0E7RUFDQTtFQUNBOztBQUdGO0VBQ0U7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTs7O0FBTVI7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQSIsInNvdXJjZXNDb250ZW50IjpbIi5kZWVwbGliLXN1YnNjcmVlbixcbi5kZWVwbGliLW1vZGFsIHtcbiAgLS1kZWVwbGliLWJhY2tncm91bmQtY29sb3I6IHZhcigtLXRtZC1tYWluLCB3aGl0ZSk7XG4gIC0tZGVlcGxpYi1lbGVtZW50LWNvbG9yOiB2YXIoLS10bWQtZWxlbWVudCwgd2hpdGUpO1xuICAtLWRlZXBsaWItZWxlbWVudC1ob3Zlci1jb2xvcjogdmFyKC0tdG1kLWVsZW1lbnQtaG92ZXIsIGN5YW4pO1xuICAtLWRlZXBsaWItYmxvY2tlZC1jb2xvcjogdmFyKC0tdG1kLWJsb2NrZWQsIHJlZCk7XG4gIC0tZGVlcGxpYi10ZXh0LWNvbG9yOiB2YXIoLS10bWQtdGV4dCwgYmxhY2spO1xuICAtLWRlZXBsaWItaWNvbi1jb2xvcjogdmFyKC0tdG1kLWFjY2VudCwgd2hpdGUpO1xuICAtLWRlZXBsaWItaWNvbi1ob3Zlci1jb2xvcjogdmFyKC0tdG1kLWFjY2VudC1ob3ZlciwgY3lhbik7XG4gIC0tZGVlcGxpYi1ib3JkZXItY29sb3I6IHZhcigtLXRtZC1hY2NlbnQsIGJsYWNrKTtcbiAgLS1kZWVwbGliLWJvcmRlci13aWR0aDogbWluKDAuMnZoLCAwLjF2dyk7XG4gIC0tZGVlcGxpYi1ib3JkZXItd2lkdGg6IG1pbigwLjJkdmgsIDAuMWR2dyk7XG4gIC0tZGVlcGxpYi1ib3JkZXItcmFkaXVzOiBtaW4oMXZoLCAwLjV2dyk7XG4gIC0tZGVlcGxpYi1ib3JkZXItcmFkaXVzOiBtaW4oMWR2aCwgMC41ZHZ3KTtcbn1cbiIsIi5kZWVwbGliLWJ1dHRvbiB7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xufVxuXG4uZGVlcGxpYi1idXR0b24uYnV0dG9uLXN0eWxpbmcsXG4uZGVlcGxpYi1idXR0b24uYnV0dG9uLXN0eWxpbmc6OmJlZm9yZSB7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG59XG5cbi5kZWVwbGliLWJ1dHRvbiBpbWcge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMCU7XG4gIGxlZnQ6IDAlO1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiBsZWZ0O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWljb24tY29sb3IpO1xuICBiYWNrZ3JvdW5kLWJsZW5kLW1vZGU6IG11bHRpcGx5O1xuICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gIG1hc2stcG9zaXRpb246IGxlZnQ7XG4gIG1hc2stc2l6ZTogY29udGFpbjtcbiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgbWFzay1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgY29sb3I6IHRyYW5zcGFyZW50O1xuXG4gIGJhY2tncm91bmQtaW1hZ2U6IHZhcigtLWltYWdlKTtcbiAgbWFzay1pbWFnZTogdmFyKC0taW1hZ2UpO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuLmRlZXBsaWItYnV0dG9uOmhvdmVyIGltZyB7XG4gIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItaWNvbi1ob3Zlci1jb2xvcik7XG59XG5cbi5kZWVwbGliLWJ1dHRvbiAuYnV0dG9uLWxhYmVsIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQgIWltcG9ydGFudDtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG4gIGZvbnQtc2l6ZTogbWluKDMuNmR2aCwgMS44ZHZ3KTtcbn1cblxuLmRlZXBsaWItYnV0dG9uIC5idXR0b24tdG9vbHRpcCB7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG59XG4iLCIjZGVlcGxpYi1wYWdlLWxhYmVsIHtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG59XG5cbiNkZWVwbGliLXN1YnNjcmVlbi10aXRsZSB7XG4gIHRleHQtYWxpZ246IGxlZnQ7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xufVxuXG4uZGVlcGxpYi10ZXh0IHtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG59XG5cbi5kZWVwbGliLXN1YnNjcmVlbiB7XG4gIHBhZGRpbmc6IDA7XG4gIG1hcmdpbjogMDtcbiAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG59XG5cbi5kZWVwbGliLXN1YnNjcmVlbiAqIHtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgcG9pbnRlci1ldmVudHM6IGFsbDtcbn1cblxuLmRlZXBsaWItc2V0dGluZ3Mge1xuICBkaXNwbGF5OiBncmlkO1xuICBncmlkLWF1dG8tcm93czogbWluLWNvbnRlbnQ7XG4gIHBhZGRpbmc6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIGdhcDogMC4zZW07XG4gIG92ZXJmbG93LXk6IHNjcm9sbDtcbn1cblxuLmRlZXBsaWItbWlzYyB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW4tcmV2ZXJzZTtcbiAgZ2FwOiBtaW4oMXZoLCAwLjV2dyk7XG59XG5cbi5kZWVwbGliLXRvb2x0aXAge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWVsZW1lbnQtY29sb3IpO1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIHBhZGRpbmc6IG1pbigxdmgsIDAuNXZ3KTtcbiAgZm9udC1zaXplOiAwLjhlbTtcbiAgYm9yZGVyOiBtaW4oMC4ydmgsIDAuMXZ3KSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG59XG5cbi5kZWVwbGliLW92ZXJmbG93LWJveCB7XG4gIGJvcmRlcjogdmFyKC0tZGVlcGxpYi1ib3JkZXItY29sb3IpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLXdpZHRoKTtcbn1cblxuLmRlZXBsaWItcHJldi1uZXh0IHtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBnYXA6IG1pbigyZHZoLCAxZHZ3KTtcbiAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIGJvcmRlcjogbWluKDAuMnZoLCAwLjF2dykgc29saWQgdmFyKC0tZGVlcGxpYi1ib3JkZXItY29sb3IpO1xuXG4gIC5kZWVwbGliLXByZXYtbmV4dC1idXR0b24ge1xuICAgICY6aG92ZXIge1xuICAgICAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWhvdmVyLWNvbG9yKTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IHZhcigtLWRlZXBsaWItYm9yZGVyLXJhZGl1cyk7XG4gICAgfVxuICAgIFxuICAgIGhlaWdodDogMTAwJTtcbiAgICBhc3BlY3QtcmF0aW86IDE7XG4gIH1cblxuICAuZGVlcGxpYi1wcmV2LW5leHQtbGFiZWwge1xuICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XG4gIH1cbn1cblxuI2RlZXBsaWItbmF2LW1lbnUge1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBnYXA6IG1pbigyZHZoLCAxZHZ3KTtcbn0iLCIuZGVlcGxpYi1jaGVja2JveC1jb250YWluZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IDAuM2VtO1xufVxuXG4uZGVlcGxpYi1jaGVja2JveC1jb250YWluZXIgaW5wdXQuZGVlcGxpYi1pbnB1dCB7XG4gIHdpZHRoOiBtaW4oNXZoLCAyLjV2dyk7XG4gIGhlaWdodDogbWluKDV2aCwgMi41dncpO1xuICBib3JkZXItcmFkaXVzOiBtaW4oMS4wZHZoLCAwLjVkdncpO1xufVxuXG4uZGVlcGxpYi1jaGVja2JveC1jb250YWluZXIgaW5wdXQuZGVlcGxpYi1pbnB1dFt0eXBlPVwiY2hlY2tib3hcIl06Y2hlY2tlZDo6YmVmb3JlIHtcbiAgd2lkdGg6IDgwJTtcbiAgaGVpZ2h0OiA4MCU7XG59XG5cbi5kZWVwbGliLWlucHV0LWNvbnRhaW5lciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGdhcDogMC4zZW07XG59XG5cbi5kZWVwbGliLWlucHV0LWNvbnRhaW5lcjpoYXMobGFiZWwuZGVlcGxpYi10ZXh0KSB7XG4gIG1hcmdpbi10b3A6IG1pbigxdmgsIDAuNXZ3KTtcbn1cblxuLmRlZXBsaWItaW5wdXQtY29udGFpbmVyIGlucHV0LmRlZXBsaWItaW5wdXQge1xuICBmb250LXNpemU6IDAuNmVtO1xuICBwYWRkaW5nOiA1cHggMDtcbiAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIG91dGxpbmU6IG5vbmU7XG4gIHBhZGRpbmctbGVmdDogbWluKDF2aCwgMC41dncpO1xuICBwYWRkaW5nLXJpZ2h0OiBtaW4oMXZoLCAwLjV2dyk7XG4gIG1pbi1oZWlnaHQ6IG1pbig1ZHZoLCAyLjVkdncpO1xuICBib3JkZXItcmFkaXVzOiBtaW4oMS4wZHZoLCAwLjVkdncpO1xufVxuXG5cbi5kZWVwbGliLWlucHV0LWNvbnRhaW5lciBpbnB1dC5kZWVwbGliLWlucHV0W3R5cGU9XCJjb2xvclwiXSB7XG4gIHBhZGRpbmc6IDBweDtcbiAgd2lkdGg6IG1pbig1dmgsIDIuNXZ3KTtcbiAgaGVpZ2h0OiBtaW4oNXZoLCAyLjV2dyk7XG4gIGJvcmRlci1yYWRpdXM6IDBweDtcbn1cblxuLmRlZXBsaWItaW5wdXQtY29udGFpbmVyIGlucHV0LmRlZXBsaWItaW5wdXRbdHlwZT1cImNvbG9yXCJdOmRpc2FibGVkIHtcbiAgYm9yZGVyOiB2YXIoLS1kZWVwbGliLWJsb2NrZWQtY29sb3IpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLXdpZHRoKTtcbiAgY3Vyc29yOiBub3QtYWxsb3dlZDtcbn1cblxuaW5wdXQ6Oi13ZWJraXQtb3V0ZXItc3Bpbi1idXR0b24sXG5pbnB1dDo6LXdlYmtpdC1pbm5lci1zcGluLWJ1dHRvbiB7XG4gIC13ZWJraXQtYXBwZWFyYW5jZTogbm9uZTtcbiAgbWFyZ2luOiAwO1xufVxuXG5pbnB1dFt0eXBlPW51bWJlcl0ge1xuICBhcHBlYXJhbmNlOiB0ZXh0ZmllbGQ7XG4gIC1tb3otYXBwZWFyYW5jZTogdGV4dGZpZWxkO1xufVxuIiwiLmRlZXBsaWItaGlnaGxpZ2h0LXRleHQge1xuICBmb250LXdlaWdodDogYm9sZDtcbiAgY29sb3I6IHJnYigyMDMsIDE4NSwgMjMpO1xufVxuXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyayddIGRpdi5DaGF0TWVzc2FnZS5kZWVwbGliLW1lc3NhZ2UsXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyazInXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWNvbG9yKTtcbiAgYm9yZGVyOiBtaW4oMC4yZHZoLCAwLjFkdncpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG59XG5cbiNUZXh0QXJlYUNoYXRMb2cgZGl2LkNoYXRNZXNzYWdlLmRlZXBsaWItbWVzc2FnZSB7XG4gIGJhY2tncm91bmQtY29sb3I6ICNlZWU7XG4gIGJvcmRlcjogbWluKDAuMmR2aCwgMC4xZHZ3KSBzb2xpZCAjNDQwMTcxO1xuICBjb2xvcjogIzExMTtcbiAgcGFkZGluZy1sZWZ0OiBtaW4oMC42ZHZoLCAwLjNkdncpO1xuICBkaXNwbGF5OiBibG9jaztcbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcbn1cblxuI1RleHRBcmVhQ2hhdExvZ1tkYXRhLWNvbG9ydGhlbWU9J2RhcmsnXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEsXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyazInXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEge1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbn1cblxuI1RleHRBcmVhQ2hhdExvZyBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEge1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xuICBjb2xvcjogIzExMTtcbn1cbiIsIi5kZWVwbGliLW1vZGFsIHtcbiAgcG9zaXRpb246IGZpeGVkO1xuICB0b3A6IDEwJTtcbiAgbGVmdDogNTAlO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7XG4gIHotaW5kZXg6IDEwMDE7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IDAuNWVtO1xuICB3aWR0aDogbWF4KDUwZHZ3LCAyNWR2aCk7XG4gIGZvbnQtc2l6ZTogbWluKDRkdmgsIDJkdncpO1xuICBwYWRkaW5nOiBtaW4oMmR2aCwgMWR2dyk7XG4gIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItZWxlbWVudC1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjJkdmgsIDAuNmR2dyk7XG4gIGJvcmRlcjogbWluKDAuMmR2aCwgMC4xZHZ3KSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuXG4gIC5kZWVwbGliLW1vZGFsLWlucHV0IHtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBmb250LXNpemU6IG1pbigyLjZkdmgsIDEuOGR2dyk7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDEuMGR2aCwgMC41ZHZ3KTtcbiAgICBwYWRkaW5nOiBtaW4oMWR2aCwgMC41ZHZ3KTtcbiAgfVxuXG4gIGlucHV0LmRlZXBsaWItbW9kYWwtaW5wdXQge1xuICAgIG1heC13aWR0aDogbWF4KDUwZHZoLCAyNWR2dyk7XG4gIH1cblxuICAuZGVlcGxpYi1tb2RhbC1idXR0b24tY29udGFpbmVyIHtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gICAganVzdGlmeS1jb250ZW50OiBmbGV4LWVuZDtcbiAgICBnYXA6IDAuNWVtO1xuICAgIHdpZHRoOiAxMDAlO1xuXG4gICAgLmRlZXBsaWItYnV0dG9uIHtcbiAgICAgIGZvbnQtc2l6ZTogMC44ZW07XG4gICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgd2lkdGg6IGF1dG87XG4gICAgICBwYWRkaW5nOiBtaW4oMC40dmgsIDAuMnZ3KSBtaW4oMnZoLCAxdncpO1xuXG4gICAgICAuYnV0dG9uLWxhYmVsIHtcbiAgICAgICAgZGlzcGxheTogY29udGVudHM7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi5kZWVwbGliLW1vZGFsLWJsb2NrZXIge1xuICB6LWluZGV4OiAxMDAwO1xuICBwb3NpdGlvbjogZml4ZWQ7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgd2lkdGg6IDEwMGR2dztcbiAgaGVpZ2h0OiAxMDBkdmg7XG4gIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbn1cbiJdfQ== */`;
842
+ /*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VSb290IjoiL21lZGlhL05WTUUvU3R1ZmYvQ29kZS9CQy9CQy1EZWVwTGliL3NyYy9zdHlsZXMiLCJzb3VyY2VzIjpbInZhcnMuc2NzcyIsImJ1dHRvbnMuc2NzcyIsImVsZW1lbnRzLnNjc3MiLCJpbnB1dHMuc2NzcyIsIm1lc3NhZ2VzLnNjc3MiLCJtb2RhbC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQUE7RUFFRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7OztBQ2JGO0VBQ0U7RUFDQTtFQUNBOzs7QUFHRjtBQUFBO0VBRUU7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUVBO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7OztBQzNDRjtFQUNFO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBOzs7QUFHRjtFQUNFOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtFQUNFOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQU1FO0VBQ0E7O0FBTkE7RUFDRTtFQUNBOztBQU9KO0VBQ0U7OztBQUlKO0VBQ0U7RUFDQTtFQUNBOzs7QUN0RkY7RUFDRTtFQUNBO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUFJRjtFQUNFO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7OztBQUdGO0FBQUE7RUFFRTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7OztBQzdERjtFQUNFO0VBQ0E7OztBQUdGO0FBQUE7RUFFRTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtBQUFBO0VBRUU7OztBQUdGO0VBQ0U7RUFDQTtFQUNBOzs7QUM3QkY7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7O0FBR0Y7RUFDRTs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFOzs7QUFNUjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBIiwic291cmNlc0NvbnRlbnQiOlsiLmRlZXBsaWItc3Vic2NyZWVuLFxuLmRlZXBsaWItbW9kYWwge1xuICAtLWRlZXBsaWItYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tdG1kLW1haW4sIHdoaXRlKTtcbiAgLS1kZWVwbGliLWVsZW1lbnQtY29sb3I6IHZhcigtLXRtZC1lbGVtZW50LCB3aGl0ZSk7XG4gIC0tZGVlcGxpYi1lbGVtZW50LWhvdmVyLWNvbG9yOiB2YXIoLS10bWQtZWxlbWVudC1ob3ZlciwgY3lhbik7XG4gIC0tZGVlcGxpYi1ibG9ja2VkLWNvbG9yOiB2YXIoLS10bWQtYmxvY2tlZCwgcmVkKTtcbiAgLS1kZWVwbGliLXRleHQtY29sb3I6IHZhcigtLXRtZC10ZXh0LCBibGFjayk7XG4gIC0tZGVlcGxpYi1pY29uLWNvbG9yOiB2YXIoLS10bWQtYWNjZW50LCBibGFjayk7XG4gIC0tZGVlcGxpYi1pY29uLWhvdmVyLWNvbG9yOiB2YXIoLS10bWQtYWNjZW50LWhvdmVyLCBibGFjayk7XG4gIC0tZGVlcGxpYi1ib3JkZXItY29sb3I6IHZhcigtLXRtZC1hY2NlbnQsIGJsYWNrKTtcbiAgLS1kZWVwbGliLWJvcmRlci13aWR0aDogbWluKDAuMnZoLCAwLjF2dyk7XG4gIC0tZGVlcGxpYi1ib3JkZXItd2lkdGg6IG1pbigwLjJkdmgsIDAuMWR2dyk7XG4gIC0tZGVlcGxpYi1ib3JkZXItcmFkaXVzOiBtaW4oMXZoLCAwLjV2dyk7XG4gIC0tZGVlcGxpYi1ib3JkZXItcmFkaXVzOiBtaW4oMWR2aCwgMC41ZHZ3KTtcbn1cbiIsIi5kZWVwbGliLWJ1dHRvbiB7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xufVxuXG4uZGVlcGxpYi1idXR0b24uYnV0dG9uLXN0eWxpbmcsXG4uZGVlcGxpYi1idXR0b24uYnV0dG9uLXN0eWxpbmc6OmJlZm9yZSB7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG59XG5cbi5kZWVwbGliLWJ1dHRvbiBpbWcge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMCU7XG4gIGxlZnQ6IDAlO1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiBsZWZ0O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWljb24tY29sb3IpO1xuICBiYWNrZ3JvdW5kLWJsZW5kLW1vZGU6IG11bHRpcGx5O1xuICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gIG1hc2stcG9zaXRpb246IGxlZnQ7XG4gIG1hc2stc2l6ZTogY29udGFpbjtcbiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgbWFzay1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgY29sb3I6IHRyYW5zcGFyZW50O1xuXG4gIGJhY2tncm91bmQtaW1hZ2U6IHZhcigtLWltYWdlKTtcbiAgbWFzay1pbWFnZTogdmFyKC0taW1hZ2UpO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuLmRlZXBsaWItYnV0dG9uOmhvdmVyIGltZyB7XG4gIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItaWNvbi1ob3Zlci1jb2xvcik7XG59XG5cbi5kZWVwbGliLWJ1dHRvbiAuYnV0dG9uLWxhYmVsIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQgIWltcG9ydGFudDtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG4gIGZvbnQtc2l6ZTogbWluKDMuNmR2aCwgMS44ZHZ3KTtcbn1cblxuLmRlZXBsaWItYnV0dG9uIC5idXR0b24tdG9vbHRpcCB7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG59XG4iLCIjZGVlcGxpYi1wYWdlLWxhYmVsIHtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG59XG5cbiNkZWVwbGliLXN1YnNjcmVlbi10aXRsZSB7XG4gIHRleHQtYWxpZ246IGxlZnQ7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xufVxuXG4uZGVlcGxpYi10ZXh0IHtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG59XG5cbi5kZWVwbGliLXN1YnNjcmVlbiB7XG4gIHBhZGRpbmc6IDA7XG4gIG1hcmdpbjogMDtcbiAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG59XG5cbi5kZWVwbGliLXN1YnNjcmVlbiAqIHtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgcG9pbnRlci1ldmVudHM6IGFsbDtcbn1cblxuLmRlZXBsaWItc2V0dGluZ3Mge1xuICBkaXNwbGF5OiBncmlkO1xuICBncmlkLWF1dG8tcm93czogbWluLWNvbnRlbnQ7XG4gIHBhZGRpbmc6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIGdhcDogMC4zZW07XG4gIG92ZXJmbG93LXk6IHNjcm9sbDtcbn1cblxuLmRlZXBsaWItbWlzYyB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW4tcmV2ZXJzZTtcbiAgZ2FwOiBtaW4oMXZoLCAwLjV2dyk7XG59XG5cbi5kZWVwbGliLXRvb2x0aXAge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWVsZW1lbnQtY29sb3IpO1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIHBhZGRpbmc6IG1pbigxdmgsIDAuNXZ3KTtcbiAgZm9udC1zaXplOiAwLjhlbTtcbiAgYm9yZGVyOiBtaW4oMC4ydmgsIDAuMXZ3KSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG59XG5cbi5kZWVwbGliLW92ZXJmbG93LWJveCB7XG4gIGJvcmRlcjogdmFyKC0tZGVlcGxpYi1ib3JkZXItY29sb3IpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLXdpZHRoKTtcbn1cblxuLmRlZXBsaWItcHJldi1uZXh0IHtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBnYXA6IG1pbigyZHZoLCAxZHZ3KTtcbiAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIGJvcmRlcjogbWluKDAuMnZoLCAwLjF2dykgc29saWQgdmFyKC0tZGVlcGxpYi1ib3JkZXItY29sb3IpO1xuXG4gIC5kZWVwbGliLXByZXYtbmV4dC1idXR0b24ge1xuICAgICY6aG92ZXIge1xuICAgICAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWhvdmVyLWNvbG9yKTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IHZhcigtLWRlZXBsaWItYm9yZGVyLXJhZGl1cyk7XG4gICAgfVxuICAgIFxuICAgIGhlaWdodDogMTAwJTtcbiAgICBhc3BlY3QtcmF0aW86IDE7XG4gIH1cblxuICAuZGVlcGxpYi1wcmV2LW5leHQtbGFiZWwge1xuICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XG4gIH1cbn1cblxuI2RlZXBsaWItbmF2LW1lbnUge1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBnYXA6IG1pbigyZHZoLCAxZHZ3KTtcbn0iLCIuZGVlcGxpYi1jaGVja2JveC1jb250YWluZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IDAuM2VtO1xufVxuXG4uZGVlcGxpYi1jaGVja2JveC1jb250YWluZXIgaW5wdXQuZGVlcGxpYi1pbnB1dCB7XG4gIHdpZHRoOiBtaW4oNXZoLCAyLjV2dyk7XG4gIGhlaWdodDogbWluKDV2aCwgMi41dncpO1xuICBib3JkZXItcmFkaXVzOiBtaW4oMS4wZHZoLCAwLjVkdncpO1xufVxuXG4uZGVlcGxpYi1jaGVja2JveC1jb250YWluZXIgaW5wdXQuZGVlcGxpYi1pbnB1dFt0eXBlPVwiY2hlY2tib3hcIl06Y2hlY2tlZDo6YmVmb3JlIHtcbiAgd2lkdGg6IDgwJTtcbiAgaGVpZ2h0OiA4MCU7XG59XG5cbi5kZWVwbGliLWlucHV0LWNvbnRhaW5lciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGdhcDogMC4zZW07XG59XG5cbi5kZWVwbGliLWlucHV0LWNvbnRhaW5lcjpoYXMobGFiZWwuZGVlcGxpYi10ZXh0KSB7XG4gIG1hcmdpbi10b3A6IG1pbigxdmgsIDAuNXZ3KTtcbn1cblxuLmRlZXBsaWItaW5wdXQtY29udGFpbmVyIGlucHV0LmRlZXBsaWItaW5wdXQge1xuICBmb250LXNpemU6IDAuNmVtO1xuICBwYWRkaW5nOiA1cHggMDtcbiAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIG91dGxpbmU6IG5vbmU7XG4gIHBhZGRpbmctbGVmdDogbWluKDF2aCwgMC41dncpO1xuICBwYWRkaW5nLXJpZ2h0OiBtaW4oMXZoLCAwLjV2dyk7XG4gIG1pbi1oZWlnaHQ6IG1pbig1ZHZoLCAyLjVkdncpO1xuICBib3JkZXItcmFkaXVzOiBtaW4oMS4wZHZoLCAwLjVkdncpO1xufVxuXG5cbi5kZWVwbGliLWlucHV0LWNvbnRhaW5lciBpbnB1dC5kZWVwbGliLWlucHV0W3R5cGU9XCJjb2xvclwiXSB7XG4gIHBhZGRpbmc6IDBweDtcbiAgd2lkdGg6IG1pbig1dmgsIDIuNXZ3KTtcbiAgaGVpZ2h0OiBtaW4oNXZoLCAyLjV2dyk7XG4gIGJvcmRlci1yYWRpdXM6IDBweDtcbn1cblxuLmRlZXBsaWItaW5wdXQtY29udGFpbmVyIGlucHV0LmRlZXBsaWItaW5wdXRbdHlwZT1cImNvbG9yXCJdOmRpc2FibGVkIHtcbiAgYm9yZGVyOiB2YXIoLS1kZWVwbGliLWJsb2NrZWQtY29sb3IpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLXdpZHRoKTtcbiAgY3Vyc29yOiBub3QtYWxsb3dlZDtcbn1cblxuaW5wdXQ6Oi13ZWJraXQtb3V0ZXItc3Bpbi1idXR0b24sXG5pbnB1dDo6LXdlYmtpdC1pbm5lci1zcGluLWJ1dHRvbiB7XG4gIC13ZWJraXQtYXBwZWFyYW5jZTogbm9uZTtcbiAgbWFyZ2luOiAwO1xufVxuXG5pbnB1dFt0eXBlPW51bWJlcl0ge1xuICBhcHBlYXJhbmNlOiB0ZXh0ZmllbGQ7XG4gIC1tb3otYXBwZWFyYW5jZTogdGV4dGZpZWxkO1xufVxuIiwiLmRlZXBsaWItaGlnaGxpZ2h0LXRleHQge1xuICBmb250LXdlaWdodDogYm9sZDtcbiAgY29sb3I6IHJnYigyMDMsIDE4NSwgMjMpO1xufVxuXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyayddIGRpdi5DaGF0TWVzc2FnZS5kZWVwbGliLW1lc3NhZ2UsXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyazInXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWNvbG9yKTtcbiAgYm9yZGVyOiBtaW4oMC4yZHZoLCAwLjFkdncpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG59XG5cbiNUZXh0QXJlYUNoYXRMb2cgZGl2LkNoYXRNZXNzYWdlLmRlZXBsaWItbWVzc2FnZSB7XG4gIGJhY2tncm91bmQtY29sb3I6ICNlZWU7XG4gIGJvcmRlcjogbWluKDAuMmR2aCwgMC4xZHZ3KSBzb2xpZCAjNDQwMTcxO1xuICBjb2xvcjogIzExMTtcbiAgcGFkZGluZy1sZWZ0OiBtaW4oMC42ZHZoLCAwLjNkdncpO1xuICBkaXNwbGF5OiBibG9jaztcbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcbn1cblxuI1RleHRBcmVhQ2hhdExvZ1tkYXRhLWNvbG9ydGhlbWU9J2RhcmsnXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEsXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyazInXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEge1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbn1cblxuI1RleHRBcmVhQ2hhdExvZyBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEge1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xuICBjb2xvcjogIzExMTtcbn1cbiIsIi5kZWVwbGliLW1vZGFsIHtcbiAgcG9zaXRpb246IGZpeGVkO1xuICB0b3A6IDEwJTtcbiAgbGVmdDogNTAlO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7XG4gIHotaW5kZXg6IDEwMDE7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IDAuNWVtO1xuICB3aWR0aDogbWF4KDUwZHZ3LCAyNWR2aCk7XG4gIGZvbnQtc2l6ZTogbWluKDRkdmgsIDJkdncpO1xuICBwYWRkaW5nOiBtaW4oMmR2aCwgMWR2dyk7XG4gIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItZWxlbWVudC1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjJkdmgsIDAuNmR2dyk7XG4gIGJvcmRlcjogbWluKDAuMmR2aCwgMC4xZHZ3KSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuXG4gIC5kZWVwbGliLW1vZGFsLWlucHV0IHtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBmb250LXNpemU6IG1pbigyLjZkdmgsIDEuOGR2dyk7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDEuMGR2aCwgMC41ZHZ3KTtcbiAgICBwYWRkaW5nOiBtaW4oMWR2aCwgMC41ZHZ3KTtcbiAgfVxuXG4gIGlucHV0LmRlZXBsaWItbW9kYWwtaW5wdXQge1xuICAgIG1heC13aWR0aDogbWF4KDUwZHZoLCAyNWR2dyk7XG4gIH1cblxuICAuZGVlcGxpYi1tb2RhbC1idXR0b24tY29udGFpbmVyIHtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gICAganVzdGlmeS1jb250ZW50OiBmbGV4LWVuZDtcbiAgICBnYXA6IDAuNWVtO1xuICAgIHdpZHRoOiAxMDAlO1xuXG4gICAgLmRlZXBsaWItYnV0dG9uIHtcbiAgICAgIGZvbnQtc2l6ZTogMC44ZW07XG4gICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgd2lkdGg6IGF1dG87XG4gICAgICBwYWRkaW5nOiBtaW4oMC40dmgsIDAuMnZ3KSBtaW4oMnZoLCAxdncpO1xuXG4gICAgICAuYnV0dG9uLWxhYmVsIHtcbiAgICAgICAgZGlzcGxheTogY29udGVudHM7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi5kZWVwbGliLW1vZGFsLWJsb2NrZXIge1xuICB6LWluZGV4OiAxMDAwO1xuICBwb3NpdGlvbjogZml4ZWQ7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgd2lkdGg6IDEwMGR2dztcbiAgaGVpZ2h0OiAxMDBkdmg7XG4gIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbn1cbiJdfQ== */`;
739
843
 
740
844
  // src/base/initialization.ts
741
845
  var modStorage;
@@ -769,11 +873,7 @@ async function init(options) {
769
873
  const MOD_VERSION = ModSdkManager.ModInfo.version;
770
874
  if (window[MOD_NAME + "Loaded"]) return;
771
875
  modStorage.load();
772
- if (options.pathToTranslationsFolder) {
773
- await Localization.init({
774
- pathToTranslationsFolder: options.pathToTranslationsFolder
775
- });
776
- }
876
+ await Localization.init(options.translationOptions);
777
877
  if (options.modules && !initModules(options.modules)) {
778
878
  unloadMod();
779
879
  return;
@@ -858,20 +958,34 @@ var GUI = class _GUI extends BaseModule {
858
958
  static {
859
959
  __name(this, "GUI");
860
960
  }
961
+ /** The singleton instance of the GUI controller. */
861
962
  static instance = null;
963
+ /** All subscreens managed by this GUI, including the main menu and module settings screens. */
862
964
  _subscreens;
965
+ /** The mod's main menu screen. */
863
966
  _mainMenu;
967
+ /** The currently active subscreen, or `null` if none is active. */
864
968
  _currentSubscreen = null;
969
+ /** Options defining how the mod's settings button is displayed and behaves. */
865
970
  _modButtonOptions;
971
+ /** Returns all registered subscreens. */
866
972
  get subscreens() {
867
973
  return this._subscreens;
868
974
  }
975
+ /** Returns the main menu subscreen instance. */
869
976
  get mainMenu() {
870
977
  return this._mainMenu;
871
978
  }
979
+ /** Returns the currently active subscreen. */
872
980
  get currentSubscreen() {
873
981
  return this._currentSubscreen;
874
982
  }
983
+ /**
984
+ * Sets the current subscreen.
985
+ * Accepts either a `BaseSubscreen` instance or the `name` of a subscreen.
986
+ *
987
+ * @throws If a string is provided but no subscreen with that name exists.
988
+ */
875
989
  set currentSubscreen(subscreen) {
876
990
  if (this._currentSubscreen) {
877
991
  this._currentSubscreen.unload();
@@ -883,13 +997,16 @@ var GUI = class _GUI extends BaseModule {
883
997
  } else {
884
998
  this._currentSubscreen = subscreen;
885
999
  }
886
- PreferenceMessage = "";
887
- PreferencePageCurrent = 1;
888
1000
  if (this._currentSubscreen) {
889
1001
  this._currentSubscreen.load();
890
1002
  this._currentSubscreen.resize(true);
891
1003
  }
892
1004
  }
1005
+ /**
1006
+ * Creates the GUI instance and initializes the main menu.
1007
+ *
1008
+ * @throws If another `GUI` instance already exists.
1009
+ */
893
1010
  constructor(modButtonOptions) {
894
1011
  super();
895
1012
  if (_GUI.instance) {
@@ -903,9 +1020,13 @@ var GUI = class _GUI extends BaseModule {
903
1020
  this._modButtonOptions = modButtonOptions;
904
1021
  _GUI.instance = this;
905
1022
  }
906
- get defaultSettings() {
907
- return null;
908
- }
1023
+ /**
1024
+ * Loads the GUI and registers the mod's settings button in the extensions menu.
1025
+ *
1026
+ * - Creates subscreens for each module's settings screen.
1027
+ * - Registers lifecycle callbacks for subscreens events.
1028
+ * - Sets up the main menu and its subscreens.
1029
+ */
909
1030
  load() {
910
1031
  for (const module of modules()) {
911
1032
  if (!module.settingsScreen) continue;
@@ -916,36 +1037,34 @@ var GUI = class _GUI extends BaseModule {
916
1037
  Identifier: this._modButtonOptions.Identifier,
917
1038
  ButtonText: this._modButtonOptions.ButtonText,
918
1039
  Image: this._modButtonOptions.Image,
919
- load: this._modButtonOptions.load || (() => {
1040
+ load: /* @__PURE__ */ __name(() => {
920
1041
  setSubscreen(new MainMenu(this));
921
- }),
922
- run: this._modButtonOptions.run || (() => {
1042
+ }, "load"),
1043
+ run: /* @__PURE__ */ __name(() => {
923
1044
  if (this._currentSubscreen) {
924
- MainCanvas.textAlign = "left";
925
1045
  this._currentSubscreen.run();
926
- MainCanvas.textAlign = "center";
927
1046
  const newCanvasPosition = [MainCanvas.canvas.offsetLeft, MainCanvas.canvas.offsetTop, MainCanvas.canvas.clientWidth, MainCanvas.canvas.clientHeight];
928
1047
  if (!CommonArraysEqual(newCanvasPosition, DrawCanvasPosition)) {
929
1048
  DrawCanvasPosition = newCanvasPosition;
930
1049
  this._currentSubscreen.resize(false);
931
1050
  }
932
1051
  }
933
- }),
934
- click: this._modButtonOptions.click || (() => {
1052
+ }, "run"),
1053
+ click: /* @__PURE__ */ __name(() => {
935
1054
  if (this._currentSubscreen) {
936
1055
  this._currentSubscreen.click();
937
1056
  }
938
- }),
939
- exit: this._modButtonOptions.exit || (() => {
1057
+ }, "click"),
1058
+ exit: /* @__PURE__ */ __name(() => {
940
1059
  if (this._currentSubscreen) {
941
1060
  this._currentSubscreen.exit();
942
1061
  }
943
- }),
944
- unload: this._modButtonOptions.unload || (() => {
1062
+ }, "exit"),
1063
+ unload: /* @__PURE__ */ __name(() => {
945
1064
  if (this._currentSubscreen) {
946
1065
  this._currentSubscreen.unload();
947
1066
  }
948
- })
1067
+ }, "unload")
949
1068
  });
950
1069
  }
951
1070
  };
@@ -955,10 +1074,19 @@ var VersionModule = class _VersionModule extends BaseModule {
955
1074
  static {
956
1075
  __name(this, "VersionModule");
957
1076
  }
1077
+ /** Whether the current session is running a new version compared to stored data */
958
1078
  static isItNewVersion = false;
1079
+ /** The current mod version (retrieved from `ModSdkManager.ModInfo.version`) */
959
1080
  static Version;
1081
+ /** Message to display when a new version is detected */
960
1082
  static NewVersionMessage = "";
1083
+ /** List of registered migration handlers, sorted by version */
961
1084
  static Migrators = [];
1085
+ /**
1086
+ * Initializes the module on load:
1087
+ * - Stores the current mod version.
1088
+ * - Hooks into `ChatRoomSync` to show a "new version" message when applicable.
1089
+ */
962
1090
  load() {
963
1091
  _VersionModule.Version = ModSdkManager.ModInfo.version;
964
1092
  ModSdkManager.prototype.hookFunction(
@@ -973,6 +1101,14 @@ var VersionModule = class _VersionModule extends BaseModule {
973
1101
  "VersionModule"
974
1102
  );
975
1103
  }
1104
+ /**
1105
+ * Checks if the stored version differs from the current version.
1106
+ * If a new version is detected:
1107
+ * - Flags the session as updated.
1108
+ * - Runs applicable migrations.
1109
+ * - Updates stored version in player data.
1110
+ * - Saves `modStorage`.
1111
+ */
976
1112
  static checkVersionUpdate() {
977
1113
  const PreviousVersion = _VersionModule.loadVersion();
978
1114
  const CurrentVersion = _VersionModule.Version;
@@ -983,6 +1119,10 @@ var VersionModule = class _VersionModule extends BaseModule {
983
1119
  }
984
1120
  modStorage.save();
985
1121
  }
1122
+ /**
1123
+ * Executes migrations for all registered migrators whose `MigrationVersion`
1124
+ * is newer than the previously stored version.
1125
+ */
986
1126
  static checkVersionMigration() {
987
1127
  const PreviousVersion = _VersionModule.loadVersion();
988
1128
  for (const migrator of _VersionModule.Migrators) {
@@ -992,16 +1132,27 @@ var VersionModule = class _VersionModule extends BaseModule {
992
1132
  }
993
1133
  }
994
1134
  }
1135
+ /**
1136
+ * Registers a new migrator for handling version-specific changes.
1137
+ * Migrators are sorted by their `MigrationVersion` in ascending order.
1138
+ */
995
1139
  static registerMigrator(migrator) {
996
1140
  _VersionModule.Migrators.push(migrator);
997
1141
  _VersionModule.Migrators.sort((a, b) => a.MigrationVersion.localeCompare(b.MigrationVersion));
998
1142
  }
1143
+ /** Sets the message that will be displayed when a new version is detected. */
999
1144
  static setNewVersionMessage(newVersionMessage) {
1000
1145
  _VersionModule.NewVersionMessage = newVersionMessage;
1001
1146
  }
1147
+ /** Sends the currently configured "new version" message to the local player. */
1002
1148
  static sendNewVersionMessage() {
1003
1149
  sendLocalMessage("deeplib-new-version", _VersionModule.NewVersionMessage);
1004
1150
  }
1151
+ /**
1152
+ * Determines if a given `candidate` version is newer than the `current` version.
1153
+ *
1154
+ * Version strings are expected in `MAJOR.MINOR.PATCH` format.
1155
+ */
1005
1156
  static isNewVersion(current, candidate) {
1006
1157
  if (current !== void 0) {
1007
1158
  const CURRENT_ = current.split("."), CANDIDATE_ = candidate.split(".");
@@ -1017,11 +1168,13 @@ var VersionModule = class _VersionModule extends BaseModule {
1017
1168
  }
1018
1169
  return false;
1019
1170
  }
1171
+ /** Saves the current mod version into persistent player storage. */
1020
1172
  static saveVersion() {
1021
1173
  if (modStorage.playerStorage) {
1022
1174
  Player[ModSdkManager.ModInfo.name].Version = _VersionModule.Version;
1023
1175
  }
1024
1176
  }
1177
+ /** Loads the stored mod version from persistent player storage. */
1025
1178
  static loadVersion() {
1026
1179
  return modStorage.playerStorage?.Version;
1027
1180
  }
@@ -1244,8 +1397,8 @@ function hasSetter(obj, prop) {
1244
1397
  }
1245
1398
  __name(hasSetter, "hasSetter");
1246
1399
 
1247
- // src/utilities/elements/advanced_elements.ts
1248
- var advancedElement = {
1400
+ // src/utilities/elements/elements.ts
1401
+ var advElement = {
1249
1402
  createButton: elementCreateButton,
1250
1403
  createCheckbox: elementCreateCheckbox,
1251
1404
  createInput: elementCreateInput,
@@ -1484,7 +1637,7 @@ function elementPrevNext(options) {
1484
1637
  id: options.id
1485
1638
  },
1486
1639
  children: [
1487
- advancedElement.createButton({
1640
+ advElement.createButton({
1488
1641
  id: `deeplib-prev-next-${options.id}-prev-button`,
1489
1642
  image: `${PUBLIC_URL}/dl_images/arrow_left.svg`,
1490
1643
  onClick: /* @__PURE__ */ __name(() => {
@@ -1506,14 +1659,14 @@ function elementPrevNext(options) {
1506
1659
  }
1507
1660
  }
1508
1661
  }),
1509
- advancedElement.createLabel({
1662
+ advElement.createLabel({
1510
1663
  id: `${options.id}-label`,
1511
1664
  label: options.initialLabel,
1512
1665
  htmlOptions: {
1513
1666
  classList: ["deeplib-prev-next-label"]
1514
1667
  }
1515
1668
  }),
1516
- advancedElement.createButton({
1669
+ advElement.createButton({
1517
1670
  id: `deeplib-prev-next-${options.id}-next-button`,
1518
1671
  image: `${PUBLIC_URL}/dl_images/arrow_right.svg`,
1519
1672
  onClick: /* @__PURE__ */ __name(() => {
@@ -1587,22 +1740,39 @@ var Modal = class _Modal {
1587
1740
  blocker;
1588
1741
  inputEl;
1589
1742
  timeoutId;
1743
+ /** Static modal queue. */
1590
1744
  static queue = [];
1745
+ /** Flag to indicate if a modal is currently being shown. */
1591
1746
  static processing = false;
1747
+ /**
1748
+ * Displays the modal and resolves with the chosen action and input value.
1749
+ */
1592
1750
  show() {
1593
1751
  return _Modal.enqueue(this);
1594
1752
  }
1753
+ /**
1754
+ * Shows a simple alert modal with a single "OK" button.
1755
+ */
1595
1756
  static async alert(msg, timeoutMs) {
1596
1757
  await new _Modal({ prompt: msg, buttons: [{ action: "close", text: "OK" }], timeoutMs }).show();
1597
1758
  }
1759
+ /**
1760
+ * Shows a confirmation modal with "Cancel" and "OK" buttons.
1761
+ * Returns true if "OK" is clicked.
1762
+ */
1598
1763
  static async confirm(msg) {
1599
1764
  const [action] = await new _Modal({ prompt: msg, buttons: [{ text: "Cancel", action: "cancel" }, { text: "OK", action: "ok" }] }).show();
1600
1765
  return action === "ok";
1601
1766
  }
1767
+ /**
1768
+ * Shows a prompt modal with an input field and "Submit"/"Cancel" buttons.
1769
+ * Returns the input value if submitted, otherwise null.
1770
+ */
1602
1771
  static async prompt(msg, defaultValue = "") {
1603
1772
  const [action, value] = await new _Modal({ prompt: msg, timeoutMs: 0, input: { type: "input", defaultValue }, buttons: [{ text: "Cancel", action: "cancel" }, { text: "Submit", action: "submit" }] }).show();
1604
1773
  return action === "submit" ? value : null;
1605
1774
  }
1775
+ /** Creates the input element for the modal, applying configuration and validation. */
1606
1776
  renderInput(cfg) {
1607
1777
  const el = document.createElement(cfg.type);
1608
1778
  el.classList.add("deeplib-modal-input");
@@ -1617,12 +1787,13 @@ var Modal = class _Modal {
1617
1787
  this.inputEl = el;
1618
1788
  return el;
1619
1789
  }
1790
+ /** Creates modal action buttons from configuration. */
1620
1791
  renderButtons() {
1621
1792
  const container = document.createElement("div");
1622
1793
  container.classList.add("deeplib-modal-button-container");
1623
1794
  const btns = this.opts.buttons ? [...this.opts.buttons] : [];
1624
1795
  btns.forEach((b) => {
1625
- const btn = advancedElement.createButton({
1796
+ const btn = advElement.createButton({
1626
1797
  label: b.text,
1627
1798
  id: `deeplib-modal-${b.action}`,
1628
1799
  disabled: b.disabled,
@@ -1632,6 +1803,7 @@ var Modal = class _Modal {
1632
1803
  });
1633
1804
  return container;
1634
1805
  }
1806
+ /** Creates the modal backdrop blocker with optional click-to-close behavior. */
1635
1807
  createBlocker() {
1636
1808
  const blocker = document.createElement("div");
1637
1809
  blocker.classList.add("deeplib-modal-blocker");
@@ -1640,6 +1812,7 @@ var Modal = class _Modal {
1640
1812
  blocker.addEventListener("click", () => this.close("close"));
1641
1813
  return blocker;
1642
1814
  }
1815
+ /** Implements a focus trap to keep keyboard navigation inside the modal. */
1643
1816
  setupFocusTrap() {
1644
1817
  const focusable = 'button, [href], input, textarea, select, [tabindex]:not([tabindex="-1"])';
1645
1818
  const elements = Array.from(this.dialog.querySelectorAll(focusable));
@@ -1671,6 +1844,7 @@ var Modal = class _Modal {
1671
1844
  (this.inputEl || first)?.focus();
1672
1845
  });
1673
1846
  }
1847
+ /** Closes the modal, cleans up DOM, resolves promise, and shows next queued modal. */
1674
1848
  close(action) {
1675
1849
  if (this.timeoutId) clearTimeout(this.timeoutId);
1676
1850
  this.dialog.close();
@@ -1703,7 +1877,6 @@ var Modal = class _Modal {
1703
1877
  }
1704
1878
  }
1705
1879
  };
1706
- window.Modal = Modal;
1707
1880
 
1708
1881
  // src/screens/main_menu.ts
1709
1882
  var MainMenu = class _MainMenu extends BaseSubscreen {
@@ -1725,7 +1898,7 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
1725
1898
  return;
1726
1899
  }
1727
1900
  super.load();
1728
- const exitButton = advancedElement.createButton({
1901
+ const exitButton = advElement.createButton({
1729
1902
  id: "exit",
1730
1903
  size: [90, 90],
1731
1904
  image: `${PUBLIC_URL}/dl_images/exit.svg`,
@@ -1740,7 +1913,7 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
1740
1913
  }
1741
1914
  for (const screen of this.subscreens) {
1742
1915
  if (screen.name == "mainmenu") continue;
1743
- const button = advancedElement.createButton({
1916
+ const button = advElement.createButton({
1744
1917
  id: `${screen.name}-button`,
1745
1918
  image: screen.icon,
1746
1919
  label: getText(`mainmenu.button.${screen.name}`),
@@ -1749,12 +1922,12 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
1749
1922
  }, "onClick"),
1750
1923
  size: [null, 90]
1751
1924
  });
1752
- layoutElement.appendToSettingsDiv(button);
1925
+ layout.appendToSettingsDiv(button);
1753
1926
  }
1754
- const miscDiv = layoutElement.createMiscDiv();
1755
- layoutElement.appendToSubscreenDiv(miscDiv);
1927
+ const miscDiv = layout.createMiscDiv();
1928
+ layout.appendToSubscreen(miscDiv);
1756
1929
  if (_MainMenu.options.wikiLink) {
1757
- const wikiButton = advancedElement.createButton({
1930
+ const wikiButton = advElement.createButton({
1758
1931
  id: "deeplib-wiki-button",
1759
1932
  image: `${PUBLIC_URL}/dl_images/notebook.svg`,
1760
1933
  label: getText("mainmenu.button.wiki"),
@@ -1763,10 +1936,10 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
1763
1936
  }, "onClick"),
1764
1937
  size: [null, 80]
1765
1938
  });
1766
- layoutElement.appendToMiscDiv(wikiButton);
1939
+ layout.appendToMiscDiv(wikiButton);
1767
1940
  }
1768
1941
  if (_MainMenu.options.repoLink) {
1769
- const repoButton = advancedElement.createButton({
1942
+ const repoButton = advElement.createButton({
1770
1943
  id: "deeplib-repo-button",
1771
1944
  image: `${PUBLIC_URL}/dl_images/git.svg`,
1772
1945
  label: getText("mainmenu.button.repo"),
@@ -1775,10 +1948,10 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
1775
1948
  }, "onClick"),
1776
1949
  size: [null, 80]
1777
1950
  });
1778
- layoutElement.appendToMiscDiv(repoButton);
1951
+ layout.appendToMiscDiv(repoButton);
1779
1952
  }
1780
1953
  if (_MainMenu.options.resetSubscreen) {
1781
- const resetButton = advancedElement.createButton({
1954
+ const resetButton = advElement.createButton({
1782
1955
  id: "deeplib-reset-button",
1783
1956
  image: `${PUBLIC_URL}/dl_images/trash_bin.svg`,
1784
1957
  label: getText("mainmenu.button.reset"),
@@ -1787,10 +1960,10 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
1787
1960
  }, "onClick"),
1788
1961
  size: [null, 80]
1789
1962
  });
1790
- layoutElement.appendToMiscDiv(resetButton);
1963
+ layout.appendToMiscDiv(resetButton);
1791
1964
  }
1792
1965
  if (_MainMenu.options.importExportSubscreen) {
1793
- const importExportButton = advancedElement.createButton({
1966
+ const importExportButton = advElement.createButton({
1794
1967
  id: "deeplib-import-export-button",
1795
1968
  image: `${PUBLIC_URL}/dl_images/transfer.svg`,
1796
1969
  label: getText("mainmenu.button.import_export"),
@@ -1799,10 +1972,10 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
1799
1972
  }, "onClick"),
1800
1973
  size: [null, 80]
1801
1974
  });
1802
- layoutElement.appendToMiscDiv(importExportButton);
1975
+ layout.appendToMiscDiv(importExportButton);
1803
1976
  }
1804
1977
  if (IS_DEBUG) {
1805
- const debugButton = advancedElement.createButton({
1978
+ const debugButton = advElement.createButton({
1806
1979
  id: "deeplib-debug-button",
1807
1980
  image: `${PUBLIC_URL}/dl_images/bug.svg`,
1808
1981
  onClick: /* @__PURE__ */ __name(() => {
@@ -1851,7 +2024,7 @@ var GuiImportExport = class extends BaseSubscreen {
1851
2024
  }
1852
2025
  load() {
1853
2026
  super.load();
1854
- const importFromFileButton = advancedElement.createButton({
2027
+ const importFromFileButton = advElement.createButton({
1855
2028
  id: "deeplib-import-file-button",
1856
2029
  size: [600, 90],
1857
2030
  image: `${PUBLIC_URL}/dl_images/file_import.svg`,
@@ -1860,8 +2033,8 @@ var GuiImportExport = class extends BaseSubscreen {
1860
2033
  }, "onClick"),
1861
2034
  label: getText("import-export.button.import_file")
1862
2035
  });
1863
- layoutElement.appendToSettingsDiv(importFromFileButton);
1864
- const exportToFileButton = advancedElement.createButton({
2036
+ layout.appendToSettingsDiv(importFromFileButton);
2037
+ const exportToFileButton = advElement.createButton({
1865
2038
  id: "deeplib-export-file-button",
1866
2039
  size: [600, 90],
1867
2040
  image: `${PUBLIC_URL}/dl_images/file_export.svg`,
@@ -1870,8 +2043,8 @@ var GuiImportExport = class extends BaseSubscreen {
1870
2043
  }, "onClick"),
1871
2044
  label: getText("import-export.button.export_file")
1872
2045
  });
1873
- layoutElement.appendToSettingsDiv(exportToFileButton);
1874
- const importFromClipboardButton = advancedElement.createButton({
2046
+ layout.appendToSettingsDiv(exportToFileButton);
2047
+ const importFromClipboardButton = advElement.createButton({
1875
2048
  id: "deeplib-import-clipboard-button",
1876
2049
  size: [600, 90],
1877
2050
  image: `${PUBLIC_URL}/dl_images/clipboard_import.svg`,
@@ -1880,8 +2053,8 @@ var GuiImportExport = class extends BaseSubscreen {
1880
2053
  }, "onClick"),
1881
2054
  label: getText("import-export.button.import_clipboard")
1882
2055
  });
1883
- layoutElement.appendToSettingsDiv(importFromClipboardButton);
1884
- const exportToClipboardButton = advancedElement.createButton({
2056
+ layout.appendToSettingsDiv(importFromClipboardButton);
2057
+ const exportToClipboardButton = advElement.createButton({
1885
2058
  id: "deeplib-export-clipboard-button",
1886
2059
  size: [600, 90],
1887
2060
  image: `${PUBLIC_URL}/dl_images/clipboard_export.svg`,
@@ -1890,11 +2063,12 @@ var GuiImportExport = class extends BaseSubscreen {
1890
2063
  }, "onClick"),
1891
2064
  label: getText("import-export.button.export_clipboard")
1892
2065
  });
1893
- layoutElement.appendToSettingsDiv(exportToClipboardButton);
2066
+ layout.appendToSettingsDiv(exportToClipboardButton);
1894
2067
  }
1895
2068
  resize() {
1896
2069
  super.resize();
1897
2070
  }
2071
+ /** Exports the mod data using the specified method. */
1898
2072
  async dataExport(transferMethod) {
1899
2073
  try {
1900
2074
  const data = LZString.compressToBase64(JSON.stringify(modStorage.playerStorage));
@@ -1910,6 +2084,7 @@ var GuiImportExport = class extends BaseSubscreen {
1910
2084
  deepLibLogger.error(`Data export failed for ${ModSdkManager.ModInfo.name}.`, error);
1911
2085
  }
1912
2086
  }
2087
+ /** Imports mod data using the specified method. */
1913
2088
  async dataImport(transferMethod) {
1914
2089
  try {
1915
2090
  let importedData = "";
@@ -1933,6 +2108,7 @@ var GuiImportExport = class extends BaseSubscreen {
1933
2108
  deepLibLogger.error(`Data import failed for ${ModSdkManager.ModInfo.name}.`, error);
1934
2109
  }
1935
2110
  }
2111
+ /** Saves data to a file using the browser's save dialog. */
1936
2112
  async exportToFile(data, defaultFileName) {
1937
2113
  const CUSTOM_EXTENSION = this.importExportOptions.customFileExtension.startsWith(".") ? this.importExportOptions.customFileExtension : "." + this.importExportOptions.customFileExtension;
1938
2114
  const suggestedName = defaultFileName.endsWith(CUSTOM_EXTENSION) ? defaultFileName : defaultFileName + CUSTOM_EXTENSION;
@@ -1972,6 +2148,7 @@ var GuiImportExport = class extends BaseSubscreen {
1972
2148
  URL.revokeObjectURL(link.href);
1973
2149
  }
1974
2150
  }
2151
+ /** Opens a file picker and reads the selected file's contents, importing the data. */
1975
2152
  async importFromFile() {
1976
2153
  const CUSTOM_EXTENSION = this.importExportOptions.customFileExtension.startsWith(".") ? this.importExportOptions.customFileExtension : "." + this.importExportOptions.customFileExtension;
1977
2154
  async function importFromFileInternal(file) {
@@ -2024,11 +2201,13 @@ var GuiImportExport = class extends BaseSubscreen {
2024
2201
  });
2025
2202
  }
2026
2203
  }
2204
+ /** Copies the given data to the clipboard. */
2027
2205
  async exportToClipboard(data) {
2028
2206
  return navigator.clipboard.writeText(data).catch((error) => {
2029
2207
  throw new Error("Failed to copy data to clipboard." + error);
2030
2208
  });
2031
2209
  }
2210
+ /** Prompts the user to enter data and returns it. */
2032
2211
  async importFromClipboard() {
2033
2212
  return Modal.prompt("Enter data to import").catch((error) => {
2034
2213
  throw new Error("Failed to read data from clipboard." + error);
@@ -2041,7 +2220,9 @@ var ModStorage = class _ModStorage {
2041
2220
  static {
2042
2221
  __name(this, "ModStorage");
2043
2222
  }
2223
+ /** Singleton instance of ModStorage */
2044
2224
  static _instance = null;
2225
+ /** The unique mod identifier used as key prefix in storage */
2045
2226
  modName;
2046
2227
  constructor(modName) {
2047
2228
  if (!_ModStorage._instance) {
@@ -2105,12 +2286,36 @@ var ModStorage = class _ModStorage {
2105
2286
  }
2106
2287
  };
2107
2288
 
2108
- // src/utilities/elements/element_helpers.ts
2289
+ // src/utilities/elements/helpers.ts
2109
2290
  var domUtil = {
2291
+ /**
2292
+ * Automatically sets the position of the element based on the given position.
2293
+ * The position can be either a [x, y] tuple or a function returning such a tuple.
2294
+ * If both x and y are defined, the element's position is updated accordingly.
2295
+ */
2110
2296
  autoSetPosition,
2297
+ /**
2298
+ * Automatically sets the size of the element based on the given size.
2299
+ * The size can be either a [width, height] tuple or a function returning such a tuple.
2300
+ * If both width and height are defined, the element's size is updated accordingly.
2301
+ */
2111
2302
  autoSetSize,
2303
+ /**
2304
+ * Hides the element by setting its CSS display property to 'none'.
2305
+ * If the element cannot be found, the function does nothing.
2306
+ */
2112
2307
  hide,
2308
+ /**
2309
+ * Unhides the element by clearing its CSS display property (sets it to '').
2310
+ * If the element cannot be found, the function does nothing.
2311
+ */
2113
2312
  unhide,
2313
+ /**
2314
+ * Checks if the element has overflow content.
2315
+ * Returns an object indicating if there is any overflow,
2316
+ * and specifically if there is vertical or horizontal overflow.
2317
+ * Returns null if the element is not found.
2318
+ */
2114
2319
  hasOverflow
2115
2320
  };
2116
2321
  function autoSetPosition(_, position) {
@@ -2166,12 +2371,12 @@ function hasOverflow(el) {
2166
2371
  }
2167
2372
  __name(hasOverflow, "hasOverflow");
2168
2373
 
2169
- // src/utilities/elements/layout_elements.ts
2170
- var layoutElement = {
2171
- createSubscreenDiv: elementCreateSubscreenDiv,
2172
- getSubscreenDiv: elementGetSubscreenDiv,
2173
- appendToSubscreenDiv: elementAppendToSubscreenDiv,
2174
- removeSubscreenDiv: elementRemoveSubscreenDiv,
2374
+ // src/utilities/elements/layout.ts
2375
+ var layout = {
2376
+ createSubscreen: elementCreateSubscreenDiv,
2377
+ getSubscreen: elementGetSubscreenDiv,
2378
+ appendToSubscreen: elementAppendToSubscreenDiv,
2379
+ removeSubscreen: elementRemoveSubscreenDiv,
2175
2380
  createSettingsDiv: elementCreateSettingsDiv,
2176
2381
  getSettingsDiv: elementGetSettingsDiv,
2177
2382
  appendToSettingsDiv: elementAppendToSettingsDiv,
@@ -2388,10 +2593,12 @@ var ModSdkManager = class _ModSdkManager {
2388
2593
  static SDK;
2389
2594
  static patchedFunctions = /* @__PURE__ */ new Map();
2390
2595
  static ModInfo;
2596
+ /** Registers a mod with the SDK and stores mod information. */
2391
2597
  constructor(info, options) {
2392
2598
  _ModSdkManager.SDK = bcModSdkRef.registerMod(info, options);
2393
2599
  _ModSdkManager.ModInfo = info;
2394
2600
  }
2601
+ /** Retrieves or initializes patch data for a given target function. */
2395
2602
  initPatchableFunction(target) {
2396
2603
  let result = _ModSdkManager.patchedFunctions.get(target);
2397
2604
  if (!result) {
@@ -2403,6 +2610,11 @@ var ModSdkManager = class _ModSdkManager {
2403
2610
  }
2404
2611
  return result;
2405
2612
  }
2613
+ /**
2614
+ * Hooks a function with a callback at a given priority.
2615
+ *
2616
+ * Prevents duplicate hooks.
2617
+ */
2406
2618
  hookFunction(target, priority, hook, module = null) {
2407
2619
  const data = this.initPatchableFunction(target);
2408
2620
  if (data.hooks.some((h) => h.hook === hook)) {
@@ -2418,12 +2630,23 @@ var ModSdkManager = class _ModSdkManager {
2418
2630
  data.hooks.sort((a, b) => b.priority - a.priority);
2419
2631
  return removeCallback;
2420
2632
  }
2633
+ /**
2634
+ * Applies patches to a target function.
2635
+ *
2636
+ * **This method is DANGEROUS** to use and has high potential to conflict with other mods.
2637
+ */
2421
2638
  patchFunction(target, patches) {
2422
2639
  _ModSdkManager.SDK?.patchFunction(target, patches);
2423
2640
  }
2641
+ /**
2642
+ * Removes all patches from a target function.
2643
+ */
2424
2644
  unpatchFunction(target) {
2425
2645
  _ModSdkManager.SDK?.removePatches(target);
2426
2646
  }
2647
+ /**
2648
+ * Removes all hooks associated with a specific module from a target function.
2649
+ */
2427
2650
  removeHookByModule(target, module) {
2428
2651
  const data = this.initPatchableFunction(target);
2429
2652
  for (let i = data.hooks.length - 1; i >= 0; i--) {
@@ -2434,6 +2657,9 @@ var ModSdkManager = class _ModSdkManager {
2434
2657
  }
2435
2658
  return true;
2436
2659
  }
2660
+ /**
2661
+ * Removes all hooks associated with a specific module across all patched functions.
2662
+ */
2437
2663
  removeAllHooksByModule(module) {
2438
2664
  for (const data of _ModSdkManager.patchedFunctions.values()) {
2439
2665
  for (let i = data.hooks.length - 1; i >= 0; i--) {
@@ -2449,6 +2675,10 @@ var ModSdkManager = class _ModSdkManager {
2449
2675
 
2450
2676
  // src/utilities/style.ts
2451
2677
  var Style = {
2678
+ /**
2679
+ * Injects a CSS style block directly into the document head using a <style> tag.
2680
+ * If a style element with the same `styleId` already exists, it won't inject again.
2681
+ */
2452
2682
  injectInline(styleId, styleSource) {
2453
2683
  const isStyleLoaded = document.getElementById(styleId);
2454
2684
  if (isStyleLoaded) return;
@@ -2457,6 +2687,10 @@ var Style = {
2457
2687
  styleElement.appendChild(document.createTextNode(styleSource));
2458
2688
  document.head.appendChild(styleElement);
2459
2689
  },
2690
+ /**
2691
+ * Injects a CSS stylesheet link into the document head using a <link> tag.
2692
+ * If a link element with the same `styleId` already exists, it won't inject again.
2693
+ */
2460
2694
  injectEmbed(styleId, styleLink) {
2461
2695
  const isStyleLoaded = document.getElementById(styleId);
2462
2696
  if (isStyleLoaded) return;
@@ -2466,15 +2700,24 @@ var Style = {
2466
2700
  styleElement.href = styleLink;
2467
2701
  document.head.appendChild(styleElement);
2468
2702
  },
2703
+ /**
2704
+ * Removes a style element from the document head by its ID.
2705
+ * Does nothing if the element is not found.
2706
+ */
2469
2707
  eject(id) {
2470
2708
  const style = document.getElementById(id);
2471
2709
  if (!style) return;
2472
2710
  style.remove();
2473
2711
  },
2712
+ /**
2713
+ * Reloads an inline style by removing the existing style element (if any)
2714
+ * and injecting the new styles inline again.
2715
+ */
2474
2716
  reload(styleId, styleSource) {
2475
2717
  Style.eject(styleId);
2476
2718
  Style.injectInline(styleId, styleSource);
2477
2719
  },
2720
+ /** Fetches the text content of a stylesheet or any resource at the given link. */
2478
2721
  async fetch(link) {
2479
2722
  return fetch(link).then((res) => res.text());
2480
2723
  }
@@ -2489,41 +2732,62 @@ var Localization = class _Localization {
2489
2732
  static ModTranslation = {};
2490
2733
  static PathToModTranslation;
2491
2734
  static PathToLibTranslation = `${PUBLIC_URL}/dl_translations/`;
2735
+ static DefaultLanguage = "en";
2736
+ /** Flag to prevent re-initialization */
2492
2737
  static initialized = false;
2738
+ /** Initialize the localization system by loading translation files. */
2493
2739
  static async init(initOptions) {
2494
2740
  if (_Localization.initialized) return;
2495
2741
  _Localization.initialized = true;
2496
- _Localization.PathToModTranslation = initOptions.pathToTranslationsFolder.endsWith("/") ? initOptions.pathToTranslationsFolder : initOptions.pathToTranslationsFolder + "/";
2497
- const lang = TranslationLanguage.toLowerCase();
2742
+ _Localization.PathToModTranslation = (() => {
2743
+ if (!initOptions?.pathToTranslationsFolder) return void 0;
2744
+ return initOptions.pathToTranslationsFolder.endsWith("/") ? initOptions.pathToTranslationsFolder : `${initOptions.pathToTranslationsFolder}/`;
2745
+ })();
2746
+ _Localization.DefaultLanguage = initOptions?.defaultLanguage || _Localization.DefaultLanguage;
2747
+ const lang = initOptions?.fixedLanguage ? _Localization.DefaultLanguage : TranslationLanguage.toLowerCase();
2498
2748
  const libTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, lang);
2499
- if (lang === "en") {
2749
+ if (lang === _Localization.DefaultLanguage) {
2500
2750
  _Localization.LibTranslation = libTranslation;
2501
2751
  } else {
2502
- const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, "en");
2752
+ const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, _Localization.DefaultLanguage);
2503
2753
  _Localization.LibTranslation = { ...fallbackTranslation, ...libTranslation };
2504
2754
  }
2755
+ if (!_Localization.PathToModTranslation) return;
2505
2756
  const modTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, lang);
2506
- if (lang === "en") {
2757
+ if (lang === _Localization.DefaultLanguage) {
2507
2758
  _Localization.ModTranslation = modTranslation;
2508
2759
  } else {
2509
- const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, "en");
2760
+ const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, _Localization.DefaultLanguage);
2510
2761
  _Localization.ModTranslation = { ...fallbackTranslation, ...modTranslation };
2511
2762
  }
2512
2763
  }
2764
+ /** Get a translated string from mod translations by source tag. */
2513
2765
  static getTextMod(srcTag) {
2514
2766
  return _Localization.ModTranslation?.[srcTag] || void 0;
2515
2767
  }
2768
+ /** Get a translated string from library translations by source tag. */
2516
2769
  static getTextLib(srcTag) {
2517
2770
  return _Localization.LibTranslation?.[srcTag] || void 0;
2518
2771
  }
2772
+ /**
2773
+ * Fetch and parse a language file from the given base URL and language code.
2774
+ * Falls back to default language if the requested language file is unavailable.
2775
+ */
2519
2776
  static async fetchLanguageFile(baseUrl, lang) {
2520
2777
  const response = await fetch(`${baseUrl}${lang}.lang`);
2521
- if (lang !== "en" && !response.ok) {
2522
- return this.fetchLanguageFile(baseUrl, "en");
2778
+ if (lang !== _Localization.DefaultLanguage && !response.ok) {
2779
+ return this.fetchLanguageFile(baseUrl, _Localization.DefaultLanguage);
2780
+ }
2781
+ if (!response.ok) {
2782
+ return {};
2523
2783
  }
2524
2784
  const langFileContent = await response.text();
2525
2785
  return this.parseLanguageFile(langFileContent);
2526
2786
  }
2787
+ /**
2788
+ * Parse the raw content of a language file into a TranslationDict.
2789
+ * Ignores empty lines and comments starting with '#'.
2790
+ */
2527
2791
  static parseLanguageFile(content) {
2528
2792
  const translations = {};
2529
2793
  const lines = content.split("\n");
@@ -2555,20 +2819,19 @@ export {
2555
2819
  Modal,
2556
2820
  Style,
2557
2821
  VersionModule,
2558
- advancedElement,
2822
+ advElement,
2559
2823
  deepLibLogger,
2560
2824
  deepMerge,
2561
2825
  deepMergeMatchingProperties,
2562
2826
  domUtil,
2563
2827
  exportToGlobal,
2564
- getCurrentSubscreen,
2565
2828
  getModule,
2566
2829
  getText,
2567
2830
  hasGetter,
2568
2831
  hasSetter,
2569
2832
  init,
2570
2833
  initMod,
2571
- layoutElement,
2834
+ layout,
2572
2835
  modStorage,
2573
2836
  modules,
2574
2837
  modulesMap,