@sensiblestats/widget-react 0.8.0 → 0.9.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,20 @@
1
1
  # @sensiblestats/widget-react
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Entity cards now show the season and per-competition scope chips. `EntityCard`
8
+ drops the flat `stats` field in favor of `seasonName` + `scopes` (`All` aggregate
9
+ plus one scope per competition, each with an optional logo); the widget renders a
10
+ season label and, for 2+ competitions, a chip row that switches the stat set
11
+ client-side. `widget-embed` re-bundles `widget-react`, so it is republished too.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+ - @sensiblestats/widget-sdk@0.8.0
17
+
3
18
  ## 0.8.0
4
19
 
5
20
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -193,19 +193,27 @@ function readStatCells(raw) {
193
193
  }
194
194
  return cells;
195
195
  }
196
- function readStats(card) {
197
- return readStatCells(card.stats);
198
- }
199
196
  function toCardVM(card) {
200
197
  const entityType = str(card.entityType)?.toLowerCase();
201
198
  const kind = entityType === "player" ? "player" : entityType === "team" ? "team" : "generic";
199
+ const scopes = Array.isArray(card.scopes) ? card.scopes.map((s) => {
200
+ const label = str(s.label);
201
+ if (!label) return null;
202
+ return {
203
+ competitionId: typeof s.competitionId === "number" ? s.competitionId : null,
204
+ label,
205
+ image: str(s.imagePath),
206
+ stats: readStatCells(s.stats)
207
+ };
208
+ }).filter((s) => s !== null) : [];
202
209
  return {
203
210
  id: String(card.entityId),
204
211
  kind,
205
212
  name: card.canonicalName,
206
213
  image: str(card.imagePath) ?? str(card.imageUrl) ?? str(card.image_url) ?? str(card.logoUrl) ?? str(card.logo),
207
214
  sub: str(card.subtitle) ?? str(card.teamName) ?? str(card.leagueName) ?? str(card.position),
208
- stats: readStats(card)
215
+ season: str(card.seasonName),
216
+ scopes
209
217
  };
210
218
  }
211
219
  function toActionVM(action) {
@@ -539,13 +547,53 @@ var MAX_VISIBLE = 3;
539
547
  function initials(name) {
540
548
  return name.split(/\s+/).slice(0, 2).map((w) => w[0] ?? "").join("").toUpperCase();
541
549
  }
542
- function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
543
- const [expanded, setExpanded] = (0, import_react2.useState)(false);
544
- if (cards.length === 0) return null;
545
- const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
546
- const overflow = cards.length - MAX_VISIBLE;
547
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-cards", children: [
548
- visible.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
550
+ function Crest({ scope }) {
551
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-ecard-crest", style: { backgroundImage: `url(${scope.image})` }, "aria-hidden": "true" });
552
+ }
553
+ function StatRow({ stats }) {
554
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-w-ecard-stats", children: stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-stat", children: [
555
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("b", { children: s.value }),
556
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: s.label })
557
+ ] }, s.label)) });
558
+ }
559
+ function ScopeChips({ scopes }) {
560
+ const [active, setActive] = (0, import_react2.useState)(0);
561
+ const current = scopes[active] ?? scopes[0];
562
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
563
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-w-ecard-scopes", role: "group", children: scopes.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
564
+ "button",
565
+ {
566
+ type: "button",
567
+ className: "ss-w-ecard-chip",
568
+ "aria-pressed": i === active,
569
+ "aria-label": s.label,
570
+ title: s.label,
571
+ onClick: () => setActive(i),
572
+ children: s.image ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Crest, { scope: s }) : s.label
573
+ },
574
+ String(s.competitionId ?? "all")
575
+ )) }),
576
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatRow, { stats: current.stats }, String(current.competitionId ?? "all"))
577
+ ] });
578
+ }
579
+ function CardScopes({ scopes }) {
580
+ if (scopes.length === 0) return null;
581
+ if (scopes.length === 1) {
582
+ const only = scopes[0];
583
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
584
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-ecard-tag", children: [
585
+ only.image ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Crest, { scope: only }) : null,
586
+ only.label
587
+ ] }),
588
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatRow, { stats: only.stats })
589
+ ] });
590
+ }
591
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ScopeChips, { scopes });
592
+ }
593
+ function EntityCardItem({ c }) {
594
+ const season = c.scopes.length > 0 ? c.season : void 0;
595
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard", "data-kind": c.kind, children: [
596
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-ecard-head", children: [
549
597
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
550
598
  "span",
551
599
  {
@@ -557,13 +605,23 @@ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMore
557
605
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-meta", children: [
558
606
  c.kind !== "generic" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-kind", children: c.kind }) : null,
559
607
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-nm", children: c.name }),
560
- c.sub ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-sub", children: c.sub }) : null
561
- ] }),
562
- c.stats.map((s) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-stat", children: [
563
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("b", { children: s.value }),
564
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: s.label })
565
- ] }, s.label))
566
- ] }, c.id)),
608
+ c.sub || season ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-w-sub", children: [
609
+ c.sub,
610
+ c.sub && season ? " \xB7 " : "",
611
+ season ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-w-season", children: season }) : null
612
+ ] }) : null
613
+ ] })
614
+ ] }),
615
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardScopes, { scopes: c.scopes })
616
+ ] });
617
+ }
618
+ function EntityCardList({ cards, disabled, showLessLabel = "Show less", showMoreLabel = (n) => `Show ${n} more` }) {
619
+ const [expanded, setExpanded] = (0, import_react2.useState)(false);
620
+ if (cards.length === 0) return null;
621
+ const visible = expanded ? cards : cards.slice(0, MAX_VISIBLE);
622
+ const overflow = cards.length - MAX_VISIBLE;
623
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-w-cards", children: [
624
+ visible.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(EntityCardItem, { c }, c.id)),
567
625
  overflow > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "ss-w-cards-more", disabled, onClick: () => setExpanded((v) => !v), children: expanded ? showLessLabel : showMoreLabel(overflow) }) : null
568
626
  ] });
569
627
  }
@@ -1017,7 +1075,8 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
1017
1075
 
1018
1076
  /* entity cards */
1019
1077
  .ss-w-cards { display: flex; flex-direction: column; gap: 7px; }
1020
- .ss-w-ecard { display: flex; align-items: center; gap: 11px; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 11px; text-align: left; }
1078
+ .ss-w-ecard { display: flex; flex-direction: column; align-items: stretch; gap: 8px; width: 100%; background: var(--ss-w-panel); border: 1px solid var(--ss-w-line); border-radius: 12px; padding: 8px 11px; text-align: left; }
1079
+ .ss-w-ecard-head { display: flex; align-items: center; gap: 11px; }
1021
1080
  .ss-w-thumb { width: 40px; height: 40px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 13px; font-weight: 700; color: #fff; background-color: var(--ss-w-nav); background-size: cover; background-position: center; }
1022
1081
  .ss-w-thumb.ss-w-team { border-radius: 10px; }
1023
1082
  .ss-w-ecard[data-kind="player"] .ss-w-thumb { background-color: var(--ss-w-accent); }
@@ -1025,7 +1084,14 @@ var WIDGET_CSS = `.ss-w-root { all: revert; }
1025
1084
  .ss-w-kind { font-size: 8.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ss-w-faint); line-height: 1.3; }
1026
1085
  .ss-w-nm { font-weight: 660; }
1027
1086
  .ss-w-sub { font-size: 11px; color: var(--ss-w-faint); }
1028
- .ss-w-stat { margin-left: auto; text-align: center; }
1087
+ .ss-w-season { color: var(--ss-w-accent); font-weight: 660; }
1088
+ .ss-w-ecard-scopes { display: inline-flex; align-items: center; gap: 2px; flex-wrap: wrap; align-self: flex-start; background: var(--ss-w-bubble); border: 1px solid var(--ss-w-line); border-radius: 9px; padding: 2px; }
1089
+ .ss-w-ecard-chip { display: inline-flex; align-items: center; font-size: 11px; font-weight: 600; border: none; border-radius: 7px; padding: 4px 8px; color: var(--ss-w-faint); background: none; cursor: pointer; }
1090
+ .ss-w-ecard-chip[aria-pressed="true"] { color: var(--ss-w-ink); background: var(--ss-w-panel); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
1091
+ .ss-w-ecard-crest { width: 16px; height: 16px; display: block; border-radius: 4px; background-size: cover; background-position: center; }
1092
+ .ss-w-ecard-tag { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; font-size: 11px; font-weight: 600; color: var(--ss-w-faint); }
1093
+ .ss-w-ecard-stats { display: flex; gap: 16px; }
1094
+ .ss-w-stat { text-align: center; }
1029
1095
  .ss-w-stat b { display: block; font-variant-numeric: tabular-nums; }
1030
1096
  .ss-w-stat span { font-size: 9px; text-transform: uppercase; color: var(--ss-w-faint); }
1031
1097
  .ss-w-cards-more { align-self: flex-start; font-size: 11.5px; font-weight: 560; color: var(--ss-w-accent); background: none; border: none; cursor: pointer; padding: 3px 2px; }