@sensiblestats/widget-react 0.11.0 → 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 +13 -0
- package/dist/index.cjs +126 -105
- 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 +126 -105
- package/dist/index.js.map +1 -1
- package/dist/styles.css +7 -4
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
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
|
+
|
|
3
16
|
## 0.11.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -250,6 +250,9 @@ function toInsightVM(insight) {
|
|
|
250
250
|
const fixture = home && away ? `${home} vs ${away}` : void 0;
|
|
251
251
|
const competition = str(insight.competitionName);
|
|
252
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;
|
|
253
256
|
return {
|
|
254
257
|
id: str(insight.insightId) ?? `${str(insight.ruleId) ?? "insight"}:${num(insight.matchId) ?? ""}`,
|
|
255
258
|
market,
|
|
@@ -269,7 +272,9 @@ function toInsightVM(insight) {
|
|
|
269
272
|
matchOddsId,
|
|
270
273
|
addToSlipEnabled: insight.addToSlipEnabled === true,
|
|
271
274
|
oddsDecimal: typeof oddsValue === "number" && Number.isFinite(oddsValue) ? oddsValue : void 0,
|
|
272
|
-
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
|
|
273
278
|
};
|
|
274
279
|
}
|
|
275
280
|
function toSlipSelection(vm, conversationId) {
|
|
@@ -758,20 +763,41 @@ function AddToSlipButton({ it, slip, ui }) {
|
|
|
758
763
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SlipButton, { selection, shownOdds: it.odds ?? "", marketName: it.market, slip, ui });
|
|
759
764
|
}
|
|
760
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
|
+
|
|
761
787
|
// src/components/BettingInsightList.tsx
|
|
762
|
-
var
|
|
788
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
763
789
|
function StatRows2({ stats }) {
|
|
764
|
-
return /* @__PURE__ */ (0,
|
|
765
|
-
/* @__PURE__ */ (0,
|
|
766
|
-
/* @__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 })
|
|
767
793
|
] }, `${s.label}:${s.value}`)) });
|
|
768
794
|
}
|
|
769
795
|
function ScopedStats({ scopes }) {
|
|
770
796
|
const [active, setActive] = (0, import_react5.useState)(0);
|
|
771
797
|
const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
|
|
772
|
-
return /* @__PURE__ */ (0,
|
|
773
|
-
/* @__PURE__ */ (0,
|
|
774
|
-
/* @__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)
|
|
775
801
|
] });
|
|
776
802
|
}
|
|
777
803
|
function StatsDisclosure({ it, ui }) {
|
|
@@ -779,8 +805,8 @@ function StatsDisclosure({ it, ui }) {
|
|
|
779
805
|
const hasScopes = !!it.scopes && it.scopes.length >= 2;
|
|
780
806
|
const hasStats = hasScopes || it.stats.length > 0;
|
|
781
807
|
if (!hasStats) return null;
|
|
782
|
-
return /* @__PURE__ */ (0,
|
|
783
|
-
/* @__PURE__ */ (0,
|
|
808
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ss-w-bi-stats", children: [
|
|
809
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
784
810
|
"button",
|
|
785
811
|
{
|
|
786
812
|
type: "button",
|
|
@@ -788,131 +814,123 @@ function StatsDisclosure({ it, ui }) {
|
|
|
788
814
|
"aria-expanded": open,
|
|
789
815
|
onClick: () => setOpen((v) => !v),
|
|
790
816
|
children: [
|
|
791
|
-
/* @__PURE__ */ (0,
|
|
792
|
-
/* @__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" })
|
|
793
819
|
]
|
|
794
820
|
}
|
|
795
821
|
),
|
|
796
|
-
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
|
|
797
823
|
] });
|
|
798
824
|
}
|
|
799
825
|
function InsightCard({ it, ui, slip }) {
|
|
800
826
|
const live = it.isLive || it.phase === "live";
|
|
801
|
-
return /* @__PURE__ */ (0,
|
|
802
|
-
live ? /* @__PURE__ */ (0,
|
|
803
|
-
/* @__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" }),
|
|
804
830
|
ui?.liveLabel ?? "Live"
|
|
805
831
|
] }) }) : null,
|
|
806
|
-
/* @__PURE__ */ (0,
|
|
807
|
-
/* @__PURE__ */ (0,
|
|
808
|
-
/* @__PURE__ */ (0,
|
|
809
|
-
it.selection ? /* @__PURE__ */ (0,
|
|
810
|
-
it.fixture || it.competition ? /* @__PURE__ */ (0,
|
|
811
|
-
it.fixture ? /* @__PURE__ */ (0,
|
|
812
|
-
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
|
|
813
839
|
] }) : null
|
|
814
840
|
] }),
|
|
815
|
-
/* @__PURE__ */ (0,
|
|
816
|
-
it.odds ? /* @__PURE__ */ (0,
|
|
817
|
-
/* @__PURE__ */ (0,
|
|
818
|
-
/* @__PURE__ */ (0,
|
|
819
|
-
|
|
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
|
|
820
847
|
] }) : null,
|
|
821
|
-
/* @__PURE__ */ (0,
|
|
848
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AddToSlipButton, { it, slip, ui })
|
|
822
849
|
] })
|
|
823
850
|
] }),
|
|
824
|
-
it.text ? /* @__PURE__ */ (0,
|
|
825
|
-
/* @__PURE__ */ (0,
|
|
826
|
-
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
|
|
827
854
|
] });
|
|
828
855
|
}
|
|
829
856
|
function BettingInsightList({ insights, ui, slip }) {
|
|
830
857
|
if (!insights || insights.length === 0) return null;
|
|
831
|
-
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)) });
|
|
832
859
|
}
|
|
833
860
|
|
|
834
861
|
// src/components/MarketOddsCardList.tsx
|
|
835
862
|
var import_react6 = require("react");
|
|
836
|
-
var
|
|
863
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
837
864
|
function OddsRow({ vm, row, ui, slip }) {
|
|
838
865
|
const selection = vm.addToSlipEnabled ? marketOddsRowToSlipSelection(vm, row, slip.conversationId) : null;
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
/* @__PURE__ */ (0,
|
|
843
|
-
row.
|
|
844
|
-
// Strikethrough is invisible to screen readers, so the whole was/now/direction sentence
|
|
845
|
-
// rides on one aria-label and the visual glyphs are hidden from the accessibility tree.
|
|
846
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "ss-w-mo-move", role: "img", "aria-label": movementLabel, children: [
|
|
847
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-mo-prev", "aria-hidden": "true", children: row.previousOdds }),
|
|
848
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-mo-arrow", "aria-hidden": "true", children: row.movementDirection === "shortened" ? "\u25BC" : "\u25B2" })
|
|
849
|
-
] })
|
|
850
|
-
) : null,
|
|
851
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "ss-w-mo-price", children: row.odds }),
|
|
852
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SlipButton, { selection, shownOdds: row.odds, marketName: vm.market, slip, ui })
|
|
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 })
|
|
853
871
|
] });
|
|
854
872
|
}
|
|
855
873
|
function MarketOddsCard({ vm, ui, slip }) {
|
|
856
874
|
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
857
|
-
return /* @__PURE__ */ (0,
|
|
858
|
-
/* @__PURE__ */ (0,
|
|
859
|
-
/* @__PURE__ */ (0,
|
|
860
|
-
/* @__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" })
|
|
861
879
|
] }),
|
|
862
|
-
vm.fixture || vm.competition ? /* @__PURE__ */ (0,
|
|
863
|
-
vm.fixture ? /* @__PURE__ */ (0,
|
|
864
|
-
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
|
|
865
883
|
] }) : null,
|
|
866
|
-
/* @__PURE__ */ (0,
|
|
867
|
-
vm.mainRows.map((row) => /* @__PURE__ */ (0,
|
|
868
|
-
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
|
|
869
887
|
] }),
|
|
870
|
-
vm.moreRows.length > 0 ? /* @__PURE__ */ (0,
|
|
871
|
-
/* @__PURE__ */ (0,
|
|
872
|
-
/* @__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" })
|
|
873
891
|
] }) : null,
|
|
874
|
-
vm.bookmaker ? /* @__PURE__ */ (0,
|
|
875
|
-
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
|
|
876
894
|
] });
|
|
877
895
|
}
|
|
878
896
|
function MarketOddsCardList({ cards, ui, slip }) {
|
|
879
897
|
if (!cards || cards.length === 0) return null;
|
|
880
|
-
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)) });
|
|
881
899
|
}
|
|
882
900
|
|
|
883
901
|
// src/components/ActionButtons.tsx
|
|
884
|
-
var
|
|
902
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
885
903
|
function ActionButtons({ actions, loading, disabled, onAct }) {
|
|
886
904
|
if (actions.length === 0 && !loading) return null;
|
|
887
|
-
return /* @__PURE__ */ (0,
|
|
888
|
-
actions.map((a, i) => /* @__PURE__ */ (0,
|
|
889
|
-
actions.length === 0 && loading ? /* @__PURE__ */ (0,
|
|
890
|
-
/* @__PURE__ */ (0,
|
|
891
|
-
/* @__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" })
|
|
892
910
|
] }) : null
|
|
893
911
|
] });
|
|
894
912
|
}
|
|
895
913
|
|
|
896
914
|
// src/components/ChatMessage.tsx
|
|
897
|
-
var
|
|
915
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
898
916
|
function ChatMessage({ message, disabled, onAct, ui, slip }) {
|
|
899
917
|
if (message.role === "user") {
|
|
900
|
-
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 }) });
|
|
901
919
|
}
|
|
902
|
-
return /* @__PURE__ */ (0,
|
|
903
|
-
message.text ? /* @__PURE__ */ (0,
|
|
904
|
-
/* @__PURE__ */ (0,
|
|
905
|
-
/* @__PURE__ */ (0,
|
|
906
|
-
/* @__PURE__ */ (0,
|
|
907
|
-
/* @__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 })
|
|
908
926
|
] });
|
|
909
927
|
}
|
|
910
928
|
|
|
911
929
|
// src/components/IntentChips.tsx
|
|
912
|
-
var
|
|
930
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
913
931
|
function IntentChips({ chips, onPick }) {
|
|
914
932
|
if (chips.length === 0) return null;
|
|
915
|
-
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}`)) });
|
|
916
934
|
}
|
|
917
935
|
|
|
918
936
|
// src/scroll.ts
|
|
@@ -922,7 +940,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
922
940
|
}
|
|
923
941
|
|
|
924
942
|
// src/components/MessageList.tsx
|
|
925
|
-
var
|
|
943
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
926
944
|
function MessageList({ controller, ui, slip }) {
|
|
927
945
|
const { state, send } = controller;
|
|
928
946
|
const listRef = (0, import_react7.useRef)(null);
|
|
@@ -932,7 +950,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
932
950
|
if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
|
|
933
951
|
}, [state.messages, state.status]);
|
|
934
952
|
const empty = state.messages.length === 0;
|
|
935
|
-
return /* @__PURE__ */ (0,
|
|
953
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
936
954
|
"div",
|
|
937
955
|
{
|
|
938
956
|
className: "ss-w-list",
|
|
@@ -942,7 +960,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
942
960
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
943
961
|
},
|
|
944
962
|
children: [
|
|
945
|
-
state.messages.map((m) => /* @__PURE__ */ (0,
|
|
963
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
946
964
|
ChatMessage,
|
|
947
965
|
{
|
|
948
966
|
message: m,
|
|
@@ -953,15 +971,15 @@ function MessageList({ controller, ui, slip }) {
|
|
|
953
971
|
},
|
|
954
972
|
m.id
|
|
955
973
|
)),
|
|
956
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0,
|
|
974
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
957
975
|
} }) : null,
|
|
958
|
-
state.status ? /* @__PURE__ */ (0,
|
|
959
|
-
state.error ? /* @__PURE__ */ (0,
|
|
960
|
-
/* @__PURE__ */ (0,
|
|
961
|
-
/* @__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 })
|
|
962
980
|
] }) : null,
|
|
963
|
-
empty ? /* @__PURE__ */ (0,
|
|
964
|
-
/* @__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 })
|
|
965
983
|
]
|
|
966
984
|
}
|
|
967
985
|
);
|
|
@@ -969,7 +987,7 @@ function MessageList({ controller, ui, slip }) {
|
|
|
969
987
|
|
|
970
988
|
// src/components/ChatInput.tsx
|
|
971
989
|
var import_react8 = require("react");
|
|
972
|
-
var
|
|
990
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
973
991
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
974
992
|
const [value, setValue] = (0, import_react8.useState)("");
|
|
975
993
|
const submit = () => {
|
|
@@ -984,14 +1002,14 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
984
1002
|
submit();
|
|
985
1003
|
}
|
|
986
1004
|
};
|
|
987
|
-
return /* @__PURE__ */ (0,
|
|
988
|
-
/* @__PURE__ */ (0,
|
|
989
|
-
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, {}) })
|
|
990
1008
|
] });
|
|
991
1009
|
}
|
|
992
1010
|
|
|
993
1011
|
// src/components/ChatPanel.tsx
|
|
994
|
-
var
|
|
1012
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
995
1013
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
996
1014
|
function useIsModal() {
|
|
997
1015
|
const [modal, setModal] = (0, import_react9.useState)(false);
|
|
@@ -1015,10 +1033,10 @@ function ChatPanel({ controller, ui, slip }) {
|
|
|
1015
1033
|
window.addEventListener("keydown", onKey);
|
|
1016
1034
|
return () => window.removeEventListener("keydown", onKey);
|
|
1017
1035
|
}, [close]);
|
|
1018
|
-
return /* @__PURE__ */ (0,
|
|
1019
|
-
/* @__PURE__ */ (0,
|
|
1020
|
-
/* @__PURE__ */ (0,
|
|
1021
|
-
/* @__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 })
|
|
1022
1040
|
] });
|
|
1023
1041
|
}
|
|
1024
1042
|
|
|
@@ -1207,10 +1225,13 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1207
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); }
|
|
1208
1226
|
/* Movement: BOTH directions share --ss-w-faint on purpose. Green-good/red-bad would frame a
|
|
1209
1227
|
shortening price as a discount, which inverts what it actually means for the bettor. */
|
|
1210
|
-
.ss-w-
|
|
1211
|
-
.ss-w-
|
|
1212
|
-
.ss-w-
|
|
1213
|
-
|
|
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; }
|
|
1214
1235
|
.ss-w-mo-row .ss-w-slip { margin: 0; }
|
|
1215
1236
|
.ss-w-mo-foot { display: flex; align-items: center; gap: 8px; font-size: 10.5px; color: var(--ss-w-faint); }
|
|
1216
1237
|
|
|
@@ -1251,7 +1272,7 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1251
1272
|
`;
|
|
1252
1273
|
|
|
1253
1274
|
// src/StatsWidget.tsx
|
|
1254
|
-
var
|
|
1275
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1255
1276
|
function buildClient(props) {
|
|
1256
1277
|
try {
|
|
1257
1278
|
if ("client" in props && props.client) {
|
|
@@ -1300,7 +1321,7 @@ function StatsWidget(props) {
|
|
|
1300
1321
|
}, [built, ui.injectStyles]);
|
|
1301
1322
|
if (!built) return null;
|
|
1302
1323
|
const attrs = themeAttrs(ui);
|
|
1303
|
-
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)(
|
|
1304
1325
|
ChatFab,
|
|
1305
1326
|
{
|
|
1306
1327
|
label: ui.launcherLabel,
|