@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/dist/index.js
CHANGED
|
@@ -588,21 +588,42 @@ function reducer(state, action) {
|
|
|
588
588
|
}
|
|
589
589
|
|
|
590
590
|
// src/useChatStream.ts
|
|
591
|
+
var STREAM_FALLBACK_TIMEOUT_MS = 3e4;
|
|
591
592
|
function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
592
593
|
const seed = useMemo(() => initialState(starterTexts.map(chipFromText)), []);
|
|
593
594
|
const [state, dispatch] = useReducer(reducer, seed);
|
|
594
595
|
const idRef = useRef(0);
|
|
595
596
|
const handleRef = useRef(null);
|
|
597
|
+
const fallbackTimerRef = useRef(null);
|
|
596
598
|
const stateRef = useRef(state);
|
|
597
599
|
stateRef.current = state;
|
|
598
600
|
const greetedRef = useRef(false);
|
|
599
601
|
const nextId = () => `m${idRef.current++}`;
|
|
602
|
+
const clearFallbackTimer = useCallback(() => {
|
|
603
|
+
if (fallbackTimerRef.current != null) {
|
|
604
|
+
clearTimeout(fallbackTimerRef.current);
|
|
605
|
+
fallbackTimerRef.current = null;
|
|
606
|
+
}
|
|
607
|
+
}, []);
|
|
608
|
+
const armFallbackTimer = useCallback((onFire) => {
|
|
609
|
+
clearFallbackTimer();
|
|
610
|
+
fallbackTimerRef.current = setTimeout(() => {
|
|
611
|
+
fallbackTimerRef.current = null;
|
|
612
|
+
handleRef.current?.cancel();
|
|
613
|
+
handleRef.current = null;
|
|
614
|
+
onFire();
|
|
615
|
+
}, STREAM_FALLBACK_TIMEOUT_MS);
|
|
616
|
+
}, [clearFallbackTimer]);
|
|
600
617
|
const consume = useCallback((handle, onError) => {
|
|
601
618
|
;
|
|
602
619
|
(async () => {
|
|
603
620
|
try {
|
|
604
|
-
for await (const event of handle)
|
|
621
|
+
for await (const event of handle) {
|
|
622
|
+
dispatch({ kind: "EVENT", event });
|
|
623
|
+
if (event.type === "turn_complete" || event.type === "error") clearFallbackTimer();
|
|
624
|
+
}
|
|
605
625
|
} catch (err) {
|
|
626
|
+
if (handleRef.current === handle) clearFallbackTimer();
|
|
606
627
|
if (err instanceof WidgetSdkError2) onError(err);
|
|
607
628
|
else if (err?.name === "AbortError") {
|
|
608
629
|
} else throw err;
|
|
@@ -610,18 +631,23 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
|
610
631
|
if (handleRef.current === handle) handleRef.current = null;
|
|
611
632
|
}
|
|
612
633
|
})();
|
|
613
|
-
}, []);
|
|
634
|
+
}, [clearFallbackTimer]);
|
|
614
635
|
const run = useCallback((input, displayText) => {
|
|
615
636
|
handleRef.current?.cancel();
|
|
637
|
+
clearFallbackTimer();
|
|
616
638
|
dispatch({ kind: "USER_SENT", input, userId: nextId(), assistantId: nextId(), displayText });
|
|
617
639
|
const handle = conversation.send(input);
|
|
618
640
|
handleRef.current = handle;
|
|
641
|
+
armFallbackTimer(() => {
|
|
642
|
+
dispatch({ kind: "STOP" });
|
|
643
|
+
dispatch({ kind: "STREAM_ERROR", error: new WidgetSdkError2("No response received in time", "timeout") });
|
|
644
|
+
});
|
|
619
645
|
consume(handle, (err) => dispatch({ kind: "STREAM_ERROR", error: err }));
|
|
620
|
-
}, [conversation, consume]);
|
|
646
|
+
}, [conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
621
647
|
const send = useCallback((text, opts) => {
|
|
622
648
|
const trimmed = text.trim();
|
|
623
649
|
if (!trimmed) return;
|
|
624
|
-
run({ message: trimmed, actionId: opts?.actionId,
|
|
650
|
+
run({ message: trimmed, actionId: opts?.actionId, actionRef: opts?.actionRef }, opts?.displayText);
|
|
625
651
|
}, [run]);
|
|
626
652
|
const retry = useCallback(() => {
|
|
627
653
|
const last = stateRef.current.lastUserInput;
|
|
@@ -633,25 +659,29 @@ function useChatStream(conversation, starterTexts, greetingMessage) {
|
|
|
633
659
|
greetedRef.current = true;
|
|
634
660
|
try {
|
|
635
661
|
handleRef.current?.cancel();
|
|
662
|
+
clearFallbackTimer();
|
|
636
663
|
dispatch({ kind: "GREETING_SENT", assistantId: nextId() });
|
|
637
664
|
const handle = conversation.send({ message });
|
|
638
665
|
handleRef.current = handle;
|
|
666
|
+
armFallbackTimer(() => dispatch({ kind: "STOP" }));
|
|
639
667
|
consume(handle, () => dispatch({ kind: "STOP" }));
|
|
640
668
|
} catch {
|
|
641
669
|
dispatch({ kind: "STOP" });
|
|
642
670
|
}
|
|
643
|
-
}, [greetingMessage, conversation, consume]);
|
|
671
|
+
}, [greetingMessage, conversation, consume, clearFallbackTimer, armFallbackTimer]);
|
|
644
672
|
const open = useCallback(() => dispatch({ kind: "OPEN" }), []);
|
|
645
673
|
const close = useCallback(() => {
|
|
646
674
|
handleRef.current?.cancel();
|
|
647
675
|
handleRef.current = null;
|
|
676
|
+
clearFallbackTimer();
|
|
648
677
|
dispatch({ kind: "CLOSE" });
|
|
649
|
-
}, []);
|
|
678
|
+
}, [clearFallbackTimer]);
|
|
650
679
|
const stop = useCallback(() => {
|
|
651
680
|
handleRef.current?.cancel();
|
|
652
681
|
handleRef.current = null;
|
|
682
|
+
clearFallbackTimer();
|
|
653
683
|
dispatch({ kind: "STOP" });
|
|
654
|
-
}, []);
|
|
684
|
+
}, [clearFallbackTimer]);
|
|
655
685
|
const toggle = useCallback(() => {
|
|
656
686
|
if (stateRef.current.isOpen) close();
|
|
657
687
|
else open();
|
|
@@ -1316,25 +1346,31 @@ function FixtureHeroBlock({
|
|
|
1316
1346
|
block.venue ? /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-venue", children: block.venue }) : null,
|
|
1317
1347
|
block.competition ? /* @__PURE__ */ jsx18("span", { className: "ss-w-cdash-comp", children: block.competition }) : null
|
|
1318
1348
|
] }),
|
|
1319
|
-
/* @__PURE__ */ jsx18("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.
|
|
1349
|
+
/* @__PURE__ */ jsx18("button", { type: "button", className: "ss-w-cdash-cta", onClick: () => onAction(block.ctaLabel, { actionRef: block.ctaActionRef }), children: block.ctaLabel })
|
|
1320
1350
|
] });
|
|
1321
1351
|
}
|
|
1322
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
|
+
|
|
1323
1359
|
// src/components/club-dashboard/FormGuideBlock.tsx
|
|
1324
|
-
import { jsx as
|
|
1360
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1325
1361
|
function FormGuideBlock({ block }) {
|
|
1326
1362
|
if (block.rows.length === 0) return null;
|
|
1327
|
-
return /* @__PURE__ */
|
|
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: [
|
|
1328
1364
|
/* @__PURE__ */ jsxs15("span", { className: "ss-w-cdash-form-name", children: [
|
|
1329
1365
|
row.name,
|
|
1330
1366
|
row.position != null ? ` #${row.position}` : ""
|
|
1331
1367
|
] }),
|
|
1332
|
-
/* @__PURE__ */
|
|
1368
|
+
/* @__PURE__ */ jsx20("span", { className: "ss-w-cdash-form-pills", children: /* @__PURE__ */ jsx20(ResultPills, { results: row.last5 }) })
|
|
1333
1369
|
] }, row.name)) });
|
|
1334
1370
|
}
|
|
1335
1371
|
|
|
1336
1372
|
// src/components/club-dashboard/MatchPreviewBlock.tsx
|
|
1337
|
-
import { jsx as
|
|
1373
|
+
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1338
1374
|
function MatchPreviewBlock({
|
|
1339
1375
|
block,
|
|
1340
1376
|
ui,
|
|
@@ -1343,14 +1379,14 @@ function MatchPreviewBlock({
|
|
|
1343
1379
|
if (block.facts.length === 0) return null;
|
|
1344
1380
|
const heading = ui.clubMatchPreviewHeading;
|
|
1345
1381
|
return /* @__PURE__ */ jsxs16("div", { className: "ss-w-cdash-lines", children: [
|
|
1346
|
-
/* @__PURE__ */
|
|
1382
|
+
/* @__PURE__ */ jsx21("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1347
1383
|
block.facts.map(
|
|
1348
|
-
(f, i) => f.
|
|
1384
|
+
(f, i) => f.actionRef ? /* @__PURE__ */ jsxs16(
|
|
1349
1385
|
"button",
|
|
1350
1386
|
{
|
|
1351
1387
|
type: "button",
|
|
1352
1388
|
className: "ss-w-cdash-fact",
|
|
1353
|
-
onClick: () => onAction(f.
|
|
1389
|
+
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1354
1390
|
children: [
|
|
1355
1391
|
f.sentence,
|
|
1356
1392
|
f.label ? /* @__PURE__ */ jsxs16("span", { className: "ss-w-cdash-fact-label", children: [
|
|
@@ -1360,13 +1396,47 @@ function MatchPreviewBlock({
|
|
|
1360
1396
|
]
|
|
1361
1397
|
},
|
|
1362
1398
|
i
|
|
1363
|
-
) : /* @__PURE__ */
|
|
1399
|
+
) : /* @__PURE__ */ jsx21("p", { children: f.sentence }, i)
|
|
1364
1400
|
)
|
|
1365
1401
|
] });
|
|
1366
1402
|
}
|
|
1367
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
|
+
|
|
1368
1438
|
// src/components/club-dashboard/TeamDnaBlock.tsx
|
|
1369
|
-
import { jsx as
|
|
1439
|
+
import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1370
1440
|
function TeamDnaBlock({
|
|
1371
1441
|
block,
|
|
1372
1442
|
ui,
|
|
@@ -1374,32 +1444,32 @@ function TeamDnaBlock({
|
|
|
1374
1444
|
}) {
|
|
1375
1445
|
if (block.facts.length === 0) return null;
|
|
1376
1446
|
const heading = ui.clubTeamDnaHeading;
|
|
1377
|
-
return /* @__PURE__ */
|
|
1378
|
-
/* @__PURE__ */
|
|
1447
|
+
return /* @__PURE__ */ jsxs18("div", { className: "ss-w-cdash-lines", children: [
|
|
1448
|
+
/* @__PURE__ */ jsx23("span", { className: "ss-w-cdash-lines-heading", children: heading }),
|
|
1379
1449
|
block.facts.map(
|
|
1380
|
-
(f, i) => f.
|
|
1450
|
+
(f, i) => f.actionRef ? /* @__PURE__ */ jsxs18(
|
|
1381
1451
|
"button",
|
|
1382
1452
|
{
|
|
1383
1453
|
type: "button",
|
|
1384
1454
|
className: "ss-w-cdash-fact",
|
|
1385
|
-
onClick: () => onAction(f.
|
|
1455
|
+
onClick: () => onAction(f.label ?? f.sentence, { actionRef: f.actionRef }),
|
|
1386
1456
|
children: [
|
|
1387
1457
|
f.sentence,
|
|
1388
|
-
f.label ? /* @__PURE__ */
|
|
1458
|
+
f.label ? /* @__PURE__ */ jsxs18("span", { className: "ss-w-cdash-fact-label", children: [
|
|
1389
1459
|
" ",
|
|
1390
1460
|
f.label
|
|
1391
1461
|
] }) : null
|
|
1392
1462
|
]
|
|
1393
1463
|
},
|
|
1394
1464
|
i
|
|
1395
|
-
) : /* @__PURE__ */
|
|
1465
|
+
) : /* @__PURE__ */ jsx23("p", { children: f.sentence }, i)
|
|
1396
1466
|
)
|
|
1397
1467
|
] });
|
|
1398
1468
|
}
|
|
1399
1469
|
|
|
1400
1470
|
// src/components/club-dashboard/CountdownBlock.tsx
|
|
1401
1471
|
import { useEffect as useEffect3, useState as useState7 } from "react";
|
|
1402
|
-
import { jsx as
|
|
1472
|
+
import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1403
1473
|
var DAY_MS = 24 * 3600 * 1e3;
|
|
1404
1474
|
function pad2(n) {
|
|
1405
1475
|
return String(n).padStart(2, "0");
|
|
@@ -1424,30 +1494,31 @@ function CountdownBlock({ block, ui }) {
|
|
|
1424
1494
|
if (remainingMs <= 0) return null;
|
|
1425
1495
|
if (remainingMs > DAY_MS) return null;
|
|
1426
1496
|
const { h, m, s } = splitRemaining(remainingMs);
|
|
1427
|
-
return /* @__PURE__ */
|
|
1428
|
-
/* @__PURE__ */
|
|
1429
|
-
/* @__PURE__ */
|
|
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 }),
|
|
1430
1500
|
"h",
|
|
1431
1501
|
" ",
|
|
1432
|
-
/* @__PURE__ */
|
|
1502
|
+
/* @__PURE__ */ jsx24("span", { className: "ss-w-cdash-cd-m", children: m }),
|
|
1433
1503
|
"m",
|
|
1434
1504
|
" ",
|
|
1435
|
-
/* @__PURE__ */
|
|
1505
|
+
/* @__PURE__ */ jsx24("span", { className: "ss-w-cdash-cd-s", children: s }),
|
|
1436
1506
|
"s"
|
|
1437
1507
|
] }),
|
|
1438
|
-
/* @__PURE__ */
|
|
1508
|
+
/* @__PURE__ */ jsx24("div", { className: "ss-w-cdash-cd-label", children: ui.clubCountdownLabel })
|
|
1439
1509
|
] });
|
|
1440
1510
|
}
|
|
1441
1511
|
|
|
1442
1512
|
// src/components/club-dashboard/ClubDashboard.tsx
|
|
1443
|
-
import { jsx as
|
|
1513
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1444
1514
|
var CLUB_BLOCK_REGISTRY = {
|
|
1445
|
-
greetingHeader: ({ block }) => block.type === "greetingHeader" ? /* @__PURE__ */
|
|
1446
|
-
fixtureHero: ({ block, ui, onAction }) => block.type === "fixtureHero" ? /* @__PURE__ */
|
|
1447
|
-
formGuide: ({ block, ui }) => block.type === "formGuide" ? /* @__PURE__ */
|
|
1448
|
-
matchPreview: ({ block, ui, onAction }) => block.type === "matchPreview" ? /* @__PURE__ */
|
|
1449
|
-
|
|
1450
|
-
|
|
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
|
|
1451
1522
|
};
|
|
1452
1523
|
function ClubDashboard({
|
|
1453
1524
|
dashboard,
|
|
@@ -1455,39 +1526,39 @@ function ClubDashboard({
|
|
|
1455
1526
|
onAction
|
|
1456
1527
|
}) {
|
|
1457
1528
|
if (!dashboard.blocks.length) return null;
|
|
1458
|
-
return /* @__PURE__ */
|
|
1529
|
+
return /* @__PURE__ */ jsx25("div", { className: "ss-w-cdash", children: dashboard.blocks.map((block, i) => {
|
|
1459
1530
|
const Comp = Object.prototype.hasOwnProperty.call(CLUB_BLOCK_REGISTRY, block.type) ? CLUB_BLOCK_REGISTRY[block.type] : void 0;
|
|
1460
1531
|
if (!Comp) {
|
|
1461
1532
|
console.warn(`[club-dashboard] no renderer for block type "${block.type}"`);
|
|
1462
1533
|
return null;
|
|
1463
1534
|
}
|
|
1464
|
-
return /* @__PURE__ */
|
|
1535
|
+
return /* @__PURE__ */ jsx25("div", { className: "ss-w-cdash-block", children: /* @__PURE__ */ jsx25(Comp, { block, ui, onAction }) }, i);
|
|
1465
1536
|
}) });
|
|
1466
1537
|
}
|
|
1467
1538
|
|
|
1468
1539
|
// src/components/ChatMessage.tsx
|
|
1469
|
-
import { jsx as
|
|
1540
|
+
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1470
1541
|
function ChatMessage({ message, disabled, onAct, onTap, onClubAction, ui, slip }) {
|
|
1471
1542
|
if (message.role === "user") {
|
|
1472
|
-
return /* @__PURE__ */
|
|
1543
|
+
return /* @__PURE__ */ jsx26("div", { className: "ss-w-msg ss-w-user", children: /* @__PURE__ */ jsx26("div", { className: "ss-w-bubble", children: message.text }) });
|
|
1473
1544
|
}
|
|
1474
|
-
return /* @__PURE__ */
|
|
1475
|
-
message.text && !message.greetingDashboard && !message.clubDashboard ? /* @__PURE__ */
|
|
1476
|
-
message.greetingDashboard ? /* @__PURE__ */
|
|
1477
|
-
message.clubDashboard && ui ? /* @__PURE__ */
|
|
1478
|
-
/* @__PURE__ */
|
|
1479
|
-
/* @__PURE__ */
|
|
1480
|
-
/* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
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 })
|
|
1483
1554
|
] });
|
|
1484
1555
|
}
|
|
1485
1556
|
|
|
1486
1557
|
// src/components/IntentChips.tsx
|
|
1487
|
-
import { jsx as
|
|
1558
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
1488
1559
|
function IntentChips({ chips, onPick }) {
|
|
1489
1560
|
if (chips.length === 0) return null;
|
|
1490
|
-
return /* @__PURE__ */
|
|
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}`)) });
|
|
1491
1562
|
}
|
|
1492
1563
|
|
|
1493
1564
|
// src/scroll.ts
|
|
@@ -1497,7 +1568,7 @@ function isPinnedToBottom(el, threshold = PIN_THRESHOLD) {
|
|
|
1497
1568
|
}
|
|
1498
1569
|
|
|
1499
1570
|
// src/components/MessageList.tsx
|
|
1500
|
-
import { jsx as
|
|
1571
|
+
import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1501
1572
|
function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
1502
1573
|
const { state, send } = controller;
|
|
1503
1574
|
const listRef = useRef2(null);
|
|
@@ -1508,7 +1579,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1508
1579
|
}, [state.messages, state.status]);
|
|
1509
1580
|
const hasUserMessage = state.messages.some((m) => m.role === "user");
|
|
1510
1581
|
const hasDashboard = state.messages.some((m) => m.role === "assistant" && m.greetingDashboard);
|
|
1511
|
-
return /* @__PURE__ */
|
|
1582
|
+
return /* @__PURE__ */ jsxs21(
|
|
1512
1583
|
"div",
|
|
1513
1584
|
{
|
|
1514
1585
|
className: "ss-w-list",
|
|
@@ -1518,7 +1589,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1518
1589
|
if (listRef.current) pinnedRef.current = isPinnedToBottom(listRef.current);
|
|
1519
1590
|
},
|
|
1520
1591
|
children: [
|
|
1521
|
-
state.messages.map((m) => /* @__PURE__ */
|
|
1592
|
+
state.messages.map((m) => /* @__PURE__ */ jsx28(
|
|
1522
1593
|
ChatMessage,
|
|
1523
1594
|
{
|
|
1524
1595
|
message: m,
|
|
@@ -1528,21 +1599,21 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1528
1599
|
send(tile.actionValue, { displayText: tile.title });
|
|
1529
1600
|
if (m.role === "assistant" && m.greetingDashboard) onDashboardTap?.(tile, index, m.greetingDashboard.layout);
|
|
1530
1601
|
},
|
|
1531
|
-
onClubAction: (
|
|
1602
|
+
onClubAction: (label, opts) => send(label, { actionRef: opts.actionRef }),
|
|
1532
1603
|
ui,
|
|
1533
1604
|
slip
|
|
1534
1605
|
},
|
|
1535
1606
|
m.id
|
|
1536
1607
|
)),
|
|
1537
|
-
state.isStreaming && state.actionsLoading ? /* @__PURE__ */
|
|
1608
|
+
state.isStreaming && state.actionsLoading ? /* @__PURE__ */ jsx28(ActionButtons, { actions: [], loading: true, onAct: () => {
|
|
1538
1609
|
} }) : null,
|
|
1539
|
-
state.status ? /* @__PURE__ */
|
|
1540
|
-
state.error ? /* @__PURE__ */
|
|
1541
|
-
/* @__PURE__ */
|
|
1542
|
-
/* @__PURE__ */
|
|
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 })
|
|
1543
1614
|
] }) : null,
|
|
1544
|
-
!hasUserMessage && !hasDashboard ? /* @__PURE__ */
|
|
1545
|
-
/* @__PURE__ */
|
|
1615
|
+
!hasUserMessage && !hasDashboard ? /* @__PURE__ */ jsx28(IntentChips, { chips: state.starters, onPick: (t) => send(t) }) : null,
|
|
1616
|
+
/* @__PURE__ */ jsx28("div", { ref: endRef })
|
|
1546
1617
|
]
|
|
1547
1618
|
}
|
|
1548
1619
|
);
|
|
@@ -1550,7 +1621,7 @@ function MessageList({ controller, ui, slip, onDashboardTap }) {
|
|
|
1550
1621
|
|
|
1551
1622
|
// src/components/ChatInput.tsx
|
|
1552
1623
|
import { useState as useState8 } from "react";
|
|
1553
|
-
import { jsx as
|
|
1624
|
+
import { jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1554
1625
|
function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop response", sendLabel = "Send message" }) {
|
|
1555
1626
|
const [value, setValue] = useState8("");
|
|
1556
1627
|
const submit = () => {
|
|
@@ -1565,14 +1636,14 @@ function ChatInput({ placeholder, streaming, onSend, onStop, stopLabel = "Stop r
|
|
|
1565
1636
|
submit();
|
|
1566
1637
|
}
|
|
1567
1638
|
};
|
|
1568
|
-
return /* @__PURE__ */
|
|
1569
|
-
/* @__PURE__ */
|
|
1570
|
-
streaming ? /* @__PURE__ */
|
|
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, {}) })
|
|
1571
1642
|
] });
|
|
1572
1643
|
}
|
|
1573
1644
|
|
|
1574
1645
|
// src/components/ChatPanel.tsx
|
|
1575
|
-
import { jsx as
|
|
1646
|
+
import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1576
1647
|
var FULLSCREEN_QUERY = "(max-width: 639px)";
|
|
1577
1648
|
function useIsModal() {
|
|
1578
1649
|
const [modal, setModal] = useState9(false);
|
|
@@ -1596,10 +1667,10 @@ function ChatPanel({ controller, ui, slip, onDashboardTap }) {
|
|
|
1596
1667
|
window.addEventListener("keydown", onKey);
|
|
1597
1668
|
return () => window.removeEventListener("keydown", onKey);
|
|
1598
1669
|
}, [close]);
|
|
1599
|
-
return /* @__PURE__ */
|
|
1600
|
-
/* @__PURE__ */
|
|
1601
|
-
/* @__PURE__ */
|
|
1602
|
-
/* @__PURE__ */
|
|
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 })
|
|
1603
1674
|
] });
|
|
1604
1675
|
}
|
|
1605
1676
|
|
|
@@ -1991,10 +2062,27 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
|
|
|
1991
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); }
|
|
1992
2063
|
.ss-w-cdash-cd-h, .ss-w-cdash-cd-m, .ss-w-cdash-cd-s { color: var(--ss-w-accent); }
|
|
1993
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; }
|
|
1994
2082
|
`;
|
|
1995
2083
|
|
|
1996
2084
|
// src/StatsWidget.tsx
|
|
1997
|
-
import { jsx as
|
|
2085
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1998
2086
|
function buildClient(props) {
|
|
1999
2087
|
try {
|
|
2000
2088
|
if ("client" in props && props.client) {
|
|
@@ -2047,7 +2135,7 @@ function StatsWidget(props) {
|
|
|
2047
2135
|
}, [built, ui.injectStyles]);
|
|
2048
2136
|
if (!built) return null;
|
|
2049
2137
|
const attrs = themeAttrs(ui);
|
|
2050
|
-
return /* @__PURE__ */
|
|
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(
|
|
2051
2139
|
ChatFab,
|
|
2052
2140
|
{
|
|
2053
2141
|
label: ui.launcherLabel,
|