@sportsdataverse/sdvplot 0.1.0 → 0.2.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/NOTICE.md +15 -0
- package/README.md +84 -8
- package/dist/chartjs-surface.d.ts +2 -2
- package/dist/chartjs-surface.js +2 -2
- package/dist/chartjs-surface.js.map +1 -1
- package/dist/chartjs.d.ts +32 -2
- package/dist/chartjs.js +7 -4
- package/dist/chartjs.js.map +1 -1
- package/dist/chunk-57WFSI4Q.js +128 -0
- package/dist/chunk-57WFSI4Q.js.map +1 -0
- package/dist/{chunk-KKH6ABMA.js → chunk-7ULOCCFL.js} +94 -4
- package/dist/chunk-7ULOCCFL.js.map +1 -0
- package/dist/chunk-AMXASQHT.js +120 -0
- package/dist/chunk-AMXASQHT.js.map +1 -0
- package/dist/chunk-B2MP37SR.js +175 -0
- package/dist/chunk-B2MP37SR.js.map +1 -0
- package/dist/{chunk-NLPH2VZT.js → chunk-DYMUVE6K.js} +4 -4
- package/dist/{chunk-NLPH2VZT.js.map → chunk-DYMUVE6K.js.map} +1 -1
- package/dist/{chunk-QY65DUEF.js → chunk-H2C3FMMA.js} +4 -10
- package/dist/chunk-H2C3FMMA.js.map +1 -0
- package/dist/{chunk-JJFTD4VB.js → chunk-J4P4HDBF.js} +4 -4
- package/dist/{chunk-JJFTD4VB.js.map → chunk-J4P4HDBF.js.map} +1 -1
- package/dist/chunk-M3XD2OSN.js +132 -0
- package/dist/chunk-M3XD2OSN.js.map +1 -0
- package/dist/{chunk-OKEE4AH6.js → chunk-OIILARXI.js} +3 -3
- package/dist/{chunk-OKEE4AH6.js.map → chunk-OIILARXI.js.map} +1 -1
- package/dist/chunk-RPVVJY74.js +170 -0
- package/dist/chunk-RPVVJY74.js.map +1 -0
- package/dist/chunk-UL5M6KDE.js +205 -0
- package/dist/chunk-UL5M6KDE.js.map +1 -0
- package/dist/chunk-WQT4IVLX.js +10 -0
- package/dist/chunk-WQT4IVLX.js.map +1 -0
- package/dist/{chunk-TAXO3VXH.js → chunk-ZAEQXFJM.js} +3 -3
- package/dist/{chunk-TAXO3VXH.js.map → chunk-ZAEQXFJM.js.map} +1 -1
- package/dist/cytoscape.d.ts +188 -0
- package/dist/cytoscape.js +219 -0
- package/dist/cytoscape.js.map +1 -0
- package/dist/d3.d.ts +3 -3
- package/dist/d3.js +6 -6
- package/dist/d3.js.map +1 -1
- package/dist/deckgl.d.ts +232 -0
- package/dist/deckgl.js +197 -0
- package/dist/deckgl.js.map +1 -0
- package/dist/echarts.js +5 -5
- package/dist/g2.d.ts +251 -0
- package/dist/g2.js +102 -0
- package/dist/g2.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -5
- package/dist/lightweight-charts.d.ts +217 -0
- package/dist/lightweight-charts.js +155 -0
- package/dist/lightweight-charts.js.map +1 -0
- package/dist/maplibre.d.ts +271 -0
- package/dist/maplibre.js +175 -0
- package/dist/maplibre.js.map +1 -0
- package/dist/mui.d.ts +338 -0
- package/dist/mui.js +184 -0
- package/dist/mui.js.map +1 -0
- package/dist/nivo.d.ts +193 -0
- package/dist/nivo.js +8 -0
- package/dist/nivo.js.map +1 -0
- package/dist/perspective.d.ts +198 -0
- package/dist/perspective.js +171 -0
- package/dist/perspective.js.map +1 -0
- package/dist/placement-UWkqUzpa.d.ts +32 -0
- package/dist/plot.d.ts +7 -5
- package/dist/plot.js +9 -8
- package/dist/plot.js.map +1 -1
- package/dist/plotly.js +5 -5
- package/dist/react.d.ts +279 -3
- package/dist/react.js +364 -6
- package/dist/react.js.map +1 -1
- package/dist/recharts.d.ts +162 -0
- package/dist/recharts.js +8 -0
- package/dist/recharts.js.map +1 -0
- package/dist/shadcn.d.ts +83 -0
- package/dist/shadcn.js +88 -0
- package/dist/shadcn.js.map +1 -0
- package/dist/shots.js +3 -2
- package/dist/shots.js.map +1 -1
- package/dist/surface-TR7YFJW3.js +4 -0
- package/dist/surface-TR7YFJW3.js.map +1 -0
- package/dist/surfaces-MIG7HOFU.js +6 -0
- package/dist/surfaces-MIG7HOFU.js.map +1 -0
- package/dist/surfaces-W-odWLpT.d.ts +47 -0
- package/dist/svelte/HeadshotMark.svelte +25 -0
- package/dist/svelte/HeadshotMark.svelte.d.ts +10 -0
- package/dist/svelte/HeadshotMark.svelte.d.ts.map +1 -0
- package/dist/svelte/LogoMark.svelte +25 -0
- package/dist/svelte/LogoMark.svelte.d.ts +10 -0
- package/dist/svelte/LogoMark.svelte.d.ts.map +1 -0
- package/dist/svelte/Marks.svelte +25 -0
- package/dist/svelte/Marks.svelte.d.ts +10 -0
- package/dist/svelte/Marks.svelte.d.ts.map +1 -0
- package/dist/svelte/Surface.svelte +29 -0
- package/dist/svelte/Surface.svelte.d.ts +9 -0
- package/dist/svelte/Surface.svelte.d.ts.map +1 -0
- package/dist/svelte/SurfaceBackdrop.svelte +26 -0
- package/dist/svelte/SurfaceBackdrop.svelte.d.ts +11 -0
- package/dist/svelte/SurfaceBackdrop.svelte.d.ts.map +1 -0
- package/dist/svelte/index.d.ts +13 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +11 -0
- package/dist/svelte-core.d.ts +139 -0
- package/dist/svelte-core.js +123 -0
- package/dist/svelte-core.js.map +1 -0
- package/dist/tanstack.d.ts +240 -0
- package/dist/tanstack.js +110 -0
- package/dist/tanstack.js.map +1 -0
- package/dist/testing.js +4 -5
- package/dist/testing.js.map +1 -1
- package/dist/three.d.ts +223 -0
- package/dist/three.js +50 -0
- package/dist/three.js.map +1 -0
- package/dist/{tiers-B6pUBPcE.d.ts → tiers-BN4md-GB.d.ts} +2 -30
- package/dist/unovis.d.ts +127 -0
- package/dist/unovis.js +108 -0
- package/dist/unovis.js.map +1 -0
- package/dist/uplot.d.ts +120 -0
- package/dist/uplot.js +110 -0
- package/dist/uplot.js.map +1 -0
- package/dist/vega.js +5 -5
- package/dist/victory.d.ts +107 -0
- package/dist/victory.js +38 -0
- package/dist/victory.js.map +1 -0
- package/package.json +218 -6
- package/dist/chunk-KKH6ABMA.js.map +0 -1
- package/dist/chunk-QY65DUEF.js.map +0 -1
- package/dist/chunk-RMT2GMFH.js +0 -97
- package/dist/chunk-RMT2GMFH.js.map +0 -1
- package/dist/chunk-SEBO35DV.js +0 -76
- package/dist/chunk-SEBO35DV.js.map +0 -1
- package/dist/chunk-TDNBAEQB.js +0 -105
- package/dist/chunk-TDNBAEQB.js.map +0 -1
- package/dist/surfaces-ChaD9nei.d.ts +0 -38
package/dist/react.js
CHANGED
|
@@ -1,10 +1,368 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import './chunk-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { logoLayer, teamColors } from './chunk-RPVVJY74.js';
|
|
3
|
+
import { trajectoryTube } from './chunk-AMXASQHT.js';
|
|
4
|
+
import { aspect, seasons, imageSource } from './chunk-UL5M6KDE.js';
|
|
5
|
+
import { checkAlpha, logoUrlSync, placeSync, placedName } from './chunk-7ULOCCFL.js';
|
|
6
|
+
import { loadLeague, resolveSync, getLeagueSync, loadGsis, headshotUrl, palette, HEADSHOT_ASPECT, checkLeague } from './chunk-ZAEQXFJM.js';
|
|
7
|
+
import './chunk-J6R2LEJ7.js';
|
|
8
|
+
import { OptionalDependencyError, warn, UnsupportedTargetError, InputError } from './chunk-E7G7VSLV.js';
|
|
9
|
+
import { lazy, useId, useMemo, createElement, useEffect, Suspense, useState, useRef, useSyncExternalStore, useLayoutEffect } from 'react';
|
|
10
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
11
|
|
|
12
|
+
var missing = (peer, e) => new OptionalDependencyError(
|
|
13
|
+
`SurfaceBackdrop needs the optional peer ${peer}, which could not be loaded: pnpm add ${peer}`,
|
|
14
|
+
{ cause: e }
|
|
15
|
+
);
|
|
16
|
+
var numeric = (d) => d !== void 0 && d.length === 2 && d.every((v) => typeof v === "number" && Number.isFinite(v)) && d[1] !== d[0];
|
|
17
|
+
function linear(scale, d0, d1, dir) {
|
|
18
|
+
if (scale === void 0) return true;
|
|
19
|
+
const [a, m, b] = [d0, (d0 + d1) / 2, d1].map((v) => Number(scale(v)));
|
|
20
|
+
if (![a, m, b].every((v) => Number.isFinite(v))) return true;
|
|
21
|
+
return dir * (b - a) > 0 && Math.abs(m - (a + b) / 2) < 0.5;
|
|
22
|
+
}
|
|
23
|
+
var Backdrop = lazy(async () => {
|
|
24
|
+
const [rc, surfaces, svg] = await Promise.all([
|
|
25
|
+
import('recharts').catch((e) => {
|
|
26
|
+
throw missing("recharts", e);
|
|
27
|
+
}),
|
|
28
|
+
import('./surfaces-MIG7HOFU.js').catch((e) => {
|
|
29
|
+
throw missing("@sportsdataverse/sporty", e);
|
|
30
|
+
}),
|
|
31
|
+
import('@sportsdataverse/sporty/svg').catch((e) => {
|
|
32
|
+
throw missing("@sportsdataverse/sporty", e);
|
|
33
|
+
})
|
|
34
|
+
]);
|
|
35
|
+
const noScale = () => void 0;
|
|
36
|
+
const useXScale = rc.useXAxisScale ?? noScale;
|
|
37
|
+
const useYScale = rc.useYAxisScale ?? noScale;
|
|
38
|
+
function Drawn({ league, xAxisId, yAxisId, ...o }) {
|
|
39
|
+
const area = rc.usePlotArea();
|
|
40
|
+
const xd = rc.useXAxisDomain(xAxisId);
|
|
41
|
+
const yd = rc.useYAxisDomain(yAxisId);
|
|
42
|
+
const sx = useXScale(xAxisId);
|
|
43
|
+
const sy = useYScale(yAxisId);
|
|
44
|
+
const clip = `sdv-surface-${useId().replace(/[^\w-]/g, "")}`;
|
|
45
|
+
const key = JSON.stringify(o, (_k, v) => typeof v === "bigint" ? `${v}n` : v);
|
|
46
|
+
const scene = useMemo(() => surfaces.surfaceScene(league, o), [league, key]);
|
|
47
|
+
if (area === void 0 || xd === void 0 || yd === void 0) return null;
|
|
48
|
+
if (!numeric(xd) || !numeric(yd)) {
|
|
49
|
+
warn(
|
|
50
|
+
"react:SurfaceBackdrop:domain",
|
|
51
|
+
`SurfaceBackdrop draws nothing: both axes must be type="number" with a numeric domain in the surface's units (got x ${JSON.stringify(xd)}, y ${JSON.stringify(yd)})`
|
|
52
|
+
);
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const [dx0, dx1] = xd;
|
|
56
|
+
const [dy0, dy1] = yd;
|
|
57
|
+
if (!linear(sx, dx0, dx1, 1) || !linear(sy, dy0, dy1, -1)) {
|
|
58
|
+
warn(
|
|
59
|
+
"react:SurfaceBackdrop:scale",
|
|
60
|
+
"SurfaceBackdrop draws nothing on a reversed or log axis: use linear, unreversed number axes"
|
|
61
|
+
);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const fx = (v) => area.x + (v - dx0) / (dx1 - dx0) * area.width;
|
|
65
|
+
const fy = (v) => area.y + (dy1 - v) / (dy1 - dy0) * area.height;
|
|
66
|
+
const [x0, y0, x1, y1] = scene.bbox;
|
|
67
|
+
const width = fx(x1) - fx(x0);
|
|
68
|
+
const height = fy(y0) - fy(y1);
|
|
69
|
+
if (!(width > 0 && height > 0)) {
|
|
70
|
+
warn(
|
|
71
|
+
"react:SurfaceBackdrop:empty",
|
|
72
|
+
`SurfaceBackdrop draws nothing: the surface spans ${width} x ${height} px`
|
|
73
|
+
);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const drawn = svg.toSVG(scene, { width, height }).replace("<svg ", `<svg x="${fx(x0)}" y="${fy(y1)}" preserveAspectRatio="none" `);
|
|
77
|
+
return /* @__PURE__ */ jsxs("g", { "data-sdv-surface": "", className: "sdv-surface", children: [
|
|
78
|
+
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: clip, children: /* @__PURE__ */ jsx("rect", { x: area.x, y: area.y, width: area.width, height: area.height }) }) }),
|
|
79
|
+
/* @__PURE__ */ jsx("g", { clipPath: `url(#${clip})`, dangerouslySetInnerHTML: { __html: drawn } })
|
|
80
|
+
] });
|
|
81
|
+
}
|
|
82
|
+
return { default: Drawn };
|
|
83
|
+
});
|
|
84
|
+
function SurfaceBackdrop(props) {
|
|
85
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(Backdrop, { ...props }) });
|
|
86
|
+
}
|
|
87
|
+
var LAYERS = ["grid", "axes", "labels", "lines", "points"];
|
|
88
|
+
var Chart = lazy(async () => {
|
|
89
|
+
const m = await import('@nivo/bump').catch((e) => {
|
|
90
|
+
throw new OptionalDependencyError(
|
|
91
|
+
"LogoBump needs the optional peer @nivo/bump, which could not be loaded: pnpm add @nivo/bump @nivo/core",
|
|
92
|
+
{ cause: e }
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
const Drawn = (p) => createElement(
|
|
96
|
+
p.width === void 0 || p.height === void 0 ? m.ResponsiveBump : m.Bump,
|
|
97
|
+
p
|
|
98
|
+
);
|
|
99
|
+
return { default: Drawn };
|
|
100
|
+
});
|
|
101
|
+
function LogoBump({
|
|
102
|
+
league,
|
|
103
|
+
season,
|
|
104
|
+
idSystem,
|
|
105
|
+
background,
|
|
106
|
+
logoHeight,
|
|
107
|
+
at,
|
|
108
|
+
variant,
|
|
109
|
+
markType,
|
|
110
|
+
layers,
|
|
111
|
+
...rest
|
|
112
|
+
}) {
|
|
113
|
+
const teams = rest.data.map((s) => s.id);
|
|
114
|
+
const key = JSON.stringify([
|
|
115
|
+
league,
|
|
116
|
+
season,
|
|
117
|
+
idSystem,
|
|
118
|
+
background,
|
|
119
|
+
logoHeight,
|
|
120
|
+
at,
|
|
121
|
+
variant,
|
|
122
|
+
markType,
|
|
123
|
+
teams
|
|
124
|
+
]);
|
|
125
|
+
const drawn = useMemo(() => {
|
|
126
|
+
const o = {
|
|
127
|
+
league,
|
|
128
|
+
...season === void 0 ? {} : { season },
|
|
129
|
+
...idSystem === void 0 ? {} : { idSystem }
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
colors: teamColors({ ...o, ...background === void 0 ? {} : { teams, background } }),
|
|
133
|
+
logos: logoLayer({
|
|
134
|
+
...o,
|
|
135
|
+
...logoHeight === void 0 ? {} : { height: logoHeight },
|
|
136
|
+
...at === void 0 ? {} : { at },
|
|
137
|
+
...variant === void 0 ? {} : { variant },
|
|
138
|
+
...markType === void 0 ? {} : { markType }
|
|
139
|
+
})
|
|
140
|
+
};
|
|
141
|
+
}, [key]);
|
|
142
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
|
|
143
|
+
Chart,
|
|
144
|
+
{
|
|
145
|
+
colors: drawn.colors,
|
|
146
|
+
...rest,
|
|
147
|
+
layers: layers === void 0 ? [...LAYERS, drawn.logos, "mesh"] : [...layers, drawn.logos]
|
|
148
|
+
}
|
|
149
|
+
) });
|
|
150
|
+
}
|
|
151
|
+
var isNum = (v) => typeof v === "number" && Number.isFinite(v);
|
|
152
|
+
function checkSize(size) {
|
|
153
|
+
if (!(isNum(size) && size > 0))
|
|
154
|
+
throw new InputError(`size is an image height in px > 0, got ${String(size)}`);
|
|
155
|
+
if (size < 1)
|
|
156
|
+
throw new InputError(
|
|
157
|
+
`size is a height in px, not a fraction of the plot (echarts' \`height\`): got ${size}, which draws a sub-pixel image`
|
|
158
|
+
);
|
|
159
|
+
return size;
|
|
160
|
+
}
|
|
161
|
+
function placed(x, y, raw, rows, o) {
|
|
162
|
+
const season = seasons(rows, o.season);
|
|
163
|
+
return placeSync([x], [y], [raw], {
|
|
164
|
+
league: o.league,
|
|
165
|
+
kind: o.markType ?? "logo",
|
|
166
|
+
...season === void 0 ? {} : { season },
|
|
167
|
+
...o.variant === void 0 ? {} : { variant: o.variant },
|
|
168
|
+
...o.idSystem === void 0 ? {} : { idSystem: o.idSystem }
|
|
169
|
+
})[0];
|
|
170
|
+
}
|
|
171
|
+
function image(p, o, raw, box, at, extra) {
|
|
172
|
+
const kind = o.markType ?? "logo";
|
|
173
|
+
return createElement("image", {
|
|
174
|
+
...extra,
|
|
175
|
+
href: imageSource(p, o.embed),
|
|
176
|
+
x: box.left,
|
|
177
|
+
y: box.top,
|
|
178
|
+
width: box.h * aspect(p),
|
|
179
|
+
height: box.h,
|
|
180
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
181
|
+
role: "img",
|
|
182
|
+
"aria-label": `${placedName(p, o.league, raw)} ${kind}`,
|
|
183
|
+
"data-sdv-id": p.id,
|
|
184
|
+
"data-sdv-kind": kind,
|
|
185
|
+
"data-sdv-x": String(at.x),
|
|
186
|
+
"data-sdv-y": String(at.y),
|
|
187
|
+
"data-sdv-frame": "1"
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
function noBox(props, name, how) {
|
|
191
|
+
for (const k of ["height", "width"]) if (k in props) throw new InputError(`${name} takes no ${k}: ${how}`);
|
|
192
|
+
}
|
|
193
|
+
function LogoPoint(props) {
|
|
194
|
+
noBox(
|
|
195
|
+
props,
|
|
196
|
+
"LogoPoint",
|
|
197
|
+
"each logo is as tall as Victory drew the point (twice the scatter's size, in px)"
|
|
198
|
+
);
|
|
199
|
+
const alpha = checkAlpha(props.alpha ?? 1);
|
|
200
|
+
const { x, y, size } = props;
|
|
201
|
+
if (!(isNum(x) && isNum(y) && isNum(size)))
|
|
202
|
+
throw new UnsupportedTargetError(
|
|
203
|
+
"LogoPoint is a VictoryScatter dataComponent: it needs the point's x, y and size, which the scatter hands it"
|
|
204
|
+
);
|
|
205
|
+
const row = props.datum ?? {};
|
|
206
|
+
const raw = row[props.team];
|
|
207
|
+
if (raw === void 0 || raw === null) {
|
|
208
|
+
warn(
|
|
209
|
+
`victory:LogoPoint:no-team:${props.team}`,
|
|
210
|
+
`LogoPoint: a datum has no ${props.team} field: nothing drawn`
|
|
211
|
+
);
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
if (!(size > 0)) {
|
|
215
|
+
warn(
|
|
216
|
+
`victory:LogoPoint:size:${size}`,
|
|
217
|
+
`LogoPoint: Victory drew a point of size ${size} (px): nothing drawn`
|
|
218
|
+
);
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
const p = placed(x, y, raw, [row], props);
|
|
222
|
+
if (p === void 0) return null;
|
|
223
|
+
const h = 2 * size;
|
|
224
|
+
const w = h * aspect(p);
|
|
225
|
+
return image(
|
|
226
|
+
p,
|
|
227
|
+
props,
|
|
228
|
+
raw,
|
|
229
|
+
{ left: x - w / 2, top: y - h / 2, h },
|
|
230
|
+
{ x, y },
|
|
231
|
+
{ ...props.events, ...alpha === 1 ? {} : { opacity: alpha } }
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
var Label = lazy(async () => {
|
|
235
|
+
const m = await import('victory').catch((e) => {
|
|
236
|
+
throw new OptionalDependencyError(
|
|
237
|
+
"LogoTick needs the optional peer victory to draw a label as text, and it could not be loaded: pnpm add victory",
|
|
238
|
+
{ cause: e }
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
return { default: m.VictoryLabel };
|
|
242
|
+
});
|
|
243
|
+
function LogoTick(props) {
|
|
244
|
+
noBox(props, "LogoTick", "size is the logo's height in px (Victory hands a tick label no plot height)");
|
|
245
|
+
const h = checkSize(props.size ?? 24);
|
|
246
|
+
const { league, season, variant, idSystem, markType, embed, size, ...label } = props;
|
|
247
|
+
const x = isNum(props.x) ? props.x : 0;
|
|
248
|
+
const y = isNum(props.y) ? props.y : 0;
|
|
249
|
+
const raw = typeof props.text === "string" || typeof props.text === "number" ? props.text : void 0;
|
|
250
|
+
const p = raw === void 0 ? void 0 : placed(x, y, raw, [], props);
|
|
251
|
+
if (p === void 0)
|
|
252
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(Label, { ...label }) });
|
|
253
|
+
const w = h * aspect(p);
|
|
254
|
+
const anchor = props.textAnchor ?? "start";
|
|
255
|
+
const vertical = props.verticalAnchor ?? "middle";
|
|
256
|
+
const left = anchor === "end" ? x - w : anchor === "middle" ? x - w / 2 : x;
|
|
257
|
+
const top = vertical === "end" ? y - h : vertical === "middle" ? y - h / 2 : y;
|
|
258
|
+
return image(p, props, raw, { left, top, h }, { x, y }, {});
|
|
259
|
+
}
|
|
260
|
+
async function peers(who) {
|
|
261
|
+
try {
|
|
262
|
+
return await Promise.all([import('three'), import('@react-three/fiber')]);
|
|
263
|
+
} catch (e) {
|
|
264
|
+
throw new OptionalDependencyError(
|
|
265
|
+
`${who} needs the optional peers three and @react-three/fiber, which could not be loaded: pnpm add three @react-three/fiber`,
|
|
266
|
+
{ cause: e }
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function meshOf(THREE, fiber) {
|
|
271
|
+
return function Drawn({ buffers, material, renderOrder }) {
|
|
272
|
+
const invalidate = fiber.useThree((s) => s.invalidate);
|
|
273
|
+
const geometry = useMemo(() => {
|
|
274
|
+
const g = new THREE.BufferGeometry();
|
|
275
|
+
g.setAttribute("position", new THREE.BufferAttribute(buffers.positions, 3));
|
|
276
|
+
if (buffers.colors !== void 0) g.setAttribute("color", new THREE.BufferAttribute(buffers.colors, 4));
|
|
277
|
+
if (buffers.normals !== void 0)
|
|
278
|
+
g.setAttribute("normal", new THREE.BufferAttribute(buffers.normals, 3));
|
|
279
|
+
g.setIndex(new THREE.BufferAttribute(buffers.indices, 1));
|
|
280
|
+
g.computeBoundingSphere();
|
|
281
|
+
return g;
|
|
282
|
+
}, [buffers]);
|
|
283
|
+
useEffect(() => {
|
|
284
|
+
invalidate();
|
|
285
|
+
return () => geometry.dispose();
|
|
286
|
+
}, [geometry, invalidate]);
|
|
287
|
+
return createElement("mesh", { geometry, renderOrder }, createElement("meshBasicMaterial", material));
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function loaded(league) {
|
|
291
|
+
checkLeague(league);
|
|
292
|
+
try {
|
|
293
|
+
getLeagueSync(league);
|
|
294
|
+
return true;
|
|
295
|
+
} catch {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
var SurfaceBody = lazy(async () => {
|
|
300
|
+
const [[THREE, fiber], { surfaceMesh }] = await Promise.all([
|
|
301
|
+
peers("Surface3D"),
|
|
302
|
+
import('./surface-TR7YFJW3.js').catch((e) => {
|
|
303
|
+
throw new OptionalDependencyError(
|
|
304
|
+
"Surface3D needs the optional peer @sportsdataverse/sporty, which could not be loaded: pnpm add @sportsdataverse/sporty",
|
|
305
|
+
{ cause: e }
|
|
306
|
+
);
|
|
307
|
+
})
|
|
308
|
+
]);
|
|
309
|
+
const Drawn = meshOf(THREE, fiber);
|
|
310
|
+
const material = {
|
|
311
|
+
vertexColors: true,
|
|
312
|
+
transparent: true,
|
|
313
|
+
depthWrite: false,
|
|
314
|
+
toneMapped: false,
|
|
315
|
+
side: THREE.DoubleSide
|
|
316
|
+
};
|
|
317
|
+
function Body({ sport, league, options, renderOrder = -1 }) {
|
|
318
|
+
const key = JSON.stringify([sport, league, options]);
|
|
319
|
+
const buffers = useMemo(() => surfaceMesh(sport, league, options), [key]);
|
|
320
|
+
return createElement(Drawn, { buffers, material, renderOrder });
|
|
321
|
+
}
|
|
322
|
+
return { default: Body };
|
|
323
|
+
});
|
|
324
|
+
function Surface3D(props) {
|
|
325
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(SurfaceBody, { ...props }) });
|
|
326
|
+
}
|
|
327
|
+
var TubeBody = lazy(
|
|
328
|
+
async () => {
|
|
329
|
+
const [THREE, fiber] = await peers("Trajectory");
|
|
330
|
+
const Drawn = meshOf(THREE, fiber);
|
|
331
|
+
function Body({ tube, renderOrder }) {
|
|
332
|
+
const material = useMemo(() => ({ color: tube.color, toneMapped: false }), [tube.color]);
|
|
333
|
+
return createElement(Drawn, { buffers: tube, material, renderOrder });
|
|
334
|
+
}
|
|
335
|
+
return { default: Body };
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
function Trajectory({ points, renderOrder = 0, ...o }) {
|
|
339
|
+
const league = o.color === void 0 ? o.league : void 0;
|
|
340
|
+
const ready = league === void 0 || loaded(league);
|
|
341
|
+
const [, loadedNow] = useState(0);
|
|
342
|
+
useEffect(() => {
|
|
343
|
+
if (ready || league === void 0) return;
|
|
344
|
+
let live = true;
|
|
345
|
+
loadLeague(league).then(
|
|
346
|
+
() => live && loadedNow((n) => n + 1),
|
|
347
|
+
() => {
|
|
348
|
+
}
|
|
349
|
+
// a league that cannot load leaves the tube undrawn, as it is now
|
|
350
|
+
);
|
|
351
|
+
return () => {
|
|
352
|
+
live = false;
|
|
353
|
+
};
|
|
354
|
+
}, [league, ready]);
|
|
355
|
+
const key = JSON.stringify([points, o, ready]);
|
|
356
|
+
const tube = useMemo(() => ready ? trajectoryTube(points, o) : null, [key]);
|
|
357
|
+
if (tube === null) {
|
|
358
|
+
warn(
|
|
359
|
+
`three:Trajectory:unloaded:${league}`,
|
|
360
|
+
`<Trajectory team> draws nothing until league ${league} is loaded: await loadLeague("${league}") first (on a server, before rendering)`
|
|
361
|
+
);
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(TubeBody, { tube, renderOrder }) });
|
|
365
|
+
}
|
|
8
366
|
function TeamLogo({
|
|
9
367
|
team,
|
|
10
368
|
league,
|
|
@@ -159,6 +517,6 @@ function useSelection(store) {
|
|
|
159
517
|
return useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
160
518
|
}
|
|
161
519
|
|
|
162
|
-
export { Headshot, TeamLogo, Wordmark, useResolve, useSelection, useTeamColors };
|
|
520
|
+
export { Headshot, LogoBump, LogoPoint, LogoTick, Surface3D, SurfaceBackdrop, TeamLogo, Trajectory, Wordmark, useResolve, useSelection, useTeamColors };
|
|
163
521
|
//# sourceMappingURL=react.js.map
|
|
164
522
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/index.tsx"],"names":[],"mappings":"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","file":"react.js","sourcesContent":["import {\n type ImgHTMLAttributes,\n type ReactElement,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { type ColorOptions, palette } from \"../colors.js\";\nimport { type EspnHeadshotLeague, HEADSHOT_ASPECT, headshotUrl, loadGsis } from \"../headshots.js\";\nimport { getLeagueSync, loadLeague } from \"../index-data.js\";\nimport { type LogoUrlOptions, logoUrlSync } from \"../marks.js\";\nimport { type ResolveOptions, type Value, resolveSync } from \"../resolve.js\";\nimport type { SelectionState, SelectionStore } from \"../selection.js\";\nimport type { HeadshotIdSystem, League, MarkType, TeamId, Variant } from \"../types.js\";\n\ntype ImgProps = Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"alt\" | \"height\" | \"width\">;\n\nexport interface TeamLogoProps extends ImgProps {\n team: Value;\n league: League;\n season?: LogoUrlOptions[\"season\"];\n variant?: Variant;\n markType?: MarkType;\n /** Rendered `height` in px; width is left unset so the browser keeps the aspect. */\n size?: number;\n /** Defaults to the team's name. */\n alt?: string;\n}\n\n/**\n * Team logo `<img>`. Loads the league index on first use; renders nothing until resolved and for an unknown team.\n *\n * @example\n * ```tsx\n * import { TeamLogo } from \"@sportsdataverse/sdvplot/react\";\n *\n * <TeamLogo team=\"KC\" league=\"nfl\" size={64} />;\n * ```\n */\nexport function TeamLogo({\n team,\n league,\n season,\n variant,\n markType,\n size,\n alt,\n ...imgProps\n}: TeamLogoProps): ReactElement | null {\n const [mark, setMark] = useState<{ src: string; name: string } | undefined>();\n useEffect(() => {\n let live = true;\n // One async body: any throw (bad league, bad variant, lookup error) becomes a rejection the .catch swallows.\n (async () => {\n await loadLeague(league);\n if (!live) return;\n const o: LogoUrlOptions = {};\n if (season !== undefined) o.season = season;\n if (variant !== undefined) o.variant = variant;\n if (markType !== undefined) o.markType = markType;\n const src = logoUrlSync(team, league, o);\n const id = resolveSync(team, league, { season });\n const name = getLeagueSync(league).teams.find((t) => t.team_id === id)?.name ?? \"\";\n setMark(src === undefined ? undefined : { src, name });\n })().catch(() => {\n if (live) setMark(undefined);\n });\n return () => {\n live = false;\n };\n }, [team, league, season, variant, markType]);\n if (mark === undefined) return null;\n // biome-ignore lint/a11y/useAltText: alt is always set (prop or team name); imgProps cannot carry it\n return <img src={mark.src} alt={alt ?? mark.name} height={size} {...imgProps} />;\n}\n\n/** `TeamLogo` with `markType=\"wordmark\"`. */\nexport function Wordmark(props: Omit<TeamLogoProps, \"markType\">): ReactElement | null {\n return <TeamLogo {...props} markType=\"wordmark\" />;\n}\n\nexport interface HeadshotProps extends ImgProps {\n playerId: Value;\n league: EspnHeadshotLeague;\n idSystem?: HeadshotIdSystem;\n /** Height in px (default 60); width follows the 600:436 headshot aspect. */\n height?: number;\n /** Default `name`, then \"Player headshot\". `\"\"` marks it decorative (the initials box is then `aria-hidden`). */\n alt?: string;\n /**\n * `\"initials\"`: when there is no headshot URL or the image fails to load, show up to three initials of `name` in a\n * box of the headshot's size (blazing-the-nets `main` `components/Headshot.tsx:15-29`). Default `\"none\"`: a failed\n * load leaves the `<img>`, and an id with no URL renders nothing.\n */\n fallback?: \"none\" | \"initials\";\n /** The player's name, for the initials and the default alt text. */\n name?: string;\n}\n\n/**\n * The first character of every space-separated word, up to three, as blazing-the-nets `main` does\n * (`Headshot.tsx:16-20`): suffixes and particles are words (\"Brian Thomas Jr.\" is \"BTJ\"), \"De'Von\" is one word.\n * It differs from `main` only on an astral first character, which it keeps whole where `w[0]` leaves half of it.\n */\nconst initialsOf = (name: string): string =>\n name\n .split(\" \")\n .map((w) => Array.from(w)[0] ?? \"\")\n .join(\"\")\n .slice(0, 3);\n\n// useLayoutEffect warns during React 18 server rendering; on the server no effect runs anyway.\nconst useClientLayoutEffect = typeof document === \"undefined\" ? useEffect : useLayoutEffect;\n\n/**\n * Player headshot `<img>`: sync for ESPN ids; gsis ids render once the gsis map has loaded. Renders nothing for an\n * unknown/malformed id, or a league/idSystem `headshotUrl` rejects, unless `fallback=\"initials\"` and a `name` are\n * given, which show the player's initials instead.\n *\n * @example\n * ```tsx\n * import { Headshot } from \"@sportsdataverse/sdvplot/react\";\n *\n * <Headshot playerId=\"3918298\" league=\"nfl\" height={80} alt=\"Josh Allen\" />;\n * ```\n */\nexport function Headshot({\n playerId,\n league,\n idSystem,\n height = 60,\n alt,\n fallback = \"none\",\n name,\n ...imgProps\n}: HeadshotProps): ReactElement | null {\n const [, setGsisReady] = useState(false); // re-render once loadGsis resolves\n const [failed, setFailed] = useState<string | undefined>(); // the src that failed to load\n const img = useRef<HTMLImageElement>(null);\n useEffect(() => {\n if (idSystem !== \"gsis\") return;\n let live = true;\n loadGsis().then(\n () => {\n if (live) setGsisReady(true);\n },\n () => {},\n );\n return () => {\n live = false;\n };\n }, [idSystem]);\n let src: string | undefined;\n try {\n src = headshotUrl(playerId, league, idSystem === undefined ? {} : { idSystem });\n } catch {\n src = undefined;\n }\n const label = alt ?? (name || undefined) ?? \"Player headshot\";\n const width = Math.round(height * HEADSHOT_ASPECT);\n // React replays no error that fired before hydration (or before mount): read the settled image instead. A\n // loading image is not complete yet, and a loaded one has a natural width.\n useClientLayoutEffect(() => {\n if (img.current?.complete && img.current.naturalWidth === 0) setFailed(src);\n }, [src]);\n if (src === undefined || (fallback === \"initials\" && src === failed)) {\n if (fallback !== \"initials\" || name === undefined) return null;\n return (\n <span\n {...(label === \"\" ? { \"aria-hidden\": true } : { role: \"img\", \"aria-label\": label })}\n className={imgProps.className}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width,\n height,\n background: \"var(--sdv-line, #e2e2e2)\",\n color: \"var(--sdv-muted, #525252)\",\n ...imgProps.style,\n }}\n >\n {initialsOf(name)}\n </span>\n );\n }\n const shown = src;\n return (\n // biome-ignore lint/a11y/useAltText: alt always defaults to a string; imgProps cannot carry it\n <img\n ref={img}\n src={shown}\n alt={label}\n height={height}\n width={width}\n {...imgProps}\n onError={(e) => {\n setFailed(shown);\n imgProps.onError?.(e);\n }}\n />\n );\n}\n\n/** `{team: \"#hex\"}` for a league once loaded (`undefined` before); reloads when `league`/`which` change. */\nexport function useTeamColors(\n league: League,\n { which }: { which?: ColorOptions[\"which\"] } = {},\n): Record<string, string> | undefined {\n const [colors, setColors] = useState<Record<string, string> | undefined>();\n useEffect(() => {\n let live = true;\n setColors(undefined);\n palette(league, undefined, which === undefined ? {} : { which })\n .then((c) => {\n if (live) setColors(c);\n })\n .catch(() => {\n if (live) setColors(undefined);\n });\n return () => {\n live = false;\n };\n }, [league, which]);\n return colors;\n}\n\n/** Sync resolver `(value, opts?) => TeamId | undefined` once the league is loaded (`undefined` before); reloads when `league` changes. */\nexport function useResolve(\n league: League,\n): ((value: Value, opts?: ResolveOptions) => TeamId | undefined) | undefined {\n const [ready, setReady] = useState<League | undefined>();\n useEffect(() => {\n let live = true;\n setReady(undefined);\n loadLeague(league)\n .then(() => {\n if (live) setReady(league);\n })\n .catch(() => {\n if (live) setReady(undefined);\n });\n return () => {\n live = false;\n };\n }, [league]);\n return ready === undefined ? undefined : (value, opts) => resolveSync(value, ready, opts);\n}\n\n/**\n * The state of a `createSelection` store (J31), re-rendering on every change and never on a no-op patch. On the\n * server, and in the first client render, it reads the store's current state, so server and client markup agree.\n * Redrawing from it is the component's choice: filter rows with `state.predicate`, emphasise `state.selected`.\n *\n * @example\n * ```tsx\n * import { createSelection } from \"@sportsdataverse/sdvplot\";\n * import { useSelection } from \"@sportsdataverse/sdvplot/react\";\n * import type { ReactElement } from \"react\";\n *\n * const store = createSelection();\n * store.set({ selected: [\"KC\", \"BUF\"] });\n * function Picked(): ReactElement {\n * const { selected } = useSelection(store); // re-renders on every change of the store\n * return (\n * <table>\n * <tbody>\n * {[...selected].map((id) => (\n * <tr key={id}>\n * <td>{id}</td>\n * </tr>\n * ))}\n * </tbody>\n * </table>\n * );\n * }\n * <Picked />;\n * ```\n */\nexport function useSelection<Row>(store: SelectionStore<Row>): SelectionState<Row> {\n // The store's methods are closures (no `this`), so they pass unbound; getState is referentially stable between\n // changes, which is all useSyncExternalStore needs.\n return useSyncExternalStore(store.subscribe, store.getState, store.getState);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/recharts.tsx","../src/react/nivo.tsx","../src/react/victory.tsx","../src/react/three.tsx","../src/react/index.tsx"],"names":["lazy","useMemo","jsx","Suspense","createElement","useState","useEffect"],"mappings":"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","file":"react.js","sourcesContent":["import { type ComponentType, type ReactElement, Suspense, lazy, useId, useMemo } from \"react\";\nimport { OptionalDependencyError, warn } from \"../errors.js\";\nimport type { Value } from \"../resolve.js\";\nimport type { SurfaceSceneOptions } from \"../surfaces.js\";\nimport type { League, SeasonInput } from \"../types.js\";\n\n/**\n * `<SurfaceBackdrop>` props: the league whose surface to draw, how to paint it (the options of sdvplot's other\n * `surface` functions), and which axes place it. The sporty-specific options are typed loosely, so `sdvplot/react`'s\n * types never name `@sportsdataverse/sporty` (an optional peer); sporty checks them when the surface is built.\n */\nexport interface SurfaceBackdropProps {\n /** The league whose court, field or rink to draw, e.g. \"nba\". */\n league: League;\n /** The team whose colours paint the surface. */\n team?: Value;\n /** The season the team's colours are taken from. */\n season?: SeasonInput;\n /** Overrides on top of the team painting, keyed by sporty colour key (e.g. `{ painted_area: \"#0e2240\" }`). */\n colorUpdates?: Readonly<Record<string, string>>;\n /** Degrees to rotate the surface by. */\n rotation?: number;\n /** A sporty display range for the league's sport, e.g. \"defense\"; one the sport does not know throws. */\n displayRange?: string;\n xlim?: readonly [number, number];\n ylim?: readonly [number, number];\n units?: \"ft\" | \"m\" | \"yd\" | \"in\" | \"cm\" | \"mm\";\n /** Sporty parameter overrides for the league's surface. */\n updates?: Readonly<Record<string, unknown>>;\n arcResolution?: number;\n xTrans?: number;\n yTrans?: number;\n /** The `xAxisId` of the numeric x axis the surface's units are on. Default 0. */\n xAxisId?: string | number;\n /** The `yAxisId` of the numeric y axis the surface's units are on. Default 0. */\n yAxisId?: string | number;\n}\n\nconst missing = (peer: string, e: unknown): OptionalDependencyError =>\n new OptionalDependencyError(\n `SurfaceBackdrop needs the optional peer ${peer}, which could not be loaded: pnpm add ${peer}`,\n { cause: e },\n );\ntype Domain = readonly unknown[] | undefined;\nconst numeric = (d: Domain): d is readonly [number, number] =>\n d !== undefined &&\n d.length === 2 &&\n d.every((v) => typeof v === \"number\" && Number.isFinite(v)) &&\n d[1] !== d[0];\n\n/** A scale (when recharts has the hooks) that grows with the value in direction `dir` (+1 left to right, -1 bottom\n * to top in pixels) and is linear: its midpoint lands half way. */\nfunction linear(scale: ((v: number) => unknown) | undefined, d0: number, d1: number, dir: 1 | -1): boolean {\n if (scale === undefined) return true;\n const [a, m, b] = [d0, (d0 + d1) / 2, d1].map((v) => Number(scale(v)));\n if (![a, m, b].every((v) => Number.isFinite(v))) return true; // not laid out yet: the domain check covers the rest\n return (\n dir * ((b as number) - (a as number)) > 0 &&\n Math.abs((m as number) - ((a as number) + (b as number)) / 2) < 0.5\n );\n}\n\n// recharts and sporty load on first render, never with sdvplot/react: a page that draws no backdrop needs neither.\nconst Backdrop = lazy(async (): Promise<{ default: ComponentType<SurfaceBackdropProps> }> => {\n const [rc, surfaces, svg] = await Promise.all([\n import(\"recharts\").catch((e: unknown) => {\n throw missing(\"recharts\", e);\n }),\n import(\"../surfaces.js\").catch((e: unknown) => {\n throw missing(\"@sportsdataverse/sporty\", e);\n }),\n import(\"@sportsdataverse/sporty/svg\").catch((e: unknown) => {\n throw missing(\"@sportsdataverse/sporty\", e);\n }),\n ]);\n // recharts 3.8 added the scale hooks; before it a reversed or log axis cannot be told apart (documented)\n const noScale = (): undefined => undefined;\n const useXScale: (id?: string | number) => ((v: number) => unknown) | undefined =\n rc.useXAxisScale ?? noScale;\n const useYScale: (id?: string | number) => ((v: number) => unknown) | undefined =\n rc.useYAxisScale ?? noScale;\n function Drawn({ league, xAxisId, yAxisId, ...o }: SurfaceBackdropProps): ReactElement | null {\n const area = rc.usePlotArea();\n const xd: Domain = rc.useXAxisDomain(xAxisId);\n const yd: Domain = rc.useYAxisDomain(yAxisId);\n const sx = useXScale(xAxisId);\n const sy = useYScale(yAxisId);\n const clip = `sdv-surface-${useId().replace(/[^\\w-]/g, \"\")}`;\n // a bigint team id is a `Value`: JSON.stringify throws on bigint, so key it as text\n const key = JSON.stringify(o, (_k, v: unknown) => (typeof v === \"bigint\" ? `${v}n` : v));\n // biome-ignore lint/correctness/useExhaustiveDependencies: `key` is `o` by value (a fresh object every render)\n const scene = useMemo(() => surfaces.surfaceScene(league, o as SurfaceSceneOptions), [league, key]);\n // undefined: the chart has not laid out yet (the first render), which is not worth a warning\n if (area === undefined || xd === undefined || yd === undefined) return null;\n if (!numeric(xd) || !numeric(yd)) {\n warn(\n \"react:SurfaceBackdrop:domain\",\n `SurfaceBackdrop draws nothing: both axes must be type=\"number\" with a numeric domain in the surface's units (got x ${JSON.stringify(xd)}, y ${JSON.stringify(yd)})`,\n );\n return null;\n }\n // ponytail: a linear map from the axes' domains (recharts 3.2 hooks): a reversed or log axis is refused, where\n // recharts 3.8's scale hooks can tell (on 3.2 to 3.7 it would draw mirrored or stretched)\n const [dx0, dx1] = xd;\n const [dy0, dy1] = yd;\n if (!linear(sx, dx0, dx1, 1) || !linear(sy, dy0, dy1, -1)) {\n warn(\n \"react:SurfaceBackdrop:scale\",\n \"SurfaceBackdrop draws nothing on a reversed or log axis: use linear, unreversed number axes\",\n );\n return null;\n }\n const fx = (v: number): number => area.x + ((v - dx0) / (dx1 - dx0)) * area.width;\n const fy = (v: number): number => area.y + ((dy1 - v) / (dy1 - dy0)) * area.height;\n const [x0, y0, x1, y1] = scene.bbox;\n const width = fx(x1) - fx(x0);\n const height = fy(y0) - fy(y1);\n if (!(width > 0 && height > 0)) {\n warn(\n \"react:SurfaceBackdrop:empty\",\n `SurfaceBackdrop draws nothing: the surface spans ${width} x ${height} px`,\n );\n return null;\n }\n // toSVG maps the scene's bbox onto its own viewport; placed and stretched over the bbox's pixel rectangle, the\n // surface's units land on the axes' (strokes stay 1 px: non-scaling)\n const drawn = svg\n .toSVG(scene, { width, height })\n .replace(\"<svg \", `<svg x=\"${fx(x0)}\" y=\"${fy(y1)}\" preserveAspectRatio=\"none\" `);\n return (\n <g data-sdv-surface=\"\" className=\"sdv-surface\">\n <defs>\n <clipPath id={clip}>\n <rect x={area.x} y={area.y} width={area.width} height={area.height} />\n </clipPath>\n </defs>\n {/* biome-ignore lint/security/noDangerouslySetInnerHtml: sporty's own SVG, its text and colours escaped by toSVG */}\n <g clipPath={`url(#${clip})`} dangerouslySetInnerHTML={{ __html: drawn }} />\n </g>\n );\n }\n return { default: Drawn };\n});\n\n/**\n * A team-painted court, field or rink under a Recharts chart's series: place it as a child of the chart (before the\n * series), as Recharts 3 renders any element there (`<Customized>` is deprecated). The surface is drawn in the\n * numeric axes' units: set both axes' `domain` to the surface's bbox (sporty's `surface(...).bbox`) to fill the plot\n * area, or to any range in those units to show part of it. recharts (3.8 or later) and `@sportsdataverse/sporty`\n * load when it first renders, never with `sdvplot/react`; either missing throws `OptionalDependencyError` then. A\n * server render draws nothing (it loads on the client).\n *\n * @example\n * ```tsx\n * import { SurfaceBackdrop } from \"@sportsdataverse/sdvplot/react\";\n * import { surface } from \"@sportsdataverse/sporty\";\n * import { Scatter, ScatterChart, XAxis, YAxis } from \"recharts\";\n *\n * const [x0, y0, x1, y1] = surface(\"basketball\", \"nba\", { displayRange: \"defense\" }).bbox;\n * <ScatterChart width={500} height={470}>\n * <XAxis type=\"number\" dataKey=\"x\" domain={[x0, x1]} hide />\n * <YAxis type=\"number\" dataKey=\"y\" domain={[y0, y1]} hide />\n * <SurfaceBackdrop league=\"nba\" team=\"DEN\" displayRange=\"defense\" />\n * <Scatter data={[{ x: 0, y: 5.25 }]} />\n * </ScatterChart>;\n * ```\n */\nexport function SurfaceBackdrop(props: SurfaceBackdropProps): ReactElement {\n return (\n <Suspense fallback={null}>\n <Backdrop {...props} />\n </Suspense>\n );\n}\n","import { type ComponentType, type ReactElement, Suspense, createElement, lazy, useMemo } from \"react\";\nimport { OptionalDependencyError } from \"../errors.js\";\nimport { type NivoLayerOptions, logoLayer, teamColors } from \"../nivo.js\";\nimport type { IdSystem, League, MarkType, SeasonInput, Variant } from \"../types.js\";\n\n/**\n * `<LogoBump>` props: the series, the league their ids belong to, and how to draw the logos; every other prop goes to\n * nivo's `Bump` as is (typed loosely, so `sdvplot/react`'s types never name `@nivo/bump`, an optional peer).\n */\nexport interface LogoBumpProps {\n /** nivo Bump series, `{ id, data: [{ x, y }] }`: each `id` is a team (abbreviation, name or id). */\n data: readonly {\n readonly id: string;\n readonly data: readonly { x: number | string; y: number | null }[];\n }[];\n /** The league the series' teams belong to, e.g. \"nfl\". */\n league: League;\n /** The season the teams are resolved for. */\n season?: SeasonInput;\n /** How the series' ids are read. Default \"auto\". */\n idSystem?: IdSystem;\n /** The chart's background: the line colours keep 3:1 contrast against it and aim to stay distinct (`teamColors`). */\n background?: string;\n /** Logo height as a fraction of the plot height, in (0, 1]. Default 0.08. */\n logoHeight?: number;\n /** Which points get a logo: \"last\" (default), \"first\" or \"all\". */\n at?: NivoLayerOptions[\"at\"];\n /** Logo variant, e.g. \"dark\". Default \"default\". */\n variant?: Variant;\n /** \"logo\" (default) or \"wordmark\". */\n markType?: MarkType;\n /** Width and height in px. Both given: a fixed-size `Bump`; otherwise a `ResponsiveBump` that fills its parent. */\n width?: number;\n /** Chart height in px (see `width`). */\n height?: number;\n /**\n * nivo's layers. Default nivo's own: grid, axes, labels, lines, points, then the logos, then mesh. Given, the logos\n * are appended after them all, after any \"mesh\" too, which is harmless: the logo layer has `pointer-events: none`.\n */\n layers?: readonly unknown[];\n /** Any other nivo `Bump` prop (margin, axes, pointSize, animate, theme, ...). */\n [prop: string]: unknown;\n}\n\nconst LAYERS = [\"grid\", \"axes\", \"labels\", \"lines\", \"points\"]; // then the logos, then nivo's \"mesh\" (mouse) on top\n\n// @nivo/bump loads on first render, never with sdvplot/react: a page that draws no LogoBump needs no nivo.\nconst Chart = lazy(async (): Promise<{ default: ComponentType<Record<string, unknown>> }> => {\n const m = await import(\"@nivo/bump\").catch((e: unknown) => {\n throw new OptionalDependencyError(\n \"LogoBump needs the optional peer @nivo/bump, which could not be loaded: pnpm add @nivo/bump @nivo/core\",\n { cause: e },\n );\n });\n const Drawn = (p: Record<string, unknown>): ReactElement =>\n createElement(\n (p.width === undefined || p.height === undefined ? m.ResponsiveBump : m.Bump) as ComponentType<\n Record<string, unknown>\n >,\n p,\n );\n return { default: Drawn };\n});\n\n/**\n * A nivo bump chart of teams: each line in its team's colour (`teamColors`), a logo at the end of each line\n * (`logoLayer`). `@nivo/bump` (0.99 or later) loads when it first renders, never with `sdvplot/react`; missing, it\n * throws `OptionalDependencyError` then. A server render draws nothing (it loads on the client). For anything this\n * does not cover, use `teamColors` and `logoLayer` from `sdvplot/nivo` on nivo's own `Bump`. A `colors` prop replaces\n * the team colours (it is passed to nivo after them).\n */\nexport function LogoBump({\n league,\n season,\n idSystem,\n background,\n logoHeight,\n at,\n variant,\n markType,\n layers,\n ...rest\n}: LogoBumpProps): ReactElement {\n const teams = rest.data.map((s) => s.id);\n const key = JSON.stringify([\n league,\n season,\n idSystem,\n background,\n logoHeight,\n at,\n variant,\n markType,\n teams,\n ]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: `key` is the options by value\n const drawn = useMemo(() => {\n const o = {\n league,\n ...(season === undefined ? {} : { season }),\n ...(idSystem === undefined ? {} : { idSystem }),\n };\n return {\n colors: teamColors({ ...o, ...(background === undefined ? {} : { teams, background }) }),\n logos: logoLayer({\n ...o,\n ...(logoHeight === undefined ? {} : { height: logoHeight }),\n ...(at === undefined ? {} : { at }),\n ...(variant === undefined ? {} : { variant }),\n ...(markType === undefined ? {} : { markType }),\n }),\n };\n }, [key]);\n return (\n <Suspense fallback={null}>\n <Chart\n colors={drawn.colors}\n {...rest}\n layers={layers === undefined ? [...LAYERS, drawn.logos, \"mesh\"] : [...layers, drawn.logos]}\n />\n </Suspense>\n );\n}\n","import { type ComponentType, type ReactElement, Suspense, createElement, lazy } from \"react\";\nimport { type Row, aspect, checkAlpha, imageSource, place, seasons } from \"../_web.js\";\nimport { InputError, OptionalDependencyError, UnsupportedTargetError, warn } from \"../errors.js\";\nimport { type Placement, placedName } from \"../placement.js\";\nimport type { Value } from \"../resolve.js\";\nimport type { IdSystem, League, MarkType, SeasonInput, Variant } from \"../types.js\";\n\ninterface Shared {\n /** The league the teams belong to, e.g. \"nfl\". */\n league: League;\n /** Logo variant, e.g. \"dark\". Default \"default\". */\n variant?: Variant;\n /** How the team values are read. Default \"auto\". */\n idSystem?: IdSystem;\n /** \"logo\" (default) or \"wordmark\". */\n markType?: MarkType;\n /** url → data URI map from `embedSources`, to inline the images. */\n embed?: ReadonlyMap<string, string>;\n}\n/**\n * `<LogoPoint>` props: yours (the league, the datum field holding the team, ...), plus the point Victory hands its\n * `dataComponent` (`x`, `y`, `size`, `datum`, `events`), which you leave out.\n */\nexport interface LogoPointProps extends Shared {\n /** The field of each datum (each data row) holding the team: abbreviation, name or id (see `idSystem`). */\n team: string;\n /** A season (number or string) for every point, or the name of the datum field holding each one's season. */\n season?: SeasonInput;\n /** Opacity in [0, 1]. Default 1. */\n alpha?: number;\n /** Set by Victory: the point's centre in px. */\n x?: number;\n /** Set by Victory: the point's centre in px. */\n y?: number;\n /** Set by Victory: the point's radius in px (the scatter's `size`). The logo is twice it tall. */\n size?: number;\n /** Set by Victory: the data row the point was drawn from. */\n datum?: object;\n /** Set by Victory: the point's event handlers (tooltips, voronoi, your `events`). */\n events?: object;\n}\n/**\n * `<LogoTick>` props: yours (the league, the logo size, ...), plus the tick label Victory hands its\n * `tickLabelComponent` (`x`, `y`, `text`, the anchors, and VictoryLabel's other props), which you leave out.\n */\nexport interface LogoTickProps extends Shared {\n /** The season the axis' teams are resolved for. */\n season?: SeasonInput;\n /** The logo's height in px, 1 or more (Victory hands a tick label no plot height). Default 24. */\n size?: number;\n /** Set by Victory: the label's anchor in px. */\n x?: number;\n /** Set by Victory: the label's anchor in px. */\n y?: number;\n /** Set by Victory: the tick's label, the team (abbreviation, name or id; see `idSystem`). */\n text?: unknown;\n /** Set by Victory: which side of the anchor the label would run. VictoryLabel's default \"start\". */\n textAnchor?: string;\n /** Set by Victory: which side of the anchor the label would hang. VictoryLabel's default \"middle\". */\n verticalAnchor?: string;\n}\n\nconst isNum = (v: unknown): v is number => typeof v === \"number\" && Number.isFinite(v);\n\nfunction checkSize(size: unknown): number {\n if (!(isNum(size) && size > 0))\n throw new InputError(`size is an image height in px > 0, got ${String(size)}`);\n if (size < 1)\n throw new InputError(\n `size is a height in px, not a fraction of the plot (echarts' \\`height\\`): got ${size}, which draws a sub-pixel image`,\n );\n return size;\n}\n\nfunction placed(\n x: number,\n y: number,\n raw: Value,\n rows: readonly Row[],\n o: Shared & { season?: SeasonInput },\n) {\n const season = seasons(rows, o.season);\n return place([x], [y], [raw], {\n league: o.league,\n kind: o.markType ?? \"logo\",\n ...(season === undefined ? {} : { season }),\n ...(o.variant === undefined ? {} : { variant: o.variant }),\n ...(o.idSystem === undefined ? {} : { idSystem: o.idSystem }),\n })[0];\n}\n\n/** The `<image>` of a placed mark, `h` px tall with its top-left at (left, top), stamped with what `sdvplot/testing`'s\n * `drawnMarks` reads back. ponytail: the frame is 1 px, so drawnMarks' `height` reads in px (no plot height here). */\nfunction image(\n p: Placement,\n o: Shared,\n raw: Value,\n box: { left: number; top: number; h: number },\n at: { x: number; y: number },\n extra: object,\n): ReactElement {\n const kind = o.markType ?? \"logo\";\n return createElement(\"image\", {\n ...extra,\n href: imageSource(p, o.embed),\n x: box.left,\n y: box.top,\n width: box.h * aspect(p),\n height: box.h,\n preserveAspectRatio: \"xMidYMid meet\",\n role: \"img\",\n \"aria-label\": `${placedName(p, o.league, raw)} ${kind}`,\n \"data-sdv-id\": p.id,\n \"data-sdv-kind\": kind,\n \"data-sdv-x\": String(at.x),\n \"data-sdv-y\": String(at.y),\n \"data-sdv-frame\": \"1\",\n });\n}\n\n/** A stray `height` or `width` (the spec adapters' fraction of the plot, or a box) is refused: these size in px. */\nfunction noBox(props: object, name: string, how: string): void {\n for (const k of [\"height\", \"width\"]) if (k in props) throw new InputError(`${name} takes no ${k}: ${how}`);\n}\n\n/**\n * Team logos as a Victory scatter's points: `<VictoryScatter dataComponent={<LogoPoint league team />}>`. Each point\n * draws the logo of its datum's `team` field, centred on the point and as tall as the point it replaces (twice the\n * scatter's `size`, in px: set `size` on the `VictoryScatter`). A team with no logo draws nothing and warns once, as\n * `sdvplot/echarts` does. Victory's event handlers (tooltips, voronoi) stay on the image. Synchronous: call it after\n * `loadLeague(league)`. Needs nothing from victory itself, so it also renders on the server.\n *\n * @example\n * ```tsx\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { LogoPoint } from \"@sportsdataverse/sdvplot/react\";\n * import { VictoryChart, VictoryScatter } from \"victory\";\n *\n * await loadLeague(\"nfl\");\n * const rows = [\n * { team: \"KC\", pf: 385, pa: 326 },\n * { team: \"LAC\", pf: 402, pa: 301 },\n * { team: \"DEN\", pf: 425, pa: 311 },\n * ];\n * <VictoryChart domainPadding={30}>\n * <VictoryScatter data={rows} x=\"pf\" y=\"pa\" size={14} dataComponent={<LogoPoint league=\"nfl\" team=\"team\" />} />\n * </VictoryChart>;\n * ```\n */\nexport function LogoPoint(props: LogoPointProps): ReactElement | null {\n noBox(\n props,\n \"LogoPoint\",\n \"each logo is as tall as Victory drew the point (twice the scatter's size, in px)\",\n );\n const alpha = checkAlpha(props.alpha ?? 1);\n const { x, y, size } = props;\n if (!(isNum(x) && isNum(y) && isNum(size)))\n throw new UnsupportedTargetError(\n \"LogoPoint is a VictoryScatter dataComponent: it needs the point's x, y and size, which the scatter hands it\",\n );\n const row = (props.datum ?? {}) as Row;\n const raw = row[props.team] as Value;\n if (raw === undefined || raw === null) {\n warn(\n `victory:LogoPoint:no-team:${props.team}`,\n `LogoPoint: a datum has no ${props.team} field: nothing drawn`,\n );\n return null;\n }\n if (!(size > 0)) {\n warn(\n `victory:LogoPoint:size:${size}`,\n `LogoPoint: Victory drew a point of size ${size} (px): nothing drawn`,\n );\n return null;\n }\n const p = placed(x, y, raw, [row], props);\n if (p === undefined) return null; // no mark: nothing drawn, one warning (placeSync), as sdvplot/echarts\n const h = 2 * size;\n const w = h * aspect(p);\n return image(\n p,\n props,\n raw,\n { left: x - w / 2, top: y - h / 2, h },\n { x, y },\n { ...props.events, ...(alpha === 1 ? {} : { opacity: alpha }) },\n );\n}\n\n// victory loads only to draw a tick label as text (a team with no logo), never with sdvplot/react.\nconst Label = lazy(async (): Promise<{ default: ComponentType<Record<string, unknown>> }> => {\n const m = await import(\"victory\").catch((e: unknown) => {\n throw new OptionalDependencyError(\n \"LogoTick needs the optional peer victory to draw a label as text, and it could not be loaded: pnpm add victory\",\n { cause: e },\n );\n });\n return { default: m.VictoryLabel as ComponentType<Record<string, unknown>> };\n});\n\n/**\n * Team logos as an axis' tick labels: `<VictoryAxis tickLabelComponent={<LogoTick league />} />` on an axis whose\n * labels are teams. The logo sits where the label would, on the side of Victory's anchor the label would run (under\n * a bottom axis, left of a left one), `size` px tall. A label that resolves to no logo keeps its text, drawn by\n * Victory's own `VictoryLabel` (loaded from victory when it first draws one; it then also warns once), as\n * `sdvplot/echarts`' `withAxisLogos` does. Logos do not\n * rotate with a tick's `angle`. Synchronous: call it after `loadLeague(league)`.\n *\n * @example\n * ```tsx\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { LogoTick } from \"@sportsdataverse/sdvplot/react\";\n * import { VictoryAxis, VictoryBar, VictoryChart } from \"victory\";\n *\n * await loadLeague(\"nfl\");\n * const rows = [\n * { team: \"KC\", wins: 15 },\n * { team: \"BUF\", wins: 13 },\n * { team: \"LAC\", wins: 11 },\n * ];\n * <VictoryChart domainPadding={40} padding={{ top: 20, bottom: 60, left: 50, right: 20 }}>\n * <VictoryAxis tickLabelComponent={<LogoTick league=\"nfl\" size={32} />} />\n * <VictoryAxis dependentAxis />\n * <VictoryBar data={rows} x=\"team\" y=\"wins\" />\n * </VictoryChart>;\n * ```\n */\nexport function LogoTick(props: LogoTickProps): ReactElement {\n noBox(props, \"LogoTick\", \"size is the logo's height in px (Victory hands a tick label no plot height)\");\n const h = checkSize(props.size ?? 24);\n const { league, season, variant, idSystem, markType, embed, size, ...label } = props;\n const x = isNum(props.x) ? props.x : 0;\n const y = isNum(props.y) ? props.y : 0;\n const raw = typeof props.text === \"string\" || typeof props.text === \"number\" ? props.text : undefined;\n const p = raw === undefined ? undefined : placed(x, y, raw, [], props);\n if (p === undefined)\n return (\n <Suspense fallback={null}>\n <Label {...label} />\n </Suspense>\n );\n const w = h * aspect(p);\n const anchor = props.textAnchor ?? \"start\";\n const vertical = props.verticalAnchor ?? \"middle\";\n const left = anchor === \"end\" ? x - w : anchor === \"middle\" ? x - w / 2 : x;\n const top = vertical === \"end\" ? y - h : vertical === \"middle\" ? y - h / 2 : y;\n return image(p, props, raw as Value, { left, top, h }, { x, y }, {});\n}\n","import {\n type ComponentType,\n type ReactElement,\n Suspense,\n createElement,\n lazy,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { OptionalDependencyError, warn } from \"../errors.js\";\nimport { checkLeague, getLeagueSync, loadLeague } from \"../index-data.js\";\nimport { type TrajectoryTubeOptions, type TubeMesh, trajectoryTube } from \"../three/tube.js\";\nimport type { IdSystem, League, SeasonInput, Which } from \"../types.js\";\n\ntype Three = typeof import(\"three\");\ntype Fiber = typeof import(\"@react-three/fiber\");\n/** What a drawn mesh needs: its buffers (positions, then colours or normals), indices and material. */\ninterface Buffers {\n positions: Float32Array;\n indices: Uint32Array;\n colors?: Float32Array;\n normals?: Float32Array;\n}\ntype MeshProps = { buffers: Buffers; material: Record<string, unknown>; renderOrder: number };\n\n/**\n * `three` and `@react-three/fiber`, loaded on first render, never with `sdvplot/react`: a page that draws no 3D needs\n * neither. Missing, the component throws `OptionalDependencyError` when it renders.\n */\nasync function peers(who: string): Promise<[Three, Fiber]> {\n try {\n return await Promise.all([import(\"three\"), import(\"@react-three/fiber\")]);\n } catch (e) {\n throw new OptionalDependencyError(\n `${who} needs the optional peers three and @react-three/fiber, which could not be loaded: pnpm add three @react-three/fiber`,\n { cause: e },\n );\n }\n}\n\n/**\n * A mesh of `buffers` in react-three-fiber: the geometry is built once per buffers object and freed when it changes\n * or unmounts. `useThree` makes using it outside a `<Canvas>` an error that says so, and asks a canvas drawn on demand\n * (`frameloop=\"demand\"`) for a frame.\n */\nfunction meshOf(THREE: Three, fiber: Fiber): ComponentType<MeshProps> {\n return function Drawn({ buffers, material, renderOrder }): ReactElement {\n const invalidate = fiber.useThree((s) => s.invalidate);\n // biome-ignore lint/correctness/useExhaustiveDependencies: THREE is the module namespace, the same object always\n const geometry = useMemo(() => {\n const g = new THREE.BufferGeometry();\n g.setAttribute(\"position\", new THREE.BufferAttribute(buffers.positions, 3));\n if (buffers.colors !== undefined) g.setAttribute(\"color\", new THREE.BufferAttribute(buffers.colors, 4));\n if (buffers.normals !== undefined)\n g.setAttribute(\"normal\", new THREE.BufferAttribute(buffers.normals, 3));\n g.setIndex(new THREE.BufferAttribute(buffers.indices, 1));\n g.computeBoundingSphere();\n return g;\n }, [buffers]);\n useEffect(() => {\n invalidate();\n return () => geometry.dispose();\n }, [geometry, invalidate]);\n // react-three-fiber frees the material it made; the geometry, made here, is freed above\n return createElement(\"mesh\", { geometry, renderOrder }, createElement(\"meshBasicMaterial\", material));\n };\n}\n\n/** Whether `league` (a known league, else InputError) is loaded for the *Sync lookups. */\nfunction loaded(league: League): boolean {\n checkLeague(league);\n try {\n getLeagueSync(league);\n return true;\n } catch {\n return false;\n }\n}\n\n/** `<Surface3D>` props: sporty's sport and league, and sporty's `surface()` options. */\nexport interface Surface3DProps {\n /** sporty's sport, e.g. \"baseball\". */\n sport: string;\n /** sporty's league key for it, e.g. \"mlb\". */\n league: string;\n /** sporty's `surface()` options (`colorUpdates`, `units`, `rotation`, ...). */\n options?: Record<string, unknown>;\n /** The mesh's `renderOrder`. Default -1: drawn before the scene's other objects, as a ground should be. */\n renderOrder?: number;\n}\n\n// the peers and sporty (through ../three/surface.js) load on first render, never with sdvplot/react\nconst SurfaceBody = lazy(async (): Promise<{ default: ComponentType<Surface3DProps> }> => {\n const [[THREE, fiber], { surfaceMesh }] = await Promise.all([\n peers(\"Surface3D\"),\n import(\"../three/surface.js\").catch((e: unknown) => {\n throw new OptionalDependencyError(\n \"Surface3D needs the optional peer @sportsdataverse/sporty, which could not be loaded: pnpm add @sportsdataverse/sporty\",\n { cause: e },\n );\n }),\n ]);\n const Drawn = meshOf(THREE, fiber);\n const material = {\n vertexColors: true,\n transparent: true,\n depthWrite: false,\n toneMapped: false,\n side: THREE.DoubleSide,\n };\n function Body({ sport, league, options, renderOrder = -1 }: Surface3DProps): ReactElement {\n const key = JSON.stringify([sport, league, options]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: `key` is the props by value\n const buffers = useMemo(() => surfaceMesh(sport as never, league as never, options as never), [key]);\n return createElement<MeshProps>(Drawn, { buffers, material, renderOrder });\n }\n return { default: Body };\n});\n\n/**\n * sporty's playing surface in a react-three-fiber scene: `surfaceMesh` as one mesh in the z = 0 plane, in the\n * surface's own units (feet for a baseball field or a rink, metres for a pitch), z up, so set the camera's\n * `up={[0, 0, 1]}`. Drawn unlit in sporty's colours, before the scene's other objects and without depth writes, so its\n * features paint over each other in order with no z-fighting. Put it inside your `<Canvas>`. `three` and\n * `@react-three/fiber` (0.186.1 and 9.8.1 or later) and `@sportsdataverse/sporty` load when it first renders, never\n * with `sdvplot/react`; a missing peer throws `OptionalDependencyError` then. The failed load is kept until the page\n * reloads, so installing the peer needs a reload. A server render draws nothing.\n *\n * See it drawn in the Three.js guide (`sdvplot/three/statcast-pitches` in the gallery).\n */\nexport function Surface3D(props: Surface3DProps): ReactElement {\n return (\n <Suspense fallback={null}>\n <SurfaceBody {...props} />\n </Suspense>\n );\n}\n\n/** `<Trajectory>` props: the path, the tube's radius in world units, and its colour or team. */\nexport interface TrajectoryProps {\n /** The path, `[x, y, z]` points in world units (`statcastPitchPath` gives a pitch's). */\n points: readonly (readonly [x: number, y: number, z: number])[];\n /** The tube's radius in the points' world units, not px (a baseball's is 0.121 ft). */\n radius: number;\n /** Vertices round each ring, 3 or more. Default 12. */\n radialSegments?: number;\n /** The tube's colour, `#rrggbb`. Give this or `team` and `league`. */\n color?: string;\n /** The team whose colour the tube takes (abbreviation, name or id), with `league`. */\n team?: unknown;\n league?: League;\n season?: SeasonInput;\n idSystem?: IdSystem;\n /** \"primary\" (default) or \"secondary\". */\n which?: Which;\n /** What the tube is seen against: the colour keeps 3:1 contrast against it (`teamColorPalette`). */\n background?: string;\n /** The colour of a team that does not resolve. Default \"#808080\". */\n fallback?: string;\n /** The mesh's `renderOrder`. Default 0. */\n renderOrder?: number;\n}\n\nconst TubeBody = lazy(\n async (): Promise<{ default: ComponentType<{ tube: TubeMesh; renderOrder: number }> }> => {\n const [THREE, fiber] = await peers(\"Trajectory\");\n const Drawn = meshOf(THREE, fiber);\n function Body({ tube, renderOrder }: { tube: TubeMesh; renderOrder: number }): ReactElement {\n const material = useMemo(() => ({ color: tube.color, toneMapped: false }), [tube.color]);\n return createElement<MeshProps>(Drawn, { buffers: tube, material, renderOrder });\n }\n return { default: Body };\n },\n);\n\n/**\n * A team-coloured tube along a 3D path (a pitch, a ball flight) in a react-three-fiber scene: `trajectoryTube` as one\n * mesh, `radius` round in the points' world units, drawn unlit and not tone-mapped so the team's colour shows as it\n * is. Put it inside your `<Canvas>`, over a `<Surface3D>` in the same units. `three` and `@react-three/fiber` load\n * when it first renders, never with `sdvplot/react`; a missing peer throws `OptionalDependencyError` then (kept until\n * the page reloads, so installing the peer needs a reload), and a bad radius or colour throws `InputError`. With\n * `team`, the team's league must be loaded for its colour: until it is, the tube draws nothing (one warning), and in\n * the browser it loads the league and then draws. A server render draws nothing.\n *\n * See it drawn in the Three.js guide (`sdvplot/three/statcast-pitches` in the gallery).\n */\nexport function Trajectory({ points, renderOrder = 0, ...o }: TrajectoryProps): ReactElement | null {\n // a team's colour needs its league loaded: until it is, draw nothing (a server render included), and load it here\n const league = o.color === undefined ? o.league : undefined;\n const ready = league === undefined || loaded(league);\n const [, loadedNow] = useState(0);\n useEffect(() => {\n if (ready || league === undefined) return;\n let live = true;\n loadLeague(league).then(\n () => live && loadedNow((n) => n + 1),\n () => {}, // a league that cannot load leaves the tube undrawn, as it is now\n );\n return () => {\n live = false;\n };\n }, [league, ready]);\n const key = JSON.stringify([points, o, ready]);\n // biome-ignore lint/correctness/useExhaustiveDependencies: `key` is the props by value\n const tube = useMemo(() => (ready ? trajectoryTube(points, o as TrajectoryTubeOptions) : null), [key]);\n if (tube === null) {\n warn(\n `three:Trajectory:unloaded:${league}`,\n `<Trajectory team> draws nothing until league ${league} is loaded: await loadLeague(\"${league}\") first (on a server, before rendering)`,\n );\n return null;\n }\n return (\n <Suspense fallback={null}>\n <TubeBody tube={tube} renderOrder={renderOrder} />\n </Suspense>\n );\n}\n","import {\n type ImgHTMLAttributes,\n type ReactElement,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { type ColorOptions, palette } from \"../colors.js\";\nimport { type EspnHeadshotLeague, HEADSHOT_ASPECT, headshotUrl, loadGsis } from \"../headshots.js\";\nimport { getLeagueSync, loadLeague } from \"../index-data.js\";\nimport { type LogoUrlOptions, logoUrlSync } from \"../marks.js\";\nimport { type ResolveOptions, type Value, resolveSync } from \"../resolve.js\";\nimport type { SelectionState, SelectionStore } from \"../selection.js\";\nimport type { HeadshotIdSystem, League, MarkType, TeamId, Variant } from \"../types.js\";\nexport { SurfaceBackdrop, type SurfaceBackdropProps } from \"./recharts.js\";\nexport { LogoBump, type LogoBumpProps } from \"./nivo.js\";\nexport { LogoPoint, type LogoPointProps, LogoTick, type LogoTickProps } from \"./victory.js\";\n\nexport { Surface3D, type Surface3DProps, Trajectory, type TrajectoryProps } from \"./three.js\";\n\ntype ImgProps = Omit<ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"alt\" | \"height\" | \"width\">;\n\nexport interface TeamLogoProps extends ImgProps {\n team: Value;\n league: League;\n season?: LogoUrlOptions[\"season\"];\n variant?: Variant;\n markType?: MarkType;\n /** Rendered `height` in px; width is left unset so the browser keeps the aspect. */\n size?: number;\n /** Defaults to the team's name. */\n alt?: string;\n}\n\n/**\n * Team logo `<img>`. Loads the league index on first use; renders nothing until resolved and for an unknown team.\n *\n * @example\n * ```tsx\n * import { TeamLogo } from \"@sportsdataverse/sdvplot/react\";\n *\n * <TeamLogo team=\"KC\" league=\"nfl\" size={64} />;\n * ```\n */\nexport function TeamLogo({\n team,\n league,\n season,\n variant,\n markType,\n size,\n alt,\n ...imgProps\n}: TeamLogoProps): ReactElement | null {\n const [mark, setMark] = useState<{ src: string; name: string } | undefined>();\n useEffect(() => {\n let live = true;\n // One async body: any throw (bad league, bad variant, lookup error) becomes a rejection the .catch swallows.\n (async () => {\n await loadLeague(league);\n if (!live) return;\n const o: LogoUrlOptions = {};\n if (season !== undefined) o.season = season;\n if (variant !== undefined) o.variant = variant;\n if (markType !== undefined) o.markType = markType;\n const src = logoUrlSync(team, league, o);\n const id = resolveSync(team, league, { season });\n const name = getLeagueSync(league).teams.find((t) => t.team_id === id)?.name ?? \"\";\n setMark(src === undefined ? undefined : { src, name });\n })().catch(() => {\n if (live) setMark(undefined);\n });\n return () => {\n live = false;\n };\n }, [team, league, season, variant, markType]);\n if (mark === undefined) return null;\n // biome-ignore lint/a11y/useAltText: alt is always set (prop or team name); imgProps cannot carry it\n return <img src={mark.src} alt={alt ?? mark.name} height={size} {...imgProps} />;\n}\n\n/** `TeamLogo` with `markType=\"wordmark\"`. */\nexport function Wordmark(props: Omit<TeamLogoProps, \"markType\">): ReactElement | null {\n return <TeamLogo {...props} markType=\"wordmark\" />;\n}\n\nexport interface HeadshotProps extends ImgProps {\n playerId: Value;\n league: EspnHeadshotLeague;\n idSystem?: HeadshotIdSystem;\n /** Height in px (default 60); width follows the 600:436 headshot aspect. */\n height?: number;\n /** Default `name`, then \"Player headshot\". `\"\"` marks it decorative (the initials box is then `aria-hidden`). */\n alt?: string;\n /**\n * `\"initials\"`: when there is no headshot URL or the image fails to load, show up to three initials of `name` in a\n * box of the headshot's size (blazing-the-nets `main` `components/Headshot.tsx:15-29`). Default `\"none\"`: a failed\n * load leaves the `<img>`, and an id with no URL renders nothing.\n */\n fallback?: \"none\" | \"initials\";\n /** The player's name, for the initials and the default alt text. */\n name?: string;\n}\n\n/**\n * The first character of every space-separated word, up to three, as blazing-the-nets `main` does\n * (`Headshot.tsx:16-20`): suffixes and particles are words (\"Brian Thomas Jr.\" is \"BTJ\"), \"De'Von\" is one word.\n * It differs from `main` only on an astral first character, which it keeps whole where `w[0]` leaves half of it.\n */\nconst initialsOf = (name: string): string =>\n name\n .split(\" \")\n .map((w) => Array.from(w)[0] ?? \"\")\n .join(\"\")\n .slice(0, 3);\n\n// useLayoutEffect warns during React 18 server rendering; on the server no effect runs anyway.\nconst useClientLayoutEffect = typeof document === \"undefined\" ? useEffect : useLayoutEffect;\n\n/**\n * Player headshot `<img>`: sync for ESPN ids; gsis ids render once the gsis map has loaded. Renders nothing for an\n * unknown/malformed id, or a league/idSystem `headshotUrl` rejects, unless `fallback=\"initials\"` and a `name` are\n * given, which show the player's initials instead.\n *\n * @example\n * ```tsx\n * import { Headshot } from \"@sportsdataverse/sdvplot/react\";\n *\n * <Headshot playerId=\"3918298\" league=\"nfl\" height={80} alt=\"Josh Allen\" />;\n * ```\n */\nexport function Headshot({\n playerId,\n league,\n idSystem,\n height = 60,\n alt,\n fallback = \"none\",\n name,\n ...imgProps\n}: HeadshotProps): ReactElement | null {\n const [, setGsisReady] = useState(false); // re-render once loadGsis resolves\n const [failed, setFailed] = useState<string | undefined>(); // the src that failed to load\n const img = useRef<HTMLImageElement>(null);\n useEffect(() => {\n if (idSystem !== \"gsis\") return;\n let live = true;\n loadGsis().then(\n () => {\n if (live) setGsisReady(true);\n },\n () => {},\n );\n return () => {\n live = false;\n };\n }, [idSystem]);\n let src: string | undefined;\n try {\n src = headshotUrl(playerId, league, idSystem === undefined ? {} : { idSystem });\n } catch {\n src = undefined;\n }\n const label = alt ?? (name || undefined) ?? \"Player headshot\";\n const width = Math.round(height * HEADSHOT_ASPECT);\n // React replays no error that fired before hydration (or before mount): read the settled image instead. A\n // loading image is not complete yet, and a loaded one has a natural width.\n useClientLayoutEffect(() => {\n if (img.current?.complete && img.current.naturalWidth === 0) setFailed(src);\n }, [src]);\n if (src === undefined || (fallback === \"initials\" && src === failed)) {\n if (fallback !== \"initials\" || name === undefined) return null;\n return (\n <span\n {...(label === \"\" ? { \"aria-hidden\": true } : { role: \"img\", \"aria-label\": label })}\n className={imgProps.className}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width,\n height,\n background: \"var(--sdv-line, #e2e2e2)\",\n color: \"var(--sdv-muted, #525252)\",\n ...imgProps.style,\n }}\n >\n {initialsOf(name)}\n </span>\n );\n }\n const shown = src;\n return (\n // biome-ignore lint/a11y/useAltText: alt always defaults to a string; imgProps cannot carry it\n <img\n ref={img}\n src={shown}\n alt={label}\n height={height}\n width={width}\n {...imgProps}\n onError={(e) => {\n setFailed(shown);\n imgProps.onError?.(e);\n }}\n />\n );\n}\n\n/** `{team: \"#hex\"}` for a league once loaded (`undefined` before); reloads when `league`/`which` change. */\nexport function useTeamColors(\n league: League,\n { which }: { which?: ColorOptions[\"which\"] } = {},\n): Record<string, string> | undefined {\n const [colors, setColors] = useState<Record<string, string> | undefined>();\n useEffect(() => {\n let live = true;\n setColors(undefined);\n palette(league, undefined, which === undefined ? {} : { which })\n .then((c) => {\n if (live) setColors(c);\n })\n .catch(() => {\n if (live) setColors(undefined);\n });\n return () => {\n live = false;\n };\n }, [league, which]);\n return colors;\n}\n\n/** Sync resolver `(value, opts?) => TeamId | undefined` once the league is loaded (`undefined` before); reloads when `league` changes. */\nexport function useResolve(\n league: League,\n): ((value: Value, opts?: ResolveOptions) => TeamId | undefined) | undefined {\n const [ready, setReady] = useState<League | undefined>();\n useEffect(() => {\n let live = true;\n setReady(undefined);\n loadLeague(league)\n .then(() => {\n if (live) setReady(league);\n })\n .catch(() => {\n if (live) setReady(undefined);\n });\n return () => {\n live = false;\n };\n }, [league]);\n return ready === undefined ? undefined : (value, opts) => resolveSync(value, ready, opts);\n}\n\n/**\n * The state of a `createSelection` store (J31), re-rendering on every change and never on a no-op patch. On the\n * server, and in the first client render, it reads the store's current state, so server and client markup agree.\n * Redrawing from it is the component's choice: filter rows with `state.predicate`, emphasise `state.selected`.\n *\n * @example\n * ```tsx\n * import { createSelection } from \"@sportsdataverse/sdvplot\";\n * import { useSelection } from \"@sportsdataverse/sdvplot/react\";\n * import type { ReactElement } from \"react\";\n *\n * const store = createSelection();\n * store.set({ selected: [\"KC\", \"BUF\"] });\n * function Picked(): ReactElement {\n * const { selected } = useSelection(store); // re-renders on every change of the store\n * return (\n * <table>\n * <tbody>\n * {[...selected].map((id) => (\n * <tr key={id}>\n * <td>{id}</td>\n * </tr>\n * ))}\n * </tbody>\n * </table>\n * );\n * }\n * <Picked />;\n * ```\n */\nexport function useSelection<Row>(store: SelectionStore<Row>): SelectionState<Row> {\n // The store's methods are closures (no `this`), so they pass unbound; getState is referentially stable between\n // changes, which is all useSyncExternalStore needs.\n return useSyncExternalStore(store.subscribe, store.getState, store.getState);\n}\n"]}
|