@sensiblestats/widget-react 0.41.0 → 0.43.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,24 @@
1
1
  # @sensiblestats/widget-react
2
2
 
3
+ ## 0.43.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Betting cards (insight, market-odds, odds-movement) now render a server-supplied `kickoffLabel`
8
+ in the operator's timezone and language when present, falling back to browser-zone formatting of
9
+ `kickoffUtc` for older servers.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+ - @sensiblestats/widget-sdk@0.31.0
15
+
16
+ ## 0.42.0
17
+
18
+ ### Minor Changes
19
+
20
+ - Two-tier layout for betting-insight cards so nothing truncates on a narrow panel: the competition, kickoff and match pin sit on a quiet meta line above a full-width fixture line (long club names no longer clip), and the market label gets its own line above the selection · odds · slip · pin pick row. The market-odds card's fixture line adopts the same hero weight so both card types read consistently.
21
+
3
22
  ## 0.41.0
4
23
 
5
24
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -534,7 +534,8 @@ function toInsightVM(insight) {
534
534
  homeCrest: str(insight.homeTeamImagePath),
535
535
  awayCrest: str(insight.awayTeamImagePath),
536
536
  competitionCrest: str(insight.competitionImagePath),
537
- kickoffUtc: str(insight.kickoffUtc)
537
+ kickoffUtc: str(insight.kickoffUtc),
538
+ kickoffLabel: str(insight.kickoffLabel)
538
539
  };
539
540
  }
540
541
  function toSlipSelection(vm, conversationId) {
@@ -583,6 +584,7 @@ function toMarketOddsVM(card) {
583
584
  competitionCrest: str(card.competitionImagePath),
584
585
  competition: str(card.competitionName),
585
586
  kickoffUtc: str(card.kickoffUtc),
587
+ kickoffLabel: str(card.kickoffLabel),
586
588
  bookmaker: rows.map((r) => str(r.bookmakerName)).find(Boolean),
587
589
  updatedAt: updated.length > 0 ? updated[updated.length - 1] : void 0,
588
590
  isLive: rows.some((r) => r.isLive === true),
@@ -1937,58 +1939,60 @@ function CardFixture({ it }) {
1937
1939
  }
1938
1940
  function InsightCard({ it, ui, slip, monitor }) {
1939
1941
  const live = it.isLive || it.phase === "live";
1940
- const kickoff = it.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(it.kickoffUtc) : void 0;
1942
+ const kickoffFallback = it.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(it.kickoffUtc) : void 0;
1943
+ const kickoff = it.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
1941
1944
  const hasNamedTeams = !!it.homeTeamName && !!it.awayTeamName;
1942
1945
  const leftIsFixture = hasNamedTeams || !!it.fixture;
1943
- const compInMeta = leftIsFixture && !!it.competition;
1944
1946
  const showPin = !!monitor && it.pinEnabled;
1945
1947
  const showHeader = leftIsFixture || !!it.competition || live || !!kickoff || showPin;
1948
+ const headerControls = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1949
+ live ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "ss-w-bi-live", children: [
1950
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
1951
+ ui?.liveLabel ?? "Live"
1952
+ ] }) : null,
1953
+ kickoff ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-kick", children: kickoff }) : null,
1954
+ showPin && ui ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PinToggle, { ui, monitor, pin: { kind: "match", matchId: it.matchId } }) : null
1955
+ ] });
1946
1956
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-binsight", children: [
1947
- showHeader ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-header", children: [
1957
+ showHeader ? leftIsFixture ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-head", children: [
1958
+ it.competition || live || kickoff || showPin ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-meta", children: [
1959
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-meta-left", children: it.competition ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1960
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Crest2, { kind: "comp", url: it.competitionCrest, name: it.competition }),
1961
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-comp", children: it.competition })
1962
+ ] }) : null }),
1963
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-meta-right", children: headerControls })
1964
+ ] }) : null,
1965
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "ss-w-bi-fixture-line", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardFixture, { it }) })
1966
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-header", children: [
1948
1967
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-header-left", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardFixture, { it }) }),
1949
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "ss-w-bi-header-right", children: [
1950
- live ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "ss-w-bi-live", children: [
1951
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
1952
- ui?.liveLabel ?? "Live"
1953
- ] }) : null,
1954
- compInMeta ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-comp-meta", title: it.competition, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Crest2, { kind: "comp", url: it.competitionCrest, name: it.competition }) }) : null,
1955
- kickoff ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "ss-w-bi-kick", children: [
1956
- kickoff.dayLabel,
1957
- " ",
1958
- kickoff.time
1959
- ] }) : null,
1960
- showPin && ui ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PinToggle, { ui, monitor, pin: { kind: "match", matchId: it.matchId } }) : null
1961
- ] })
1968
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-header-right", children: headerControls })
1962
1969
  ] }) : null,
1963
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-action-row", children: [
1964
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "ss-w-bi-pick", children: [
1965
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-market", children: it.market }),
1966
- it.selection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1967
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-pick-dot", "aria-hidden": "true", children: "\xB7" }),
1968
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-sel", children: it.selection })
1969
- ] }) : null
1970
- ] }),
1971
- it.odds ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "ss-w-bi-odds", children: [
1972
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("b", { children: it.odds }),
1973
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(OddsMovementBadge, { previous: it.previousOdds, current: it.odds, direction: it.movementDirection, ui }),
1974
- it.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
1975
- ] }) : null,
1976
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AddToSlipButton, { it, slip, ui }),
1977
- showPin && ui ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1978
- PinToggle,
1979
- {
1980
- ui,
1981
- monitor,
1982
- pin: {
1983
- kind: "selection",
1984
- matchId: it.matchId,
1985
- marketDeveloperName: it.marketDeveloperName,
1986
- selectionLabel: it.selectionLabel,
1987
- line: it.line,
1988
- matchOddsId: it.matchOddsId
1970
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-action", children: [
1971
+ it.market ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-market", children: it.market }) : null,
1972
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "ss-w-bi-pick-row", children: [
1973
+ it.selection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-sel", children: it.selection }) : null,
1974
+ it.odds ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "ss-w-bi-odds", children: [
1975
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("b", { children: it.odds }),
1976
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(OddsMovementBadge, { previous: it.previousOdds, current: it.odds, direction: it.movementDirection, ui }),
1977
+ it.bookmaker ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-book", children: it.bookmaker }) : null
1978
+ ] }) : null,
1979
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AddToSlipButton, { it, slip, ui }),
1980
+ showPin && ui ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1981
+ PinToggle,
1982
+ {
1983
+ ui,
1984
+ monitor,
1985
+ pin: {
1986
+ kind: "selection",
1987
+ matchId: it.matchId,
1988
+ marketDeveloperName: it.marketDeveloperName,
1989
+ selectionLabel: it.selectionLabel,
1990
+ line: it.line,
1991
+ matchOddsId: it.matchOddsId
1992
+ }
1989
1993
  }
1990
- }
1991
- ) : null
1994
+ ) : null
1995
+ ] })
1992
1996
  ] }),
1993
1997
  it.isMarketFloor ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ss-w-bi-floor", children: ui?.marketFloorLabel ?? "Market price \xB7 not a value pick" }) : null,
1994
1998
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ReasonStrip, { it, ui }),
@@ -2019,7 +2023,8 @@ function OddsRow({ vm, row, ui, slip, inSlipIds }) {
2019
2023
  }
2020
2024
  function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }) {
2021
2025
  const [open, setOpen] = (0, import_react13.useState)(false);
2022
- const kickoff = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
2026
+ const kickoffFallback = vm.kickoffUtc && ui?.bettingKickoff ? ui.bettingKickoff(vm.kickoffUtc) : void 0;
2027
+ const kickoff = vm.kickoffLabel ?? (kickoffFallback ? `${kickoffFallback.dayLabel} ${kickoffFallback.time}` : void 0);
2023
2028
  const hasNamedTeams = !!vm.homeTeamName && !!vm.awayTeamName;
2024
2029
  const showPin = !!monitor && vm.pinEnabled;
2025
2030
  const showMarketPin = showPin && !pinRef;
@@ -2036,11 +2041,7 @@ function MarketOddsCard({ vm, ui, slip, monitor, inSlipIds, hideHeader, pinRef }
2036
2041
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-live-dot", "aria-hidden": "true" }),
2037
2042
  ui?.liveLabel ?? "Live"
2038
2043
  ] }) : null,
2039
- kickoff ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "ss-w-bi-kick", children: [
2040
- kickoff.dayLabel,
2041
- " ",
2042
- kickoff.time
2043
- ] }) : null,
2044
+ kickoff ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ss-w-bi-kick", children: kickoff }) : null,
2044
2045
  showPin && ui ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2045
2046
  PinToggle,
2046
2047
  {
@@ -3698,10 +3699,18 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
3698
3699
  .ss-w-binsights { display: flex; flex-direction: column; gap: 7px; }
3699
3700
  .ss-w-binsight { background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; border-left: 3px solid var(--ss-w-accent); padding: 9px 11px; display: flex; flex-direction: column; gap: 8px; }
3700
3701
 
3701
- /* row 1: competition logo + name on the left, live badge + kickoff on the right */
3702
+ /* header, competition-hero fallback: comp on the left, live badge + kickoff + pin on the right,
3703
+ all on one line (used when there is no fixture, and by MarketOddsCardList) */
3702
3704
  .ss-w-bi-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; padding-bottom: 7px; border-bottom: 1px solid var(--ss-w-line); }
3703
3705
  .ss-w-bi-header-left { display: inline-flex; align-items: center; gap: 6px; min-width: 0; flex: 1; font-size: 12.5px; font-weight: 650; color: var(--ss-w-ink); }
3704
3706
  .ss-w-bi-header-right { display: inline-flex; align-items: center; gap: 8px; flex: none; }
3707
+ /* two-tier header: a quiet meta line (competition + kickoff + match pin) stacked above the
3708
+ fixture, so long club names get the whole width to themselves and stop truncating (u350) */
3709
+ .ss-w-bi-head { display: flex; flex-direction: column; gap: 6px; padding-bottom: 7px; border-bottom: 1px solid var(--ss-w-line); }
3710
+ .ss-w-bi-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }
3711
+ .ss-w-bi-meta-left { display: inline-flex; align-items: center; gap: 5px; min-width: 0; flex: 1; }
3712
+ .ss-w-bi-meta-right { display: inline-flex; align-items: center; gap: 8px; flex: none; }
3713
+ .ss-w-bi-fixture-line { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }
3705
3714
  .ss-w-bi-comp { font-size: 10.5px; color: var(--ss-w-faint); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
3706
3715
  .ss-w-bi-kick { font-size: 10.5px; font-weight: 600; color: var(--ss-w-faint); white-space: nowrap; flex: none; }
3707
3716
  .ss-w-bi-live { font-size: 8.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: #fff; background: #c0392b; border-radius: 4px; padding: 1px 5px; display: inline-flex; align-items: center; gap: 4px; flex: none; }
@@ -3713,24 +3722,24 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
3713
3722
  .ss-w-bi-crest { width: 24px; height: 24px; flex: none; display: block; border-radius: 50%; object-fit: contain; }
3714
3723
  .ss-w-bi-crest-mono { display: grid; place-items: center; font-size: 10px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 16%, var(--ss-w-panel)); }
3715
3724
 
3716
- /* header fixture atoms (team hero lives in .ss-w-bi-header-left; comp demotes to the meta) */
3725
+ /* fixture atoms -- crest-flanked team pair; shared by the insight fixture line and MarketOddsCardList */
3717
3726
  .ss-w-bi-team { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
3718
3727
  .ss-w-bi-vs { font-size: 10px; font-weight: 600; color: var(--ss-w-faint); flex: none; }
3719
3728
  .ss-w-bi-fixture-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
3720
- .ss-w-bi-comp-meta { display: inline-flex; align-items: center; gap: 5px; flex: none; min-width: 0; }
3721
- /* shared crest-flanked team row, still consumed by MarketOddsCardList */
3722
- .ss-w-bi-fixture { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; font-size: 12px; font-weight: 650; color: var(--ss-w-ink); }
3723
-
3724
- /* row 2: one action line -- market \xB7 selection (left, market ellipsises first), odds, slip button */
3725
- .ss-w-bi-action-row { display: flex; align-items: center; gap: 9px; }
3726
- .ss-w-bi-pick { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 6px; }
3727
- .ss-w-bi-market { font-size: 12px; font-weight: 600; line-height: 1.2; color: var(--ss-w-faint); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
3728
- .ss-w-bi-pick-dot { flex: none; color: var(--ss-w-faint); font-weight: 700; }
3729
- .ss-w-bi-sel { flex: none; font-size: 12.5px; font-weight: 700; line-height: 1.2; color: var(--ss-w-ink); white-space: nowrap; }
3730
- .ss-w-bi-odds { flex: none; display: flex; align-items: baseline; justify-content: flex-end; gap: 5px; }
3729
+ /* shared crest-flanked team row (MarketOddsCardList); matches .ss-w-bi-fixture-line's hero weight
3730
+ so the fixture reads the same on both card types (u350) */
3731
+ .ss-w-bi-fixture { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; font-size: 13px; font-weight: 700; color: var(--ss-w-ink); }
3732
+
3733
+ /* row 2, two-tier: the market label owns a full-width line above the pick row (selection grows
3734
+ left, odds + slip + pin sit right), so neither the market name nor the fixture clips (u350) */
3735
+ .ss-w-bi-action { display: flex; flex-direction: column; gap: 6px; }
3736
+ .ss-w-bi-market { font-size: 12px; font-weight: 600; line-height: 1.25; color: var(--ss-w-faint); min-width: 0; }
3737
+ .ss-w-bi-pick-row { display: flex; align-items: center; gap: 9px; }
3738
+ .ss-w-bi-sel { flex: 1; min-width: 0; font-size: 13px; font-weight: 700; line-height: 1.2; color: var(--ss-w-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
3739
+ .ss-w-bi-odds { flex: none; margin-left: auto; display: flex; align-items: baseline; justify-content: flex-end; gap: 5px; }
3731
3740
  .ss-w-bi-odds b { font-size: 20px; font-family: ui-monospace, monospace; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ss-w-accent); line-height: 1.05; }
3732
3741
  .ss-w-bi-book { font-size: 9.5px; color: var(--ss-w-faint); }
3733
- .ss-w-bi-action-row .ss-w-slip { flex: none; }
3742
+ .ss-w-bi-pick-row .ss-w-slip { flex: none; }
3734
3743
 
3735
3744
  /* row 3: bar-chart glyph + reasoning prose + stats-expander chevron, in a subtle strip */
3736
3745
  .ss-w-bi-reason { display: flex; align-items: flex-start; gap: 8px; background: var(--ss-w-bubble); border-radius: 10px; padding: 8px 10px; }