@open-slot-ui/core 0.1.0 → 0.2.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.
- package/dist/index.cjs +32 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -38
- package/dist/index.d.ts +31 -38
- package/dist/index.js +32 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1172,9 +1172,6 @@ function validateSpec(spec) {
|
|
|
1172
1172
|
if (spec.rtp != null && !(typeof spec.rtp === "number" && Number.isFinite(spec.rtp))) {
|
|
1173
1173
|
add("error", "rtp", "bad-rtp", `rtp must be a number, got ${String(spec.rtp)}`);
|
|
1174
1174
|
}
|
|
1175
|
-
if (spec.statusBar != null && spec.statusBar !== "top" && spec.statusBar !== "bottom") {
|
|
1176
|
-
add("error", "statusBar", "bad-statusbar", `statusBar must be 'top' or 'bottom', got "${String(spec.statusBar)}"`);
|
|
1177
|
-
}
|
|
1178
1175
|
if (spec.realityCheck != null && !(typeof spec.realityCheck.everyMinutes === "number" && spec.realityCheck.everyMinutes > 0)) {
|
|
1179
1176
|
add("error", "realityCheck.everyMinutes", "bad-interval", "realityCheck.everyMinutes must be a number > 0");
|
|
1180
1177
|
}
|
|
@@ -1314,7 +1311,6 @@ function applyJurisdiction(ui, jur) {
|
|
|
1314
1311
|
lockHidden("bonus");
|
|
1315
1312
|
ui.bonusButton.disable();
|
|
1316
1313
|
}
|
|
1317
|
-
if (jur.disabledSuperTurbo && ui.turbo.modeCount > 2) ui.turbo.setModes(["off", "on"]);
|
|
1318
1314
|
if (jur.disabledSlamstop) ui.spin.allowSlamStop.set(false);
|
|
1319
1315
|
if (jur.disabledSpacebar) {
|
|
1320
1316
|
ui.spin.holdToSpin = false;
|
|
@@ -1388,13 +1384,6 @@ var openuiDefaults = {
|
|
|
1388
1384
|
"openui.buyFeature.title": "Buy feature",
|
|
1389
1385
|
"openui.buyFeature.message": "Buy this feature now?",
|
|
1390
1386
|
"openui.freeSpins": "FS",
|
|
1391
|
-
// ── social / sweepstakes wording (used when `ui.social` is on; see OpenUI.t) ──
|
|
1392
|
-
// open-ui resolves `<key>.social` first in social mode, falling back to the base
|
|
1393
|
-
// key. These are the gambling-loaded terms a sweepstakes jurisdiction must avoid;
|
|
1394
|
-
// override any of them (or add `openui.bet.social` etc.) in your messages dict.
|
|
1395
|
-
"openui.buyFeature.title.social": "Play bonus",
|
|
1396
|
-
"openui.buyFeature.message.social": "Play this bonus now?",
|
|
1397
|
-
"openui.win.social": "Prize",
|
|
1398
1387
|
// reality check (RTS 13) — {{minutes}} is interpolated by open-ui's scheduler
|
|
1399
1388
|
"openui.realityCheck.title": "Reality check",
|
|
1400
1389
|
"openui.realityCheck.message": "You've been playing for {{minutes}} minutes. Take a moment before continuing.",
|
|
@@ -1416,17 +1405,27 @@ var openuiDefaults = {
|
|
|
1416
1405
|
"openui.err.connection.title": "Connection lost",
|
|
1417
1406
|
"openui.err.connection.message": "A stable connection is required. Reload to finish any open round."
|
|
1418
1407
|
};
|
|
1408
|
+
var openuiSocialDefaults = {
|
|
1409
|
+
"openui.bet": "Play",
|
|
1410
|
+
"openui.balance": "Credits",
|
|
1411
|
+
"openui.win": "Prize",
|
|
1412
|
+
"openui.buyFeature.title": "Play bonus",
|
|
1413
|
+
"openui.buyFeature.message": "Play this bonus now?"
|
|
1414
|
+
};
|
|
1419
1415
|
function interpolate(template, vars) {
|
|
1420
1416
|
if (!vars) return template;
|
|
1421
1417
|
return template.replace(/\{\{(\w+)\}\}/g, (_m, k) => String(vars[k] ?? `{{${k}}}`));
|
|
1422
1418
|
}
|
|
1423
1419
|
var DictionaryTranslator = class {
|
|
1424
|
-
constructor(messages, locale) {
|
|
1420
|
+
constructor(messages, locale, socialMessages = {}) {
|
|
1425
1421
|
this.messages = messages;
|
|
1422
|
+
this.socialMessages = socialMessages;
|
|
1426
1423
|
this._locale = locale;
|
|
1427
1424
|
}
|
|
1428
1425
|
messages;
|
|
1426
|
+
socialMessages;
|
|
1429
1427
|
_locale;
|
|
1428
|
+
_social = false;
|
|
1430
1429
|
subs = /* @__PURE__ */ new Set();
|
|
1431
1430
|
get locale() {
|
|
1432
1431
|
return this._locale;
|
|
@@ -1436,8 +1435,12 @@ var DictionaryTranslator = class {
|
|
|
1436
1435
|
this._locale = next;
|
|
1437
1436
|
for (const cb of [...this.subs]) cb(next);
|
|
1438
1437
|
}
|
|
1438
|
+
setSocial(on) {
|
|
1439
|
+
this._social = on;
|
|
1440
|
+
}
|
|
1439
1441
|
t(key, vars) {
|
|
1440
|
-
const
|
|
1442
|
+
const social = this._social ? this.socialMessages[this._locale]?.[key] ?? openuiSocialDefaults[key] : void 0;
|
|
1443
|
+
const resolved = social ?? this.messages[this._locale]?.[key] ?? openuiDefaults[key] ?? key;
|
|
1441
1444
|
return interpolate(resolved, vars);
|
|
1442
1445
|
}
|
|
1443
1446
|
onChange(cb) {
|
|
@@ -1447,8 +1450,8 @@ var DictionaryTranslator = class {
|
|
|
1447
1450
|
};
|
|
1448
1451
|
}
|
|
1449
1452
|
};
|
|
1450
|
-
function dictionary(messages, locale) {
|
|
1451
|
-
return new DictionaryTranslator(messages, locale);
|
|
1453
|
+
function dictionary(messages, locale, socialMessages) {
|
|
1454
|
+
return new DictionaryTranslator(messages, locale, socialMessages);
|
|
1452
1455
|
}
|
|
1453
1456
|
|
|
1454
1457
|
// src/format/currency.ts
|
|
@@ -1554,9 +1557,6 @@ var OpenUI = class {
|
|
|
1554
1557
|
settingsPanel;
|
|
1555
1558
|
musicSlider;
|
|
1556
1559
|
sfxSlider;
|
|
1557
|
-
rulesButton;
|
|
1558
|
-
infoPanel;
|
|
1559
|
-
infoClose;
|
|
1560
1560
|
turbo;
|
|
1561
1561
|
autoplay;
|
|
1562
1562
|
bonusButton;
|
|
@@ -1611,9 +1611,6 @@ var OpenUI = class {
|
|
|
1611
1611
|
);
|
|
1612
1612
|
this.musicSlider = new SliderControl({ id: "music", label: "Music", layout: { anchor: "center" }, initial: 0.7 }, this.bus);
|
|
1613
1613
|
this.sfxSlider = new SliderControl({ id: "sfx", label: "Sound", layout: { anchor: "center" }, initial: 0.5 }, this.bus);
|
|
1614
|
-
this.rulesButton = new ButtonControl({ id: "rules", label: "Rules", layout: { anchor: "center" } }, this.bus);
|
|
1615
|
-
this.infoPanel = new PanelControl({ id: "info-panel", variant: "modal", title: "Game Info", layout: { anchor: "center" } }, this.bus);
|
|
1616
|
-
this.infoClose = new ButtonControl({ id: "info-close", layout: { anchor: "top-right" } }, this.bus);
|
|
1617
1614
|
this.bonusButton = new ButtonControl({ id: "bonus", layout: { anchor: "bottom-center", offset: [-400, -440] } }, this.bus);
|
|
1618
1615
|
this.autoplay = new AutoplayControl(
|
|
1619
1616
|
{ id: "autoplay", layout: { anchor: "bottom-center", offset: [-225, -440] }, options: [5, 10, 25, 50, 100, Infinity] },
|
|
@@ -1637,9 +1634,6 @@ var OpenUI = class {
|
|
|
1637
1634
|
this.settingsPanel,
|
|
1638
1635
|
this.musicSlider,
|
|
1639
1636
|
this.sfxSlider,
|
|
1640
|
-
this.rulesButton,
|
|
1641
|
-
this.infoPanel,
|
|
1642
|
-
this.infoClose,
|
|
1643
1637
|
this.bonusButton,
|
|
1644
1638
|
this.autoplay,
|
|
1645
1639
|
this.turbo,
|
|
@@ -1660,12 +1654,7 @@ var OpenUI = class {
|
|
|
1660
1654
|
this.hidden.add("session-timer");
|
|
1661
1655
|
this.bus.on("buttonActivated", ({ id }) => {
|
|
1662
1656
|
if (id === "settings") this.settingsPanel.toggle();
|
|
1663
|
-
else if (id === "
|
|
1664
|
-
this.settingsPanel.closePanel();
|
|
1665
|
-
this.infoPanel.openPanel();
|
|
1666
|
-
} else if (id === "info-close") {
|
|
1667
|
-
this.infoPanel.closePanel();
|
|
1668
|
-
} else if (id === "bet-plus") {
|
|
1657
|
+
else if (id === "bet-plus") {
|
|
1669
1658
|
this.betStepper.inc();
|
|
1670
1659
|
} else if (id === "bet-minus") {
|
|
1671
1660
|
this.betStepper.dec();
|
|
@@ -1860,26 +1849,23 @@ var OpenUI = class {
|
|
|
1860
1849
|
setLocale(next) {
|
|
1861
1850
|
this.translator.setLocale(next);
|
|
1862
1851
|
}
|
|
1863
|
-
/** Translate a key (or pass plain text through) via the active translator.
|
|
1864
|
-
*
|
|
1865
|
-
*
|
|
1852
|
+
/** Translate a key (or pass plain text through) via the active translator. Social
|
|
1853
|
+
* wording is resolved by the translator from a SEPARATE social dictionary (see
|
|
1854
|
+
* `setSocial`), so gambling and social copy can never be mixed by accident. */
|
|
1866
1855
|
t(key, vars) {
|
|
1867
|
-
if (this.social.get()) {
|
|
1868
|
-
const sk = `${key}.social`;
|
|
1869
|
-
const s = this.translator.t(sk, vars);
|
|
1870
|
-
if (s !== sk) return s;
|
|
1871
|
-
}
|
|
1872
1856
|
return this.translator.t(key, vars);
|
|
1873
1857
|
}
|
|
1874
1858
|
/**
|
|
1875
|
-
* Turn social / sweepstakes mode on or off (one switch).
|
|
1876
|
-
* (Bet
|
|
1877
|
-
* given (e.g. `'GC'`/`'SC'
|
|
1878
|
-
* re-renders live
|
|
1859
|
+
* Turn social / sweepstakes mode on or off (one switch). Flips the translator to
|
|
1860
|
+
* its SEPARATE social dictionary (Bet→Play, Buy feature→Play bonus, etc.) and,
|
|
1861
|
+
* when a `coin` is given (e.g. `'GC'`/`'SC'`), shows balance/bet/net in that coin.
|
|
1862
|
+
* Wording re-renders live. Social copy lives in `locale.socialMessages` — kept
|
|
1863
|
+
* apart from your normal `locale.messages` by design.
|
|
1879
1864
|
*/
|
|
1880
1865
|
setSocial(on, coin) {
|
|
1881
1866
|
if (on !== this.social.get()) {
|
|
1882
1867
|
this.social.set(on);
|
|
1868
|
+
this.translator.setSocial?.(on);
|
|
1883
1869
|
this.locale.update(() => {
|
|
1884
1870
|
});
|
|
1885
1871
|
}
|
|
@@ -1894,7 +1880,7 @@ var OpenUI = class {
|
|
|
1894
1880
|
* just a hide — `confirmBuy`/autoplay entry points consult this). */
|
|
1895
1881
|
isDisabled(feature) {
|
|
1896
1882
|
const j = this.jurisdiction;
|
|
1897
|
-
return feature === "autoplay" && !!j.disabledAutoplay || feature === "buyFeature" && !!j.disabledBuyFeature || feature === "turbo" && !!j.disabledTurbo || feature === "
|
|
1883
|
+
return feature === "autoplay" && !!j.disabledAutoplay || feature === "buyFeature" && !!j.disabledBuyFeature || feature === "turbo" && !!j.disabledTurbo || feature === "fullscreen" && !!j.disabledFullscreen || feature === "slamstop" && !!j.disabledSlamstop || feature === "spacebar" && !!j.disabledSpacebar;
|
|
1898
1884
|
}
|
|
1899
1885
|
/**
|
|
1900
1886
|
* Start a reality-check reminder (RTS 13). Every `everyMinutes` (WALL-CLOCK, so a
|
|
@@ -1938,7 +1924,7 @@ var OpenUI = class {
|
|
|
1938
1924
|
this.showNotice(
|
|
1939
1925
|
[
|
|
1940
1926
|
{ kind: "heading", id: "rc-title", text: this.t(opts.title ?? "openui.realityCheck.title", vars) },
|
|
1941
|
-
{ kind: "
|
|
1927
|
+
{ kind: "text", id: "rc-body", text: this.t(opts.message ?? "openui.realityCheck.message", vars) }
|
|
1942
1928
|
],
|
|
1943
1929
|
opts.actions ?? [{ label: "openui.continue", variant: "primary" }]
|
|
1944
1930
|
);
|
|
@@ -2027,7 +2013,7 @@ var ANALYTICS_EVENTS = [
|
|
|
2027
2013
|
function createUI(spec = {}, hooks = {}) {
|
|
2028
2014
|
const { issues } = validateSpec(spec);
|
|
2029
2015
|
for (const issue of issues) hooks.onDataIssue?.(issue);
|
|
2030
|
-
const translator = spec.locale ? new DictionaryTranslator(spec.locale.messages, spec.locale.locale) : void 0;
|
|
2016
|
+
const translator = spec.locale ? new DictionaryTranslator(spec.locale.messages, spec.locale.locale, spec.locale.socialMessages) : void 0;
|
|
2031
2017
|
const theme = resolveTheme(spec.theme, (i) => hooks.onDataIssue?.(i));
|
|
2032
2018
|
const ui = new OpenUI({ theme, layout: spec.layout, translator, startMuted: spec.audio?.startMuted });
|
|
2033
2019
|
if (spec.currency) {
|
|
@@ -2257,20 +2243,6 @@ function clampBet(amount, cfg, divisor = API_AMOUNT_DIVISOR) {
|
|
|
2257
2243
|
return Math.min(max, Math.max(min, v));
|
|
2258
2244
|
}
|
|
2259
2245
|
|
|
2260
|
-
// src/win.ts
|
|
2261
|
-
var DEFAULT_WIN_TIERS = Object.freeze([
|
|
2262
|
-
{ name: "big", minMultiplier: 10 },
|
|
2263
|
-
{ name: "mega", minMultiplier: 50 },
|
|
2264
|
-
{ name: "epic", minMultiplier: 100 }
|
|
2265
|
-
]);
|
|
2266
|
-
function winTier(win, stake, tiers = DEFAULT_WIN_TIERS) {
|
|
2267
|
-
if (!Number.isFinite(win) || !Number.isFinite(stake) || stake <= 0 || win <= stake) return "none";
|
|
2268
|
-
const mult = win / stake;
|
|
2269
|
-
let name = "win";
|
|
2270
|
-
for (const t of tiers) if (mult >= t.minMultiplier) name = t.name;
|
|
2271
|
-
return name;
|
|
2272
|
-
}
|
|
2273
|
-
|
|
2274
2246
|
exports.API_AMOUNT_DIVISOR = API_AMOUNT_DIVISOR;
|
|
2275
2247
|
exports.AutoplayControl = AutoplayControl;
|
|
2276
2248
|
exports.BLOCK_KINDS = BLOCK_KINDS;
|
|
@@ -2281,7 +2253,6 @@ exports.Control = Control;
|
|
|
2281
2253
|
exports.ControlRegistry = ControlRegistry;
|
|
2282
2254
|
exports.DEFAULT_MENU_TITLES = DEFAULT_MENU_TITLES;
|
|
2283
2255
|
exports.DEFAULT_NOTICE_ACTION = DEFAULT_NOTICE_ACTION;
|
|
2284
|
-
exports.DEFAULT_WIN_TIERS = DEFAULT_WIN_TIERS;
|
|
2285
2256
|
exports.DictionaryTranslator = DictionaryTranslator;
|
|
2286
2257
|
exports.EventBus = EventBus;
|
|
2287
2258
|
exports.EventLog = EventLog;
|
|
@@ -2332,6 +2303,7 @@ exports.integerDigits = integerDigits;
|
|
|
2332
2303
|
exports.isSafeColor = isSafeColor;
|
|
2333
2304
|
exports.isSocialCurrency = isSocialCurrency;
|
|
2334
2305
|
exports.openuiDefaults = openuiDefaults;
|
|
2306
|
+
exports.openuiSocialDefaults = openuiSocialDefaults;
|
|
2335
2307
|
exports.resolveCurrency = resolveCurrency;
|
|
2336
2308
|
exports.resolvePlacement = resolvePlacement;
|
|
2337
2309
|
exports.resolveTheme = resolveTheme;
|
|
@@ -2341,6 +2313,5 @@ exports.sanitizeThemeOverrides = sanitizeThemeOverrides;
|
|
|
2341
2313
|
exports.themePresets = themePresets;
|
|
2342
2314
|
exports.validateSpec = validateSpec;
|
|
2343
2315
|
exports.valueFitMaxWidth = valueFitMaxWidth;
|
|
2344
|
-
exports.winTier = winTier;
|
|
2345
2316
|
//# sourceMappingURL=index.cjs.map
|
|
2346
2317
|
//# sourceMappingURL=index.cjs.map
|