@energy8platform/shell 0.4.0 → 0.4.1
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 +30 -5
- package/dist/html.cjs.js.map +1 -1
- package/dist/html.d.ts +2 -2
- package/dist/html.esm.js +30 -5
- package/dist/html.esm.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +1 -1
- package/dist/pixi.cjs.js +113 -28
- package/dist/pixi.cjs.js.map +1 -1
- package/dist/pixi.d.ts +2 -2
- package/dist/pixi.esm.js +113 -28
- package/dist/pixi.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/core/version.ts +1 -1
- package/src/ui/html/components/pickers.ts +13 -1
- package/src/ui/html/shell.css.ts +19 -3
- package/src/ui/pixi/components/GameInfo.ts +52 -13
- package/src/ui/pixi/components/pickers.ts +66 -15
package/dist/index.cjs.js
CHANGED
|
@@ -1412,7 +1412,7 @@ class KeyboardController {
|
|
|
1412
1412
|
|
|
1413
1413
|
// AUTO-GENERATED by scripts/gen-version.mjs — do not edit. Mirrors package.json "version".
|
|
1414
1414
|
/** The @energy8platform/shell package version, stamped into the game-info footer. */
|
|
1415
|
-
const PACKAGE_VERSION = '0.4.
|
|
1415
|
+
const PACKAGE_VERSION = '0.4.1';
|
|
1416
1416
|
|
|
1417
1417
|
/** Apply defaults to the raw config (the mount target lives on the renderer, not here). */
|
|
1418
1418
|
function resolveConfig(config) {
|
package/dist/index.d.ts
CHANGED
|
@@ -471,7 +471,7 @@ declare class ShellController extends EventEmitter<ShellEvents> implements Shell
|
|
|
471
471
|
tokens: ShellTokens;
|
|
472
472
|
layout: ShellLayoutMode;
|
|
473
473
|
soundOn: boolean;
|
|
474
|
-
readonly engineVersion = "0.4.
|
|
474
|
+
readonly engineVersion = "0.4.1";
|
|
475
475
|
readonly actions: ShellActions;
|
|
476
476
|
private renderer;
|
|
477
477
|
private i18n;
|
|
@@ -537,7 +537,7 @@ interface I18n {
|
|
|
537
537
|
declare function createI18n(opts: I18nOptions): I18n;
|
|
538
538
|
|
|
539
539
|
/** The @energy8platform/shell package version, stamped into the game-info footer. */
|
|
540
|
-
declare const PACKAGE_VERSION = "0.4.
|
|
540
|
+
declare const PACKAGE_VERSION = "0.4.1";
|
|
541
541
|
|
|
542
542
|
/** A shell: the renderer-agnostic controller plus the surface facade (safeArea/barHeight/setVisible)
|
|
543
543
|
* an embedding host reads. `createShell`, `createGameShell` and `createPixiShell` all return this. */
|
package/dist/index.esm.js
CHANGED
|
@@ -1410,7 +1410,7 @@ class KeyboardController {
|
|
|
1410
1410
|
|
|
1411
1411
|
// AUTO-GENERATED by scripts/gen-version.mjs — do not edit. Mirrors package.json "version".
|
|
1412
1412
|
/** The @energy8platform/shell package version, stamped into the game-info footer. */
|
|
1413
|
-
const PACKAGE_VERSION = '0.4.
|
|
1413
|
+
const PACKAGE_VERSION = '0.4.1';
|
|
1414
1414
|
|
|
1415
1415
|
/** Apply defaults to the raw config (the mount target lives on the renderer, not here). */
|
|
1416
1416
|
function resolveConfig(config) {
|
package/dist/pixi.cjs.js
CHANGED
|
@@ -1439,7 +1439,7 @@ class KeyboardController {
|
|
|
1439
1439
|
|
|
1440
1440
|
// AUTO-GENERATED by scripts/gen-version.mjs — do not edit. Mirrors package.json "version".
|
|
1441
1441
|
/** The @energy8platform/shell package version, stamped into the game-info footer. */
|
|
1442
|
-
const PACKAGE_VERSION = '0.4.
|
|
1442
|
+
const PACKAGE_VERSION = '0.4.1';
|
|
1443
1443
|
|
|
1444
1444
|
/** Apply defaults to the raw config (the mount target lives on the renderer, not here). */
|
|
1445
1445
|
function resolveConfig(config) {
|
|
@@ -4081,28 +4081,69 @@ function sectionHotkeys(host, title, width) {
|
|
|
4081
4081
|
visible.forEach((r, i) => {
|
|
4082
4082
|
if (i > 0)
|
|
4083
4083
|
sec.add(hairline$1(host, inner));
|
|
4084
|
-
sec.add(hkRow(host, r));
|
|
4084
|
+
sec.add(hkRow(host, r, inner));
|
|
4085
4085
|
});
|
|
4086
4086
|
return sec;
|
|
4087
4087
|
}
|
|
4088
|
-
/** Render a single hotkey row: keycap chip(s) on the left, action name on the right.
|
|
4088
|
+
/** Render a single hotkey row: keycap chip(s) on the left, action name on the right. The row is
|
|
4089
|
+
* constrained to `inner` (chips left, label right). On narrow widths the chip combos stack onto
|
|
4090
|
+
* their own lines and the label wraps within the leftover width, so nothing clips past the plaque
|
|
4091
|
+
* — the Pixi analogue of the HTML `.ge-gi-hk-chips { flex:0 1 auto; flex-wrap }` + label wrap. */
|
|
4089
4092
|
function hkRow(host, r, inner) {
|
|
4090
|
-
const
|
|
4091
|
-
//
|
|
4092
|
-
const chipsCol = new FlexBox({ direction: 'row', align: 'center', gap: 4 });
|
|
4093
|
+
const GAP = 14;
|
|
4094
|
+
const LABEL_MIN = 92; // reserve at least this much for the action label before wrapping the chips
|
|
4093
4095
|
const chipKeys = buildChipKeys(r);
|
|
4096
|
+
// Lay the chips on one line and measure. If that leaves too little room for the label, stack the
|
|
4097
|
+
// combos (split at the '/') onto their own lines so the chips give up horizontal width.
|
|
4098
|
+
let chips = chipLine(host, chipKeys);
|
|
4099
|
+
let chipsW = chips.measureSize().w;
|
|
4100
|
+
if (chipsW > inner - GAP - LABEL_MIN) {
|
|
4101
|
+
chips = chipCombos(host, chipKeys);
|
|
4102
|
+
chipsW = chips.measureSize().w;
|
|
4103
|
+
}
|
|
4104
|
+
// The label takes the leftover width and WRAPS within it (never clips); right-aligned to sit
|
|
4105
|
+
// against the plaque edge like the DOM `.ge-gi-hk-tx`.
|
|
4106
|
+
const labelW = Math.max(LABEL_MIN, inner - chipsW - GAP);
|
|
4107
|
+
const nameText = makeText(host.t(r.name), { size: 15, weight: '700', color: '#ffffff', wrapWidth: labelW, align: 'right' });
|
|
4108
|
+
const row = new FlexBox({ direction: 'row', align: 'center', justify: 'space-between', gap: GAP, padding: { top: 8, bottom: 8 }, width: inner });
|
|
4109
|
+
row.add(chips);
|
|
4110
|
+
row.add(nameText);
|
|
4111
|
+
return row;
|
|
4112
|
+
}
|
|
4113
|
+
/** Chips on a single row, with '/' separators between the combos (as flattened by buildChipKeys). */
|
|
4114
|
+
function chipLine(host, chipKeys) {
|
|
4115
|
+
const line = new FlexBox({ direction: 'row', align: 'center', gap: 4 });
|
|
4116
|
+
for (const key of chipKeys) {
|
|
4117
|
+
if (key === '/')
|
|
4118
|
+
line.add(makeText('/', { size: 12, weight: '500', color: host.tokens.plaqueLabel }));
|
|
4119
|
+
else
|
|
4120
|
+
line.add(keycap(host, key));
|
|
4121
|
+
}
|
|
4122
|
+
return line;
|
|
4123
|
+
}
|
|
4124
|
+
/** Chips stacked as combos — split at the '/' separators, one combo per line (drops the inline
|
|
4125
|
+
* '/', which reads as a line break once the combos are stacked). */
|
|
4126
|
+
function chipCombos(host, chipKeys) {
|
|
4127
|
+
const col = new FlexBox({ direction: 'column', align: 'start', gap: 4 });
|
|
4128
|
+
let line = new FlexBox({ direction: 'row', align: 'center', gap: 4 });
|
|
4129
|
+
let filled = false;
|
|
4130
|
+
const flush = () => {
|
|
4131
|
+
if (!filled)
|
|
4132
|
+
return;
|
|
4133
|
+
col.add(line);
|
|
4134
|
+
line = new FlexBox({ direction: 'row', align: 'center', gap: 4 });
|
|
4135
|
+
filled = false;
|
|
4136
|
+
};
|
|
4094
4137
|
for (const key of chipKeys) {
|
|
4095
4138
|
if (key === '/') {
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
else {
|
|
4099
|
-
chipsCol.add(keycap(host, key));
|
|
4139
|
+
flush();
|
|
4140
|
+
continue;
|
|
4100
4141
|
}
|
|
4142
|
+
line.add(keycap(host, key));
|
|
4143
|
+
filled = true;
|
|
4101
4144
|
}
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
row.add(nameText);
|
|
4105
|
-
return row;
|
|
4145
|
+
flush();
|
|
4146
|
+
return col;
|
|
4106
4147
|
}
|
|
4107
4148
|
/** Flatten a row's chip list into display tokens — for bet rows, produce: Shift ↑ / Shift = style. */
|
|
4108
4149
|
function buildChipKeys(r) {
|
|
@@ -5268,8 +5309,27 @@ class PickerModal extends CardModal {
|
|
|
5268
5309
|
}
|
|
5269
5310
|
}
|
|
5270
5311
|
/** A centred picker (chips grid + accent Confirm) on the shared card modal. */
|
|
5312
|
+
/** A ScrollBox that reports a fixed box to the FlexBox layout — so a capped, scrolling grid slots
|
|
5313
|
+
* into the card body like any other sized child (measured/positioned by its viewport, not its
|
|
5314
|
+
* full content bounds). */
|
|
5315
|
+
class SizedScrollBox extends ScrollBox {
|
|
5316
|
+
boxW;
|
|
5317
|
+
boxH;
|
|
5318
|
+
constructor(boxW, boxH, canvas) {
|
|
5319
|
+
super(canvas);
|
|
5320
|
+
this.boxW = boxW;
|
|
5321
|
+
this.boxH = boxH;
|
|
5322
|
+
this.setViewport(boxW, boxH);
|
|
5323
|
+
}
|
|
5324
|
+
measureSize() {
|
|
5325
|
+
return { w: this.boxW, h: this.boxH };
|
|
5326
|
+
}
|
|
5327
|
+
setLayoutSize() {
|
|
5328
|
+
/* fixed viewport — ignore layout-imposed sizing */
|
|
5329
|
+
}
|
|
5330
|
+
}
|
|
5271
5331
|
function buildSheet(host, opts) {
|
|
5272
|
-
const
|
|
5332
|
+
const maxColumns = typeof opts.columns === 'number'
|
|
5273
5333
|
? opts.columns
|
|
5274
5334
|
: host.layout === 'mobile' ? opts.columns.mobile : opts.columns.wide;
|
|
5275
5335
|
let selected = opts.selected;
|
|
@@ -5321,27 +5381,51 @@ function buildSheet(host, opts) {
|
|
|
5321
5381
|
const em = modal.emSize;
|
|
5322
5382
|
const gap = 0.65 * em;
|
|
5323
5383
|
const innerW = modal.cardWidth - 2.4 * em;
|
|
5384
|
+
// Build the chips first (at natural width) so autoFit can measure the widest label.
|
|
5385
|
+
for (let i = 0; i < opts.choices.length; i++) {
|
|
5386
|
+
const c = opts.choices[i];
|
|
5387
|
+
const chipIndex = i;
|
|
5388
|
+
chips.push(new Chip(host, c.id, c.label, chipIndex === focusIndex, em, (id) => {
|
|
5389
|
+
const idx = opts.choices.findIndex((ch) => ch.id === id);
|
|
5390
|
+
if (idx >= 0)
|
|
5391
|
+
setHighlight(idx);
|
|
5392
|
+
}));
|
|
5393
|
+
}
|
|
5394
|
+
// Column count: with autoFit, drop below the max until the widest label fits. Short labels
|
|
5395
|
+
// (a normal currency) exceed the max and clamp back to it — so the compact 6-wide layout is
|
|
5396
|
+
// preserved and only wide currencies reflow to fewer columns.
|
|
5397
|
+
let columns = maxColumns;
|
|
5398
|
+
if (opts.autoFit) {
|
|
5399
|
+
const widest = chips.reduce((m, ch) => Math.max(m, ch.measureSize().w), 0);
|
|
5400
|
+
const fitCols = Math.floor((innerW + gap) / (widest + gap));
|
|
5401
|
+
columns = Math.max(1, Math.min(maxColumns, fitCols));
|
|
5402
|
+
}
|
|
5324
5403
|
const colW = (innerW - gap * (columns - 1)) / columns;
|
|
5325
5404
|
const grid = new FlexBox({ direction: 'column', align: 'start', gap });
|
|
5326
|
-
for (let i = 0; i <
|
|
5327
|
-
const rowChoices = opts.choices.slice(i, i + columns);
|
|
5405
|
+
for (let i = 0; i < chips.length; i += columns) {
|
|
5328
5406
|
const row = new FlexBox({ direction: 'row', align: 'center', gap });
|
|
5329
|
-
for (let j = 0; j <
|
|
5330
|
-
const
|
|
5331
|
-
const chipIndex = i + j;
|
|
5332
|
-
const chip = new Chip(host, c.id, c.label, chipIndex === focusIndex, em, (id) => {
|
|
5333
|
-
const idx = opts.choices.findIndex((ch) => ch.id === id);
|
|
5334
|
-
if (idx >= 0)
|
|
5335
|
-
setHighlight(idx);
|
|
5336
|
-
});
|
|
5407
|
+
for (let j = 0; j < columns && i + j < chips.length; j++) {
|
|
5408
|
+
const chip = chips[i + j];
|
|
5337
5409
|
chip.setLayoutSize(colW, undefined);
|
|
5338
|
-
chips.push(chip);
|
|
5339
5410
|
row.add(chip);
|
|
5340
5411
|
}
|
|
5341
|
-
row.layout();
|
|
5342
5412
|
grid.add(row);
|
|
5343
5413
|
}
|
|
5344
|
-
|
|
5414
|
+
// Cap the grid height and scroll when the ladder overflows — the Pixi analogue of the HTML
|
|
5415
|
+
// shell's `max-height:min(50vh,28em); overflow-y:auto`. (Mask hit-testing clips to the viewport
|
|
5416
|
+
// but still lets clicks through to chips inside it — verified against pixi.js 8.16's
|
|
5417
|
+
// EventBoundary.) When it fits, drop the scroll box entirely so nothing is masked needlessly.
|
|
5418
|
+
const gridH = grid.measureSize().h;
|
|
5419
|
+
const maxGridH = Math.min(host.screenH * 0.5, 28 * em);
|
|
5420
|
+
if (opts.autoFit && gridH > maxGridH) {
|
|
5421
|
+
const scroll = new SizedScrollBox(innerW, maxGridH, host.canvas);
|
|
5422
|
+
scroll.content.addChild(grid);
|
|
5423
|
+
scroll.refresh();
|
|
5424
|
+
modal.body.add(scroll);
|
|
5425
|
+
}
|
|
5426
|
+
else {
|
|
5427
|
+
modal.body.add(grid);
|
|
5428
|
+
}
|
|
5345
5429
|
modal.setActions([
|
|
5346
5430
|
{
|
|
5347
5431
|
label: opts.confirmLabel,
|
|
@@ -5358,6 +5442,7 @@ function openBetPicker(host) {
|
|
|
5358
5442
|
tag: 'bet-modal',
|
|
5359
5443
|
title: host.t('Bet'),
|
|
5360
5444
|
columns: { wide: 6, mobile: 3 },
|
|
5445
|
+
autoFit: true, // reflow columns + scroll when a wide currency makes the labels grow
|
|
5361
5446
|
maxEm: 44, // wider card to fit 6 chips/row
|
|
5362
5447
|
confirmLabel: host.t('Confirm'),
|
|
5363
5448
|
choices: host.state.availableBets.map((b) => ({ id: String(b), label: host.fmt(b) })),
|