@sensiblestats/widget-react 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/index.cjs +238 -92
- 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 +225 -79
- package/dist/index.js.map +1 -1
- package/dist/styles.css +35 -17
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @sensiblestats/widget-react
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8af5152: Render the new market_odds card: hero main-line rows, collapsible ladder with per-row add-to-slip, bookmaker/updated footer. Older servers simply never emit the event; older widgets ignore it.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [8af5152]
|
|
12
|
+
- @sensiblestats/widget-sdk@0.7.0
|
|
13
|
+
|
|
14
|
+
## 0.7.2
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Redesign the betting insight card for clarity. The market/selection is now the visual hero, the odds token is unmistakable (legible `ODDS` label + larger value, boxed and tinted). Stats and scope chips are collapsed by default behind a `Show stats` toggle — the reason-to-bet prose carries the justification, and the numbers are one tap away. When expanded, all stat rows show at once (the old three-row `Show N more` cap is removed) and the `This League / All comps / H2H` scopes render as a segmented control. Add to slip stays visible whether stats are open or closed. Adds `showStats` / `hideStats` UI strings (en + tr) to `UiConfig`.
|
|
19
|
+
|
|
3
20
|
## 0.7.1
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
37
|
|
|
38
38
|
// src/StatsWidget.tsx
|
|
39
|
-
var
|
|
39
|
+
var import_react10 = require("react");
|
|
40
40
|
var import_widget_sdk4 = require("@sensiblestats/widget-sdk");
|
|
41
41
|
|
|
42
42
|
// src/i18n.ts
|
|
@@ -53,9 +53,15 @@ var STRINGS = {
|
|
|
53
53
|
retry: "Retry",
|
|
54
54
|
showLess: "Show less",
|
|
55
55
|
showMore: (n) => `Show ${n} more`,
|
|
56
|
+
showStats: "Show stats",
|
|
57
|
+
hideStats: "Hide stats",
|
|
56
58
|
oddsLabel: "Odds",
|
|
57
59
|
liveLabel: "Live",
|
|
58
60
|
addToSlip: "Add to slip",
|
|
61
|
+
marketPrices: "Market prices",
|
|
62
|
+
moreLines: "More lines",
|
|
63
|
+
hideLines: "Hide lines",
|
|
64
|
+
updatedLabel: "updated",
|
|
59
65
|
inSlip: "In slip",
|
|
60
66
|
slipAdded: (n) => n === void 0 ? "Added to slip" : `Added to slip (${n} selection${n === 1 ? "" : "s"})`,
|
|
61
67
|
slipDuplicate: "Already in your slip",
|
|
@@ -77,9 +83,15 @@ var STRINGS = {
|
|
|
77
83
|
retry: "Tekrar dene",
|
|
78
84
|
showLess: "Daha az g\xF6ster",
|
|
79
85
|
showMore: (n) => `${n} tane daha g\xF6ster`,
|
|
86
|
+
showStats: "\u0130statistikleri g\xF6ster",
|
|
87
|
+
hideStats: "\u0130statistikleri gizle",
|
|
80
88
|
oddsLabel: "Oran",
|
|
81
89
|
liveLabel: "Canl\u0131",
|
|
82
90
|
addToSlip: "Kupona ekle",
|
|
91
|
+
marketPrices: "Piyasa fiyatlar\u0131",
|
|
92
|
+
moreLines: "Di\u011Fer \xE7izgiler",
|
|
93
|
+
hideLines: "\xC7izgileri gizle",
|
|
94
|
+
updatedLabel: "g\xFCncellendi",
|
|
83
95
|
inSlip: "Kuponda",
|
|
84
96
|
slipAdded: (n) => n === void 0 ? "Kupona eklendi" : `Kupona eklendi (${n} se\xE7im)`,
|
|
85
97
|
slipDuplicate: "Bu se\xE7im kuponunuzda zaten var",
|
|
@@ -118,8 +130,14 @@ function normalizeUi(cfg) {
|
|
|
118
130
|
retry: strings.retry,
|
|
119
131
|
showLess: strings.showLess,
|
|
120
132
|
showMore: strings.showMore,
|
|
133
|
+
showStats: strings.showStats,
|
|
134
|
+
hideStats: strings.hideStats,
|
|
121
135
|
oddsLabel: strings.oddsLabel,
|
|
122
136
|
liveLabel: strings.liveLabel,
|
|
137
|
+
marketPrices: strings.marketPrices,
|
|
138
|
+
moreLines: strings.moreLines,
|
|
139
|
+
hideLines: strings.hideLines,
|
|
140
|
+
updatedLabel: strings.updatedLabel,
|
|
123
141
|
addToSlip: strings.addToSlip,
|
|
124
142
|
inSlip: strings.inSlip,
|
|
125
143
|
slipAdded: strings.slipAdded,
|
|
@@ -249,6 +267,47 @@ function toSlipSelection(vm, conversationId) {
|
|
|
249
267
|
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
250
268
|
return selection;
|
|
251
269
|
}
|
|
270
|
+
function toMarketOddsVM(card) {
|
|
271
|
+
const rows = Array.isArray(card.rows) ? card.rows : [];
|
|
272
|
+
const toRow = (r, i) => {
|
|
273
|
+
const selection = [str(r.selectionLabel), str(r.line)].filter(Boolean).join(" ");
|
|
274
|
+
const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
|
|
275
|
+
return {
|
|
276
|
+
key: `${selection}:${str(r.line) ?? ""}:${i}`,
|
|
277
|
+
selection,
|
|
278
|
+
odds: price !== void 0 ? price.toFixed(2) : "",
|
|
279
|
+
oddsDecimal: price,
|
|
280
|
+
matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
|
|
281
|
+
quotedAtUtc: str(r.quotedAtUtc),
|
|
282
|
+
isMain: r.isMainLine !== false
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
const vms = rows.map(toRow).filter((r) => r.selection && r.odds);
|
|
286
|
+
const home = str(card.homeTeamName);
|
|
287
|
+
const away = str(card.awayTeamName);
|
|
288
|
+
const updated = rows.map((r) => str(r.quotedAtUtc)).filter((v) => !!v).sort();
|
|
289
|
+
return {
|
|
290
|
+
id: `${typeof card.matchId === "number" ? card.matchId : 0}:${str(card.marketDeveloperName) ?? ""}`,
|
|
291
|
+
market: str(card.marketLabel) ?? str(card.marketDeveloperName) ?? "",
|
|
292
|
+
fixture: home && away ? `${home} vs ${away}` : void 0,
|
|
293
|
+
competition: str(card.competitionName),
|
|
294
|
+
bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
|
|
295
|
+
updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
|
|
296
|
+
isLive: rows.some((r) => r.isLive === true),
|
|
297
|
+
matchId: typeof card.matchId === "number" ? card.matchId : 0,
|
|
298
|
+
mainRows: vms.filter((r) => r.isMain),
|
|
299
|
+
moreRows: vms.filter((r) => !r.isMain),
|
|
300
|
+
disclaimer: str(card.disclaimer),
|
|
301
|
+
addToSlipEnabled: card.addToSlipEnabled === true
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function marketOddsRowToSlipSelection(vm, row, conversationId) {
|
|
305
|
+
if (row.matchOddsId === void 0 || row.oddsDecimal === void 0) return null;
|
|
306
|
+
const selection = { matchOddsId: row.matchOddsId, matchId: vm.matchId, oddsDecimal: row.oddsDecimal };
|
|
307
|
+
if (row.quotedAtUtc !== void 0) selection.quotedAtUtc = row.quotedAtUtc;
|
|
308
|
+
if (conversationId !== void 0) selection.conversationId = conversationId;
|
|
309
|
+
return selection;
|
|
310
|
+
}
|
|
252
311
|
|
|
253
312
|
// src/reducer.ts
|
|
254
313
|
var POPUP_MAX = 160;
|
|
@@ -280,6 +339,8 @@ function applyEvent(state, event) {
|
|
|
280
339
|
return { ...state, actionsLoading: false, messages: mapActive(state, (t) => ({ ...t, actions: [...t.actions, toActionVM(event.data.action)] })) };
|
|
281
340
|
case "betting_insight":
|
|
282
341
|
return { ...state, messages: mapActive(state, (t) => ({ ...t, insights: [...t.insights, toInsightVM(event.data.insight)] })) };
|
|
342
|
+
case "market_odds":
|
|
343
|
+
return { ...state, messages: mapActive(state, (t) => ({ ...t, marketOdds: [...t.marketOdds, toMarketOddsVM(event.data.card)] })) };
|
|
283
344
|
case "intent_chip": {
|
|
284
345
|
const chip = toChipVM(event.data.intent);
|
|
285
346
|
return chip ? { ...state, starters: [...state.starters, chip] } : state;
|
|
@@ -315,11 +376,11 @@ function reducer(state, action) {
|
|
|
315
376
|
return { ...state, isOpen: false, isStreaming: false, status: null, actionsLoading: false };
|
|
316
377
|
case "USER_SENT": {
|
|
317
378
|
const user = { role: "user", id: action.userId, text: action.displayText ?? action.input.message };
|
|
318
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false };
|
|
379
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], marketOdds: [], done: false };
|
|
319
380
|
return { ...state, messages: [...state.messages, user, assistant], isStreaming: true, status: null, actionsLoading: false, starters: [], error: null, lastUserInput: action.input, lastDisplayText: action.displayText ?? null };
|
|
320
381
|
}
|
|
321
382
|
case "GREETING_SENT": {
|
|
322
|
-
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], done: false, isGreeting: true };
|
|
383
|
+
const assistant = { role: "assistant", id: action.assistantId, text: "", cards: [], actions: [], insights: [], marketOdds: [], done: false, isGreeting: true };
|
|
323
384
|
return { ...state, messages: [...state.messages, assistant], isStreaming: true, status: null, error: null };
|
|
324
385
|
}
|
|
325
386
|
case "DISMISS_POPUP":
|
|
@@ -441,7 +502,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
|
|
|
441
502
|
}
|
|
442
503
|
|
|
443
504
|
// src/components/ChatPanel.tsx
|
|
444
|
-
var
|
|
505
|
+
var import_react9 = require("react");
|
|
445
506
|
|
|
446
507
|
// src/components/ChatHeader.tsx
|
|
447
508
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -454,7 +515,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
|
|
|
454
515
|
}
|
|
455
516
|
|
|
456
517
|
// src/components/MessageList.tsx
|
|
457
|
-
var
|
|
518
|
+
var import_react7 = require("react");
|
|
458
519
|
|
|
459
520
|
// src/components/Markdown.tsx
|
|
460
521
|
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
@@ -564,13 +625,12 @@ function withTimeout(value) {
|
|
|
564
625
|
new Promise((_, reject) => setTimeout(() => reject(new Error("add-to-slip timed out")), ADD_TO_SLIP_TIMEOUT_MS))
|
|
565
626
|
]);
|
|
566
627
|
}
|
|
567
|
-
function
|
|
628
|
+
function SlipButton({ selection, shownOdds, marketName, slip, ui }) {
|
|
568
629
|
const [pending, setPending] = (0, import_react4.useState)(false);
|
|
569
630
|
const [settled, setSettled] = (0, import_react4.useState)(false);
|
|
570
631
|
const [toast, setToast] = (0, import_react4.useState)(null);
|
|
571
632
|
const dismiss = (0, import_react4.useCallback)(() => setToast(null), []);
|
|
572
633
|
const handler = slip.onAddToSlip;
|
|
573
|
-
const selection = it.addToSlipEnabled ? toSlipSelection(it, slip.conversationId) : null;
|
|
574
634
|
if (!ui || !handler || !selection) return null;
|
|
575
635
|
const onClick = async () => {
|
|
576
636
|
setPending(true);
|
|
@@ -578,11 +638,11 @@ function AddToSlipButton({ it, slip, ui }) {
|
|
|
578
638
|
const raw = await withTimeout(Promise.resolve(handler(selection)));
|
|
579
639
|
if (raw != null && !(0, import_widget_sdk3.isAddToSlipResult)(raw)) throw new Error("malformed add-to-slip result");
|
|
580
640
|
const result = raw ?? void 0;
|
|
581
|
-
setToast(resultToToast(result,
|
|
641
|
+
setToast(resultToToast(result, shownOdds || selection.oddsDecimal.toFixed(2), ui));
|
|
582
642
|
setSettled(isTerminal(result));
|
|
583
643
|
if (wasAdded(result) && slip.onMarketClicked) {
|
|
584
644
|
try {
|
|
585
|
-
slip.onMarketClicked(
|
|
645
|
+
slip.onMarketClicked(marketName);
|
|
586
646
|
} catch {
|
|
587
647
|
}
|
|
588
648
|
}
|
|
@@ -606,29 +666,47 @@ function AddToSlipButton({ it, slip, ui }) {
|
|
|
606
666
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Toast, { toast, onDismiss: dismiss })
|
|
607
667
|
] });
|
|
608
668
|
}
|
|
669
|
+
function AddToSlipButton({ it, slip, ui }) {
|
|
670
|
+
const selection = it.addToSlipEnabled ? toSlipSelection(it, slip.conversationId) : null;
|
|
671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SlipButton, { selection, shownOdds: it.odds ?? "", marketName: it.market, slip, ui });
|
|
672
|
+
}
|
|
609
673
|
|
|
610
674
|
// src/components/BettingInsightList.tsx
|
|
611
675
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ss-w-bi-rows", children: [
|
|
618
|
-
shown.map((s) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ss-w-bi-row", children: [
|
|
619
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ss-w-bi-row-lbl", children: s.label }),
|
|
620
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ss-w-bi-row-dots", "aria-hidden": "true" }),
|
|
621
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ss-w-bi-row-num", children: s.value })
|
|
622
|
-
] }, `${s.label}:${s.value}`)),
|
|
623
|
-
overflow > 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "ss-w-bi-more", onClick: () => setExpanded((v) => !v), children: expanded ? ui?.showLess ?? "Show less" : (ui?.showMore ?? ((n) => `Show ${n} more`))(overflow) }) : null
|
|
624
|
-
] });
|
|
676
|
+
function StatRows({ stats }) {
|
|
677
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ss-w-bi-rows", children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ss-w-bi-row", children: [
|
|
678
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ss-w-bi-row-lbl", children: s.label }),
|
|
679
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ss-w-bi-row-num", children: s.value })
|
|
680
|
+
] }, `${s.label}:${s.value}`)) });
|
|
625
681
|
}
|
|
626
|
-
function ScopedStats({ scopes
|
|
682
|
+
function ScopedStats({ scopes }) {
|
|
627
683
|
const [active, setActive] = (0, import_react5.useState)(0);
|
|
628
684
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
629
685
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ss-w-bi-scoped", children: [
|
|
630
686
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
|
|
631
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StatRows, { stats: current.stats
|
|
687
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StatRows, { stats: current.stats }, current.key)
|
|
688
|
+
] });
|
|
689
|
+
}
|
|
690
|
+
function StatsDisclosure({ it, ui }) {
|
|
691
|
+
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
692
|
+
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
693
|
+
const hasStats = hasScopes || it.stats.length > 0;
|
|
694
|
+
if (!hasStats) return null;
|
|
695
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "ss-w-bi-stats", children: [
|
|
696
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
697
|
+
"button",
|
|
698
|
+
{
|
|
699
|
+
type: "button",
|
|
700
|
+
className: "ss-w-bi-toggle",
|
|
701
|
+
"aria-expanded": open,
|
|
702
|
+
onClick: () => setOpen((v) => !v),
|
|
703
|
+
children: [
|
|
704
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: open ? ui?.hideStats ?? "Hide stats" : ui?.showStats ?? "Show stats" }),
|
|
705
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: `ss-w-bi-chev${open ? " ss-w-bi-chev-up" : ""}`, "aria-hidden": "true" })
|
|
706
|
+
]
|
|
707
|
+
}
|
|
708
|
+
),
|
|
709
|
+
open ? hasScopes ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ScopedStats, { scopes: it.scopes }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StatRows, { stats: it.stats }) : null
|
|
632
710
|
] });
|
|
633
711
|
}
|
|
634
712
|
function InsightCard({ it, ui, slip }) {
|
|
@@ -654,7 +732,7 @@ function InsightCard({ it, ui, slip }) {
|
|
|
654
732
|
] }) : null
|
|
655
733
|
] }),
|
|
656
734
|
it.text ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "ss-w-bi-text", children: it.text }) : null,
|
|
657
|
-
|
|
735
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StatsDisclosure, { it, ui }),
|
|
658
736
|
it.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null,
|
|
659
737
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AddToSlipButton, { it, slip, ui })
|
|
660
738
|
] });
|
|
@@ -664,38 +742,88 @@ function BettingInsightList({ insights, ui, slip }) {
|
|
|
664
742
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(InsightCard, { it, ui, slip }, it.id)) });
|
|
665
743
|
}
|
|
666
744
|
|
|
667
|
-
// src/components/
|
|
745
|
+
// src/components/MarketOddsCardList.tsx
|
|
746
|
+
var import_react6 = require("react");
|
|
668
747
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
748
|
+
function OddsRow({ vm, row, ui, slip }) {
|
|
749
|
+
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
750
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-mo-row", children: [
|
|
751
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-mo-sel", children: row.selection }),
|
|
752
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-mo-price", children: row.odds }),
|
|
753
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
754
|
+
] });
|
|
755
|
+
}
|
|
756
|
+
function formatUpdated(iso) {
|
|
757
|
+
if (!iso) return void 0;
|
|
758
|
+
const date = new Date(iso);
|
|
759
|
+
if (Number.isNaN(date.getTime())) return void 0;
|
|
760
|
+
return date.toLocaleTimeString(void 0, { hour: "2-digit", minute: "2-digit" });
|
|
761
|
+
}
|
|
762
|
+
function MarketOddsCard({ vm, ui, slip }) {
|
|
763
|
+
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
764
|
+
const updated = formatUpdated(vm.updatedAt);
|
|
765
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-mocard", children: [
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-mo-head", children: [
|
|
767
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-mo-market", children: vm.market }),
|
|
768
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-mo-tag", children: ui?.marketPrices ?? "Market prices" })
|
|
769
|
+
] }),
|
|
770
|
+
vm.fixture || vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-mo-fixture", children: [
|
|
771
|
+
vm.fixture ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: vm.fixture }) : null,
|
|
772
|
+
vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-mo-comp", children: vm.competition }) : null
|
|
773
|
+
] }) : null,
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-mo-rows", children: [
|
|
775
|
+
vm.mainRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(OddsRow, { vm, row, ui, slip }, row.key)),
|
|
776
|
+
open ? vm.moreRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(OddsRow, { vm, row, ui, slip }, row.key)) : null
|
|
777
|
+
] }),
|
|
778
|
+
vm.moreRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "button", className: "ss-w-bi-toggle", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
|
|
780
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: `ss-w-bi-chev${open ? " ss-w-bi-chev-up" : ""}`, "aria-hidden": "true" })
|
|
781
|
+
] }) : null,
|
|
782
|
+
vm.bookmaker || updated ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-mo-foot", children: [
|
|
783
|
+
vm.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: vm.bookmaker }) : null,
|
|
784
|
+
updated ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: `${ui?.updatedLabel ?? "updated"} ${updated}` }) : null
|
|
785
|
+
] }) : null,
|
|
786
|
+
vm.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
|
|
787
|
+
] });
|
|
788
|
+
}
|
|
789
|
+
function MarketOddsCardList({ cards, ui, slip }) {
|
|
790
|
+
if (!cards || cards.length === 0) return null;
|
|
791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MarketOddsCard, { vm, ui, slip }, vm.id)) });
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// src/components/ActionButtons.tsx
|
|
795
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
669
796
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
670
797
|
if (actions.length === 0 && !loading) return null;
|
|
671
|
-
return /* @__PURE__ */ (0,
|
|
672
|
-
actions.map((a, i) => /* @__PURE__ */ (0,
|
|
673
|
-
actions.length === 0 && loading ? /* @__PURE__ */ (0,
|
|
674
|
-
/* @__PURE__ */ (0,
|
|
675
|
-
/* @__PURE__ */ (0,
|
|
798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-actions", children: [
|
|
799
|
+
actions.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ss-w-abtn", disabled, onClick: () => onAct(a), children: a.label }, `${a.label}-${i}`)),
|
|
800
|
+
actions.length === 0 && loading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-abtn-shimmer" }),
|
|
802
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-abtn-shimmer" })
|
|
676
803
|
] }) : null
|
|
677
804
|
] });
|
|
678
805
|
}
|
|
679
806
|
|
|
680
807
|
// src/components/ChatMessage.tsx
|
|
681
|
-
var
|
|
808
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
682
809
|
function ChatMessage({ message, disabled, onAct, ui, slip }) {
|
|
683
810
|
if (message.role === "user") {
|
|
684
|
-
return /* @__PURE__ */ (0,
|
|
811
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
|
|
685
812
|
}
|
|
686
|
-
return /* @__PURE__ */ (0,
|
|
687
|
-
message.text ? /* @__PURE__ */ (0,
|
|
688
|
-
/* @__PURE__ */ (0,
|
|
689
|
-
/* @__PURE__ */ (0,
|
|
690
|
-
/* @__PURE__ */ (0,
|
|
813
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
814
|
+
message.text ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Markdown, { text: message.text }) : null,
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
816
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
691
819
|
] });
|
|
692
820
|
}
|
|
693
821
|
|
|
694
822
|
// src/components/IntentChips.tsx
|
|
695
|
-
var
|
|
823
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
696
824
|
function IntentChips({ chips, onPick }) {
|
|
697
825
|
if (chips.length === 0) return null;
|
|
698
|
-
return /* @__PURE__ */ (0,
|
|
826
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
699
827
|
}
|
|
700
828
|
|
|
701
829
|
// src/scroll.ts
|
|
@@ -705,17 +833,17 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
705
833
|
}
|
|
706
834
|
|
|
707
835
|
// src/components/MessageList.tsx
|
|
708
|
-
var
|
|
836
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
709
837
|
function MessageList({ controller, ui, slip }) {
|
|
710
838
|
const { state, send } = controller;
|
|
711
|
-
const listRef = (0,
|
|
712
|
-
const endRef = (0,
|
|
713
|
-
const pinnedRef = (0,
|
|
714
|
-
(0,
|
|
839
|
+
const listRef = (0, import_react7.useRef)(null);
|
|
840
|
+
const endRef = (0, import_react7.useRef)(null);
|
|
841
|
+
const pinnedRef = (0, import_react7.useRef)(true);
|
|
842
|
+
(0, import_react7.useEffect)(() => {
|
|
715
843
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
716
844
|
}, [state.messages, state.status]);
|
|
717
845
|
const empty = state.messages.length === 0;
|
|
718
|
-
return /* @__PURE__ */ (0,
|
|
846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
719
847
|
"div",
|
|
720
848
|
{
|
|
721
849
|
className: "ss-w-list",
|
|
@@ -725,7 +853,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
725
853
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
726
854
|
},
|
|
727
855
|
children: [
|
|
728
|
-
state.messages.map((m) => /* @__PURE__ */ (0,
|
|
856
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
729
857
|
ChatMessage,
|
|
730
858
|
{
|
|
731
859
|
message: m,
|
|
@@ -736,25 +864,25 @@ function MessageList({ controller, ui, slip }) {
|
|
|
736
864
|
},
|
|
737
865
|
m.id
|
|
738
866
|
)),
|
|
739
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0,
|
|
867
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
740
868
|
} }) : null,
|
|
741
|
-
state.status ? /* @__PURE__ */ (0,
|
|
742
|
-
state.error ? /* @__PURE__ */ (0,
|
|
743
|
-
/* @__PURE__ */ (0,
|
|
744
|
-
/* @__PURE__ */ (0,
|
|
869
|
+
state.status ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
|
|
870
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
|
|
871
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
872
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
745
873
|
] }) : null,
|
|
746
|
-
empty ? /* @__PURE__ */ (0,
|
|
747
|
-
/* @__PURE__ */ (0,
|
|
874
|
+
empty ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
875
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref: endRef })
|
|
748
876
|
]
|
|
749
877
|
}
|
|
750
878
|
);
|
|
751
879
|
}
|
|
752
880
|
|
|
753
881
|
// src/components/ChatInput.tsx
|
|
754
|
-
var
|
|
755
|
-
var
|
|
882
|
+
var import_react8 = require("react");
|
|
883
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
756
884
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
757
|
-
const [value, setValue] = (0,
|
|
885
|
+
const [value, setValue] = (0, import_react8.useState)("");
|
|
758
886
|
const submit = () => {
|
|
759
887
|
const t = value.trim();
|
|
760
888
|
if (!t) return;
|
|
@@ -767,18 +895,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
767
895
|
submit();
|
|
768
896
|
}
|
|
769
897
|
};
|
|
770
|
-
return /* @__PURE__ */ (0,
|
|
771
|
-
/* @__PURE__ */ (0,
|
|
772
|
-
streaming ? /* @__PURE__ */ (0,
|
|
898
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "ss-w-input", children: [
|
|
899
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
900
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SendIcon, {}) })
|
|
773
901
|
] });
|
|
774
902
|
}
|
|
775
903
|
|
|
776
904
|
// src/components/ChatPanel.tsx
|
|
777
|
-
var
|
|
905
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
778
906
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
779
907
|
function useIsModal() {
|
|
780
|
-
const [modal, setModal] = (0,
|
|
781
|
-
(0,
|
|
908
|
+
const [modal, setModal] = (0, import_react9.useState)(false);
|
|
909
|
+
(0, import_react9.useEffect)(() => {
|
|
782
910
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
783
911
|
const mql = window.matchMedia(FULLSCREEN_QUERY);
|
|
784
912
|
const sync = () => setModal(mql.matches);
|
|
@@ -791,17 +919,17 @@ function useIsModal() {
|
|
|
791
919
|
function ChatPanel({ controller, ui, slip }) {
|
|
792
920
|
const { state, close, stop, send } = controller;
|
|
793
921
|
const isModal = useIsModal();
|
|
794
|
-
(0,
|
|
922
|
+
(0, import_react9.useEffect)(() => {
|
|
795
923
|
const onKey = (e) => {
|
|
796
924
|
if (e.key === "Escape") close();
|
|
797
925
|
};
|
|
798
926
|
window.addEventListener("keydown", onKey);
|
|
799
927
|
return () => window.removeEventListener("keydown", onKey);
|
|
800
928
|
}, [close]);
|
|
801
|
-
return /* @__PURE__ */ (0,
|
|
802
|
-
/* @__PURE__ */ (0,
|
|
803
|
-
/* @__PURE__ */ (0,
|
|
804
|
-
/* @__PURE__ */ (0,
|
|
929
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
930
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MessageList, { controller, ui, slip }),
|
|
932
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
805
933
|
] });
|
|
806
934
|
}
|
|
807
935
|
|
|
@@ -913,27 +1041,45 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
913
1041
|
.ss-w-bi-live { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #fff; background: #c0392b; border-radius: 4px; padding: 1px 5px; display: inline-flex; align-items: center; gap: 4px; flex: none; }
|
|
914
1042
|
.ss-w-bi-live-dot { width: 5px; height: 5px; border-radius: 50%; background: #fff; }
|
|
915
1043
|
.ss-w-bi-head { display: flex; align-items: flex-start; gap: 10px; }
|
|
916
|
-
.ss-w-bi-mkt { display: flex; flex-direction: column; gap:
|
|
917
|
-
.ss-w-bi-market { font-size:
|
|
918
|
-
.ss-w-bi-sel { font-size:
|
|
919
|
-
.ss-w-bi-odds { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent)
|
|
920
|
-
.ss-w-bi-odds-cap { font-size:
|
|
921
|
-
.ss-w-bi-odds b { font-size:
|
|
1044
|
+
.ss-w-bi-mkt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
1045
|
+
.ss-w-bi-market { font-size: 15px; font-weight: 700; line-height: 1.25; color: var(--ss-w-ink); }
|
|
1046
|
+
.ss-w-bi-sel { font-size: 12px; line-height: 1.3; color: var(--ss-w-faint); }
|
|
1047
|
+
.ss-w-bi-odds { margin-left: auto; flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 1px; background: color-mix(in srgb, var(--ss-w-accent) 12%, var(--ss-w-panel)); border: 1px solid color-mix(in srgb, var(--ss-w-accent) 30%, var(--ss-w-line)); border-radius: 10px; padding: 4px 11px; min-width: 62px; }
|
|
1048
|
+
.ss-w-bi-odds-cap { font-size: 9px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); }
|
|
1049
|
+
.ss-w-bi-odds b { font-size: 19px; font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); line-height: 1.1; }
|
|
922
1050
|
.ss-w-bi-book { font-size: 9.5px; color: var(--ss-w-faint); }
|
|
923
|
-
.ss-w-bi-text { font-size: 12px; color: var(--ss-w-ink); }
|
|
1051
|
+
.ss-w-bi-text { font-size: 12px; line-height: 1.45; color: var(--ss-w-ink); }
|
|
1052
|
+
.ss-w-bi-stats { display: flex; flex-direction: column; gap: 8px; }
|
|
1053
|
+
.ss-w-bi-toggle { align-self: flex-start; display: inline-flex; align-items: center; gap: 5px; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 11.5px; font-weight: 600; padding: 2px 0; cursor: pointer; }
|
|
1054
|
+
.ss-w-bi-toggle:hover { text-decoration: underline; }
|
|
1055
|
+
.ss-w-bi-chev { width: 7px; height: 7px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: translateY(-2px) rotate(45deg); transition: transform .15s ease; }
|
|
1056
|
+
.ss-w-bi-chev-up { transform: translateY(1px) rotate(-135deg); }
|
|
924
1057
|
.ss-w-bi-rows { display: flex; flex-direction: column; }
|
|
925
|
-
.ss-w-bi-row { display: flex; align-items: baseline; gap:
|
|
1058
|
+
.ss-w-bi-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 5px 0; border-top: 1px solid var(--ss-w-line); }
|
|
926
1059
|
.ss-w-bi-row:first-child { border-top: none; }
|
|
927
|
-
.ss-w-bi-row-lbl { font-size:
|
|
928
|
-
.ss-w-bi-row-
|
|
929
|
-
.ss-w-bi-row-num { font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; font-size: 12.5px; flex: none; color: var(--ss-w-ink); }
|
|
930
|
-
.ss-w-bi-more { align-self: flex-start; background: none; border: none; color: var(--ss-w-accent); font: inherit; font-size: 11px; font-weight: 560; padding: 2px 0; cursor: pointer; }
|
|
931
|
-
.ss-w-bi-more:hover { text-decoration: underline; }
|
|
1060
|
+
.ss-w-bi-row-lbl { font-size: 11.5px; color: var(--ss-w-faint); min-width: 0; }
|
|
1061
|
+
.ss-w-bi-row-num { font-family: ui-monospace, monospace; font-weight: 700; font-variant-numeric: tabular-nums; font-size: 13px; flex: none; color: var(--ss-w-ink); }
|
|
932
1062
|
.ss-w-bi-disc { font-size: 10px; font-style: italic; color: var(--ss-w-faint); }
|
|
933
|
-
.ss-w-bi-scoped { display: flex; flex-direction: column; gap:
|
|
934
|
-
.ss-w-bi-scopes { display: flex; align-items: center; gap:
|
|
935
|
-
.ss-w-bi-chip { font-size: 11px; font-weight:
|
|
936
|
-
.ss-w-bi-chip[aria-pressed="true"] { color:
|
|
1063
|
+
.ss-w-bi-scoped { display: flex; flex-direction: column; gap: 8px; }
|
|
1064
|
+
.ss-w-bi-scopes { display: inline-flex; align-items: center; gap: 2px; flex-wrap: wrap; align-self: flex-start; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 2px; }
|
|
1065
|
+
.ss-w-bi-chip { font-size: 11px; font-weight: 600; border: none; border-radius: 7px; padding: 4px 10px; color: var(--ss-w-faint); background: none; cursor: pointer; }
|
|
1066
|
+
.ss-w-bi-chip[aria-pressed="true"] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
|
|
1067
|
+
|
|
1068
|
+
/* market odds card */
|
|
1069
|
+
.ss-w-mocards { display: flex; flex-direction: column; gap: 7px; }
|
|
1070
|
+
.ss-w-mocard { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 6px; }
|
|
1071
|
+
.ss-w-mo-head { display: flex; align-items: center; gap: 8px; }
|
|
1072
|
+
.ss-w-mo-market { font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }
|
|
1073
|
+
.ss-w-mo-tag { margin-left: auto; flex: none; font-size: 9px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--ss-w-faint); border: 1px solid var(--ss-w-line); border-radius: 8px; padding: 2px 7px; }
|
|
1074
|
+
.ss-w-mo-fixture { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--ss-w-faint); min-width: 0; }
|
|
1075
|
+
.ss-w-mo-comp { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1076
|
+
.ss-w-mo-rows { display: flex; flex-direction: column; gap: 4px; }
|
|
1077
|
+
.ss-w-mo-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--ss-w-line); }
|
|
1078
|
+
.ss-w-mo-row:last-child { border-bottom: none; }
|
|
1079
|
+
.ss-w-mo-sel { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }
|
|
1080
|
+
.ss-w-mo-price { margin-left: auto; font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 14px; font-weight: 700; color: var(--ss-w-accent); }
|
|
1081
|
+
.ss-w-mo-row .ss-w-slip { margin: 0; }
|
|
1082
|
+
.ss-w-mo-foot { display: flex; align-items: center; gap: 8px; font-size: 10.5px; color: var(--ss-w-faint); }
|
|
937
1083
|
|
|
938
1084
|
/* action buttons */
|
|
939
1085
|
.ss-w-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
|
|
@@ -972,7 +1118,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
972
1118
|
`;
|
|
973
1119
|
|
|
974
1120
|
// src/StatsWidget.tsx
|
|
975
|
-
var
|
|
1121
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
976
1122
|
function buildClient(props) {
|
|
977
1123
|
try {
|
|
978
1124
|
if ("client" in props && props.client) {
|
|
@@ -997,11 +1143,11 @@ function injectStyles(root) {
|
|
|
997
1143
|
function StatsWidget(props) {
|
|
998
1144
|
const injectedClient = "client" in props ? props.client : void 0;
|
|
999
1145
|
const cfg = props.config;
|
|
1000
|
-
const built = (0,
|
|
1001
|
-
const ui = (0,
|
|
1002
|
-
const rootRef = (0,
|
|
1146
|
+
const built = (0, import_react10.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
|
|
1147
|
+
const ui = (0, import_react10.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
|
|
1148
|
+
const rootRef = (0, import_react10.useRef)(null);
|
|
1003
1149
|
const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
|
|
1004
|
-
const slip = (0,
|
|
1150
|
+
const slip = (0, import_react10.useMemo)(
|
|
1005
1151
|
() => ({
|
|
1006
1152
|
onAddToSlip: props.config?.onAddToSlip,
|
|
1007
1153
|
conversationId: controller.state.conversationId ?? void 0,
|
|
@@ -1014,14 +1160,14 @@ function StatsWidget(props) {
|
|
|
1014
1160
|
}),
|
|
1015
1161
|
[props.config?.onAddToSlip, controller.state.conversationId, built]
|
|
1016
1162
|
);
|
|
1017
|
-
(0,
|
|
1163
|
+
(0, import_react10.useEffect)(() => {
|
|
1018
1164
|
if (!built || !ui.injectStyles) return;
|
|
1019
1165
|
const node = rootRef.current?.getRootNode();
|
|
1020
1166
|
if (node) injectStyles(node);
|
|
1021
1167
|
}, [built, ui.injectStyles]);
|
|
1022
1168
|
if (!built) return null;
|
|
1023
1169
|
const attrs = themeAttrs(ui);
|
|
1024
|
-
return /* @__PURE__ */ (0,
|
|
1170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("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__ */ (0, import_jsx_runtime17.jsx)(ChatPanel, { controller, ui, slip }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1025
1171
|
ChatFab,
|
|
1026
1172
|
{
|
|
1027
1173
|
label: ui.launcherLabel,
|