@sensiblestats/widget-react 0.26.2 → 0.27.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,11 @@
1
1
  # @sensiblestats/widget-react
2
2
 
3
+ ## 0.27.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Entity-card stat-strip redesign: the player/team card renders as a horizontal stat strip instead of vertical stat rows, a W-D-L stat renders as a bar with the record as its label, competition scope tabs move above the strip, and the season chip is pinned to the top-right of the header.
8
+
3
9
  ## 0.26.2
4
10
 
5
11
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -853,8 +853,15 @@ function initials(name) {
853
853
  function shortSeason(season) {
854
854
  return season.replace(/\d{4}/g, (year) => year.slice(2));
855
855
  }
856
- function Crest({ image }) {
857
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-crest", style: { backgroundImage: `url(${image})` }, "aria-hidden": "true" });
856
+ function Crest({ image, label }) {
857
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
858
+ "span",
859
+ {
860
+ className: "ss-w-ecard-crest",
861
+ style: { backgroundImage: `url(${image})` },
862
+ ...label ? { role: "img", title: label, "aria-label": label } : { "aria-hidden": "true" }
863
+ }
864
+ );
858
865
  }
859
866
  function FormBar({ w, d, l }) {
860
867
  if (w + d + l === 0) return null;
@@ -864,73 +871,73 @@ function FormBar({ w, d, l }) {
864
871
  l > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-form-l", style: { flexGrow: l } }) : null
865
872
  ] });
866
873
  }
867
- function StatRows({ stats }) {
868
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-w-ecard-stats", children: stats.map((s) => {
869
- const m = RECORD_RE.exec(s.value);
870
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-row", children: [
871
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-rlabel", children: s.label }),
872
- m ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormBar, { w: Number(m[1]), d: Number(m[2]), l: Number(m[3]) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", {}),
873
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-rval", children: s.value })
874
- ] }, s.label);
875
- }) });
876
- }
877
- function CardBody({ c }) {
878
- const [active, setActive] = (0, import_react3.useState)(0);
879
- if (c.scopes.length === 0) return null;
880
- const season = c.season ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-season", children: shortSeason(c.season) }) : null;
881
- if (c.scopes.length === 1) {
882
- const only = c.scopes[0];
883
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-body", children: [
884
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-tabs ss-w-ecard-tabs-static", children: [
885
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-ecard-lead", title: only.label, children: [
886
- only.image ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Crest, { image: only.image }) : null,
887
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-lead-txt", children: only.label })
888
- ] }),
889
- season
890
- ] }),
891
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatRows, { stats: only.stats })
874
+ function StatCellView({ s }) {
875
+ const m = RECORD_RE.exec(s.value);
876
+ if (m) {
877
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-cell", children: [
878
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-cval", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FormBar, { w: Number(m[1]), d: Number(m[2]), l: Number(m[3]) }) }),
879
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-clabel", children: s.value })
892
880
  ] });
893
881
  }
894
- const current = c.scopes[active] ?? c.scopes[0];
895
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-body", children: [
896
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-tabs", role: "tablist", children: [
897
- c.scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
898
- "button",
899
- {
900
- type: "button",
901
- role: "tab",
902
- className: "ss-w-ecard-tab",
903
- "aria-selected": i === active,
904
- "aria-label": s.label,
905
- title: s.label,
906
- onClick: () => setActive(i),
907
- children: s.image ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Crest, { image: s.image }) : s.label
908
- },
909
- String(s.competitionId ?? "all")
910
- )),
911
- season
882
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-cell", children: [
883
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-cval", children: s.value }),
884
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-clabel", children: s.label })
885
+ ] });
886
+ }
887
+ function StatStrip({ stats }) {
888
+ if (stats.length === 0) return null;
889
+ const cols = Math.min(stats.length, 4);
890
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-w-ecard-strip", style: { gridTemplateColumns: `repeat(${cols}, 1fr)` }, children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatCellView, { s }, s.label + s.value)) });
891
+ }
892
+ function CardHeader({ c, showScopeCrest }) {
893
+ const onlyScope = c.scopes.length === 1 ? c.scopes[0] : null;
894
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-hd", children: [
895
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
896
+ "span",
897
+ {
898
+ className: c.kind === "team" ? "ss-w-thumb ss-w-team" : "ss-w-thumb",
899
+ style: c.image ? { backgroundImage: `url(${c.image})` } : void 0,
900
+ children: c.image ? "" : initials(c.name)
901
+ }
902
+ ),
903
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-ecard-idtext", children: [
904
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-nm", children: c.name }),
905
+ c.sub ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-sub", children: c.sub }) : null
912
906
  ] }),
913
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatRows, { stats: current.stats }, String(current.competitionId ?? "all"))
907
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-ecard-meta", children: [
908
+ showScopeCrest && onlyScope?.image ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Crest, { image: onlyScope.image, label: onlyScope.label }) : null,
909
+ c.season ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-season", children: shortSeason(c.season) }) : null
910
+ ] })
914
911
  ] });
915
912
  }
913
+ function ScopeTabs({ scopes, active, onSelect }) {
914
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-w-ecard-scopes", role: "tablist", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
915
+ "button",
916
+ {
917
+ type: "button",
918
+ role: "tab",
919
+ className: "ss-w-ecard-scope",
920
+ "aria-selected": i === active,
921
+ "aria-label": s.label,
922
+ title: s.label,
923
+ onClick: () => onSelect(i),
924
+ children: s.image ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Crest, { image: s.image }) : s.label
925
+ },
926
+ String(s.competitionId ?? "all")
927
+ )) });
928
+ }
916
929
  function EntityCardItem({ c }) {
930
+ const [active, setActive] = (0, import_react3.useState)(0);
917
931
  const hasBody = c.scopes.length > 0;
918
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: hasBody ? "ss-w-ecard" : "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: [
919
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-id", children: [
920
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
921
- "span",
922
- {
923
- className: c.kind === "team" ? "ss-w-thumb ss-w-team" : "ss-w-thumb",
924
- style: c.image ? { backgroundImage: `url(${c.image})` } : void 0,
925
- children: c.image ? "" : initials(c.name)
926
- }
927
- ),
928
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-ecard-idtext", children: [
929
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-nm", children: c.name }),
930
- c.sub ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-sub", children: c.sub }) : null
931
- ] })
932
- ] }),
933
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardBody, { c })
932
+ if (!hasBody) {
933
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-w-ecard ss-w-ecard-bare", "data-kind": c.kind, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardHeader, { c, showScopeCrest: false }) });
934
+ }
935
+ const multi = c.scopes.length > 1;
936
+ const scope = c.scopes[multi ? c.scopes[active] ? active : 0 : 0];
937
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
938
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardHeader, { c, showScopeCrest: !multi }),
939
+ multi ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ScopeTabs, { scopes: c.scopes, active, onSelect: setActive }) : null,
940
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatStrip, { stats: scope.stats })
934
941
  ] });
935
942
  }
936
943
  function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
@@ -1085,7 +1092,7 @@ function Crest2({ url, name, kind }) {
1085
1092
 
1086
1093
  // src/components/BettingInsightList.tsx
1087
1094
  var import_jsx_runtime11 = require("react/jsx-runtime");
1088
- function StatRows2({ stats }) {
1095
+ function StatRows({ stats }) {
1089
1096
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-bi-rows", children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-row", children: [
1090
1097
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-row-lbl", children: s.label }),
1091
1098
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-row-num", children: s.value })
@@ -1096,7 +1103,7 @@ function ScopedStats({ scopes }) {
1096
1103
  const current = scopes[active] ?? scopes[0] ?? { key: "", label: "", stats: [] };
1097
1104
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-scoped", children: [
1098
1105
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "ss-w-bi-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: "ss-w-bi-chip", "aria-pressed": i === active, onClick: () => setActive(i), children: s.label }, s.key)) }),
1099
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatRows2, { stats: current.stats }, current.key)
1106
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatRows, { stats: current.stats }, current.key)
1100
1107
  ] });
1101
1108
  }
1102
1109
  function hasStatsContent(it) {
@@ -1113,7 +1120,7 @@ function ReasonStrip({ it, ui }) {
1113
1120
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ss-w-bi-chart", "aria-hidden": "true" }),
1114
1121
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ss-w-bi-reason-body", children: [
1115
1122
  hasText ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: `ss-w-bi-text${open ? "" : " ss-w-bi-text-clamp"}`, children: it.text }) : null,
1116
- open && hasStats ? hasScopes ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScopedStats, { scopes: it.scopes }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatRows2, { stats: it.stats }) : null
1123
+ open && hasStats ? hasScopes ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScopedStats, { scopes: it.scopes }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatRows, { stats: it.stats }) : null
1117
1124
  ] }),
1118
1125
  expandable ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1119
1126
  "button",
@@ -2088,10 +2095,9 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
2088
2095
  /* entity cards */
2089
2096
  .ss-w-cards { display: flex; flex-direction: column; gap: 8px; }
2090
2097
 
2091
- /* Identity Hero: crest-led identity block | tabbed stats panel */
2092
- .ss-w-ecard { display: grid; grid-template-columns: 112px 1fr; align-items: stretch; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; text-align: left; }
2098
+ /* Entity card: identity header row over a horizontal stat strip */
2099
+ .ss-w-ecard { display: flex; flex-direction: column; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; overflow: hidden; text-align: left; }
2093
2100
 
2094
- .ss-w-ecard-id { display: flex; flex-direction: column; align-items: center; gap: 7px; text-align: center; padding: 13px 10px; border-right: 1px solid var(--ss-w-line); background: linear-gradient(158deg, var(--ss-w-bubble), color-mix(in srgb, var(--ss-w-accent) 9%, var(--ss-w-bubble))); }
2095
2101
  .ss-w-ecard-idtext { display: flex; flex-direction: column; gap: 1px; min-width: 0; max-width: 100%; }
2096
2102
  .ss-w-thumb { width: 54px; height: 54px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 16px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; box-shadow: 0 1px 3px rgba(0,0,0,.14); }
2097
2103
  .ss-w-thumb.ss-w-team { border-radius: 12px; }
@@ -2101,27 +2107,31 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
2101
2107
 
2102
2108
  /* bare card (no stat scopes): simple avatar + name row */
2103
2109
  .ss-w-ecard-bare { display: flex; align-items: center; }
2104
- .ss-w-ecard-bare .ss-w-ecard-id { flex-direction: row; text-align: left; gap: 11px; background: none; border-right: none; padding: 10px 12px; }
2105
- .ss-w-ecard-bare .ss-w-thumb { width: 40px; height: 40px; font-size: 13px; box-shadow: none; }
2106
- .ss-w-ecard-bare .ss-w-thumb.ss-w-team { border-radius: 10px; }
2107
-
2108
- .ss-w-ecard-body { min-width: 0; padding: 9px 12px 12px; display: flex; flex-direction: column; }
2109
-
2110
- /* tab strip seated on the stats panel's top edge; active tab underlined in accent */
2111
- .ss-w-ecard-tabs { display: flex; align-items: stretch; gap: 3px; border-bottom: 1px solid var(--ss-w-line); margin-bottom: 9px; flex-wrap: wrap; }
2112
- .ss-w-ecard-tab { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 620; color: var(--ss-w-faint); background: none; border: none; cursor: pointer; padding: 5px 8px 8px; margin-bottom: -1px; border-bottom: 2px solid transparent; }
2113
- .ss-w-ecard-tab[aria-selected="true"] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }
2114
- .ss-w-ecard-tabs-static { align-items: center; flex-wrap: nowrap; }
2115
- .ss-w-ecard-lead { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 640; color: var(--ss-w-ink); padding: 4px 2px 8px; min-width: 0; flex: 1; }
2116
- .ss-w-ecard-lead-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2110
+ .ss-w-ecard-bare .ss-w-ecard-hd { padding: 10px 12px; }
2111
+
2112
+ .ss-w-ecard-hd { display: flex; align-items: center; gap: 11px; padding: 11px 13px; }
2113
+ .ss-w-ecard-hd .ss-w-thumb { width: 40px; height: 40px; font-size: 13px; box-shadow: none; }
2114
+ .ss-w-ecard-hd .ss-w-thumb.ss-w-team { border-radius: 10px; }
2115
+ .ss-w-ecard-meta { display: inline-flex; align-items: center; gap: 7px; flex: none; align-self: flex-start; margin-left: auto; }
2116
+ .ss-w-ecard-meta .ss-w-ecard-season { margin: 0; }
2117
+
2118
+ /* scope tabs: reuse the underline pattern, relocated above the strip */
2119
+ .ss-w-ecard-scopes { display: flex; align-items: stretch; gap: 2px; padding: 0 11px; border-top: 1px solid var(--ss-w-line); flex-wrap: wrap; }
2120
+ .ss-w-ecard-scope { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 620; color: var(--ss-w-faint); background: none; border: none; cursor: pointer; padding: 7px 8px; margin-bottom: -1px; border-bottom: 2px solid transparent; }
2121
+ .ss-w-ecard-scope[aria-selected="true"] { color: var(--ss-w-ink); border-bottom-color: var(--ss-w-accent); }
2122
+ .ss-w-ecard-scope .ss-w-ecard-crest { width: 14px; height: 14px; }
2123
+ .ss-w-ecard-scopes + .ss-w-ecard-strip { border-top: none; }
2124
+
2117
2125
  .ss-w-ecard-crest { width: 15px; height: 15px; flex: none; display: block; border-radius: 4px; background-size: cover; background-position: center; }
2118
2126
  .ss-w-ecard-season { flex: none; margin-left: auto; align-self: center; margin-bottom: 5px; font-size: 10.5px; font-weight: 700; color: var(--ss-w-accent); background: color-mix(in srgb, var(--ss-w-accent) 13%, var(--ss-w-panel)); border-radius: 999px; padding: 3px 9px; white-space: nowrap; }
2119
- .ss-w-ecard-tabs-static .ss-w-ecard-season { margin-bottom: 4px; }
2120
2127
 
2121
- .ss-w-ecard-stats { display: flex; flex-direction: column; gap: 4px; }
2122
- .ss-w-ecard-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 10px; }
2123
- .ss-w-ecard-rlabel { font-size: 9.5px; text-transform: uppercase; letter-spacing: .045em; color: var(--ss-w-faint); font-weight: 600; }
2124
- .ss-w-ecard-rval { justify-self: end; font-size: 15px; font-weight: 720; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
2128
+ /* stat strip: 1px gap over a line-colored ground paints hairlines between cells, wrap-safe */
2129
+ .ss-w-ecard-strip { display: grid; gap: 1px; background: var(--ss-w-line); border-top: 1px solid var(--ss-w-line); }
2130
+ .ss-w-ecard-cell { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 4px; padding: 10px 4px 11px; background: var(--ss-w-panel); }
2131
+ .ss-w-ecard-cval { height: 20px; display: flex; align-items: center; font-size: 17px; font-weight: 720; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
2132
+ .ss-w-ecard-cval .ss-w-form { width: 42px; }
2133
+ .ss-w-ecard-clabel { font-size: 9px; text-transform: uppercase; letter-spacing: .05em; color: var(--ss-w-faint); font-weight: 600; font-variant-numeric: tabular-nums; }
2134
+
2125
2135
  .ss-w-form { justify-self: end; display: flex; height: 6px; width: 48px; border-radius: 4px; overflow: hidden; gap: 2px; }
2126
2136
  .ss-w-form span { display: block; border-radius: 2px; }
2127
2137
  .ss-w-form-w { background: var(--ss-w-pos); }