@sensiblestats/widget-react 0.69.0 → 0.70.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/CHANGELOG.md +25 -0
- package/dist/index.cjs +1064 -319
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +978 -233
- package/dist/index.js.map +1 -1
- package/dist/styles.css +66 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/StatsWidget.tsx
|
|
2
|
-
import { useCallback as
|
|
2
|
+
import { useCallback as useCallback14, useEffect as useEffect26, useMemo as useMemo5, useRef as useRef22, useState as useState44 } from "react";
|
|
3
3
|
import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
|
|
4
4
|
|
|
5
5
|
// src/kickoff.ts
|
|
@@ -123,6 +123,30 @@ var STRINGS = {
|
|
|
123
123
|
gamePlay: "Play",
|
|
124
124
|
gameLocked: "Locked",
|
|
125
125
|
gameVoided: "Voided",
|
|
126
|
+
presets: {
|
|
127
|
+
lang: "en",
|
|
128
|
+
setNumbers: "Set the numbers",
|
|
129
|
+
buildCombo: "Build a combo",
|
|
130
|
+
dialName: "Set the numbers and Build a combo",
|
|
131
|
+
maxPriceRow: "{count} picks, max {price}",
|
|
132
|
+
minPriceRow: "Picks from {price} up",
|
|
133
|
+
comboRow: "A combo of {legs} matches priced at about {total}",
|
|
134
|
+
maxPriceDisplay: (count, price) => `${count} picks, max ${price.toFixed(2)}`,
|
|
135
|
+
maxPriceMessage: (count, price) => `Show me ${count} picks priced at ${price.toFixed(2)} or less.`,
|
|
136
|
+
minPriceDisplay: (count, price) => `${count} picks from ${price.toFixed(2)} up`,
|
|
137
|
+
minPriceMessage: (count, price) => `Show me ${count} picks priced at ${price.toFixed(2)} or more.`,
|
|
138
|
+
comboDisplay: (legs, total) => `A combo of ${legs} priced at about ${total.toFixed(1)}`,
|
|
139
|
+
comboMessage: (legs, total) => `Build me a combo of ${legs} priced at about ${total.toFixed(1)}.`,
|
|
140
|
+
unavailable: "Not available today.",
|
|
141
|
+
send: "Send",
|
|
142
|
+
close: "Close",
|
|
143
|
+
totalLabel: "Total",
|
|
144
|
+
matchesLabel: "Matches",
|
|
145
|
+
fewerMatches: "Fewer matches",
|
|
146
|
+
moreMatches: "More matches",
|
|
147
|
+
changeNumber: (value) => `${value}, tap to change`,
|
|
148
|
+
changeCombo: "Change total or matches"
|
|
149
|
+
},
|
|
126
150
|
games: {
|
|
127
151
|
lang: "en",
|
|
128
152
|
dailyChallenge: "Daily challenge",
|
|
@@ -429,6 +453,30 @@ var STRINGS = {
|
|
|
429
453
|
gamePlay: "Oyna",
|
|
430
454
|
gameLocked: "Kilitli",
|
|
431
455
|
gameVoided: "\u0130ptal edildi",
|
|
456
|
+
presets: {
|
|
457
|
+
lang: "tr",
|
|
458
|
+
setNumbers: "Say\u0131lar\u0131 belirle",
|
|
459
|
+
buildCombo: "Kombin olu\u015Ftur",
|
|
460
|
+
dialName: "Say\u0131lar\u0131 belirle ve Kombin olu\u015Ftur",
|
|
461
|
+
maxPriceRow: "{count} se\xE7im, en fazla {price}",
|
|
462
|
+
minPriceRow: "{price} ve \xFCzeri se\xE7imler",
|
|
463
|
+
comboRow: "Yakla\u015F\u0131k {total} oranl\u0131 {legs} ma\xE7l\u0131k kombin",
|
|
464
|
+
maxPriceDisplay: (count, price) => `${count} se\xE7im, en fazla ${price.toFixed(2)}`,
|
|
465
|
+
maxPriceMessage: (count, price) => `${price.toFixed(2)} veya alt\u0131 oranl\u0131 ${count} se\xE7im g\xF6ster.`,
|
|
466
|
+
minPriceDisplay: (count, price) => `${count} se\xE7im, ${price.toFixed(2)} ve \xFCzeri`,
|
|
467
|
+
minPriceMessage: (count, price) => `${price.toFixed(2)} veya \xFCzeri oranl\u0131 ${count} se\xE7im g\xF6ster.`,
|
|
468
|
+
comboDisplay: (legs, total) => `${legs} ma\xE7l\u0131k kombin, yakla\u015F\u0131k ${total.toFixed(1)}`,
|
|
469
|
+
comboMessage: (legs, total) => `Yakla\u015F\u0131k ${total.toFixed(1)} oranl\u0131 ${legs} ma\xE7l\u0131k bir kombin haz\u0131rla.`,
|
|
470
|
+
unavailable: "Bug\xFCn mevcut de\u011Fil.",
|
|
471
|
+
send: "G\xF6nder",
|
|
472
|
+
close: "Kapat",
|
|
473
|
+
totalLabel: "Toplam",
|
|
474
|
+
matchesLabel: "Ma\xE7 say\u0131s\u0131",
|
|
475
|
+
fewerMatches: "Daha az ma\xE7",
|
|
476
|
+
moreMatches: "Daha fazla ma\xE7",
|
|
477
|
+
changeNumber: (value) => `${value}, de\u011Fi\u015Ftirmek i\xE7in dokun`,
|
|
478
|
+
changeCombo: "Toplam\u0131 veya ma\xE7lar\u0131 de\u011Fi\u015Ftir"
|
|
479
|
+
},
|
|
432
480
|
games: {
|
|
433
481
|
lang: "tr",
|
|
434
482
|
dailyChallenge: "G\xFCn\xFCn meydan okumas\u0131",
|
|
@@ -755,6 +803,7 @@ function normalizeUi(cfg) {
|
|
|
755
803
|
gameLocked: strings.gameLocked,
|
|
756
804
|
gameVoided: strings.gameVoided,
|
|
757
805
|
games: strings.games,
|
|
806
|
+
presets: strings.presets,
|
|
758
807
|
liveCard: strings.liveCard
|
|
759
808
|
};
|
|
760
809
|
}
|
|
@@ -1093,7 +1142,9 @@ function toComboCardVM(card) {
|
|
|
1093
1142
|
legs,
|
|
1094
1143
|
multiplication,
|
|
1095
1144
|
replacedNote: str(card.replacedNote),
|
|
1096
|
-
addToSlipEnabled: card.addToSlipEnabled === true
|
|
1145
|
+
addToSlipEnabled: card.addToSlipEnabled === true,
|
|
1146
|
+
target: finite(card.target),
|
|
1147
|
+
legCount: finite(card.legCount)
|
|
1097
1148
|
};
|
|
1098
1149
|
}
|
|
1099
1150
|
function comboLegToSlipSelection(leg, conversationId) {
|
|
@@ -1167,10 +1218,10 @@ function resultToToast(result, shownOdds, ui) {
|
|
|
1167
1218
|
}
|
|
1168
1219
|
|
|
1169
1220
|
// src/useHostEvents.ts
|
|
1170
|
-
import { useCallback as
|
|
1221
|
+
import { useCallback as useCallback7, useEffect as useEffect16, useMemo as useMemo2, useRef as useRef12, useState as useState36 } from "react";
|
|
1171
1222
|
|
|
1172
1223
|
// src/components/ChatPanel.tsx
|
|
1173
|
-
import { useEffect as
|
|
1224
|
+
import { useCallback as useCallback6, useEffect as useEffect15, useMemo, useRef as useRef11, useState as useState35 } from "react";
|
|
1174
1225
|
|
|
1175
1226
|
// src/components/ChatHeader.tsx
|
|
1176
1227
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
@@ -1199,6 +1250,20 @@ function KebabIcon() {
|
|
|
1199
1250
|
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "1.6" })
|
|
1200
1251
|
] }) });
|
|
1201
1252
|
}
|
|
1253
|
+
function SlidersIcon() {
|
|
1254
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("g", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
|
|
1255
|
+
/* @__PURE__ */ jsx("path", { d: "M4 6h9M17 6h3M4 12h3M11 12h9M4 18h11M19 18h1" }),
|
|
1256
|
+
/* @__PURE__ */ jsx("circle", { cx: "15", cy: "6", r: "2" }),
|
|
1257
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "12", r: "2" }),
|
|
1258
|
+
/* @__PURE__ */ jsx("circle", { cx: "17", cy: "18", r: "2" })
|
|
1259
|
+
] }) });
|
|
1260
|
+
}
|
|
1261
|
+
function ComboIcon() {
|
|
1262
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1em", height: "1em", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("g", { fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinejoin: "round", children: [
|
|
1263
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "11", height: "11", rx: "2" }),
|
|
1264
|
+
/* @__PURE__ */ jsx("rect", { x: "10", y: "10", width: "11", height: "11", rx: "2" })
|
|
1265
|
+
] }) });
|
|
1266
|
+
}
|
|
1202
1267
|
var DASHBOARD_EMOJI = {
|
|
1203
1268
|
football: "\u26BD",
|
|
1204
1269
|
"goal-net": "\u{1F945}",
|
|
@@ -1971,6 +2036,13 @@ function BettingInsightList({ insights, ui, slip, monitor }) {
|
|
|
1971
2036
|
return /* @__PURE__ */ jsx13("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ jsx13(InsightCard, { it, ui, slip, monitor }, it.id)) });
|
|
1972
2037
|
}
|
|
1973
2038
|
|
|
2039
|
+
// src/presetToolsContext.ts
|
|
2040
|
+
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
2041
|
+
var PresetToolsContext = createContext4(null);
|
|
2042
|
+
function usePresetTools() {
|
|
2043
|
+
return useContext4(PresetToolsContext);
|
|
2044
|
+
}
|
|
2045
|
+
|
|
1974
2046
|
// src/components/ComboCardList.tsx
|
|
1975
2047
|
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1976
2048
|
function ComboLegRow({ leg, addToSlipEnabled, ui, slip }) {
|
|
@@ -2013,10 +2085,13 @@ function ComboLegRow({ leg, addToSlipEnabled, ui, slip }) {
|
|
|
2013
2085
|
] });
|
|
2014
2086
|
}
|
|
2015
2087
|
function ComboCardView({ vm, ui, slip }) {
|
|
2088
|
+
const tools = usePresetTools();
|
|
2089
|
+
const { target, legCount } = vm;
|
|
2016
2090
|
return /* @__PURE__ */ jsxs9("div", { className: "ss-w-combo", children: [
|
|
2017
2091
|
/* @__PURE__ */ jsx14("ol", { className: "ss-w-combo-legs", role: "list", children: vm.legs.map((leg) => /* @__PURE__ */ jsx14(ComboLegRow, { leg, addToSlipEnabled: vm.addToSlipEnabled, ui, slip }, leg.key)) }),
|
|
2018
2092
|
/* @__PURE__ */ jsx14("div", { className: "ss-w-combo-math", children: vm.multiplication }),
|
|
2019
|
-
vm.replacedNote ? /* @__PURE__ */ jsx14("p", { className: "ss-w-combo-note", children: vm.replacedNote }) : null
|
|
2093
|
+
vm.replacedNote ? /* @__PURE__ */ jsx14("p", { className: "ss-w-combo-note", children: vm.replacedNote }) : null,
|
|
2094
|
+
tools && target !== void 0 && legCount !== void 0 ? /* @__PURE__ */ jsx14("button", { type: "button", className: "ss-w-combo-change", onClick: () => tools.openBuilder(target, legCount), children: tools.changeLabel }) : null
|
|
2020
2095
|
] });
|
|
2021
2096
|
}
|
|
2022
2097
|
function ComboCardList({ cards, ui, slip }) {
|
|
@@ -3375,11 +3450,15 @@ function MessageList({ controller, ui, slip, onDashboardTap, monitor }) {
|
|
|
3375
3450
|
}
|
|
3376
3451
|
|
|
3377
3452
|
// src/components/ChatInput.tsx
|
|
3378
|
-
import { useState as useState16 } from "react";
|
|
3453
|
+
import { forwardRef, useEffect as useEffect8, useImperativeHandle, useRef as useRef5, useState as useState16 } from "react";
|
|
3379
3454
|
import { jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3380
|
-
|
|
3455
|
+
var ChatInput = forwardRef(function ChatInput2({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message", disabled = false, onType }, ref) {
|
|
3381
3456
|
const [value, setValue] = useState16("");
|
|
3457
|
+
const textareaRef = useRef5(null);
|
|
3458
|
+
const stopRef = useRef5(null);
|
|
3459
|
+
const textBoxWantsFocusRef = useRef5(false);
|
|
3382
3460
|
const submit = () => {
|
|
3461
|
+
if (disabled) return;
|
|
3383
3462
|
const t = value.trim();
|
|
3384
3463
|
if (!t) return;
|
|
3385
3464
|
onSend(t);
|
|
@@ -3391,11 +3470,48 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
3391
3470
|
submit();
|
|
3392
3471
|
}
|
|
3393
3472
|
};
|
|
3473
|
+
useImperativeHandle(ref, () => ({
|
|
3474
|
+
focus() {
|
|
3475
|
+
const box = textareaRef.current;
|
|
3476
|
+
if (box && !box.disabled) {
|
|
3477
|
+
textBoxWantsFocusRef.current = false;
|
|
3478
|
+
box.focus();
|
|
3479
|
+
return;
|
|
3480
|
+
}
|
|
3481
|
+
textBoxWantsFocusRef.current = true;
|
|
3482
|
+
stopRef.current?.focus();
|
|
3483
|
+
}
|
|
3484
|
+
}), []);
|
|
3485
|
+
useEffect8(() => {
|
|
3486
|
+
if (streaming || disabled || !textBoxWantsFocusRef.current) return;
|
|
3487
|
+
textBoxWantsFocusRef.current = false;
|
|
3488
|
+
const box = textareaRef.current;
|
|
3489
|
+
if (!box) return;
|
|
3490
|
+
const active = box.getRootNode().activeElement;
|
|
3491
|
+
const input = box.closest(".ss-w-input");
|
|
3492
|
+
const isWithinComponent = input?.contains(active);
|
|
3493
|
+
if (!active || active === box.ownerDocument.body || isWithinComponent) box.focus();
|
|
3494
|
+
}, [streaming, disabled]);
|
|
3394
3495
|
return /* @__PURE__ */ jsxs40("div", { className: "ss-w-input", children: [
|
|
3395
|
-
/* @__PURE__ */ jsx46(
|
|
3396
|
-
|
|
3496
|
+
/* @__PURE__ */ jsx46(
|
|
3497
|
+
"textarea",
|
|
3498
|
+
{
|
|
3499
|
+
ref: textareaRef,
|
|
3500
|
+
className: "ss-w-textarea",
|
|
3501
|
+
rows: 1,
|
|
3502
|
+
placeholder,
|
|
3503
|
+
value,
|
|
3504
|
+
disabled: streaming || disabled,
|
|
3505
|
+
onChange: (e) => {
|
|
3506
|
+
setValue(e.target.value);
|
|
3507
|
+
onType?.();
|
|
3508
|
+
},
|
|
3509
|
+
onKeyDown
|
|
3510
|
+
}
|
|
3511
|
+
),
|
|
3512
|
+
streaming ? /* @__PURE__ */ jsx46("button", { ref: stopRef, type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, disabled, onClick: onStop, children: /* @__PURE__ */ jsx46("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx46("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, disabled, onClick: submit, children: /* @__PURE__ */ jsx46(SendIcon, {}) })
|
|
3397
3513
|
] });
|
|
3398
|
-
}
|
|
3514
|
+
});
|
|
3399
3515
|
|
|
3400
3516
|
// src/components/TabBar.tsx
|
|
3401
3517
|
import { jsx as jsx47, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
@@ -3878,7 +3994,7 @@ function TodayPanel({ discovery, ui, monitor }) {
|
|
|
3878
3994
|
}
|
|
3879
3995
|
|
|
3880
3996
|
// src/components/GamesPanel.tsx
|
|
3881
|
-
import { useEffect as
|
|
3997
|
+
import { useEffect as useEffect12, useState as useState31 } from "react";
|
|
3882
3998
|
|
|
3883
3999
|
// src/components/GamesLoginWall.tsx
|
|
3884
4000
|
import { jsx as jsx55 } from "react/jsx-runtime";
|
|
@@ -3887,7 +4003,7 @@ function GamesLoginWall({ ui }) {
|
|
|
3887
4003
|
}
|
|
3888
4004
|
|
|
3889
4005
|
// src/components/GamesHub.tsx
|
|
3890
|
-
import { useEffect as
|
|
4006
|
+
import { useEffect as useEffect9, useState as useState18 } from "react";
|
|
3891
4007
|
|
|
3892
4008
|
// src/components/games/ui/gameMeta.ts
|
|
3893
4009
|
function prettifyGameId(gameId) {
|
|
@@ -4073,7 +4189,7 @@ function pickHeroGame(games) {
|
|
|
4073
4189
|
var tileKey = (g) => `${g.gameId}-${g.gameDay}-${g.fixtureId}`;
|
|
4074
4190
|
function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }) {
|
|
4075
4191
|
const [, setTick] = useState18(0);
|
|
4076
|
-
|
|
4192
|
+
useEffect9(() => {
|
|
4077
4193
|
const id = setInterval(() => setTick((t) => t + 1), 6e4);
|
|
4078
4194
|
return () => clearInterval(id);
|
|
4079
4195
|
}, []);
|
|
@@ -4133,10 +4249,10 @@ function GamesHub({ games, myWeeklyRow, weeklyPrize, onOpen, ui }) {
|
|
|
4133
4249
|
}
|
|
4134
4250
|
|
|
4135
4251
|
// src/components/GameScreenHost.tsx
|
|
4136
|
-
import { useEffect as
|
|
4252
|
+
import { useEffect as useEffect11, useRef as useRef8, useState as useState30 } from "react";
|
|
4137
4253
|
|
|
4138
4254
|
// src/useGamePlay.ts
|
|
4139
|
-
import { useCallback as useCallback4, useRef as
|
|
4255
|
+
import { useCallback as useCallback4, useRef as useRef6, useState as useState19 } from "react";
|
|
4140
4256
|
function toSubmitResult(payload) {
|
|
4141
4257
|
return {
|
|
4142
4258
|
// 'pending' means the play is recorded but awaiting resolution (fixture games)
|
|
@@ -4151,12 +4267,12 @@ function useGamePlay(conversation, { gameId, gameDay, fixtureId, locale, refresh
|
|
|
4151
4267
|
const [result, setResult] = useState19(null);
|
|
4152
4268
|
const [submitting, setSubmitting] = useState19(false);
|
|
4153
4269
|
const [rawStatus, setRawStatus] = useState19(null);
|
|
4154
|
-
const inFlightRef =
|
|
4155
|
-
const convRef =
|
|
4270
|
+
const inFlightRef = useRef6(false);
|
|
4271
|
+
const convRef = useRef6(conversation);
|
|
4156
4272
|
convRef.current = conversation;
|
|
4157
|
-
const optsRef =
|
|
4273
|
+
const optsRef = useRef6({ gameId, gameDay, fixtureId, locale, refresh });
|
|
4158
4274
|
optsRef.current = { gameId, gameDay, fixtureId, locale, refresh };
|
|
4159
|
-
const resultRef =
|
|
4275
|
+
const resultRef = useRef6(null);
|
|
4160
4276
|
resultRef.current = result;
|
|
4161
4277
|
const refetch = useCallback4(async () => {
|
|
4162
4278
|
const conv = convRef.current;
|
|
@@ -5086,7 +5202,7 @@ function CareerPathGame({
|
|
|
5086
5202
|
}
|
|
5087
5203
|
|
|
5088
5204
|
// src/components/games/BeatTheGridGame.tsx
|
|
5089
|
-
import React, { useEffect as
|
|
5205
|
+
import React, { useEffect as useEffect10, useId as useId4, useRef as useRef7, useState as useState24 } from "react";
|
|
5090
5206
|
import { Fragment as Fragment14, jsx as jsx74, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
5091
5207
|
function criterionIconKind(label, key) {
|
|
5092
5208
|
const l = (key ?? label).toLowerCase();
|
|
@@ -5169,8 +5285,8 @@ function SearchSheet({
|
|
|
5169
5285
|
const s = ui.games.beatTheGrid;
|
|
5170
5286
|
const [query, setQuery] = useState24("");
|
|
5171
5287
|
const inputId = useId4();
|
|
5172
|
-
const inputRef =
|
|
5173
|
-
|
|
5288
|
+
const inputRef = useRef7(null);
|
|
5289
|
+
useEffect10(() => {
|
|
5174
5290
|
inputRef.current?.focus();
|
|
5175
5291
|
}, [row, col]);
|
|
5176
5292
|
const filtered = playerPool.filter(
|
|
@@ -6472,7 +6588,7 @@ function GameScreenHost({
|
|
|
6472
6588
|
}) {
|
|
6473
6589
|
const { gameId, fixtureId, gameDay = "", lockAtUtc = null } = selected;
|
|
6474
6590
|
const [configJson, setConfigJson] = useState30(null);
|
|
6475
|
-
|
|
6591
|
+
useEffect11(() => {
|
|
6476
6592
|
setConfigJson(null);
|
|
6477
6593
|
if (!conversation) return;
|
|
6478
6594
|
let cancelled = false;
|
|
@@ -6495,12 +6611,12 @@ function GameScreenHost({
|
|
|
6495
6611
|
fixtureId: fixtureId || void 0,
|
|
6496
6612
|
locale: ui.games.lang
|
|
6497
6613
|
});
|
|
6498
|
-
|
|
6614
|
+
useEffect11(() => {
|
|
6499
6615
|
if (conversation) hydrate();
|
|
6500
6616
|
}, [conversation, gameId]);
|
|
6501
|
-
const hydrateRef =
|
|
6617
|
+
const hydrateRef = useRef8(hydrate);
|
|
6502
6618
|
hydrateRef.current = hydrate;
|
|
6503
|
-
|
|
6619
|
+
useEffect11(() => {
|
|
6504
6620
|
if (!FIXTURE_GAME_IDS.has(gameId)) return;
|
|
6505
6621
|
if (rawStatus !== "pending") return;
|
|
6506
6622
|
const timerId = setInterval(() => {
|
|
@@ -6636,7 +6752,7 @@ function GamesPanel({
|
|
|
6636
6752
|
refreshHub
|
|
6637
6753
|
}) {
|
|
6638
6754
|
const [selected, setSelected] = useState31(null);
|
|
6639
|
-
|
|
6755
|
+
useEffect12(() => {
|
|
6640
6756
|
ensureGamesFonts();
|
|
6641
6757
|
}, []);
|
|
6642
6758
|
if (!loggedIn) return /* @__PURE__ */ jsx83(GamesLoginWall, { ui });
|
|
@@ -6831,12 +6947,440 @@ function LeaderboardPanel({ loggedIn, data, loading, onPlay, ui }) {
|
|
|
6831
6947
|
return /* @__PURE__ */ jsx87("div", { className: "ss-w-mon-list", children: /* @__PURE__ */ jsx87(Leaderboard, { data: data ?? EMPTY_PAYLOAD, ui, onPlay }) });
|
|
6832
6948
|
}
|
|
6833
6949
|
|
|
6834
|
-
// src/components/
|
|
6950
|
+
// src/components/PresetSpeedDial.tsx
|
|
6951
|
+
import { useId as useId9 } from "react";
|
|
6835
6952
|
import { jsx as jsx88, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
6953
|
+
function PresetSpeedDial({ expanded, showDot, strings, onToggle, onOpen, rootRef, buttonRef }) {
|
|
6954
|
+
const pillsId = useId9();
|
|
6955
|
+
const tabIndex = expanded ? 0 : -1;
|
|
6956
|
+
return /* @__PURE__ */ jsxs72("div", { ref: rootRef, className: "ss-w-dial", children: [
|
|
6957
|
+
/* @__PURE__ */ jsxs72(
|
|
6958
|
+
"button",
|
|
6959
|
+
{
|
|
6960
|
+
ref: buttonRef,
|
|
6961
|
+
type: "button",
|
|
6962
|
+
className: "ss-w-dial-btn",
|
|
6963
|
+
"aria-expanded": expanded,
|
|
6964
|
+
"aria-controls": pillsId,
|
|
6965
|
+
"aria-label": strings.dialName,
|
|
6966
|
+
onClick: onToggle,
|
|
6967
|
+
children: [
|
|
6968
|
+
/* @__PURE__ */ jsx88("span", { className: "ss-w-dial-icon ss-w-dial-icon--open", children: /* @__PURE__ */ jsx88(SlidersIcon, {}) }),
|
|
6969
|
+
/* @__PURE__ */ jsx88("span", { className: "ss-w-dial-icon ss-w-dial-icon--close", children: /* @__PURE__ */ jsx88(CloseIcon, {}) }),
|
|
6970
|
+
showDot && !expanded ? /* @__PURE__ */ jsx88("span", { className: "ss-w-dial-dot", "aria-hidden": "true" }) : null
|
|
6971
|
+
]
|
|
6972
|
+
}
|
|
6973
|
+
),
|
|
6974
|
+
/* @__PURE__ */ jsxs72("div", { id: pillsId, className: "ss-w-dial-pills", "data-open": expanded ? "" : void 0, children: [
|
|
6975
|
+
/* @__PURE__ */ jsxs72("button", { type: "button", className: "ss-w-dial-pill", tabIndex, onClick: () => onOpen("numbers"), children: [
|
|
6976
|
+
/* @__PURE__ */ jsx88(SlidersIcon, {}),
|
|
6977
|
+
/* @__PURE__ */ jsx88("span", { className: "ss-w-dial-pill-label", children: strings.setNumbers })
|
|
6978
|
+
] }),
|
|
6979
|
+
/* @__PURE__ */ jsxs72("button", { type: "button", className: "ss-w-dial-pill", tabIndex, onClick: () => onOpen("combo"), children: [
|
|
6980
|
+
/* @__PURE__ */ jsx88(ComboIcon, {}),
|
|
6981
|
+
/* @__PURE__ */ jsx88("span", { className: "ss-w-dial-pill-label", children: strings.buildCombo })
|
|
6982
|
+
] })
|
|
6983
|
+
] })
|
|
6984
|
+
] });
|
|
6985
|
+
}
|
|
6986
|
+
|
|
6987
|
+
// src/components/PresetTools.tsx
|
|
6988
|
+
import { Fragment as Fragment20, useEffect as useEffect13, useId as useId10, useRef as useRef9, useState as useState33 } from "react";
|
|
6989
|
+
|
|
6990
|
+
// src/presetGrid.ts
|
|
6991
|
+
var DEFAULT_SINGLES_LIMITS = [1.3, 1.5, 1.7, 2];
|
|
6992
|
+
var DEFAULT_SINGLES_FLOORS = [1.5, 2, 2.5, 3];
|
|
6993
|
+
var DEFAULT_COMBO_TOTALS = [3, 5, 10, 20, 50];
|
|
6994
|
+
var FIXED_SINGLES_COUNT = 3;
|
|
6995
|
+
var MIN_COMBO_LEGS = 2;
|
|
6996
|
+
var MAX_COMBO_LEGS = 6;
|
|
6997
|
+
var START = { maxPrice: 1.5, minPrice: 2, comboTotal: 5, comboLegs: 3 };
|
|
6998
|
+
var finite2 = (v) => typeof v === "number" && Number.isFinite(v);
|
|
6999
|
+
var cents = (n) => Math.round(n * 100);
|
|
7000
|
+
function samePrice(a, b) {
|
|
7001
|
+
return cents(a) === cents(b);
|
|
7002
|
+
}
|
|
7003
|
+
function isPresetGrid(v) {
|
|
7004
|
+
if (!v || typeof v !== "object") return false;
|
|
7005
|
+
const g = v;
|
|
7006
|
+
return Array.isArray(g.singles) && Array.isArray(g.singlesFrom) && Array.isArray(g.combos) && finite2(g.maxLegs);
|
|
7007
|
+
}
|
|
7008
|
+
function drawable(p) {
|
|
7009
|
+
return !!p && finite2(p.price) && finite2(p.matchOddsId) && finite2(p.matchId) && typeof p.homeTeamName === "string" && typeof p.awayTeamName === "string";
|
|
7010
|
+
}
|
|
7011
|
+
function choices(defaults, present) {
|
|
7012
|
+
const out = [];
|
|
7013
|
+
for (const n of [...defaults, ...present]) {
|
|
7014
|
+
if (finite2(n) && n > 0 && !out.some((m) => samePrice(m, n))) out.push(n);
|
|
7015
|
+
}
|
|
7016
|
+
return out.sort((a, b) => a - b);
|
|
7017
|
+
}
|
|
7018
|
+
function singlesLimits(grid) {
|
|
7019
|
+
return choices(DEFAULT_SINGLES_LIMITS, grid.singles.map((c) => c?.price));
|
|
7020
|
+
}
|
|
7021
|
+
function singlesFloors(grid) {
|
|
7022
|
+
return choices(DEFAULT_SINGLES_FLOORS, grid.singlesFrom.map((c) => c?.price));
|
|
7023
|
+
}
|
|
7024
|
+
function comboTotals(grid) {
|
|
7025
|
+
return choices(DEFAULT_COMBO_TOTALS, grid.combos.map((c) => c?.total));
|
|
7026
|
+
}
|
|
7027
|
+
function comboLegChoices(grid) {
|
|
7028
|
+
const max = Math.min(MAX_COMBO_LEGS, Math.floor(grid.maxLegs));
|
|
7029
|
+
const out = [];
|
|
7030
|
+
for (let n = MIN_COMBO_LEGS; n <= max; n++) out.push(n);
|
|
7031
|
+
return out;
|
|
7032
|
+
}
|
|
7033
|
+
function cycle(values, current) {
|
|
7034
|
+
if (values.length === 0) return current;
|
|
7035
|
+
const i = values.findIndex((v) => samePrice(v, current));
|
|
7036
|
+
return values[(i + 1) % values.length] ?? current;
|
|
7037
|
+
}
|
|
7038
|
+
function startValue(values, preferred) {
|
|
7039
|
+
return values.find((v) => samePrice(v, preferred)) ?? values[0] ?? preferred;
|
|
7040
|
+
}
|
|
7041
|
+
function nearest(values, target) {
|
|
7042
|
+
const first = values[0];
|
|
7043
|
+
if (first === void 0) return target;
|
|
7044
|
+
if (!(target > 0)) return first;
|
|
7045
|
+
const distance = (v) => Math.abs(Math.log(v / target));
|
|
7046
|
+
return values.reduce((best, v) => distance(v) < distance(best) ? v : best, first);
|
|
7047
|
+
}
|
|
7048
|
+
function clampLegs(values, legs) {
|
|
7049
|
+
const lo = values[0];
|
|
7050
|
+
const hi = values[values.length - 1];
|
|
7051
|
+
if (lo === void 0 || hi === void 0) return legs;
|
|
7052
|
+
return Math.min(Math.max(Math.round(legs), lo), hi);
|
|
7053
|
+
}
|
|
7054
|
+
function findSingles(cells, price, count) {
|
|
7055
|
+
const cell = cells.find((c) => !!c && finite2(c.price) && samePrice(c.price, price) && c.count === count);
|
|
7056
|
+
return cell && Array.isArray(cell.picks) && cell.picks.length === count && cell.picks.every(drawable) ? cell : null;
|
|
7057
|
+
}
|
|
7058
|
+
function findCombo(grid, total, legs) {
|
|
7059
|
+
const cell = grid.combos.find((c) => !!c && finite2(c.total) && samePrice(c.total, total) && c.legs === legs);
|
|
7060
|
+
const combo = cell?.combo;
|
|
7061
|
+
const whole = !!combo && typeof combo.multiplication === "string" && combo.multiplication !== "" && Array.isArray(combo.legs) && combo.legs.length === legs && combo.legs.every(drawable);
|
|
7062
|
+
return cell && whole ? cell : null;
|
|
7063
|
+
}
|
|
7064
|
+
function idsOf(picks) {
|
|
7065
|
+
return { matchOddsIds: picks.map((p) => p.matchOddsId), matchIds: picks.map((p) => p.matchId) };
|
|
7066
|
+
}
|
|
7067
|
+
function maxPriceAsk(cell, s) {
|
|
7068
|
+
return {
|
|
7069
|
+
message: s.maxPriceMessage(cell.count, cell.price),
|
|
7070
|
+
displayText: s.maxPriceDisplay(cell.count, cell.price),
|
|
7071
|
+
preset: { kind: "max_price", price: cell.price, count: cell.count, ...idsOf(cell.picks) }
|
|
7072
|
+
};
|
|
7073
|
+
}
|
|
7074
|
+
function minPriceAsk(cell, s) {
|
|
7075
|
+
return {
|
|
7076
|
+
message: s.minPriceMessage(cell.count, cell.price),
|
|
7077
|
+
displayText: s.minPriceDisplay(cell.count, cell.price),
|
|
7078
|
+
preset: { kind: "min_price", price: cell.price, count: cell.count, ...idsOf(cell.picks) }
|
|
7079
|
+
};
|
|
7080
|
+
}
|
|
7081
|
+
function comboAsk(cell, s) {
|
|
7082
|
+
return {
|
|
7083
|
+
message: s.comboMessage(cell.legs, cell.total),
|
|
7084
|
+
displayText: s.comboDisplay(cell.legs, cell.total),
|
|
7085
|
+
preset: { kind: "combo", total: cell.total, legs: cell.legs, ...idsOf(cell.combo.legs) }
|
|
7086
|
+
};
|
|
7087
|
+
}
|
|
7088
|
+
|
|
7089
|
+
// src/components/PresetTools.tsx
|
|
7090
|
+
import { Fragment as Fragment21, jsx as jsx89, jsxs as jsxs73 } from "react/jsx-runtime";
|
|
7091
|
+
var FOCUSABLE = 'button:not([disabled]), [href], input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
7092
|
+
function PresetToolModal({ title, closeLabel, onClose, children, footer }) {
|
|
7093
|
+
const dialogRef = useRef9(null);
|
|
7094
|
+
const titleId = useId10();
|
|
7095
|
+
useEffect13(() => {
|
|
7096
|
+
dialogRef.current?.focus();
|
|
7097
|
+
}, []);
|
|
7098
|
+
useEffect13(() => {
|
|
7099
|
+
const onKey = (e) => {
|
|
7100
|
+
if (e.key !== "Escape") return;
|
|
7101
|
+
e.stopPropagation();
|
|
7102
|
+
e.preventDefault();
|
|
7103
|
+
onClose();
|
|
7104
|
+
};
|
|
7105
|
+
window.addEventListener("keydown", onKey, true);
|
|
7106
|
+
return () => window.removeEventListener("keydown", onKey, true);
|
|
7107
|
+
}, [onClose]);
|
|
7108
|
+
const trapTab = (e) => {
|
|
7109
|
+
if (e.key !== "Tab") return;
|
|
7110
|
+
const dialog = dialogRef.current;
|
|
7111
|
+
if (!dialog) return;
|
|
7112
|
+
const items = Array.from(dialog.querySelectorAll(FOCUSABLE));
|
|
7113
|
+
const first = items[0];
|
|
7114
|
+
const last = items[items.length - 1];
|
|
7115
|
+
if (!first || !last) {
|
|
7116
|
+
e.preventDefault();
|
|
7117
|
+
return;
|
|
7118
|
+
}
|
|
7119
|
+
const active = dialog.getRootNode().activeElement;
|
|
7120
|
+
if (e.shiftKey && (active === first || active === dialog)) {
|
|
7121
|
+
e.preventDefault();
|
|
7122
|
+
last.focus();
|
|
7123
|
+
} else if (!e.shiftKey && active === last) {
|
|
7124
|
+
e.preventDefault();
|
|
7125
|
+
first.focus();
|
|
7126
|
+
}
|
|
7127
|
+
};
|
|
7128
|
+
return /* @__PURE__ */ jsx89("div", { className: "ss-w-tool-backdrop", children: /* @__PURE__ */ jsxs73("div", { ref: dialogRef, className: "ss-w-tool", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, tabIndex: -1, onKeyDown: trapTab, children: [
|
|
7129
|
+
/* @__PURE__ */ jsxs73("div", { className: "ss-w-tool-head", children: [
|
|
7130
|
+
/* @__PURE__ */ jsx89("h2", { id: titleId, className: "ss-w-tool-title", children: title }),
|
|
7131
|
+
/* @__PURE__ */ jsx89("button", { type: "button", className: "ss-w-tool-close", "aria-label": closeLabel, onClick: onClose, children: /* @__PURE__ */ jsx89(CloseIcon, {}) })
|
|
7132
|
+
] }),
|
|
7133
|
+
/* @__PURE__ */ jsx89("div", { className: "ss-w-tool-body", children }),
|
|
7134
|
+
footer ? /* @__PURE__ */ jsx89("div", { className: "ss-w-tool-foot", children: footer }) : null
|
|
7135
|
+
] }) });
|
|
7136
|
+
}
|
|
7137
|
+
function fillTemplate(template, slots) {
|
|
7138
|
+
return template.split(/(\{[a-z]+\})/).filter((part) => part !== "").map((part, i) => {
|
|
7139
|
+
const key = /^\{([a-z]+)\}$/.exec(part)?.[1];
|
|
7140
|
+
return /* @__PURE__ */ jsx89(Fragment20, { children: key !== void 0 && key in slots ? slots[key] : part }, i);
|
|
7141
|
+
});
|
|
7142
|
+
}
|
|
7143
|
+
function NumberButton({ value, label, onCycle }) {
|
|
7144
|
+
return /* @__PURE__ */ jsx89("button", { type: "button", className: "ss-w-tool-num", "aria-label": label, onClick: onCycle, children: value });
|
|
7145
|
+
}
|
|
7146
|
+
function SendButton({ label, display, disabled, onClick }) {
|
|
7147
|
+
return /* @__PURE__ */ jsx89("button", { type: "button", className: "ss-w-tool-send", "aria-label": `${label}: ${display}`, disabled, onClick, children: label });
|
|
7148
|
+
}
|
|
7149
|
+
function PickList({ picks, formatKickoff }) {
|
|
7150
|
+
return /* @__PURE__ */ jsx89("ul", { className: "ss-w-tool-picks", role: "list", children: picks.map((p) => /* @__PURE__ */ jsxs73("li", { className: "ss-w-tool-pick", children: [
|
|
7151
|
+
/* @__PURE__ */ jsxs73("span", { className: "ss-w-tool-pick-match", children: [
|
|
7152
|
+
p.homeTeamName,
|
|
7153
|
+
" \u2013 ",
|
|
7154
|
+
p.awayTeamName
|
|
7155
|
+
] }),
|
|
7156
|
+
/* @__PURE__ */ jsxs73("span", { className: "ss-w-tool-pick-sel", children: [
|
|
7157
|
+
p.marketLabel,
|
|
7158
|
+
": ",
|
|
7159
|
+
p.selectionLabel,
|
|
7160
|
+
p.line ? ` ${p.line}` : ""
|
|
7161
|
+
] }),
|
|
7162
|
+
/* @__PURE__ */ jsx89("span", { className: "ss-w-tool-pick-kick", children: formatKickoff(p.kickoffUtc) }),
|
|
7163
|
+
/* @__PURE__ */ jsx89("span", { className: "ss-w-tool-pick-price", children: p.price.toFixed(2) })
|
|
7164
|
+
] }, p.matchOddsId)) });
|
|
7165
|
+
}
|
|
7166
|
+
function ComboPreview({ cell, formatKickoff }) {
|
|
7167
|
+
return /* @__PURE__ */ jsxs73(Fragment21, { children: [
|
|
7168
|
+
/* @__PURE__ */ jsx89(PickList, { picks: cell.combo.legs, formatKickoff }),
|
|
7169
|
+
/* @__PURE__ */ jsx89("div", { className: "ss-w-tool-math", children: cell.combo.multiplication })
|
|
7170
|
+
] });
|
|
7171
|
+
}
|
|
7172
|
+
function Unavailable({ text }) {
|
|
7173
|
+
return /* @__PURE__ */ jsx89("p", { className: "ss-w-tool-unavailable", children: text });
|
|
7174
|
+
}
|
|
7175
|
+
function SetNumbersTool({ grid, strings, streaming, formatKickoff, onSend, onClose }) {
|
|
7176
|
+
const limits = singlesLimits(grid);
|
|
7177
|
+
const floors = singlesFloors(grid);
|
|
7178
|
+
const totals = comboTotals(grid);
|
|
7179
|
+
const legChoices = comboLegChoices(grid);
|
|
7180
|
+
const count = FIXED_SINGLES_COUNT;
|
|
7181
|
+
const [maxPrice, setMaxPrice] = useState33(() => startValue(limits, START.maxPrice));
|
|
7182
|
+
const [minPrice, setMinPrice] = useState33(() => startValue(floors, START.minPrice));
|
|
7183
|
+
const [total, setTotal] = useState33(() => startValue(totals, START.comboTotal));
|
|
7184
|
+
const [legs, setLegs] = useState33(() => startValue(legChoices, START.comboLegs));
|
|
7185
|
+
const [announcement, setAnnouncement] = useState33("");
|
|
7186
|
+
const maxCell = findSingles(grid.singles, maxPrice, count);
|
|
7187
|
+
const minCell = findSingles(grid.singlesFrom, minPrice, count);
|
|
7188
|
+
const comboCell = findCombo(grid, total, legs);
|
|
7189
|
+
const announce = (display, available) => setAnnouncement(available ? display : `${display}. ${strings.unavailable}`);
|
|
7190
|
+
const nextMax = () => {
|
|
7191
|
+
const v = cycle(limits, maxPrice);
|
|
7192
|
+
setMaxPrice(v);
|
|
7193
|
+
announce(strings.maxPriceDisplay(count, v), !!findSingles(grid.singles, v, count));
|
|
7194
|
+
};
|
|
7195
|
+
const nextMin = () => {
|
|
7196
|
+
const v = cycle(floors, minPrice);
|
|
7197
|
+
setMinPrice(v);
|
|
7198
|
+
announce(strings.minPriceDisplay(count, v), !!findSingles(grid.singlesFrom, v, count));
|
|
7199
|
+
};
|
|
7200
|
+
const nextLegs = () => {
|
|
7201
|
+
const v = cycle(legChoices, legs);
|
|
7202
|
+
setLegs(v);
|
|
7203
|
+
announce(strings.comboDisplay(v, total), !!findCombo(grid, total, v));
|
|
7204
|
+
};
|
|
7205
|
+
const nextTotal = () => {
|
|
7206
|
+
const v = cycle(totals, total);
|
|
7207
|
+
setTotal(v);
|
|
7208
|
+
announce(strings.comboDisplay(legs, v), !!findCombo(grid, v, legs));
|
|
7209
|
+
};
|
|
7210
|
+
return /* @__PURE__ */ jsxs73(PresetToolModal, { title: strings.setNumbers, closeLabel: strings.close, onClose, children: [
|
|
7211
|
+
/* @__PURE__ */ jsxs73("section", { className: "ss-w-tool-row", children: [
|
|
7212
|
+
/* @__PURE__ */ jsx89("p", { className: "ss-w-tool-ask", children: fillTemplate(strings.maxPriceRow, {
|
|
7213
|
+
count: String(count),
|
|
7214
|
+
price: /* @__PURE__ */ jsx89(NumberButton, { value: maxPrice.toFixed(2), label: strings.changeNumber(maxPrice.toFixed(2)), onCycle: nextMax })
|
|
7215
|
+
}) }),
|
|
7216
|
+
maxCell ? /* @__PURE__ */ jsx89(PickList, { picks: maxCell.picks, formatKickoff }) : /* @__PURE__ */ jsx89(Unavailable, { text: strings.unavailable }),
|
|
7217
|
+
/* @__PURE__ */ jsx89(SendButton, { label: strings.send, display: strings.maxPriceDisplay(count, maxPrice), disabled: !maxCell || streaming, onClick: () => {
|
|
7218
|
+
if (maxCell) onSend(maxPriceAsk(maxCell, strings));
|
|
7219
|
+
} })
|
|
7220
|
+
] }),
|
|
7221
|
+
/* @__PURE__ */ jsxs73("section", { className: "ss-w-tool-row", children: [
|
|
7222
|
+
/* @__PURE__ */ jsx89("p", { className: "ss-w-tool-ask", children: fillTemplate(strings.minPriceRow, {
|
|
7223
|
+
count: String(count),
|
|
7224
|
+
price: /* @__PURE__ */ jsx89(NumberButton, { value: minPrice.toFixed(2), label: strings.changeNumber(minPrice.toFixed(2)), onCycle: nextMin })
|
|
7225
|
+
}) }),
|
|
7226
|
+
minCell ? /* @__PURE__ */ jsx89(PickList, { picks: minCell.picks, formatKickoff }) : /* @__PURE__ */ jsx89(Unavailable, { text: strings.unavailable }),
|
|
7227
|
+
/* @__PURE__ */ jsx89(SendButton, { label: strings.send, display: strings.minPriceDisplay(count, minPrice), disabled: !minCell || streaming, onClick: () => {
|
|
7228
|
+
if (minCell) onSend(minPriceAsk(minCell, strings));
|
|
7229
|
+
} })
|
|
7230
|
+
] }),
|
|
7231
|
+
/* @__PURE__ */ jsxs73("section", { className: "ss-w-tool-row", children: [
|
|
7232
|
+
/* @__PURE__ */ jsx89("p", { className: "ss-w-tool-ask", children: fillTemplate(strings.comboRow, {
|
|
7233
|
+
legs: /* @__PURE__ */ jsx89(NumberButton, { value: String(legs), label: strings.changeNumber(String(legs)), onCycle: nextLegs }),
|
|
7234
|
+
total: /* @__PURE__ */ jsx89(NumberButton, { value: total.toFixed(1), label: strings.changeNumber(total.toFixed(1)), onCycle: nextTotal })
|
|
7235
|
+
}) }),
|
|
7236
|
+
comboCell ? /* @__PURE__ */ jsx89(ComboPreview, { cell: comboCell, formatKickoff }) : /* @__PURE__ */ jsx89(Unavailable, { text: strings.unavailable }),
|
|
7237
|
+
/* @__PURE__ */ jsx89(SendButton, { label: strings.send, display: strings.comboDisplay(legs, total), disabled: !comboCell || streaming, onClick: () => {
|
|
7238
|
+
if (comboCell) onSend(comboAsk(comboCell, strings));
|
|
7239
|
+
} })
|
|
7240
|
+
] }),
|
|
7241
|
+
/* @__PURE__ */ jsx89("p", { className: "ss-w-vh", "aria-live": "polite", children: announcement })
|
|
7242
|
+
] });
|
|
7243
|
+
}
|
|
7244
|
+
function BuildComboTool({ grid, strings, streaming, formatKickoff, initialTotal, initialLegs, onSend, onClose }) {
|
|
7245
|
+
const totals = comboTotals(grid);
|
|
7246
|
+
const legChoices = comboLegChoices(grid);
|
|
7247
|
+
const [total, setTotal] = useState33(() => initialTotal !== void 0 ? nearest(totals, initialTotal) : startValue(totals, START.comboTotal));
|
|
7248
|
+
const [legs, setLegs] = useState33(() => initialLegs !== void 0 ? clampLegs(legChoices, initialLegs) : startValue(legChoices, START.comboLegs));
|
|
7249
|
+
const [announcement, setAnnouncement] = useState33("");
|
|
7250
|
+
const cell = findCombo(grid, total, legs);
|
|
7251
|
+
const minLegs = legChoices[0] ?? legs;
|
|
7252
|
+
const maxLegs = legChoices[legChoices.length - 1] ?? legs;
|
|
7253
|
+
const display = strings.comboDisplay(legs, total);
|
|
7254
|
+
const choose = (nextTotal, nextLegs) => {
|
|
7255
|
+
setTotal(nextTotal);
|
|
7256
|
+
setLegs(nextLegs);
|
|
7257
|
+
const d = strings.comboDisplay(nextLegs, nextTotal);
|
|
7258
|
+
setAnnouncement(findCombo(grid, nextTotal, nextLegs) ? d : `${d}. ${strings.unavailable}`);
|
|
7259
|
+
};
|
|
7260
|
+
const footer = /* @__PURE__ */ jsx89(SendButton, { label: strings.send, display, disabled: !cell || streaming, onClick: () => {
|
|
7261
|
+
if (cell) onSend(comboAsk(cell, strings));
|
|
7262
|
+
} });
|
|
7263
|
+
return /* @__PURE__ */ jsxs73(PresetToolModal, { title: strings.buildCombo, closeLabel: strings.close, onClose, footer, children: [
|
|
7264
|
+
/* @__PURE__ */ jsxs73("div", { className: "ss-w-tool-section", role: "group", "aria-label": strings.totalLabel, children: [
|
|
7265
|
+
/* @__PURE__ */ jsx89("span", { className: "ss-w-tool-label", "aria-hidden": "true", children: strings.totalLabel }),
|
|
7266
|
+
/* @__PURE__ */ jsx89("div", { className: "ss-w-tool-chips", children: totals.map((t) => /* @__PURE__ */ jsx89("button", { type: "button", className: "ss-w-tool-chip", "aria-pressed": samePrice(t, total), onClick: () => choose(t, legs), children: t.toFixed(1) }, t)) })
|
|
7267
|
+
] }),
|
|
7268
|
+
/* @__PURE__ */ jsxs73("div", { className: "ss-w-tool-section", role: "group", "aria-label": strings.matchesLabel, children: [
|
|
7269
|
+
/* @__PURE__ */ jsx89("span", { className: "ss-w-tool-label", "aria-hidden": "true", children: strings.matchesLabel }),
|
|
7270
|
+
/* @__PURE__ */ jsxs73("div", { className: "ss-w-tool-stepper", children: [
|
|
7271
|
+
/* @__PURE__ */ jsx89("button", { type: "button", className: "ss-w-tool-step", "aria-label": strings.fewerMatches, disabled: legs <= minLegs, onClick: () => choose(total, legs - 1), children: "\u2212" }),
|
|
7272
|
+
/* @__PURE__ */ jsx89("span", { className: "ss-w-tool-count", children: legs }),
|
|
7273
|
+
/* @__PURE__ */ jsx89("button", { type: "button", className: "ss-w-tool-step", "aria-label": strings.moreMatches, disabled: legs >= maxLegs, onClick: () => choose(total, legs + 1), children: "+" })
|
|
7274
|
+
] })
|
|
7275
|
+
] }),
|
|
7276
|
+
cell ? /* @__PURE__ */ jsx89(ComboPreview, { cell, formatKickoff }) : /* @__PURE__ */ jsx89(Unavailable, { text: strings.unavailable }),
|
|
7277
|
+
/* @__PURE__ */ jsx89("p", { className: "ss-w-vh", "aria-live": "polite", children: announcement })
|
|
7278
|
+
] });
|
|
7279
|
+
}
|
|
7280
|
+
|
|
7281
|
+
// src/usePresetDial.ts
|
|
7282
|
+
import { useCallback as useCallback5, useEffect as useEffect14, useRef as useRef10, useState as useState34 } from "react";
|
|
7283
|
+
function sendInFlight(messages, isStreaming) {
|
|
7284
|
+
const last = messages[messages.length - 1];
|
|
7285
|
+
return isStreaming && !!last && last.role === "assistant" && !last.done && !last.isGreeting;
|
|
7286
|
+
}
|
|
7287
|
+
function lastUserId(messages) {
|
|
7288
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
7289
|
+
const m = messages[i];
|
|
7290
|
+
if (m && m.role === "user") return m.id;
|
|
7291
|
+
}
|
|
7292
|
+
return null;
|
|
7293
|
+
}
|
|
7294
|
+
var SCROLL_KEYS = /* @__PURE__ */ new Set(["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " "]);
|
|
7295
|
+
function usePresetDial({ layerRef, dialRef, dialButtonRef, messages, isStreaming, activeTab }) {
|
|
7296
|
+
const [expanded, setExpanded] = useState34(() => !sendInFlight(messages, isStreaming));
|
|
7297
|
+
const fold = useCallback5(() => setExpanded(false), []);
|
|
7298
|
+
const toggle = useCallback5(() => setExpanded((e) => !e), []);
|
|
7299
|
+
const currentUserId = lastUserId(messages);
|
|
7300
|
+
const userIdRef = useRef10(currentUserId);
|
|
7301
|
+
useEffect14(() => {
|
|
7302
|
+
if (currentUserId === userIdRef.current) return;
|
|
7303
|
+
userIdRef.current = currentUserId;
|
|
7304
|
+
setExpanded(false);
|
|
7305
|
+
}, [currentUserId]);
|
|
7306
|
+
const tabRef = useRef10(activeTab);
|
|
7307
|
+
useEffect14(() => {
|
|
7308
|
+
if (activeTab === tabRef.current) return;
|
|
7309
|
+
tabRef.current = activeTab;
|
|
7310
|
+
setExpanded(false);
|
|
7311
|
+
}, [activeTab]);
|
|
7312
|
+
const expandedRef = useRef10(expanded);
|
|
7313
|
+
expandedRef.current = expanded;
|
|
7314
|
+
useEffect14(() => {
|
|
7315
|
+
const onEscape = (e) => {
|
|
7316
|
+
const dial = dialRef.current;
|
|
7317
|
+
if (e.key !== "Escape" || !dial || !e.composedPath().includes(dial)) return;
|
|
7318
|
+
e.stopPropagation();
|
|
7319
|
+
e.preventDefault();
|
|
7320
|
+
if (!expandedRef.current) return;
|
|
7321
|
+
setExpanded(false);
|
|
7322
|
+
dialButtonRef.current?.focus();
|
|
7323
|
+
};
|
|
7324
|
+
window.addEventListener("keydown", onEscape, true);
|
|
7325
|
+
return () => window.removeEventListener("keydown", onEscape, true);
|
|
7326
|
+
}, [dialRef, dialButtonRef]);
|
|
7327
|
+
useEffect14(() => {
|
|
7328
|
+
if (!expanded) return;
|
|
7329
|
+
const layer = layerRef.current;
|
|
7330
|
+
const inDial = (e) => {
|
|
7331
|
+
const dial = dialRef.current;
|
|
7332
|
+
return !!dial && e.composedPath().includes(dial);
|
|
7333
|
+
};
|
|
7334
|
+
const inList = (e) => e.composedPath().some((n) => n instanceof Element && n.classList.contains("ss-w-list"));
|
|
7335
|
+
const onPress = (e) => {
|
|
7336
|
+
if (!inDial(e)) setExpanded(false);
|
|
7337
|
+
};
|
|
7338
|
+
const onScrollGesture = (e) => {
|
|
7339
|
+
if (inList(e) && !inDial(e)) setExpanded(false);
|
|
7340
|
+
};
|
|
7341
|
+
const onKey = (e) => {
|
|
7342
|
+
if (SCROLL_KEYS.has(e.key) && inList(e)) setExpanded(false);
|
|
7343
|
+
};
|
|
7344
|
+
const doc = layer?.ownerDocument ?? document;
|
|
7345
|
+
doc.addEventListener("pointerdown", onPress, true);
|
|
7346
|
+
layer?.addEventListener("wheel", onScrollGesture, { passive: true });
|
|
7347
|
+
layer?.addEventListener("touchmove", onScrollGesture, { passive: true });
|
|
7348
|
+
window.addEventListener("keydown", onKey, true);
|
|
7349
|
+
return () => {
|
|
7350
|
+
doc.removeEventListener("pointerdown", onPress, true);
|
|
7351
|
+
layer?.removeEventListener("wheel", onScrollGesture);
|
|
7352
|
+
layer?.removeEventListener("touchmove", onScrollGesture);
|
|
7353
|
+
window.removeEventListener("keydown", onKey, true);
|
|
7354
|
+
};
|
|
7355
|
+
}, [expanded, layerRef, dialRef]);
|
|
7356
|
+
return { expanded, toggle, fold };
|
|
7357
|
+
}
|
|
7358
|
+
|
|
7359
|
+
// src/presetSeen.ts
|
|
7360
|
+
var KEY = "ss-w-presets-tool-opened";
|
|
7361
|
+
var openedThisPage = false;
|
|
7362
|
+
function readToolSeen() {
|
|
7363
|
+
if (openedThisPage) return true;
|
|
7364
|
+
try {
|
|
7365
|
+
return window.localStorage.getItem(KEY) === "1";
|
|
7366
|
+
} catch {
|
|
7367
|
+
return false;
|
|
7368
|
+
}
|
|
7369
|
+
}
|
|
7370
|
+
function markToolSeen() {
|
|
7371
|
+
openedThisPage = true;
|
|
7372
|
+
try {
|
|
7373
|
+
window.localStorage.setItem(KEY, "1");
|
|
7374
|
+
} catch {
|
|
7375
|
+
}
|
|
7376
|
+
}
|
|
7377
|
+
|
|
7378
|
+
// src/components/ChatPanel.tsx
|
|
7379
|
+
import { jsx as jsx90, jsxs as jsxs74 } from "react/jsx-runtime";
|
|
6836
7380
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
6837
7381
|
function useIsModal() {
|
|
6838
|
-
const [modal, setModal] =
|
|
6839
|
-
|
|
7382
|
+
const [modal, setModal] = useState35(false);
|
|
7383
|
+
useEffect15(() => {
|
|
6840
7384
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
6841
7385
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
6842
7386
|
const sync = () => setModal(mql.matches);
|
|
@@ -6846,10 +7390,11 @@ function useIsModal() {
|
|
|
6846
7390
|
}, []);
|
|
6847
7391
|
return modal;
|
|
6848
7392
|
}
|
|
6849
|
-
|
|
7393
|
+
var HIDDEN_LAYER_STYLE = { position: "absolute", inset: 0, visibility: "hidden", display: "flex", flexDirection: "column" };
|
|
7394
|
+
function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, gamesResult, leaderboardResult, loggedIn, conversation, presetGrid }) {
|
|
6850
7395
|
const { state, close, stop, send, reset } = controller;
|
|
6851
7396
|
const isModal = useIsModal();
|
|
6852
|
-
|
|
7397
|
+
useEffect15(() => {
|
|
6853
7398
|
const onKey = (e) => {
|
|
6854
7399
|
if (e.key === "Escape") close();
|
|
6855
7400
|
};
|
|
@@ -6864,11 +7409,66 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
|
|
|
6864
7409
|
monitor?.setActiveTab("chat");
|
|
6865
7410
|
send(text, { grounding });
|
|
6866
7411
|
};
|
|
6867
|
-
|
|
7412
|
+
useEffect15(() => {
|
|
6868
7413
|
if (monitor && monitor.activeTab !== "chat" && state.isStreaming) monitor.markChatActivity();
|
|
6869
7414
|
}, [monitor, state.isStreaming, state.messages.length]);
|
|
6870
|
-
|
|
6871
|
-
|
|
7415
|
+
const onChatTab = !monitor || monitor.activeTab === "chat";
|
|
7416
|
+
const layerRef = useRef11(null);
|
|
7417
|
+
const dialRef = useRef11(null);
|
|
7418
|
+
const dialButtonRef = useRef11(null);
|
|
7419
|
+
const inputRef = useRef11(null);
|
|
7420
|
+
const focusAfterCloseRef = useRef11(null);
|
|
7421
|
+
const [tool, setTool] = useState35(null);
|
|
7422
|
+
const [toolSeen, setToolSeen] = useState35(readToolSeen);
|
|
7423
|
+
const dial = usePresetDial({
|
|
7424
|
+
layerRef,
|
|
7425
|
+
dialRef,
|
|
7426
|
+
dialButtonRef,
|
|
7427
|
+
messages: state.messages,
|
|
7428
|
+
isStreaming: state.isStreaming,
|
|
7429
|
+
activeTab: monitor?.activeTab ?? "chat"
|
|
7430
|
+
});
|
|
7431
|
+
const { fold } = dial;
|
|
7432
|
+
const showDial = !!presetGrid && onChatTab && !tool;
|
|
7433
|
+
const openTool = useCallback6((next) => {
|
|
7434
|
+
fold();
|
|
7435
|
+
markToolSeen();
|
|
7436
|
+
setToolSeen(true);
|
|
7437
|
+
setTool(next);
|
|
7438
|
+
}, [fold]);
|
|
7439
|
+
const onPill = useCallback6((kind) => openTool(kind === "numbers" ? { kind: "numbers" } : { kind: "combo" }), [openTool]);
|
|
7440
|
+
const toolsValue = useMemo(
|
|
7441
|
+
() => presetGrid ? { openBuilder: (total, legs) => openTool({ kind: "combo", total, legs }), changeLabel: ui.presets.changeCombo } : null,
|
|
7442
|
+
[presetGrid, openTool, ui.presets.changeCombo]
|
|
7443
|
+
);
|
|
7444
|
+
const closeTool = useCallback6(() => {
|
|
7445
|
+
focusAfterCloseRef.current = "dial";
|
|
7446
|
+
setTool(null);
|
|
7447
|
+
}, []);
|
|
7448
|
+
const sendAsk = useCallback6((ask) => {
|
|
7449
|
+
focusAfterCloseRef.current = "composer";
|
|
7450
|
+
setTool(null);
|
|
7451
|
+
monitor?.setActiveTab("chat");
|
|
7452
|
+
send(ask.message, { displayText: ask.displayText, preset: ask.preset });
|
|
7453
|
+
}, [monitor, send]);
|
|
7454
|
+
const formatKickoff = useCallback6((kickoffUtc) => {
|
|
7455
|
+
const k = ui.bettingKickoff(kickoffUtc);
|
|
7456
|
+
return `${k.dayLabel} ${k.time}`;
|
|
7457
|
+
}, [ui]);
|
|
7458
|
+
useEffect15(() => {
|
|
7459
|
+
if (tool) return;
|
|
7460
|
+
const target = focusAfterCloseRef.current;
|
|
7461
|
+
focusAfterCloseRef.current = null;
|
|
7462
|
+
if (target === "dial") dialButtonRef.current?.focus();
|
|
7463
|
+
else if (target === "composer") inputRef.current?.focus();
|
|
7464
|
+
}, [tool]);
|
|
7465
|
+
useEffect15(() => {
|
|
7466
|
+
if (!tool || onChatTab && presetGrid) return;
|
|
7467
|
+
focusAfterCloseRef.current = "composer";
|
|
7468
|
+
setTool(null);
|
|
7469
|
+
}, [tool, onChatTab, presetGrid]);
|
|
7470
|
+
return /* @__PURE__ */ jsxs74("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
7471
|
+
/* @__PURE__ */ jsx90(
|
|
6872
7472
|
ChatHeader,
|
|
6873
7473
|
{
|
|
6874
7474
|
onClose: close,
|
|
@@ -6881,7 +7481,7 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
|
|
|
6881
7481
|
moreOptionsLabel: ui.moreOptions
|
|
6882
7482
|
}
|
|
6883
7483
|
),
|
|
6884
|
-
monitor && /* @__PURE__ */
|
|
7484
|
+
monitor && /* @__PURE__ */ jsx90(
|
|
6885
7485
|
TabBar,
|
|
6886
7486
|
{
|
|
6887
7487
|
monitor,
|
|
@@ -6893,17 +7493,26 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
|
|
|
6893
7493
|
gamesEnabled: gamesResult?.enabled ?? false
|
|
6894
7494
|
}
|
|
6895
7495
|
),
|
|
6896
|
-
/* @__PURE__ */
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
7496
|
+
/* @__PURE__ */ jsxs74("div", { ref: layerRef, className: "ss-w-chat-layer", "data-dial": presetGrid ? "" : void 0, style: onChatTab ? void 0 : HIDDEN_LAYER_STYLE, children: [
|
|
7497
|
+
/* @__PURE__ */ jsx90(PresetToolsContext.Provider, { value: toolsValue, children: /* @__PURE__ */ jsx90(MessageList, { controller, ui, slip, onDashboardTap, monitor }) }),
|
|
7498
|
+
showDial ? /* @__PURE__ */ jsx90(
|
|
7499
|
+
PresetSpeedDial,
|
|
7500
|
+
{
|
|
7501
|
+
expanded: dial.expanded,
|
|
7502
|
+
showDot: !toolSeen,
|
|
7503
|
+
strings: ui.presets,
|
|
7504
|
+
onToggle: dial.toggle,
|
|
7505
|
+
onOpen: onPill,
|
|
7506
|
+
rootRef: dialRef,
|
|
7507
|
+
buttonRef: dialButtonRef
|
|
7508
|
+
}
|
|
7509
|
+
) : null,
|
|
7510
|
+
tool && presetGrid && onChatTab ? tool.kind === "numbers" ? /* @__PURE__ */ jsx90(SetNumbersTool, { grid: presetGrid, strings: ui.presets, streaming: state.isStreaming, formatKickoff, onSend: sendAsk, onClose: closeTool }) : /* @__PURE__ */ jsx90(BuildComboTool, { grid: presetGrid, strings: ui.presets, streaming: state.isStreaming, formatKickoff, initialTotal: tool.total, initialLegs: tool.legs, onSend: sendAsk, onClose: closeTool }) : null
|
|
7511
|
+
] }),
|
|
7512
|
+
monitor && discovery && monitor.activeTab === "today" && /* @__PURE__ */ jsx90(TodayPanel, { discovery, ui, monitor }),
|
|
7513
|
+
monitor && monitor.activeTab === "following" && /* @__PURE__ */ jsx90(MatchesPanel, { monitor, ui, slip, onAsk: handleAsk }),
|
|
7514
|
+
monitor && monitor.activeTab === "odds" && /* @__PURE__ */ jsx90(OddsPanel, { monitor, ui, slip }),
|
|
7515
|
+
monitor && monitor.activeTab === "games" && gamesResult && /* @__PURE__ */ jsx90(
|
|
6907
7516
|
GamesPanel,
|
|
6908
7517
|
{
|
|
6909
7518
|
loggedIn: !!loggedIn,
|
|
@@ -6917,7 +7526,7 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
|
|
|
6917
7526
|
}
|
|
6918
7527
|
}
|
|
6919
7528
|
),
|
|
6920
|
-
monitor && monitor.activeTab === "leaderboard" && leaderboardResult && /* @__PURE__ */
|
|
7529
|
+
monitor && monitor.activeTab === "leaderboard" && leaderboardResult && /* @__PURE__ */ jsx90(
|
|
6921
7530
|
LeaderboardPanel,
|
|
6922
7531
|
{
|
|
6923
7532
|
loggedIn: !!loggedIn,
|
|
@@ -6927,7 +7536,20 @@ function ChatPanel({ controller, ui, slip, onDashboardTap, monitor, discovery, g
|
|
|
6927
7536
|
ui
|
|
6928
7537
|
}
|
|
6929
7538
|
),
|
|
6930
|
-
(!monitor || monitor.activeTab !== "games" && monitor.activeTab !== "leaderboard") && /* @__PURE__ */
|
|
7539
|
+
(!monitor || monitor.activeTab !== "games" && monitor.activeTab !== "leaderboard") && /* @__PURE__ */ jsx90(
|
|
7540
|
+
ChatInput,
|
|
7541
|
+
{
|
|
7542
|
+
ref: inputRef,
|
|
7543
|
+
placeholder: ui.placeholder,
|
|
7544
|
+
streaming: state.isStreaming,
|
|
7545
|
+
onSend: handleSend,
|
|
7546
|
+
onStop: stop,
|
|
7547
|
+
stopLabel: ui.stopResponse,
|
|
7548
|
+
sendLabel: ui.sendMessage,
|
|
7549
|
+
disabled: !!tool,
|
|
7550
|
+
onType: fold
|
|
7551
|
+
}
|
|
7552
|
+
)
|
|
6931
7553
|
] });
|
|
6932
7554
|
}
|
|
6933
7555
|
|
|
@@ -7136,15 +7758,15 @@ function toSlipEvent(name, entry) {
|
|
|
7136
7758
|
// src/useHostEvents.ts
|
|
7137
7759
|
function useHostEvents(opts) {
|
|
7138
7760
|
const { host, operatorId, currentUser, logger, isOpen, closePanel, onOpenMatch, openMatchLabel } = opts;
|
|
7139
|
-
const [added, setAdded] =
|
|
7140
|
-
const [settled, setSettled] =
|
|
7141
|
-
const markAdded =
|
|
7761
|
+
const [added, setAdded] = useState36({});
|
|
7762
|
+
const [settled, setSettled] = useState36({});
|
|
7763
|
+
const markAdded = useCallback7((matchOddsId) => {
|
|
7142
7764
|
setAdded((prev) => prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true });
|
|
7143
7765
|
}, []);
|
|
7144
|
-
const settle =
|
|
7766
|
+
const settle = useCallback7((matchOddsId) => {
|
|
7145
7767
|
setSettled((prev) => prev[matchOddsId] ? prev : { ...prev, [matchOddsId]: true });
|
|
7146
7768
|
}, []);
|
|
7147
|
-
const clearMarks =
|
|
7769
|
+
const clearMarks = useCallback7((ids) => {
|
|
7148
7770
|
const drop = (prev) => {
|
|
7149
7771
|
if (!ids.some((id) => prev[id])) return prev;
|
|
7150
7772
|
const next = { ...prev };
|
|
@@ -7155,26 +7777,26 @@ function useHostEvents(opts) {
|
|
|
7155
7777
|
setSettled(drop);
|
|
7156
7778
|
}, []);
|
|
7157
7779
|
const hasHost = host !== void 0;
|
|
7158
|
-
const ledger =
|
|
7780
|
+
const ledger = useMemo2(
|
|
7159
7781
|
() => hasHost ? createSlipLedger(`ss-w-slip:${operatorId}`) : null,
|
|
7160
7782
|
[hasHost, operatorId]
|
|
7161
7783
|
);
|
|
7162
|
-
const currentUserRef =
|
|
7784
|
+
const currentUserRef = useRef12(currentUser);
|
|
7163
7785
|
currentUserRef.current = currentUser;
|
|
7164
|
-
const recordAdd =
|
|
7786
|
+
const recordAdd = useCallback7((add) => {
|
|
7165
7787
|
ledger?.record({ id: add.selection.matchOddsId, market: add.market, ...add.pick, user: currentUserRef.current });
|
|
7166
7788
|
}, [ledger]);
|
|
7167
|
-
const slipState =
|
|
7789
|
+
const slipState = useMemo2(
|
|
7168
7790
|
() => ({ added, settled, settle, recordAdd }),
|
|
7169
7791
|
[added, settled, settle, recordAdd]
|
|
7170
7792
|
);
|
|
7171
7793
|
const hasOpenMatch = typeof onOpenMatch === "function";
|
|
7172
7794
|
const tracksViews = hasHost || hasOpenMatch;
|
|
7173
|
-
const views =
|
|
7795
|
+
const views = useMemo2(
|
|
7174
7796
|
() => tracksViews ? createMatchViews(`ss-w-views:${operatorId}`, { user: currentUser }) : null,
|
|
7175
7797
|
[tracksViews, operatorId, currentUser]
|
|
7176
7798
|
);
|
|
7177
|
-
const sinkRef =
|
|
7799
|
+
const sinkRef = useRef12(() => {
|
|
7178
7800
|
});
|
|
7179
7801
|
sinkRef.current = (command) => {
|
|
7180
7802
|
if (command.kind === "matchOpened") {
|
|
@@ -7195,11 +7817,11 @@ function useHostEvents(opts) {
|
|
|
7195
7817
|
logger?.log(toSlipEvent(name, entry));
|
|
7196
7818
|
}
|
|
7197
7819
|
};
|
|
7198
|
-
|
|
7820
|
+
useEffect16(() => {
|
|
7199
7821
|
if (!host) return;
|
|
7200
7822
|
return attachHost(host, (command) => sinkRef.current(command));
|
|
7201
7823
|
}, [host]);
|
|
7202
|
-
|
|
7824
|
+
useEffect16(() => {
|
|
7203
7825
|
if (!isOpen || !views) return;
|
|
7204
7826
|
const held = views.markOpened();
|
|
7205
7827
|
if (held.length === 0) return;
|
|
@@ -7208,7 +7830,7 @@ function useHostEvents(opts) {
|
|
|
7208
7830
|
}
|
|
7209
7831
|
void logger?.flushNow();
|
|
7210
7832
|
}, [isOpen, views, logger]);
|
|
7211
|
-
const openMatchRef =
|
|
7833
|
+
const openMatchRef = useRef12(() => {
|
|
7212
7834
|
});
|
|
7213
7835
|
openMatchRef.current = (matchId) => {
|
|
7214
7836
|
if (views?.view(matchId) === "log") {
|
|
@@ -7222,7 +7844,7 @@ function useHostEvents(opts) {
|
|
|
7222
7844
|
}
|
|
7223
7845
|
if (typeof window.matchMedia === "function" && window.matchMedia(FULLSCREEN_QUERY).matches) closePanel();
|
|
7224
7846
|
};
|
|
7225
|
-
const matchLink =
|
|
7847
|
+
const matchLink = useMemo2(
|
|
7226
7848
|
() => hasOpenMatch ? { open: (matchId) => openMatchRef.current(matchId), label: openMatchLabel } : null,
|
|
7227
7849
|
[hasOpenMatch, openMatchLabel]
|
|
7228
7850
|
);
|
|
@@ -7290,7 +7912,7 @@ function themeAttrs(ui) {
|
|
|
7290
7912
|
}
|
|
7291
7913
|
|
|
7292
7914
|
// src/useChatStream.ts
|
|
7293
|
-
import { useCallback as
|
|
7915
|
+
import { useCallback as useCallback8, useEffect as useEffect18, useMemo as useMemo3, useReducer as useReducer2, useRef as useRef14 } from "react";
|
|
7294
7916
|
import { WidgetSdkError as WidgetSdkError2 } from "@sensiblestats/widget-sdk";
|
|
7295
7917
|
|
|
7296
7918
|
// src/reducer.ts
|
|
@@ -7450,7 +8072,7 @@ function reducer(state, action) {
|
|
|
7450
8072
|
}
|
|
7451
8073
|
|
|
7452
8074
|
// src/useLiveDashboardPoll.ts
|
|
7453
|
-
import { useEffect as
|
|
8075
|
+
import { useEffect as useEffect17, useReducer, useRef as useRef13 } from "react";
|
|
7454
8076
|
var POLL_INTERVAL_MS = 6e4;
|
|
7455
8077
|
var LEAD_MS = 12e4;
|
|
7456
8078
|
var GIVE_UP_MS = 30 * 6e4;
|
|
@@ -7494,11 +8116,11 @@ function findEarliestWakeupMs(messages) {
|
|
|
7494
8116
|
function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
|
|
7495
8117
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
7496
8118
|
const anchor = findAnchor(messages);
|
|
7497
|
-
const anchorRef =
|
|
8119
|
+
const anchorRef = useRef13(anchor);
|
|
7498
8120
|
anchorRef.current = anchor;
|
|
7499
|
-
const inFlightRef =
|
|
8121
|
+
const inFlightRef = useRef13(false);
|
|
7500
8122
|
const anchorKey = anchor ? `${anchor.messageId}:${anchor.kind}` : null;
|
|
7501
|
-
|
|
8123
|
+
useEffect17(() => {
|
|
7502
8124
|
if (!anchorKey || !anchorRef.current) return;
|
|
7503
8125
|
const tick = async () => {
|
|
7504
8126
|
if (inFlightRef.current) return;
|
|
@@ -7534,7 +8156,7 @@ function useLiveDashboardPoll({ messages, dispatch, getLiveDashboard }) {
|
|
|
7534
8156
|
}, POLL_INTERVAL_MS);
|
|
7535
8157
|
return () => window.clearInterval(id);
|
|
7536
8158
|
}, [anchorKey, dispatch, getLiveDashboard]);
|
|
7537
|
-
|
|
8159
|
+
useEffect17(() => {
|
|
7538
8160
|
if (anchorKey !== null) return;
|
|
7539
8161
|
const wakeAt = findEarliestWakeupMs(messages);
|
|
7540
8162
|
if (wakeAt === null) return;
|
|
@@ -7599,7 +8221,7 @@ function seedIdCounter(messages) {
|
|
|
7599
8221
|
return max + 1;
|
|
7600
8222
|
}
|
|
7601
8223
|
function useChatStream(conversation, starterTexts, greetingMessage, storageKey) {
|
|
7602
|
-
const boot =
|
|
8224
|
+
const boot = useMemo3(() => {
|
|
7603
8225
|
const payload = storageKey ? readConversation(storageKey, Date.now()) : null;
|
|
7604
8226
|
const restored = payload != null && payload !== "expired" && payload !== "corrupt";
|
|
7605
8227
|
const base = initialState(starterTexts.map(chipFromText));
|
|
@@ -7609,26 +8231,26 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7609
8231
|
return { state: base, restored: false, stale: payload === "expired" || payload === "corrupt" };
|
|
7610
8232
|
}, []);
|
|
7611
8233
|
const [state, dispatch] = useReducer2(reducer, boot.state);
|
|
7612
|
-
const idRef =
|
|
7613
|
-
const handleRef =
|
|
7614
|
-
const fallbackTimerRef =
|
|
7615
|
-
const stateRef =
|
|
8234
|
+
const idRef = useRef14(seedIdCounter(boot.state.messages));
|
|
8235
|
+
const handleRef = useRef14(null);
|
|
8236
|
+
const fallbackTimerRef = useRef14(null);
|
|
8237
|
+
const stateRef = useRef14(state);
|
|
7616
8238
|
stateRef.current = state;
|
|
7617
|
-
const greetedRef =
|
|
7618
|
-
const hydratedRef =
|
|
7619
|
-
const restoreSeededRef =
|
|
8239
|
+
const greetedRef = useRef14(boot.restored);
|
|
8240
|
+
const hydratedRef = useRef14(false);
|
|
8241
|
+
const restoreSeededRef = useRef14(false);
|
|
7620
8242
|
if (!restoreSeededRef.current) {
|
|
7621
8243
|
restoreSeededRef.current = true;
|
|
7622
8244
|
if (boot.restored && boot.state.conversationId) conversation.conversationId = boot.state.conversationId;
|
|
7623
8245
|
}
|
|
7624
8246
|
const nextId = () => `m${idRef.current++}`;
|
|
7625
|
-
const clearFallbackTimer =
|
|
8247
|
+
const clearFallbackTimer = useCallback8(() => {
|
|
7626
8248
|
if (fallbackTimerRef.current != null) {
|
|
7627
8249
|
clearTimeout(fallbackTimerRef.current);
|
|
7628
8250
|
fallbackTimerRef.current = null;
|
|
7629
8251
|
}
|
|
7630
8252
|
}, []);
|
|
7631
|
-
const armFallbackTimer =
|
|
8253
|
+
const armFallbackTimer = useCallback8((onFire) => {
|
|
7632
8254
|
clearFallbackTimer();
|
|
7633
8255
|
fallbackTimerRef.current = setTimeout(() => {
|
|
7634
8256
|
fallbackTimerRef.current = null;
|
|
@@ -7637,7 +8259,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7637
8259
|
onFire();
|
|
7638
8260
|
}, STREAM_FALLBACK_TIMEOUT_MS);
|
|
7639
8261
|
}, [clearFallbackTimer]);
|
|
7640
|
-
const consume =
|
|
8262
|
+
const consume = useCallback8((handle, onError) => {
|
|
7641
8263
|
;
|
|
7642
8264
|
(async () => {
|
|
7643
8265
|
try {
|
|
@@ -7655,7 +8277,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7655
8277
|
}
|
|
7656
8278
|
})();
|
|
7657
8279
|
}, [clearFallbackTimer]);
|
|
7658
|
-
const run =
|
|
8280
|
+
const run = useCallback8((input, displayText) => {
|
|
7659
8281
|
handleRef.current?.cancel();
|
|
7660
8282
|
clearFallbackTimer();
|
|
7661
8283
|
dispatch({ kind: "USER_SENT", input, userId: nextId(), assistantId: nextId(), displayText });
|
|
@@ -7667,7 +8289,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7667
8289
|
});
|
|
7668
8290
|
consume(handle, (err) => dispatch({ kind: "STREAM_ERROR", error: err }));
|
|
7669
8291
|
}, [conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
7670
|
-
const send =
|
|
8292
|
+
const send = useCallback8((text, opts) => {
|
|
7671
8293
|
const trimmed = text.trim();
|
|
7672
8294
|
if (!trimmed) return;
|
|
7673
8295
|
run({
|
|
@@ -7675,14 +8297,15 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7675
8297
|
actionId: opts?.actionId,
|
|
7676
8298
|
actionRef: opts?.actionRef,
|
|
7677
8299
|
grounding: opts?.grounding,
|
|
7678
|
-
clientCapabilities: [...CLIENT_CAPABILITIES]
|
|
8300
|
+
clientCapabilities: [...CLIENT_CAPABILITIES],
|
|
8301
|
+
...opts?.preset ? { preset: opts.preset } : {}
|
|
7679
8302
|
}, opts?.displayText);
|
|
7680
8303
|
}, [run]);
|
|
7681
|
-
const retry =
|
|
8304
|
+
const retry = useCallback8(() => {
|
|
7682
8305
|
const last = stateRef.current.lastUserInput;
|
|
7683
8306
|
if (last) run(last, stateRef.current.lastDisplayText ?? void 0);
|
|
7684
8307
|
}, [run]);
|
|
7685
|
-
const fireGreeting =
|
|
8308
|
+
const fireGreeting = useCallback8(() => {
|
|
7686
8309
|
const message = greetingMessage?.trim();
|
|
7687
8310
|
if (!message) return;
|
|
7688
8311
|
try {
|
|
@@ -7697,15 +8320,15 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7697
8320
|
dispatch({ kind: "STOP" });
|
|
7698
8321
|
}
|
|
7699
8322
|
}, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
7700
|
-
|
|
8323
|
+
useEffect18(() => {
|
|
7701
8324
|
if (greetedRef.current) return;
|
|
7702
8325
|
greetedRef.current = true;
|
|
7703
8326
|
fireGreeting();
|
|
7704
8327
|
}, [fireGreeting]);
|
|
7705
|
-
|
|
8328
|
+
useEffect18(() => {
|
|
7706
8329
|
if (boot.stale && storageKey) clearConversation(storageKey);
|
|
7707
8330
|
}, []);
|
|
7708
|
-
|
|
8331
|
+
useEffect18(() => {
|
|
7709
8332
|
if (!storageKey || state.isStreaming) return;
|
|
7710
8333
|
if (hydratedRef.current) {
|
|
7711
8334
|
hydratedRef.current = false;
|
|
@@ -7722,7 +8345,7 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7722
8345
|
if (persistable.length === 0) return;
|
|
7723
8346
|
writeConversation(storageKey, state.conversationId, persistable, Date.now());
|
|
7724
8347
|
}, [storageKey, state.isStreaming, state.messages, state.conversationId]);
|
|
7725
|
-
|
|
8348
|
+
useEffect18(() => {
|
|
7726
8349
|
if (!storageKey) return;
|
|
7727
8350
|
const onStorage = (e) => {
|
|
7728
8351
|
if (e.key !== storageKey || e.storageArea !== window.localStorage) return;
|
|
@@ -7746,25 +8369,25 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7746
8369
|
window.addEventListener("storage", onStorage);
|
|
7747
8370
|
return () => window.removeEventListener("storage", onStorage);
|
|
7748
8371
|
}, [storageKey, conversation, fireGreeting]);
|
|
7749
|
-
const open =
|
|
7750
|
-
const close =
|
|
8372
|
+
const open = useCallback8(() => dispatch({ kind: "OPEN" }), []);
|
|
8373
|
+
const close = useCallback8(() => {
|
|
7751
8374
|
handleRef.current?.cancel();
|
|
7752
8375
|
handleRef.current = null;
|
|
7753
8376
|
clearFallbackTimer();
|
|
7754
8377
|
dispatch({ kind: "CLOSE" });
|
|
7755
8378
|
}, [clearFallbackTimer]);
|
|
7756
|
-
const stop =
|
|
8379
|
+
const stop = useCallback8(() => {
|
|
7757
8380
|
handleRef.current?.cancel();
|
|
7758
8381
|
handleRef.current = null;
|
|
7759
8382
|
clearFallbackTimer();
|
|
7760
8383
|
dispatch({ kind: "STOP" });
|
|
7761
8384
|
}, [clearFallbackTimer]);
|
|
7762
|
-
const toggle =
|
|
8385
|
+
const toggle = useCallback8(() => {
|
|
7763
8386
|
if (stateRef.current.isOpen) close();
|
|
7764
8387
|
else open();
|
|
7765
8388
|
}, [close, open]);
|
|
7766
|
-
const dismissPopup =
|
|
7767
|
-
const reset =
|
|
8389
|
+
const dismissPopup = useCallback8(() => dispatch({ kind: "DISMISS_POPUP" }), []);
|
|
8390
|
+
const reset = useCallback8(() => {
|
|
7768
8391
|
handleRef.current?.cancel();
|
|
7769
8392
|
handleRef.current = null;
|
|
7770
8393
|
clearFallbackTimer();
|
|
@@ -7775,18 +8398,18 @@ function useChatStream(conversation, starterTexts, greetingMessage, storageKey)
|
|
|
7775
8398
|
greetedRef.current = true;
|
|
7776
8399
|
fireGreeting();
|
|
7777
8400
|
}, [storageKey, conversation, clearFallbackTimer, fireGreeting]);
|
|
7778
|
-
const getLiveDashboard =
|
|
8401
|
+
const getLiveDashboard = useCallback8(() => conversation.getLiveDashboard(), [conversation]);
|
|
7779
8402
|
useLiveDashboardPoll({ messages: state.messages, dispatch, getLiveDashboard });
|
|
7780
8403
|
return { state, open, close, stop, toggle, send, retry, dismissPopup, reset, _dispatch: dispatch };
|
|
7781
8404
|
}
|
|
7782
8405
|
|
|
7783
8406
|
// src/useLiveMonitor.ts
|
|
7784
|
-
import { useCallback as
|
|
8407
|
+
import { useCallback as useCallback9, useEffect as useEffect19, useRef as useRef15, useState as useState38 } from "react";
|
|
7785
8408
|
|
|
7786
8409
|
// src/useTabs.ts
|
|
7787
|
-
import { useState as
|
|
8410
|
+
import { useState as useState37 } from "react";
|
|
7788
8411
|
function useTabs(initial = "chat") {
|
|
7789
|
-
const [activeTab, setActiveTab] =
|
|
8412
|
+
const [activeTab, setActiveTab] = useState37(initial);
|
|
7790
8413
|
return { activeTab, setActiveTab };
|
|
7791
8414
|
}
|
|
7792
8415
|
|
|
@@ -7811,38 +8434,38 @@ function phaseForPin(snapshot, pin) {
|
|
|
7811
8434
|
return snapshot.markets.find((mk) => mk.key === pin.key)?.phase;
|
|
7812
8435
|
}
|
|
7813
8436
|
function useLiveMonitor(opts) {
|
|
7814
|
-
const sessionIdRef =
|
|
7815
|
-
const [pins, setPins] =
|
|
7816
|
-
const [store] =
|
|
7817
|
-
const [enabled, setEnabled] =
|
|
7818
|
-
const [snapshot, setSnapshotState] =
|
|
8437
|
+
const sessionIdRef = useRef15(crypto.randomUUID());
|
|
8438
|
+
const [pins, setPins] = useState38([]);
|
|
8439
|
+
const [store] = useState38(() => createPinStore(opts.storageKey, sessionIdRef.current, setPins));
|
|
8440
|
+
const [enabled, setEnabled] = useState38(true);
|
|
8441
|
+
const [snapshot, setSnapshotState] = useState38(null);
|
|
7819
8442
|
const { activeTab, setActiveTab: setActiveTabState } = useTabs("chat");
|
|
7820
|
-
const [chatDot, setChatDot] =
|
|
7821
|
-
const [matchesDot, setMatchesDot] =
|
|
7822
|
-
const [oddsDot, setOddsDot] =
|
|
7823
|
-
const [todayDot, setTodayDot] =
|
|
7824
|
-
const [lastViewedPrices, setLastViewedPrices] =
|
|
7825
|
-
const [openMarket, setOpenMarket] =
|
|
7826
|
-
const [marketOdds, setMarketOdds] =
|
|
7827
|
-
const pinsRef =
|
|
8443
|
+
const [chatDot, setChatDot] = useState38(false);
|
|
8444
|
+
const [matchesDot, setMatchesDot] = useState38(false);
|
|
8445
|
+
const [oddsDot, setOddsDot] = useState38(false);
|
|
8446
|
+
const [todayDot, setTodayDot] = useState38(false);
|
|
8447
|
+
const [lastViewedPrices, setLastViewedPrices] = useState38({});
|
|
8448
|
+
const [openMarket, setOpenMarket] = useState38({});
|
|
8449
|
+
const [marketOdds, setMarketOdds] = useState38({});
|
|
8450
|
+
const pinsRef = useRef15(pins);
|
|
7828
8451
|
pinsRef.current = pins;
|
|
7829
|
-
const watchesRef =
|
|
8452
|
+
const watchesRef = useRef15(opts.watches ?? []);
|
|
7830
8453
|
watchesRef.current = opts.watches ?? [];
|
|
7831
|
-
const activeTabRef =
|
|
8454
|
+
const activeTabRef = useRef15(activeTab);
|
|
7832
8455
|
activeTabRef.current = activeTab;
|
|
7833
|
-
const snapshotRef =
|
|
8456
|
+
const snapshotRef = useRef15(snapshot);
|
|
7834
8457
|
snapshotRef.current = snapshot;
|
|
7835
|
-
const lastViewedPricesRef =
|
|
8458
|
+
const lastViewedPricesRef = useRef15(lastViewedPrices);
|
|
7836
8459
|
lastViewedPricesRef.current = lastViewedPrices;
|
|
7837
|
-
const openMarketRef =
|
|
8460
|
+
const openMarketRef = useRef15(openMarket);
|
|
7838
8461
|
openMarketRef.current = openMarket;
|
|
7839
|
-
const marketOddsRef =
|
|
8462
|
+
const marketOddsRef = useRef15(marketOdds);
|
|
7840
8463
|
marketOddsRef.current = marketOdds;
|
|
7841
8464
|
const hasToday = opts.hasToday ?? false;
|
|
7842
8465
|
const marketKey = (matchId, dev) => `${matchId}:${dev}`;
|
|
7843
|
-
const getMarketOddsRef =
|
|
8466
|
+
const getMarketOddsRef = useRef15(opts.getMarketOdds);
|
|
7844
8467
|
getMarketOddsRef.current = opts.getMarketOdds;
|
|
7845
|
-
const fetchMarket =
|
|
8468
|
+
const fetchMarket = useCallback9((matchId, dev) => {
|
|
7846
8469
|
const key = marketKey(matchId, dev);
|
|
7847
8470
|
const existing = marketOddsRef.current[key];
|
|
7848
8471
|
if (existing?.loading) return;
|
|
@@ -7861,7 +8484,7 @@ function useLiveMonitor(opts) {
|
|
|
7861
8484
|
setMarketOdds((prev) => ({ ...prev, [key]: entry }));
|
|
7862
8485
|
});
|
|
7863
8486
|
}, []);
|
|
7864
|
-
const toggleMarket =
|
|
8487
|
+
const toggleMarket = useCallback9((matchId, dev) => {
|
|
7865
8488
|
const key = marketKey(matchId, dev);
|
|
7866
8489
|
const wasOpen = openMarketRef.current[matchId] === dev;
|
|
7867
8490
|
const nextValue = wasOpen ? null : dev;
|
|
@@ -7872,10 +8495,10 @@ function useLiveMonitor(opts) {
|
|
|
7872
8495
|
fetchMarket(matchId, dev);
|
|
7873
8496
|
}
|
|
7874
8497
|
}, [fetchMarket]);
|
|
7875
|
-
const retryMarket =
|
|
8498
|
+
const retryMarket = useCallback9((matchId, dev) => {
|
|
7876
8499
|
fetchMarket(matchId, dev);
|
|
7877
8500
|
}, [fetchMarket]);
|
|
7878
|
-
const applySnapshot =
|
|
8501
|
+
const applySnapshot = useCallback9((next) => {
|
|
7879
8502
|
if (next === null) {
|
|
7880
8503
|
setEnabled(false);
|
|
7881
8504
|
return;
|
|
@@ -7938,13 +8561,13 @@ function useLiveMonitor(opts) {
|
|
|
7938
8561
|
snapshotRef.current = next;
|
|
7939
8562
|
setSnapshotState(next);
|
|
7940
8563
|
}, [store]);
|
|
7941
|
-
const inFlightRef =
|
|
7942
|
-
const timerRef =
|
|
7943
|
-
const disabledRef =
|
|
7944
|
-
const mountedRef =
|
|
7945
|
-
const getLiveMonitorRef =
|
|
8564
|
+
const inFlightRef = useRef15(false);
|
|
8565
|
+
const timerRef = useRef15(void 0);
|
|
8566
|
+
const disabledRef = useRef15(false);
|
|
8567
|
+
const mountedRef = useRef15(false);
|
|
8568
|
+
const getLiveMonitorRef = useRef15(opts.getLiveMonitor);
|
|
7946
8569
|
getLiveMonitorRef.current = opts.getLiveMonitor;
|
|
7947
|
-
const tick =
|
|
8570
|
+
const tick = useCallback9(async () => {
|
|
7948
8571
|
const allPins = [...pinsRef.current, ...watchesRef.current];
|
|
7949
8572
|
if (inFlightRef.current || disabledRef.current || allPins.length === 0) return;
|
|
7950
8573
|
inFlightRef.current = true;
|
|
@@ -7968,7 +8591,7 @@ function useLiveMonitor(opts) {
|
|
|
7968
8591
|
scheduleRef.current();
|
|
7969
8592
|
}
|
|
7970
8593
|
}, [applySnapshot, fetchMarket]);
|
|
7971
|
-
const scheduleRef =
|
|
8594
|
+
const scheduleRef = useRef15(() => {
|
|
7972
8595
|
});
|
|
7973
8596
|
scheduleRef.current = () => {
|
|
7974
8597
|
window.clearTimeout(timerRef.current);
|
|
@@ -7978,14 +8601,14 @@ function useLiveMonitor(opts) {
|
|
|
7978
8601
|
const hinted = snapshotRef.current ? snapshotRef.current.nextPollSeconds * 1e3 : fallbackMs;
|
|
7979
8602
|
timerRef.current = window.setTimeout(() => void tick(), Math.max(MIN_POLL_MS, hinted));
|
|
7980
8603
|
};
|
|
7981
|
-
|
|
8604
|
+
useEffect19(() => {
|
|
7982
8605
|
mountedRef.current = true;
|
|
7983
8606
|
return () => {
|
|
7984
8607
|
mountedRef.current = false;
|
|
7985
8608
|
};
|
|
7986
8609
|
}, []);
|
|
7987
|
-
const prevPinsLengthRef =
|
|
7988
|
-
|
|
8610
|
+
const prevPinsLengthRef = useRef15(0);
|
|
8611
|
+
useEffect19(() => {
|
|
7989
8612
|
const wasEmpty = prevPinsLengthRef.current === 0 && watchesRef.current.length === 0;
|
|
7990
8613
|
prevPinsLengthRef.current = pins.length;
|
|
7991
8614
|
if (pins.length === 0 && watchesRef.current.length === 0) {
|
|
@@ -7994,27 +8617,27 @@ function useLiveMonitor(opts) {
|
|
|
7994
8617
|
}
|
|
7995
8618
|
if (wasEmpty) void tick();
|
|
7996
8619
|
}, [pins.length, tick]);
|
|
7997
|
-
const prevWatchesLengthRef =
|
|
8620
|
+
const prevWatchesLengthRef = useRef15(0);
|
|
7998
8621
|
const watchesLength = opts.watches?.length ?? 0;
|
|
7999
|
-
|
|
8622
|
+
useEffect19(() => {
|
|
8000
8623
|
const wasEmpty = prevWatchesLengthRef.current === 0 && pinsRef.current.length === 0;
|
|
8001
8624
|
prevWatchesLengthRef.current = watchesLength;
|
|
8002
8625
|
if (wasEmpty && watchesLength > 0) void tick();
|
|
8003
8626
|
}, [watchesLength, tick]);
|
|
8004
|
-
|
|
8627
|
+
useEffect19(() => {
|
|
8005
8628
|
const matchPins = pins.filter((p) => p.kind === "match").length;
|
|
8006
8629
|
const marketPins = pins.length - matchPins;
|
|
8007
8630
|
if (activeTab === "following" && matchPins === 0) setActiveTabState(hasToday ? "today" : "chat");
|
|
8008
8631
|
if (activeTab === "odds" && marketPins === 0) setActiveTabState(hasToday ? "today" : "chat");
|
|
8009
8632
|
if (activeTab === "today" && !hasToday) setActiveTabState("chat");
|
|
8010
8633
|
}, [pins, activeTab, hasToday]);
|
|
8011
|
-
const prevIsOpenRef =
|
|
8012
|
-
|
|
8634
|
+
const prevIsOpenRef = useRef15(false);
|
|
8635
|
+
useEffect19(() => {
|
|
8013
8636
|
const wasClosed = !prevIsOpenRef.current;
|
|
8014
8637
|
prevIsOpenRef.current = opts.isOpen;
|
|
8015
8638
|
if (wasClosed && opts.isOpen) void tick();
|
|
8016
8639
|
}, [opts.isOpen, tick]);
|
|
8017
|
-
|
|
8640
|
+
useEffect19(() => {
|
|
8018
8641
|
const onVisibility = () => {
|
|
8019
8642
|
if (document.visibilityState === "hidden") window.clearTimeout(timerRef.current);
|
|
8020
8643
|
else void tick();
|
|
@@ -8025,7 +8648,7 @@ function useLiveMonitor(opts) {
|
|
|
8025
8648
|
window.clearTimeout(timerRef.current);
|
|
8026
8649
|
};
|
|
8027
8650
|
}, [tick]);
|
|
8028
|
-
const setActiveTab =
|
|
8651
|
+
const setActiveTab = useCallback9((tab) => {
|
|
8029
8652
|
setActiveTabState(tab);
|
|
8030
8653
|
if (tab === "chat") setChatDot(false);
|
|
8031
8654
|
if (tab === "today") setTodayDot(false);
|
|
@@ -8046,14 +8669,14 @@ function useLiveMonitor(opts) {
|
|
|
8046
8669
|
void tick();
|
|
8047
8670
|
}
|
|
8048
8671
|
}, [tick]);
|
|
8049
|
-
const togglePin =
|
|
8672
|
+
const togglePin = useCallback9((pin) => {
|
|
8050
8673
|
const result = store.toggle(pin);
|
|
8051
8674
|
pinsRef.current = store.pins;
|
|
8052
8675
|
return result;
|
|
8053
8676
|
}, [store]);
|
|
8054
|
-
const isPinned =
|
|
8055
|
-
const markChatActivity =
|
|
8056
|
-
const markTodayActivity =
|
|
8677
|
+
const isPinned = useCallback9((key) => pinsRef.current.some((p) => p.key === key), []);
|
|
8678
|
+
const markChatActivity = useCallback9(() => setChatDot(true), []);
|
|
8679
|
+
const markTodayActivity = useCallback9(() => {
|
|
8057
8680
|
if (activeTabRef.current !== "today") setTodayDot(true);
|
|
8058
8681
|
}, []);
|
|
8059
8682
|
return {
|
|
@@ -8080,7 +8703,7 @@ function useLiveMonitor(opts) {
|
|
|
8080
8703
|
}
|
|
8081
8704
|
|
|
8082
8705
|
// src/useMatchDiscovery.ts
|
|
8083
|
-
import { useCallback as
|
|
8706
|
+
import { useCallback as useCallback10, useEffect as useEffect20, useMemo as useMemo4, useRef as useRef16, useState as useState39 } from "react";
|
|
8084
8707
|
|
|
8085
8708
|
// src/scheduleCache.ts
|
|
8086
8709
|
var PREFIX = "ss-w-schedule:";
|
|
@@ -8168,27 +8791,27 @@ function localDateOf(now) {
|
|
|
8168
8791
|
return `${y}-${m}-${d}`;
|
|
8169
8792
|
}
|
|
8170
8793
|
function useMatchDiscovery(opts) {
|
|
8171
|
-
const [groups, setGroups] =
|
|
8172
|
-
const [states, setStates] =
|
|
8173
|
-
const [failures, setFailures] =
|
|
8174
|
-
const [expanded, setExpanded] =
|
|
8175
|
-
const [touched, setTouched] =
|
|
8176
|
-
const groupsRef =
|
|
8794
|
+
const [groups, setGroups] = useState39([]);
|
|
8795
|
+
const [states, setStates] = useState39({});
|
|
8796
|
+
const [failures, setFailures] = useState39(0);
|
|
8797
|
+
const [expanded, setExpanded] = useState39({});
|
|
8798
|
+
const [touched, setTouched] = useState39({});
|
|
8799
|
+
const groupsRef = useRef16(groups);
|
|
8177
8800
|
groupsRef.current = groups;
|
|
8178
|
-
const statesRef =
|
|
8801
|
+
const statesRef = useRef16(states);
|
|
8179
8802
|
statesRef.current = states;
|
|
8180
|
-
const getStatesRef =
|
|
8803
|
+
const getStatesRef = useRef16(opts.getStates);
|
|
8181
8804
|
getStatesRef.current = opts.getStates;
|
|
8182
8805
|
const pinnedKey = opts.pinnedMatchIds.join(",");
|
|
8183
|
-
const [localDate, setLocalDate] =
|
|
8184
|
-
|
|
8806
|
+
const [localDate, setLocalDate] = useState39(() => localDateOf(/* @__PURE__ */ new Date()));
|
|
8807
|
+
useEffect20(() => {
|
|
8185
8808
|
const id = setInterval(() => {
|
|
8186
8809
|
const next = localDateOf(/* @__PURE__ */ new Date());
|
|
8187
8810
|
setLocalDate((prev) => prev === next ? prev : next);
|
|
8188
8811
|
}, ROLLOVER_CHECK_MS);
|
|
8189
8812
|
return () => clearInterval(id);
|
|
8190
8813
|
}, []);
|
|
8191
|
-
|
|
8814
|
+
useEffect20(() => {
|
|
8192
8815
|
let cancelled = false;
|
|
8193
8816
|
const utcOffsetMinutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
8194
8817
|
const cached = readSchedule(opts.operatorId, localDate, Date.now());
|
|
@@ -8213,7 +8836,7 @@ function useMatchDiscovery(opts) {
|
|
|
8213
8836
|
cancelled = true;
|
|
8214
8837
|
};
|
|
8215
8838
|
}, [opts.operatorId, localDate]);
|
|
8216
|
-
|
|
8839
|
+
useEffect20(() => {
|
|
8217
8840
|
setExpanded((prev) => {
|
|
8218
8841
|
const next = {};
|
|
8219
8842
|
for (const group of groups) {
|
|
@@ -8224,7 +8847,7 @@ function useMatchDiscovery(opts) {
|
|
|
8224
8847
|
return next;
|
|
8225
8848
|
});
|
|
8226
8849
|
}, [groups, pinnedKey, touched]);
|
|
8227
|
-
const tick =
|
|
8850
|
+
const tick = useCallback10(async () => {
|
|
8228
8851
|
const ids = dueMatchIds(groupsRef.current, statesRef.current, Date.now());
|
|
8229
8852
|
if (ids.length === 0) return;
|
|
8230
8853
|
try {
|
|
@@ -8240,7 +8863,7 @@ function useMatchDiscovery(opts) {
|
|
|
8240
8863
|
setFailures((n) => n + 1);
|
|
8241
8864
|
}
|
|
8242
8865
|
}, []);
|
|
8243
|
-
|
|
8866
|
+
useEffect20(() => {
|
|
8244
8867
|
if (!opts.isOpen) return;
|
|
8245
8868
|
void tick();
|
|
8246
8869
|
const id = setInterval(() => {
|
|
@@ -8249,11 +8872,11 @@ function useMatchDiscovery(opts) {
|
|
|
8249
8872
|
return () => clearInterval(id);
|
|
8250
8873
|
}, [opts.isOpen, tick, groups]);
|
|
8251
8874
|
const stale = failures >= STALE_AFTER_FAILURES;
|
|
8252
|
-
const liveCount =
|
|
8875
|
+
const liveCount = useMemo4(
|
|
8253
8876
|
() => stale ? 0 : Object.values(states).filter((s) => s.phase === "live").length,
|
|
8254
8877
|
[states, stale]
|
|
8255
8878
|
);
|
|
8256
|
-
const toggleGroup =
|
|
8879
|
+
const toggleGroup = useCallback10((competitionId) => {
|
|
8257
8880
|
setTouched((prev) => ({ ...prev, [competitionId]: true }));
|
|
8258
8881
|
setExpanded((prev) => ({ ...prev, [competitionId]: !prev[competitionId] }));
|
|
8259
8882
|
}, []);
|
|
@@ -8261,25 +8884,25 @@ function useMatchDiscovery(opts) {
|
|
|
8261
8884
|
}
|
|
8262
8885
|
|
|
8263
8886
|
// src/useGames.ts
|
|
8264
|
-
import { useCallback as
|
|
8887
|
+
import { useCallback as useCallback11, useEffect as useEffect21, useRef as useRef17, useState as useState40 } from "react";
|
|
8265
8888
|
var GAMES_POLL_MS = 6e4;
|
|
8266
8889
|
var DEFAULT_TZ = "Europe/London";
|
|
8267
8890
|
function computeGameDay(timezone) {
|
|
8268
8891
|
return new Intl.DateTimeFormat("en-CA", { timeZone: timezone }).format(/* @__PURE__ */ new Date());
|
|
8269
8892
|
}
|
|
8270
8893
|
function useGames(conversation, { activeTab, operatorTimezone }) {
|
|
8271
|
-
const [enabled, setEnabled] =
|
|
8272
|
-
const [games, setGames] =
|
|
8273
|
-
const [loading, setLoading] =
|
|
8274
|
-
const [refreshCount, setRefreshCount] =
|
|
8275
|
-
const inFlightRef =
|
|
8276
|
-
const hardOffRef =
|
|
8277
|
-
const conversationRef =
|
|
8894
|
+
const [enabled, setEnabled] = useState40(false);
|
|
8895
|
+
const [games, setGames] = useState40([]);
|
|
8896
|
+
const [loading, setLoading] = useState40(false);
|
|
8897
|
+
const [refreshCount, setRefreshCount] = useState40(0);
|
|
8898
|
+
const inFlightRef = useRef17(false);
|
|
8899
|
+
const hardOffRef = useRef17(false);
|
|
8900
|
+
const conversationRef = useRef17(conversation);
|
|
8278
8901
|
conversationRef.current = conversation;
|
|
8279
|
-
const tzRef =
|
|
8902
|
+
const tzRef = useRef17(operatorTimezone ?? DEFAULT_TZ);
|
|
8280
8903
|
tzRef.current = operatorTimezone ?? DEFAULT_TZ;
|
|
8281
8904
|
const ready = conversation != null;
|
|
8282
|
-
|
|
8905
|
+
useEffect21(() => {
|
|
8283
8906
|
if (hardOffRef.current) return;
|
|
8284
8907
|
let active = true;
|
|
8285
8908
|
const doFetch = async () => {
|
|
@@ -8322,22 +8945,22 @@ function useGames(conversation, { activeTab, operatorTimezone }) {
|
|
|
8322
8945
|
if (intervalId !== void 0) window.clearInterval(intervalId);
|
|
8323
8946
|
};
|
|
8324
8947
|
}, [activeTab, refreshCount, ready]);
|
|
8325
|
-
const refresh =
|
|
8948
|
+
const refresh = useCallback11(() => {
|
|
8326
8949
|
setRefreshCount((c) => c + 1);
|
|
8327
8950
|
}, []);
|
|
8328
8951
|
return { enabled, games, loading, refresh };
|
|
8329
8952
|
}
|
|
8330
8953
|
|
|
8331
8954
|
// src/useLeaderboard.ts
|
|
8332
|
-
import { useCallback as
|
|
8955
|
+
import { useCallback as useCallback12, useEffect as useEffect22, useRef as useRef18, useState as useState41 } from "react";
|
|
8333
8956
|
function useLeaderboard(conversation, { activeTab }) {
|
|
8334
|
-
const [data, setData] =
|
|
8335
|
-
const [loading, setLoading] =
|
|
8336
|
-
const [refreshCount, setRefreshCount] =
|
|
8337
|
-
const inFlightRef =
|
|
8338
|
-
const conversationRef =
|
|
8957
|
+
const [data, setData] = useState41(null);
|
|
8958
|
+
const [loading, setLoading] = useState41(false);
|
|
8959
|
+
const [refreshCount, setRefreshCount] = useState41(0);
|
|
8960
|
+
const inFlightRef = useRef18(false);
|
|
8961
|
+
const conversationRef = useRef18(conversation);
|
|
8339
8962
|
conversationRef.current = conversation;
|
|
8340
|
-
|
|
8963
|
+
useEffect22(() => {
|
|
8341
8964
|
if (activeTab !== "leaderboard" && activeTab !== "games") return;
|
|
8342
8965
|
let active = true;
|
|
8343
8966
|
const doFetch = async () => {
|
|
@@ -8360,18 +8983,68 @@ function useLeaderboard(conversation, { activeTab }) {
|
|
|
8360
8983
|
inFlightRef.current = false;
|
|
8361
8984
|
};
|
|
8362
8985
|
}, [activeTab, refreshCount]);
|
|
8363
|
-
const refresh =
|
|
8986
|
+
const refresh = useCallback12(() => {
|
|
8364
8987
|
setRefreshCount((c) => c + 1);
|
|
8365
8988
|
}, []);
|
|
8366
8989
|
return { data, loading, refresh };
|
|
8367
8990
|
}
|
|
8368
8991
|
|
|
8992
|
+
// src/usePresetGrid.ts
|
|
8993
|
+
import { useEffect as useEffect23, useRef as useRef19, useState as useState42 } from "react";
|
|
8994
|
+
var GRID_MAX_AGE_MS = 6e5;
|
|
8995
|
+
function usePresetGrid({ getPricePresets, isOpen, locale, now = Date.now }) {
|
|
8996
|
+
const [grid, setGrid] = useState42(null);
|
|
8997
|
+
const keptRef = useRef19(null);
|
|
8998
|
+
const localeRef = useRef19(locale);
|
|
8999
|
+
const inFlightRef = useRef19(false);
|
|
9000
|
+
const mountedRef = useRef19(true);
|
|
9001
|
+
const getRef = useRef19(getPricePresets);
|
|
9002
|
+
getRef.current = getPricePresets;
|
|
9003
|
+
const nowRef = useRef19(now);
|
|
9004
|
+
nowRef.current = now;
|
|
9005
|
+
useEffect23(() => {
|
|
9006
|
+
mountedRef.current = true;
|
|
9007
|
+
return () => {
|
|
9008
|
+
mountedRef.current = false;
|
|
9009
|
+
};
|
|
9010
|
+
}, []);
|
|
9011
|
+
useEffect23(() => {
|
|
9012
|
+
if (localeRef.current !== locale) {
|
|
9013
|
+
localeRef.current = locale;
|
|
9014
|
+
keptRef.current = null;
|
|
9015
|
+
setGrid(null);
|
|
9016
|
+
}
|
|
9017
|
+
if (!isOpen || inFlightRef.current) return;
|
|
9018
|
+
const kept = keptRef.current;
|
|
9019
|
+
const age = kept ? nowRef.current() - Date.parse(kept.builtAtUtc) : Number.NaN;
|
|
9020
|
+
if (age <= GRID_MAX_AGE_MS) return;
|
|
9021
|
+
inFlightRef.current = true;
|
|
9022
|
+
Promise.resolve().then(() => getRef.current(locale)).then((body) => {
|
|
9023
|
+
if (body === null || isPresetGrid(body) && !hasAnyCell(body)) {
|
|
9024
|
+
keptRef.current = null;
|
|
9025
|
+
if (mountedRef.current) setGrid(null);
|
|
9026
|
+
return;
|
|
9027
|
+
}
|
|
9028
|
+
if (!isPresetGrid(body)) return;
|
|
9029
|
+
keptRef.current = body;
|
|
9030
|
+
if (mountedRef.current) setGrid(body);
|
|
9031
|
+
}).catch(() => {
|
|
9032
|
+
}).finally(() => {
|
|
9033
|
+
inFlightRef.current = false;
|
|
9034
|
+
});
|
|
9035
|
+
}, [isOpen, locale]);
|
|
9036
|
+
return grid;
|
|
9037
|
+
}
|
|
9038
|
+
function hasAnyCell(grid) {
|
|
9039
|
+
return grid.singles.length > 0 || grid.singlesFrom.length > 0 || grid.combos.length > 0;
|
|
9040
|
+
}
|
|
9041
|
+
|
|
8369
9042
|
// src/popupTelemetry.ts
|
|
8370
|
-
import { useCallback as
|
|
9043
|
+
import { useCallback as useCallback13, useEffect as useEffect24, useRef as useRef20 } from "react";
|
|
8371
9044
|
function usePopupTelemetry(log, isOpen, popupText, dismissPopup) {
|
|
8372
|
-
const shownRef =
|
|
8373
|
-
const closedTextRef =
|
|
8374
|
-
|
|
9045
|
+
const shownRef = useRef20(/* @__PURE__ */ new Set());
|
|
9046
|
+
const closedTextRef = useRef20(null);
|
|
9047
|
+
useEffect24(() => {
|
|
8375
9048
|
if (isOpen) {
|
|
8376
9049
|
if (closedTextRef.current) log?.log({ name: "popup_opened" });
|
|
8377
9050
|
closedTextRef.current = null;
|
|
@@ -8383,65 +9056,65 @@ function usePopupTelemetry(log, isOpen, popupText, dismissPopup) {
|
|
|
8383
9056
|
log?.log({ name: "popup_shown" });
|
|
8384
9057
|
}
|
|
8385
9058
|
}, [log, isOpen, popupText]);
|
|
8386
|
-
return
|
|
9059
|
+
return useCallback13(() => {
|
|
8387
9060
|
log?.log({ name: "popup_dismissed" });
|
|
8388
9061
|
dismissPopup();
|
|
8389
9062
|
}, [log, dismissPopup]);
|
|
8390
9063
|
}
|
|
8391
9064
|
|
|
8392
9065
|
// src/components/ChatFab.tsx
|
|
8393
|
-
import { useEffect as
|
|
9066
|
+
import { useEffect as useEffect25, useRef as useRef21, useState as useState43 } from "react";
|
|
8394
9067
|
|
|
8395
9068
|
// src/components/GreetingBubble.tsx
|
|
8396
|
-
import { jsx as
|
|
9069
|
+
import { jsx as jsx91, jsxs as jsxs75 } from "react/jsx-runtime";
|
|
8397
9070
|
function GreetingBubble({ text, onOpen, onDismiss, dismissLabel = "Dismiss", asks }) {
|
|
8398
|
-
const body = /* @__PURE__ */
|
|
8399
|
-
/* @__PURE__ */
|
|
8400
|
-
/* @__PURE__ */
|
|
8401
|
-
/* @__PURE__ */
|
|
8402
|
-
/* @__PURE__ */
|
|
9071
|
+
const body = /* @__PURE__ */ jsxs75("button", { type: "button", className: "ss-w-greeting-body", onClick: onOpen, children: [
|
|
9072
|
+
/* @__PURE__ */ jsxs75("span", { className: "ss-w-greeting-dots", "aria-hidden": "true", children: [
|
|
9073
|
+
/* @__PURE__ */ jsx91("i", {}),
|
|
9074
|
+
/* @__PURE__ */ jsx91("i", {}),
|
|
9075
|
+
/* @__PURE__ */ jsx91("i", {})
|
|
8403
9076
|
] }),
|
|
8404
|
-
/* @__PURE__ */
|
|
9077
|
+
/* @__PURE__ */ jsx91("span", { className: "ss-w-greeting-text", children: text })
|
|
8405
9078
|
] });
|
|
8406
|
-
const dismiss = onDismiss ? /* @__PURE__ */
|
|
9079
|
+
const dismiss = onDismiss ? /* @__PURE__ */ jsx91("button", { type: "button", className: "ss-w-greeting-x", "aria-label": dismissLabel, onClick: onDismiss, children: "\xD7" }) : null;
|
|
8407
9080
|
if (!asks || asks.length === 0) {
|
|
8408
|
-
return /* @__PURE__ */
|
|
9081
|
+
return /* @__PURE__ */ jsxs75("div", { className: "ss-w-greeting", role: "note", children: [
|
|
8409
9082
|
body,
|
|
8410
9083
|
dismiss
|
|
8411
9084
|
] });
|
|
8412
9085
|
}
|
|
8413
|
-
return /* @__PURE__ */
|
|
8414
|
-
/* @__PURE__ */
|
|
9086
|
+
return /* @__PURE__ */ jsxs75("div", { className: "ss-w-greeting ss-w-greeting--asks", role: "note", children: [
|
|
9087
|
+
/* @__PURE__ */ jsxs75("div", { className: "ss-w-greeting-top", children: [
|
|
8415
9088
|
body,
|
|
8416
9089
|
dismiss
|
|
8417
9090
|
] }),
|
|
8418
|
-
/* @__PURE__ */
|
|
9091
|
+
/* @__PURE__ */ jsx91("div", { className: "ss-w-greeting-asks", children: asks.map((ask, i) => /* @__PURE__ */ jsx91("button", { type: "button", className: "ss-w-greeting-ask", onClick: ask.onTap, children: ask.label }, `${i}:${ask.label}`)) })
|
|
8419
9092
|
] });
|
|
8420
9093
|
}
|
|
8421
9094
|
|
|
8422
9095
|
// src/components/ChatFab.tsx
|
|
8423
|
-
import { jsx as
|
|
9096
|
+
import { jsx as jsx92, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
8424
9097
|
function ChatFab({ label, greeting, popupText, logoUrl, onOpen, onDismissPopup, dismissLabel = "Dismiss", introAllowed = false, onIntroStart, asks }) {
|
|
8425
9098
|
const bubble = popupText ?? greeting;
|
|
8426
|
-
const [intro, setIntro] =
|
|
8427
|
-
const armedRef =
|
|
8428
|
-
|
|
9099
|
+
const [intro, setIntro] = useState43(false);
|
|
9100
|
+
const armedRef = useRef21(introAllowed);
|
|
9101
|
+
useEffect25(() => {
|
|
8429
9102
|
if (armedRef.current && bubble) {
|
|
8430
9103
|
armedRef.current = false;
|
|
8431
9104
|
setIntro(true);
|
|
8432
9105
|
onIntroStart?.();
|
|
8433
9106
|
}
|
|
8434
9107
|
}, [bubble, onIntroStart]);
|
|
8435
|
-
return /* @__PURE__ */
|
|
8436
|
-
bubble ? /* @__PURE__ */
|
|
8437
|
-
/* @__PURE__ */
|
|
9108
|
+
return /* @__PURE__ */ jsxs76("div", { className: intro ? "ss-w-fab-wrap ss-w-intro" : "ss-w-fab-wrap", children: [
|
|
9109
|
+
bubble ? /* @__PURE__ */ jsx92(GreetingBubble, { text: bubble, onOpen, onDismiss: popupText ? onDismissPopup : void 0, dismissLabel, asks: popupText ? asks : void 0 }) : null,
|
|
9110
|
+
/* @__PURE__ */ jsx92("button", { type: "button", className: "ss-w-fab", "aria-label": label, onClick: onOpen, children: /* @__PURE__ */ jsx92(BrandMark, { logoUrl, className: "ss-w-fab-mark" }) })
|
|
8438
9111
|
] });
|
|
8439
9112
|
}
|
|
8440
9113
|
|
|
8441
9114
|
// src/components/HostEventsProvider.tsx
|
|
8442
|
-
import { jsx as
|
|
9115
|
+
import { jsx as jsx93 } from "react/jsx-runtime";
|
|
8443
9116
|
function HostEventsProvider({ value, children }) {
|
|
8444
|
-
return /* @__PURE__ */
|
|
9117
|
+
return /* @__PURE__ */ jsx93(SlipStateContext.Provider, { value: value.slipState, children: /* @__PURE__ */ jsx93(MatchLinkContext.Provider, { value: value.matchLink, children }) });
|
|
8445
9118
|
}
|
|
8446
9119
|
|
|
8447
9120
|
// src/styles/css.generated.ts
|
|
@@ -8878,6 +9551,71 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
8878
9551
|
.ss-w-combo-leg-stat { font-size: 12px; line-height: 1.45; color: var(--ss-w-ink); background: var(--ss-w-bubble); border-radius: 8px; padding: 6px 9px; }
|
|
8879
9552
|
.ss-w-combo-math { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 700; line-height: 1.4; color: var(--ss-w-ink); text-align: right; background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; padding: 8px 10px; overflow-wrap: anywhere; }
|
|
8880
9553
|
.ss-w-combo-note { font-size: 11px; line-height: 1.4; color: var(--ss-w-faint); }
|
|
9554
|
+
.ss-w-combo-change { align-self: flex-start; min-height: 36px; padding: 6px 12px; font: inherit; font-size: 12px; font-weight: 650; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-accent); border-radius: 16px; cursor: pointer; }
|
|
9555
|
+
|
|
9556
|
+
/* onboarding presets stage 2: the two tools (spec Stage 2 Behaviour, boards 1c and 2c). A sheet
|
|
9557
|
+
over the message list, inside .ss-w-chat-layer; the body scrolls and the builder's Send sits in
|
|
9558
|
+
the footer, so it stays visible on a phone. Colours come from the theme tokens. */
|
|
9559
|
+
.ss-w-tool-backdrop { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; justify-content: flex-end; background: rgba(0,0,0,.35); }
|
|
9560
|
+
.ss-w-tool { display: flex; flex-direction: column; min-height: 0; max-height: 100%; background: var(--ss-w-panel); color: var(--ss-w-ink); border-top: 1px solid var(--ss-w-line); border-radius: 16px 16px 0 0; box-shadow: 0 -8px 24px rgba(0,0,0,.18); outline: none; }
|
|
9561
|
+
.ss-w-tool-head { flex: none; display: flex; align-items: center; gap: 8px; padding: 12px 14px 8px; }
|
|
9562
|
+
.ss-w-tool-title { flex: 1; font-size: 15px; font-weight: 700; line-height: 1.3; }
|
|
9563
|
+
.ss-w-tool-close { flex: none; width: 36px; height: 36px; display: grid; place-items: center; font-size: 16px; color: var(--ss-w-faint); background: var(--ss-w-bubble); border: none; border-radius: 50%; cursor: pointer; }
|
|
9564
|
+
.ss-w-tool-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 12px; padding: 4px 14px 14px; }
|
|
9565
|
+
.ss-w-tool-body > * { flex: none; }
|
|
9566
|
+
.ss-w-tool-foot { flex: none; padding: 10px 14px 12px; border-top: 1px solid var(--ss-w-line); }
|
|
9567
|
+
.ss-w-tool-row { display: flex; flex-direction: column; gap: 8px; padding: 10px 11px; border: 1px solid var(--ss-w-line); border-left: 3px solid var(--ss-w-accent); border-radius: 12px; }
|
|
9568
|
+
.ss-w-tool-ask { font-size: 14px; font-weight: 650; line-height: 1.7; color: var(--ss-w-ink); overflow-wrap: anywhere; }
|
|
9569
|
+
.ss-w-tool-num { display: inline-block; min-width: 44px; min-height: 32px; margin: 0 2px; padding: 3px 8px; font: inherit; font-variant-numeric: tabular-nums; font-weight: 800; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 10%, var(--ss-w-panel)); border: 1px dashed color-mix(in srgb, var(--ss-w-accent) 55%, var(--ss-w-line)); border-radius: 8px; cursor: pointer; }
|
|
9570
|
+
.ss-w-tool-picks { list-style: none; display: flex; flex-direction: column; gap: 4px; }
|
|
9571
|
+
.ss-w-tool-pick { display: grid; grid-template-columns: 1fr auto; column-gap: 8px; padding: 5px 8px; font-size: 12px; line-height: 1.35; background: var(--ss-w-bubble); border-radius: 8px; }
|
|
9572
|
+
.ss-w-tool-pick-match { grid-column: 1; font-weight: 650; color: var(--ss-w-ink); overflow-wrap: anywhere; }
|
|
9573
|
+
.ss-w-tool-pick-sel { grid-column: 1; color: var(--ss-w-faint); overflow-wrap: anywhere; }
|
|
9574
|
+
.ss-w-tool-pick-kick { grid-column: 1; font-size: 11px; color: var(--ss-w-faint); }
|
|
9575
|
+
.ss-w-tool-pick-price { grid-column: 2; grid-row: 1 / span 3; align-self: center; font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 800; color: var(--ss-w-accent); }
|
|
9576
|
+
.ss-w-tool-math { padding: 6px 8px; font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 700; text-align: right; color: var(--ss-w-ink); background: color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-panel)); border-radius: 8px; overflow-wrap: anywhere; }
|
|
9577
|
+
.ss-w-tool-unavailable { padding: 6px 8px; font-size: 12px; color: var(--ss-w-faint); border: 1px dashed var(--ss-w-line); border-radius: 8px; }
|
|
9578
|
+
.ss-w-tool-send { align-self: flex-end; min-height: 40px; padding: 8px 18px; font: inherit; font-size: 13px; font-weight: 700; color: #fff; background: var(--ss-w-accent); border: none; border-radius: 20px; cursor: pointer; }
|
|
9579
|
+
.ss-w-tool-send:disabled { color: var(--ss-w-faint); background: var(--ss-w-bubble); cursor: not-allowed; }
|
|
9580
|
+
.ss-w-tool-foot .ss-w-tool-send { width: 100%; }
|
|
9581
|
+
.ss-w-tool-section { display: flex; flex-direction: column; gap: 6px; }
|
|
9582
|
+
.ss-w-tool-label { font-size: 11.5px; font-weight: 650; color: var(--ss-w-faint); }
|
|
9583
|
+
.ss-w-tool-chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
9584
|
+
.ss-w-tool-chip { min-width: 52px; min-height: 36px; padding: 6px 10px; font: inherit; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ss-w-ink); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 18px; cursor: pointer; }
|
|
9585
|
+
.ss-w-tool-chip[aria-pressed="true"] { color: #fff; background: var(--ss-w-accent); border-color: var(--ss-w-accent); }
|
|
9586
|
+
.ss-w-tool-stepper { display: inline-flex; align-items: center; gap: 10px; }
|
|
9587
|
+
.ss-w-tool-step { width: 40px; height: 40px; display: grid; place-items: center; font: inherit; font-size: 18px; font-weight: 700; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 50%; cursor: pointer; }
|
|
9588
|
+
.ss-w-tool-step:disabled { opacity: .5; cursor: not-allowed; }
|
|
9589
|
+
.ss-w-tool-count { min-width: 24px; text-align: center; font-size: 16px; font-weight: 800; font-variant-numeric: tabular-nums; }
|
|
9590
|
+
|
|
9591
|
+
/* onboarding presets stage 2: the chat layer and the speed dial (spec Stage 2 Behaviour). The
|
|
9592
|
+
layer is the message list's positioned box (P6), so the dial sits against the list's bottom
|
|
9593
|
+
right and rises with the composer: right 8px puts the 44px button's centre on Send's (12px
|
|
9594
|
+
padding + 18px), bottom 10px is above the composer's top border. While the button shows the list
|
|
9595
|
+
gets 54px more bottom padding so its last message can scroll clear. */
|
|
9596
|
+
.ss-w-chat-layer { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
|
|
9597
|
+
.ss-w-chat-layer[data-dial] .ss-w-list { padding-bottom: 68px; }
|
|
9598
|
+
.ss-w-dial { position: absolute; left: 12px; right: 8px; bottom: 10px; z-index: 2; display: flex; flex-direction: column-reverse; align-items: flex-end; gap: 8px; pointer-events: none; }
|
|
9599
|
+
.ss-w-dial-btn, .ss-w-dial-pill { pointer-events: auto; }
|
|
9600
|
+
.ss-w-dial-btn { position: relative; flex: none; width: 44px; height: 44px; display: grid; place-items: center; padding: 0; font-size: 20px; color: var(--ss-w-accent); background: var(--ss-w-panel); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 40%, var(--ss-w-line)); border-radius: 50%; box-shadow: 0 4px 14px rgba(0,0,0,.18); cursor: pointer; }
|
|
9601
|
+
.ss-w-dial-btn[aria-expanded="true"] { color: var(--ss-w-panel); background: var(--ss-w-accent); border-color: var(--ss-w-accent); }
|
|
9602
|
+
.ss-w-dial-btn:focus-visible, .ss-w-dial-pill:focus-visible { outline: 2px solid var(--ss-w-accent); outline-offset: 2px; }
|
|
9603
|
+
.ss-w-dial-icon { grid-area: 1 / 1; display: grid; place-items: center; transition: transform 200ms ease, opacity 200ms ease; }
|
|
9604
|
+
.ss-w-dial-icon--close { opacity: 0; transform: rotate(-90deg); }
|
|
9605
|
+
.ss-w-dial-btn[aria-expanded="true"] .ss-w-dial-icon--open { opacity: 0; transform: rotate(90deg); }
|
|
9606
|
+
.ss-w-dial-btn[aria-expanded="true"] .ss-w-dial-icon--close { opacity: 1; transform: none; }
|
|
9607
|
+
.ss-w-dial-dot { position: absolute; top: 3px; right: 3px; width: 10px; height: 10px; background: var(--ss-w-accent); border: 2px solid var(--ss-w-panel); border-radius: 50%; }
|
|
9608
|
+
.ss-w-dial-pills { max-width: 100%; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
|
|
9609
|
+
.ss-w-dial-pill { max-width: 100%; min-height: 44px; display: inline-flex; align-items: center; gap: 8px; padding: 6px 16px 6px 12px; font: inherit; font-size: 12.5px; font-weight: 650; line-height: 1.25; text-align: left; white-space: normal; overflow-wrap: anywhere; color: var(--ss-w-ink); background: var(--ss-w-panel); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 35%, var(--ss-w-line)); border-radius: 22px; box-shadow: 0 4px 14px rgba(0,0,0,.16); cursor: pointer; opacity: 0; visibility: hidden; transform: translateY(14px) scale(.5); transform-origin: bottom right; transition: opacity 200ms ease, transform 200ms ease, visibility 0s linear 200ms; }
|
|
9610
|
+
.ss-w-dial-pill svg { flex: none; font-size: 18px; color: var(--ss-w-accent); }
|
|
9611
|
+
.ss-w-dial-pill-label { min-width: 0; }
|
|
9612
|
+
.ss-w-dial-pills[data-open] .ss-w-dial-pill { opacity: 1; visibility: visible; transform: none; transition: opacity 200ms ease, transform 200ms ease, visibility 0s; }
|
|
9613
|
+
@media (prefers-reduced-motion: reduce) {
|
|
9614
|
+
.ss-w-dial-pill { transform: none; transition: opacity 200ms ease, visibility 0s linear 200ms; }
|
|
9615
|
+
.ss-w-dial-pills[data-open] .ss-w-dial-pill { transition: opacity 200ms ease, visibility 0s; }
|
|
9616
|
+
.ss-w-dial-icon { transition: opacity 200ms ease; }
|
|
9617
|
+
.ss-w-dial-icon--close, .ss-w-dial-btn[aria-expanded="true"] .ss-w-dial-icon--open { transform: none; }
|
|
9618
|
+
}
|
|
8881
9619
|
|
|
8882
9620
|
/* Compact price list (D16): three or more cards of one turn, one row per fixture. Team names wrap
|
|
8883
9621
|
to a second line and are never cut; the time sits above the match pin, with no column of its own. */
|
|
@@ -8964,6 +9702,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
8964
9702
|
.ss-w-textarea { font-size: 16px; }
|
|
8965
9703
|
}
|
|
8966
9704
|
.ss-w-send { width: 36px; height: 36px; flex: none; border: none; border-radius: 50%; background: var(--ss-w-accent); color: #fff; cursor: pointer; display: grid; place-items: center; font-size: 16px; }
|
|
9705
|
+
.ss-w-send:disabled { opacity: .45; cursor: not-allowed; }
|
|
8967
9706
|
.ss-w-stop-glyph { width: 11px; height: 11px; background: currentColor; border-radius: 2px; }
|
|
8968
9707
|
|
|
8969
9708
|
/* add to slip */
|
|
@@ -10003,7 +10742,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
10003
10742
|
`;
|
|
10004
10743
|
|
|
10005
10744
|
// src/StatsWidget.tsx
|
|
10006
|
-
import { jsx as
|
|
10745
|
+
import { jsx as jsx94 } from "react/jsx-runtime";
|
|
10007
10746
|
function buildClient(props) {
|
|
10008
10747
|
try {
|
|
10009
10748
|
if ("client" in props && props.client) {
|
|
@@ -10028,24 +10767,24 @@ function injectStyles(root) {
|
|
|
10028
10767
|
function StatsWidget(props) {
|
|
10029
10768
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
10030
10769
|
const cfg = props.config;
|
|
10031
|
-
const built =
|
|
10032
|
-
const logger =
|
|
10770
|
+
const built = useMemo5(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
10771
|
+
const logger = useMemo5(
|
|
10033
10772
|
() => built ? built.client.createEventLogger({
|
|
10034
10773
|
operatorUserId: cfg?.userContext?.operatorUserId,
|
|
10035
10774
|
anonymousUserId: cfg?.userContext?.anonymousUserId
|
|
10036
10775
|
}) : null,
|
|
10037
10776
|
[built?.client]
|
|
10038
10777
|
);
|
|
10039
|
-
const ui =
|
|
10040
|
-
const rootRef =
|
|
10041
|
-
const introDoneRef =
|
|
10042
|
-
const markIntroDone =
|
|
10778
|
+
const ui = useMemo5(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
10779
|
+
const rootRef = useRef22(null);
|
|
10780
|
+
const introDoneRef = useRef22(false);
|
|
10781
|
+
const markIntroDone = useCallback14(() => {
|
|
10043
10782
|
introDoneRef.current = true;
|
|
10044
10783
|
}, []);
|
|
10045
10784
|
const convStorageKey = `ss-w-conv:${cfg?.operatorId ?? ""}:${cfg?.userContext?.operatorUserId ?? "anon"}`;
|
|
10046
10785
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0, convStorageKey);
|
|
10047
|
-
const [hasToday, setHasToday] =
|
|
10048
|
-
const liveCardWatches =
|
|
10786
|
+
const [hasToday, setHasToday] = useState44(false);
|
|
10787
|
+
const liveCardWatches = useMemo5(() => {
|
|
10049
10788
|
const seen = /* @__PURE__ */ new Set();
|
|
10050
10789
|
const out = [];
|
|
10051
10790
|
for (const msg of controller.state.messages) {
|
|
@@ -10067,15 +10806,15 @@ function StatsWidget(props) {
|
|
|
10067
10806
|
hasToday,
|
|
10068
10807
|
watches: liveCardWatches
|
|
10069
10808
|
});
|
|
10070
|
-
const getSchedule =
|
|
10809
|
+
const getSchedule = useCallback14(
|
|
10071
10810
|
(localDate, utcOffsetMinutes) => built ? built.conversation.getSchedule(localDate, utcOffsetMinutes) : Promise.resolve(null),
|
|
10072
10811
|
[built]
|
|
10073
10812
|
);
|
|
10074
|
-
const getStates =
|
|
10813
|
+
const getStates = useCallback14(
|
|
10075
10814
|
(matchIds) => built ? built.conversation.getStates(matchIds) : Promise.resolve(null),
|
|
10076
10815
|
[built]
|
|
10077
10816
|
);
|
|
10078
|
-
const pinnedMatchIds =
|
|
10817
|
+
const pinnedMatchIds = useMemo5(
|
|
10079
10818
|
() => monitor.pins.filter((p) => p.kind === "match").map((p) => p.matchId),
|
|
10080
10819
|
[monitor.pins]
|
|
10081
10820
|
);
|
|
@@ -10087,11 +10826,11 @@ function StatsWidget(props) {
|
|
|
10087
10826
|
pinnedMatchIds
|
|
10088
10827
|
});
|
|
10089
10828
|
const todayHasContent = visibleGroupsOf(discovery.groups, discovery.states).length > 0;
|
|
10090
|
-
|
|
10829
|
+
useEffect26(() => {
|
|
10091
10830
|
setHasToday(todayHasContent);
|
|
10092
10831
|
}, [todayHasContent]);
|
|
10093
|
-
const prevLiveSnapshotRef =
|
|
10094
|
-
|
|
10832
|
+
const prevLiveSnapshotRef = useRef22(monitor.snapshot);
|
|
10833
|
+
useEffect26(() => {
|
|
10095
10834
|
const snap = monitor.snapshot;
|
|
10096
10835
|
if (!snap || snap === prevLiveSnapshotRef.current) return;
|
|
10097
10836
|
prevLiveSnapshotRef.current = snap;
|
|
@@ -10127,9 +10866,14 @@ function StatsWidget(props) {
|
|
|
10127
10866
|
}, [monitor.snapshot]);
|
|
10128
10867
|
const gamesResult = useGames(built?.conversation ?? null, { activeTab: monitor.activeTab });
|
|
10129
10868
|
const leaderboardResult = useLeaderboard(built?.conversation ?? null, { activeTab: monitor.activeTab });
|
|
10869
|
+
const getPricePresets = useCallback14(
|
|
10870
|
+
(locale2) => built ? built.conversation.getPricePresets(locale2) : Promise.resolve(null),
|
|
10871
|
+
[built]
|
|
10872
|
+
);
|
|
10873
|
+
const presetGrid = usePresetGrid({ getPricePresets, isOpen: controller.state.isOpen, locale: ui.presets.lang });
|
|
10130
10874
|
const markTodayActivity = monitor.markTodayActivity;
|
|
10131
|
-
const prevLiveCountRef =
|
|
10132
|
-
|
|
10875
|
+
const prevLiveCountRef = useRef22(0);
|
|
10876
|
+
useEffect26(() => {
|
|
10133
10877
|
const rose = prevLiveCountRef.current === 0 && discovery.liveCount > 0;
|
|
10134
10878
|
prevLiveCountRef.current = discovery.liveCount;
|
|
10135
10879
|
if (rose) markTodayActivity();
|
|
@@ -10145,7 +10889,7 @@ function StatsWidget(props) {
|
|
|
10145
10889
|
openMatchLabel: ui.openMatch
|
|
10146
10890
|
});
|
|
10147
10891
|
const markAdded = hostEvents.markAdded;
|
|
10148
|
-
const slip =
|
|
10892
|
+
const slip = useMemo5(
|
|
10149
10893
|
() => {
|
|
10150
10894
|
const handler = props.config?.onAddToSlip;
|
|
10151
10895
|
return {
|
|
@@ -10164,7 +10908,7 @@ function StatsWidget(props) {
|
|
|
10164
10908
|
},
|
|
10165
10909
|
[props.config?.onAddToSlip, controller.state.conversationId, markAdded]
|
|
10166
10910
|
);
|
|
10167
|
-
const onDashboardTap =
|
|
10911
|
+
const onDashboardTap = useMemo5(
|
|
10168
10912
|
() => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input), logger) : void 0,
|
|
10169
10913
|
[built, logger]
|
|
10170
10914
|
);
|
|
@@ -10182,11 +10926,11 @@ function StatsWidget(props) {
|
|
|
10182
10926
|
const operatorUserId = cfg?.userContext?.operatorUserId;
|
|
10183
10927
|
const anonymousUserId = cfg?.userContext?.anonymousUserId;
|
|
10184
10928
|
const conversationId = controller.state.conversationId ?? void 0;
|
|
10185
|
-
|
|
10929
|
+
useEffect26(() => {
|
|
10186
10930
|
if (!logger) return;
|
|
10187
10931
|
logger.setIdentity({ operatorUserId, anonymousUserId, conversationId });
|
|
10188
10932
|
}, [logger, operatorUserId, anonymousUserId, conversationId]);
|
|
10189
|
-
|
|
10933
|
+
useEffect26(() => {
|
|
10190
10934
|
if (!logger) return;
|
|
10191
10935
|
logger.resume();
|
|
10192
10936
|
const onHide = () => {
|
|
@@ -10204,14 +10948,14 @@ function StatsWidget(props) {
|
|
|
10204
10948
|
logger.dispose();
|
|
10205
10949
|
};
|
|
10206
10950
|
}, [logger]);
|
|
10207
|
-
|
|
10951
|
+
useEffect26(() => {
|
|
10208
10952
|
if (!built || !ui.injectStyles) return;
|
|
10209
10953
|
const node = rootRef.current?.getRootNode();
|
|
10210
10954
|
if (node) injectStyles(node);
|
|
10211
10955
|
}, [built, ui.injectStyles]);
|
|
10212
10956
|
if (!built) return null;
|
|
10213
10957
|
const attrs = themeAttrs(ui);
|
|
10214
|
-
return /* @__PURE__ */
|
|
10958
|
+
return /* @__PURE__ */ jsx94(EventLogContext.Provider, { value: logger, children: /* @__PURE__ */ jsx94(HostEventsProvider, { value: hostEvents, children: /* @__PURE__ */ jsx94("div", { ref: rootRef, className: "ss-w-root", "data-ss-w-theme": attrs["data-ss-w-theme"], "data-ss-w-pos": attrs["data-ss-w-pos"], style: attrs.style, children: controller.state.isOpen ? /* @__PURE__ */ jsx94(
|
|
10215
10959
|
ChatPanel,
|
|
10216
10960
|
{
|
|
10217
10961
|
controller,
|
|
@@ -10223,9 +10967,10 @@ function StatsWidget(props) {
|
|
|
10223
10967
|
gamesResult,
|
|
10224
10968
|
leaderboardResult,
|
|
10225
10969
|
loggedIn: !!operatorUserId,
|
|
10226
|
-
conversation: built?.conversation ?? null
|
|
10970
|
+
conversation: built?.conversation ?? null,
|
|
10971
|
+
presetGrid
|
|
10227
10972
|
}
|
|
10228
|
-
) : /* @__PURE__ */
|
|
10973
|
+
) : /* @__PURE__ */ jsx94(
|
|
10229
10974
|
ChatFab,
|
|
10230
10975
|
{
|
|
10231
10976
|
label: ui.launcherLabel,
|