@sensiblestats/widget-react 0.20.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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @sensiblestats/widget-react
2
2
 
3
+ ## 0.22.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Remove club match-day dashboard renderers and SDK types. The server no longer emits the `clubDashboard` block; the corresponding widget renderers, CSS, and SDK type union are stripped in this forward bump.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @sensiblestats/widget-sdk@0.19.0
13
+
14
+ ## 0.21.0
15
+
16
+ ### Minor Changes
17
+
18
+ - Match Preview card: deterministic matchPreviewCard block type (sdk) + renderer (react).
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies
23
+ - @sensiblestats/widget-sdk@0.18.0
24
+
3
25
  ## 0.20.0
4
26
 
5
27
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -36,7 +36,7 @@ __export(index_exports, {
36
36
  module.exports = __toCommonJS(index_exports);
37
37
 
38
38
  // src/StatsWidget.tsx
39
- var import_react13 = require("react");
39
+ var import_react11 = require("react");
40
40
  var import_widget_sdk5 = require("@sensiblestats/widget-sdk");
41
41
 
42
42
  // src/kickoff.ts
@@ -92,12 +92,6 @@ var STRINGS = {
92
92
  const drift = direction ? `, ${direction}` : "";
93
93
  return `Price movement over the last ${span}: opened at ${opening}, currently ${current}${drift}.`;
94
94
  },
95
- clubMatchPreviewHeading: "Match preview",
96
- clubTeamDnaHeading: "How they play",
97
- clubFormHeading: "Recent form",
98
- clubCountdownLabel: "Countdown to kick-off",
99
- clubKickoff: (ms) => new Intl.DateTimeFormat("en-GB", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(ms)),
100
- 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))}`,
101
95
  inSlip: "In slip",
102
96
  slipAdded: (n) => n === void 0 ? "Added to slip" : `Added to slip (${n} selection${n === 1 ? "" : "s"})`,
103
97
  slipDuplicate: "Already in your slip",
@@ -149,12 +143,6 @@ var STRINGS = {
149
143
  const drift = direction ? `, ${direction}` : "";
150
144
  return `Son ${span} i\xE7indeki oran hareketi: ${opening} ile a\xE7\u0131ld\u0131, \u015Fu anda ${current}${drift}.`;
151
145
  },
152
- clubMatchPreviewHeading: "Ma\xE7 \xF6nizlemesi",
153
- clubTeamDnaHeading: "Nas\u0131l oynuyorlar",
154
- clubFormHeading: "Son form",
155
- clubCountdownLabel: "Ba\u015Flama vuru\u015Funa kalan",
156
- clubKickoff: (ms) => new Intl.DateTimeFormat("tr-TR", { weekday: "short", day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }).format(new Date(ms)),
157
- 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))}`,
158
146
  inSlip: "Kuponda",
159
147
  slipAdded: (n) => n === void 0 ? "Kupona eklendi" : `Kupona eklendi (${n} se\xE7im)`,
160
148
  slipDuplicate: "Bu se\xE7im kuponunuzda zaten var",
@@ -218,12 +206,6 @@ function normalizeUi(cfg) {
218
206
  excludedSuspended: strings.excludedSuspended,
219
207
  chartTimeLabel: strings.chartTimeLabel,
220
208
  chartAria: strings.chartAria,
221
- clubMatchPreviewHeading: strings.clubMatchPreviewHeading,
222
- clubTeamDnaHeading: strings.clubTeamDnaHeading,
223
- clubFormHeading: strings.clubFormHeading,
224
- clubCountdownLabel: strings.clubCountdownLabel,
225
- clubKickoff: strings.clubKickoff,
226
- clubKickoffAria: strings.clubKickoffAria,
227
209
  addToSlip: strings.addToSlip,
228
210
  inSlip: strings.inSlip,
229
211
  slipAdded: strings.slipAdded,
@@ -586,8 +568,7 @@ function applyEvent(state, event) {
586
568
  messages: mapActive(state, (t) => ({
587
569
  ...t,
588
570
  done: true,
589
- greetingDashboard: event.data.dashboard ?? void 0,
590
- clubDashboard: event.data.clubDashboard ?? void 0
571
+ greetingDashboard: event.data.dashboard ?? void 0
591
572
  }))
592
573
  };
593
574
  }
@@ -784,7 +765,7 @@ function ChatFab({ label, greeting, popupText, onOpen, onDismissPopup, dismissLa
784
765
  }
785
766
 
786
767
  // src/components/ChatPanel.tsx
787
- var import_react12 = require("react");
768
+ var import_react10 = require("react");
788
769
 
789
770
  // src/components/ChatHeader.tsx
790
771
  var import_jsx_runtime4 = require("react/jsx-runtime");
@@ -797,7 +778,7 @@ function ChatHeader({ onClose, closeLabel = "Close chat" }) {
797
778
  }
798
779
 
799
780
  // src/components/MessageList.tsx
800
- var import_react10 = require("react");
781
+ var import_react8 = require("react");
801
782
 
802
783
  // src/components/Markdown.tsx
803
784
  var import_react_markdown = __toESM(require("react-markdown"), 1);
@@ -1343,218 +1324,28 @@ function GreetingDashboard({ dashboard, onTap }) {
1343
1324
  ] });
1344
1325
  }
1345
1326
 
1346
- // src/components/club-dashboard/GreetingHeaderBlock.tsx
1347
- var import_jsx_runtime17 = require("react/jsx-runtime");
1348
- function GreetingHeaderBlock({ block }) {
1349
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-cdash-greeting", children: [
1350
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-cdash-greeting-title", children: block.title }),
1351
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-cdash-greeting-subtitle", children: block.subtitle })
1352
- ] });
1353
- }
1354
-
1355
- // src/components/club-dashboard/FixtureHeroBlock.tsx
1356
- var import_react8 = require("react");
1357
- var import_jsx_runtime18 = require("react/jsx-runtime");
1358
- function initials3(name) {
1359
- return name.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
1360
- }
1361
- function Crest3({ url, name }) {
1362
- const [broken, setBroken] = (0, import_react8.useState)(false);
1363
- if (!url || broken) {
1364
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-crest ss-w-cdash-crest--fallback", "aria-hidden": "true", children: initials3(name) });
1365
- }
1366
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("img", { className: "ss-w-cdash-crest", src: url, alt: "", "aria-hidden": "true", onError: () => setBroken(true) });
1367
- }
1368
- function FixtureHeroBlock({
1369
- block,
1370
- ui,
1371
- onAction
1372
- }) {
1373
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-cdash-fixture", children: [
1374
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-cdash-tie", children: [
1375
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Crest3, { url: block.homeCrestUrl, name: block.homeName }),
1376
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-team", children: block.homeName }),
1377
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-vs", children: "v" }),
1378
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-team", children: block.awayName }),
1379
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Crest3, { url: block.awayCrestUrl, name: block.awayName })
1380
- ] }),
1381
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "ss-w-cdash-fixture-meta", children: [
1382
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-kickoff", children: ui.clubKickoff(block.kickoffUnix * 1e3) }),
1383
- block.venue ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-venue", children: block.venue }) : null,
1384
- block.competition ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-comp", children: block.competition }) : null
1385
- ] }),
1386
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.ctaLabel, { actionRef: block.ctaActionRef }), children: block.ctaLabel })
1387
- ] });
1388
- }
1389
-
1390
- // src/components/club-dashboard/FormGuideBlock.tsx
1391
- var import_jsx_runtime19 = require("react/jsx-runtime");
1392
- function FormGuideBlock({ block }) {
1393
- if (block.rows.length === 0) return null;
1394
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ss-w-cdash-form", children: block.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-cdash-form-row", children: [
1395
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "ss-w-cdash-form-name", children: [
1396
- row.name,
1397
- row.position != null ? ` #${row.position}` : ""
1398
- ] }),
1399
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ss-w-cdash-form-pills", children: row.last5.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: `ss-w-cdash-pill ss-w-cdash-pill--${r.toLowerCase()}`, children: r }, i)) })
1400
- ] }, row.name)) });
1401
- }
1402
-
1403
- // src/components/club-dashboard/MatchPreviewBlock.tsx
1404
- var import_jsx_runtime20 = require("react/jsx-runtime");
1405
- function MatchPreviewBlock({
1406
- block,
1407
- ui,
1408
- onAction
1409
- }) {
1410
- if (block.facts.length === 0) return null;
1411
- const heading = ui.clubMatchPreviewHeading;
1412
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-cdash-lines", children: [
1413
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
1414
- block.facts.map(
1415
- (f, i) => f.actionRef ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1416
- "button",
1417
- {
1418
- type: "button",
1419
- className: "ss-w-cdash-fact",
1420
- onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
1421
- children: [
1422
- f.sentence,
1423
- f.label ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ss-w-cdash-fact-label", children: [
1424
- " ",
1425
- f.label
1426
- ] }) : null
1427
- ]
1428
- },
1429
- i
1430
- ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: f.sentence }, i)
1431
- )
1432
- ] });
1433
- }
1434
-
1435
- // src/components/club-dashboard/TeamDnaBlock.tsx
1436
- var import_jsx_runtime21 = require("react/jsx-runtime");
1437
- function TeamDnaBlock({
1438
- block,
1439
- ui,
1440
- onAction
1441
- }) {
1442
- if (block.facts.length === 0) return null;
1443
- const heading = ui.clubTeamDnaHeading;
1444
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-cdash-lines", children: [
1445
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
1446
- block.facts.map(
1447
- (f, i) => f.actionRef ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1448
- "button",
1449
- {
1450
- type: "button",
1451
- className: "ss-w-cdash-fact",
1452
- onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
1453
- children: [
1454
- f.sentence,
1455
- f.label ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "ss-w-cdash-fact-label", children: [
1456
- " ",
1457
- f.label
1458
- ] }) : null
1459
- ]
1460
- },
1461
- i
1462
- ) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: f.sentence }, i)
1463
- )
1464
- ] });
1465
- }
1466
-
1467
- // src/components/club-dashboard/CountdownBlock.tsx
1468
- var import_react9 = require("react");
1469
- var import_jsx_runtime22 = require("react/jsx-runtime");
1470
- var DAY_MS = 24 * 3600 * 1e3;
1471
- function pad2(n) {
1472
- return String(n).padStart(2, "0");
1473
- }
1474
- function splitRemaining(remainingMs) {
1475
- const totalSeconds = Math.max(0, Math.floor(remainingMs / 1e3));
1476
- const h = Math.floor(totalSeconds / 3600);
1477
- const m = Math.floor(totalSeconds % 3600 / 60);
1478
- const s = totalSeconds % 60;
1479
- return { h: pad2(h), m: pad2(m), s: pad2(s) };
1480
- }
1481
- function CountdownBlock({ block, ui }) {
1482
- const [remainingMs, setRemainingMs] = (0, import_react9.useState)(() => block.kickoffUnix * 1e3 - Date.now());
1483
- (0, import_react9.useEffect)(() => {
1484
- setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
1485
- if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
1486
- const id = setInterval(() => {
1487
- setRemainingMs(block.kickoffUnix * 1e3 - Date.now());
1488
- }, 1e3);
1489
- return () => clearInterval(id);
1490
- }, [block.kickoffUnix]);
1491
- if (remainingMs <= 0) return null;
1492
- if (remainingMs > DAY_MS) return null;
1493
- const { h, m, s } = splitRemaining(remainingMs);
1494
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-cd", "aria-label": ui.clubKickoffAria(block.kickoffUnix * 1e3), children: [
1495
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-cd-clock", "aria-hidden": "true", children: [
1496
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-cd-h", children: h }),
1497
- "h",
1498
- " ",
1499
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-cd-m", children: m }),
1500
- "m",
1501
- " ",
1502
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-cd-s", children: s }),
1503
- "s"
1504
- ] }),
1505
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
1506
- ] });
1507
- }
1508
-
1509
- // src/components/club-dashboard/ClubDashboard.tsx
1510
- var import_jsx_runtime23 = require("react/jsx-runtime");
1511
- var CLUB_BLOCK_REGISTRY = {
1512
- greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(GreetingHeaderBlock, { block }) : null,
1513
- fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FixtureHeroBlock, { block, ui, onAction }) : null,
1514
- formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FormGuideBlock, { block, ui }) : null,
1515
- matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MatchPreviewBlock, { block, ui, onAction }) : null,
1516
- teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TeamDnaBlock, { block, ui, onAction }) : null,
1517
- countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CountdownBlock, { block, ui }) : null
1518
- };
1519
- function ClubDashboard({
1520
- dashboard,
1521
- ui,
1522
- onAction
1523
- }) {
1524
- if (!dashboard.blocks.length) return null;
1525
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
1526
- const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
1527
- if (!Comp) {
1528
- console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
1529
- return null;
1530
- }
1531
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Comp, { block, ui, onAction }) }, i);
1532
- }) });
1533
- }
1534
-
1535
1327
  // src/components/ChatMessage.tsx
1536
- var import_jsx_runtime24 = require("react/jsx-runtime");
1537
- function ChatMessage({ message, disabled, onAct, onTap, onClubAction, ui, slip }) {
1328
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1329
+ function ChatMessage({ message, disabled, onAct, onTap, ui, slip }) {
1538
1330
  if (message.role === "user") {
1539
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
1331
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
1540
1332
  }
1541
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
1542
- message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Markdown, { text: message.text }) : null,
1543
- message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1544
- message.clubDashboard && ui ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ClubDashboard, { dashboard: message.clubDashboard, ui, onAction: onClubAction }) : null,
1545
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1546
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
1547
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1548
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1549
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1333
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
1334
+ message.text && !message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Markdown, { text: message.text }) : null,
1335
+ message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
1336
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
1337
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
1338
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
1339
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
1340
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
1550
1341
  ] });
1551
1342
  }
1552
1343
 
1553
1344
  // src/components/IntentChips.tsx
1554
- var import_jsx_runtime25 = require("react/jsx-runtime");
1345
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1555
1346
  function IntentChips({ chips, onPick }) {
1556
1347
  if (chips.length === 0) return null;
1557
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1348
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
1558
1349
  }
1559
1350
 
1560
1351
  // src/scroll.ts
@@ -1564,18 +1355,18 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
1564
1355
  }
1565
1356
 
1566
1357
  // src/components/MessageList.tsx
1567
- var import_jsx_runtime26 = require("react/jsx-runtime");
1358
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1568
1359
  function MessageList({ controller, ui, slip, onDashboardTap }) {
1569
1360
  const { state, send } = controller;
1570
- const listRef = (0, import_react10.useRef)(null);
1571
- const endRef = (0, import_react10.useRef)(null);
1572
- const pinnedRef = (0, import_react10.useRef)(true);
1573
- (0, import_react10.useEffect)(() => {
1361
+ const listRef = (0, import_react8.useRef)(null);
1362
+ const endRef = (0, import_react8.useRef)(null);
1363
+ const pinnedRef = (0, import_react8.useRef)(true);
1364
+ (0, import_react8.useEffect)(() => {
1574
1365
  if (pinnedRef.current) endRef.current?.scrollIntoView({ block: "end" });
1575
1366
  }, [state.messages, state.status]);
1576
1367
  const hasUserMessage = state.messages.some((m) => m.role === "user");
1577
1368
  const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
1578
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
1369
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1579
1370
  "div",
1580
1371
  {
1581
1372
  className: "ss-w-list",
@@ -1585,7 +1376,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1585
1376
  if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
1586
1377
  },
1587
1378
  children: [
1588
- state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1379
+ state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1589
1380
  ChatMessage,
1590
1381
  {
1591
1382
  message: m,
@@ -1595,31 +1386,30 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
1595
1386
  send(tile.actionValue, { displayText: tile.title });
1596
1387
  if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
1597
1388
  },
1598
- onClubAction: (label, opts) => send(label, { actionRef: opts.actionRef }),
1599
1389
  ui,
1600
1390
  slip
1601
1391
  },
1602
1392
  m.id
1603
1393
  )),
1604
- state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
1394
+ state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
1605
1395
  } }) : null,
1606
- state.status ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
1607
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
1608
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1609
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1396
+ state.status ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
1397
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
1398
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
1399
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
1610
1400
  ] }) : null,
1611
- !hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1612
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { ref: endRef })
1401
+ !hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
1402
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { ref: endRef })
1613
1403
  ]
1614
1404
  }
1615
1405
  );
1616
1406
  }
1617
1407
 
1618
1408
  // src/components/ChatInput.tsx
1619
- var import_react11 = require("react");
1620
- var import_jsx_runtime27 = require("react/jsx-runtime");
1409
+ var import_react9 = require("react");
1410
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1621
1411
  function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
1622
- const [value, setValue] = (0, import_react11.useState)("");
1412
+ const [value, setValue] = (0, import_react9.useState)("");
1623
1413
  const submit = () => {
1624
1414
  const t = value.trim();
1625
1415
  if (!t) return;
@@ -1632,18 +1422,18 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
1632
1422
  submit();
1633
1423
  }
1634
1424
  };
1635
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "ss-w-input", children: [
1636
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1637
- streaming ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SendIcon, {}) })
1425
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-input", children: [
1426
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
1427
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SendIcon, {}) })
1638
1428
  ] });
1639
1429
  }
1640
1430
 
1641
1431
  // src/components/ChatPanel.tsx
1642
- var import_jsx_runtime28 = require("react/jsx-runtime");
1432
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1643
1433
  var FULLSCREEN_QUERY = "(max-width: 639px)";
1644
1434
  function useIsModal() {
1645
- const [modal, setModal] = (0, import_react12.useState)(false);
1646
- (0, import_react12.useEffect)(() => {
1435
+ const [modal, setModal] = (0, import_react10.useState)(false);
1436
+ (0, import_react10.useEffect)(() => {
1647
1437
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1648
1438
  const mql = window.matchMedia(FULLSCREEN_QUERY);
1649
1439
  const sync = () => setModal(mql.matches);
@@ -1656,17 +1446,17 @@ function useIsModal() {
1656
1446
  function ChatPanel({ controller, ui, slip, onDashboardTap }) {
1657
1447
  const { state, close, stop, send } = controller;
1658
1448
  const isModal = useIsModal();
1659
- (0, import_react12.useEffect)(() => {
1449
+ (0, import_react10.useEffect)(() => {
1660
1450
  const onKey = (e) => {
1661
1451
  if (e.key === "Escape") close();
1662
1452
  };
1663
1453
  window.addEventListener("keydown", onKey);
1664
1454
  return () => window.removeEventListener("keydown", onKey);
1665
1455
  }, [close]);
1666
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1667
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1668
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
1669
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1456
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
1457
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
1458
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
1459
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
1670
1460
  ] });
1671
1461
  }
1672
1462
 
@@ -2019,49 +1809,10 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
2019
1809
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(2) { background: #eef3fb; }
2020
1810
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(3) { background: #fdf6ec; }
2021
1811
  .ss-w-dash--discovery .ss-w-dash-tile:nth-child(4) { background: #f5eefb; }
2022
-
2023
- /* club match-day dashboard */
2024
- .ss-w-cdash { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; }
2025
- .ss-w-cdash-block { display: flex; flex-direction: column; }
2026
-
2027
- .ss-w-cdash-greeting { display: flex; flex-direction: column; gap: 2px; }
2028
- .ss-w-cdash-greeting-title { font-weight: 700; font-size: 14px; color: var(--ss-w-ink); }
2029
- .ss-w-cdash-greeting-subtitle { font-size: 11.5px; color: var(--ss-w-faint); }
2030
-
2031
- .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; }
2032
- .ss-w-cdash-tie { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; }
2033
- .ss-w-cdash-team { font-weight: 650; font-size: 13px; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
2034
- .ss-w-cdash-vs { font-size: 11px; color: var(--ss-w-faint); font-weight: 600; }
2035
- .ss-w-cdash-crest { flex: none; width: 28px; height: 28px; border-radius: 50%; object-fit: cover; background: var(--ss-w-bubble); }
2036
- .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)); }
2037
- .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); }
2038
- .ss-w-cdash-kickoff { font-weight: 700; color: var(--ss-w-ink); }
2039
- .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; }
2040
-
2041
- .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; }
2042
- .ss-w-cdash-form-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
2043
- .ss-w-cdash-form-name { font-size: 12px; font-weight: 600; color: var(--ss-w-ink); min-width: 0; overflow-wrap: anywhere; }
2044
- .ss-w-cdash-form-pills { flex: none; display: flex; align-items: center; gap: 3px; }
2045
- .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; }
2046
- .ss-w-cdash-pill--w { background: color-mix(in srgb, var(--ss-w-pos) 88%, black); }
2047
- .ss-w-cdash-pill--d { background: var(--ss-w-faint); }
2048
- .ss-w-cdash-pill--l { background: color-mix(in srgb, var(--ss-w-neg) 88%, black); }
2049
-
2050
- .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; }
2051
- .ss-w-cdash-lines-heading { font-size: 12px; font-weight: 700; color: var(--ss-w-accent); }
2052
- .ss-w-cdash-lines p { font-size: 12px; line-height: 1.4; color: var(--ss-w-ink); margin: 0; }
2053
- .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; }
2054
- .ss-w-cdash-fact:hover, .ss-w-cdash-fact:focus-visible { color: var(--ss-w-accent); text-decoration: underline; }
2055
- .ss-w-cdash-fact-label { font-size: 11px; font-weight: 700; color: var(--ss-w-accent); }
2056
-
2057
- .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; }
2058
- .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); }
2059
- .ss-w-cdash-cd-h, .ss-w-cdash-cd-m, .ss-w-cdash-cd-s { color: var(--ss-w-accent); }
2060
- .ss-w-cdash-cd-label { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
2061
1812
  `;
2062
1813
 
2063
1814
  // src/StatsWidget.tsx
2064
- var import_jsx_runtime29 = require("react/jsx-runtime");
1815
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2065
1816
  function buildClient(props) {
2066
1817
  try {
2067
1818
  if ("client" in props && props.client) {
@@ -2086,11 +1837,11 @@ function injectStyles(root) {
2086
1837
  function StatsWidget(props) {
2087
1838
  const injectedClient = "client" in props ? props.client : void 0;
2088
1839
  const cfg = props.config;
2089
- const built = (0, import_react13.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
2090
- const ui = (0, import_react13.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
2091
- const rootRef = (0, import_react13.useRef)(null);
1840
+ const built = (0, import_react11.useMemo)(() => buildClient(props), [injectedClient, cfg?.operatorId, cfg?.publicKey, cfg?.baseUrl]);
1841
+ const ui = (0, import_react11.useMemo)(() => normalizeUi(props.config ?? { operatorId: "", publicKey: "" }), [props.config]);
1842
+ const rootRef = (0, import_react11.useRef)(null);
2092
1843
  const controller = useChatStream(built?.conversation ?? emptyConversation(), ui.starters, built ? ui.greetingMessage : void 0);
2093
- const slip = (0, import_react13.useMemo)(
1844
+ const slip = (0, import_react11.useMemo)(
2094
1845
  () => ({
2095
1846
  onAddToSlip: props.config?.onAddToSlip,
2096
1847
  conversationId: controller.state.conversationId ?? void 0,
@@ -2103,18 +1854,18 @@ function StatsWidget(props) {
2103
1854
  }),
2104
1855
  [props.config?.onAddToSlip, controller.state.conversationId, built]
2105
1856
  );
2106
- const onDashboardTap = (0, import_react13.useMemo)(
1857
+ const onDashboardTap = (0, import_react11.useMemo)(
2107
1858
  () => built ? createDashboardTapSignal((input) => built.conversation.sendSignal(input)) : void 0,
2108
1859
  [built]
2109
1860
  );
2110
- (0, import_react13.useEffect)(() => {
1861
+ (0, import_react11.useEffect)(() => {
2111
1862
  if (!built || !ui.injectStyles) return;
2112
1863
  const node = rootRef.current?.getRootNode();
2113
1864
  if (node) injectStyles(node);
2114
1865
  }, [built, ui.injectStyles]);
2115
1866
  if (!built) return null;
2116
1867
  const attrs = themeAttrs(ui);
2117
- return /* @__PURE__ */ (0, import_jsx_runtime29.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_runtime29.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1868
+ return /* @__PURE__ */ (0, import_jsx_runtime22.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_runtime22.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2118
1869
  ChatFab,
2119
1870
  {
2120
1871
  label: ui.launcherLabel,