@open-slot-ui/pixi 0.8.1 → 0.8.2

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
@@ -4272,7 +4272,7 @@ var OHM_CSS = `
4272
4272
  // src/mountHud.ts
4273
4273
  function showReplayModal(ui, info, buttonKey, onSelect) {
4274
4274
  const cur = info.currency ?? ui.balance.currency.get();
4275
- const money = (n) => core.formatAmount(n, cur);
4275
+ const money2 = (n) => core.formatAmount(n, cur);
4276
4276
  ui.showNotice(
4277
4277
  [
4278
4278
  { kind: "heading", id: "openui-replay-h", text: "openui.replay.title" },
@@ -4280,10 +4280,10 @@ function showReplayModal(ui, info, buttonKey, onSelect) {
4280
4280
  kind: "stat-grid",
4281
4281
  id: "openui-replay-g",
4282
4282
  items: [
4283
- { label: "openui.replay.baseBet", value: money(info.baseBet) },
4283
+ { label: "openui.replay.baseBet", value: money2(info.baseBet) },
4284
4284
  { label: "openui.replay.costMultiplier", value: `${info.costMultiplier}\xD7` },
4285
4285
  { label: "openui.replay.payoutMultiplier", value: `${info.payoutMultiplier}\xD7` },
4286
- { label: "openui.replay.amount", value: money(info.amount) }
4286
+ { label: "openui.replay.amount", value: money2(info.amount) }
4287
4287
  ]
4288
4288
  }
4289
4289
  ],
@@ -4411,10 +4411,237 @@ function mountHud(app, spec = {}, opts = {}) {
4411
4411
  dispose: teardown
4412
4412
  };
4413
4413
  }
4414
+ function money(amount, cur) {
4415
+ return core.formatAmount(amount, cur);
4416
+ }
4417
+ var esc2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4418
+ function mountBuyFeatureModal(_app, hud, features, opts = {}) {
4419
+ const ui = hud.ui;
4420
+ const tr = (k) => ui.t(k);
4421
+ const list = features.slice(0, 4);
4422
+ const boosts = /* @__PURE__ */ new Set();
4423
+ const activation = opts.activation ?? "multi";
4424
+ const blocksBuy = opts.activationBlocksBuy ?? false;
4425
+ const disposers = [];
4426
+ const host2 = document.createElement("div");
4427
+ host2.className = "bfm-root";
4428
+ const vars = {
4429
+ "--accent": "#d99000",
4430
+ "--accent-text": "#1a1200",
4431
+ "--surface": "#ffffff",
4432
+ "--surface-alt": "#eef1f6",
4433
+ "--text": "#181b20",
4434
+ "--text-dim": "#5b6472",
4435
+ "--font": ui.theme.type.family
4436
+ };
4437
+ for (const [k, v] of Object.entries(vars)) host2.style.setProperty(k, v);
4438
+ host2.innerHTML = `
4439
+ <div class="bfm-backdrop" data-close></div>
4440
+ <button class="bfm-x" data-close aria-label="Close">\u2715</button>
4441
+ <div class="bfm-panel" role="dialog" aria-modal="true">
4442
+ <div class="bfm-fit" id="bfm-fit">
4443
+ <h2 class="bfm-title" data-t="Buy Feature">${esc2(tr("Buy Feature"))}</h2>
4444
+ <div class="bfm-bet">
4445
+ <button class="bfm-step" id="bfm-minus" aria-label="Decrease">\u2212</button>
4446
+ <div class="bfm-betbox"><span class="bfm-betlabel" data-t="Bet">${esc2(tr("Bet"))}</span><b id="bfm-betval">\u2014</b></div>
4447
+ <button class="bfm-step" id="bfm-plus" aria-label="Increase">+</button>
4448
+ </div>
4449
+ <div class="bfm-cards" id="bfm-cards"></div>
4450
+ </div>
4451
+ </div>
4452
+ <div class="bfm-confirm" id="bfm-confirm">
4453
+ <div class="bfm-confirm-card">
4454
+ <p class="bfm-confirm-msg" id="bfm-confirm-msg"></p>
4455
+ <div class="bfm-confirm-row">
4456
+ <button class="bfm-confirm-btn bfm-confirm-no" id="bfm-confirm-no" data-t="openui.cancel">${esc2(tr("openui.cancel"))}</button>
4457
+ <button class="bfm-confirm-btn bfm-confirm-yes" id="bfm-confirm-yes" data-t="openui.confirm">${esc2(tr("openui.confirm"))}</button>
4458
+ </div>
4459
+ </div>
4460
+ </div>`;
4461
+ const style = document.createElement("style");
4462
+ style.textContent = BFM_CSS;
4463
+ host2.appendChild(style);
4464
+ document.body.appendChild(host2);
4465
+ const $ = (sel) => host2.querySelector(sel);
4466
+ const panel = $(".bfm-panel");
4467
+ const fitEl = $("#bfm-fit");
4468
+ const cardsEl = $("#bfm-cards");
4469
+ const betValEl = $("#bfm-betval");
4470
+ const confirmEl = $("#bfm-confirm");
4471
+ const confirmMsg = $("#bfm-confirm-msg");
4472
+ const confirmYes = $("#bfm-confirm-yes");
4473
+ const confirmNo = $("#bfm-confirm-no");
4474
+ let pendingConfirm = null;
4475
+ const hideConfirm = () => {
4476
+ confirmEl.classList.remove("show");
4477
+ pendingConfirm = null;
4478
+ };
4479
+ confirmNo.addEventListener("click", hideConfirm);
4480
+ confirmYes.addEventListener("click", () => {
4481
+ const fn = pendingConfirm;
4482
+ hideConfirm();
4483
+ fn?.();
4484
+ });
4485
+ const askConfirm = (totalCost, name, price, onYes) => {
4486
+ if (!hud.shouldConfirmBuy(totalCost)) {
4487
+ onYes();
4488
+ return;
4489
+ }
4490
+ confirmMsg.textContent = ui.t("openui.buyFeature.confirm", { name: ui.t(name), price });
4491
+ pendingConfirm = onYes;
4492
+ confirmEl.classList.add("show");
4493
+ };
4494
+ const layout = () => {
4495
+ const vw = window.innerWidth;
4496
+ const vh = window.innerHeight;
4497
+ const cols = vh <= 540 || vw >= 900 ? Math.min(4, list.length) : Math.min(2, list.length);
4498
+ cardsEl.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
4499
+ const fitW = Math.min(vw * 0.96, cols >= 4 ? 1180 : cols === 1 ? 380 : 760);
4500
+ fitEl.style.width = `${fitW}px`;
4501
+ fitEl.style.transform = "none";
4502
+ const natH = fitEl.offsetHeight;
4503
+ const s = Math.min(1, vh * 0.95 / natH);
4504
+ fitEl.style.transform = `translateX(-50%) scale(${s})`;
4505
+ panel.style.width = `${Math.ceil(fitW * s)}px`;
4506
+ panel.style.height = `${Math.ceil(natH * s)}px`;
4507
+ };
4508
+ const renderCards = () => {
4509
+ const bet = opts.getBet ? opts.getBet() : ui.bet.get();
4510
+ const cur = ui.bet.currency.get();
4511
+ cardsEl.innerHTML = list.map((f) => {
4512
+ const active = boosts.has(f.id);
4513
+ const buyBlocked = f.variant === "buy" && blocksBuy && boosts.size > 0;
4514
+ const price = f.variant === "buy" ? money(f.cost * bet, cur) : `+${money(f.cost * bet, cur)}`;
4515
+ const label = f.variant === "buy" ? tr("Buy") : active ? tr("Activated") : tr("Activate");
4516
+ const cls = `bfm-action bfm-action--${f.variant}${active ? " is-active" : ""}${buyBlocked ? " is-blocked" : ""}`;
4517
+ const img = f.image ? ` style="background-image:url('${f.image}')"` : "";
4518
+ return `
4519
+ <div class="bfm-cell">
4520
+ <div class="bfm-card">
4521
+ <div class="bfm-cardimg"${img}></div>
4522
+ <div class="bfm-strip"></div>
4523
+ <div class="bfm-cardbody">
4524
+ <span class="bfm-name">${esc2(tr(f.name))}</span>
4525
+ <b class="bfm-price">${esc2(price)}</b>
4526
+ </div>
4527
+ </div>
4528
+ <button class="${cls}" data-id="${f.id}" data-variant="${f.variant}"${buyBlocked ? " disabled" : ""}>${esc2(label)}</button>
4529
+ </div>`;
4530
+ }).join("");
4531
+ betValEl.textContent = money(bet, cur);
4532
+ cardsEl.querySelectorAll(".bfm-action").forEach((b) => {
4533
+ b.addEventListener("click", () => onAction(b.dataset.id, b.dataset.variant));
4534
+ });
4535
+ layout();
4536
+ };
4537
+ const onAction = (id, variant) => {
4538
+ const f = list.find((x) => x.id === id);
4539
+ const bet = opts.getBet ? opts.getBet() : ui.bet.get();
4540
+ const cur = ui.bet.currency.get();
4541
+ if (variant === "boost") {
4542
+ const wasActive = boosts.has(id);
4543
+ const commit = () => {
4544
+ if (activation === "single") boosts.clear();
4545
+ if (wasActive) boosts.delete(id);
4546
+ else boosts.add(id);
4547
+ ui.bus.emit("cardActivated", { id });
4548
+ renderCards();
4549
+ opts.onActivate?.([...boosts], id, boosts.has(id));
4550
+ };
4551
+ if (wasActive) {
4552
+ commit();
4553
+ return;
4554
+ }
4555
+ const total = 1 + (f?.cost ?? 0);
4556
+ askConfirm(total, f?.name ?? id, money(total * bet, cur), commit);
4557
+ } else {
4558
+ if (blocksBuy && boosts.size > 0) return;
4559
+ const cost = (f?.cost ?? 0) * bet;
4560
+ askConfirm(f?.cost ?? 0, f?.name ?? id, money(cost, cur), () => {
4561
+ ui.bus.emit("cardActivated", { id });
4562
+ close();
4563
+ opts.onBuy?.(id, cost);
4564
+ });
4565
+ }
4566
+ };
4567
+ $("#bfm-minus").addEventListener("click", () => ui.betStepper.dec());
4568
+ $("#bfm-plus").addEventListener("click", () => ui.betStepper.inc());
4569
+ disposers.push(ui.bet.value.subscribe(() => renderCards()));
4570
+ const open = () => {
4571
+ renderCards();
4572
+ host2.classList.add("open");
4573
+ };
4574
+ const close = () => host2.classList.remove("open");
4575
+ host2.querySelectorAll("[data-close]").forEach((b) => b.addEventListener("click", close));
4576
+ disposers.push(ui.on("buttonActivated", ({ id }) => {
4577
+ if (id === "bonus") open();
4578
+ }));
4579
+ const onResize = () => {
4580
+ if (host2.classList.contains("open")) layout();
4581
+ };
4582
+ window.addEventListener("resize", onResize);
4583
+ disposers.push(
4584
+ ui.locale.subscribe(() => {
4585
+ host2.querySelectorAll("[data-t]").forEach((n) => n.textContent = tr(n.dataset.t));
4586
+ renderCards();
4587
+ })
4588
+ );
4589
+ renderCards();
4590
+ return () => {
4591
+ window.removeEventListener("resize", onResize);
4592
+ for (const d of disposers.splice(0)) d();
4593
+ host2.remove();
4594
+ };
4595
+ }
4596
+ var BFM_CSS = `
4597
+ .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; }
4598
+ .bfm-root.open { opacity: 1; pointer-events: auto; }
4599
+ .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; }
4600
+ .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); }
4601
+ .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; }
4602
+ .bfm-x:hover { transform: scale(1.08); background: rgba(18,14,10,.95); }
4603
+ .bfm-root *, .bfm-root *::before, .bfm-root *::after { box-sizing: border-box; }
4604
+ .bfm-panel { position: relative; transform: translateY(8px) scale(.985); transition: transform .18s ease; }
4605
+ .bfm-root.open .bfm-panel { transform: none; }
4606
+ .bfm-fit { position: absolute; top: 0; left: 50%; transform: translateX(-50%); transform-origin: top center; }
4607
+ .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); }
4608
+ .bfm-bet { display: flex; align-items: center; justify-content: center; gap: 16px; margin: 0 0 24px; }
4609
+ .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; }
4610
+ .bfm-betlabel { font-size: 12px; font-weight: 700; color: var(--text-dim); text-transform: uppercase; letter-spacing: 1px; }
4611
+ .bfm-betbox b { font-size: 24px; color: var(--text); }
4612
+ .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); }
4613
+ .bfm-step:hover { background: var(--surface-alt); }
4614
+ .bfm-step:active { transform: scale(.92); }
4615
+ .bfm-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; align-items: start; }
4616
+ .bfm-cell { display: flex; flex-direction: column; min-width: 0; }
4617
+ .bfm-card { background: var(--surface); border: 4px solid #000; border-radius: 14px; overflow: hidden; box-shadow: 0 14px 34px rgba(0,0,0,.45); }
4618
+ .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); }
4619
+ .bfm-strip { height: 8px; background: linear-gradient(90deg, #f0a500, #ffd166, #f0a500); }
4620
+ .bfm-cardbody { padding: 12px 14px 16px; text-align: center; }
4621
+ .bfm-name { display: block; font-size: 15px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
4622
+ .bfm-price { display: block; margin-top: 2px; font-size: 22px; font-weight: 800; color: var(--text); }
4623
+ .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; }
4624
+ .bfm-action:hover { background: var(--surface-alt); }
4625
+ .bfm-action:active { transform: scale(.96); }
4626
+ .bfm-action.is-active { background: var(--accent); color: var(--accent-text); border-color: #000; }
4627
+ .bfm-action.is-blocked, .bfm-action:disabled { opacity: .38; cursor: not-allowed; box-shadow: none; }
4628
+ .bfm-action.is-blocked:hover, .bfm-action:disabled:hover { background: var(--surface); }
4629
+ .bfm-confirm { position: absolute; inset: 0; z-index: 5; display: grid; place-items: center; opacity: 0; pointer-events: none; transition: opacity .16s ease; }
4630
+ .bfm-confirm.show { opacity: 1; pointer-events: auto; }
4631
+ .bfm-confirm::before { content: ""; position: absolute; inset: 0; background: rgba(8,6,4,.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
4632
+ .bfm-confirm-card { position: relative; width: min(90%, 420px); background: var(--surface); color: var(--text); border: 3px solid #000; border-radius: 14px; padding: 26px 24px 22px; box-shadow: 0 24px 60px rgba(0,0,0,.55); text-align: center; }
4633
+ .bfm-confirm-msg { margin: 0 0 22px; font-size: 19px; font-weight: 700; line-height: 1.4; color: var(--text); }
4634
+ .bfm-confirm-row { display: flex; gap: 14px; }
4635
+ .bfm-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; }
4636
+ .bfm-confirm-btn:active { transform: scale(.96); }
4637
+ .bfm-confirm-no { background: var(--surface); color: var(--text); }
4638
+ .bfm-confirm-no:hover { background: var(--surface-alt); }
4639
+ .bfm-confirm-yes { background: var(--accent); color: var(--accent-text); }
4640
+ `;
4414
4641
 
4415
4642
  // src/bootError.ts
4416
4643
  var host = null;
4417
- var esc2 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4644
+ var esc3 = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4418
4645
  function showBootError(opts = {}) {
4419
4646
  const title = opts.title ?? "Connection lost";
4420
4647
  const message = opts.message ?? "The game could not reach the game server. Please reload to reconnect and continue.";
@@ -4428,10 +4655,10 @@ function showBootError(opts = {}) {
4428
4655
  <div class="openui-be-icon" aria-hidden="true">
4429
4656
  <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
4657
  </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>` : ""}
4658
+ <h1 class="openui-be-title">${esc3(title)}</h1>
4659
+ <p class="openui-be-msg">${esc3(message)}</p>
4660
+ ${opts.detail ? `<p class="openui-be-detail">${esc3(opts.detail)}</p>` : ""}
4661
+ ${showReload ? `<button class="openui-be-reload" type="button">${esc3(opts.reloadLabel ?? "Reload")}</button>` : ""}
4435
4662
  </div>
4436
4663
  <style>
4437
4664
  .openui-boot-error { position: fixed; inset: 0; z-index: 2147483000; display: grid; place-items: center;
@@ -4511,6 +4738,7 @@ exports.defaultSpinSkin = defaultSpinSkin;
4511
4738
  exports.drawSpin = drawSpin;
4512
4739
  exports.hideBootError = hideBootError;
4513
4740
  exports.isDesktop = isDesktop;
4741
+ exports.mountBuyFeatureModal = mountBuyFeatureModal;
4514
4742
  exports.mountHud = mountHud;
4515
4743
  exports.mountInfoMenu = mountInfoMenu;
4516
4744
  exports.showBootError = showBootError;