@sensiblestats/widget-react 0.46.0 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/index.cjs +60 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +60 -15
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -91,6 +91,7 @@ var STRINGS = {
|
|
|
91
91
|
accordionSuspended: "Suspended",
|
|
92
92
|
tabToday: "Today",
|
|
93
93
|
sectionLive: "Live",
|
|
94
|
+
halfTime: "HT",
|
|
94
95
|
staleStates: "Live scores can't be updated \u2014 showing the last known state."
|
|
95
96
|
},
|
|
96
97
|
tr: {
|
|
@@ -168,6 +169,7 @@ var STRINGS = {
|
|
|
168
169
|
accordionSuspended: "Ask\u0131da",
|
|
169
170
|
tabToday: "Bug\xFCn",
|
|
170
171
|
sectionLive: "Canl\u0131",
|
|
172
|
+
halfTime: "\u0130Y",
|
|
171
173
|
staleStates: "Canl\u0131 skorlar g\xFCncellenemiyor \u2014 son bilinen durum g\xF6steriliyor."
|
|
172
174
|
}
|
|
173
175
|
};
|
|
@@ -246,6 +248,7 @@ function normalizeUi(cfg) {
|
|
|
246
248
|
tabOdds: strings.tabOdds,
|
|
247
249
|
tabToday: strings.tabToday,
|
|
248
250
|
sectionLive: strings.sectionLive,
|
|
251
|
+
halfTime: strings.halfTime,
|
|
249
252
|
staleStates: strings.staleStates,
|
|
250
253
|
pinLabel: strings.pinLabel,
|
|
251
254
|
unpinLabel: strings.unpinLabel,
|
|
@@ -1505,8 +1508,40 @@ function dueMatchIds(groups, states, nowMs) {
|
|
|
1505
1508
|
return [...due];
|
|
1506
1509
|
}
|
|
1507
1510
|
|
|
1511
|
+
// src/liveClock.ts
|
|
1512
|
+
var STALE_READING_MS = 5 * 6e4;
|
|
1513
|
+
function parseMinute(label) {
|
|
1514
|
+
if (!label) return null;
|
|
1515
|
+
const plus = /^(\d+)\+(\d+)'$/.exec(label);
|
|
1516
|
+
if (plus) return Number(plus[1]) + Number(plus[2]);
|
|
1517
|
+
const plain = /^(\d+)'$/.exec(label);
|
|
1518
|
+
return plain ? Number(plain[1]) : null;
|
|
1519
|
+
}
|
|
1520
|
+
function readingAgeMs(state, nowMs) {
|
|
1521
|
+
if (!state?.stateAsOfUtc) return null;
|
|
1522
|
+
const t = Date.parse(state.stateAsOfUtc);
|
|
1523
|
+
return Number.isNaN(t) ? null : Math.max(0, nowMs - t);
|
|
1524
|
+
}
|
|
1525
|
+
function isReadingStale(state, nowMs) {
|
|
1526
|
+
if (state?.isHalfTime) return false;
|
|
1527
|
+
const age = readingAgeMs(state, nowMs);
|
|
1528
|
+
return age !== null && age > STALE_READING_MS;
|
|
1529
|
+
}
|
|
1530
|
+
function displayMinute(state, nowMs) {
|
|
1531
|
+
if (!state || state.phase !== "live") return null;
|
|
1532
|
+
if (state.isHalfTime) return null;
|
|
1533
|
+
if (isReadingStale(state, nowMs)) return null;
|
|
1534
|
+
const base = parseMinute(state.minuteLabel);
|
|
1535
|
+
if (base === null) return null;
|
|
1536
|
+
const age = readingAgeMs(state, nowMs);
|
|
1537
|
+
if (age === null) return state.minuteLabel ?? null;
|
|
1538
|
+
const advanced = base + Math.floor(age / 6e4);
|
|
1539
|
+
return `${advanced}'`;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1508
1542
|
// src/useMatchDiscovery.ts
|
|
1509
1543
|
var POLL_MS = 6e4;
|
|
1544
|
+
var CLOCK_MS = 1e4;
|
|
1510
1545
|
var ROLLOVER_CHECK_MS = 6e4;
|
|
1511
1546
|
var STALE_AFTER_FAILURES = 2;
|
|
1512
1547
|
function localDateOf(now) {
|
|
@@ -1519,6 +1554,7 @@ function useMatchDiscovery(opts) {
|
|
|
1519
1554
|
const [groups, setGroups] = useState2([]);
|
|
1520
1555
|
const [states, setStates] = useState2({});
|
|
1521
1556
|
const [failures, setFailures] = useState2(0);
|
|
1557
|
+
const [nowMs, setNowMs] = useState2(() => Date.now());
|
|
1522
1558
|
const [expanded, setExpanded] = useState2({});
|
|
1523
1559
|
const [touched, setTouched] = useState2({});
|
|
1524
1560
|
const groupsRef = useRef4(groups);
|
|
@@ -1596,16 +1632,21 @@ function useMatchDiscovery(opts) {
|
|
|
1596
1632
|
}, POLL_MS);
|
|
1597
1633
|
return () => clearInterval(id);
|
|
1598
1634
|
}, [opts.isOpen, tick, groups]);
|
|
1635
|
+
useEffect4(() => {
|
|
1636
|
+
if (!opts.isOpen) return;
|
|
1637
|
+
const id = setInterval(() => setNowMs(Date.now()), CLOCK_MS);
|
|
1638
|
+
return () => clearInterval(id);
|
|
1639
|
+
}, [opts.isOpen]);
|
|
1599
1640
|
const stale = failures >= STALE_AFTER_FAILURES;
|
|
1600
1641
|
const liveCount = useMemo2(
|
|
1601
|
-
() => stale ? 0 : Object.values(states).filter((s) => s.phase === "live").length,
|
|
1602
|
-
[states, stale]
|
|
1642
|
+
() => stale ? 0 : Object.values(states).filter((s) => s.phase === "live" && !isReadingStale(s, nowMs)).length,
|
|
1643
|
+
[states, stale, nowMs]
|
|
1603
1644
|
);
|
|
1604
1645
|
const toggleGroup = useCallback3((competitionId) => {
|
|
1605
1646
|
setTouched((prev) => ({ ...prev, [competitionId]: true }));
|
|
1606
1647
|
setExpanded((prev) => ({ ...prev, [competitionId]: !prev[competitionId] }));
|
|
1607
1648
|
}, []);
|
|
1608
|
-
return { groups, states, liveCount, stale, expanded, toggleGroup, _tick: tick };
|
|
1649
|
+
return { groups, states, nowMs, liveCount, stale, expanded, toggleGroup, _tick: tick };
|
|
1609
1650
|
}
|
|
1610
1651
|
|
|
1611
1652
|
// src/eventLogContext.ts
|
|
@@ -2963,7 +3004,7 @@ function computeDisplayMinute(minute, clockRunning, receivedAtMs) {
|
|
|
2963
3004
|
return minute + Math.min(Math.max(0, elapsedMinutes), MAX_LIVE_TICK_MINUTES);
|
|
2964
3005
|
}
|
|
2965
3006
|
function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
2966
|
-
const [
|
|
3007
|
+
const [displayMinute2, setDisplayMinute] = useState15(
|
|
2967
3008
|
() => computeDisplayMinute(minute, clockRunning, receivedAtMs)
|
|
2968
3009
|
);
|
|
2969
3010
|
useEffect9(() => {
|
|
@@ -2974,7 +3015,7 @@ function useLiveClock(minute, clockRunning, receivedAtMs) {
|
|
|
2974
3015
|
}, TICK_MS);
|
|
2975
3016
|
return () => window.clearInterval(id);
|
|
2976
3017
|
}, [minute, clockRunning, receivedAtMs]);
|
|
2977
|
-
return
|
|
3018
|
+
return displayMinute2;
|
|
2978
3019
|
}
|
|
2979
3020
|
|
|
2980
3021
|
// src/components/dashboard/LiveScoreCard.tsx
|
|
@@ -3006,7 +3047,7 @@ function LiveScoreCard({
|
|
|
3006
3047
|
if (!seedRef.current || seedRef.current.key !== seedKey) {
|
|
3007
3048
|
seedRef.current = { key: seedKey, receivedAtMs: Date.now() };
|
|
3008
3049
|
}
|
|
3009
|
-
const
|
|
3050
|
+
const displayMinute2 = useLiveClock(data.minute, data.clockRunning, seedRef.current.receivedAtMs);
|
|
3010
3051
|
const minuteSuffix = data.minuteLabel.replace(/^\d+/, "");
|
|
3011
3052
|
const scorers = scorersLine(goalEvents);
|
|
3012
3053
|
return /* @__PURE__ */ jsxs32("div", { className: "ss-w-fandash-card ss-w-fandash-live-score", children: [
|
|
@@ -3016,7 +3057,7 @@ function LiveScoreCard({
|
|
|
3016
3057
|
/* @__PURE__ */ jsx36("span", { className: "ss-w-fandash-live-dot", "aria-hidden": "true" }),
|
|
3017
3058
|
data.statusLabel
|
|
3018
3059
|
] }),
|
|
3019
|
-
/* @__PURE__ */ jsx36("span", { className: "ss-w-fandash-live-minute", children: `${
|
|
3060
|
+
/* @__PURE__ */ jsx36("span", { className: "ss-w-fandash-live-minute", children: `${displayMinute2}${minuteSuffix}` }),
|
|
3020
3061
|
data.competition ? /* @__PURE__ */ jsx36("span", { className: "ss-w-fandash-live-competition", children: data.competition }) : null
|
|
3021
3062
|
] }),
|
|
3022
3063
|
/* @__PURE__ */ jsxs32("div", { className: "ss-w-fandash-live-main", children: [
|
|
@@ -3698,12 +3739,14 @@ function Side({ name, crest }) {
|
|
|
3698
3739
|
/* @__PURE__ */ jsx49("span", { className: "ss-w-drow-nm", children: name })
|
|
3699
3740
|
] });
|
|
3700
3741
|
}
|
|
3701
|
-
function FixtureRow({ match, state, stale, ui, monitor }) {
|
|
3702
|
-
const
|
|
3742
|
+
function FixtureRow({ match, state, stale, nowMs, ui, monitor }) {
|
|
3743
|
+
const readingStale = isReadingStale(state, nowMs);
|
|
3744
|
+
const isLive = state?.phase === "live" && !stale && !readingStale;
|
|
3703
3745
|
const hasScore = (state?.phase === "live" || state?.phase === "fullTime") && typeof state.homeScore === "number" && typeof state.awayScore === "number";
|
|
3704
|
-
const
|
|
3705
|
-
|
|
3706
|
-
|
|
3746
|
+
const ticked = displayMinute(state, nowMs);
|
|
3747
|
+
const when = state?.isHalfTime && !stale ? ui.halfTime : isLive ? ticked ?? "\u2014" : state?.phase === "live" ? "\u2014" : kickoffLabel(match.kickoffUnix);
|
|
3748
|
+
return /* @__PURE__ */ jsxs44("div", { className: isLive || state?.isHalfTime ? "ss-w-drow ss-w-drow--live" : "ss-w-drow", children: [
|
|
3749
|
+
/* @__PURE__ */ jsx49("span", { className: isLive || state?.isHalfTime ? "ss-w-drow-when ss-w-drow-when--live" : "ss-w-drow-when", children: when }),
|
|
3707
3750
|
/* @__PURE__ */ jsxs44("span", { className: "ss-w-drow-fx", children: [
|
|
3708
3751
|
/* @__PURE__ */ jsx49(Side, { name: match.homeTeamName, crest: match.homeTeamImagePath }),
|
|
3709
3752
|
/* @__PURE__ */ jsx49("span", { className: "ss-w-drow-dash", children: "\u2013" }),
|
|
@@ -3716,7 +3759,7 @@ function FixtureRow({ match, state, stale, ui, monitor }) {
|
|
|
3716
3759
|
|
|
3717
3760
|
// src/components/CompetitionGroup.tsx
|
|
3718
3761
|
import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3719
|
-
function CompetitionGroup({ group, open, onToggle, states, stale, ui, monitor, disambiguate = false }) {
|
|
3762
|
+
function CompetitionGroup({ group, open, onToggle, states, stale, nowMs, ui, monitor, disambiguate = false }) {
|
|
3720
3763
|
const own = group.matches.filter((m) => states[m.matchId]?.phase !== "live" || stale);
|
|
3721
3764
|
const hasLive = own.length !== group.matches.length;
|
|
3722
3765
|
return /* @__PURE__ */ jsxs45("div", { className: "ss-w-grp", children: [
|
|
@@ -3733,14 +3776,14 @@ function CompetitionGroup({ group, open, onToggle, states, stale, ui, monitor, d
|
|
|
3733
3776
|
] }),
|
|
3734
3777
|
/* @__PURE__ */ jsx50("span", { className: "ss-w-grp-count", children: own.length })
|
|
3735
3778
|
] }),
|
|
3736
|
-
open && /* @__PURE__ */ jsx50("div", { className: "ss-w-grp-body", children: own.map((m) => /* @__PURE__ */ jsx50(FixtureRow, { match: m, state: states[m.matchId], stale, ui, monitor }, m.matchId)) })
|
|
3779
|
+
open && /* @__PURE__ */ jsx50("div", { className: "ss-w-grp-body", children: own.map((m) => /* @__PURE__ */ jsx50(FixtureRow, { match: m, state: states[m.matchId], stale, nowMs, ui, monitor }, m.matchId)) })
|
|
3737
3780
|
] });
|
|
3738
3781
|
}
|
|
3739
3782
|
|
|
3740
3783
|
// src/components/TodayPanel.tsx
|
|
3741
3784
|
import { Fragment as Fragment7, jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3742
3785
|
function TodayPanel({ discovery, ui, monitor }) {
|
|
3743
|
-
const { groups, states, stale, expanded, toggleGroup } = discovery;
|
|
3786
|
+
const { groups, states, nowMs, stale, expanded, toggleGroup } = discovery;
|
|
3744
3787
|
const liveRows = stale ? [] : groups.flatMap((group) => group.matches.filter((m) => states[m.matchId]?.phase === "live").map((match) => ({ match, rank: group.rank }))).sort((a, b) => a.rank - b.rank);
|
|
3745
3788
|
const nameCounts = groups.reduce((acc, g) => {
|
|
3746
3789
|
acc[g.competitionName] = (acc[g.competitionName] ?? 0) + 1;
|
|
@@ -3759,6 +3802,7 @@ function TodayPanel({ discovery, ui, monitor }) {
|
|
|
3759
3802
|
match,
|
|
3760
3803
|
state: states[match.matchId],
|
|
3761
3804
|
stale,
|
|
3805
|
+
nowMs,
|
|
3762
3806
|
ui,
|
|
3763
3807
|
monitor
|
|
3764
3808
|
},
|
|
@@ -3774,6 +3818,7 @@ function TodayPanel({ discovery, ui, monitor }) {
|
|
|
3774
3818
|
disambiguate: (nameCounts[group.competitionName] ?? 0) > 1,
|
|
3775
3819
|
states,
|
|
3776
3820
|
stale,
|
|
3821
|
+
nowMs,
|
|
3777
3822
|
ui,
|
|
3778
3823
|
monitor
|
|
3779
3824
|
},
|