@sensiblestats/widget-react 0.21.0 → 0.22.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/StatsWidget.tsx
2
- import { useEffect as useEffect6, useMemo as useMemo2, useRef as useRef3 } from "react";
2
+ import { useEffect as useEffect5, useMemo as useMemo2, useRef as useRef3 } from "react";
3
3
  import { StatsWidgetClient } from "@sensiblestats/widget-sdk";
4
4
 
5
5
  // src/kickoff.ts
@@ -55,12 +55,6 @@ var STRINGS = {
55
55
  const drift = direction ? `, ${direction}` : "";
56
56
  return `Price movement over the last ${span}: opened at ${opening}, currently ${current}${drift}.`;
57
57
  },
58
- clubMatchPreviewHeading: "Match preview",
59
- clubTeamDnaHeading: "How they play",
60
- clubFormHeading: "Recent form",
61
- clubCountdownLabel: "Countdown to kick-off",
62
- clubKickoff: (ms) => new Intl.DateTimeFormat("en-GB", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(ms)),
63
- clubKickoffAria: (ms) => `Kick-off ${new Intl.DateTimeFormat("en-GB", { weekday: "long", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" }).format(new Date(ms))}`,
64
58
  inSlip: "In slip",
65
59
  slipAdded: (n) => n === void 0 ? "Added to slip" : `Added to slip (${n} selection${n === 1 ? "" : "s"})`,
66
60
  slipDuplicate: "Already in your slip",
@@ -112,12 +106,6 @@ var STRINGS = {
112
106
  const drift = direction ? `, ${direction}` : "";
113
107
  return `Son ${span} i\xE7indeki oran hareketi: ${opening} ile a\xE7\u0131ld\u0131, \u015Fu anda ${current}${drift}.`;
114
108
  },
115
- clubMatchPreviewHeading: "Ma\xE7 \xF6nizlemesi",
116
- clubTeamDnaHeading: "Nas\u0131l oynuyorlar",
117
- clubFormHeading: "Son form",
118
- clubCountdownLabel: "Ba\u015Flama vuru\u015Funa kalan",
119
- clubKickoff: (ms) => new Intl.DateTimeFormat("tr-TR", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(ms)),
120
- clubKickoffAria: (ms) => `Ba\u015Flama vuru\u015Fu ${new Intl.DateTimeFormat("tr-TR", { weekday: "long", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" }).format(new Date(ms))}`,
121
109
  inSlip: "Kuponda",
122
110
  slipAdded: (n) => n === void 0 ? "Kupona eklendi" : `Kupona eklendi (${n} se\xE7im)`,
123
111
  slipDuplicate: "Bu se\xE7im kuponunuzda zaten var",
@@ -181,12 +169,6 @@ function normalizeUi(cfg) {
181
169
  excludedSuspended: strings.excludedSuspended,
182
170
  chartTimeLabel: strings.chartTimeLabel,
183
171
  chartAria: strings.chartAria,
184
- clubMatchPreviewHeading: strings.clubMatchPreviewHeading,
185
- clubTeamDnaHeading: strings.clubTeamDnaHeading,
186
- clubFormHeading: strings.clubFormHeading,
187
- clubCountdownLabel: strings.clubCountdownLabel,
188
- clubKickoff: strings.clubKickoff,
189
- clubKickoffAria: strings.clubKickoffAria,
190
172
  addToSlip: strings.addToSlip,
191
173
  inSlip: strings.inSlip,
192
174
  slipAdded: strings.slipAdded,
@@ -549,8 +531,7 @@ function applyEvent(state, event) {
549
531
  messages: mapActive(state, (t) => ({
550
532
  ...t,
551
533
  done: true,
552
- greetingDashboard: event.data.dashboard ?? void 0,
553
- clubDashboard: event.data.clubDashboard ?? void 0
534
+ greetingDashboard: event.data.dashboard ?? void 0
554
535
  }))
555
536
  };
556
537
  }
@@ -747,7 +728,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
747
728
  }
748
729
 
749
730
  // src/components/ChatPanel.tsx
750
- import { useEffect as useEffect5, useState as useState9 } from "react";
731
+ import { useEffect as useEffect4, useState as useState7 } from "react";
751
732
 
752
733
  // src/components/ChatHeader.tsx
753
734
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -760,7 +741,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
760
741
  }
761
742
 
762
743
  // src/components/MessageList.tsx
763
- import { useEffect as useEffect4, useRef as useRef2 } from "react";
744
+ import { useEffect as useEffect3, useRef as useRef2 } from "react";
764
745
 
765
746
  // src/components/Markdown.tsx
766
747
  import ReactMarkdown from "react-markdown";
@@ -1306,259 +1287,28 @@ function GreetingDashboard({ dashboard, onTap }) {
1306
1287
  ] });
1307
1288
  }
1308
1289
 
1309
- // src/components/club-dashboard/GreetingHeaderBlock.tsx
1310
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1311
- function GreetingHeaderBlock({ block }) {
1312
- return /* @__PURE__ */ jsxs13("div", { className: "ss-w-cdash-greeting", children: [
1313
- /* @__PURE__ */ jsx17("div", { className: "ss-w-cdash-greeting-title", children: block.title }),
1314
- /* @__PURE__ */ jsx17("div", { className: "ss-w-cdash-greeting-subtitle", children: block.subtitle })
1315
- ] });
1316
- }
1317
-
1318
- // src/components/club-dashboard/FixtureHeroBlock.tsx
1319
- import { useState as useState6 } from "react";
1320
- import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1321
- function initials3(name) {
1322
- return name.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
1323
- }
1324
- function Crest3({ url, name }) {
1325
- const [broken, setBroken] = useState6(false);
1326
- if (!url || broken) {
1327
- return /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-crest ss-w-cdash-crest--fallback", "aria-hidden": "true", children: initials3(name) });
1328
- }
1329
- return /* @__PURE__ */ jsx18("img", { className: "ss-w-cdash-crest", src: url, alt: "", "aria-hidden": "true", onError: () => setBroken(true) });
1330
- }
1331
- function FixtureHeroBlock({
1332
- block,
1333
- ui,
1334
- onAction
1335
- }) {
1336
- return /* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-fixture", children: [
1337
- /* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-tie", children: [
1338
- /* @__PURE__ */ jsx18(Crest3, { url: block.homeCrestUrl, name: block.homeName }),
1339
- /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-team", children: block.homeName }),
1340
- /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-vs", children: "v" }),
1341
- /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-team", children: block.awayName }),
1342
- /* @__PURE__ */ jsx18(Crest3, { url: block.awayCrestUrl, name: block.awayName })
1343
- ] }),
1344
- /* @__PURE__ */ jsxs14("div", { className: "ss-w-cdash-fixture-meta", children: [
1345
- /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-kickoff", children: ui.clubKickoff(block.kickoffUnix * 1e3) }),
1346
- block.venue ? /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-venue", children: block.venue }) : null,
1347
- block.competition ? /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-comp", children: block.competition }) : null
1348
- ] }),
1349
- /* @__PURE__ */ jsx18("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.ctaLabel, { actionRef: block.ctaActionRef }), children: block.ctaLabel })
1350
- ] });
1351
- }
1352
-
1353
- // src/components/club-dashboard/ResultPills.tsx
1354
- import { Fragment as Fragment5, jsx as jsx19 } from "react/jsx-runtime";
1355
- function ResultPills({ results }) {
1356
- return /* @__PURE__ */ jsx19(Fragment5, { children: results.map((r, i) => /* @__PURE__ */ jsx19("span", { className: `ss-w-cdash-pill ss-w-cdash-pill--${r.toLowerCase()}`, children: r }, i)) });
1357
- }
1358
-
1359
- // src/components/club-dashboard/FormGuideBlock.tsx
1360
- import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
1361
- function FormGuideBlock({ block }) {
1362
- if (block.rows.length === 0) return null;
1363
- return /* @__PURE__ */ jsx20("div", { className: "ss-w-cdash-form", children: block.rows.map((row) => /* @__PURE__ */ jsxs15("div", { className: "ss-w-cdash-form-row", children: [
1364
- /* @__PURE__ */ jsxs15("span", { className: "ss-w-cdash-form-name", children: [
1365
- row.name,
1366
- row.position != null ? ` #${row.position}` : ""
1367
- ] }),
1368
- /* @__PURE__ */ jsx20("span", { className: "ss-w-cdash-form-pills", children: /* @__PURE__ */ jsx20(ResultPills, { results: row.last5 }) })
1369
- ] }, row.name)) });
1370
- }
1371
-
1372
- // src/components/club-dashboard/MatchPreviewBlock.tsx
1373
- import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
1374
- function MatchPreviewBlock({
1375
- block,
1376
- ui,
1377
- onAction
1378
- }) {
1379
- if (block.facts.length === 0) return null;
1380
- const heading = ui.clubMatchPreviewHeading;
1381
- return /* @__PURE__ */ jsxs16("div", { className: "ss-w-cdash-lines", children: [
1382
- /* @__PURE__ */ jsx21("span", { className: "ss-w-cdash-lines-heading", children: heading }),
1383
- block.facts.map(
1384
- (f, i) => f.actionRef ? /* @__PURE__ */ jsxs16(
1385
- "button",
1386
- {
1387
- type: "button",
1388
- className: "ss-w-cdash-fact",
1389
- onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
1390
- children: [
1391
- f.sentence,
1392
- f.label ? /* @__PURE__ */ jsxs16("span", { className: "ss-w-cdash-fact-label", children: [
1393
- " ",
1394
- f.label
1395
- ] }) : null
1396
- ]
1397
- },
1398
- i
1399
- ) : /* @__PURE__ */ jsx21("p", { children: f.sentence }, i)
1400
- )
1401
- ] });
1402
- }
1403
-
1404
- // src/components/club-dashboard/MatchPreviewCardBlock.tsx
1405
- import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
1406
- function position(p) {
1407
- return p != null ? `#${p}` : "\u2014";
1408
- }
1409
- function MatchPreviewCardBlock({ block }) {
1410
- return /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview", children: [
1411
- /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview-header", children: [
1412
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-team", children: block.homeName }),
1413
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-vs", children: "v" }),
1414
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-team", children: block.awayName })
1415
- ] }),
1416
- /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview-row", children: [
1417
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-value", children: position(block.homePosition) }),
1418
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-label", children: block.tableLabel }),
1419
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-value", children: position(block.awayPosition) })
1420
- ] }),
1421
- /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview-row", children: [
1422
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-pills", children: /* @__PURE__ */ jsx22(ResultPills, { results: block.homeLast5 }) }),
1423
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-label", children: block.last5Label }),
1424
- /* @__PURE__ */ jsx22("span", { className: "ss-w-cdash-preview-pills", children: /* @__PURE__ */ jsx22(ResultPills, { results: block.awayLast5 }) })
1425
- ] }),
1426
- block.edgeTeamName ? /* @__PURE__ */ jsxs17("div", { className: "ss-w-cdash-preview-edge", children: [
1427
- /* @__PURE__ */ jsx22("span", { "aria-hidden": "true", children: "\u25B8" }),
1428
- /* @__PURE__ */ jsx22("strong", { children: block.edgeTeamName }),
1429
- block.edgeReason ? /* @__PURE__ */ jsxs17("span", { children: [
1430
- " \u2014 ",
1431
- block.edgeReason
1432
- ] }) : null
1433
- ] }) : null,
1434
- block.h2HLines.length > 0 ? /* @__PURE__ */ jsx22("div", { className: "ss-w-cdash-preview-h2h", children: block.h2HLines.map((line, i) => /* @__PURE__ */ jsx22("p", { children: line }, i)) }) : null
1435
- ] });
1436
- }
1437
-
1438
- // src/components/club-dashboard/TeamDnaBlock.tsx
1439
- import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
1440
- function TeamDnaBlock({
1441
- block,
1442
- ui,
1443
- onAction
1444
- }) {
1445
- if (block.facts.length === 0) return null;
1446
- const heading = ui.clubTeamDnaHeading;
1447
- return /* @__PURE__ */ jsxs18("div", { className: "ss-w-cdash-lines", children: [
1448
- /* @__PURE__ */ jsx23("span", { className: "ss-w-cdash-lines-heading", children: heading }),
1449
- block.facts.map(
1450
- (f, i) => f.actionRef ? /* @__PURE__ */ jsxs18(
1451
- "button",
1452
- {
1453
- type: "button",
1454
- className: "ss-w-cdash-fact",
1455
- onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
1456
- children: [
1457
- f.sentence,
1458
- f.label ? /* @__PURE__ */ jsxs18("span", { className: "ss-w-cdash-fact-label", children: [
1459
- " ",
1460
- f.label
1461
- ] }) : null
1462
- ]
1463
- },
1464
- i
1465
- ) : /* @__PURE__ */ jsx23("p", { children: f.sentence }, i)
1466
- )
1467
- ] });
1468
- }
1469
-
1470
- // src/components/club-dashboard/CountdownBlock.tsx
1471
- import { useEffect as useEffect3, useState as useState7 } from "react";
1472
- import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
1473
- var DAY_MS = 24 * 3600 * 1e3;
1474
- function pad2(n) {
1475
- return String(n).padStart(2, "0");
1476
- }
1477
- function splitRemaining(remainingMs) {
1478
- const totalSeconds = Math.max(0, Math.floor(remainingMs / 1e3));
1479
- const h = Math.floor(totalSeconds / 3600);
1480
- const m = Math.floor(totalSeconds % 3600 / 60);
1481
- const s = totalSeconds % 60;
1482
- return { h: pad2(h), m: pad2(m), s: pad2(s) };
1483
- }
1484
- function CountdownBlock({ block, ui }) {
1485
- const [remainingMs, setRemainingMs] = useState7(() => block.kickoffUnix * 1e3 - Date.now());
1486
- useEffect3(() => {
1487
- setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
1488
- if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
1489
- const id = setInterval(() => {
1490
- setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
1491
- }, 1e3);
1492
- return () => clearInterval(id);
1493
- }, [block.kickoffUnix]);
1494
- if (remainingMs <= 0) return null;
1495
- if (remainingMs > DAY_MS) return null;
1496
- const { h, m, s } = splitRemaining(remainingMs);
1497
- return /* @__PURE__ */ jsxs19("div", { className: "ss-w-cdash-cd", "aria-label": ui.clubKickoffAria(block.kickoffUnix * 1e3), children: [
1498
- /* @__PURE__ */ jsxs19("div", { className: "ss-w-cdash-cd-clock", "aria-hidden": "true", children: [
1499
- /* @__PURE__ */ jsx24("span", { className: "ss-w-cdash-cd-h", children: h }),
1500
- "h",
1501
- " ",
1502
- /* @__PURE__ */ jsx24("span", { className: "ss-w-cdash-cd-m", children: m }),
1503
- "m",
1504
- " ",
1505
- /* @__PURE__ */ jsx24("span", { className: "ss-w-cdash-cd-s", children: s }),
1506
- "s"
1507
- ] }),
1508
- /* @__PURE__ */ jsx24("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
1509
- ] });
1510
- }
1511
-
1512
- // src/components/club-dashboard/ClubDashboard.tsx
1513
- import { jsx as jsx25 } from "react/jsx-runtime";
1514
- var CLUB_BLOCK_REGISTRY = {
1515
- greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ jsx25(GreetingHeaderBlock, { block }) : null,
1516
- fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ jsx25(FixtureHeroBlock, { block, ui, onAction }) : null,
1517
- formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ jsx25(FormGuideBlock, { block, ui }) : null,
1518
- matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ jsx25(MatchPreviewBlock, { block, ui, onAction }) : null,
1519
- matchPreviewCard: ({ block, ui }) => block.type === "matchPreviewCard" ? /* @__PURE__ */ jsx25(MatchPreviewCardBlock, { block, ui }) : null,
1520
- teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */ jsx25(TeamDnaBlock, { block, ui, onAction }) : null,
1521
- countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */ jsx25(CountdownBlock, { block, ui }) : null
1522
- };
1523
- function ClubDashboard({
1524
- dashboard,
1525
- ui,
1526
- onAction
1527
- }) {
1528
- if (!dashboard.blocks.length) return null;
1529
- return /* @__PURE__ */ jsx25("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
1530
- const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
1531
- if (!Comp) {
1532
- console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
1533
- return null;
1534
- }
1535
- return /* @__PURE__ */ jsx25("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ jsx25(Comp, { block, ui, onAction }) }, i);
1536
- }) });
1537
- }
1538
-
1539
1290
  // src/components/ChatMessage.tsx
1540
- import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
1541
- function ChatMessage({ message, disabled, onAct, onTap, onClubAction, ui, slip }) {
1291
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1292
+ function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
1542
1293
  if (message.role === "user") {
1543
- return /* @__PURE__ */ jsx26("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx26("div", { className: "ss-w-bubble", children: message.text }) });
1294
+ return /* @__PURE__ */ jsx17("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx17("div", { className: "ss-w-bubble", children: message.text }) });
1544
1295
  }
1545
- return /* @__PURE__ */ jsxs20("div", { className: "ss-w-msg ss-w-bot", children: [
1546
- message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */ jsx26(Markdown, { text: message.text }) : null,
1547
- message.greetingDashboard ? /* @__PURE__ */ jsx26(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1548
- message.clubDashboard && ui ? /* @__PURE__ */ jsx26(ClubDashboard, { dashboard: message.clubDashboard, ui, onAction: onClubAction }) : null,
1549
- /* @__PURE__ */ jsx26(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1550
- /* @__PURE__ */ jsx26(BettingInsightList, { insights: message.insights, ui, slip }),
1551
- /* @__PURE__ */ jsx26(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1552
- /* @__PURE__ */ jsx26(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1553
- /* @__PURE__ */ jsx26(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1296
+ return /* @__PURE__ */ jsxs13("div", { className: "ss-w-msg ss-w-bot", children: [
1297
+ message.text && !message.greetingDashboard ? /* @__PURE__ */ jsx17(Markdown, { text: message.text }) : null,
1298
+ message.greetingDashboard ? /* @__PURE__ */ jsx17(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1299
+ /* @__PURE__ */ jsx17(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1300
+ /* @__PURE__ */ jsx17(BettingInsightList, { insights: message.insights, ui, slip }),
1301
+ /* @__PURE__ */ jsx17(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1302
+ /* @__PURE__ */ jsx17(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1303
+ /* @__PURE__ */ jsx17(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1554
1304
  ] });
1555
1305
  }
1556
1306
 
1557
1307
  // src/components/IntentChips.tsx
1558
- import { jsx as jsx27 } from "react/jsx-runtime";
1308
+ import { jsx as jsx18 } from "react/jsx-runtime";
1559
1309
  function IntentChips({ chips, onPick }) {
1560
1310
  if (chips.length === 0) return null;
1561
- return /* @__PURE__ */ jsx27("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx27("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1311
+ return /* @__PURE__ */ jsx18("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ jsx18("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1562
1312
  }
1563
1313
 
1564
1314
  // src/scroll.ts
@@ -1568,18 +1318,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
1568
1318
  }
1569
1319
 
1570
1320
  // src/components/MessageList.tsx
1571
- import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
1321
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
1572
1322
  function MessageList({ controller, ui, slip, onDashboardTap }) {
1573
1323
  const { state, send } = controller;
1574
1324
  const listRef = useRef2(null);
1575
1325
  const endRef = useRef2(null);
1576
1326
  const pinnedRef = useRef2(true);
1577
- useEffect4(() => {
1327
+ useEffect3(() => {
1578
1328
  if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
1579
1329
  }, [state.messages, state.status]);
1580
1330
  const hasUserMessage = state.messages.some((m) => m.role === "user");
1581
1331
  const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
1582
- return /* @__PURE__ */ jsxs21(
1332
+ return /* @__PURE__ */ jsxs14(
1583
1333
  "div",
1584
1334
  {
1585
1335
  className: "ss-w-list",
@@ -1589,7 +1339,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1589
1339
  if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
1590
1340
  },
1591
1341
  children: [
1592
- state.messages.map((m) => /* @__PURE__ */ jsx28(
1342
+ state.messages.map((m) => /* @__PURE__ */ jsx19(
1593
1343
  ChatMessage,
1594
1344
  {
1595
1345
  message: m,
@@ -1599,31 +1349,30 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1599
1349
  send(tile.actionValue, { displayText: tile.title });
1600
1350
  if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
1601
1351
  },
1602
- onClubAction: (label, opts) => send(label, { actionRef: opts.actionRef }),
1603
1352
  ui,
1604
1353
  slip
1605
1354
  },
1606
1355
  m.id
1607
1356
  )),
1608
- state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx28(ActionButtons, { actions: [], loading: true, onAct: () => {
1357
+ state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx19(ActionButtons, { actions: [], loading: true, onAct: () => {
1609
1358
  } }) : null,
1610
- state.status ? /* @__PURE__ */ jsx28("div", { className: "ss-w-status", children: state.status }) : null,
1611
- state.error ? /* @__PURE__ */ jsxs21("div", { className: "ss-w-error", role: "alert", children: [
1612
- /* @__PURE__ */ jsx28("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1613
- /* @__PURE__ */ jsx28("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1359
+ state.status ? /* @__PURE__ */ jsx19("div", { className: "ss-w-status", children: state.status }) : null,
1360
+ state.error ? /* @__PURE__ */ jsxs14("div", { className: "ss-w-error", role: "alert", children: [
1361
+ /* @__PURE__ */ jsx19("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1362
+ /* @__PURE__ */ jsx19("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1614
1363
  ] }) : null,
1615
- !hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx28(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1616
- /* @__PURE__ */ jsx28("div", { ref: endRef })
1364
+ !hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx19(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1365
+ /* @__PURE__ */ jsx19("div", { ref: endRef })
1617
1366
  ]
1618
1367
  }
1619
1368
  );
1620
1369
  }
1621
1370
 
1622
1371
  // src/components/ChatInput.tsx
1623
- import { useState as useState8 } from "react";
1624
- import { jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
1372
+ import { useState as useState6 } from "react";
1373
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
1625
1374
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
1626
- const [value, setValue] = useState8("");
1375
+ const [value, setValue] = useState6("");
1627
1376
  const submit = () => {
1628
1377
  const t = value.trim();
1629
1378
  if (!t) return;
@@ -1636,18 +1385,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
1636
1385
  submit();
1637
1386
  }
1638
1387
  };
1639
- return /* @__PURE__ */ jsxs22("div", { className: "ss-w-input", children: [
1640
- /* @__PURE__ */ jsx29("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1641
- streaming ? /* @__PURE__ */ jsx29("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx29("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx29("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx29(SendIcon, {}) })
1388
+ return /* @__PURE__ */ jsxs15("div", { className: "ss-w-input", children: [
1389
+ /* @__PURE__ */ jsx20("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1390
+ streaming ? /* @__PURE__ */ jsx20("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ jsx20("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ jsx20("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ jsx20(SendIcon, {}) })
1642
1391
  ] });
1643
1392
  }
1644
1393
 
1645
1394
  // src/components/ChatPanel.tsx
1646
- import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
1395
+ import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
1647
1396
  var FULLSCREEN_QUERY = "(max-width: 639px)";
1648
1397
  function useIsModal() {
1649
- const [modal, setModal] = useState9(false);
1650
- useEffect5(() => {
1398
+ const [modal, setModal] = useState7(false);
1399
+ useEffect4(() => {
1651
1400
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1652
1401
  const mql = window.matchMedia(FULLSCREEN_QUERY);
1653
1402
  const sync = () => setModal(mql.matches);
@@ -1660,17 +1409,17 @@ function useIsModal() {
1660
1409
  function ChatPanel({ controller, ui, slip, onDashboardTap }) {
1661
1410
  const { state, close, stop, send } = controller;
1662
1411
  const isModal = useIsModal();
1663
- useEffect5(() => {
1412
+ useEffect4(() => {
1664
1413
  const onKey = (e) => {
1665
1414
  if (e.key === "Escape") close();
1666
1415
  };
1667
1416
  window.addEventListener("keydown", onKey);
1668
1417
  return () => window.removeEventListener("keydown", onKey);
1669
1418
  }, [close]);
1670
- return /* @__PURE__ */ jsxs23("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1671
- /* @__PURE__ */ jsx30(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1672
- /* @__PURE__ */ jsx30(MessageList, { controller, ui, slip, onDashboardTap }),
1673
- /* @__PURE__ */ jsx30(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1419
+ return /* @__PURE__ */ jsxs16("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1420
+ /* @__PURE__ */ jsx21(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1421
+ /* @__PURE__ */ jsx21(MessageList, { controller, ui, slip, onDashboardTap }),
1422
+ /* @__PURE__ */ jsx21(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1674
1423
  ] });
1675
1424
  }
1676
1425
 
@@ -2023,66 +1772,10 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
2023
1772
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
2024
1773
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
2025
1774
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
2026
-
2027
- /* club match-day dashboard */
2028
- .ss-w-cdash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
2029
- .ss-w-cdash-block { display: flex; flex-direction: column; }
2030
-
2031
- .ss-w-cdash-greeting { display: flex; flex-direction: column; gap: 2px; }
2032
- .ss-w-cdash-greeting-title { font-weight: 700; font-size: 14px; color: var(--ss-w-ink); }
2033
- .ss-w-cdash-greeting-subtitle { font-size: 11.5px; color: var(--ss-w-faint); }
2034
-
2035
- .ss-w-cdash-fixture { display: flex; flex-direction: column; align-items: center; gap: 8px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 12px; text-align: center; }
2036
- .ss-w-cdash-tie { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; }
2037
- .ss-w-cdash-team { font-weight: 650; font-size: 13px; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
2038
- .ss-w-cdash-vs { font-size: 11px; color: var(--ss-w-faint); font-weight: 600; }
2039
- .ss-w-cdash-crest { flex: none; width: 28px; height: 28px; border-radius: 50%; object-fit: cover; background: var(--ss-w-bubble); }
2040
- .ss-w-cdash-crest--fallback { display: grid; place-items: center; font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
2041
- .ss-w-cdash-fixture-meta { display: flex; align-items: center; justify-content: center; gap: 6px; flex-wrap: wrap; font-size: 11px; color: var(--ss-w-faint); }
2042
- .ss-w-cdash-kickoff { font-weight: 700; color: var(--ss-w-ink); }
2043
- .ss-w-cdash-cta { font: inherit; font-weight: 700; font-size: 12px; color: var(--ss-w-cta-ink); background: var(--ss-w-cta); border: none; border-radius: 999px; padding: 8px 18px; cursor: pointer; }
2044
-
2045
- .ss-w-cdash-form { display: flex; flex-direction: column; gap: 6px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 10px 12px; }
2046
- .ss-w-cdash-form-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
2047
- .ss-w-cdash-form-name { font-size: 12px; font-weight: 600; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
2048
- .ss-w-cdash-form-pills { flex: none; display: flex; align-items: center; gap: 3px; }
2049
- .ss-w-cdash-pill { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; font-size: 9.5px; font-weight: 700; color: #fff; }
2050
- .ss-w-cdash-pill--w { background: color-mix(in srgb, var(--ss-w-pos) 88%, black); }
2051
- .ss-w-cdash-pill--d { background: var(--ss-w-faint); }
2052
- .ss-w-cdash-pill--l { background: color-mix(in srgb, var(--ss-w-neg) 88%, black); }
2053
-
2054
- .ss-w-cdash-lines { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; width: 100%; text-align: left; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-left: 3px solid var(--ss-w-accent); border-radius: 12px; padding: 10px 12px; }
2055
- .ss-w-cdash-lines-heading { font-size: 12px; font-weight: 700; color: var(--ss-w-accent); }
2056
- .ss-w-cdash-lines p { font-size: 12px; line-height: 1.4; color: var(--ss-w-ink); margin: 0; }
2057
- .ss-w-cdash-fact { display: block; width: 100%; text-align: left; font: inherit; font-size: 12px; line-height: 1.4; color: var(--ss-w-ink); background: none; border: none; padding: 0; cursor: pointer; }
2058
- .ss-w-cdash-fact:hover, .ss-w-cdash-fact:focus-visible { color: var(--ss-w-accent); text-decoration: underline; }
2059
- .ss-w-cdash-fact-label { font-size: 11px; font-weight: 700; color: var(--ss-w-accent); }
2060
-
2061
- .ss-w-cdash-cd { display: flex; flex-direction: column; align-items: center; gap: 4px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 10px 12px; text-align: center; }
2062
- .ss-w-cdash-cd-clock { display: flex; align-items: baseline; justify-content: center; gap: 2px; font-variant-numeric: tabular-nums; font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; font-weight: 700; font-size: 18px; color: var(--ss-w-ink); }
2063
- .ss-w-cdash-cd-h, .ss-w-cdash-cd-m, .ss-w-cdash-cd-s { color: var(--ss-w-accent); }
2064
- .ss-w-cdash-cd-label { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
2065
-
2066
- .ss-w-cdash-preview { display: flex; flex-direction: column; gap: 8px; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 10px 12px; }
2067
- .ss-w-cdash-preview-header { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 6px; }
2068
- .ss-w-cdash-preview-header .ss-w-cdash-team:first-child { justify-self: start; text-align: left; }
2069
- .ss-w-cdash-preview-header .ss-w-cdash-team:last-child { justify-self: end; text-align: right; }
2070
- .ss-w-cdash-preview-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 6px; }
2071
- .ss-w-cdash-preview-label { font-size: 10.5px; font-weight: 600; color: var(--ss-w-faint); text-align: center; text-transform: uppercase; letter-spacing: 0.03em; }
2072
- .ss-w-cdash-preview-value { font-size: 12px; font-weight: 700; color: var(--ss-w-ink); text-align: center; }
2073
- .ss-w-cdash-preview-pills { display: flex; align-items: center; justify-content: center; gap: 3px; }
2074
- .ss-w-cdash-preview-row:first-of-type .ss-w-cdash-preview-value { justify-self: start; }
2075
- .ss-w-cdash-preview-row:first-of-type .ss-w-cdash-preview-value:last-child { justify-self: end; }
2076
- .ss-w-cdash-preview-row:last-of-type .ss-w-cdash-preview-pills:first-child { justify-self: start; }
2077
- .ss-w-cdash-preview-row:last-of-type .ss-w-cdash-preview-pills:last-child { justify-self: end; }
2078
- .ss-w-cdash-preview-edge { display: flex; align-items: baseline; gap: 4px; font-size: 12px; line-height: 1.4; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 10%, transparent); border-radius: 8px; padding: 6px 8px; }
2079
- .ss-w-cdash-preview-edge strong { color: var(--ss-w-ink); }
2080
- .ss-w-cdash-preview-h2h { display: flex; flex-direction: column; gap: 2px; }
2081
- .ss-w-cdash-preview-h2h p { font-size: 11.5px; line-height: 1.4; color: var(--ss-w-faint); margin: 0; }
2082
1775
  `;
2083
1776
 
2084
1777
  // src/StatsWidget.tsx
2085
- import { jsx as jsx31 } from "react/jsx-runtime";
1778
+ import { jsx as jsx22 } from "react/jsx-runtime";
2086
1779
  function buildClient(props) {
2087
1780
  try {
2088
1781
  if ("client" in props && props.client) {
@@ -2128,14 +1821,14 @@ function StatsWidget(props) {
2128
1821
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
2129
1822
  [built]
2130
1823
  );
2131
- useEffect6(() => {
1824
+ useEffect5(() => {
2132
1825
  if (!built || !ui.injectStyles) return;
2133
1826
  const node = rootRef.current?.getRootNode();
2134
1827
  if (node) injectStyles(node);
2135
1828
  }, [built, ui.injectStyles]);
2136
1829
  if (!built) return null;
2137
1830
  const attrs = themeAttrs(ui);
2138
- return /* @__PURE__ */ jsx31("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__ */ jsx31(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ jsx31(
1831
+ return /* @__PURE__ */ jsx22("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__ */ jsx22(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ jsx22(
2139
1832
  ChatFab,
2140
1833
  {
2141
1834
  label: ui.launcherLabel,