@open-slot-ui/core 0.4.1 → 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.
package/dist/index.js CHANGED
@@ -99,7 +99,9 @@ var defaultLayoutConfig = {
99
99
  refLandscape: [1920, 1080],
100
100
  refPortrait: [1080, 2337],
101
101
  portraitBelowAspect: 0.85,
102
- breakpoints: { mobile: 480, tablet: 840 }
102
+ breakpoints: { mobile: 480, tablet: 840 },
103
+ // Bottom bar hugs the screen bottom; extra height opens above (reel area).
104
+ stageAnchor: [0.5, 1]
103
105
  };
104
106
  function breakpointFor(width, height, cfg) {
105
107
  const short = Math.min(Math.max(width, 1), Math.max(height, 1));
@@ -113,7 +115,11 @@ function computeScreen(width, height, cfg) {
113
115
  const orientation = w / h < cfg.portraitBelowAspect ? "portrait" : "landscape";
114
116
  const [rw, rh] = orientation === "portrait" ? cfg.refPortrait : cfg.refLandscape;
115
117
  const scale = Math.min(w / rw, h / rh);
116
- return { width: w, height: h, orientation, breakpoint: breakpointFor(w, h, cfg), scale };
118
+ const sw = rw * scale;
119
+ const sh = rh * scale;
120
+ const [ax, ay] = cfg.stageAnchor ?? [0.5, 1];
121
+ const stage = { x: (w - sw) * ax, y: (h - sh) * ay, width: sw, height: sh };
122
+ return { width: w, height: h, orientation, breakpoint: breakpointFor(w, h, cfg), scale, stage };
117
123
  }
118
124
 
119
125
  // src/layout/anchor.ts
@@ -125,9 +131,10 @@ function anchorFactors(anchor) {
125
131
  function resolvePlacement(spec, screen) {
126
132
  const [ax, ay] = anchorFactors(spec.anchor);
127
133
  const [ox, oy] = spec.offset ?? [0, 0];
134
+ const st = screen.stage;
128
135
  return {
129
- x: ax * screen.width + ox * screen.scale,
130
- y: ay * screen.height + oy * screen.scale,
136
+ x: st.x + ax * st.width + ox * screen.scale,
137
+ y: st.y + ay * st.height + oy * screen.scale,
131
138
  scale: screen.scale * (spec.scale ?? 1),
132
139
  rotation: (spec.rotation ?? 0) * Math.PI / 180
133
140
  };
@@ -135,14 +142,21 @@ function resolvePlacement(spec, screen) {
135
142
 
136
143
  // src/layout/defaultLayouts.ts
137
144
  var landscapeDefaultLayouts = Object.freeze({
138
- spin: { anchor: "bottom-center", offset: [0, -140], scale: 0.9 },
139
- autoplay: { anchor: "bottom-center", offset: [-204, -112] },
140
- turbo: { anchor: "bottom-center", offset: [204, -112] },
145
+ // Measured 1:1 from the Figma "Desk DEF" frame (1920×1080): spin ~0.95 of the base
146
+ // 220px coin, dropped to −124, autoplay/turbo flanking at ±204. (The homogeneous
147
+ // stage keeps this off the reels, so it no longer needs shrinking.)
148
+ spin: { anchor: "bottom-center", offset: [0, -124], scale: 0.95 },
149
+ autoplay: { anchor: "bottom-center", offset: [-204, -100] },
150
+ turbo: { anchor: "bottom-center", offset: [204, -100] },
141
151
  balance: { anchor: "bottom-left", offset: [135, -104], rotation: -5 },
142
152
  bet: { anchor: "bottom-right", offset: [-186, -104], rotation: 5 },
143
153
  "bet-plus": { anchor: "bottom-right", offset: [-120, -188], rotation: 5 },
144
154
  "bet-minus": { anchor: "bottom-right", offset: [-120, -104], rotation: 5 },
145
155
  bonus: { anchor: "bottom-center", offset: [740, -320] },
156
+ // Bonus "total win" readout — occupies the buy-feature corner; the renderer swaps
157
+ // the two so only one shows at a time (buy in base play, total-win in a bonus round).
158
+ // Right-anchored so a long localized caption grows LEFT and never clips the edge.
159
+ "total-win": { anchor: "bottom-right", offset: [-150, -300] },
146
160
  settings: { anchor: "bottom-center", offset: [-740, -320], rotation: -5 },
147
161
  mute: { anchor: "top-right", offset: [-122, 46] },
148
162
  fullscreen: { anchor: "top-right", offset: [-46, 46] },
@@ -157,6 +171,9 @@ var portraitDefaultLayouts = Object.freeze({
157
171
  autoplay: { anchor: "bottom-center", offset: [-258, -510], scale: 1.5 },
158
172
  turbo: { anchor: "bottom-center", offset: [258, -510], scale: 1.5 },
159
173
  bonus: { anchor: "bottom-center", offset: [-438, -480], scale: 1.3 },
174
+ // Figma "Mobile FS": the total-win sits on the LEFT at the spin's level (where the
175
+ // buy coin lives in base play), left-aligned + tilted −10° — NOT centred over spin.
176
+ "total-win": { anchor: "bottom-left", offset: [30, -520], rotation: -10 },
160
177
  settings: { anchor: "bottom-center", offset: [438, -480], scale: 1.5, rotation: -5 },
161
178
  "bet-minus": { anchor: "bottom-center", offset: [-105, -267], scale: 1.5 },
162
179
  "bet-plus": { anchor: "bottom-center", offset: [105, -267], scale: 1.5 },
@@ -862,6 +879,10 @@ var ReadoutControl = class extends Control {
862
879
  value = new Signal(0);
863
880
  /** Whether a `'duration'` readout is currently advancing. */
864
881
  running = new Signal(false);
882
+ /** Accent emphasis: the renderer tints the value in the theme accent while on — for
883
+ * a MODIFIED readout (e.g. net position while a bet boost is active). Mirrors
884
+ * {@link ValueDisplay.emphasized}. */
885
+ emphasized = new Signal(false);
865
886
  kind;
866
887
  label;
867
888
  decimals;
@@ -881,6 +902,10 @@ var ReadoutControl = class extends Control {
881
902
  set(v) {
882
903
  this.value.set(safeAmount(v, this.value.get()));
883
904
  }
905
+ /** Accent-tint the value ("this readout is modified"). Strict boolean. */
906
+ setEmphasis(on) {
907
+ this.emphasized.set(on === true);
908
+ }
884
909
  get() {
885
910
  return this.value.get();
886
911
  }
@@ -1407,6 +1432,7 @@ var openuiDefaults = {
1407
1432
  "openui.bet": "Bet",
1408
1433
  "openui.balance": "Balance",
1409
1434
  "openui.win": "Win",
1435
+ "openui.totalWin": "Total Win",
1410
1436
  "openui.menu": "Menu",
1411
1437
  "openui.rules": "Rules",
1412
1438
  "openui.paytable": "Paytable",
@@ -1456,6 +1482,13 @@ var openuiSocialDefaults = {
1456
1482
  "openui.bet": "Play",
1457
1483
  "openui.balance": "Balance",
1458
1484
  "openui.win": "Prize",
1485
+ "openui.totalWin": "Total Prize",
1486
+ // "Paytable" (contains "pay") and "Insufficient funds" ("funds") are restricted in
1487
+ // social mode → their compliant equivalents. The literal "Paytable" is overridden too
1488
+ // because the menu SECTION heading uses it as its key (DEFAULT_MENU_TITLES).
1489
+ "openui.paytable": "Prizes",
1490
+ Paytable: "Prizes",
1491
+ "openui.err.insufficient.title": "Insufficient balance",
1459
1492
  "openui.buyFeature.title": "Play bonus",
1460
1493
  "openui.buyFeature.message": "Play this bonus now?",
1461
1494
  "openui.err.insufficient.message": "You don't have enough balance for this play.",
@@ -1504,27 +1537,67 @@ function dictionary(messages, locale, socialMessages) {
1504
1537
  }
1505
1538
 
1506
1539
  // src/format/currency.ts
1507
- var ZERO_DECIMAL = ["JPY", "KRW", "VND", "CLP", "ISK", "HUF", "TWD", "UGX", "XAF", "XOF", "PYG", "RWF"];
1508
- var CRYPTO = { BTC: 8, ETH: 8, LTC: 8, BCH: 8, DOGE: 8, XRP: 6, SOL: 6, TRX: 6, USDT: 2, USDC: 2 };
1509
1540
  var CURRENCY_TABLE = Object.freeze({
1510
- ...Object.fromEntries(ZERO_DECIMAL.map((c) => [c, { decimals: 0 }])),
1511
- ...Object.fromEntries(Object.entries(CRYPTO).map(([c, d]) => [c, { decimals: d }])),
1512
- // Stake social currencies: Gold Coins + Stake Cash — shown as GC/SC, not fiat.
1513
- XGC: { decimals: 2, display: "GC", social: true },
1514
- XSC: { decimals: 2, display: "SC", social: true },
1515
- GC: { decimals: 2, display: "GC", social: true },
1516
- SC: { decimals: 2, display: "SC", social: true }
1541
+ // ── fiat symbol BEFORE the amount ──────────────────────────────────────────
1542
+ USD: { symbol: "$", decimals: 2 },
1543
+ CAD: { symbol: "CA$", decimals: 2 },
1544
+ JPY: { symbol: "\xA5", decimals: 0 },
1545
+ EUR: { symbol: "\u20AC", decimals: 2 },
1546
+ RUB: { symbol: "\u20BD", decimals: 2 },
1547
+ CNY: { symbol: "CN\xA5", decimals: 2 },
1548
+ PHP: { symbol: "\u20B1", decimals: 2 },
1549
+ INR: { symbol: "\u20B9", decimals: 2 },
1550
+ IDR: { symbol: "Rp", decimals: 0 },
1551
+ KRW: { symbol: "\u20A9", decimals: 0 },
1552
+ BRL: { symbol: "R$", decimals: 2 },
1553
+ MXN: { symbol: "MX$", decimals: 2 },
1554
+ TRY: { symbol: "\u20BA", decimals: 2 },
1555
+ GBP: { symbol: "\xA3", decimals: 2 },
1556
+ // ── fiat — symbol AFTER the amount ───────────────────────────────────────────
1557
+ DKK: { symbol: "kr", decimals: 2, symbolAfter: true },
1558
+ PLN: { symbol: "z\u0142", decimals: 2, symbolAfter: true },
1559
+ VND: { symbol: "\u20AB", decimals: 0, symbolAfter: true },
1560
+ CLP: { symbol: "CLP", decimals: 0, symbolAfter: true },
1561
+ ARS: { symbol: "ARS", decimals: 2, symbolAfter: true },
1562
+ PEN: { symbol: "S/", decimals: 2, symbolAfter: true },
1563
+ // ── crypto (8-dp, so sub-cent + high precision format correctly) ─────────────
1564
+ BTC: { symbol: "\u20BF", decimals: 8 },
1565
+ ETH: { symbol: "\u039E", decimals: 8 },
1566
+ LTC: { symbol: "\u0141", decimals: 8 },
1567
+ BCH: { symbol: "BCH", decimals: 8 },
1568
+ DOGE: { symbol: "\xD0", decimals: 8 },
1569
+ USDT: { symbol: "\u20AE", decimals: 2 },
1570
+ USDC: { symbol: "USDC", decimals: 2 },
1571
+ // ── Stake social coins — Gold Coins / Stake Cash (shown as GC / SC) ───────────
1572
+ XGC: { symbol: "GC", decimals: 2, social: true },
1573
+ XSC: { symbol: "SC", decimals: 2, social: true },
1574
+ GC: { symbol: "GC", decimals: 2, social: true },
1575
+ SC: { symbol: "SC", decimals: 2, social: true }
1517
1576
  });
1518
1577
  var upper = (code) => typeof code === "string" ? code.toUpperCase() : "";
1519
1578
  function isSocialCurrency(code) {
1520
1579
  return CURRENCY_TABLE[upper(code)]?.social === true;
1521
1580
  }
1522
1581
  function resolveCurrency(code, overrides = {}) {
1523
- const info = CURRENCY_TABLE[upper(code)] ?? { decimals: 2 };
1582
+ const info = CURRENCY_TABLE[upper(code)];
1583
+ if (!info) {
1584
+ return {
1585
+ code: overrides.code ?? code,
1586
+ decimals: clampDecimals(overrides.decimals ?? 2),
1587
+ position: overrides.position ?? "suffix",
1588
+ separator: overrides.separator ?? ",",
1589
+ decimalChar: overrides.decimalChar ?? ".",
1590
+ ...overrides.symbol ? { symbol: overrides.symbol, display: overrides.display ?? "symbol" } : {}
1591
+ };
1592
+ }
1524
1593
  return {
1525
- code: overrides.code ?? info.display ?? code,
1594
+ // Social coins carry their DISPLAY code (XGC → "GC", XSC → "SC"); fiat/crypto keep
1595
+ // their ISO code (the symbol is what's actually rendered under `display:'symbol'`).
1596
+ code: overrides.code ?? (info.social ? info.symbol : code),
1597
+ symbol: overrides.symbol ?? info.symbol,
1598
+ display: overrides.display ?? "symbol",
1599
+ position: overrides.position ?? (info.symbolAfter ? "suffix" : "prefix"),
1526
1600
  decimals: clampDecimals(overrides.decimals ?? info.decimals),
1527
- position: overrides.position ?? "suffix",
1528
1601
  separator: overrides.separator ?? ",",
1529
1602
  decimalChar: overrides.decimalChar ?? "."
1530
1603
  };
@@ -1540,7 +1613,11 @@ function formatAmount(value, spec, opts = {}) {
1540
1613
  const body = frac ? `${grouped}${dot}${frac}` : grouped;
1541
1614
  const sign = n < 0 ? "-" : opts.signed ? "+" : "";
1542
1615
  const number = `${sign}${body}`;
1543
- return (spec.position ?? "suffix") === "prefix" ? `${spec.code} ${number}` : `${number} ${spec.code}`;
1616
+ const symbolMode = spec.display === "symbol" && !!spec.symbol;
1617
+ const affix = symbolMode ? spec.symbol : spec.code;
1618
+ const prefix = (spec.position ?? "suffix") === "prefix";
1619
+ const gap = symbolMode && prefix ? "" : " ";
1620
+ return prefix ? `${affix}${gap}${number}` : `${number}${gap}${affix}`;
1544
1621
  }
1545
1622
 
1546
1623
  // src/OpenUI.ts
@@ -1602,6 +1679,9 @@ var OpenUI = class {
1602
1679
  spin;
1603
1680
  balance;
1604
1681
  bet;
1682
+ /** Bonus "total win" readout — shown in the buy-feature slot during a bonus/free-
1683
+ * spins round (the renderer swaps it for the buy button). Same money logic as `bet`. */
1684
+ totalWin;
1605
1685
  settingsButton;
1606
1686
  settingsPanel;
1607
1687
  musicSlider;
@@ -1650,6 +1730,13 @@ var OpenUI = class {
1650
1730
  currency: { code: "USD", decimals: 2 },
1651
1731
  initial: 1
1652
1732
  });
1733
+ this.totalWin = new ValueDisplay({
1734
+ id: "total-win",
1735
+ label: "openui.totalWin",
1736
+ layout: defaultLayout("total-win"),
1737
+ currency: { code: "USD", decimals: 2 },
1738
+ initial: 0
1739
+ });
1653
1740
  this.settingsButton = new ButtonControl(
1654
1741
  { id: "settings", layout: defaultLayout("settings") },
1655
1742
  this.bus
@@ -1679,6 +1766,7 @@ var OpenUI = class {
1679
1766
  this.spin,
1680
1767
  this.balance,
1681
1768
  this.bet,
1769
+ this.totalWin,
1682
1770
  this.settingsButton,
1683
1771
  this.settingsPanel,
1684
1772
  this.musicSlider,
@@ -2055,6 +2143,127 @@ function installResponsive(ui, responsive) {
2055
2143
  };
2056
2144
  }
2057
2145
 
2146
+ // src/spec/socialPhrases.ts
2147
+ var FORBIDDEN = [
2148
+ { re: /\bpay\w*/i, term: "pay*", replacement: 'prize / award (e.g. "paytable" \u2192 "prizes")' },
2149
+ { re: /\bpayout\w*/i, term: "payout", replacement: "award" },
2150
+ { re: /\bbets?\b|\bbetting\b/i, term: "bet", replacement: "play" },
2151
+ { re: /\bwager\w*/i, term: "wager", replacement: "play" },
2152
+ { re: /\bgambl\w*/i, term: "gamble", replacement: "play" },
2153
+ { re: /\bcash\w*/i, term: "cash", replacement: "coins" },
2154
+ { re: /\bfunds?\b/i, term: "funds", replacement: "coins / balance" },
2155
+ { re: /\bmoney\b/i, term: "money", replacement: "coins" },
2156
+ { re: /\bdeposit\w*/i, term: "deposit", replacement: "purchase" },
2157
+ { re: /\bwithdraw\w*/i, term: "withdraw", replacement: "redeem" },
2158
+ { re: /\bcredits?\b/i, term: "credit", replacement: "coins / balance" },
2159
+ { re: /\bwinnings?\b/i, term: "winnings", replacement: "prizes" },
2160
+ { re: /\bjackpots?\b/i, term: "jackpot", replacement: "grand prize" },
2161
+ { re: /\breal[-\s]?money\b/i, term: "real money", replacement: "coins" }
2162
+ ];
2163
+ function findForbiddenPhrases(text) {
2164
+ if (typeof text !== "string" || !text) return [];
2165
+ const seen = /* @__PURE__ */ new Set();
2166
+ const out = [];
2167
+ for (const r of FORBIDDEN) {
2168
+ if (r.re.test(text) && !seen.has(r.term)) {
2169
+ seen.add(r.term);
2170
+ out.push({ term: r.term, replacement: r.replacement });
2171
+ }
2172
+ }
2173
+ return out;
2174
+ }
2175
+ function walkBlock(b, src, out) {
2176
+ const add = (t, s = src) => {
2177
+ if (typeof t === "string" && t) out.push({ source: s, text: t });
2178
+ };
2179
+ const anyB = b;
2180
+ switch (b.kind) {
2181
+ case "text":
2182
+ case "heading":
2183
+ case "subheading":
2184
+ case "legal":
2185
+ add(b.text);
2186
+ break;
2187
+ case "callout":
2188
+ add(b.title);
2189
+ add(b.text);
2190
+ break;
2191
+ case "media":
2192
+ add(b.title);
2193
+ add(b.text);
2194
+ break;
2195
+ case "slider":
2196
+ case "toggle":
2197
+ case "button":
2198
+ case "select":
2199
+ case "stepper":
2200
+ case "value":
2201
+ add(anyB.label);
2202
+ add(anyB.hint);
2203
+ break;
2204
+ case "steps":
2205
+ b.items.forEach((s, i) => add(s, `${src}.items[${i}]`));
2206
+ break;
2207
+ case "table":
2208
+ (b.columns ?? []).forEach((c) => add(c));
2209
+ b.rows.forEach((row) => row.forEach((c) => add(c)));
2210
+ break;
2211
+ case "paytable":
2212
+ b.rows.forEach((r) => {
2213
+ add(r.symbol);
2214
+ add(r.payouts);
2215
+ });
2216
+ break;
2217
+ case "cards":
2218
+ b.items.forEach((it) => {
2219
+ add(it.title);
2220
+ add(it.text);
2221
+ });
2222
+ break;
2223
+ case "stat-grid":
2224
+ b.items.forEach((it) => {
2225
+ add(it.label);
2226
+ add(it.value);
2227
+ });
2228
+ break;
2229
+ case "group":
2230
+ add(b.title);
2231
+ b.children.forEach((c, i) => walkBlock(c, `${src}.children[${i}]`, out));
2232
+ break;
2233
+ }
2234
+ }
2235
+ function collectSocialCopy(spec) {
2236
+ const out = [];
2237
+ const menu = spec.menu;
2238
+ if (menu) {
2239
+ const sections = [
2240
+ ["settings", menu.settings],
2241
+ ["paytable", menu.paytable],
2242
+ ["rules", menu.rules]
2243
+ ];
2244
+ for (const [sec, blocks] of sections) (blocks ?? []).forEach((b, i) => walkBlock(b, `menu.${sec}[${i}]`, out));
2245
+ if (menu.titles) {
2246
+ for (const [k, v] of Object.entries(menu.titles)) if (v) out.push({ source: `menu.titles.${k}`, text: v });
2247
+ }
2248
+ if (menu.banner?.src) ;
2249
+ }
2250
+ (spec.rules ?? []).forEach((b, i) => walkBlock(b, `rules[${i}]`, out));
2251
+ if (spec.game?.name) out.push({ source: "game.name", text: spec.game.name });
2252
+ const en = spec.locale?.messages?.en;
2253
+ if (en) {
2254
+ for (const [k, v] of Object.entries(en)) if (typeof v === "string") out.push({ source: `locale.en[${JSON.stringify(k)}]`, text: v });
2255
+ }
2256
+ return out;
2257
+ }
2258
+ function checkSocialPhrases(spec) {
2259
+ const issues = [];
2260
+ for (const { source, text } of collectSocialCopy(spec)) {
2261
+ const matches = findForbiddenPhrases(text);
2262
+ if (matches.length) issues.push({ source, text, matches });
2263
+ }
2264
+ return issues;
2265
+ }
2266
+
2058
2267
  // src/spec/createUI.ts
2059
2268
  function resolveTurboModes(modes) {
2060
2269
  if (Array.isArray(modes)) return modes.length ? modes : ["off", "on"];
@@ -2084,12 +2293,27 @@ function createUI(spec = {}, hooks = {}) {
2084
2293
  const cur = typeof spec.currency === "string" ? resolveCurrency(spec.currency) : spec.currency;
2085
2294
  ui.balance.setCurrency(cur);
2086
2295
  ui.bet.setCurrency(cur);
2296
+ ui.totalWin.setCurrency(cur);
2087
2297
  ui.netPosition.setCurrency(cur);
2088
2298
  }
2089
2299
  if (spec.social) {
2090
2300
  if (typeof spec.social === "object") ui.setSocial(true, spec.social.coin);
2091
2301
  else ui.setSocial(true);
2092
2302
  }
2303
+ if (spec.social || spec.jurisdiction?.socialCasino) {
2304
+ const found = checkSocialPhrases(spec);
2305
+ for (const issue of found) {
2306
+ hooks.onDataIssue?.({
2307
+ level: "warn",
2308
+ path: issue.source,
2309
+ code: "social-forbidden-phrase",
2310
+ message: `Social mode restricted wording in "${issue.text}": ${issue.matches.map((m) => `\u201C${m.term}\u201D \u2192 ${m.replacement}`).join("; ")}`
2311
+ });
2312
+ }
2313
+ if (found.length && typeof console !== "undefined") {
2314
+ console.warn(`[open-ui] social mode: ${found.length} string(s) contain restricted phrases (see onDataIssue). First: ${found[0].source} \u2192 "${found[0].text}"`);
2315
+ }
2316
+ }
2093
2317
  if (typeof spec.rtp === "number") ui.rtp.set(spec.rtp);
2094
2318
  if (spec.game) ui.gameInfo = { name: spec.game.name, version: spec.game.version };
2095
2319
  if (spec.betLadder?.levels?.length) {
@@ -2314,6 +2538,6 @@ function clampBet(amount, cfg, divisor = API_AMOUNT_DIVISOR) {
2314
2538
  return Math.min(max, Math.max(min, v));
2315
2539
  }
2316
2540
 
2317
- export { API_AMOUNT_DIVISOR, AutoplayControl, BLOCK_KINDS, ButtonControl, CURRENCY_TABLE, CardControl, Control, ControlRegistry, DEFAULT_MENU_TITLES, DEFAULT_NOTICE_ACTION, DictionaryTranslator, EventBus, EventLog, Fade, LOCALE_LABELS, OpenUI, PanelControl, Parallel, Pulse, RGS_ERROR_KEYS, ReadoutControl, SelectControl, Sequence, Signal, SliderControl, SpinControl, Squish, StepperControl, ToggleControl, TurboControl, Turn, ValueDisplay, applyJurisdiction, breakpointFor, buildBetLadder, buildBlocks, buildPanel, buttonBlocks, clampBet, clampDecimals, clampDigits, clampMinDigits, composeMenu, computeScreen, createUI, defaultHudSpec, defaultLayout, defaultLayoutConfig, defaultTheme, defineUI, dictionary, displayDigits, effect, errorBlocks, extendTheme, formatAmount, installResponsive, integerDigits, isSafeColor, isSocialCurrency, landscapeDefaultLayouts, openuiDefaults, openuiSocialDefaults, portraitDefaultLayouts, resolveCurrency, resolvePlacement, resolveTheme, resolveTurboModes, safeAmount, sanitizeThemeOverrides, themePresets, validateSpec, valueFitMaxWidth };
2541
+ export { API_AMOUNT_DIVISOR, AutoplayControl, BLOCK_KINDS, ButtonControl, CURRENCY_TABLE, CardControl, Control, ControlRegistry, DEFAULT_MENU_TITLES, DEFAULT_NOTICE_ACTION, DictionaryTranslator, EventBus, EventLog, Fade, LOCALE_LABELS, OpenUI, PanelControl, Parallel, Pulse, RGS_ERROR_KEYS, ReadoutControl, SelectControl, Sequence, Signal, SliderControl, SpinControl, Squish, StepperControl, ToggleControl, TurboControl, Turn, ValueDisplay, applyJurisdiction, breakpointFor, buildBetLadder, buildBlocks, buildPanel, buttonBlocks, checkSocialPhrases, clampBet, clampDecimals, clampDigits, clampMinDigits, collectSocialCopy, composeMenu, computeScreen, createUI, defaultHudSpec, defaultLayout, defaultLayoutConfig, defaultTheme, defineUI, dictionary, displayDigits, effect, errorBlocks, extendTheme, findForbiddenPhrases, formatAmount, installResponsive, integerDigits, isSafeColor, isSocialCurrency, landscapeDefaultLayouts, openuiDefaults, openuiSocialDefaults, portraitDefaultLayouts, resolveCurrency, resolvePlacement, resolveTheme, resolveTurboModes, safeAmount, sanitizeThemeOverrides, themePresets, validateSpec, valueFitMaxWidth };
2318
2542
  //# sourceMappingURL=index.js.map
2319
2543
  //# sourceMappingURL=index.js.map