@sensiblestats/widget-react 0.10.1 → 0.12.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 +24 -0
- package/dist/index.cjs +142 -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 +142 -92
- package/dist/index.js.map +1 -1
- package/dist/styles.css +9 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @sensiblestats/widget-react
|
|
2
2
|
|
|
3
|
+
## 0.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3c93b88: Show odds movement on betting insight cards, using the same markup and neutral styling as market-odds rows.
|
|
8
|
+
|
|
9
|
+
The movement markup moves into a shared component and its CSS classes are renamed from `ss-w-mo-move` / `ss-w-mo-prev` / `ss-w-mo-arrow` to `ss-w-move` / `ss-w-move-prev` / `ss-w-move-arrow`, since the same element is now rendered by both card types. Operator stylesheets targeting the old names need updating.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [3c93b88]
|
|
14
|
+
- @sensiblestats/widget-sdk@0.10.0
|
|
15
|
+
|
|
16
|
+
## 0.11.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- Neutral odds price-movement display on market_odds card rows.
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies
|
|
25
|
+
- @sensiblestats/widget-sdk@0.9.0
|
|
26
|
+
|
|
3
27
|
## 0.10.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -61,6 +61,9 @@ var STRINGS = {
|
|
|
61
61
|
marketPrices: "Market prices",
|
|
62
62
|
moreLines: "More lines",
|
|
63
63
|
hideLines: "Hide lines",
|
|
64
|
+
oddsMoved: (was, now, direction) => `was ${was}, now ${now}, ${direction}`,
|
|
65
|
+
oddsShortened: "shortened",
|
|
66
|
+
oddsDrifted: "drifted",
|
|
64
67
|
updatedLabel: "updated",
|
|
65
68
|
inSlip: "In slip",
|
|
66
69
|
slipAdded: (n) => n === void 0 ? "Added to slip" : `Added to slip (${n} selection${n === 1 ? "" : "s"})`,
|
|
@@ -91,6 +94,9 @@ var STRINGS = {
|
|
|
91
94
|
marketPrices: "Piyasa fiyatlar\u0131",
|
|
92
95
|
moreLines: "Di\u011Fer \xE7izgiler",
|
|
93
96
|
hideLines: "\xC7izgileri gizle",
|
|
97
|
+
oddsMoved: (was, now, direction) => `\xF6nce ${was}, \u015Fimdi ${now}, ${direction}`,
|
|
98
|
+
oddsShortened: "d\xFC\u015Ft\xFC",
|
|
99
|
+
oddsDrifted: "y\xFCkseldi",
|
|
94
100
|
updatedLabel: "g\xFCncellendi",
|
|
95
101
|
inSlip: "Kuponda",
|
|
96
102
|
slipAdded: (n) => n === void 0 ? "Kupona eklendi" : `Kupona eklendi (${n} se\xE7im)`,
|
|
@@ -137,6 +143,9 @@ function normalizeUi(cfg) {
|
|
|
137
143
|
marketPrices: strings.marketPrices,
|
|
138
144
|
moreLines: strings.moreLines,
|
|
139
145
|
hideLines: strings.hideLines,
|
|
146
|
+
oddsMoved: strings.oddsMoved,
|
|
147
|
+
oddsShortened: strings.oddsShortened,
|
|
148
|
+
oddsDrifted: strings.oddsDrifted,
|
|
140
149
|
updatedLabel: strings.updatedLabel,
|
|
141
150
|
addToSlip: strings.addToSlip,
|
|
142
151
|
inSlip: strings.inSlip,
|
|
@@ -241,6 +250,9 @@ function toInsightVM(insight) {
|
|
|
241
250
|
const fixture = home && away ? `${home} vs ${away}` : void 0;
|
|
242
251
|
const competition = str(insight.competitionName);
|
|
243
252
|
const scopes = Array.isArray(insight.scopes) ? insight.scopes.map((s) => ({ key: str(s.key), label: str(s.label), stats: readStatCells(s.stats) })).filter((s) => !!s.key && !!s.label) : void 0;
|
|
253
|
+
const previousValue = insight.odds?.previousValue;
|
|
254
|
+
const previous = typeof previousValue === "number" && Number.isFinite(previousValue) ? previousValue : void 0;
|
|
255
|
+
const direction = insight.odds?.movementDirection === "shortened" || insight.odds?.movementDirection === "drifted" ? insight.odds.movementDirection : void 0;
|
|
244
256
|
return {
|
|
245
257
|
id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
|
|
246
258
|
market,
|
|
@@ -260,7 +272,9 @@ function toInsightVM(insight) {
|
|
|
260
272
|
matchOddsId,
|
|
261
273
|
addToSlipEnabled: insight.addToSlipEnabled === true,
|
|
262
274
|
oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
|
|
263
|
-
quotedAtUtc: str(insight.odds?.quotedAtUtc)
|
|
275
|
+
quotedAtUtc: str(insight.odds?.quotedAtUtc),
|
|
276
|
+
previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
|
|
277
|
+
movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0
|
|
264
278
|
};
|
|
265
279
|
}
|
|
266
280
|
function toSlipSelection(vm, conversationId) {
|
|
@@ -280,6 +294,8 @@ function toMarketOddsVM(card) {
|
|
|
280
294
|
const toRow = (r, i) => {
|
|
281
295
|
const selection = [str(r.selectionLabel), str(r.line)].filter(Boolean).join(" ");
|
|
282
296
|
const price = typeof r.price === "number" && Number.isFinite(r.price) ? r.price : void 0;
|
|
297
|
+
const previous = typeof r.previousPrice === "number" && Number.isFinite(r.previousPrice) ? r.previousPrice : void 0;
|
|
298
|
+
const direction = r.movementDirection === "shortened" || r.movementDirection === "drifted" ? r.movementDirection : void 0;
|
|
283
299
|
return {
|
|
284
300
|
key: `${selection}:${str(r.line) ?? ""}:${i}`,
|
|
285
301
|
selection,
|
|
@@ -287,7 +303,9 @@ function toMarketOddsVM(card) {
|
|
|
287
303
|
oddsDecimal: price,
|
|
288
304
|
matchOddsId: typeof r.matchOddsId === "number" ? r.matchOddsId : void 0,
|
|
289
305
|
quotedAtUtc: str(r.quotedAtUtc),
|
|
290
|
-
isMain: r.isMainLine !== false
|
|
306
|
+
isMain: r.isMainLine !== false,
|
|
307
|
+
previousOdds: previous !== void 0 && direction !== void 0 ? previous.toFixed(2) : void 0,
|
|
308
|
+
movementDirection: previous !== void 0 && direction !== void 0 ? direction : void 0
|
|
291
309
|
};
|
|
292
310
|
};
|
|
293
311
|
const vms = rows.map(toRow).filter((r) => r.selection && r.odds);
|
|
@@ -745,20 +763,41 @@ function AddToSlipButton({ it, slip, ui }) {
|
|
|
745
763
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SlipButton, { selection, shownOdds: it.odds ?? "", marketName: it.market, slip, ui });
|
|
746
764
|
}
|
|
747
765
|
|
|
766
|
+
// src/components/OddsMovementBadge.tsx
|
|
767
|
+
var import_jsx_runtime9 = (
|
|
768
|
+
// Strikethrough is invisible to screen readers, so the whole was/now/direction sentence rides
|
|
769
|
+
// on one aria-label and the visual glyphs are hidden from the accessibility tree.
|
|
770
|
+
require("react/jsx-runtime")
|
|
771
|
+
);
|
|
772
|
+
function OddsMovementBadge({
|
|
773
|
+
previous,
|
|
774
|
+
current,
|
|
775
|
+
direction,
|
|
776
|
+
ui
|
|
777
|
+
}) {
|
|
778
|
+
if (previous === void 0 || direction === void 0) return null;
|
|
779
|
+
const directionWord = direction === "shortened" ? ui?.oddsShortened ?? "shortened" : ui?.oddsDrifted ?? "drifted";
|
|
780
|
+
const label = ui?.oddsMoved?.(previous, current, directionWord) ?? `was ${previous}, now ${current}, ${directionWord}`;
|
|
781
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "ss-w-move", role: "img", "aria-label": label, children: [
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ss-w-move-prev", "aria-hidden": "true", children: previous }),
|
|
783
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ss-w-move-arrow", "aria-hidden": "true", children: direction === "shortened" ? "\u25BC" : "\u25B2" })
|
|
784
|
+
] });
|
|
785
|
+
}
|
|
786
|
+
|
|
748
787
|
// src/components/BettingInsightList.tsx
|
|
749
|
-
var
|
|
788
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
750
789
|
function StatRows2({ stats }) {
|
|
751
|
-
return /* @__PURE__ */ (0,
|
|
752
|
-
/* @__PURE__ */ (0,
|
|
753
|
-
/* @__PURE__ */ (0,
|
|
790
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ss-w-bi-rows", children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-row", children: [
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-row-lbl", children: s.label }),
|
|
792
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-row-num", children: s.value })
|
|
754
793
|
] }, `${s.label}:${s.value}`)) });
|
|
755
794
|
}
|
|
756
795
|
function ScopedStats({ scopes }) {
|
|
757
796
|
const [active, setActive] = (0, import_react5.useState)(0);
|
|
758
797
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
759
|
-
return /* @__PURE__ */ (0,
|
|
760
|
-
/* @__PURE__ */ (0,
|
|
761
|
-
/* @__PURE__ */ (0,
|
|
798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-scoped", children: [
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRows2, { stats: current.stats }, current.key)
|
|
762
801
|
] });
|
|
763
802
|
}
|
|
764
803
|
function StatsDisclosure({ it, ui }) {
|
|
@@ -766,8 +805,8 @@ function StatsDisclosure({ it, ui }) {
|
|
|
766
805
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
767
806
|
const hasStats = hasScopes || it.stats.length > 0;
|
|
768
807
|
if (!hasStats) return null;
|
|
769
|
-
return /* @__PURE__ */ (0,
|
|
770
|
-
/* @__PURE__ */ (0,
|
|
808
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-stats", children: [
|
|
809
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
771
810
|
"button",
|
|
772
811
|
{
|
|
773
812
|
type: "button",
|
|
@@ -775,121 +814,123 @@ function StatsDisclosure({ it, ui }) {
|
|
|
775
814
|
"aria-expanded": open,
|
|
776
815
|
onClick: () => setOpen((v) => !v),
|
|
777
816
|
children: [
|
|
778
|
-
/* @__PURE__ */ (0,
|
|
779
|
-
/* @__PURE__ */ (0,
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: open ? ui?.hideStats ?? "Hide stats" : ui?.showStats ?? "Show stats" }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: `ss-w-bi-chev${open ? " ss-w-bi-chev-up" : ""}`, "aria-hidden": "true" })
|
|
780
819
|
]
|
|
781
820
|
}
|
|
782
821
|
),
|
|
783
|
-
open ? hasScopes ? /* @__PURE__ */ (0,
|
|
822
|
+
open ? hasScopes ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScopedStats, { scopes: it.scopes }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRows2, { stats: it.stats }) : null
|
|
784
823
|
] });
|
|
785
824
|
}
|
|
786
825
|
function InsightCard({ it, ui, slip }) {
|
|
787
826
|
const live = it.isLive || it.phase === "live";
|
|
788
|
-
return /* @__PURE__ */ (0,
|
|
789
|
-
live ? /* @__PURE__ */ (0,
|
|
790
|
-
/* @__PURE__ */ (0,
|
|
827
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-binsight", children: [
|
|
828
|
+
live ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ss-w-bi-status", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ss-w-bi-live", children: [
|
|
829
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
|
|
791
830
|
ui?.liveLabel ?? "Live"
|
|
792
831
|
] }) }) : null,
|
|
793
|
-
/* @__PURE__ */ (0,
|
|
794
|
-
/* @__PURE__ */ (0,
|
|
795
|
-
/* @__PURE__ */ (0,
|
|
796
|
-
it.selection ? /* @__PURE__ */ (0,
|
|
797
|
-
it.fixture || it.competition ? /* @__PURE__ */ (0,
|
|
798
|
-
it.fixture ? /* @__PURE__ */ (0,
|
|
799
|
-
it.competition ? /* @__PURE__ */ (0,
|
|
832
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-head", children: [
|
|
833
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ss-w-bi-mkt", children: [
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-market", children: it.market }),
|
|
835
|
+
it.selection ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-sel", children: it.selection }) : null,
|
|
836
|
+
it.fixture || it.competition ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ss-w-bi-match", children: [
|
|
837
|
+
it.fixture ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-fixture", children: it.fixture }) : null,
|
|
838
|
+
it.competition ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-comp", children: it.competition }) : null
|
|
800
839
|
] }) : null
|
|
801
840
|
] }),
|
|
802
|
-
/* @__PURE__ */ (0,
|
|
803
|
-
it.odds ? /* @__PURE__ */ (0,
|
|
804
|
-
/* @__PURE__ */ (0,
|
|
805
|
-
/* @__PURE__ */ (0,
|
|
806
|
-
|
|
841
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-action", children: [
|
|
842
|
+
it.odds ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ss-w-bi-odds", children: [
|
|
843
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-odds-cap", children: ui?.oddsLabel ?? "Odds" }),
|
|
844
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("b", { children: it.odds }),
|
|
845
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(OddsMovementBadge, { previous: it.previousOdds, current: it.odds, direction: it.movementDirection, ui }),
|
|
846
|
+
it.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
|
|
807
847
|
] }) : null,
|
|
808
|
-
/* @__PURE__ */ (0,
|
|
848
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AddToSlipButton, { it, slip, ui })
|
|
809
849
|
] })
|
|
810
850
|
] }),
|
|
811
|
-
it.text ? /* @__PURE__ */ (0,
|
|
812
|
-
/* @__PURE__ */ (0,
|
|
813
|
-
it.disclaimer ? /* @__PURE__ */ (0,
|
|
851
|
+
it.text ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ss-w-bi-text", children: it.text }) : null,
|
|
852
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatsDisclosure, { it, ui }),
|
|
853
|
+
it.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "ss-w-bi-disc", children: it.disclaimer }) : null
|
|
814
854
|
] });
|
|
815
855
|
}
|
|
816
856
|
function BettingInsightList({ insights, ui, slip }) {
|
|
817
857
|
if (!insights || insights.length === 0) return null;
|
|
818
|
-
return /* @__PURE__ */ (0,
|
|
858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "ss-w-binsights", children: insights.map((it) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(InsightCard, { it, ui, slip }, it.id)) });
|
|
819
859
|
}
|
|
820
860
|
|
|
821
861
|
// src/components/MarketOddsCardList.tsx
|
|
822
862
|
var import_react6 = require("react");
|
|
823
|
-
var
|
|
863
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
824
864
|
function OddsRow({ vm, row, ui, slip }) {
|
|
825
865
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
826
|
-
return /* @__PURE__ */ (0,
|
|
827
|
-
/* @__PURE__ */ (0,
|
|
828
|
-
/* @__PURE__ */ (0,
|
|
829
|
-
/* @__PURE__ */ (0,
|
|
866
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-mo-row", children: [
|
|
867
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-mo-sel", children: row.selection }),
|
|
868
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OddsMovementBadge, { previous: row.previousOdds, current: row.odds, direction: row.movementDirection, ui }),
|
|
869
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-mo-price", children: row.odds }),
|
|
870
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
830
871
|
] });
|
|
831
872
|
}
|
|
832
873
|
function MarketOddsCard({ vm, ui, slip }) {
|
|
833
874
|
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
834
|
-
return /* @__PURE__ */ (0,
|
|
835
|
-
/* @__PURE__ */ (0,
|
|
836
|
-
/* @__PURE__ */ (0,
|
|
837
|
-
/* @__PURE__ */ (0,
|
|
875
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-mocard", children: [
|
|
876
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-mo-head", children: [
|
|
877
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-mo-market", children: vm.market }),
|
|
878
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-mo-tag", children: ui?.marketPrices ?? "Market prices" })
|
|
838
879
|
] }),
|
|
839
|
-
vm.fixture || vm.competition ? /* @__PURE__ */ (0,
|
|
840
|
-
vm.fixture ? /* @__PURE__ */ (0,
|
|
841
|
-
vm.competition ? /* @__PURE__ */ (0,
|
|
880
|
+
vm.fixture || vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-mo-fixture", children: [
|
|
881
|
+
vm.fixture ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: vm.fixture }) : null,
|
|
882
|
+
vm.competition ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-mo-comp", children: vm.competition }) : null
|
|
842
883
|
] }) : null,
|
|
843
|
-
/* @__PURE__ */ (0,
|
|
844
|
-
vm.mainRows.map((row) => /* @__PURE__ */ (0,
|
|
845
|
-
open ? vm.moreRows.map((row) => /* @__PURE__ */ (0,
|
|
884
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-mo-rows", children: [
|
|
885
|
+
vm.mainRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OddsRow, { vm, row, ui, slip }, row.key)),
|
|
886
|
+
open ? vm.moreRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OddsRow, { vm, row, ui, slip }, row.key)) : null
|
|
846
887
|
] }),
|
|
847
|
-
vm.moreRows.length > 0 ? /* @__PURE__ */ (0,
|
|
848
|
-
/* @__PURE__ */ (0,
|
|
849
|
-
/* @__PURE__ */ (0,
|
|
888
|
+
vm.moreRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { type: "button", className: "ss-w-bi-toggle", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [
|
|
889
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: open ? ui?.hideLines ?? "Hide lines" : `${ui?.moreLines ?? "More lines"} (${vm.moreRows.length})` }),
|
|
890
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `ss-w-bi-chev${open ? " ss-w-bi-chev-up" : ""}`, "aria-hidden": "true" })
|
|
850
891
|
] }) : null,
|
|
851
|
-
vm.bookmaker ? /* @__PURE__ */ (0,
|
|
852
|
-
vm.disclaimer ? /* @__PURE__ */ (0,
|
|
892
|
+
vm.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-mo-foot", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: vm.bookmaker }) }) : null,
|
|
893
|
+
vm.disclaimer ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "ss-w-bi-disc", children: vm.disclaimer }) : null
|
|
853
894
|
] });
|
|
854
895
|
}
|
|
855
896
|
function MarketOddsCardList({ cards, ui, slip }) {
|
|
856
897
|
if (!cards || cards.length === 0) return null;
|
|
857
|
-
return /* @__PURE__ */ (0,
|
|
898
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-mocards", children: cards.map((vm) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MarketOddsCard, { vm, ui, slip }, vm.id)) });
|
|
858
899
|
}
|
|
859
900
|
|
|
860
901
|
// src/components/ActionButtons.tsx
|
|
861
|
-
var
|
|
902
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
862
903
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
863
904
|
if (actions.length === 0 && !loading) return null;
|
|
864
|
-
return /* @__PURE__ */ (0,
|
|
865
|
-
actions.map((a, i) => /* @__PURE__ */ (0,
|
|
866
|
-
actions.length === 0 && loading ? /* @__PURE__ */ (0,
|
|
867
|
-
/* @__PURE__ */ (0,
|
|
868
|
-
/* @__PURE__ */ (0,
|
|
905
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ss-w-actions", children: [
|
|
906
|
+
actions.map((a, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "ss-w-abtn", disabled, onClick: () => onAct(a), children: a.label }, `${a.label}-${i}`)),
|
|
907
|
+
actions.length === 0 && loading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
908
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-abtn-shimmer" }),
|
|
909
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "ss-w-abtn-shimmer" })
|
|
869
910
|
] }) : null
|
|
870
911
|
] });
|
|
871
912
|
}
|
|
872
913
|
|
|
873
914
|
// src/components/ChatMessage.tsx
|
|
874
|
-
var
|
|
915
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
875
916
|
function ChatMessage({ message, disabled, onAct, ui, slip }) {
|
|
876
917
|
if (message.role === "user") {
|
|
877
|
-
return /* @__PURE__ */ (0,
|
|
918
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
|
|
878
919
|
}
|
|
879
|
-
return /* @__PURE__ */ (0,
|
|
880
|
-
message.text ? /* @__PURE__ */ (0,
|
|
881
|
-
/* @__PURE__ */ (0,
|
|
882
|
-
/* @__PURE__ */ (0,
|
|
883
|
-
/* @__PURE__ */ (0,
|
|
884
|
-
/* @__PURE__ */ (0,
|
|
920
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
921
|
+
message.text ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Markdown, { text: message.text }) : null,
|
|
922
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
924
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
925
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
885
926
|
] });
|
|
886
927
|
}
|
|
887
928
|
|
|
888
929
|
// src/components/IntentChips.tsx
|
|
889
|
-
var
|
|
930
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
890
931
|
function IntentChips({ chips, onPick }) {
|
|
891
932
|
if (chips.length === 0) return null;
|
|
892
|
-
return /* @__PURE__ */ (0,
|
|
933
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
893
934
|
}
|
|
894
935
|
|
|
895
936
|
// src/scroll.ts
|
|
@@ -899,7 +940,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
899
940
|
}
|
|
900
941
|
|
|
901
942
|
// src/components/MessageList.tsx
|
|
902
|
-
var
|
|
943
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
903
944
|
function MessageList({ controller, ui, slip }) {
|
|
904
945
|
const { state, send } = controller;
|
|
905
946
|
const listRef = (0, import_react7.useRef)(null);
|
|
@@ -909,7 +950,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
909
950
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
910
951
|
}, [state.messages, state.status]);
|
|
911
952
|
const empty = state.messages.length === 0;
|
|
912
|
-
return /* @__PURE__ */ (0,
|
|
953
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
913
954
|
"div",
|
|
914
955
|
{
|
|
915
956
|
className: "ss-w-list",
|
|
@@ -919,7 +960,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
919
960
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
920
961
|
},
|
|
921
962
|
children: [
|
|
922
|
-
state.messages.map((m) => /* @__PURE__ */ (0,
|
|
963
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
923
964
|
ChatMessage,
|
|
924
965
|
{
|
|
925
966
|
message: m,
|
|
@@ -930,15 +971,15 @@ function MessageList({ controller, ui, slip }) {
|
|
|
930
971
|
},
|
|
931
972
|
m.id
|
|
932
973
|
)),
|
|
933
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0,
|
|
974
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
934
975
|
} }) : null,
|
|
935
|
-
state.status ? /* @__PURE__ */ (0,
|
|
936
|
-
state.error ? /* @__PURE__ */ (0,
|
|
937
|
-
/* @__PURE__ */ (0,
|
|
938
|
-
/* @__PURE__ */ (0,
|
|
976
|
+
state.status ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
|
|
977
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
|
|
978
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
979
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
939
980
|
] }) : null,
|
|
940
|
-
empty ? /* @__PURE__ */ (0,
|
|
941
|
-
/* @__PURE__ */ (0,
|
|
981
|
+
empty ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
982
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { ref: endRef })
|
|
942
983
|
]
|
|
943
984
|
}
|
|
944
985
|
);
|
|
@@ -946,7 +987,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
946
987
|
|
|
947
988
|
// src/components/ChatInput.tsx
|
|
948
989
|
var import_react8 = require("react");
|
|
949
|
-
var
|
|
990
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
950
991
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
951
992
|
const [value, setValue] = (0, import_react8.useState)("");
|
|
952
993
|
const submit = () => {
|
|
@@ -961,14 +1002,14 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
961
1002
|
submit();
|
|
962
1003
|
}
|
|
963
1004
|
};
|
|
964
|
-
return /* @__PURE__ */ (0,
|
|
965
|
-
/* @__PURE__ */ (0,
|
|
966
|
-
streaming ? /* @__PURE__ */ (0,
|
|
1005
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "ss-w-input", children: [
|
|
1006
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
1007
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SendIcon, {}) })
|
|
967
1008
|
] });
|
|
968
1009
|
}
|
|
969
1010
|
|
|
970
1011
|
// src/components/ChatPanel.tsx
|
|
971
|
-
var
|
|
1012
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
972
1013
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
973
1014
|
function useIsModal() {
|
|
974
1015
|
const [modal, setModal] = (0, import_react9.useState)(false);
|
|
@@ -992,10 +1033,10 @@ function ChatPanel({ controller, ui, slip }) {
|
|
|
992
1033
|
window.addEventListener("keydown", onKey);
|
|
993
1034
|
return () => window.removeEventListener("keydown", onKey);
|
|
994
1035
|
}, [close]);
|
|
995
|
-
return /* @__PURE__ */ (0,
|
|
996
|
-
/* @__PURE__ */ (0,
|
|
997
|
-
/* @__PURE__ */ (0,
|
|
998
|
-
/* @__PURE__ */ (0,
|
|
1036
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
1037
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
1038
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MessageList, { controller, ui, slip }),
|
|
1039
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
999
1040
|
] });
|
|
1000
1041
|
}
|
|
1001
1042
|
|
|
@@ -1182,6 +1223,15 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1182
1223
|
.ss-w-mo-row:last-child { border-bottom: none; }
|
|
1183
1224
|
.ss-w-mo-sel { font-size: 12.5px; font-weight: 600; color: var(--ss-w-ink); }
|
|
1184
1225
|
.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); }
|
|
1226
|
+
/* Movement: BOTH directions share --ss-w-faint on purpose. Green-good/red-bad would frame a
|
|
1227
|
+
shortening price as a discount, which inverts what it actually means for the bettor. */
|
|
1228
|
+
.ss-w-move { display: inline-flex; align-items: baseline; gap: 4px; color: var(--ss-w-faint); }
|
|
1229
|
+
.ss-w-move-prev { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; font-size: 12px; text-decoration: line-through; }
|
|
1230
|
+
.ss-w-move-arrow { font-size: 9px; line-height: 1; }
|
|
1231
|
+
/* margin-left:auto is row layout, not badge styling -- it belongs to the market-odds row, which is
|
|
1232
|
+
a flex row, and must NOT follow the badge into the insight card's odds column. */
|
|
1233
|
+
.ss-w-mo-row .ss-w-move { margin-left: auto; }
|
|
1234
|
+
.ss-w-mo-row .ss-w-move + .ss-w-mo-price { margin-left: 0; }
|
|
1185
1235
|
.ss-w-mo-row .ss-w-slip { margin: 0; }
|
|
1186
1236
|
.ss-w-mo-foot { display: flex; align-items: center; gap: 8px; font-size: 10.5px; color: var(--ss-w-faint); }
|
|
1187
1237
|
|
|
@@ -1222,7 +1272,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1222
1272
|
`;
|
|
1223
1273
|
|
|
1224
1274
|
// src/StatsWidget.tsx
|
|
1225
|
-
var
|
|
1275
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1226
1276
|
function buildClient(props) {
|
|
1227
1277
|
try {
|
|
1228
1278
|
if ("client" in props && props.client) {
|
|
@@ -1271,7 +1321,7 @@ function StatsWidget(props) {
|
|
|
1271
1321
|
}, [built, ui.injectStyles]);
|
|
1272
1322
|
if (!built) return null;
|
|
1273
1323
|
const attrs = themeAttrs(ui);
|
|
1274
|
-
return /* @__PURE__ */ (0,
|
|
1324
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.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_runtime18.jsx)(ChatPanel, { controller, ui, slip }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1275
1325
|
ChatFab,
|
|
1276
1326
|
{
|
|
1277
1327
|
label: ui.launcherLabel,
|