@open-slot-ui/pixi 0.8.1 → 0.8.3

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 CHANGED
@@ -4269,10 +4269,67 @@ var OHM_CSS = `
4269
4269
  .ohm-group { margin: 8px 0; }
4270
4270
  `;
4271
4271
 
4272
+ // src/confirmModal.ts
4273
+ var esc2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4274
+ function showConfirm(ui, opts) {
4275
+ return new Promise((resolve) => {
4276
+ const host2 = document.createElement("div");
4277
+ host2.className = "osc-confirm";
4278
+ host2.style.setProperty("--font", ui.theme.type.family);
4279
+ const title = ui.t(opts.title ?? "Buy Feature");
4280
+ const yes = ui.t(opts.confirmLabel ?? "openui.confirm");
4281
+ const no = ui.t(opts.cancelLabel ?? "openui.cancel");
4282
+ host2.innerHTML = `
4283
+ <div class="osc-confirm-backdrop" data-no></div>
4284
+ <div class="osc-confirm-card" role="dialog" aria-modal="true">
4285
+ ${title ? `<h3 class="osc-confirm-title">${esc2(title)}</h3>` : ""}
4286
+ <p class="osc-confirm-msg">${esc2(opts.message)}</p>
4287
+ <div class="osc-confirm-row">
4288
+ <button class="osc-confirm-btn osc-confirm-no" data-no>${esc2(no)}</button>
4289
+ <button class="osc-confirm-btn osc-confirm-yes" data-yes>${esc2(yes)}</button>
4290
+ </div>
4291
+ </div>`;
4292
+ const style = document.createElement("style");
4293
+ style.textContent = CONFIRM_CSS;
4294
+ host2.appendChild(style);
4295
+ document.body.appendChild(host2);
4296
+ let settled = false;
4297
+ const close = (val) => {
4298
+ if (settled) return;
4299
+ settled = true;
4300
+ window.removeEventListener("keydown", onKey);
4301
+ host2.remove();
4302
+ resolve(val);
4303
+ };
4304
+ const onKey = (e) => {
4305
+ if (e.key === "Escape") close(false);
4306
+ else if (e.key === "Enter") close(true);
4307
+ };
4308
+ host2.querySelectorAll("[data-no]").forEach((b) => b.addEventListener("click", () => close(false)));
4309
+ host2.querySelector("[data-yes]")?.addEventListener("click", () => close(true));
4310
+ window.addEventListener("keydown", onKey);
4311
+ });
4312
+ }
4313
+ var CONFIRM_CSS = `
4314
+ .osc-confirm { position: fixed; inset: 0; z-index: 12000; display: grid; place-items: center; font-family: var(--font); }
4315
+ .osc-confirm *, .osc-confirm *::before, .osc-confirm *::after { box-sizing: border-box; }
4316
+ .osc-confirm-backdrop { position: absolute; inset: 0; background: rgba(8,6,4,.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
4317
+ .osc-confirm-card { position: relative; width: min(90vw, 420px); background: #ffffff; color: #181b20; border: 3px solid #000; border-radius: 14px; padding: 24px; box-shadow: 0 24px 60px rgba(0,0,0,.55); text-align: center; }
4318
+ .osc-confirm-title { margin: 0 0 12px; font-size: 22px; font-weight: 800; letter-spacing: .3px; }
4319
+ .osc-confirm-msg { margin: 0 0 22px; font-size: 19px; font-weight: 700; line-height: 1.4; }
4320
+ .osc-confirm-row { display: flex; gap: 14px; }
4321
+ .osc-confirm-btn { flex: 1; padding: 14px 10px; border-radius: 12px; border: 3px solid #000; font-size: 15px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase; cursor: pointer; transition: transform .1s, background .12s; }
4322
+ .osc-confirm-btn:active { transform: scale(.96); }
4323
+ .osc-confirm-no { background: #ffffff; color: #181b20; }
4324
+ .osc-confirm-no:hover { background: #eef1f6; }
4325
+ .osc-confirm-yes { background: #d99000; color: #1a1200; }
4326
+ .osc-confirm-yes:hover { filter: brightness(1.05); }
4327
+ `;
4328
+
4272
4329
  // src/mountHud.ts
4273
4330
  function showReplayModal(ui, info, buttonKey, onSelect) {
4274
4331
  const cur = info.currency ?? ui.balance.currency.get();
4275
- const money = (n) => core.formatAmount(n, cur);
4332
+ const money2 = (n) => core.formatAmount(n, cur);
4276
4333
  ui.showNotice(
4277
4334
  [
4278
4335
  { kind: "heading", id: "openui-replay-h", text: "openui.replay.title" },
@@ -4280,10 +4337,10 @@ function showReplayModal(ui, info, buttonKey, onSelect) {
4280
4337
  kind: "stat-grid",
4281
4338
  id: "openui-replay-g",
4282
4339
  items: [
4283
- { label: "openui.replay.baseBet", value: money(info.baseBet) },
4340
+ { label: "openui.replay.baseBet", value: money2(info.baseBet) },
4284
4341
  { label: "openui.replay.costMultiplier", value: `${info.costMultiplier}\xD7` },
4285
4342
  { label: "openui.replay.payoutMultiplier", value: `${info.payoutMultiplier}\xD7` },
4286
- { label: "openui.replay.amount", value: money(info.amount) }
4343
+ { label: "openui.replay.amount", value: money2(info.amount) }
4287
4344
  ]
4288
4345
  }
4289
4346
  ],
@@ -4387,17 +4444,15 @@ function mountHud(app, spec = {}, opts = {}) {
4387
4444
  o.onConfirm();
4388
4445
  return;
4389
4446
  }
4390
- const message = o.message ?? (o.name ? ui.t("openui.buyFeature.confirm", { name: ui.t(o.name), price: o.price ?? "" }) : "openui.buyFeature.message");
4391
- ui.showNotice(
4392
- [
4393
- { kind: "heading", id: "buy-title", text: o.title ?? "openui.buyFeature.title" },
4394
- { kind: "text", id: "buy-body", text: message }
4395
- ],
4396
- [
4397
- { label: o.cancelLabel ?? "openui.cancel", variant: "secondary" },
4398
- { label: o.confirmLabel ?? "openui.confirm", variant: "primary", onSelect: o.onConfirm }
4399
- ]
4400
- );
4447
+ const message = o.message ?? (o.name ? ui.t("openui.buyFeature.confirm", { name: ui.t(o.name), price: o.price ?? "" }) : ui.t("openui.buyFeature.message"));
4448
+ void showConfirm(ui, {
4449
+ title: o.title ?? "openui.buyFeature.title",
4450
+ message,
4451
+ confirmLabel: o.confirmLabel,
4452
+ cancelLabel: o.cancelLabel
4453
+ }).then((ok) => {
4454
+ if (ok) o.onConfirm();
4455
+ });
4401
4456
  },
4402
4457
  showControls: () => pixi.setControlsVisible(true),
4403
4458
  hideControls: () => pixi.setControlsVisible(false),
@@ -4411,10 +4466,199 @@ function mountHud(app, spec = {}, opts = {}) {
4411
4466
  dispose: teardown
4412
4467
  };
4413
4468
  }
4469
+ function money(amount, cur) {
4470
+ return core.formatAmount(amount, cur);
4471
+ }
4472
+ var esc3 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4473
+ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
4474
+ const ui = hud.ui;
4475
+ const tr = (k) => ui.t(k);
4476
+ const list = features.slice(0, 4);
4477
+ const boosts = /* @__PURE__ */ new Set();
4478
+ const activation = opts.activation ?? "multi";
4479
+ const blocksBuy = opts.activationBlocksBuy ?? false;
4480
+ const disposers = [];
4481
+ const host2 = document.createElement("div");
4482
+ host2.className = "bfm-root";
4483
+ const vars = {
4484
+ "--accent": "#d99000",
4485
+ "--accent-text": "#1a1200",
4486
+ "--surface": "#ffffff",
4487
+ "--surface-alt": "#eef1f6",
4488
+ "--text": "#181b20",
4489
+ "--text-dim": "#5b6472",
4490
+ "--font": ui.theme.type.family
4491
+ };
4492
+ for (const [k, v] of Object.entries(vars)) host2.style.setProperty(k, v);
4493
+ host2.innerHTML = `
4494
+ <div class="bfm-backdrop" data-close></div>
4495
+ <button class="bfm-x" data-close aria-label="Close">\u2715</button>
4496
+ <div class="bfm-panel" role="dialog" aria-modal="true">
4497
+ <div class="bfm-fit" id="bfm-fit">
4498
+ <h2 class="bfm-title" data-t="Buy Feature">${esc3(tr("Buy Feature"))}</h2>
4499
+ <div class="bfm-bet">
4500
+ <button class="bfm-step" id="bfm-minus" aria-label="Decrease">\u2212</button>
4501
+ <div class="bfm-betbox"><span class="bfm-betlabel" data-t="Bet">${esc3(tr("Bet"))}</span><b id="bfm-betval">\u2014</b></div>
4502
+ <button class="bfm-step" id="bfm-plus" aria-label="Increase">+</button>
4503
+ </div>
4504
+ <div class="bfm-cards" id="bfm-cards"></div>
4505
+ </div>
4506
+ </div>`;
4507
+ const style = document.createElement("style");
4508
+ style.textContent = BFM_CSS;
4509
+ host2.appendChild(style);
4510
+ document.body.appendChild(host2);
4511
+ const $ = (sel) => host2.querySelector(sel);
4512
+ const panel = $(".bfm-panel");
4513
+ const fitEl = $("#bfm-fit");
4514
+ const cardsEl = $("#bfm-cards");
4515
+ const betValEl = $("#bfm-betval");
4516
+ const askConfirm = (name, price, onYes) => {
4517
+ const message = ui.t("openui.buyFeature.confirm", { name: ui.t(name), price });
4518
+ void showConfirm(ui, { title: "Buy Feature", message }).then((ok) => {
4519
+ if (ok) onYes();
4520
+ });
4521
+ };
4522
+ const layout = () => {
4523
+ const vw = window.innerWidth;
4524
+ const vh = window.innerHeight;
4525
+ const cols = vh <= 540 || vw >= 900 ? Math.min(4, list.length) : Math.min(2, list.length);
4526
+ cardsEl.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
4527
+ const fitW = Math.min(vw * 0.96, cols >= 4 ? 1180 : cols === 1 ? 380 : 760);
4528
+ fitEl.style.width = `${fitW}px`;
4529
+ fitEl.style.transform = "none";
4530
+ const natH = fitEl.offsetHeight;
4531
+ const s = Math.min(1, vh * 0.95 / natH);
4532
+ fitEl.style.transform = `translateX(-50%) scale(${s})`;
4533
+ panel.style.width = `${Math.ceil(fitW * s)}px`;
4534
+ panel.style.height = `${Math.ceil(natH * s)}px`;
4535
+ };
4536
+ const renderCards = () => {
4537
+ const bet = opts.getBet ? opts.getBet() : ui.bet.get();
4538
+ const cur = ui.bet.currency.get();
4539
+ cardsEl.innerHTML = list.map((f) => {
4540
+ const active = boosts.has(f.id);
4541
+ const buyBlocked = f.variant === "buy" && blocksBuy && boosts.size > 0;
4542
+ const price = f.variant === "buy" ? money(f.cost * bet, cur) : `+${money(f.cost * bet, cur)}`;
4543
+ const label = f.variant === "buy" ? tr("Buy") : active ? tr("Activated") : tr("Activate");
4544
+ const cls = `bfm-action bfm-action--${f.variant}${active ? " is-active" : ""}${buyBlocked ? " is-blocked" : ""}`;
4545
+ const img = f.image ? ` style="background-image:url('${f.image}')"` : "";
4546
+ return `
4547
+ <div class="bfm-cell">
4548
+ <div class="bfm-card">
4549
+ <div class="bfm-cardimg"${img}></div>
4550
+ <div class="bfm-strip"></div>
4551
+ <div class="bfm-cardbody">
4552
+ <span class="bfm-name">${esc3(tr(f.name))}</span>
4553
+ <b class="bfm-price">${esc3(price)}</b>
4554
+ </div>
4555
+ </div>
4556
+ <button class="${cls}" data-id="${f.id}" data-variant="${f.variant}"${buyBlocked ? " disabled" : ""}>${esc3(label)}</button>
4557
+ </div>`;
4558
+ }).join("");
4559
+ betValEl.textContent = money(bet, cur);
4560
+ cardsEl.querySelectorAll(".bfm-action").forEach((b) => {
4561
+ b.addEventListener("click", () => onAction(b.dataset.id, b.dataset.variant));
4562
+ });
4563
+ layout();
4564
+ };
4565
+ const onAction = (id, variant) => {
4566
+ const f = list.find((x) => x.id === id);
4567
+ const bet = opts.getBet ? opts.getBet() : ui.bet.get();
4568
+ const cur = ui.bet.currency.get();
4569
+ if (variant === "boost") {
4570
+ const wasActive = boosts.has(id);
4571
+ const commit = () => {
4572
+ if (activation === "single") boosts.clear();
4573
+ if (wasActive) boosts.delete(id);
4574
+ else boosts.add(id);
4575
+ ui.bus.emit("cardActivated", { id });
4576
+ renderCards();
4577
+ opts.onActivate?.([...boosts], id, boosts.has(id));
4578
+ };
4579
+ if (wasActive) {
4580
+ commit();
4581
+ return;
4582
+ }
4583
+ const total = 1 + (f?.cost ?? 0);
4584
+ askConfirm(f?.name ?? id, money(total * bet, cur), commit);
4585
+ } else {
4586
+ if (blocksBuy && boosts.size > 0) return;
4587
+ const cost = (f?.cost ?? 0) * bet;
4588
+ askConfirm(f?.name ?? id, money(cost, cur), () => {
4589
+ ui.bus.emit("cardActivated", { id });
4590
+ close();
4591
+ opts.onBuy?.(id, cost);
4592
+ });
4593
+ }
4594
+ };
4595
+ $("#bfm-minus").addEventListener("click", () => ui.betStepper.dec());
4596
+ $("#bfm-plus").addEventListener("click", () => ui.betStepper.inc());
4597
+ disposers.push(ui.bet.value.subscribe(() => renderCards()));
4598
+ const open = () => {
4599
+ renderCards();
4600
+ host2.classList.add("open");
4601
+ };
4602
+ const close = () => host2.classList.remove("open");
4603
+ host2.querySelectorAll("[data-close]").forEach((b) => b.addEventListener("click", close));
4604
+ disposers.push(ui.on("buttonActivated", ({ id }) => {
4605
+ if (id === "bonus") open();
4606
+ }));
4607
+ const onResize = () => {
4608
+ if (host2.classList.contains("open")) layout();
4609
+ };
4610
+ window.addEventListener("resize", onResize);
4611
+ disposers.push(
4612
+ ui.locale.subscribe(() => {
4613
+ host2.querySelectorAll("[data-t]").forEach((n) => n.textContent = tr(n.dataset.t));
4614
+ renderCards();
4615
+ })
4616
+ );
4617
+ renderCards();
4618
+ return () => {
4619
+ window.removeEventListener("resize", onResize);
4620
+ for (const d of disposers.splice(0)) d();
4621
+ host2.remove();
4622
+ };
4623
+ }
4624
+ var BFM_CSS = `
4625
+ .bfm-root { position: fixed; inset: 0; z-index: 11000; display: grid; place-items: center; font-family: var(--font); opacity: 0; pointer-events: none; transition: opacity .18s ease; }
4626
+ .bfm-root.open { opacity: 1; pointer-events: auto; }
4627
+ .bfm-backdrop { position: absolute; inset: 0; background: rgba(8,6,4,0); backdrop-filter: blur(0px) saturate(1); -webkit-backdrop-filter: blur(0px) saturate(1); transition: background .4s ease, backdrop-filter .4s ease, -webkit-backdrop-filter .4s ease; }
4628
+ .bfm-root.open .bfm-backdrop { background: rgba(8,6,4,.5); backdrop-filter: blur(10px) saturate(1.1); -webkit-backdrop-filter: blur(10px) saturate(1.1); }
4629
+ .bfm-x { position: absolute; top: 18px; right: 22px; width: 46px; height: 46px; border-radius: 999px; border: 0; background: rgba(18,14,10,.82); color: #fff; font-size: 18px; cursor: pointer; display: grid; place-items: center; box-shadow: 0 6px 18px rgba(0,0,0,.45); z-index: 2; transition: transform .12s, background .12s; }
4630
+ .bfm-x:hover { transform: scale(1.08); background: rgba(18,14,10,.95); }
4631
+ .bfm-root *, .bfm-root *::before, .bfm-root *::after { box-sizing: border-box; }
4632
+ .bfm-panel { position: relative; transform: translateY(8px) scale(.985); transition: transform .18s ease; }
4633
+ .bfm-root.open .bfm-panel { transform: none; }
4634
+ .bfm-fit { position: absolute; top: 0; left: 50%; transform: translateX(-50%); transform-origin: top center; }
4635
+ .bfm-title { margin: 0 0 14px; text-align: center; color: #fff; font-size: 30px; font-weight: 800; letter-spacing: 1px; text-shadow: 0 2px 12px rgba(0,0,0,.6); }
4636
+ .bfm-bet { display: flex; align-items: center; justify-content: center; gap: 16px; margin: 0 0 24px; }
4637
+ .bfm-betbox { min-width: 200px; padding: 10px 22px; border-radius: 12px; background: var(--surface); border: 3px solid #000; display: flex; flex-direction: column; align-items: center; line-height: 1.1; }
4638
+ .bfm-betlabel { font-size: 12px; font-weight: 700; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }
4639
+ .bfm-betbox b { font-size: 24px; color: var(--text); }
4640
+ .bfm-step { flex: none; width: 54px; height: 54px; border-radius: 999px; border: 3px solid #000; background: var(--surface); color: var(--text); font-size: 28px; font-weight: 800; cursor: pointer; display: grid; place-items: center; line-height: 1; transition: transform .1s, background .12s; box-shadow: 0 4px 12px rgba(0,0,0,.3); }
4641
+ .bfm-step:hover { background: var(--surface-alt); }
4642
+ .bfm-step:active { transform: scale(.92); }
4643
+ .bfm-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; align-items: start; }
4644
+ .bfm-cell { display: flex; flex-direction: column; min-width: 0; }
4645
+ .bfm-card { background: var(--surface); border: 4px solid #000; border-radius: 14px; overflow: hidden; box-shadow: 0 14px 34px rgba(0,0,0,.45); }
4646
+ .bfm-cardimg { width: 100%; aspect-ratio: 16 / 10; background-size: cover; background-position: center; background-color: var(--surface-alt); background-image: linear-gradient(135deg, #e7ebf2, #cfd6e2); }
4647
+ .bfm-strip { height: 8px; background: linear-gradient(90deg, #f0a500, #ffd166, #f0a500); }
4648
+ .bfm-cardbody { padding: 12px 14px 16px; text-align: center; }
4649
+ .bfm-name { display: block; font-size: 15px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
4650
+ .bfm-price { display: block; margin-top: 2px; font-size: 22px; font-weight: 800; color: var(--text); }
4651
+ .bfm-action { display: block; width: 100%; margin-top: 12px; padding: 14px 10px; border-radius: 12px; border: 4px solid #000; background: var(--surface); color: var(--text); font-size: 15px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase; cursor: pointer; transition: transform .1s, background .12s, color .12s; box-shadow: 0 5px 14px rgba(0,0,0,.35); white-space: nowrap; }
4652
+ .bfm-action:hover { background: var(--surface-alt); }
4653
+ .bfm-action:active { transform: scale(.96); }
4654
+ .bfm-action.is-active { background: var(--accent); color: var(--accent-text); border-color: #000; }
4655
+ .bfm-action.is-blocked, .bfm-action:disabled { opacity: .38; cursor: not-allowed; box-shadow: none; }
4656
+ .bfm-action.is-blocked:hover, .bfm-action:disabled:hover { background: var(--surface); }
4657
+ `;
4414
4658
 
4415
4659
  // src/bootError.ts
4416
4660
  var host = null;
4417
- var esc2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4661
+ var esc4 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4418
4662
  function showBootError(opts = {}) {
4419
4663
  const title = opts.title ?? "Connection lost";
4420
4664
  const message = opts.message ?? "The game could not reach the game server. Please reload to reconnect and continue.";
@@ -4428,10 +4672,10 @@ function showBootError(opts = {}) {
4428
4672
  <div class="openui-be-icon" aria-hidden="true">
4429
4673
  <svg viewBox="0 0 48 48" width="48" height="48"><path d="M24 4 3 42h42L24 4Z" fill="none" stroke="#ffc935" stroke-width="3" stroke-linejoin="round"/><rect x="22" y="18" width="4" height="12" rx="2" fill="#ffc935"/><circle cx="24" cy="35" r="2.4" fill="#ffc935"/></svg>
4430
4674
  </div>
4431
- <h1 class="openui-be-title">${esc2(title)}</h1>
4432
- <p class="openui-be-msg">${esc2(message)}</p>
4433
- ${opts.detail ? `<p class="openui-be-detail">${esc2(opts.detail)}</p>` : ""}
4434
- ${showReload ? `<button class="openui-be-reload" type="button">${esc2(opts.reloadLabel ?? "Reload")}</button>` : ""}
4675
+ <h1 class="openui-be-title">${esc4(title)}</h1>
4676
+ <p class="openui-be-msg">${esc4(message)}</p>
4677
+ ${opts.detail ? `<p class="openui-be-detail">${esc4(opts.detail)}</p>` : ""}
4678
+ ${showReload ? `<button class="openui-be-reload" type="button">${esc4(opts.reloadLabel ?? "Reload")}</button>` : ""}
4435
4679
  </div>
4436
4680
  <style>
4437
4681
  .openui-boot-error { position: fixed; inset: 0; z-index: 2147483000; display: grid; place-items: center;
@@ -4511,9 +4755,11 @@ exports.defaultSpinSkin = defaultSpinSkin;
4511
4755
  exports.drawSpin = drawSpin;
4512
4756
  exports.hideBootError = hideBootError;
4513
4757
  exports.isDesktop = isDesktop;
4758
+ exports.mountBuyFeatureModal = mountBuyFeatureModal;
4514
4759
  exports.mountHud = mountHud;
4515
4760
  exports.mountInfoMenu = mountInfoMenu;
4516
4761
  exports.showBootError = showBootError;
4762
+ exports.showConfirm = showConfirm;
4517
4763
  exports.svgSpinSkin = svgSpinSkin;
4518
4764
  //# sourceMappingURL=index.cjs.map
4519
4765
  //# sourceMappingURL=index.cjs.map