@caperjs/core 0.4.0 → 0.5.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.
Files changed (86) hide show
  1. package/build/index.d.mts +29 -0
  2. package/build/internal/manifest.mjs +2 -2
  3. package/build/internal/validate.mjs +2 -1
  4. package/build/plugins/assetTypes.mjs +0 -6
  5. package/build/plugins/caperConfig.mjs +5 -3
  6. package/build/plugins/lists.mjs +0 -15
  7. package/lib/{CaptionsPlugin-cSJj-R9M.js → CaptionsPlugin-CDbGZrN9.js} +11 -11
  8. package/lib/CaptionsPlugin-CDbGZrN9.js.map +1 -0
  9. package/lib/{DataAdapter-D2tc6hx9.js → DataAdapter-BTlNzWqg.js} +2 -2
  10. package/lib/{DataAdapter-D2tc6hx9.js.map → DataAdapter-BTlNzWqg.js.map} +1 -1
  11. package/lib/{DebugRenderer-CGUKy6Fy.js → DebugRenderer-eSVpon4c.js} +2 -2
  12. package/lib/{DebugRenderer-CGUKy6Fy.js.map → DebugRenderer-eSVpon4c.js.map} +1 -1
  13. package/lib/{DevToolsPlugin-B8GX3H9b.js → DevToolsPlugin-Ci6r9j-m.js} +2 -2
  14. package/lib/{DevToolsPlugin-B8GX3H9b.js.map → DevToolsPlugin-Ci6r9j-m.js.map} +1 -1
  15. package/lib/{GSAPPlugin-Br9AjuTD.js → GSAPPlugin-C8zo-fyt.js} +2 -2
  16. package/lib/{GSAPPlugin-Br9AjuTD.js.map → GSAPPlugin-C8zo-fyt.js.map} +1 -1
  17. package/lib/{LayoutPlugin-BX3OP7pw.js → LayoutPlugin-Cs2lcXKb.js} +4 -4
  18. package/lib/{LayoutPlugin-BX3OP7pw.js.map → LayoutPlugin-Cs2lcXKb.js.map} +1 -1
  19. package/lib/{SpinePlugin-C-JDdXpf.js → SpinePlugin-CLgSXBQm.js} +2 -2
  20. package/lib/{SpinePlugin-C-JDdXpf.js.map → SpinePlugin-CLgSXBQm.js.map} +1 -1
  21. package/lib/{StatsPlugin-yJlJtoQ2.js → StatsPlugin-D_90U3BG.js} +4 -4
  22. package/lib/{StatsPlugin-yJlJtoQ2.js.map → StatsPlugin-D_90U3BG.js.map} +1 -1
  23. package/lib/{VoiceOverPlugin-DjSZp4Ko.js → VoiceOverPlugin-CAE1dtOw.js} +33 -33
  24. package/lib/{VoiceOverPlugin-DjSZp4Ko.js.map → VoiceOverPlugin-CAE1dtOw.js.map} +1 -1
  25. package/lib/caper.mjs +87 -87
  26. package/lib/caper.mjs.map +1 -1
  27. package/lib/{const-C3sxeYhl.js → const-BTDpIdRO.js} +192 -199
  28. package/lib/const-BTDpIdRO.js.map +1 -0
  29. package/lib/display/Container.d.ts +1 -28
  30. package/lib/display/Container.d.ts.map +1 -1
  31. package/lib/display/ParticleContainer.d.ts +20 -29
  32. package/lib/display/ParticleContainer.d.ts.map +1 -1
  33. package/lib/display/ParticleContainer.test.d.ts +2 -0
  34. package/lib/display/ParticleContainer.test.d.ts.map +1 -0
  35. package/lib/display/SpineAnimation.d.ts +1 -2
  36. package/lib/display/SpineAnimation.d.ts.map +1 -1
  37. package/lib/display/SpineAnimation.test.d.ts +1 -0
  38. package/lib/display/SpineAnimation.test.d.ts.map +1 -0
  39. package/lib/mixins/factory/const.d.ts.map +1 -1
  40. package/lib/mixins/focus.d.ts.map +1 -1
  41. package/lib/mixins/index.d.ts +1 -0
  42. package/lib/mixins/index.d.ts.map +1 -1
  43. package/lib/mixins/lifecycle.d.ts +56 -0
  44. package/lib/mixins/lifecycle.d.ts.map +1 -0
  45. package/lib/plugins/FullScreenPlugin.d.ts.map +1 -1
  46. package/lib/plugins/KeyboardPlugin.d.ts.map +1 -1
  47. package/lib/plugins/Plugin.d.ts.map +1 -1
  48. package/lib/plugins/WebEventsPlugin.d.ts +1 -0
  49. package/lib/plugins/WebEventsPlugin.d.ts.map +1 -1
  50. package/lib/plugins/audio/AudioInstance.d.ts +3 -3
  51. package/lib/plugins/audio/AudioInstance.d.ts.map +1 -1
  52. package/lib/plugins/captions/CaptionsRenderer.d.ts.map +1 -1
  53. package/lib/plugins/focus/FocusManagerPlugin.d.ts.map +1 -1
  54. package/lib/{registries-BfV-VF7a.js → registries-nN_hU44y.js} +109 -77
  55. package/lib/registries-nN_hU44y.js.map +1 -0
  56. package/lib/utils/types.d.ts.map +1 -1
  57. package/package.json +3 -2
  58. package/src/core/Application.ts +2 -2
  59. package/src/display/Container.ts +5 -72
  60. package/src/display/ParticleContainer.test.ts +127 -0
  61. package/src/display/ParticleContainer.ts +28 -62
  62. package/src/display/SpineAnimation.test.ts +79 -0
  63. package/src/display/SpineAnimation.ts +4 -6
  64. package/src/mixins/factory/const.ts +2 -1
  65. package/src/mixins/focus.ts +0 -2
  66. package/src/mixins/index.ts +4 -0
  67. package/src/mixins/lifecycle.ts +160 -0
  68. package/src/plugins/DataAdapter.ts +1 -1
  69. package/src/plugins/FullScreenPlugin.test.ts +9 -0
  70. package/src/plugins/FullScreenPlugin.ts +0 -1
  71. package/src/plugins/KeyboardPlugin.ts +0 -1
  72. package/src/plugins/Plugin.ts +0 -2
  73. package/src/plugins/TimerPlugin.ts +1 -1
  74. package/src/plugins/WebEventsPlugin.test.ts +13 -0
  75. package/src/plugins/WebEventsPlugin.ts +12 -1
  76. package/src/plugins/audio/AudioInstance.ts +2 -2
  77. package/src/plugins/captions/CaptionsPlugin.test.ts +48 -3
  78. package/src/plugins/captions/CaptionsPlugin.ts +5 -5
  79. package/src/plugins/captions/CaptionsRenderer.ts +0 -1
  80. package/src/plugins/focus/FocusManagerPlugin.ts +0 -1
  81. package/src/ui/Input.ts +2 -2
  82. package/src/utils/types.ts +0 -1
  83. package/src/version.ts +1 -1
  84. package/lib/CaptionsPlugin-cSJj-R9M.js.map +0 -1
  85. package/lib/const-C3sxeYhl.js.map +0 -1
  86. package/lib/registries-BfV-VF7a.js.map +0 -1
@@ -0,0 +1,29 @@
1
+ import type { PluginOption } from 'vite';
2
+ import type { VitePWAOptions } from 'vite-plugin-pwa';
3
+
4
+ export interface CaperOptions {
5
+ /**
6
+ * AssetPack pixi-pipes overrides, deep-merged over caper's defaults.
7
+ * `false` omits the asset plugins entirely. Set `pngFallback: true` to keep
8
+ * the png twins a production build otherwise prunes.
9
+ */
10
+ assets?: Record<string, unknown> | false;
11
+ /**
12
+ * vite-plugin-pwa options, merged over caper's PWA defaults. Absent means no
13
+ * service worker and no web manifest. `autoRegister` (default true) and
14
+ * `update` ('prompt' shows caper's update banner, 'auto' reloads when a new
15
+ * build lands, 'manual' leaves it to the game via `app.onPwaUpdateAvailable`)
16
+ * are caper's own extras.
17
+ */
18
+ pwa?: Partial<VitePWAOptions> & {
19
+ autoRegister?: boolean;
20
+ update?: 'prompt' | 'auto' | 'manual';
21
+ };
22
+ }
23
+
24
+ /**
25
+ * The caper Vite preset. An app's whole `vite.config.ts` is:
26
+ * `export default defineConfig({ plugins: [caper()] })`.
27
+ */
28
+ export declare function caper(options?: CaperOptions): PluginOption[];
29
+ export default caper;
@@ -15,8 +15,8 @@ import { logger } from './util.mjs';
15
15
  * whatever directory the build was launched from. See `internal/discovery.mjs`
16
16
  * for the same contract.
17
17
  */
18
- export function loadManifestBundleNames(root, manifestUrl = 'assets.json') {
19
- const manifestPath = path.join(root, 'public', 'assets', manifestUrl);
18
+ export function loadManifestBundleNames(root, manifestUrl = 'assets.json', publicDir) {
19
+ const manifestPath = path.join(publicDir ?? path.join(root, 'public'), 'assets', manifestUrl);
20
20
  if (!fs.existsSync(manifestPath)) return null;
21
21
  try {
22
22
  const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
@@ -14,6 +14,7 @@ export function runBuildTimeValidation({
14
14
  server,
15
15
  root,
16
16
  manifestUrl,
17
+ publicDir,
17
18
  configPath,
18
19
  configObject,
19
20
  scenes,
@@ -23,7 +24,7 @@ export function runBuildTimeValidation({
23
24
  breakpointsName,
24
25
  }) {
25
26
  const warnings = [];
26
- const bundleNames = loadManifestBundleNames(root, manifestUrl);
27
+ const bundleNames = loadManifestBundleNames(root, manifestUrl, publicDir);
27
28
 
28
29
  // 1. Scene bundle references
29
30
  if (bundleNames && bundleNames.size > 0) {
@@ -452,9 +452,3 @@ export function assetTypesPlugin(manifestUrl = 'assets.json') {
452
452
  },
453
453
  };
454
454
  }
455
-
456
- /**
457
- * Read the assetpack manifest from disk and return the set of bundle names.
458
- * Returns `null` if the manifest doesn't exist yet — in that case the caller
459
- * should skip bundle-name validation rather than spam false warnings.
460
- */
@@ -21,7 +21,6 @@ import {
21
21
  import { caperConfigSchema } from '../internal/schema.mjs';
22
22
  import { cwd, DTS_FILE_NAME, logger } from '../internal/util.mjs';
23
23
  import { runBuildTimeValidation } from '../internal/validate.mjs';
24
- import { loadManifestBundleNames } from '../internal/manifest.mjs';
25
24
 
26
25
  async function validateCaperConfig(server, root) {
27
26
  if (!server || typeof server.ssrLoadModule !== 'function') return true;
@@ -98,10 +97,11 @@ export function caperConfigPlugin(isProject = true, manifestUrl = 'assets.json')
98
97
  // than process.cwd(), so `vite --root elsewhere` and monorepo invocations from
99
98
  // a parent directory find the right caper.config.ts and src/ tree.
100
99
  let root = cwd;
100
+ let publicDir;
101
101
  const virtualModuleId = 'virtual:caper-config';
102
102
  const resolvedVirtualModuleId = '\0' + virtualModuleId;
103
103
 
104
- async function generateTypes(server, root) {
104
+ async function generateTypes(server, root, publicDir) {
105
105
  if (!isProject) return { types: 'export {}' };
106
106
 
107
107
  const configPath = path.resolve(root, 'caper.config.ts');
@@ -230,6 +230,7 @@ export function caperConfigPlugin(isProject = true, manifestUrl = 'assets.json')
230
230
  server,
231
231
  root,
232
232
  manifestUrl,
233
+ publicDir,
233
234
  configPath,
234
235
  configObject,
235
236
  scenes,
@@ -385,7 +386,7 @@ declare module '@caperjs/core' {
385
386
 
386
387
  async function build(msg = `Building ${DTS_FILE_NAME}`, server) {
387
388
  logger.info(msg);
388
- const { types, error } = await generateTypes(server, root);
389
+ const { types, error } = await generateTypes(server, root, publicDir);
389
390
 
390
391
  if (error) {
391
392
  if (server) {
@@ -418,6 +419,7 @@ declare module '@caperjs/core' {
418
419
  return {
419
420
  name: 'vite-plugin-caper-config',
420
421
  configResolved(config) {
422
+ publicDir = config.publicDir;
421
423
  root = config.root;
422
424
  },
423
425
  enforce: 'pre',
@@ -134,21 +134,6 @@ export function uiListPlugin(isProject = true) {
134
134
  });
135
135
  }
136
136
 
137
- /**
138
- * Walks `src/locales/`, picks a reference locale file (prefers `en.ts`,
139
- * falls back alphabetically), AST-parses its default-exported object, and
140
- * flattens every leaf path into a dot-notation key.
141
- *
142
- * Given:
143
- * export default { foo: 'bar', obj: { nested: 'baz' }, replace: { x: '...' } };
144
- * Returns:
145
- * ['foo', 'obj.nested', 'replace.x']
146
- *
147
- * Only string literal leaves are emitted. Arrays, function calls, and other
148
- * non-object/non-literal expressions are ignored (they can't be typed
149
- * meaningfully at this layer).
150
- */
151
-
152
137
  export function pluginListPlugin(isProject = true) {
153
138
  function extractClassName(plugin) {
154
139
  // For static (non-function) imports, the module value is the raw import path.
@@ -1,4 +1,4 @@
1
- import { Dt as e, H as t, bt as n, f as r, jt as i } from "./registries-BfV-VF7a.js";
1
+ import { Mt as e, Ot as t, U as n, f as r, xt as i } from "./registries-nN_hU44y.js";
2
2
  import { t as a } from "./padding-1kHDpGlQ.js";
3
3
  import { Assets as o, Container as s, Texture as c } from "pixi.js";
4
4
  import { gsap as l } from "gsap";
@@ -72,7 +72,7 @@ var u = class extends r {
72
72
  getSizeMultiplier() {
73
73
  return this.plugin.options.fontSizeMultiplier;
74
74
  }
75
- }, d = i, f = {
75
+ }, d = e, f = {
76
76
  renderer: u,
77
77
  defaultLocale: "en",
78
78
  fontFile: "./caper/font/Sans.fnt",
@@ -96,7 +96,7 @@ var u = class extends r {
96
96
  function p(e, t) {
97
97
  return e <= 0 ? 0 : e > 0 && e <= 1 ? t * e : e;
98
98
  }
99
- var m = class extends t {
99
+ var m = class extends n {
100
100
  constructor(...e) {
101
101
  super(...e), this.id = "captions", this.view = new s(), this._dicts = {}, this._activeCaptionLine = -1, this._activeCaptionTime = 0, this._paused = !1;
102
102
  }
@@ -192,21 +192,21 @@ var m = class extends t {
192
192
  this.maxWidth = this._originalOptions.maxWidth;
193
193
  }
194
194
  postInitialize() {
195
- this.app.i18n.onLocaleChanged.connect(this._handleLocaleChange), this.app.voiceover.onVoiceOverStart.connect(this._handleVoiceOverStart), this.app.voiceover.onVoiceOverPaused.connect(this._handleVoiceOverPaused), this.app.voiceover.onVoiceOverResumed.connect(this._handleVoiceOverResumed), this.app.voiceover.onVoiceOverComplete.connect(this._handleVoiceoverComplete), this.app.voiceover.onVoiceOverStopped.connect(this._handleVoiceoverStopped), this.app.stage.addChild(this.view), this._options.maxWidth = p(this._originalOptions.maxWidth, this.app.size.width);
195
+ this.app.i18n.onLocaleChanged.connect(this._handleLocaleChange), this.addSignalConnection(this.app.voiceover.onVoiceOverStart.connect(this._handleVoiceOverStart)), this.addSignalConnection(this.app.voiceover.onVoiceOverPaused.connect(this._handleVoiceOverPaused)), this.addSignalConnection(this.app.voiceover.onVoiceOverResumed.connect(this._handleVoiceOverResumed)), this.addSignalConnection(this.app.voiceover.onVoiceOverComplete.connect(this._handleVoiceoverComplete)), this.addSignalConnection(this.app.voiceover.onVoiceOverStopped.connect(this._handleVoiceoverStopped)), this.app.stage.addChild(this.view), this._options.maxWidth = p(this._originalOptions.maxWidth, this.app.size.width);
196
196
  let e = this.options.renderer;
197
197
  this.renderer = this.view.addChild(new e(this)), this.addTickerCallback(this.update), this.app.scenes.onSceneChangeStart.connect(this.stopAllCaptions);
198
198
  }
199
199
  async setLocale(e) {
200
200
  return this._locale === e ? this._locale : (this._activeCaptionId && this.stopCaption(this._activeCaptionId), this._activeCaptionId = void 0, await this._loadAndSetLocale(e), this._locale = e, this._locale);
201
201
  }
202
- async loadLocale(t) {
203
- if (this._dicts[t]) return;
204
- let r = this._options.files.find((e) => t === e.id);
205
- if (!r) {
206
- e.error(`i18n:: Could not find locale file for ${t}`);
202
+ async loadLocale(e) {
203
+ if (this._dicts[e]) return;
204
+ let n = this._options.files.find((t) => e === t.id);
205
+ if (!n) {
206
+ t.error(`i18n:: Could not find locale file for ${e}`);
207
207
  return;
208
208
  }
209
- this._dicts[t] = r.json ? await o.load(r.json) : await n(r);
209
+ this._dicts[e] = n.json ? await o.load(n.json) : await i(n);
210
210
  }
211
211
  render() {
212
212
  this.renderer.resize();
@@ -275,4 +275,4 @@ var m = class extends t {
275
275
  //#endregion
276
276
  export { m as CaptionsPlugin };
277
277
 
278
- //# sourceMappingURL=CaptionsPlugin-cSJj-R9M.js.map
278
+ //# sourceMappingURL=CaptionsPlugin-CDbGZrN9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CaptionsPlugin-CDbGZrN9.js","names":[],"sources":["../src/plugins/captions/CaptionsRenderer.ts","../src/plugins/captions/CaptionsPlugin.ts"],"sourcesContent":["import { gsap } from 'gsap';\nimport { BitmapText, Container as PIXIContainer, Sprite, Texture } from 'pixi.js';\nimport { Container } from '../../display/Container';\nimport { type Size } from '../../utils';\nimport { CaptionsPlugin } from './CaptionsPlugin';\n\nexport type CaptionLine = {\n id: string;\n start: number;\n end: number;\n content: string;\n speaker?: string;\n};\n\nexport interface ICaptionRenderer extends PIXIContainer {\n visible: boolean;\n\n start(): void;\n\n stop(): void;\n\n lineBegin(line: CaptionLine): void;\n\n lineEnd(line: CaptionLine): void;\n\n resize(size?: Size): void;\n\n updateSettings(): void;\n\n destroy(): void;\n}\n\nexport class CaptionsRenderer extends Container implements ICaptionRenderer {\n private readonly _bg: Sprite;\n private readonly _text: BitmapText;\n private readonly _size: Size = { width: 0, height: 0 };\n private readonly fontSize = 48;\n\n constructor(private plugin: CaptionsPlugin) {\n super({ autoResize: false });\n\n this._bg = this.add.sprite({ asset: Texture.WHITE, anchor: [0.5, 0] });\n this._bg.tint = this.plugin.options.backgroundColor;\n this._bg.alpha = 0;\n\n this._text = this.add.bitmapText({\n font: plugin.options.fontName,\n resolution: 2,\n roundPixels: true,\n style: {\n fill: this.plugin.options.textColor,\n fontSize: this.fontSize * this.getSizeMultiplier(),\n fontWeight: 'bold',\n align: 'center',\n wordWrapWidth: this.plugin.maxWidth,\n wordWrap: true,\n lineHeight: this.fontSize * this.getSizeMultiplier() * 2 + 20,\n },\n });\n this._text.style.wordWrap = true;\n this._text.alpha = 0;\n this._text.visible = false;\n this._text.anchor.x = 0.5;\n this._text.anchor.y = 0;\n this.addChild(this._text);\n\n if (this.plugin.debug) {\n let isTapping = false;\n this._bg.eventMode = 'static';\n this._bg.on('pointertap', () => {\n if (isTapping) {\n return;\n }\n isTapping = true;\n setTimeout(() => {\n isTapping = false;\n void this.app.voiceover.stopVO();\n }, 100);\n });\n }\n }\n\n public start(): void {\n this._text.visible = true;\n this._bg.visible = true;\n\n gsap.killTweensOf([this._bg, this._text]);\n this.animate({ alpha: this.plugin.options.backgroundAlpha, visible: true, duration: 0.2 }, this._bg);\n this.animate({ alpha: 1, visible: true, duration: 0.2 }, this._text);\n }\n\n public stop(): void {\n gsap.killTweensOf([this._bg, this._text]);\n this.animate({ alpha: 0, visible: false, duration: 0.2 }, [this._bg, this._text]);\n }\n\n public lineBegin(line: CaptionLine): void {\n let text = line.content\n .replace(/<[^>]*>/gi, '') // remove html tags\n .replace(/\\[.*]\\W*/gi, ''); // remove brackets\n if (line.start === 0) {\n text = text.charAt(0).toUpperCase() + text.slice(1);\n }\n this._text.text = text;\n this.resize();\n }\n\n public lineEnd(_line: CaptionLine): void {}\n\n public resize(): void {\n const size = this.app.size;\n const opts = this.plugin.options;\n\n this._size.width = size.width;\n this._size.height = size.height;\n\n this._text.style.fontSize = this.fontSize * this.getSizeMultiplier();\n this._text.style.wordWrapWidth = opts.maxWidth * 2;\n this._text.scale.set(0.5);\n this._text.position.set(this._size.width * 0.5, 0);\n\n this._bg.position.set(this._size.width * 0.5, 0);\n\n let h = this._text.height;\n if (opts.padding.top) {\n h += opts.padding.top;\n }\n if (opts.padding.bottom) {\n h += opts.padding.bottom;\n }\n this._bg.height = h;\n\n this._text.y += opts.padding.top;\n\n if (opts.floating) {\n let w = this._text.width;\n\n if (opts.padding.left) {\n w += opts.padding.left;\n }\n if (opts.padding.right) {\n w += opts.padding.right;\n }\n\n this._bg.x += opts.padding.right * 0.5 - opts.padding.left * 0.5;\n this._bg.width = w;\n } else {\n this._bg.width = size.width;\n }\n\n if (opts.position === 'top') {\n this.position.set(-size.width * 0.5, Math.round(-size.height * 0.5));\n if (opts.floating) {\n this.position.y += Math.round(opts.distance - this._bg.y);\n }\n } else {\n this.position.set(-size.width * 0.5, Math.round(size.height * 0.5 - this._bg.height));\n if (opts.floating) {\n this.position.y -= Math.round(opts.distance + this._bg.y);\n }\n }\n }\n\n updateSettings() {\n if (this.plugin.options.enabled) {\n this._text.style.fill = this.plugin.options.textColor;\n this._bg.tint = this.plugin.options.backgroundColor;\n if (this._bg.visible) {\n this._bg.alpha = this.plugin.options.backgroundAlpha;\n this.resize();\n }\n } else {\n this.stop();\n this._bg.visible = false;\n this._text.visible = false;\n this._bg.alpha = this._text.alpha = 0;\n }\n }\n\n private getSizeMultiplier(): number {\n return this.plugin.options.fontSizeMultiplier;\n }\n}\n","import { Assets, Container, Ticker } from 'pixi.js';\nimport type { ImportListItem, ImportListItemModule, Padding, PointLike } from '../../utils';\nimport { ensurePadding, getDynamicModuleFromImportListItem, isDev, Logger } from '../../utils';\nimport type { IAudioInstance } from '../audio';\nimport type { IPlugin } from '../Plugin';\nimport { Plugin } from '../Plugin';\nimport type { ICaptionRenderer } from './CaptionsRenderer';\nimport { CaptionsRenderer } from './CaptionsRenderer';\n\nconst isDebug = isDev;\n\n/**\n * Type definition for i18n dictionary.\n */\ntype CaptionsDict = Record<string, any>;\n\n/**\n * Type definition for i18n import list item.\n */\ntype CaptionsImportListItem<T> = {\n id: string;\n namedExport?: string;\n options?: any;\n module?: ImportListItemModule<T>;\n} & {\n json?: string;\n};\n\ntype CaptionRendererConstructor = new (owner: CaptionsPlugin) => ICaptionRenderer;\n\n/**\n * Type definition for i18n options.\n */\nexport type CaptionsOptions = {\n renderer: CaptionRendererConstructor;\n defaultLocale: string;\n files: CaptionsImportListItem<CaptionsDict>[];\n fontFile: string;\n fontName: string;\n fontSizeMultiplier: number;\n maxWidth: number;\n textColor: number;\n backgroundColor: number;\n backgroundAlpha: number;\n enabled: boolean;\n floating: boolean;\n distance: number;\n padding: Padding;\n position: 'top' | 'bottom';\n};\n\n/**\n * Default options for i18n module.\n */\nconst defaultOptions: Partial<CaptionsOptions> = {\n renderer: CaptionsRenderer,\n defaultLocale: 'en',\n fontFile: './caper/font/Sans.fnt',\n fontName: 'Sans',\n fontSizeMultiplier: 1,\n maxWidth: 0.8,\n textColor: 0xffffff,\n backgroundColor: 0x0,\n backgroundAlpha: 0.4,\n enabled: true,\n floating: false,\n distance: 0,\n padding: { top: 20, left: 0, bottom: 20, right: 0 },\n position: 'top',\n};\n\nfunction resolveMaxWidth(value: number, appWidth: number) {\n if (value <= 0) {\n return 0;\n }\n if (value > 0 && value <= 1) {\n return appWidth * value;\n }\n return value;\n}\n\n/**\n * Interface for i18n module.\n */\nexport interface ICaptionsPlugin extends IPlugin {\n readonly locale: string;\n view: Container;\n enabled: boolean;\n floating: boolean;\n distance: number;\n padding: Padding;\n position: 'top' | 'bottom';\n backgroundColor: number;\n textColor: number;\n backgroundAlpha: number;\n fontSizeMultiplier: number;\n maxWidth: number;\n options: Partial<CaptionsOptions>;\n\n setLocale(localeId: string): Promise<string>;\n\n loadLocale(localeId: string): Promise<void>;\n\n render(): void;\n}\n\n/**\n * i18n module class.\n */\nexport class CaptionsPlugin extends Plugin<CaptionsOptions> implements ICaptionsPlugin {\n public readonly id = 'captions';\n public view: Container = new Container();\n public renderer: ICaptionRenderer;\n private _dicts: Record<string, CaptionsDict> = {};\n private _locales: string[];\n private _activeCaptionLine = -1;\n private _activeCaptionTime = 0;\n\n private _locale: string;\n\n /**\n * Getter for locale.\n */\n get locale(): string {\n return this._locale;\n }\n\n private _originalOptions: CaptionsOptions;\n\n get options(): CaptionsOptions {\n return this._options;\n }\n\n set options(value: Partial<CaptionsOptions>) {\n this._options = { ...this._options, ...value };\n\n if (value.padding) {\n this._options.padding = ensurePadding(value.padding);\n }\n }\n\n private _activeCaptionId?: string;\n\n get activeCaptionId() {\n return this._activeCaptionId;\n }\n\n private _paused: boolean = false;\n\n get paused(): boolean {\n return this._paused;\n }\n\n set paused(value: boolean) {\n this._paused = value;\n }\n\n get floating(): boolean {\n return this.options.floating;\n }\n\n set floating(value: boolean) {\n this.options.floating = value;\n this.updateRenderer();\n }\n\n public get enabled(): boolean {\n return this.options.enabled;\n }\n\n set enabled(value: boolean) {\n this.options.enabled = value;\n if (this.enabled) {\n this.view.visible = true;\n } else {\n this.view.visible = false;\n }\n }\n\n public get position(): 'top' | 'bottom' {\n return this.options.position;\n }\n\n public set position(value: 'top' | 'bottom') {\n this.options.position = value;\n this.renderer.updateSettings();\n }\n\n set backgroundColor(value: number) {\n this.options.backgroundColor = value;\n this.updateRenderer();\n }\n\n set textColor(value: number) {\n this.options.textColor = value;\n this.updateRenderer();\n }\n\n set backgroundAlpha(value: number) {\n this.options.backgroundAlpha = value;\n this.updateRenderer();\n }\n\n get padding(): Padding {\n return this.options.padding;\n }\n\n set padding(value: Partial<Padding> | PointLike) {\n this.options.padding = ensurePadding(value);\n this.updateRenderer();\n }\n\n get distance(): number {\n return this.options.distance;\n }\n\n set distance(value: number) {\n this.options.distance = value;\n this.updateRenderer();\n }\n\n public get fontSizeMultiplier(): number {\n return this.options.fontSizeMultiplier;\n }\n\n public set fontSizeMultiplier(value: number) {\n this.options.fontSizeMultiplier = value;\n this.renderer.resize();\n }\n\n public get maxWidth(): number {\n return this.options.maxWidth;\n }\n\n public set maxWidth(value: number) {\n this.options.maxWidth = resolveMaxWidth(value, this.app.size.width);\n this.renderer?.resize();\n }\n\n get list(): CaptionsDict {\n return this._dicts[this._locale];\n }\n\n get debug(): boolean {\n return isDebug;\n }\n\n /**\n * Initializes the i18n module.\n * sets the default locale and loads the locale files.\n * @param _app\n * @param options The i18n options.\n * @returns Promise<void>\n */\n public async initialize(options: Partial<CaptionsOptions>): Promise<void> {\n this._options = {\n ...defaultOptions,\n ...options,\n } as CaptionsOptions;\n\n this._originalOptions = { ...this._options };\n\n if (options?.padding) {\n this._options.padding = ensurePadding(options.padding);\n }\n\n this._locale = this.app.i18n.locale;\n this._locales = this.app.i18n.locales;\n\n if (this._options.fontFile) {\n await Assets.load(this._options.fontFile);\n }\n\n if (this._options?.files?.length > 0) {\n const files = this._options.files.filter((file) => this._locales.includes(file.id));\n for (const file of files) {\n await this.loadLocale(file.id);\n }\n }\n\n this.addSignalConnection(this.app.onResize.connect(this.handleResize, 'highest'));\n }\n\n private handleResize() {\n this.maxWidth = this._originalOptions.maxWidth;\n }\n\n public postInitialize(): void {\n this.app.i18n.onLocaleChanged.connect(this._handleLocaleChange);\n this.addSignalConnection(this.app.voiceover.onVoiceOverStart.connect(this._handleVoiceOverStart));\n this.addSignalConnection(this.app.voiceover.onVoiceOverPaused.connect(this._handleVoiceOverPaused));\n this.addSignalConnection(this.app.voiceover.onVoiceOverResumed.connect(this._handleVoiceOverResumed));\n this.addSignalConnection(this.app.voiceover.onVoiceOverComplete.connect(this._handleVoiceoverComplete));\n this.addSignalConnection(this.app.voiceover.onVoiceOverStopped.connect(this._handleVoiceoverStopped));\n\n this.app.stage.addChild(this.view);\n this._options.maxWidth = resolveMaxWidth(this._originalOptions.maxWidth, this.app.size.width);\n const RendererClass: CaptionRendererConstructor = this.options.renderer;\n this.renderer = this.view.addChild(new RendererClass(this)) as CaptionsRenderer;\n\n this.addTickerCallback(this.update);\n this.app.scenes.onSceneChangeStart.connect(this.stopAllCaptions);\n }\n\n /**\n * Sets the locale.\n * If the locale is not loaded, it will load it first.\n * @param localeId The locale id to set.\n * @returns Promise<string>\n */\n async setLocale(localeId: string) {\n if (this._locale === localeId) {\n return this._locale;\n }\n if (this._activeCaptionId) {\n this.stopCaption(this._activeCaptionId);\n }\n this._activeCaptionId = undefined;\n await this._loadAndSetLocale(localeId);\n this._locale = localeId;\n return this._locale;\n }\n\n /**\n * Loads a locale.\n * @param localeId The locale id to load.\n * @returns Promise<void>\n */\n async loadLocale(localeId: string) {\n if (this._dicts[localeId]) {\n return;\n }\n const file = this._options.files.find((file) => localeId === file.id);\n if (!file) {\n Logger.error(`i18n:: Could not find locale file for ${localeId}`);\n return;\n }\n this._dicts[localeId] = file.json\n ? await Assets.load(file.json)\n : await getDynamicModuleFromImportListItem(file as ImportListItem<CaptionsDict>);\n }\n\n render() {\n this.renderer.resize();\n }\n\n update(ticker: Ticker): void {\n if (this._paused) {\n return;\n }\n const dt: number = ticker.deltaMS / 1000;\n const id = this._activeCaptionId;\n if (id) {\n this._activeCaptionTime += dt;\n const ms = this._activeCaptionTime * 1000;\n const cc = this.list[id];\n const n = cc.length;\n for (let i = 0; i < n; i++) {\n if (ms >= cc[i].start && ms < cc[i].end) {\n if (this._activeCaptionLine !== i) {\n this.playLine(id, i);\n }\n break;\n }\n }\n if (ms >= cc[n - 1].end) {\n this.playLine(id, -1);\n }\n }\n }\n\n public playCaption(id: string): void {\n // remove extension from id\n id = this._getId(id);\n this.playLine(id, 0);\n }\n\n public stopCaption(id: string): void {\n // remove extension from id\n id = this._getId(id);\n if (this._activeCaptionId === id) {\n this.playLine(id, -1);\n }\n }\n\n public stopAllCaptions(): void {\n this.renderer?.stop();\n this._activeCaptionId = undefined;\n this._activeCaptionLine = -1;\n }\n\n private _getId(id: string) {\n return id.replace(/\\.[^/.]+$/, '');\n }\n\n private updateRenderer() {\n if (!this.enabled) {\n return;\n }\n this.renderer.updateSettings();\n }\n\n private _handleLocaleChange() {\n void this.setLocale(this.app.i18n.locale);\n }\n\n private _handleVoiceOverStart(vo: IAudioInstance) {\n this.playCaption(vo.id);\n }\n\n private _handleVoiceOverPaused() {\n this.paused = true;\n }\n\n private _handleVoiceOverResumed() {\n this.paused = false;\n }\n\n private _handleVoiceoverComplete(vo: IAudioInstance) {\n const id = this._getId(vo?.id || '');\n if (this._activeCaptionId === id) {\n this.stopCaption(id);\n }\n }\n\n private _handleVoiceoverStopped() {\n this.stopAllCaptions();\n }\n\n /**\n * Loads and sets a locale.\n * If the locale is not loaded, it will load it first.\n * @param localeId The locale id to load and set.\n */\n private async _loadAndSetLocale(localeId: string) {\n if (!this._dicts[localeId]) {\n await this.loadLocale(localeId);\n }\n }\n\n private playLine(id: string, index: number) {\n const cc = this.list[id];\n const line = cc ? cc[index] : undefined;\n if (line) {\n if (this._activeCaptionId !== id) {\n this._activeCaptionId = id;\n this._activeCaptionTime = 0;\n this._activeCaptionLine = -1;\n this.renderer?.start();\n }\n if (this._activeCaptionLine !== index) {\n this._activeCaptionLine = index;\n this.renderer?.lineBegin({\n id: this._activeCaptionId,\n ...cc[index],\n });\n }\n } else if (this._activeCaptionId === id && cc) {\n this.renderer?.lineEnd({\n id: this._activeCaptionId,\n ...cc[this._activeCaptionLine],\n });\n this.renderer?.stop();\n this._activeCaptionId = undefined;\n this._activeCaptionLine = -1;\n }\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { G as e, H as t, Ut as n, lt as r } from "./registries-BfV-VF7a.js";
1
+ import { K as e, U as t, Wt as n, ut as r } from "./registries-nN_hU44y.js";
2
2
  //#region src/plugins/DataAdapter.ts
3
3
  var i = /* @__PURE__ */ n({
4
4
  DataAdapter: () => o,
@@ -86,4 +86,4 @@ var o = class extends t {
86
86
  //#endregion
87
87
  export { i as n, a as r, o as t };
88
88
 
89
- //# sourceMappingURL=DataAdapter-D2tc6hx9.js.map
89
+ //# sourceMappingURL=DataAdapter-BTlNzWqg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataAdapter-D2tc6hx9.js","names":[],"sources":["../src/plugins/DataAdapter.ts"],"sourcesContent":["import { Signal } from '../signals';\nimport { AppTypeOverrides, deepMerge, DeepPartial } from '../utils';\nimport { Plugin } from './Plugin';\n\nexport type DataSchema = {\n [key: string]: any;\n};\n\n/**\n * Interface for the options of the DataAdapter.\n */\nexport interface IDataAdapterOptions {\n initial: Partial<AppTypeOverrides['Data']>;\n /**\n * The namespace to use for the keys in local storage.\n */\n namespace: string;\n /**\n * Whether to override the data with the data from local storage.\n */\n overrideWithLocalStorage: boolean;\n /**\n * Whether to backup all data to local storage.\n */\n backupAll: boolean;\n /**\n * The keys to backup to local storage.\n */\n backupKeys: Array<keyof AppTypeOverrides['Data']>;\n}\n\nexport interface DataChangeSignalDetail {\n key?: any;\n value?: any;\n restore?: boolean;\n clear?: boolean;\n}\n\ntype DataAdapterType = AppTypeOverrides['Data'];\n\nexport interface IDataAdapter {\n get(): DataAdapterType;\n get<K extends keyof DataAdapterType>(key: K): DataAdapterType[K] | undefined;\n set<K extends keyof DataAdapterType>(key: K, data: DataAdapterType[K]): DataAdapterType;\n set(data: DeepPartial<DataAdapterType>, merge?: boolean): DataAdapterType;\n clear(): void;\n clear<K extends keyof DataAdapterType>(key: K): void;\n increment<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends number ? P : never }[keyof DataAdapterType],\n >(\n key: K,\n amount?: number,\n ): DataAdapterType[K];\n concat<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends any[] ? P : never }[keyof DataAdapterType],\n >(\n key: K,\n value: DataAdapterType[K] extends (infer E)[] ? E | E[] : never,\n ): DataAdapterType[K];\n append<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends string ? P : never }[keyof DataAdapterType],\n >(\n key: K,\n value: string,\n separator?: string,\n ): DataAdapterType[K];\n snapshot(): DataAdapterType;\n snapshot<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K];\n onDataChange: Signal<(detail: DataChangeSignalDetail) => void>;\n clearOnResume?: boolean;\n}\n\nexport function defineData<T extends DataSchema>(data: T): T {\n return data;\n}\n\n/**\n * An in-memory game-data plugin with optional localStorage backup.\n *\n * Not `IStorageCapability` — its API (`get`/`set`/`increment`/...) is richer\n * than the generic save/load contract. Accessed directly via `app.data`.\n */\nexport class DataAdapter extends Plugin<Partial<IDataAdapterOptions>> implements IDataAdapter {\n public data: DataAdapterType;\n\n public onDataChange: Signal<(detail: DataChangeSignalDetail) => void> = new Signal();\n\n private backupKeys: Array<keyof DataAdapterType> = [];\n private backupAll: boolean = false;\n private namespace: string = '';\n private overrideWithLocalStorage: boolean = true;\n\n constructor(id: string = 'data') {\n super(id);\n }\n\n public getCoreSignals(): string[] {\n return ['onDataChange'];\n }\n\n destroy() {\n this.data = {} as DataAdapterType;\n super.destroy();\n }\n\n public initialize(options?: Partial<IDataAdapterOptions>): void {\n this.namespace = options?.namespace || this.app.appName;\n this.data = (options?.initial as DataAdapterType) || ({} as DataAdapterType);\n this.backupKeys = options?.backupKeys || [];\n this.backupAll = options?.backupAll || false;\n this.overrideWithLocalStorage = options?.overrideWithLocalStorage === false ? false : true;\n\n if (this.backupAll || this.backupKeys.length > 0) {\n if (this.overrideWithLocalStorage) {\n this.restoreFromLocalStorage(this.backupKeys);\n }\n this.backupToLocalStorage(this.backupKeys);\n }\n }\n\n set<K extends keyof DataAdapterType>(key: K, data: DataAdapterType[K]): DataAdapterType;\n set(data: DeepPartial<DataAdapterType>, merge?: boolean): DataAdapterType;\n set<K extends keyof DataAdapterType>(\n keyOrData: K | DeepPartial<DataAdapterType>,\n dataOrMerge?: DataAdapterType[K] | boolean,\n ): DataAdapterType {\n if (typeof keyOrData === 'string' || typeof keyOrData === 'number' || typeof keyOrData === 'symbol') {\n const key = keyOrData;\n const data = dataOrMerge as DataAdapterType[K];\n\n this.data[key] = data;\n if (this.backupAll || this.backupKeys.includes(key)) {\n this.backupToLocalStorage([key]);\n }\n this.onDataChange.emit({ key, value: data });\n return this.data;\n }\n\n const data = keyOrData as DeepPartial<DataAdapterType>;\n const merge = (dataOrMerge as boolean) ?? true;\n\n if (merge) {\n this.data = deepMerge({ ...this.data }, data);\n } else {\n this.data = data as DataAdapterType;\n }\n\n if (this.backupAll || this.backupKeys.length > 0) {\n this.backupToLocalStorage(this.backupKeys);\n }\n\n this.onDataChange.emit({\n key: Object.keys(data)?.length === 1 ? Object.keys(data)[0] : Object.keys(data),\n value: data[Object.keys(data)[0]] as DataAdapterType[keyof DataAdapterType],\n });\n\n return this.data;\n }\n\n get(): DataAdapterType;\n get<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K] | undefined;\n get<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K] | DataAdapterType | undefined {\n if (key === undefined) {\n return this.data;\n }\n return this.data[key];\n }\n\n increment<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends number ? P : never }[keyof DataAdapterType],\n >(key: K, amount: number = 1): DataAdapterType[K] {\n const currentValue = this.data[key] || 0;\n const newValue = currentValue + amount;\n this.set({ [key]: newValue } as DeepPartial<DataAdapterType>);\n return newValue as DataAdapterType[K];\n }\n\n concat<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends any[] ? P : never }[keyof DataAdapterType],\n >(key: K, value: DataAdapterType[K] extends (infer E)[] ? E | E[] : never): DataAdapterType[K] {\n const currentValue = this.data[key];\n const newValue = [...currentValue, ...(Array.isArray(value) ? value : [value])];\n this.set({ [key]: newValue } as DeepPartial<DataAdapterType>);\n return newValue as DataAdapterType[K];\n }\n\n append<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends string ? P : never }[keyof DataAdapterType],\n >(key: K, value: string, separator: string = ''): DataAdapterType[K] {\n const currentValue = this.data[key];\n let newValue = value;\n if ((currentValue as string)?.length > 0) {\n newValue = currentValue + separator + value;\n }\n this.set({ [key]: newValue } as DeepPartial<DataAdapterType>);\n return newValue as DataAdapterType[K];\n }\n\n clear(): void;\n clear<K extends keyof DataAdapterType>(key?: K): void {\n if (key === undefined) {\n this.data = {} as DataAdapterType;\n const prefix = `${this.namespace}-`;\n for (const storageKey of Object.keys(localStorage).filter((k) => k.startsWith(prefix))) {\n localStorage.removeItem(storageKey);\n }\n this.onDataChange.emit({ key, clear: true });\n } else {\n delete this.data[key];\n localStorage.removeItem(`${this.namespace}-${key as string}`);\n this.onDataChange.emit({ clear: true });\n }\n }\n\n snapshot(): DataAdapterType;\n snapshot<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K];\n snapshot<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K] | DataAdapterType {\n if (key === undefined) {\n return JSON.parse(JSON.stringify(this.data));\n }\n return JSON.parse(JSON.stringify(this.data[key]));\n }\n\n private backupToLocalStorage(keys?: Array<keyof DataAdapterType>): void {\n const dataToBackup =\n keys && keys?.length > 0 ? Object.fromEntries(keys.map((key) => [key, this.data[key]])) : this.data;\n\n for (const key in dataToBackup) {\n localStorage.setItem(`${this.namespace}-${key}`, JSON.stringify(dataToBackup[key]));\n }\n }\n\n private restoreFromLocalStorage(keys?: Array<keyof DataAdapterType>): void {\n const keysToRestore = keys && keys?.length > 0 ? keys : (Object.keys(this.data) as Array<keyof DataAdapterType>);\n keysToRestore.forEach((key) => {\n try {\n const loadedData = localStorage.getItem(`${this.namespace}-${String(key)}`);\n if (loadedData !== null) {\n try {\n const parsedData = JSON.parse(loadedData);\n this.data[key] = parsedData;\n } catch (parseError) {\n console.warn(\n `Failed to parse data for key \"${String(key)}\" in namespace \"${this.namespace}\". Using default value.`,\n );\n }\n }\n } catch (storageError) {\n console.error(\n `Error accessing localStorage for key \"${String(key)}\" in namespace \"${this.namespace}\":`,\n storageError,\n );\n }\n });\n this.onDataChange.emit({ restore: true });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataAdapter-BTlNzWqg.js","names":[],"sources":["../src/plugins/DataAdapter.ts"],"sourcesContent":["import { Signal } from '../signals';\nimport { AppTypeOverrides, deepMerge, DeepPartial } from '../utils';\nimport { Plugin } from './Plugin';\n\nexport type DataSchema = {\n [key: string]: any;\n};\n\n/**\n * Interface for the options of the DataAdapter.\n */\nexport interface IDataAdapterOptions {\n initial: Partial<AppTypeOverrides['Data']>;\n /**\n * The namespace to use for the keys in local storage.\n */\n namespace: string;\n /**\n * Whether to override the data with the data from local storage.\n */\n overrideWithLocalStorage: boolean;\n /**\n * Whether to backup all data to local storage.\n */\n backupAll: boolean;\n /**\n * The keys to backup to local storage.\n */\n backupKeys: Array<keyof AppTypeOverrides['Data']>;\n}\n\nexport interface DataChangeSignalDetail {\n key?: any;\n value?: any;\n restore?: boolean;\n clear?: boolean;\n}\n\ntype DataAdapterType = AppTypeOverrides['Data'];\n\nexport interface IDataAdapter {\n get(): DataAdapterType;\n get<K extends keyof DataAdapterType>(key: K): DataAdapterType[K] | undefined;\n set<K extends keyof DataAdapterType>(key: K, data: DataAdapterType[K]): DataAdapterType;\n set(data: DeepPartial<DataAdapterType>, merge?: boolean): DataAdapterType;\n clear(): void;\n clear<K extends keyof DataAdapterType>(key: K): void;\n increment<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends number ? P : never }[keyof DataAdapterType],\n >(\n key: K,\n amount?: number,\n ): DataAdapterType[K];\n concat<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends any[] ? P : never }[keyof DataAdapterType],\n >(\n key: K,\n value: DataAdapterType[K] extends (infer E)[] ? E | E[] : never,\n ): DataAdapterType[K];\n append<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends string ? P : never }[keyof DataAdapterType],\n >(\n key: K,\n value: string,\n separator?: string,\n ): DataAdapterType[K];\n snapshot(): DataAdapterType;\n snapshot<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K];\n onDataChange: Signal<(detail: DataChangeSignalDetail) => void>;\n clearOnResume?: boolean;\n}\n\nexport function defineData<T extends DataSchema>(data: T): T {\n return data;\n}\n\n/**\n * An in-memory game-data plugin with optional localStorage backup.\n *\n * Not `IStorageCapability` — its API (`get`/`set`/`increment`/...) is richer\n * than the generic save/load contract. Accessed directly via `app.data`.\n */\nexport class DataAdapter extends Plugin<Partial<IDataAdapterOptions>> implements IDataAdapter {\n public data: DataAdapterType;\n\n public onDataChange: Signal<(detail: DataChangeSignalDetail) => void> = new Signal();\n\n private backupKeys: Array<keyof DataAdapterType> = [];\n private backupAll: boolean = false;\n private namespace: string = '';\n private overrideWithLocalStorage: boolean = true;\n\n constructor(id: string = 'data') {\n super(id);\n }\n\n public getCoreSignals(): string[] {\n return ['onDataChange'];\n }\n\n destroy() {\n this.data = {} as DataAdapterType;\n super.destroy();\n }\n\n public initialize(options?: Partial<IDataAdapterOptions>): void {\n this.namespace = options?.namespace || this.app.appName;\n this.data = (options?.initial as DataAdapterType) || ({} as DataAdapterType);\n this.backupKeys = options?.backupKeys || [];\n this.backupAll = options?.backupAll || false;\n this.overrideWithLocalStorage = options?.overrideWithLocalStorage === false ? false : true;\n\n if (this.backupAll || this.backupKeys.length > 0) {\n if (this.overrideWithLocalStorage) {\n this.restoreFromLocalStorage(this.backupKeys);\n }\n this.backupToLocalStorage(this.backupKeys);\n }\n }\n\n set<K extends keyof DataAdapterType>(key: K, data: DataAdapterType[K]): DataAdapterType;\n set(data: DeepPartial<DataAdapterType>, merge?: boolean): DataAdapterType;\n set<K extends keyof DataAdapterType>(\n keyOrData: K | DeepPartial<DataAdapterType>,\n dataOrMerge?: DataAdapterType[K] | boolean,\n ): DataAdapterType {\n if (typeof keyOrData === 'string' || typeof keyOrData === 'number' || typeof keyOrData === 'symbol') {\n const key = keyOrData;\n const data = dataOrMerge as DataAdapterType[K];\n\n this.data[key] = data;\n if (this.backupAll || this.backupKeys.includes(key)) {\n this.backupToLocalStorage([key]);\n }\n this.onDataChange.emit({ key, value: data });\n return this.data;\n }\n\n const data = keyOrData as DeepPartial<DataAdapterType>;\n const merge = (dataOrMerge as boolean) ?? true;\n\n if (merge) {\n this.data = deepMerge({ ...this.data }, data);\n } else {\n this.data = data as DataAdapterType;\n }\n\n if (this.backupAll || this.backupKeys.length > 0) {\n this.backupToLocalStorage(this.backupKeys);\n }\n\n this.onDataChange.emit({\n key: Object.keys(data)?.length === 1 ? Object.keys(data)[0] : Object.keys(data),\n value: data[Object.keys(data)[0]] as DataAdapterType[keyof DataAdapterType],\n });\n\n return this.data;\n }\n\n get(): DataAdapterType;\n get<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K] | undefined;\n get<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K] | DataAdapterType | undefined {\n if (key === undefined) {\n return this.data;\n }\n return this.data[key];\n }\n\n increment<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends number ? P : never }[keyof DataAdapterType],\n >(key: K, amount: number = 1): DataAdapterType[K] {\n const currentValue = this.data[key] || 0;\n const newValue = currentValue + amount;\n this.set({ [key]: newValue } as DeepPartial<DataAdapterType>);\n return newValue as DataAdapterType[K];\n }\n\n concat<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends any[] ? P : never }[keyof DataAdapterType],\n >(key: K, value: DataAdapterType[K] extends (infer E)[] ? E | E[] : never): DataAdapterType[K] {\n const currentValue = this.data[key];\n const newValue = [...currentValue, ...(Array.isArray(value) ? value : [value])];\n this.set({ [key]: newValue } as DeepPartial<DataAdapterType>);\n return newValue as DataAdapterType[K];\n }\n\n append<\n K extends keyof DataAdapterType &\n { [P in keyof DataAdapterType]: DataAdapterType[P] extends string ? P : never }[keyof DataAdapterType],\n >(key: K, value: string, separator: string = ''): DataAdapterType[K] {\n const currentValue = this.data[key];\n let newValue = value;\n if ((currentValue as string)?.length > 0) {\n newValue = currentValue + separator + value;\n }\n this.set({ [key]: newValue } as DeepPartial<DataAdapterType>);\n return newValue as DataAdapterType[K];\n }\n\n clear(): void;\n clear<K extends keyof DataAdapterType>(key?: K): void {\n if (key === undefined) {\n this.data = {} as DataAdapterType;\n const prefix = `${this.namespace}-`;\n for (const storageKey of Object.keys(localStorage).filter((k) => k.startsWith(prefix))) {\n localStorage.removeItem(storageKey);\n }\n this.onDataChange.emit({ key, clear: true });\n } else {\n delete this.data[key];\n localStorage.removeItem(`${this.namespace}-${key as string}`);\n this.onDataChange.emit({ clear: true });\n }\n }\n\n snapshot(): DataAdapterType;\n snapshot<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K];\n snapshot<K extends keyof DataAdapterType>(key?: K): DataAdapterType[K] | DataAdapterType {\n if (key === undefined) {\n return JSON.parse(JSON.stringify(this.data));\n }\n return JSON.parse(JSON.stringify(this.data[key]));\n }\n\n private backupToLocalStorage(keys?: Array<keyof DataAdapterType>): void {\n const dataToBackup =\n keys && keys?.length > 0 ? Object.fromEntries(keys.map((key) => [key, this.data[key]])) : this.data;\n\n for (const key in dataToBackup) {\n localStorage.setItem(`${this.namespace}-${key}`, JSON.stringify(dataToBackup[key]));\n }\n }\n\n private restoreFromLocalStorage(keys?: Array<keyof DataAdapterType>): void {\n const keysToRestore = keys && keys?.length > 0 ? keys : (Object.keys(this.data) as Array<keyof DataAdapterType>);\n keysToRestore.forEach((key) => {\n try {\n const loadedData = localStorage.getItem(`${this.namespace}-${String(key)}`);\n if (loadedData !== null) {\n try {\n const parsedData = JSON.parse(loadedData);\n this.data[key] = parsedData;\n } catch {\n console.warn(\n `Failed to parse data for key \"${String(key)}\" in namespace \"${this.namespace}\". Using default value.`,\n );\n }\n }\n } catch (storageError) {\n console.error(\n `Error accessing localStorage for key \"${String(key)}\" in namespace \"${this.namespace}\":`,\n storageError,\n );\n }\n });\n this.onDataChange.emit({ restore: true });\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { Ut as e } from "./registries-BfV-VF7a.js";
1
+ import { Wt as e } from "./registries-nN_hU44y.js";
2
2
  import { BigPool as t, Bounds as n, Container as r, Graphics as i, Rectangle as a } from "pixi.js";
3
3
  //#region ../../node_modules/.pnpm/yoga-layout@3.2.1/node_modules/yoga-layout/dist/binaries/yoga-wasm-base64-esm.js
4
4
  var o = (() => {
@@ -1382,4 +1382,4 @@ var se = class extends r {
1382
1382
  //#endregion
1383
1383
  export { s as a, d as c, g as d, _ as f, C as h, re as i, f as l, x as m, w as n, c as o, b as p, E as r, u as s, ce as t, h as u };
1384
1384
 
1385
- //# sourceMappingURL=DebugRenderer-CGUKy6Fy.js.map
1385
+ //# sourceMappingURL=DebugRenderer-eSVpon4c.js.map