@sensiblestats/widget-react 0.19.0 → 0.21.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 +22 -0
- package/dist/index.cjs +165 -77
- 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 +162 -74
- package/dist/index.js.map +1 -1
- package/dist/styles.css +17 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @sensiblestats/widget-react
|
|
2
2
|
|
|
3
|
+
## 0.21.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Match Preview card: deterministic matchPreviewCard block type (sdk) + renderer (react).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @sensiblestats/widget-sdk@0.18.0
|
|
13
|
+
|
|
14
|
+
## 0.20.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- Club-dashboard taps (FixtureHero CTA, MatchPreview/TeamDna facts) now send the backend's opaque `actionRef` instead of a prose command, and `useChatStream` gains a client-side fallback timeout so the panel can no longer hang forever waiting for a `turn_complete`/`error` that never arrives.
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @sensiblestats/widget-sdk@0.17.0
|
|
24
|
+
|
|
3
25
|
## 0.19.0
|
|
4
26
|
|
|
5
27
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -625,21 +625,42 @@ function reducer(state, action) {
|
|
|
625
625
|
}
|
|
626
626
|
|
|
627
627
|
// src/useChatStream.ts
|
|
628
|
+
var STREAM_FALLBACK_TIMEOUT_MS = 3e4;
|
|
628
629
|
function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
629
630
|
const seed = (0, import_react.useMemo)(() => initialState(starterTexts.map(chipFromText)), []);
|
|
630
631
|
const [state, dispatch] = (0, import_react.useReducer)(reducer, seed);
|
|
631
632
|
const idRef = (0, import_react.useRef)(0);
|
|
632
633
|
const handleRef = (0, import_react.useRef)(null);
|
|
634
|
+
const fallbackTimerRef = (0, import_react.useRef)(null);
|
|
633
635
|
const stateRef = (0, import_react.useRef)(state);
|
|
634
636
|
stateRef.current = state;
|
|
635
637
|
const greetedRef = (0, import_react.useRef)(false);
|
|
636
638
|
const nextId = () => `m${idRef.current++}`;
|
|
639
|
+
const clearFallbackTimer = (0, import_react.useCallback)(() => {
|
|
640
|
+
if (fallbackTimerRef.current != null) {
|
|
641
|
+
clearTimeout(fallbackTimerRef.current);
|
|
642
|
+
fallbackTimerRef.current = null;
|
|
643
|
+
}
|
|
644
|
+
}, []);
|
|
645
|
+
const armFallbackTimer = (0, import_react.useCallback)((onFire) => {
|
|
646
|
+
clearFallbackTimer();
|
|
647
|
+
fallbackTimerRef.current = setTimeout(() => {
|
|
648
|
+
fallbackTimerRef.current = null;
|
|
649
|
+
handleRef.current?.cancel();
|
|
650
|
+
handleRef.current = null;
|
|
651
|
+
onFire();
|
|
652
|
+
}, STREAM_FALLBACK_TIMEOUT_MS);
|
|
653
|
+
}, [clearFallbackTimer]);
|
|
637
654
|
const consume = (0, import_react.useCallback)((handle, onError) => {
|
|
638
655
|
;
|
|
639
656
|
(async () => {
|
|
640
657
|
try {
|
|
641
|
-
for await (const event of handle)
|
|
658
|
+
for await (const event of handle) {
|
|
659
|
+
dispatch({ kind: "EVENT", event });
|
|
660
|
+
if (event.type === "turn_complete" || event.type === "error") clearFallbackTimer();
|
|
661
|
+
}
|
|
642
662
|
} catch (err) {
|
|
663
|
+
if (handleRef.current === handle) clearFallbackTimer();
|
|
643
664
|
if (err instanceof import_widget_sdk3.WidgetSdkError) onError(err);
|
|
644
665
|
else if (err?.name === "AbortError") {
|
|
645
666
|
} else throw err;
|
|
@@ -647,18 +668,23 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
|
647
668
|
if (handleRef.current === handle) handleRef.current = null;
|
|
648
669
|
}
|
|
649
670
|
})();
|
|
650
|
-
}, []);
|
|
671
|
+
}, [clearFallbackTimer]);
|
|
651
672
|
const run = (0, import_react.useCallback)((input, displayText) => {
|
|
652
673
|
handleRef.current?.cancel();
|
|
674
|
+
clearFallbackTimer();
|
|
653
675
|
dispatch({ kind: "USER_SENT", input, userId: nextId(), assistantId: nextId(), displayText });
|
|
654
676
|
const handle = conversation.send(input);
|
|
655
677
|
handleRef.current = handle;
|
|
678
|
+
armFallbackTimer(() => {
|
|
679
|
+
dispatch({ kind: "STOP" });
|
|
680
|
+
dispatch({ kind: "STREAM_ERROR", error: new import_widget_sdk3.WidgetSdkError("No response received in time", "timeout") });
|
|
681
|
+
});
|
|
656
682
|
consume(handle, (err) => dispatch({ kind: "STREAM_ERROR", error: err }));
|
|
657
|
-
}, [conversation, consume]);
|
|
683
|
+
}, [conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
658
684
|
const send = (0, import_react.useCallback)((text, opts) => {
|
|
659
685
|
const trimmed = text.trim();
|
|
660
686
|
if (!trimmed) return;
|
|
661
|
-
run({ message: trimmed, actionId: opts?.actionId,
|
|
687
|
+
run({ message: trimmed, actionId: opts?.actionId, actionRef: opts?.actionRef }, opts?.displayText);
|
|
662
688
|
}, [run]);
|
|
663
689
|
const retry = (0, import_react.useCallback)(() => {
|
|
664
690
|
const last = stateRef.current.lastUserInput;
|
|
@@ -670,25 +696,29 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
|
670
696
|
greetedRef.current = true;
|
|
671
697
|
try {
|
|
672
698
|
handleRef.current?.cancel();
|
|
699
|
+
clearFallbackTimer();
|
|
673
700
|
dispatch({ kind: "GREETING_SENT", assistantId: nextId() });
|
|
674
701
|
const handle = conversation.send({ message });
|
|
675
702
|
handleRef.current = handle;
|
|
703
|
+
armFallbackTimer(() => dispatch({ kind: "STOP" }));
|
|
676
704
|
consume(handle, () => dispatch({ kind: "STOP" }));
|
|
677
705
|
} catch {
|
|
678
706
|
dispatch({ kind: "STOP" });
|
|
679
707
|
}
|
|
680
|
-
}, [greetingMessage, conversation, consume]);
|
|
708
|
+
}, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
681
709
|
const open = (0, import_react.useCallback)(() => dispatch({ kind: "OPEN" }), []);
|
|
682
710
|
const close = (0, import_react.useCallback)(() => {
|
|
683
711
|
handleRef.current?.cancel();
|
|
684
712
|
handleRef.current = null;
|
|
713
|
+
clearFallbackTimer();
|
|
685
714
|
dispatch({ kind: "CLOSE" });
|
|
686
|
-
}, []);
|
|
715
|
+
}, [clearFallbackTimer]);
|
|
687
716
|
const stop = (0, import_react.useCallback)(() => {
|
|
688
717
|
handleRef.current?.cancel();
|
|
689
718
|
handleRef.current = null;
|
|
719
|
+
clearFallbackTimer();
|
|
690
720
|
dispatch({ kind: "STOP" });
|
|
691
|
-
}, []);
|
|
721
|
+
}, [clearFallbackTimer]);
|
|
692
722
|
const toggle = (0, import_react.useCallback)(() => {
|
|
693
723
|
if (stateRef.current.isOpen) close();
|
|
694
724
|
else open();
|
|
@@ -1353,25 +1383,31 @@ function FixtureHeroBlock({
|
|
|
1353
1383
|
block.venue ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-venue", children: block.venue }) : null,
|
|
1354
1384
|
block.competition ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "ss-w-cdash-comp", children: block.competition }) : null
|
|
1355
1385
|
] }),
|
|
1356
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.
|
|
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 })
|
|
1357
1387
|
] });
|
|
1358
1388
|
}
|
|
1359
1389
|
|
|
1360
|
-
// src/components/club-dashboard/
|
|
1390
|
+
// src/components/club-dashboard/ResultPills.tsx
|
|
1361
1391
|
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1392
|
+
function ResultPills({ results }) {
|
|
1393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children: results.map((r, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: `ss-w-cdash-pill ss-w-cdash-pill--${r.toLowerCase()}`, children: r }, i)) });
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
// src/components/club-dashboard/FormGuideBlock.tsx
|
|
1397
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1362
1398
|
function FormGuideBlock({ block }) {
|
|
1363
1399
|
if (block.rows.length === 0) return null;
|
|
1364
|
-
return /* @__PURE__ */ (0,
|
|
1365
|
-
/* @__PURE__ */ (0,
|
|
1400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ss-w-cdash-form", children: block.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "ss-w-cdash-form-row", children: [
|
|
1401
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ss-w-cdash-form-name", children: [
|
|
1366
1402
|
row.name,
|
|
1367
1403
|
row.position != null ? ` #${row.position}` : ""
|
|
1368
1404
|
] }),
|
|
1369
|
-
/* @__PURE__ */ (0,
|
|
1405
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ss-w-cdash-form-pills", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ResultPills, { results: row.last5 }) })
|
|
1370
1406
|
] }, row.name)) });
|
|
1371
1407
|
}
|
|
1372
1408
|
|
|
1373
1409
|
// src/components/club-dashboard/MatchPreviewBlock.tsx
|
|
1374
|
-
var
|
|
1410
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1375
1411
|
function MatchPreviewBlock({
|
|
1376
1412
|
block,
|
|
1377
1413
|
ui,
|
|
@@ -1379,31 +1415,65 @@ function MatchPreviewBlock({
|
|
|
1379
1415
|
}) {
|
|
1380
1416
|
if (block.facts.length === 0) return null;
|
|
1381
1417
|
const heading = ui.clubMatchPreviewHeading;
|
|
1382
|
-
return /* @__PURE__ */ (0,
|
|
1383
|
-
/* @__PURE__ */ (0,
|
|
1418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "ss-w-cdash-lines", children: [
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1384
1420
|
block.facts.map(
|
|
1385
|
-
(f, i) => f.
|
|
1421
|
+
(f, i) => f.actionRef ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1386
1422
|
"button",
|
|
1387
1423
|
{
|
|
1388
1424
|
type: "button",
|
|
1389
1425
|
className: "ss-w-cdash-fact",
|
|
1390
|
-
onClick: () => onAction(f.
|
|
1426
|
+
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1391
1427
|
children: [
|
|
1392
1428
|
f.sentence,
|
|
1393
|
-
f.label ? /* @__PURE__ */ (0,
|
|
1429
|
+
f.label ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1394
1430
|
" ",
|
|
1395
1431
|
f.label
|
|
1396
1432
|
] }) : null
|
|
1397
1433
|
]
|
|
1398
1434
|
},
|
|
1399
1435
|
i
|
|
1400
|
-
) : /* @__PURE__ */ (0,
|
|
1436
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: f.sentence }, i)
|
|
1401
1437
|
)
|
|
1402
1438
|
] });
|
|
1403
1439
|
}
|
|
1404
1440
|
|
|
1441
|
+
// src/components/club-dashboard/MatchPreviewCardBlock.tsx
|
|
1442
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1443
|
+
function position(p) {
|
|
1444
|
+
return p != null ? `#${p}` : "\u2014";
|
|
1445
|
+
}
|
|
1446
|
+
function MatchPreviewCardBlock({ block }) {
|
|
1447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-preview", children: [
|
|
1448
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-preview-header", children: [
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-team", children: block.homeName }),
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-vs", children: "v" }),
|
|
1451
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-team", children: block.awayName })
|
|
1452
|
+
] }),
|
|
1453
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-preview-row", children: [
|
|
1454
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-preview-value", children: position(block.homePosition) }),
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-preview-label", children: block.tableLabel }),
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-preview-value", children: position(block.awayPosition) })
|
|
1457
|
+
] }),
|
|
1458
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-preview-row", children: [
|
|
1459
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-preview-pills", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ResultPills, { results: block.homeLast5 }) }),
|
|
1460
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-preview-label", children: block.last5Label }),
|
|
1461
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "ss-w-cdash-preview-pills", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ResultPills, { results: block.awayLast5 }) })
|
|
1462
|
+
] }),
|
|
1463
|
+
block.edgeTeamName ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "ss-w-cdash-preview-edge", children: [
|
|
1464
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": "true", children: "\u25B8" }),
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("strong", { children: block.edgeTeamName }),
|
|
1466
|
+
block.edgeReason ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { children: [
|
|
1467
|
+
" \u2014 ",
|
|
1468
|
+
block.edgeReason
|
|
1469
|
+
] }) : null
|
|
1470
|
+
] }) : null,
|
|
1471
|
+
block.h2HLines.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "ss-w-cdash-preview-h2h", children: block.h2HLines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: line }, i)) }) : null
|
|
1472
|
+
] });
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1405
1475
|
// src/components/club-dashboard/TeamDnaBlock.tsx
|
|
1406
|
-
var
|
|
1476
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1407
1477
|
function TeamDnaBlock({
|
|
1408
1478
|
block,
|
|
1409
1479
|
ui,
|
|
@@ -1411,32 +1481,32 @@ function TeamDnaBlock({
|
|
|
1411
1481
|
}) {
|
|
1412
1482
|
if (block.facts.length === 0) return null;
|
|
1413
1483
|
const heading = ui.clubTeamDnaHeading;
|
|
1414
|
-
return /* @__PURE__ */ (0,
|
|
1415
|
-
/* @__PURE__ */ (0,
|
|
1484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "ss-w-cdash-lines", children: [
|
|
1485
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1416
1486
|
block.facts.map(
|
|
1417
|
-
(f, i) => f.
|
|
1487
|
+
(f, i) => f.actionRef ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
1418
1488
|
"button",
|
|
1419
1489
|
{
|
|
1420
1490
|
type: "button",
|
|
1421
1491
|
className: "ss-w-cdash-fact",
|
|
1422
|
-
onClick: () => onAction(f.
|
|
1492
|
+
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1423
1493
|
children: [
|
|
1424
1494
|
f.sentence,
|
|
1425
|
-
f.label ? /* @__PURE__ */ (0,
|
|
1495
|
+
f.label ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1426
1496
|
" ",
|
|
1427
1497
|
f.label
|
|
1428
1498
|
] }) : null
|
|
1429
1499
|
]
|
|
1430
1500
|
},
|
|
1431
1501
|
i
|
|
1432
|
-
) : /* @__PURE__ */ (0,
|
|
1502
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: f.sentence }, i)
|
|
1433
1503
|
)
|
|
1434
1504
|
] });
|
|
1435
1505
|
}
|
|
1436
1506
|
|
|
1437
1507
|
// src/components/club-dashboard/CountdownBlock.tsx
|
|
1438
1508
|
var import_react9 = require("react");
|
|
1439
|
-
var
|
|
1509
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1440
1510
|
var DAY_MS = 24 * 3600 * 1e3;
|
|
1441
1511
|
function pad2(n) {
|
|
1442
1512
|
return String(n).padStart(2, "0");
|
|
@@ -1461,30 +1531,31 @@ function CountdownBlock({ block, ui }) {
|
|
|
1461
1531
|
if (remainingMs <= 0) return null;
|
|
1462
1532
|
if (remainingMs > DAY_MS) return null;
|
|
1463
1533
|
const { h, m, s } = splitRemaining(remainingMs);
|
|
1464
|
-
return /* @__PURE__ */ (0,
|
|
1465
|
-
/* @__PURE__ */ (0,
|
|
1466
|
-
/* @__PURE__ */ (0,
|
|
1534
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "ss-w-cdash-cd", "aria-label": ui.clubKickoffAria(block.kickoffUnix * 1e3), children: [
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "ss-w-cdash-cd-clock", "aria-hidden": "true", children: [
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-cdash-cd-h", children: h }),
|
|
1467
1537
|
"h",
|
|
1468
1538
|
" ",
|
|
1469
|
-
/* @__PURE__ */ (0,
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-cdash-cd-m", children: m }),
|
|
1470
1540
|
"m",
|
|
1471
1541
|
" ",
|
|
1472
|
-
/* @__PURE__ */ (0,
|
|
1542
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "ss-w-cdash-cd-s", children: s }),
|
|
1473
1543
|
"s"
|
|
1474
1544
|
] }),
|
|
1475
|
-
/* @__PURE__ */ (0,
|
|
1545
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
|
|
1476
1546
|
] });
|
|
1477
1547
|
}
|
|
1478
1548
|
|
|
1479
1549
|
// src/components/club-dashboard/ClubDashboard.tsx
|
|
1480
|
-
var
|
|
1550
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1481
1551
|
var CLUB_BLOCK_REGISTRY = {
|
|
1482
|
-
greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ (0,
|
|
1483
|
-
fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ (0,
|
|
1484
|
-
formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ (0,
|
|
1485
|
-
matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ (0,
|
|
1486
|
-
|
|
1487
|
-
|
|
1552
|
+
greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(GreetingHeaderBlock, { block }) : null,
|
|
1553
|
+
fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FixtureHeroBlock, { block, ui, onAction }) : null,
|
|
1554
|
+
formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FormGuideBlock, { block, ui }) : null,
|
|
1555
|
+
matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(MatchPreviewBlock, { block, ui, onAction }) : null,
|
|
1556
|
+
matchPreviewCard: ({ block, ui }) => block.type === "matchPreviewCard" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(MatchPreviewCardBlock, { block, ui }) : null,
|
|
1557
|
+
teamDna: ({ block, ui, onAction }) => block.type === "teamDna" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(TeamDnaBlock, { block, ui, onAction }) : null,
|
|
1558
|
+
countdown: ({ block, ui }) => block.type === "countdown" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CountdownBlock, { block, ui }) : null
|
|
1488
1559
|
};
|
|
1489
1560
|
function ClubDashboard({
|
|
1490
1561
|
dashboard,
|
|
@@ -1492,39 +1563,39 @@ function ClubDashboard({
|
|
|
1492
1563
|
onAction
|
|
1493
1564
|
}) {
|
|
1494
1565
|
if (!dashboard.blocks.length) return null;
|
|
1495
|
-
return /* @__PURE__ */ (0,
|
|
1566
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
|
|
1496
1567
|
const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
|
|
1497
1568
|
if (!Comp) {
|
|
1498
1569
|
console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
|
|
1499
1570
|
return null;
|
|
1500
1571
|
}
|
|
1501
|
-
return /* @__PURE__ */ (0,
|
|
1572
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Comp, { block, ui, onAction }) }, i);
|
|
1502
1573
|
}) });
|
|
1503
1574
|
}
|
|
1504
1575
|
|
|
1505
1576
|
// src/components/ChatMessage.tsx
|
|
1506
|
-
var
|
|
1577
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1507
1578
|
function ChatMessage({ message, disabled, onAct, onTap, onClubAction, ui, slip }) {
|
|
1508
1579
|
if (message.role === "user") {
|
|
1509
|
-
return /* @__PURE__ */ (0,
|
|
1580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "ss-w-bubble", children: message.text }) });
|
|
1510
1581
|
}
|
|
1511
|
-
return /* @__PURE__ */ (0,
|
|
1512
|
-
message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */ (0,
|
|
1513
|
-
message.greetingDashboard ? /* @__PURE__ */ (0,
|
|
1514
|
-
message.clubDashboard && ui ? /* @__PURE__ */ (0,
|
|
1515
|
-
/* @__PURE__ */ (0,
|
|
1516
|
-
/* @__PURE__ */ (0,
|
|
1517
|
-
/* @__PURE__ */ (0,
|
|
1518
|
-
/* @__PURE__ */ (0,
|
|
1519
|
-
/* @__PURE__ */ (0,
|
|
1582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "ss-w-msg ss-w-bot", children: [
|
|
1583
|
+
message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Markdown, { text: message.text }) : null,
|
|
1584
|
+
message.greetingDashboard ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(GreetingDashboard, { dashboard: message.greetingDashboard, onTap }) : null,
|
|
1585
|
+
message.clubDashboard && ui ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ClubDashboard, { dashboard: message.clubDashboard, ui, onAction: onClubAction }) : null,
|
|
1586
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(EntityCardList, { cards: message.cards, disabled, showLessLabel: ui?.showLess, showMoreLabel: ui?.showMore }),
|
|
1587
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(BettingInsightList, { insights: message.insights, ui, slip }),
|
|
1588
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(MarketOddsCardList, { cards: message.marketOdds, ui, slip }),
|
|
1589
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OddsMovementCardList, { cards: message.oddsMovement, ui }),
|
|
1590
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ActionButtons, { actions: message.actions, loading: false, disabled, onAct })
|
|
1520
1591
|
] });
|
|
1521
1592
|
}
|
|
1522
1593
|
|
|
1523
1594
|
// src/components/IntentChips.tsx
|
|
1524
|
-
var
|
|
1595
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1525
1596
|
function IntentChips({ chips, onPick }) {
|
|
1526
1597
|
if (chips.length === 0) return null;
|
|
1527
|
-
return /* @__PURE__ */ (0,
|
|
1598
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "ss-w-chips", children: chips.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("button", { type: "button", className: "ss-w-chip", onClick: () => onPick(c.text), children: c.text }, `${c.text}-${i}`)) });
|
|
1528
1599
|
}
|
|
1529
1600
|
|
|
1530
1601
|
// src/scroll.ts
|
|
@@ -1534,7 +1605,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1534
1605
|
}
|
|
1535
1606
|
|
|
1536
1607
|
// src/components/MessageList.tsx
|
|
1537
|
-
var
|
|
1608
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1538
1609
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1539
1610
|
const { state, send } = controller;
|
|
1540
1611
|
const listRef = (0, import_react10.useRef)(null);
|
|
@@ -1545,7 +1616,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1545
1616
|
}, [state.messages, state.status]);
|
|
1546
1617
|
const hasUserMessage = state.messages.some((m) => m.role === "user");
|
|
1547
1618
|
const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
|
|
1548
|
-
return /* @__PURE__ */ (0,
|
|
1619
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1549
1620
|
"div",
|
|
1550
1621
|
{
|
|
1551
1622
|
className: "ss-w-list",
|
|
@@ -1555,7 +1626,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1555
1626
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1556
1627
|
},
|
|
1557
1628
|
children: [
|
|
1558
|
-
state.messages.map((m) => /* @__PURE__ */ (0,
|
|
1629
|
+
state.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1559
1630
|
ChatMessage,
|
|
1560
1631
|
{
|
|
1561
1632
|
message: m,
|
|
@@ -1565,21 +1636,21 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1565
1636
|
send(tile.actionValue, { displayText: tile.title });
|
|
1566
1637
|
if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
|
|
1567
1638
|
},
|
|
1568
|
-
onClubAction: (
|
|
1639
|
+
onClubAction: (label, opts) => send(label, { actionRef: opts.actionRef }),
|
|
1569
1640
|
ui,
|
|
1570
1641
|
slip
|
|
1571
1642
|
},
|
|
1572
1643
|
m.id
|
|
1573
1644
|
)),
|
|
1574
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0,
|
|
1645
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1575
1646
|
} }) : null,
|
|
1576
|
-
state.status ? /* @__PURE__ */ (0,
|
|
1577
|
-
state.error ? /* @__PURE__ */ (0,
|
|
1578
|
-
/* @__PURE__ */ (0,
|
|
1579
|
-
/* @__PURE__ */ (0,
|
|
1647
|
+
state.status ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "ss-w-status", children: state.status }) : null,
|
|
1648
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "ss-w-error", role: "alert", children: [
|
|
1649
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "message" in state.error ? state.error.message : ui.somethingWentWrong }),
|
|
1650
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("button", { type: "button", className: "ss-w-retry", onClick: () => controller.retry(), children: ui.retry })
|
|
1580
1651
|
] }) : null,
|
|
1581
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0,
|
|
1582
|
-
/* @__PURE__ */ (0,
|
|
1652
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
1653
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { ref: endRef })
|
|
1583
1654
|
]
|
|
1584
1655
|
}
|
|
1585
1656
|
);
|
|
@@ -1587,7 +1658,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1587
1658
|
|
|
1588
1659
|
// src/components/ChatInput.tsx
|
|
1589
1660
|
var import_react11 = require("react");
|
|
1590
|
-
var
|
|
1661
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1591
1662
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1592
1663
|
const [value, setValue] = (0, import_react11.useState)("");
|
|
1593
1664
|
const submit = () => {
|
|
@@ -1602,14 +1673,14 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1602
1673
|
submit();
|
|
1603
1674
|
}
|
|
1604
1675
|
};
|
|
1605
|
-
return /* @__PURE__ */ (0,
|
|
1606
|
-
/* @__PURE__ */ (0,
|
|
1607
|
-
streaming ? /* @__PURE__ */ (0,
|
|
1676
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "ss-w-input", children: [
|
|
1677
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("textarea", { className: "ss-w-textarea", rows: 1, placeholder, value, disabled: streaming, onChange: (e) => setValue(e.target.value), onKeyDown }),
|
|
1678
|
+
streaming ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "ss-w-send ss-w-stop", "aria-label": stopLabel, onClick: onStop, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "ss-w-stop-glyph" }) }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "ss-w-send", "aria-label": sendLabel, onClick: submit, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SendIcon, {}) })
|
|
1608
1679
|
] });
|
|
1609
1680
|
}
|
|
1610
1681
|
|
|
1611
1682
|
// src/components/ChatPanel.tsx
|
|
1612
|
-
var
|
|
1683
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1613
1684
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1614
1685
|
function useIsModal() {
|
|
1615
1686
|
const [modal, setModal] = (0, import_react12.useState)(false);
|
|
@@ -1633,10 +1704,10 @@ function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
|
1633
1704
|
window.addEventListener("keydown", onKey);
|
|
1634
1705
|
return () => window.removeEventListener("keydown", onKey);
|
|
1635
1706
|
}, [close]);
|
|
1636
|
-
return /* @__PURE__ */ (0,
|
|
1637
|
-
/* @__PURE__ */ (0,
|
|
1638
|
-
/* @__PURE__ */ (0,
|
|
1639
|
-
/* @__PURE__ */ (0,
|
|
1707
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "ss-w-panel", role: "dialog", "aria-modal": isModal, "aria-label": ui.chatDialogLabel, children: [
|
|
1708
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ChatHeader, { onClose: close, closeLabel: ui.closeChat }),
|
|
1709
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(MessageList, { controller, ui, slip, onDashboardTap }),
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ChatInput, { placeholder: ui.placeholder, streaming: state.isStreaming, onSend: (t) => send(t), onStop: stop, stopLabel: ui.stopResponse, sendLabel: ui.sendMessage })
|
|
1640
1711
|
] });
|
|
1641
1712
|
}
|
|
1642
1713
|
|
|
@@ -2028,10 +2099,27 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
2028
2099
|
.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); }
|
|
2029
2100
|
.ss-w-cdash-cd-h, .ss-w-cdash-cd-m, .ss-w-cdash-cd-s { color: var(--ss-w-accent); }
|
|
2030
2101
|
.ss-w-cdash-cd-label { font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
|
|
2102
|
+
|
|
2103
|
+
.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; }
|
|
2104
|
+
.ss-w-cdash-preview-header { display: grid; grid-template-columns: 1fr auto 1fr; align-items: baseline; gap: 6px; }
|
|
2105
|
+
.ss-w-cdash-preview-header .ss-w-cdash-team:first-child { justify-self: start; text-align: left; }
|
|
2106
|
+
.ss-w-cdash-preview-header .ss-w-cdash-team:last-child { justify-self: end; text-align: right; }
|
|
2107
|
+
.ss-w-cdash-preview-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 6px; }
|
|
2108
|
+
.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; }
|
|
2109
|
+
.ss-w-cdash-preview-value { font-size: 12px; font-weight: 700; color: var(--ss-w-ink); text-align: center; }
|
|
2110
|
+
.ss-w-cdash-preview-pills { display: flex; align-items: center; justify-content: center; gap: 3px; }
|
|
2111
|
+
.ss-w-cdash-preview-row:first-of-type .ss-w-cdash-preview-value { justify-self: start; }
|
|
2112
|
+
.ss-w-cdash-preview-row:first-of-type .ss-w-cdash-preview-value:last-child { justify-self: end; }
|
|
2113
|
+
.ss-w-cdash-preview-row:last-of-type .ss-w-cdash-preview-pills:first-child { justify-self: start; }
|
|
2114
|
+
.ss-w-cdash-preview-row:last-of-type .ss-w-cdash-preview-pills:last-child { justify-self: end; }
|
|
2115
|
+
.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; }
|
|
2116
|
+
.ss-w-cdash-preview-edge strong { color: var(--ss-w-ink); }
|
|
2117
|
+
.ss-w-cdash-preview-h2h { display: flex; flex-direction: column; gap: 2px; }
|
|
2118
|
+
.ss-w-cdash-preview-h2h p { font-size: 11.5px; line-height: 1.4; color: var(--ss-w-faint); margin: 0; }
|
|
2031
2119
|
`;
|
|
2032
2120
|
|
|
2033
2121
|
// src/StatsWidget.tsx
|
|
2034
|
-
var
|
|
2122
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
2035
2123
|
function buildClient(props) {
|
|
2036
2124
|
try {
|
|
2037
2125
|
if ("client" in props && props.client) {
|
|
@@ -2084,7 +2172,7 @@ function StatsWidget(props) {
|
|
|
2084
2172
|
}, [built, ui.injectStyles]);
|
|
2085
2173
|
if (!built) return null;
|
|
2086
2174
|
const attrs = themeAttrs(ui);
|
|
2087
|
-
return /* @__PURE__ */ (0,
|
|
2175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.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_runtime31.jsx)(ChatPanel, { controller, ui, slip, onDashboardTap }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2088
2176
|
ChatFab,
|
|
2089
2177
|
{
|
|
2090
2178
|
label: ui.launcherLabel,
|