@energy8platform/shell 0.6.3 → 0.6.5
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/html.cjs.js +14 -13
- package/dist/html.cjs.js.map +1 -1
- package/dist/html.d.ts +7 -4
- package/dist/html.esm.js +14 -13
- package/dist/html.esm.js.map +1 -1
- package/dist/index.cjs.js +11 -4
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.esm.js +11 -4
- package/dist/index.esm.js.map +1 -1
- package/dist/pixi.cjs.js +18 -14
- package/dist/pixi.cjs.js.map +1 -1
- package/dist/pixi.d.ts +7 -6
- package/dist/pixi.esm.js +18 -14
- package/dist/pixi.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/core/i18n.ts +10 -3
- package/src/core/renderer.ts +5 -0
- package/src/core/version.ts +1 -1
- package/src/ui/html/HtmlRenderer.ts +3 -9
- package/src/ui/pixi/PixiRenderer.ts +2 -11
- package/src/ui/pixi/text.ts +5 -0
package/package.json
CHANGED
package/src/core/i18n.ts
CHANGED
|
@@ -26,11 +26,18 @@ export interface I18nOptions { language: string; isSocial?: boolean; messages?:
|
|
|
26
26
|
export interface I18n { readonly lang: Lang; t(src: string): string; }
|
|
27
27
|
|
|
28
28
|
export function createI18n(opts: I18nOptions): I18n {
|
|
29
|
-
// Social is the `en-social` pseudo-locale: it rewrites the English source
|
|
30
|
-
//
|
|
29
|
+
// Social is the `en-social` pseudo-locale: it rewrites the English source into social-safe
|
|
30
|
+
// vocabulary. The replacement dictionary only exists for English, so social mode FORCES English —
|
|
31
|
+
// the requested `language` is ignored, matching the `isSocial` contract ("…derived from English…
|
|
32
|
+
// regardless of `language`"). Rendering a non-English locale in social mode would leak untranslated
|
|
33
|
+
// restricted terms, so we never do it.
|
|
34
|
+
if (opts.isSocial) {
|
|
35
|
+
const t = (src: string): string => socialize(src);
|
|
36
|
+
return { lang: 'en', t };
|
|
37
|
+
}
|
|
31
38
|
const lang = normalizeLang(opts.language);
|
|
32
39
|
const t = (src: string): string => {
|
|
33
|
-
if (lang === 'en') return
|
|
40
|
+
if (lang === 'en') return src;
|
|
34
41
|
return opts.messages?.[lang]?.[src] ?? LOCALES[lang]?.[src] ?? src;
|
|
35
42
|
};
|
|
36
43
|
return { lang, t };
|
package/src/core/renderer.ts
CHANGED
|
@@ -86,6 +86,11 @@ export interface ShellHost {
|
|
|
86
86
|
setVolumeRefresh(fn: ((key: VolumeKey, value: number) => void) | null): void;
|
|
87
87
|
/** Logic-bearing actions invoked by renderer controls. */
|
|
88
88
|
readonly actions: ShellActions;
|
|
89
|
+
/** Re-show the replay summary modal through the controller (keeps its OverlayHandle in sync).
|
|
90
|
+
* Used as the modal's own reopen callback after START REPLAY, so a renderer never re-pushes a
|
|
91
|
+
* replay modal behind the controller's back (which would strand `overlay` and dead-end the
|
|
92
|
+
* next close). */
|
|
93
|
+
openReplay(opts: ReplayModalOptions): void;
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
/** Every state-changing thing a control can do. Each runs logic in the controller, emits the
|
package/src/core/version.ts
CHANGED
|
@@ -162,7 +162,9 @@ export class HtmlRenderer implements ShellRenderer {
|
|
|
162
162
|
}
|
|
163
163
|
case 'replay': {
|
|
164
164
|
const opts = req.opts;
|
|
165
|
-
|
|
165
|
+
// Reopen through the controller (not a renderer-direct re-push) so its OverlayHandle stays
|
|
166
|
+
// in sync — otherwise a reopened replay modal is untracked and the next close no-ops.
|
|
167
|
+
const reopen = (): void => { this.host.openReplay(opts); };
|
|
166
168
|
const root = buildReplayModal(this.host, opts, reopen);
|
|
167
169
|
return { root };
|
|
168
170
|
}
|
|
@@ -173,14 +175,6 @@ export class HtmlRenderer implements ShellRenderer {
|
|
|
173
175
|
}
|
|
174
176
|
}
|
|
175
177
|
|
|
176
|
-
/** Opens a replay modal and shows it — used as the reopen callback after START REPLAY. */
|
|
177
|
-
private openReplayInternal(opts: import('@/core/types').ReplayModalOptions): void {
|
|
178
|
-
if (this.destroyed) return;
|
|
179
|
-
const reopen = (): void => { this.openReplayInternal(opts); };
|
|
180
|
-
const root = buildReplayModal(this.host, opts, reopen);
|
|
181
|
-
this.showModal(root);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
178
|
private showModal(el: HTMLElement, onKey?: (e: KeyboardEvent) => boolean): void {
|
|
185
179
|
// Drop focus from any open shell control so a stray Space/Enter doesn't re-activate it
|
|
186
180
|
const active = document.activeElement as HTMLElement | null;
|
|
@@ -20,7 +20,6 @@ import { openBuyBonus } from './components/BuyBonus';
|
|
|
20
20
|
import { openBetPicker, openAutoplayPicker } from './components/pickers';
|
|
21
21
|
import { buildModal } from './components/Modal';
|
|
22
22
|
import { buildReplayModal } from './components/ReplayModal';
|
|
23
|
-
import type { ReplayModalOptions } from '@/core/types';
|
|
24
23
|
|
|
25
24
|
export interface PixiRendererOptions {
|
|
26
25
|
app: Application;
|
|
@@ -147,7 +146,7 @@ export class PixiRenderer implements ShellRenderer {
|
|
|
147
146
|
layer = openAutoplayPicker(this.ctx);
|
|
148
147
|
break;
|
|
149
148
|
case 'replay':
|
|
150
|
-
layer = buildReplayModal(this.ctx, req.opts, () => this.
|
|
149
|
+
layer = buildReplayModal(this.ctx, req.opts, () => this.host.openReplay(req.opts));
|
|
151
150
|
break;
|
|
152
151
|
case 'modal':
|
|
153
152
|
layer = buildModal(this.ctx, req.opts);
|
|
@@ -226,15 +225,6 @@ export class PixiRenderer implements ShellRenderer {
|
|
|
226
225
|
this.currentLayer?.fit?.();
|
|
227
226
|
}
|
|
228
227
|
|
|
229
|
-
/** Replay's reopen path: a replay modal can rebuild itself (e.g. after a replay completes). It is
|
|
230
|
-
* routed back through the controller-equivalent open flow so the layer stack + backdrop stay in
|
|
231
|
-
* sync — mirrors PixiGameShell.openReplay (push a fresh replay modal). */
|
|
232
|
-
private openReplayInternal(opts: ReplayModalOptions): void {
|
|
233
|
-
if (this.destroyed) return;
|
|
234
|
-
const layer = buildReplayModal(this.ctx, opts, () => this.openReplayInternal(opts));
|
|
235
|
-
this.pushLayer(layer);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
228
|
// ── frosted backdrop ─────────────────────────────────────────────────────────
|
|
239
229
|
/** Snapshot the scene behind the modal layer and blur it — the Pixi analogue of the overlay's
|
|
240
230
|
* `backdrop-filter: blur(20px) saturate(120%)`. Static (captured at open time): the game is paused
|
|
@@ -333,6 +323,7 @@ export class PixiRenderer implements ShellRenderer {
|
|
|
333
323
|
get layout() { return host.layout; },
|
|
334
324
|
get soundOn() { return host.soundOn; },
|
|
335
325
|
get actions() { return host.actions; },
|
|
326
|
+
openReplay: (opts) => host.openReplay(opts),
|
|
336
327
|
t: (s) => host.t(s),
|
|
337
328
|
formatCurrency: (n, win) => host.formatCurrency(n, win),
|
|
338
329
|
emit: host.emit.bind(host),
|
package/src/ui/pixi/text.ts
CHANGED
|
@@ -103,6 +103,11 @@ export function makeText(str: string, opts: TextOpts): Text {
|
|
|
103
103
|
if (opts.wrapWidth != null) {
|
|
104
104
|
style.wordWrap = true;
|
|
105
105
|
style.wordWrapWidth = opts.wrapWidth;
|
|
106
|
+
// CJK (and any long unbroken run) has no spaces to wrap on — without breakWords the line
|
|
107
|
+
// overflows the wrap width instead of wrapping. This is the single shell text helper (How to
|
|
108
|
+
// Play, disclaimer, Game Info section titles, mode table, win messages, buy-bonus cards), so
|
|
109
|
+
// one flag fixes wrapping everywhere.
|
|
110
|
+
style.breakWords = true;
|
|
106
111
|
}
|
|
107
112
|
if (opts.lineHeight != null) style.lineHeight = opts.lineHeight;
|
|
108
113
|
if (opts.shadow) {
|