@pitchkit/react 0.1.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.
@@ -0,0 +1,178 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties, ReactNode } from 'react';
3
+ import { PitchTypeId, Orientation, CropWindow, ViewportPadding, PitchAppearance, ScatterLayer, AnnotateLayer, ArrowsLayer, CometLayer, HeatmapLayer, PolygonLayer, ConvexHullLayer, VoronoiLayer, GoalAngleLayer, FlowLayer, FlowBin, PitchDimensions, Viewport, PixelTransform } from '@pitchkit/core';
4
+
5
+ interface PitchProps {
6
+ type: PitchTypeId;
7
+ /** @default "horizontal" */
8
+ orientation?: Orientation;
9
+ /** Fixed pixel size — the opt-out from the responsive default. Provide both, or neither. */
10
+ width?: number;
11
+ height?: number;
12
+ crop?: CropWindow;
13
+ padding?: ViewportPadding;
14
+ appearance?: PitchAppearance;
15
+ className?: string;
16
+ style?: CSSProperties;
17
+ children?: ReactNode;
18
+ }
19
+ /**
20
+ * The root pitch component: owns the coordinate system, is responsive by
21
+ * default (fills its container via ResizeObserver — explicit width/height
22
+ * is the opt-out), and provides the pixel transform to layer-component
23
+ * children via context.
24
+ */
25
+ declare function Pitch({ type, orientation, width: explicitWidth, height: explicitHeight, crop, padding, appearance, className, style, children, }: PitchProps): react.JSX.Element;
26
+
27
+ /**
28
+ * `<Pitch orientation="vertical">`, named to match mplsoccer's
29
+ * `VerticalPitch` for familiarity. Core has no separate vertical pitch
30
+ * concept (orientation is a `Viewport` field, not a distinct coordinate
31
+ * system) — this is purely a naming/ergonomics convenience at the
32
+ * component-API layer.
33
+ */
34
+ declare function VerticalPitch(props: Omit<PitchProps, "orientation">): react.JSX.Element;
35
+
36
+ interface ScatterProps<T> extends Omit<ScatterLayer<T>, "type"> {
37
+ tooltip?: (d: T, i: number) => ReactNode;
38
+ }
39
+ /** One `<circle>` per datum — the JSX equivalent of core's `paintScatterLayer`. */
40
+ declare function Scatter<T>({ data, x, y, r, fill, fillOpacity, stroke, strokeWidth, className, tooltip, }: ScatterProps<T>): react.JSX.Element;
41
+
42
+ interface AnnotateProps<T> extends Omit<AnnotateLayer<T>, "type"> {
43
+ tooltip?: (d: T, i: number) => ReactNode;
44
+ }
45
+ /** One `<text>` per datum — the JSX equivalent of core's `paintAnnotateLayer`. */
46
+ declare function Annotate<T>({ data, x, y, label, offsetX, offsetY, className, tooltip, }: AnnotateProps<T>): react.JSX.Element;
47
+
48
+ interface ArrowsProps<T> extends Omit<ArrowsLayer<T>, "type"> {
49
+ tooltip?: (d: T, i: number) => ReactNode;
50
+ }
51
+ /**
52
+ * One shaft `<line>` + arrowhead `<polygon>` per datum — the JSX
53
+ * equivalent of core's `paintArrowsLayer`, sharing its `computeArrowHeadCorners`
54
+ * geometry so the head angle can't drift between the two renderers.
55
+ */
56
+ declare function Arrows<T>({ data, x, y, x2, y2, stroke, strokeWidth, strokeOpacity, headSize, className, tooltip, }: ArrowsProps<T>): react.JSX.Element;
57
+
58
+ interface CometProps<T> extends Omit<CometLayer<T>, "type"> {
59
+ tooltip?: (d: T, i: number) => ReactNode;
60
+ }
61
+ /**
62
+ * One filled quadrilateral per datum — the JSX equivalent of core's
63
+ * `paintCometLayer`, sharing its `computeCometQuad` taper geometry. Gradient
64
+ * ids come from `useId()` (SSR-safe stable id) rather than a module-level
65
+ * counter like core's DOM renderer, since two independent server renders
66
+ * must not produce colliding ids.
67
+ */
68
+ declare function Comet<T>({ data, x, y, x2, y2, color, startWidth, endWidth, gradient, className, tooltip, }: CometProps<T>): react.JSX.Element;
69
+
70
+ interface HeatmapProps<T> extends Omit<HeatmapLayer<T>, "type"> {
71
+ /**
72
+ * Every bin gets painted (from `colorMin` to `colorMax`, including
73
+ * zero-value bins) rather than leaving low bins transparent, so a
74
+ * heatmap fully covers the pitch underneath by default. Set an opacity
75
+ * here (or a blend mode) to let the pitch show through.
76
+ */
77
+ className?: string;
78
+ style?: CSSProperties;
79
+ }
80
+ /**
81
+ * Client-only `<canvas>` heatmap, painted imperatively via core's
82
+ * `renderHeatmapLayersToCanvas` in an effect. Unlike the SVG layer
83
+ * components, this can't be re-emitted as JSX — Canvas has no declarative
84
+ * JSX equivalent, and dense raster data is exactly the case core's hybrid
85
+ * SVG+Canvas architecture (PRD §8.1) reserves Canvas for. The `<canvas>`
86
+ * itself renders server-side (empty), but its pixels only appear after the
87
+ * client effect runs — a documented client-only boundary.
88
+ *
89
+ * Wrapped in `<foreignObject>` since a raw `<canvas>` can't be a direct
90
+ * child of `<svg>` — this keeps the heatmap inside the same SVG tree as
91
+ * the pitch and every other layer, rather than needing a second,
92
+ * separately-positioned DOM element the way the vanilla-JS core example
93
+ * demo has to (core has no JSX to lean on there).
94
+ *
95
+ * No effect dependency array (runs after every render) rather than
96
+ * enumerating every spread `props` field plus `dimensions`/`viewport` —
97
+ * repainting a canvas is cheap and idempotent, so this avoids a fragile,
98
+ * easily-stale dependency list.
99
+ */
100
+ declare function Heatmap<T>({ className, style, ...layerProps }: HeatmapProps<T>): react.JSX.Element;
101
+
102
+ interface PolygonProps<T> extends Omit<PolygonLayer<T>, "type"> {
103
+ tooltip?: (d: T, i: number) => ReactNode;
104
+ }
105
+ /** One `<polygon>` per datum, from an arbitrary list of vertices — mplsoccer's `polygon`. */
106
+ declare function Polygon<T>({ data, points, fill, fillOpacity, stroke, strokeWidth, className, tooltip, }: PolygonProps<T>): react.JSX.Element;
107
+
108
+ interface ConvexHullProps<T> extends Omit<ConvexHullLayer<T>, "type"> {
109
+ /** Static — there's exactly one resulting shape for the whole dataset, not one per datum. */
110
+ tooltip?: ReactNode;
111
+ }
112
+ /**
113
+ * One filled `<polygon>` for the convex hull of every datum's `(x, y)` —
114
+ * e.g. a player's touch map. Unlike per-datum marks, `fill`/`stroke`/etc.
115
+ * take plain values rather than `Accessor<T, V>`, since there's only ever
116
+ * one shape produced from the whole `data` array.
117
+ */
118
+ declare function ConvexHull<T>({ data, x, y, fill, fillOpacity, stroke, strokeWidth, className, tooltip, }: ConvexHullProps<T>): react.JSX.Element;
119
+
120
+ interface VoronoiProps<T> extends Omit<VoronoiLayer<T>, "type"> {
121
+ tooltip?: (d: T, i: number) => ReactNode;
122
+ }
123
+ /**
124
+ * One filled `<polygon>` cell per datum — Voronoi tessellation over every
125
+ * datum's `(x, y)`, clipped to the pitch outline. Cells are computed in
126
+ * provider coordinates (against `computePitchGeometry(dimensions).outline`)
127
+ * and pixel-transformed afterward, the same order `Heatmap`'s binning uses,
128
+ * so the tessellation itself is independent of orientation/crop.
129
+ */
130
+ declare function Voronoi<T>({ data, x, y, fill, fillOpacity, stroke, strokeWidth, className, tooltip, }: VoronoiProps<T>): react.JSX.Element;
131
+
132
+ interface GoalAngleProps<T> extends Omit<GoalAngleLayer<T>, "type"> {
133
+ tooltip?: (d: T, i: number) => ReactNode;
134
+ }
135
+ /**
136
+ * One triangular `<polygon>` wedge per datum, from the point to both
137
+ * goalposts — the angle subtended at that point by the goal mouth
138
+ * (mplsoccer's `goal_angle`). Goalpost coordinates come from
139
+ * `computePitchGeometry(dimensions).goals`, already computed for the pitch
140
+ * markings themselves; picking which of the two goals uses `selectGoal`.
141
+ */
142
+ declare function GoalAngle<T>({ data, x, y, goal, fill, fillOpacity, stroke, strokeWidth, className, tooltip, }: GoalAngleProps<T>): react.JSX.Element;
143
+
144
+ interface FlowProps<T> extends Omit<FlowLayer<T>, "type"> {
145
+ /** Per-*bin* (not per-datum) — the rendered arrows are aggregates, one per occupied grid cell. */
146
+ tooltip?: (bin: FlowBin, i: number) => ReactNode;
147
+ }
148
+ /**
149
+ * Bins pass/movement data by start location (`computeFlowBins`) and draws
150
+ * one arrow per occupied bin, from the bin center toward the mean end
151
+ * point, colored and sized by that bin's volume — mplsoccer's `flow`.
152
+ * Unlike every other layer here, the rendered marks are aggregates rather
153
+ * than one-per-datum, so `tooltip` takes a `FlowBin`, not a `T`.
154
+ */
155
+ declare function Flow<T>({ data, x, y, x2, y2, binsX, binsY, colorMin, colorMax, strokeWidthMin, strokeWidthMax, className, tooltip, }: FlowProps<T>): react.JSX.Element;
156
+
157
+ interface TooltipState {
158
+ readonly content: ReactNode;
159
+ /** Pixel position within the <Pitch> wrapper, not the viewport. */
160
+ readonly x: number;
161
+ readonly y: number;
162
+ }
163
+ interface PitchContextValue {
164
+ readonly dimensions: PitchDimensions;
165
+ readonly viewport: Viewport;
166
+ readonly transform: PixelTransform;
167
+ readonly setTooltip: (tooltip: TooltipState | null) => void;
168
+ }
169
+
170
+ /**
171
+ * Imperative escape hatch: returns the enclosing `<Pitch>`/`<VerticalPitch>`'s
172
+ * dimensions, viewport, and pixel transform. Must be called from a
173
+ * descendant of `<Pitch>` — for advanced cases (custom marks, manual
174
+ * coordinate math) that the built-in layer components don't cover.
175
+ */
176
+ declare function usePitch(): Pick<PitchContextValue, "dimensions" | "viewport" | "transform">;
177
+
178
+ export { Annotate, type AnnotateProps, Arrows, type ArrowsProps, Comet, type CometProps, ConvexHull, type ConvexHullProps, Flow, type FlowProps, GoalAngle, type GoalAngleProps, Heatmap, type HeatmapProps, Pitch, type PitchProps, Polygon, type PolygonProps, Scatter, type ScatterProps, type TooltipState, VerticalPitch, Voronoi, type VoronoiProps, usePitch };
package/dist/index.js ADDED
@@ -0,0 +1,738 @@
1
+ "use client";
2
+ import { createContext, useState, useId, useRef, useEffect, useContext } from 'react';
3
+ import { getPitchDimensions, createPixelTransform, computePitchGeometry, resolve, computeArrowHeadCorners, computeCometQuad, renderHeatmapLayersToCanvas, computePolygonCentroid, computeConvexHull, computeVoronoiCells, selectGoal, computeFlowBins, createColorScale, resolveStripeCount, goalBoxDepth, computeStripeBands, computeGoalBox, partStyle, arcSweepFlag, arcPathData } from '@pitchkit/core';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+
6
+ // src/Pitch.tsx
7
+ var PitchContext = createContext(null);
8
+ function usePitchContext() {
9
+ const ctx = useContext(PitchContext);
10
+ if (!ctx) {
11
+ throw new Error(
12
+ "@pitchkit/react: this component must be rendered inside <Pitch> or <VerticalPitch>."
13
+ );
14
+ }
15
+ return ctx;
16
+ }
17
+
18
+ // src/style-string.ts
19
+ function parseStyleString(css) {
20
+ const style = {};
21
+ for (const declaration of css.split(";")) {
22
+ const trimmed = declaration.trim();
23
+ if (!trimmed) continue;
24
+ const colonIndex = trimmed.indexOf(":");
25
+ if (colonIndex === -1) continue;
26
+ const prop = trimmed.slice(0, colonIndex).trim();
27
+ const value = trimmed.slice(colonIndex + 1).trim();
28
+ const camelProp = prop.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
29
+ style[camelProp] = value;
30
+ }
31
+ return style;
32
+ }
33
+ function PitchGeometryShapes({
34
+ geometry,
35
+ transform,
36
+ dimensions,
37
+ appearance = {}
38
+ }) {
39
+ const stripeCount = resolveStripeCount(appearance.stripes);
40
+ const depth = goalBoxDepth(dimensions.markings.cornerArcRadius);
41
+ const goalType = appearance.goalType ?? "line";
42
+ return /* @__PURE__ */ jsxs("g", { "data-pitchkit-layer": "pitch", children: [
43
+ /* @__PURE__ */ jsx(RectShape, { rect: geometry.outline, transform, part: "surface" }),
44
+ computeStripeBands(geometry.outline, stripeCount).map((band, i) => /* @__PURE__ */ jsx(RectShape, { rect: band, transform, part: "stripe" }, i)),
45
+ /* @__PURE__ */ jsx(LineShape, { line: geometry.halfwayLine, transform, part: "halfway-line" }),
46
+ /* @__PURE__ */ jsx(CircleShape, { circle: geometry.centerCircle, transform, part: "center-circle" }),
47
+ /* @__PURE__ */ jsx(PointShape, { point: geometry.centerSpot, transform, part: "center-spot" }),
48
+ geometry.penaltyAreas.map((rect, i) => /* @__PURE__ */ jsx(RectShape, { rect, transform, part: "penalty-area" }, i)),
49
+ geometry.sixYardBoxes.map((rect, i) => /* @__PURE__ */ jsx(RectShape, { rect, transform, part: "six-yard-box" }, i)),
50
+ geometry.penaltySpots.map((point, i) => /* @__PURE__ */ jsx(PointShape, { point, transform, part: "penalty-spot" }, i)),
51
+ geometry.penaltyArcs.map((arc, i) => /* @__PURE__ */ jsx(ArcShape, { arc, transform, part: "penalty-arc" }, i)),
52
+ geometry.cornerArcs.map((arc, i) => /* @__PURE__ */ jsx(ArcShape, { arc, transform, part: "corner-arc" }, i)),
53
+ goalType === "box" ? /* @__PURE__ */ jsxs(Fragment, { children: [
54
+ /* @__PURE__ */ jsx(
55
+ RectShape,
56
+ {
57
+ rect: computeGoalBox(geometry.goals[0], true, depth),
58
+ transform,
59
+ part: "goal-box"
60
+ }
61
+ ),
62
+ /* @__PURE__ */ jsx(
63
+ RectShape,
64
+ {
65
+ rect: computeGoalBox(geometry.goals[1], false, depth),
66
+ transform,
67
+ part: "goal-box"
68
+ }
69
+ )
70
+ ] }) : geometry.goals.map((line, i) => /* @__PURE__ */ jsx(LineShape, { line, transform, part: "goal" }, i)),
71
+ /* @__PURE__ */ jsx(RectShape, { rect: geometry.outline, transform, part: "outline" })
72
+ ] });
73
+ }
74
+ function RectShape({
75
+ rect,
76
+ transform,
77
+ part
78
+ }) {
79
+ const cornerA = transform.toPixel([rect.x, rect.y]);
80
+ const cornerB = transform.toPixel([rect.x + rect.width, rect.y + rect.height]);
81
+ const x = Math.min(cornerA[0], cornerB[0]);
82
+ const y = Math.min(cornerA[1], cornerB[1]);
83
+ return /* @__PURE__ */ jsx(
84
+ "rect",
85
+ {
86
+ x,
87
+ y,
88
+ width: Math.abs(cornerB[0] - cornerA[0]),
89
+ height: Math.abs(cornerB[1] - cornerA[1]),
90
+ "data-pitchkit-part": part,
91
+ style: parseStyleString(partStyle(part))
92
+ }
93
+ );
94
+ }
95
+ function LineShape({
96
+ line,
97
+ transform,
98
+ part
99
+ }) {
100
+ const [x1, y1] = transform.toPixel(line.from);
101
+ const [x2, y2] = transform.toPixel(line.to);
102
+ return /* @__PURE__ */ jsx(
103
+ "line",
104
+ {
105
+ x1,
106
+ y1,
107
+ x2,
108
+ y2,
109
+ "data-pitchkit-part": part,
110
+ style: parseStyleString(partStyle(part))
111
+ }
112
+ );
113
+ }
114
+ function CircleShape({
115
+ circle,
116
+ transform,
117
+ part
118
+ }) {
119
+ const [cx, cy] = transform.toPixel(circle.center);
120
+ return /* @__PURE__ */ jsx(
121
+ "circle",
122
+ {
123
+ cx,
124
+ cy,
125
+ r: circle.radius * transform.scale,
126
+ "data-pitchkit-part": part,
127
+ style: parseStyleString(partStyle(part))
128
+ }
129
+ );
130
+ }
131
+ function PointShape({
132
+ point,
133
+ transform,
134
+ part
135
+ }) {
136
+ const [cx, cy] = transform.toPixel(point);
137
+ return /* @__PURE__ */ jsx(
138
+ "circle",
139
+ {
140
+ cx,
141
+ cy,
142
+ r: 2,
143
+ "data-pitchkit-part": part,
144
+ style: parseStyleString(partStyle(part))
145
+ }
146
+ );
147
+ }
148
+ function ArcShape({ arc, transform, part }) {
149
+ const center = transform.toPixel(arc.center);
150
+ const start = transform.toPixel(arc.start);
151
+ const end = transform.toPixel(arc.end);
152
+ const radius = arc.radius * transform.scale;
153
+ const sweep = arcSweepFlag(center, start, end);
154
+ return /* @__PURE__ */ jsx(
155
+ "path",
156
+ {
157
+ d: arcPathData(radius, start, end, sweep),
158
+ "data-pitchkit-part": part,
159
+ style: parseStyleString(partStyle(part))
160
+ }
161
+ );
162
+ }
163
+ function TooltipOverlay({ tooltip }) {
164
+ return /* @__PURE__ */ jsx(
165
+ "div",
166
+ {
167
+ role: "tooltip",
168
+ style: {
169
+ position: "absolute",
170
+ left: tooltip.x,
171
+ top: tooltip.y,
172
+ transform: "translate(-50%, -100%)",
173
+ pointerEvents: "none",
174
+ background: "var(--pitch-tooltip-bg, rgba(17, 17, 17, 0.92))",
175
+ color: "var(--pitch-tooltip-color, #fff)",
176
+ padding: "4px 8px",
177
+ borderRadius: 4,
178
+ fontSize: 12,
179
+ whiteSpace: "nowrap",
180
+ zIndex: 10
181
+ },
182
+ children: tooltip.content
183
+ }
184
+ );
185
+ }
186
+ function useResizeObserver() {
187
+ const ref = useRef(null);
188
+ const [size, setSize] = useState(null);
189
+ useEffect(() => {
190
+ const el = ref.current;
191
+ if (!el) return;
192
+ const observer = new ResizeObserver((entries) => {
193
+ const entry = entries[0];
194
+ if (!entry) return;
195
+ const { width, height } = entry.contentRect;
196
+ setSize({ width, height });
197
+ });
198
+ observer.observe(el);
199
+ return () => observer.disconnect();
200
+ }, []);
201
+ return [ref, size];
202
+ }
203
+ var NOMINAL_WIDTH = 600;
204
+ function Pitch({
205
+ type,
206
+ orientation = "horizontal",
207
+ width: explicitWidth,
208
+ height: explicitHeight,
209
+ crop,
210
+ padding,
211
+ appearance,
212
+ className,
213
+ style,
214
+ children
215
+ }) {
216
+ const dimensions = getPitchDimensions(type);
217
+ const [containerRef, measuredSize] = useResizeObserver();
218
+ const [tooltip, setTooltip] = useState(null);
219
+ const isExplicitSize = explicitWidth !== void 0 && explicitHeight !== void 0;
220
+ const cropExtentX = crop ? Math.abs(crop.x1 - crop.x0) : dimensions.length;
221
+ const cropExtentY = crop ? Math.abs(crop.y1 - crop.y0) : dimensions.width;
222
+ const pitchAspect = orientation === "vertical" ? cropExtentY / cropExtentX : cropExtentX / cropExtentY;
223
+ const fallbackSize = { width: NOMINAL_WIDTH, height: Math.round(NOMINAL_WIDTH / pitchAspect) };
224
+ const size = isExplicitSize ? { width: explicitWidth, height: explicitHeight } : measuredSize ?? fallbackSize;
225
+ const viewport = { width: size.width, height: size.height, orientation, crop, padding };
226
+ const transform = createPixelTransform(dimensions, viewport);
227
+ const geometry = computePitchGeometry(dimensions);
228
+ return /* @__PURE__ */ jsxs(
229
+ "div",
230
+ {
231
+ ref: isExplicitSize ? void 0 : containerRef,
232
+ className,
233
+ style: {
234
+ position: "relative",
235
+ width: isExplicitSize ? explicitWidth : "100%",
236
+ height: isExplicitSize ? explicitHeight : void 0,
237
+ aspectRatio: isExplicitSize ? void 0 : pitchAspect,
238
+ ...style
239
+ },
240
+ children: [
241
+ /* @__PURE__ */ jsxs(
242
+ "svg",
243
+ {
244
+ width: "100%",
245
+ height: "100%",
246
+ viewBox: `0 0 ${viewport.width} ${viewport.height}`,
247
+ style: { display: "block" },
248
+ children: [
249
+ /* @__PURE__ */ jsx(
250
+ PitchGeometryShapes,
251
+ {
252
+ geometry,
253
+ transform,
254
+ dimensions,
255
+ appearance
256
+ }
257
+ ),
258
+ /* @__PURE__ */ jsx(PitchContext.Provider, { value: { dimensions, viewport, transform, setTooltip }, children })
259
+ ]
260
+ }
261
+ ),
262
+ tooltip && /* @__PURE__ */ jsx(TooltipOverlay, { tooltip })
263
+ ]
264
+ }
265
+ );
266
+ }
267
+ function VerticalPitch(props) {
268
+ return /* @__PURE__ */ jsx(Pitch, { ...props, orientation: "vertical" });
269
+ }
270
+ var DEFAULT_RADIUS = 4;
271
+ var DEFAULT_FILL = "var(--pitch-marker-primary, #3b82f6)";
272
+ function Scatter({
273
+ data,
274
+ x,
275
+ y,
276
+ r,
277
+ fill,
278
+ fillOpacity,
279
+ stroke,
280
+ strokeWidth,
281
+ className,
282
+ tooltip
283
+ }) {
284
+ const { transform, setTooltip } = usePitchContext();
285
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "scatter", children: data.map((d, i) => {
286
+ const [cx, cy] = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);
287
+ const radius = resolve(r ?? DEFAULT_RADIUS, d, i);
288
+ const fillValue = fill !== void 0 ? resolve(fill, d, i) : className ? void 0 : DEFAULT_FILL;
289
+ const strokeValue = stroke !== void 0 ? resolve(stroke, d, i) : className ? void 0 : "none";
290
+ const fillOpacityValue = fillOpacity !== void 0 ? resolve(fillOpacity, d, i) : void 0;
291
+ const strokeWidthValue = strokeWidth !== void 0 ? resolve(strokeWidth, d, i) : void 0;
292
+ return /* @__PURE__ */ jsx(
293
+ "circle",
294
+ {
295
+ cx,
296
+ cy,
297
+ r: radius,
298
+ "data-pitchkit-mark": "scatter",
299
+ className,
300
+ style: {
301
+ fill: fillValue,
302
+ stroke: strokeValue,
303
+ fillOpacity: fillOpacityValue,
304
+ strokeWidth: strokeWidthValue
305
+ },
306
+ onMouseEnter: tooltip ? () => setTooltip({ content: tooltip(d, i), x: cx, y: cy }) : void 0,
307
+ onMouseLeave: tooltip ? () => setTooltip(null) : void 0
308
+ },
309
+ i
310
+ );
311
+ }) });
312
+ }
313
+ var TEXT_BASE_STYLE = { fontSize: 10, textAnchor: "middle" };
314
+ var DEFAULT_FILL2 = "var(--pitch-lines, rgba(255, 255, 255, 0.8))";
315
+ function Annotate({
316
+ data,
317
+ x,
318
+ y,
319
+ label,
320
+ offsetX,
321
+ offsetY,
322
+ className,
323
+ tooltip
324
+ }) {
325
+ const { transform, setTooltip } = usePitchContext();
326
+ const textStyle = className ? TEXT_BASE_STYLE : { ...TEXT_BASE_STYLE, fill: DEFAULT_FILL2 };
327
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "annotate", children: data.map((d, i) => {
328
+ const [px, py] = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);
329
+ const dx = offsetX !== void 0 ? resolve(offsetX, d, i) : 0;
330
+ const dy = offsetY !== void 0 ? resolve(offsetY, d, i) : 0;
331
+ const tx = px + dx;
332
+ const ty = py + dy;
333
+ return /* @__PURE__ */ jsx(
334
+ "text",
335
+ {
336
+ x: tx,
337
+ y: ty,
338
+ "data-pitchkit-mark": "annotate",
339
+ style: textStyle,
340
+ className,
341
+ onMouseEnter: tooltip ? () => setTooltip({ content: tooltip(d, i), x: tx, y: ty }) : void 0,
342
+ onMouseLeave: tooltip ? () => setTooltip(null) : void 0,
343
+ children: resolve(label, d, i)
344
+ },
345
+ i
346
+ );
347
+ }) });
348
+ }
349
+ var DEFAULT_STROKE = "var(--pitch-marker-primary, #3b82f6)";
350
+ var DEFAULT_STROKE_WIDTH = 1.5;
351
+ var DEFAULT_HEAD_SIZE = 6;
352
+ function Arrows({
353
+ data,
354
+ x,
355
+ y,
356
+ x2,
357
+ y2,
358
+ stroke,
359
+ strokeWidth,
360
+ strokeOpacity,
361
+ headSize,
362
+ className,
363
+ tooltip
364
+ }) {
365
+ const { transform, setTooltip } = usePitchContext();
366
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "arrows", children: data.map((d, i) => {
367
+ const start = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);
368
+ const end = transform.toPixel([resolve(x2, d, i), resolve(y2, d, i)]);
369
+ const strokeValue = stroke !== void 0 ? resolve(stroke, d, i) : className ? void 0 : DEFAULT_STROKE;
370
+ const strokeWidthValue = resolve(strokeWidth ?? DEFAULT_STROKE_WIDTH, d, i);
371
+ const opacityValue = strokeOpacity !== void 0 ? resolve(strokeOpacity, d, i) : void 0;
372
+ const headSizeValue = resolve(headSize ?? DEFAULT_HEAD_SIZE, d, i);
373
+ const [headA, headB] = computeArrowHeadCorners(start, end, headSizeValue);
374
+ return /* @__PURE__ */ jsxs(
375
+ "g",
376
+ {
377
+ onMouseEnter: tooltip ? () => setTooltip({ content: tooltip(d, i), x: end[0], y: end[1] }) : void 0,
378
+ onMouseLeave: tooltip ? () => setTooltip(null) : void 0,
379
+ children: [
380
+ /* @__PURE__ */ jsx(
381
+ "line",
382
+ {
383
+ x1: start[0],
384
+ y1: start[1],
385
+ x2: end[0],
386
+ y2: end[1],
387
+ "data-pitchkit-mark": "arrow-shaft",
388
+ className,
389
+ style: { stroke: strokeValue, strokeWidth: strokeWidthValue, opacity: opacityValue }
390
+ }
391
+ ),
392
+ /* @__PURE__ */ jsx(
393
+ "polygon",
394
+ {
395
+ points: `${end[0]},${end[1]} ${headA[0]},${headA[1]} ${headB[0]},${headB[1]}`,
396
+ "data-pitchkit-mark": "arrow-head",
397
+ className,
398
+ style: { fill: strokeValue, opacity: opacityValue }
399
+ }
400
+ )
401
+ ]
402
+ },
403
+ i
404
+ );
405
+ }) });
406
+ }
407
+ var DEFAULT_COLOR = "var(--pitch-marker-primary, #3b82f6)";
408
+ var DEFAULT_START_WIDTH = 0.5;
409
+ var DEFAULT_END_WIDTH = 4;
410
+ function Comet({
411
+ data,
412
+ x,
413
+ y,
414
+ x2,
415
+ y2,
416
+ color,
417
+ startWidth,
418
+ endWidth,
419
+ gradient,
420
+ className,
421
+ tooltip
422
+ }) {
423
+ const { transform, setTooltip } = usePitchContext();
424
+ const baseId = useId();
425
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "comet", children: data.map((d, i) => {
426
+ const start = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);
427
+ const end = transform.toPixel([resolve(x2, d, i), resolve(y2, d, i)]);
428
+ const colorValue = resolve(color ?? DEFAULT_COLOR, d, i);
429
+ const startWidthValue = resolve(startWidth ?? DEFAULT_START_WIDTH, d, i);
430
+ const endWidthValue = resolve(endWidth ?? DEFAULT_END_WIDTH, d, i);
431
+ const corners = computeCometQuad(start, end, startWidthValue, endWidthValue);
432
+ const gradientId = `${baseId}-comet-${i}`;
433
+ const flatFillValue = color !== void 0 || !className ? colorValue : void 0;
434
+ const fill = gradient ? `url(#${gradientId})` : flatFillValue;
435
+ return /* @__PURE__ */ jsxs(
436
+ "g",
437
+ {
438
+ onMouseEnter: tooltip ? () => setTooltip({ content: tooltip(d, i), x: end[0], y: end[1] }) : void 0,
439
+ onMouseLeave: tooltip ? () => setTooltip(null) : void 0,
440
+ children: [
441
+ gradient && /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
442
+ "linearGradient",
443
+ {
444
+ id: gradientId,
445
+ gradientUnits: "userSpaceOnUse",
446
+ x1: start[0],
447
+ y1: start[1],
448
+ x2: end[0],
449
+ y2: end[1],
450
+ children: [
451
+ /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: colorValue, stopOpacity: 0 }),
452
+ /* @__PURE__ */ jsx("stop", { offset: "100%", stopColor: colorValue, stopOpacity: 1 })
453
+ ]
454
+ }
455
+ ) }),
456
+ /* @__PURE__ */ jsx(
457
+ "polygon",
458
+ {
459
+ points: corners.map(([px, py]) => `${px},${py}`).join(" "),
460
+ "data-pitchkit-mark": "comet",
461
+ className,
462
+ style: { fill, stroke: "none" }
463
+ }
464
+ )
465
+ ]
466
+ },
467
+ i
468
+ );
469
+ }) });
470
+ }
471
+ function Heatmap({ className, style, ...layerProps }) {
472
+ const { dimensions, viewport } = usePitchContext();
473
+ const canvasRef = useRef(null);
474
+ useEffect(() => {
475
+ const canvas = canvasRef.current;
476
+ if (!canvas) return;
477
+ renderHeatmapLayersToCanvas(
478
+ { dimensions, viewport, layers: [{ type: "heatmap", ...layerProps }] },
479
+ canvas
480
+ );
481
+ });
482
+ return /* @__PURE__ */ jsx("foreignObject", { x: 0, y: 0, width: viewport.width, height: viewport.height, children: /* @__PURE__ */ jsx(
483
+ "canvas",
484
+ {
485
+ ref: canvasRef,
486
+ "data-pitchkit-layer": "heatmap",
487
+ className,
488
+ style: { width: "100%", height: "100%", display: "block", ...style }
489
+ }
490
+ ) });
491
+ }
492
+ var DEFAULT_FILL3 = "var(--pitch-marker-primary, #3b82f6)";
493
+ var DEFAULT_FILL_OPACITY = 0.35;
494
+ function Polygon({
495
+ data,
496
+ points,
497
+ fill,
498
+ fillOpacity,
499
+ stroke,
500
+ strokeWidth,
501
+ className,
502
+ tooltip
503
+ }) {
504
+ const { transform, setTooltip } = usePitchContext();
505
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "polygon", children: data.map((d, i) => {
506
+ const vertices = resolve(points, d, i).map((p) => transform.toPixel(p));
507
+ const [tx, ty] = computePolygonCentroid(vertices);
508
+ const fillValue = fill !== void 0 ? resolve(fill, d, i) : className ? void 0 : DEFAULT_FILL3;
509
+ const strokeValue = stroke !== void 0 ? resolve(stroke, d, i) : void 0;
510
+ const fillOpacityValue = fillOpacity !== void 0 ? resolve(fillOpacity, d, i) : className ? void 0 : DEFAULT_FILL_OPACITY;
511
+ const strokeWidthValue = strokeWidth !== void 0 ? resolve(strokeWidth, d, i) : void 0;
512
+ return /* @__PURE__ */ jsx(
513
+ "polygon",
514
+ {
515
+ points: vertices.map(([px, py]) => `${px},${py}`).join(" "),
516
+ "data-pitchkit-mark": "polygon",
517
+ className,
518
+ style: {
519
+ fill: fillValue,
520
+ fillOpacity: fillOpacityValue,
521
+ stroke: strokeValue,
522
+ strokeWidth: strokeWidthValue
523
+ },
524
+ onMouseEnter: tooltip ? () => setTooltip({ content: tooltip(d, i), x: tx, y: ty }) : void 0,
525
+ onMouseLeave: tooltip ? () => setTooltip(null) : void 0
526
+ },
527
+ i
528
+ );
529
+ }) });
530
+ }
531
+ var DEFAULT_FILL4 = "var(--pitch-marker-primary, #3b82f6)";
532
+ var DEFAULT_FILL_OPACITY2 = 0.35;
533
+ function ConvexHull({
534
+ data,
535
+ x,
536
+ y,
537
+ fill,
538
+ fillOpacity,
539
+ stroke,
540
+ strokeWidth,
541
+ className,
542
+ tooltip
543
+ }) {
544
+ const { transform, setTooltip } = usePitchContext();
545
+ const points = data.map((d, i) => transform.toPixel([resolve(x, d, i), resolve(y, d, i)]));
546
+ const hull = computeConvexHull(points);
547
+ const [tx, ty] = computePolygonCentroid(hull);
548
+ const fillValue = fill ?? (className ? void 0 : DEFAULT_FILL4);
549
+ const fillOpacityValue = fillOpacity ?? (className ? void 0 : DEFAULT_FILL_OPACITY2);
550
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "convex-hull", children: /* @__PURE__ */ jsx(
551
+ "polygon",
552
+ {
553
+ points: hull.map(([px, py]) => `${px},${py}`).join(" "),
554
+ "data-pitchkit-mark": "convex-hull",
555
+ className,
556
+ style: { fill: fillValue, fillOpacity: fillOpacityValue, stroke, strokeWidth },
557
+ onMouseEnter: tooltip !== void 0 ? () => setTooltip({ content: tooltip, x: tx, y: ty }) : void 0,
558
+ onMouseLeave: tooltip !== void 0 ? () => setTooltip(null) : void 0
559
+ }
560
+ ) });
561
+ }
562
+ var DEFAULT_FILL5 = "var(--pitch-marker-primary, #3b82f6)";
563
+ var DEFAULT_FILL_OPACITY3 = 0.2;
564
+ var DEFAULT_STROKE2 = "var(--pitch-lines, rgba(255, 255, 255, 0.8))";
565
+ function Voronoi({
566
+ data,
567
+ x,
568
+ y,
569
+ fill,
570
+ fillOpacity,
571
+ stroke,
572
+ strokeWidth,
573
+ className,
574
+ tooltip
575
+ }) {
576
+ const { dimensions, transform, setTooltip } = usePitchContext();
577
+ const sites = data.map((d, i) => [resolve(x, d, i), resolve(y, d, i)]);
578
+ const { outline } = computePitchGeometry(dimensions);
579
+ const cells = computeVoronoiCells(sites, outline);
580
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "voronoi", children: data.map((d, i) => {
581
+ const cell = (cells[i] ?? []).map((p) => transform.toPixel(p));
582
+ const fillValue = fill !== void 0 ? resolve(fill, d, i) : className ? void 0 : DEFAULT_FILL5;
583
+ const fillOpacityValue = fillOpacity !== void 0 ? resolve(fillOpacity, d, i) : className ? void 0 : DEFAULT_FILL_OPACITY3;
584
+ const strokeValue = stroke !== void 0 ? resolve(stroke, d, i) : className ? void 0 : DEFAULT_STROKE2;
585
+ const strokeWidthValue = strokeWidth !== void 0 ? resolve(strokeWidth, d, i) : 1;
586
+ return /* @__PURE__ */ jsx(
587
+ "polygon",
588
+ {
589
+ points: cell.map(([px, py]) => `${px},${py}`).join(" "),
590
+ "data-pitchkit-mark": "voronoi",
591
+ className,
592
+ style: {
593
+ fill: fillValue,
594
+ fillOpacity: fillOpacityValue,
595
+ stroke: strokeValue,
596
+ strokeWidth: strokeWidthValue
597
+ },
598
+ onMouseEnter: tooltip ? () => {
599
+ const [tx, ty] = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);
600
+ setTooltip({ content: tooltip(d, i), x: tx, y: ty });
601
+ } : void 0,
602
+ onMouseLeave: tooltip ? () => setTooltip(null) : void 0
603
+ },
604
+ i
605
+ );
606
+ }) });
607
+ }
608
+ var DEFAULT_FILL6 = "var(--pitch-marker-goal, #f97316)";
609
+ var DEFAULT_FILL_OPACITY4 = 0.25;
610
+ var DEFAULT_GOAL = "nearest";
611
+ function GoalAngle({
612
+ data,
613
+ x,
614
+ y,
615
+ goal,
616
+ fill,
617
+ fillOpacity,
618
+ stroke,
619
+ strokeWidth,
620
+ className,
621
+ tooltip
622
+ }) {
623
+ const { dimensions, transform, setTooltip } = usePitchContext();
624
+ const { goals } = computePitchGeometry(dimensions);
625
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "goal-angle", children: data.map((d, i) => {
626
+ const point = [resolve(x, d, i), resolve(y, d, i)];
627
+ const goalChoice = resolve(goal ?? DEFAULT_GOAL, d, i);
628
+ const goalLine = selectGoal(point, goals, goalChoice);
629
+ const vertices = [point, goalLine.from, goalLine.to].map((p) => transform.toPixel(p));
630
+ const [tx, ty] = computePolygonCentroid(vertices);
631
+ const fillValue = fill !== void 0 ? resolve(fill, d, i) : className ? void 0 : DEFAULT_FILL6;
632
+ const fillOpacityValue = fillOpacity !== void 0 ? resolve(fillOpacity, d, i) : className ? void 0 : DEFAULT_FILL_OPACITY4;
633
+ const strokeValue = stroke !== void 0 ? resolve(stroke, d, i) : void 0;
634
+ const strokeWidthValue = strokeWidth !== void 0 ? resolve(strokeWidth, d, i) : void 0;
635
+ return /* @__PURE__ */ jsx(
636
+ "polygon",
637
+ {
638
+ points: vertices.map(([px, py]) => `${px},${py}`).join(" "),
639
+ "data-pitchkit-mark": "goal-angle",
640
+ className,
641
+ style: {
642
+ fill: fillValue,
643
+ fillOpacity: fillOpacityValue,
644
+ stroke: strokeValue,
645
+ strokeWidth: strokeWidthValue
646
+ },
647
+ onMouseEnter: tooltip ? () => setTooltip({ content: tooltip(d, i), x: tx, y: ty }) : void 0,
648
+ onMouseLeave: tooltip ? () => setTooltip(null) : void 0
649
+ },
650
+ i
651
+ );
652
+ }) });
653
+ }
654
+ var DEFAULT_BINS_X = 6;
655
+ var DEFAULT_BINS_Y = 5;
656
+ var DEFAULT_COLOR_MIN = "#93c5fd";
657
+ var DEFAULT_COLOR_MAX = "#1d4ed8";
658
+ var DEFAULT_STROKE_WIDTH_MIN = 1;
659
+ var DEFAULT_STROKE_WIDTH_MAX = 4;
660
+ var DEFAULT_HEAD_SIZE2 = 6;
661
+ function Flow({
662
+ data,
663
+ x,
664
+ y,
665
+ x2,
666
+ y2,
667
+ binsX = DEFAULT_BINS_X,
668
+ binsY = DEFAULT_BINS_Y,
669
+ colorMin = DEFAULT_COLOR_MIN,
670
+ colorMax = DEFAULT_COLOR_MAX,
671
+ strokeWidthMin = DEFAULT_STROKE_WIDTH_MIN,
672
+ strokeWidthMax = DEFAULT_STROKE_WIDTH_MAX,
673
+ className,
674
+ tooltip
675
+ }) {
676
+ const { dimensions, transform, setTooltip } = usePitchContext();
677
+ const vectors = data.map((d, i) => ({
678
+ x: resolve(x, d, i),
679
+ y: resolve(y, d, i),
680
+ x2: resolve(x2, d, i),
681
+ y2: resolve(y2, d, i)
682
+ }));
683
+ const bins = computeFlowBins(vectors, binsX, binsY, dimensions);
684
+ const counts = bins.map((bin) => bin.count);
685
+ const minCount = counts.length > 0 ? Math.min(...counts) : 0;
686
+ const maxCount = counts.length > 0 ? Math.max(...counts) : 0;
687
+ const colorScale = createColorScale(minCount, maxCount, colorMin, colorMax);
688
+ const countRange = maxCount - minCount || 1;
689
+ return /* @__PURE__ */ jsx("g", { "data-pitchkit-layer": "flow", children: bins.map((bin, i) => {
690
+ const start = transform.toPixel([bin.x, bin.y]);
691
+ const end = transform.toPixel([bin.x2, bin.y2]);
692
+ const t = (bin.count - minCount) / countRange;
693
+ const color = colorScale(bin.count);
694
+ const strokeWidthValue = strokeWidthMin + (strokeWidthMax - strokeWidthMin) * t;
695
+ const [headA, headB] = computeArrowHeadCorners(start, end, DEFAULT_HEAD_SIZE2);
696
+ return /* @__PURE__ */ jsxs(
697
+ "g",
698
+ {
699
+ onMouseEnter: tooltip ? () => setTooltip({ content: tooltip(bin, i), x: end[0], y: end[1] }) : void 0,
700
+ onMouseLeave: tooltip ? () => setTooltip(null) : void 0,
701
+ children: [
702
+ /* @__PURE__ */ jsx(
703
+ "line",
704
+ {
705
+ x1: start[0],
706
+ y1: start[1],
707
+ x2: end[0],
708
+ y2: end[1],
709
+ "data-pitchkit-mark": "flow-shaft",
710
+ className,
711
+ style: { stroke: color, strokeWidth: strokeWidthValue }
712
+ }
713
+ ),
714
+ /* @__PURE__ */ jsx(
715
+ "polygon",
716
+ {
717
+ points: `${end[0]},${end[1]} ${headA[0]},${headA[1]} ${headB[0]},${headB[1]}`,
718
+ "data-pitchkit-mark": "flow-head",
719
+ className,
720
+ style: { fill: color }
721
+ }
722
+ )
723
+ ]
724
+ },
725
+ i
726
+ );
727
+ }) });
728
+ }
729
+
730
+ // src/use-pitch.ts
731
+ function usePitch() {
732
+ const { dimensions, viewport, transform } = usePitchContext();
733
+ return { dimensions, viewport, transform };
734
+ }
735
+
736
+ export { Annotate, Arrows, Comet, ConvexHull, Flow, GoalAngle, Heatmap, Pitch, Polygon, Scatter, VerticalPitch, Voronoi, usePitch };
737
+ //# sourceMappingURL=index.js.map
738
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context.ts","../src/style-string.ts","../src/pitch-geometry.tsx","../src/TooltipOverlay.tsx","../src/use-resize-observer.ts","../src/Pitch.tsx","../src/VerticalPitch.tsx","../src/Scatter.tsx","../src/Annotate.tsx","../src/Arrows.tsx","../src/Comet.tsx","../src/Heatmap.tsx","../src/Polygon.tsx","../src/ConvexHull.tsx","../src/Voronoi.tsx","../src/GoalAngle.tsx","../src/Flow.tsx","../src/use-pitch.ts"],"names":["jsx","useState","jsxs","DEFAULT_FILL","resolve","useRef","useEffect","DEFAULT_FILL_OPACITY","computePolygonCentroid","DEFAULT_STROKE","computePitchGeometry","DEFAULT_HEAD_SIZE","computeArrowHeadCorners"],"mappings":"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","file":"index.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { PitchDimensions, PixelTransform, Viewport } from \"@pitchkit/core\";\n\nexport interface TooltipState {\n readonly content: ReactNode;\n /** Pixel position within the <Pitch> wrapper, not the viewport. */\n readonly x: number;\n readonly y: number;\n}\n\nexport interface PitchContextValue {\n readonly dimensions: PitchDimensions;\n readonly viewport: Viewport;\n readonly transform: PixelTransform;\n readonly setTooltip: (tooltip: TooltipState | null) => void;\n}\n\nexport const PitchContext = createContext<PitchContextValue | null>(null);\n\n/**\n * Internal: every layer component (Scatter/Annotate/Arrows/Comet) reads the\n * scene's transform through this. Throws with a specific message rather\n * than silently rendering nothing, since \"layer outside <Pitch>\" is a\n * usage error a consumer should see immediately, not debug from a blank\n * pitch.\n */\nexport function usePitchContext(): PitchContextValue {\n const ctx = useContext(PitchContext);\n if (!ctx) {\n throw new Error(\n \"@pitchkit/react: this component must be rendered inside <Pitch> or <VerticalPitch>.\",\n );\n }\n return ctx;\n}\n","import type { CSSProperties } from \"react\";\n\n/**\n * Converts a `\"prop: value; prop2: value2;\"` CSS string (core's\n * `partStyle()` format, used as-is by the DOM renderer's\n * `setAttribute(\"style\", ...)`) into the camelCase object React's `style`\n * prop requires. React DOM rejects a raw string for `style` — this is the\n * one place that difference has to be bridged, so both renderers can keep\n * consuming the exact same `partStyle()` string without core's API\n * changing shape for React's sake.\n *\n * Only handles simple `prop: value` declarations (no nested at-rules,\n * comments, or `!important`) — that's all `partStyle()` ever produces.\n */\nexport function parseStyleString(css: string): CSSProperties {\n const style: Record<string, string> = {};\n for (const declaration of css.split(\";\")) {\n const trimmed = declaration.trim();\n if (!trimmed) continue;\n const colonIndex = trimmed.indexOf(\":\");\n if (colonIndex === -1) continue;\n const prop = trimmed.slice(0, colonIndex).trim();\n const value = trimmed.slice(colonIndex + 1).trim();\n const camelProp = prop.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase());\n style[camelProp] = value;\n }\n return style as CSSProperties;\n}\n","import {\n arcPathData,\n arcSweepFlag,\n computeGoalBox,\n computeStripeBands,\n goalBoxDepth,\n partStyle,\n resolveStripeCount,\n} from \"@pitchkit/core\";\nimport type {\n Arc,\n Circle,\n Line,\n PitchAppearance,\n PitchDimensions,\n PitchGeometry,\n Point,\n PixelTransform,\n Rect,\n} from \"@pitchkit/core\";\nimport { parseStyleString } from \"./style-string.js\";\n\n/**\n * Emits a PitchGeometry as JSX, one element per shape — the React\n * equivalent of core's `paintPitchGeometry` (`render/svg/paint-pitch.ts`).\n * Deliberately re-emits rather than reusing core's DOM painter: JSX is\n * what makes this SSR-able and lets marks attach native React event\n * handlers. Every piece of *logic* (styling, stripe/goal-box geometry, arc\n * sweep math) is imported from core, not reimplemented — only the\n * DOM-vs-JSX element-emission layer differs, so the two renderers cannot\n * drift on anything but syntax.\n */\nexport function PitchGeometryShapes({\n geometry,\n transform,\n dimensions,\n appearance = {},\n}: {\n geometry: PitchGeometry;\n transform: PixelTransform;\n dimensions: PitchDimensions;\n appearance?: PitchAppearance;\n}) {\n const stripeCount = resolveStripeCount(appearance.stripes);\n const depth = goalBoxDepth(dimensions.markings.cornerArcRadius);\n const goalType = appearance.goalType ?? \"line\";\n\n return (\n <g data-pitchkit-layer=\"pitch\">\n <RectShape rect={geometry.outline} transform={transform} part=\"surface\" />\n {computeStripeBands(geometry.outline, stripeCount).map((band, i) => (\n <RectShape key={i} rect={band} transform={transform} part=\"stripe\" />\n ))}\n\n <LineShape line={geometry.halfwayLine} transform={transform} part=\"halfway-line\" />\n <CircleShape circle={geometry.centerCircle} transform={transform} part=\"center-circle\" />\n <PointShape point={geometry.centerSpot} transform={transform} part=\"center-spot\" />\n\n {geometry.penaltyAreas.map((rect, i) => (\n <RectShape key={i} rect={rect} transform={transform} part=\"penalty-area\" />\n ))}\n {geometry.sixYardBoxes.map((rect, i) => (\n <RectShape key={i} rect={rect} transform={transform} part=\"six-yard-box\" />\n ))}\n {geometry.penaltySpots.map((point, i) => (\n <PointShape key={i} point={point} transform={transform} part=\"penalty-spot\" />\n ))}\n {geometry.penaltyArcs.map((arc, i) => (\n <ArcShape key={i} arc={arc} transform={transform} part=\"penalty-arc\" />\n ))}\n {geometry.cornerArcs.map((arc, i) => (\n <ArcShape key={i} arc={arc} transform={transform} part=\"corner-arc\" />\n ))}\n\n {goalType === \"box\" ? (\n <>\n <RectShape\n rect={computeGoalBox(geometry.goals[0], true, depth)}\n transform={transform}\n part=\"goal-box\"\n />\n <RectShape\n rect={computeGoalBox(geometry.goals[1], false, depth)}\n transform={transform}\n part=\"goal-box\"\n />\n </>\n ) : (\n geometry.goals.map((line, i) => (\n <LineShape key={i} line={line} transform={transform} part=\"goal\" />\n ))\n )}\n\n {/* The stroke-only border paints last: SVG strokes are centered on the\n path, so the inner half of an earlier-painted border would be masked\n by opaque stripes (issue #14). */}\n <RectShape rect={geometry.outline} transform={transform} part=\"outline\" />\n </g>\n );\n}\n\nfunction RectShape({\n rect,\n transform,\n part,\n}: {\n rect: Rect;\n transform: PixelTransform;\n part: string;\n}) {\n const cornerA = transform.toPixel([rect.x, rect.y]);\n const cornerB = transform.toPixel([rect.x + rect.width, rect.y + rect.height]);\n const x = Math.min(cornerA[0], cornerB[0]);\n const y = Math.min(cornerA[1], cornerB[1]);\n\n return (\n <rect\n x={x}\n y={y}\n width={Math.abs(cornerB[0] - cornerA[0])}\n height={Math.abs(cornerB[1] - cornerA[1])}\n data-pitchkit-part={part}\n style={parseStyleString(partStyle(part))}\n />\n );\n}\n\nfunction LineShape({\n line,\n transform,\n part,\n}: {\n line: Line;\n transform: PixelTransform;\n part: string;\n}) {\n const [x1, y1] = transform.toPixel(line.from);\n const [x2, y2] = transform.toPixel(line.to);\n\n return (\n <line\n x1={x1}\n y1={y1}\n x2={x2}\n y2={y2}\n data-pitchkit-part={part}\n style={parseStyleString(partStyle(part))}\n />\n );\n}\n\nfunction CircleShape({\n circle,\n transform,\n part,\n}: {\n circle: Circle;\n transform: PixelTransform;\n part: string;\n}) {\n const [cx, cy] = transform.toPixel(circle.center);\n\n return (\n <circle\n cx={cx}\n cy={cy}\n r={circle.radius * transform.scale}\n data-pitchkit-part={part}\n style={parseStyleString(partStyle(part))}\n />\n );\n}\n\nfunction PointShape({\n point,\n transform,\n part,\n}: {\n point: Point;\n transform: PixelTransform;\n part: string;\n}) {\n const [cx, cy] = transform.toPixel(point);\n\n return (\n <circle\n cx={cx}\n cy={cy}\n r={2}\n data-pitchkit-part={part}\n style={parseStyleString(partStyle(part))}\n />\n );\n}\n\nfunction ArcShape({ arc, transform, part }: { arc: Arc; transform: PixelTransform; part: string }) {\n const center = transform.toPixel(arc.center);\n const start = transform.toPixel(arc.start);\n const end = transform.toPixel(arc.end);\n const radius = arc.radius * transform.scale;\n const sweep = arcSweepFlag(center, start, end);\n\n return (\n <path\n d={arcPathData(radius, start, end, sweep)}\n data-pitchkit-part={part}\n style={parseStyleString(partStyle(part))}\n />\n );\n}\n","import type { TooltipState } from \"./context.js\";\n\n/**\n * Positioned absolutely within `<Pitch>`'s wrapper, offset above the\n * hovered mark. Desktop hover only for this first pass — the PRD's full\n * touch-vs-hover interaction model (§8.6) is deferred scope.\n */\nexport function TooltipOverlay({ tooltip }: { tooltip: TooltipState }) {\n return (\n <div\n role=\"tooltip\"\n style={{\n position: \"absolute\",\n left: tooltip.x,\n top: tooltip.y,\n transform: \"translate(-50%, -100%)\",\n pointerEvents: \"none\",\n background: \"var(--pitch-tooltip-bg, rgba(17, 17, 17, 0.92))\",\n color: \"var(--pitch-tooltip-color, #fff)\",\n padding: \"4px 8px\",\n borderRadius: 4,\n fontSize: 12,\n whiteSpace: \"nowrap\",\n zIndex: 10,\n }}\n >\n {tooltip.content}\n </div>\n );\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport interface Size {\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * Measures a ref'd element's content box, updating on resize via\n * ResizeObserver. This is the mechanism behind <Pitch>'s \"responsive by\n * default\" behaviour (PRD §8.6) — no `responsive` prop, just no\n * width/height.\n *\n * Returns `null` until the first measurement (SSR, or before mount) —\n * callers render a fallback (or nothing) until a size is available.\n */\nexport function useResizeObserver<T extends Element>(): [RefObject<T | null>, Size | null] {\n const ref = useRef<T | null>(null);\n const [size, setSize] = useState<Size | null>(null);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry) return;\n const { width, height } = entry.contentRect;\n setSize({ width, height });\n });\n observer.observe(el);\n\n return () => observer.disconnect();\n }, []);\n\n return [ref, size];\n}\n","import { useState } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { computePitchGeometry, createPixelTransform, getPitchDimensions } from \"@pitchkit/core\";\nimport type {\n CropWindow,\n Orientation,\n PitchAppearance,\n PitchTypeId,\n Viewport,\n ViewportPadding,\n} from \"@pitchkit/core\";\nimport { PitchContext } from \"./context.js\";\nimport type { TooltipState } from \"./context.js\";\nimport { PitchGeometryShapes } from \"./pitch-geometry.js\";\nimport { TooltipOverlay } from \"./TooltipOverlay.js\";\nimport { useResizeObserver } from \"./use-resize-observer.js\";\n\nexport interface PitchProps {\n type: PitchTypeId;\n /** @default \"horizontal\" */\n orientation?: Orientation;\n /** Fixed pixel size — the opt-out from the responsive default. Provide both, or neither. */\n width?: number;\n height?: number;\n crop?: CropWindow;\n padding?: ViewportPadding;\n appearance?: PitchAppearance;\n className?: string;\n style?: CSSProperties;\n children?: ReactNode;\n}\n\n// A nominal size (matching the pitch's own aspect ratio) used only for the\n// very first render, before ResizeObserver has measured the real\n// container — SSR included, since there's no DOM to measure server-side.\n// Picking a fallback with the *correct aspect ratio* means the SVG content\n// is never distorted, even though its absolute pixel scale may be off\n// until the first client measurement (PRD §8.6's \"explicit aspect ratio on\n// first paint, ResizeObserver refine after hydration\").\nconst NOMINAL_WIDTH = 600;\n\n/**\n * The root pitch component: owns the coordinate system, is responsive by\n * default (fills its container via ResizeObserver — explicit width/height\n * is the opt-out), and provides the pixel transform to layer-component\n * children via context.\n */\nexport function Pitch({\n type,\n orientation = \"horizontal\",\n width: explicitWidth,\n height: explicitHeight,\n crop,\n padding,\n appearance,\n className,\n style,\n children,\n}: PitchProps) {\n const dimensions = getPitchDimensions(type);\n const [containerRef, measuredSize] = useResizeObserver<HTMLDivElement>();\n const [tooltip, setTooltip] = useState<TooltipState | null>(null);\n\n const isExplicitSize = explicitWidth !== undefined && explicitHeight !== undefined;\n\n // The container's aspect ratio must match what's actually being shown —\n // the cropped extent, not the full pitch — otherwise a half-pitch crop\n // renders inside a box sized for the whole pitch, leaving room for the\n // other half's markings (which the transform maps just outside the\n // crop, but not outside the oversized container) to bleed into view.\n // `crop`'s x0/x1/y0/y1 are already in the provider's own units (same\n // space as `dimensions.length`/`width`), and x never gets axis-swapped\n // by yDirection (see `canonical.ts`), so a plain abs-difference gives\n // the right extent without needing the canonical-frame conversion.\n const cropExtentX = crop ? Math.abs(crop.x1 - crop.x0) : dimensions.length;\n const cropExtentY = crop ? Math.abs(crop.y1 - crop.y0) : dimensions.width;\n const pitchAspect = orientation === \"vertical\" ? cropExtentY / cropExtentX : cropExtentX / cropExtentY;\n const fallbackSize = { width: NOMINAL_WIDTH, height: Math.round(NOMINAL_WIDTH / pitchAspect) };\n\n const size = isExplicitSize\n ? { width: explicitWidth, height: explicitHeight }\n : (measuredSize ?? fallbackSize);\n\n const viewport: Viewport = { width: size.width, height: size.height, orientation, crop, padding };\n const transform = createPixelTransform(dimensions, viewport);\n const geometry = computePitchGeometry(dimensions);\n\n return (\n <div\n ref={isExplicitSize ? undefined : containerRef}\n className={className}\n style={{\n position: \"relative\",\n width: isExplicitSize ? explicitWidth : \"100%\",\n height: isExplicitSize ? explicitHeight : undefined,\n aspectRatio: isExplicitSize ? undefined : pitchAspect,\n ...style,\n }}\n >\n <svg\n width=\"100%\"\n height=\"100%\"\n viewBox={`0 0 ${viewport.width} ${viewport.height}`}\n style={{ display: \"block\" }}\n >\n <PitchGeometryShapes\n geometry={geometry}\n transform={transform}\n dimensions={dimensions}\n appearance={appearance}\n />\n <PitchContext.Provider value={{ dimensions, viewport, transform, setTooltip }}>\n {children}\n </PitchContext.Provider>\n </svg>\n {tooltip && <TooltipOverlay tooltip={tooltip} />}\n </div>\n );\n}\n","import { Pitch } from \"./Pitch.js\";\nimport type { PitchProps } from \"./Pitch.js\";\n\n/**\n * `<Pitch orientation=\"vertical\">`, named to match mplsoccer's\n * `VerticalPitch` for familiarity. Core has no separate vertical pitch\n * concept (orientation is a `Viewport` field, not a distinct coordinate\n * system) — this is purely a naming/ergonomics convenience at the\n * component-API layer.\n */\nexport function VerticalPitch(props: Omit<PitchProps, \"orientation\">) {\n return <Pitch {...props} orientation=\"vertical\" />;\n}\n","import type { ReactNode } from \"react\";\nimport { resolve } from \"@pitchkit/core\";\nimport type { ScatterLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface ScatterProps<T> extends Omit<ScatterLayer<T>, \"type\"> {\n tooltip?: (d: T, i: number) => ReactNode;\n}\n\nconst DEFAULT_RADIUS = 4;\nconst DEFAULT_FILL = \"var(--pitch-marker-primary, #3b82f6)\";\n\n/** One `<circle>` per datum — the JSX equivalent of core's `paintScatterLayer`. */\nexport function Scatter<T>({\n data,\n x,\n y,\n r,\n fill,\n fillOpacity,\n stroke,\n strokeWidth,\n className,\n tooltip,\n}: ScatterProps<T>) {\n const { transform, setTooltip } = usePitchContext();\n\n return (\n <g data-pitchkit-layer=\"scatter\">\n {data.map((d, i) => {\n const [cx, cy] = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);\n const radius = resolve(r ?? DEFAULT_RADIUS, d, i);\n // `fill`/`stroke` are the only two visual props with a themed\n // fallback rather than \"just leave it unset\" — and that fallback is\n // an inline style, which always beats a `className` utility class\n // (`fill-emerald-400`, say) at the same CSS property, opt-in or\n // not. So the fallback only applies when `className` is absent;\n // passing `className` hands color ownership to it, same as passing\n // `fill`/`stroke` explicitly still does either way.\n const fillValue =\n fill !== undefined ? resolve(fill, d, i) : className ? undefined : DEFAULT_FILL;\n const strokeValue =\n stroke !== undefined ? resolve(stroke, d, i) : className ? undefined : \"none\";\n const fillOpacityValue = fillOpacity !== undefined ? resolve(fillOpacity, d, i) : undefined;\n const strokeWidthValue = strokeWidth !== undefined ? resolve(strokeWidth, d, i) : undefined;\n\n return (\n <circle\n key={i}\n cx={cx}\n cy={cy}\n r={radius}\n data-pitchkit-mark=\"scatter\"\n className={className}\n style={{\n fill: fillValue,\n stroke: strokeValue,\n fillOpacity: fillOpacityValue,\n strokeWidth: strokeWidthValue,\n }}\n onMouseEnter={\n tooltip ? () => setTooltip({ content: tooltip(d, i), x: cx, y: cy }) : undefined\n }\n onMouseLeave={tooltip ? () => setTooltip(null) : undefined}\n />\n );\n })}\n </g>\n );\n}\n","import type { CSSProperties, ReactNode } from \"react\";\nimport { resolve } from \"@pitchkit/core\";\nimport type { AnnotateLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface AnnotateProps<T> extends Omit<AnnotateLayer<T>, \"type\"> {\n tooltip?: (d: T, i: number) => ReactNode;\n}\n\nconst TEXT_BASE_STYLE: CSSProperties = { fontSize: 10, textAnchor: \"middle\" };\nconst DEFAULT_FILL = \"var(--pitch-lines, rgba(255, 255, 255, 0.8))\";\n\n/** One `<text>` per datum — the JSX equivalent of core's `paintAnnotateLayer`. */\nexport function Annotate<T>({\n data,\n x,\n y,\n label,\n offsetX,\n offsetY,\n className,\n tooltip,\n}: AnnotateProps<T>) {\n const { transform, setTooltip } = usePitchContext();\n // The themed default fill is only applied when `className` is absent —\n // it's set as inline style, which always beats a class at the same\n // property, so a consumer's `fill-*` utility needs the default to back\n // off rather than losing to it. See Scatter.tsx's equivalent comment.\n const textStyle: CSSProperties = className ? TEXT_BASE_STYLE : { ...TEXT_BASE_STYLE, fill: DEFAULT_FILL };\n\n return (\n <g data-pitchkit-layer=\"annotate\">\n {data.map((d, i) => {\n const [px, py] = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);\n const dx = offsetX !== undefined ? resolve(offsetX, d, i) : 0;\n const dy = offsetY !== undefined ? resolve(offsetY, d, i) : 0;\n const tx = px + dx;\n const ty = py + dy;\n\n return (\n <text\n key={i}\n x={tx}\n y={ty}\n data-pitchkit-mark=\"annotate\"\n style={textStyle}\n className={className}\n onMouseEnter={\n tooltip ? () => setTooltip({ content: tooltip(d, i), x: tx, y: ty }) : undefined\n }\n onMouseLeave={tooltip ? () => setTooltip(null) : undefined}\n >\n {resolve(label, d, i)}\n </text>\n );\n })}\n </g>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { computeArrowHeadCorners, resolve } from \"@pitchkit/core\";\nimport type { ArrowsLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface ArrowsProps<T> extends Omit<ArrowsLayer<T>, \"type\"> {\n tooltip?: (d: T, i: number) => ReactNode;\n}\n\nconst DEFAULT_STROKE = \"var(--pitch-marker-primary, #3b82f6)\";\nconst DEFAULT_STROKE_WIDTH = 1.5;\nconst DEFAULT_HEAD_SIZE = 6;\n\n/**\n * One shaft `<line>` + arrowhead `<polygon>` per datum — the JSX\n * equivalent of core's `paintArrowsLayer`, sharing its `computeArrowHeadCorners`\n * geometry so the head angle can't drift between the two renderers.\n */\nexport function Arrows<T>({\n data,\n x,\n y,\n x2,\n y2,\n stroke,\n strokeWidth,\n strokeOpacity,\n headSize,\n className,\n tooltip,\n}: ArrowsProps<T>) {\n const { transform, setTooltip } = usePitchContext();\n\n return (\n <g data-pitchkit-layer=\"arrows\">\n {data.map((d, i) => {\n const start = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);\n const end = transform.toPixel([resolve(x2, d, i), resolve(y2, d, i)]);\n // See Scatter.tsx's equivalent comment: the themed default falls\n // back to an inline style, which always beats a `className`\n // utility at the same property, so it only applies when\n // `className` is absent.\n const strokeValue =\n stroke !== undefined ? resolve(stroke, d, i) : className ? undefined : DEFAULT_STROKE;\n const strokeWidthValue = resolve(strokeWidth ?? DEFAULT_STROKE_WIDTH, d, i);\n const opacityValue = strokeOpacity !== undefined ? resolve(strokeOpacity, d, i) : undefined;\n const headSizeValue = resolve(headSize ?? DEFAULT_HEAD_SIZE, d, i);\n const [headA, headB] = computeArrowHeadCorners(start, end, headSizeValue);\n\n return (\n <g\n key={i}\n onMouseEnter={\n tooltip\n ? () => setTooltip({ content: tooltip(d, i), x: end[0], y: end[1] })\n : undefined\n }\n onMouseLeave={tooltip ? () => setTooltip(null) : undefined}\n >\n <line\n x1={start[0]}\n y1={start[1]}\n x2={end[0]}\n y2={end[1]}\n data-pitchkit-mark=\"arrow-shaft\"\n className={className}\n style={{ stroke: strokeValue, strokeWidth: strokeWidthValue, opacity: opacityValue }}\n />\n <polygon\n points={`${end[0]},${end[1]} ${headA[0]},${headA[1]} ${headB[0]},${headB[1]}`}\n data-pitchkit-mark=\"arrow-head\"\n className={className}\n style={{ fill: strokeValue, opacity: opacityValue }}\n />\n </g>\n );\n })}\n </g>\n );\n}\n","import { useId } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { computeCometQuad, resolve } from \"@pitchkit/core\";\nimport type { CometLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface CometProps<T> extends Omit<CometLayer<T>, \"type\"> {\n tooltip?: (d: T, i: number) => ReactNode;\n}\n\nconst DEFAULT_COLOR = \"var(--pitch-marker-primary, #3b82f6)\";\nconst DEFAULT_START_WIDTH = 0.5;\nconst DEFAULT_END_WIDTH = 4;\n\n/**\n * One filled quadrilateral per datum — the JSX equivalent of core's\n * `paintCometLayer`, sharing its `computeCometQuad` taper geometry. Gradient\n * ids come from `useId()` (SSR-safe stable id) rather than a module-level\n * counter like core's DOM renderer, since two independent server renders\n * must not produce colliding ids.\n */\nexport function Comet<T>({\n data,\n x,\n y,\n x2,\n y2,\n color,\n startWidth,\n endWidth,\n gradient,\n className,\n tooltip,\n}: CometProps<T>) {\n const { transform, setTooltip } = usePitchContext();\n const baseId = useId();\n\n return (\n <g data-pitchkit-layer=\"comet\">\n {data.map((d, i) => {\n const start = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);\n const end = transform.toPixel([resolve(x2, d, i), resolve(y2, d, i)]);\n // `colorValue` always has a themed default — needed unconditionally\n // for the gradient's `<stop>` colors below, which have no\n // `className`-based equivalent. The *flat* (non-gradient) fill is\n // the one that needs to back off that default when `className` is\n // set, for the same inline-style-beats-class reason as Scatter's\n // fill/stroke.\n const colorValue = resolve(color ?? DEFAULT_COLOR, d, i);\n const startWidthValue = resolve(startWidth ?? DEFAULT_START_WIDTH, d, i);\n const endWidthValue = resolve(endWidth ?? DEFAULT_END_WIDTH, d, i);\n const corners = computeCometQuad(start, end, startWidthValue, endWidthValue);\n const gradientId = `${baseId}-comet-${i}`;\n const flatFillValue = color !== undefined || !className ? colorValue : undefined;\n const fill = gradient ? `url(#${gradientId})` : flatFillValue;\n\n return (\n <g\n key={i}\n onMouseEnter={\n tooltip\n ? () => setTooltip({ content: tooltip(d, i), x: end[0], y: end[1] })\n : undefined\n }\n onMouseLeave={tooltip ? () => setTooltip(null) : undefined}\n >\n {gradient && (\n <defs>\n <linearGradient\n id={gradientId}\n gradientUnits=\"userSpaceOnUse\"\n x1={start[0]}\n y1={start[1]}\n x2={end[0]}\n y2={end[1]}\n >\n <stop offset=\"0%\" stopColor={colorValue} stopOpacity={0} />\n <stop offset=\"100%\" stopColor={colorValue} stopOpacity={1} />\n </linearGradient>\n </defs>\n )}\n <polygon\n points={corners.map(([px, py]) => `${px},${py}`).join(\" \")}\n data-pitchkit-mark=\"comet\"\n className={className}\n style={{ fill, stroke: \"none\" }}\n />\n </g>\n );\n })}\n </g>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { renderHeatmapLayersToCanvas } from \"@pitchkit/core\";\nimport type { HeatmapLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface HeatmapProps<T> extends Omit<HeatmapLayer<T>, \"type\"> {\n /**\n * Every bin gets painted (from `colorMin` to `colorMax`, including\n * zero-value bins) rather than leaving low bins transparent, so a\n * heatmap fully covers the pitch underneath by default. Set an opacity\n * here (or a blend mode) to let the pitch show through.\n */\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Client-only `<canvas>` heatmap, painted imperatively via core's\n * `renderHeatmapLayersToCanvas` in an effect. Unlike the SVG layer\n * components, this can't be re-emitted as JSX — Canvas has no declarative\n * JSX equivalent, and dense raster data is exactly the case core's hybrid\n * SVG+Canvas architecture (PRD §8.1) reserves Canvas for. The `<canvas>`\n * itself renders server-side (empty), but its pixels only appear after the\n * client effect runs — a documented client-only boundary.\n *\n * Wrapped in `<foreignObject>` since a raw `<canvas>` can't be a direct\n * child of `<svg>` — this keeps the heatmap inside the same SVG tree as\n * the pitch and every other layer, rather than needing a second,\n * separately-positioned DOM element the way the vanilla-JS core example\n * demo has to (core has no JSX to lean on there).\n *\n * No effect dependency array (runs after every render) rather than\n * enumerating every spread `props` field plus `dimensions`/`viewport` —\n * repainting a canvas is cheap and idempotent, so this avoids a fragile,\n * easily-stale dependency list.\n */\nexport function Heatmap<T>({ className, style, ...layerProps }: HeatmapProps<T>) {\n const { dimensions, viewport } = usePitchContext();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n renderHeatmapLayersToCanvas(\n { dimensions, viewport, layers: [{ type: \"heatmap\", ...layerProps }] },\n canvas,\n );\n });\n\n return (\n <foreignObject x={0} y={0} width={viewport.width} height={viewport.height}>\n <canvas\n ref={canvasRef}\n data-pitchkit-layer=\"heatmap\"\n className={className}\n style={{ width: \"100%\", height: \"100%\", display: \"block\", ...style }}\n />\n </foreignObject>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { computePolygonCentroid, resolve } from \"@pitchkit/core\";\nimport type { PolygonLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface PolygonProps<T> extends Omit<PolygonLayer<T>, \"type\"> {\n tooltip?: (d: T, i: number) => ReactNode;\n}\n\nconst DEFAULT_FILL = \"var(--pitch-marker-primary, #3b82f6)\";\n// Area marks default to a partial fill so the pitch surface/markings\n// underneath stay visible, unlike Scatter/Comet's opaque default — those\n// are small marks, this can cover a large fraction of the pitch.\nconst DEFAULT_FILL_OPACITY = 0.35;\n\n/** One `<polygon>` per datum, from an arbitrary list of vertices — mplsoccer's `polygon`. */\nexport function Polygon<T>({\n data,\n points,\n fill,\n fillOpacity,\n stroke,\n strokeWidth,\n className,\n tooltip,\n}: PolygonProps<T>) {\n const { transform, setTooltip } = usePitchContext();\n\n return (\n <g data-pitchkit-layer=\"polygon\">\n {data.map((d, i) => {\n const vertices = resolve(points, d, i).map((p) => transform.toPixel(p));\n const [tx, ty] = computePolygonCentroid(vertices);\n // See Scatter.tsx's equivalent comment: the themed default backs\n // off when `className` is set, since an inline style always beats\n // a `className` utility at the same property.\n const fillValue =\n fill !== undefined ? resolve(fill, d, i) : className ? undefined : DEFAULT_FILL;\n const strokeValue = stroke !== undefined ? resolve(stroke, d, i) : undefined;\n const fillOpacityValue =\n fillOpacity !== undefined\n ? resolve(fillOpacity, d, i)\n : className\n ? undefined\n : DEFAULT_FILL_OPACITY;\n const strokeWidthValue = strokeWidth !== undefined ? resolve(strokeWidth, d, i) : undefined;\n\n return (\n <polygon\n key={i}\n points={vertices.map(([px, py]) => `${px},${py}`).join(\" \")}\n data-pitchkit-mark=\"polygon\"\n className={className}\n style={{\n fill: fillValue,\n fillOpacity: fillOpacityValue,\n stroke: strokeValue,\n strokeWidth: strokeWidthValue,\n }}\n onMouseEnter={\n tooltip ? () => setTooltip({ content: tooltip(d, i), x: tx, y: ty }) : undefined\n }\n onMouseLeave={tooltip ? () => setTooltip(null) : undefined}\n />\n );\n })}\n </g>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { computeConvexHull, computePolygonCentroid, resolve } from \"@pitchkit/core\";\nimport type { ConvexHullLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface ConvexHullProps<T> extends Omit<ConvexHullLayer<T>, \"type\"> {\n /** Static — there's exactly one resulting shape for the whole dataset, not one per datum. */\n tooltip?: ReactNode;\n}\n\nconst DEFAULT_FILL = \"var(--pitch-marker-primary, #3b82f6)\";\nconst DEFAULT_FILL_OPACITY = 0.35;\n\n/**\n * One filled `<polygon>` for the convex hull of every datum's `(x, y)` —\n * e.g. a player's touch map. Unlike per-datum marks, `fill`/`stroke`/etc.\n * take plain values rather than `Accessor<T, V>`, since there's only ever\n * one shape produced from the whole `data` array.\n */\nexport function ConvexHull<T>({\n data,\n x,\n y,\n fill,\n fillOpacity,\n stroke,\n strokeWidth,\n className,\n tooltip,\n}: ConvexHullProps<T>) {\n const { transform, setTooltip } = usePitchContext();\n\n const points = data.map((d, i) => transform.toPixel([resolve(x, d, i), resolve(y, d, i)]));\n const hull = computeConvexHull(points);\n const [tx, ty] = computePolygonCentroid(hull);\n\n const fillValue = fill ?? (className ? undefined : DEFAULT_FILL);\n const fillOpacityValue = fillOpacity ?? (className ? undefined : DEFAULT_FILL_OPACITY);\n\n return (\n <g data-pitchkit-layer=\"convex-hull\">\n <polygon\n points={hull.map(([px, py]) => `${px},${py}`).join(\" \")}\n data-pitchkit-mark=\"convex-hull\"\n className={className}\n style={{ fill: fillValue, fillOpacity: fillOpacityValue, stroke, strokeWidth }}\n onMouseEnter={\n tooltip !== undefined ? () => setTooltip({ content: tooltip, x: tx, y: ty }) : undefined\n }\n onMouseLeave={tooltip !== undefined ? () => setTooltip(null) : undefined}\n />\n </g>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { computePitchGeometry, computeVoronoiCells, resolve } from \"@pitchkit/core\";\nimport type { VoronoiLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface VoronoiProps<T> extends Omit<VoronoiLayer<T>, \"type\"> {\n tooltip?: (d: T, i: number) => ReactNode;\n}\n\nconst DEFAULT_FILL = \"var(--pitch-marker-primary, #3b82f6)\";\nconst DEFAULT_FILL_OPACITY = 0.2;\nconst DEFAULT_STROKE = \"var(--pitch-lines, rgba(255, 255, 255, 0.8))\";\n\n/**\n * One filled `<polygon>` cell per datum — Voronoi tessellation over every\n * datum's `(x, y)`, clipped to the pitch outline. Cells are computed in\n * provider coordinates (against `computePitchGeometry(dimensions).outline`)\n * and pixel-transformed afterward, the same order `Heatmap`'s binning uses,\n * so the tessellation itself is independent of orientation/crop.\n */\nexport function Voronoi<T>({\n data,\n x,\n y,\n fill,\n fillOpacity,\n stroke,\n strokeWidth,\n className,\n tooltip,\n}: VoronoiProps<T>) {\n const { dimensions, transform, setTooltip } = usePitchContext();\n\n const sites = data.map((d, i) => [resolve(x, d, i), resolve(y, d, i)] as const);\n const { outline } = computePitchGeometry(dimensions);\n const cells = computeVoronoiCells(sites, outline);\n\n return (\n <g data-pitchkit-layer=\"voronoi\">\n {data.map((d, i) => {\n const cell = (cells[i] ?? []).map((p) => transform.toPixel(p));\n // See Scatter.tsx's equivalent comment: the themed default backs\n // off when `className` is set.\n const fillValue =\n fill !== undefined ? resolve(fill, d, i) : className ? undefined : DEFAULT_FILL;\n const fillOpacityValue =\n fillOpacity !== undefined\n ? resolve(fillOpacity, d, i)\n : className\n ? undefined\n : DEFAULT_FILL_OPACITY;\n const strokeValue =\n stroke !== undefined ? resolve(stroke, d, i) : className ? undefined : DEFAULT_STROKE;\n const strokeWidthValue = strokeWidth !== undefined ? resolve(strokeWidth, d, i) : 1;\n\n return (\n <polygon\n key={i}\n points={cell.map(([px, py]) => `${px},${py}`).join(\" \")}\n data-pitchkit-mark=\"voronoi\"\n className={className}\n style={{\n fill: fillValue,\n fillOpacity: fillOpacityValue,\n stroke: strokeValue,\n strokeWidth: strokeWidthValue,\n }}\n onMouseEnter={\n tooltip\n ? () => {\n const [tx, ty] = transform.toPixel([resolve(x, d, i), resolve(y, d, i)]);\n setTooltip({ content: tooltip(d, i), x: tx, y: ty });\n }\n : undefined\n }\n onMouseLeave={tooltip ? () => setTooltip(null) : undefined}\n />\n );\n })}\n </g>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { computePitchGeometry, computePolygonCentroid, resolve, selectGoal } from \"@pitchkit/core\";\nimport type { GoalAngleLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface GoalAngleProps<T> extends Omit<GoalAngleLayer<T>, \"type\"> {\n tooltip?: (d: T, i: number) => ReactNode;\n}\n\nconst DEFAULT_FILL = \"var(--pitch-marker-goal, #f97316)\";\nconst DEFAULT_FILL_OPACITY = 0.25;\nconst DEFAULT_GOAL: \"left\" | \"right\" | \"nearest\" = \"nearest\";\n\n/**\n * One triangular `<polygon>` wedge per datum, from the point to both\n * goalposts — the angle subtended at that point by the goal mouth\n * (mplsoccer's `goal_angle`). Goalpost coordinates come from\n * `computePitchGeometry(dimensions).goals`, already computed for the pitch\n * markings themselves; picking which of the two goals uses `selectGoal`.\n */\nexport function GoalAngle<T>({\n data,\n x,\n y,\n goal,\n fill,\n fillOpacity,\n stroke,\n strokeWidth,\n className,\n tooltip,\n}: GoalAngleProps<T>) {\n const { dimensions, transform, setTooltip } = usePitchContext();\n const { goals } = computePitchGeometry(dimensions);\n\n return (\n <g data-pitchkit-layer=\"goal-angle\">\n {data.map((d, i) => {\n const point = [resolve(x, d, i), resolve(y, d, i)] as const;\n const goalChoice = resolve(goal ?? DEFAULT_GOAL, d, i);\n const goalLine = selectGoal(point, goals, goalChoice);\n const vertices = [point, goalLine.from, goalLine.to].map((p) => transform.toPixel(p));\n const [tx, ty] = computePolygonCentroid(vertices);\n\n // See Scatter.tsx's equivalent comment: the themed default backs\n // off when `className` is set.\n const fillValue =\n fill !== undefined ? resolve(fill, d, i) : className ? undefined : DEFAULT_FILL;\n const fillOpacityValue =\n fillOpacity !== undefined\n ? resolve(fillOpacity, d, i)\n : className\n ? undefined\n : DEFAULT_FILL_OPACITY;\n const strokeValue = stroke !== undefined ? resolve(stroke, d, i) : undefined;\n const strokeWidthValue = strokeWidth !== undefined ? resolve(strokeWidth, d, i) : undefined;\n\n return (\n <polygon\n key={i}\n points={vertices.map(([px, py]) => `${px},${py}`).join(\" \")}\n data-pitchkit-mark=\"goal-angle\"\n className={className}\n style={{\n fill: fillValue,\n fillOpacity: fillOpacityValue,\n stroke: strokeValue,\n strokeWidth: strokeWidthValue,\n }}\n onMouseEnter={\n tooltip ? () => setTooltip({ content: tooltip(d, i), x: tx, y: ty }) : undefined\n }\n onMouseLeave={tooltip ? () => setTooltip(null) : undefined}\n />\n );\n })}\n </g>\n );\n}\n","import type { ReactNode } from \"react\";\nimport { computeArrowHeadCorners, computeFlowBins, createColorScale, resolve } from \"@pitchkit/core\";\nimport type { FlowBin, FlowLayer } from \"@pitchkit/core\";\nimport { usePitchContext } from \"./context.js\";\n\nexport interface FlowProps<T> extends Omit<FlowLayer<T>, \"type\"> {\n /** Per-*bin* (not per-datum) — the rendered arrows are aggregates, one per occupied grid cell. */\n tooltip?: (bin: FlowBin, i: number) => ReactNode;\n}\n\nconst DEFAULT_BINS_X = 6;\nconst DEFAULT_BINS_Y = 5;\nconst DEFAULT_COLOR_MIN = \"#93c5fd\";\nconst DEFAULT_COLOR_MAX = \"#1d4ed8\";\nconst DEFAULT_STROKE_WIDTH_MIN = 1;\nconst DEFAULT_STROKE_WIDTH_MAX = 4;\nconst DEFAULT_HEAD_SIZE = 6;\n\n/**\n * Bins pass/movement data by start location (`computeFlowBins`) and draws\n * one arrow per occupied bin, from the bin center toward the mean end\n * point, colored and sized by that bin's volume — mplsoccer's `flow`.\n * Unlike every other layer here, the rendered marks are aggregates rather\n * than one-per-datum, so `tooltip` takes a `FlowBin`, not a `T`.\n */\nexport function Flow<T>({\n data,\n x,\n y,\n x2,\n y2,\n binsX = DEFAULT_BINS_X,\n binsY = DEFAULT_BINS_Y,\n colorMin = DEFAULT_COLOR_MIN,\n colorMax = DEFAULT_COLOR_MAX,\n strokeWidthMin = DEFAULT_STROKE_WIDTH_MIN,\n strokeWidthMax = DEFAULT_STROKE_WIDTH_MAX,\n className,\n tooltip,\n}: FlowProps<T>) {\n const { dimensions, transform, setTooltip } = usePitchContext();\n\n const vectors = data.map((d, i) => ({\n x: resolve(x, d, i),\n y: resolve(y, d, i),\n x2: resolve(x2, d, i),\n y2: resolve(y2, d, i),\n }));\n const bins = computeFlowBins(vectors, binsX, binsY, dimensions);\n const counts = bins.map((bin) => bin.count);\n const minCount = counts.length > 0 ? Math.min(...counts) : 0;\n const maxCount = counts.length > 0 ? Math.max(...counts) : 0;\n const colorScale = createColorScale(minCount, maxCount, colorMin, colorMax);\n const countRange = maxCount - minCount || 1;\n\n return (\n <g data-pitchkit-layer=\"flow\">\n {bins.map((bin, i) => {\n const start = transform.toPixel([bin.x, bin.y]);\n const end = transform.toPixel([bin.x2, bin.y2]);\n const t = (bin.count - minCount) / countRange;\n const color = colorScale(bin.count);\n const strokeWidthValue = strokeWidthMin + (strokeWidthMax - strokeWidthMin) * t;\n const [headA, headB] = computeArrowHeadCorners(start, end, DEFAULT_HEAD_SIZE);\n\n return (\n <g\n key={i}\n onMouseEnter={\n tooltip\n ? () => setTooltip({ content: tooltip(bin, i), x: end[0], y: end[1] })\n : undefined\n }\n onMouseLeave={tooltip ? () => setTooltip(null) : undefined}\n >\n <line\n x1={start[0]}\n y1={start[1]}\n x2={end[0]}\n y2={end[1]}\n data-pitchkit-mark=\"flow-shaft\"\n className={className}\n style={{ stroke: color, strokeWidth: strokeWidthValue }}\n />\n <polygon\n points={`${end[0]},${end[1]} ${headA[0]},${headA[1]} ${headB[0]},${headB[1]}`}\n data-pitchkit-mark=\"flow-head\"\n className={className}\n style={{ fill: color }}\n />\n </g>\n );\n })}\n </g>\n );\n}\n","import { usePitchContext } from \"./context.js\";\nimport type { PitchContextValue } from \"./context.js\";\n\n/**\n * Imperative escape hatch: returns the enclosing `<Pitch>`/`<VerticalPitch>`'s\n * dimensions, viewport, and pixel transform. Must be called from a\n * descendant of `<Pitch>` — for advanced cases (custom marks, manual\n * coordinate math) that the built-in layer components don't cover.\n */\nexport function usePitch(): Pick<PitchContextValue, \"dimensions\" | \"viewport\" | \"transform\"> {\n const { dimensions, viewport, transform } = usePitchContext();\n return { dimensions, viewport, transform };\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@pitchkit/react",
3
+ "version": "0.1.0",
4
+ "description": "Thin React bindings for @pitchkit/core: declarative <Pitch> + layer components, responsive by default.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup && node scripts/add-use-client.mjs",
21
+ "dev": "tsup --watch",
22
+ "lint": "eslint .",
23
+ "typecheck": "tsc --noEmit",
24
+ "test": "vitest run --coverage",
25
+ "test:watch": "vitest"
26
+ },
27
+ "dependencies": {
28
+ "@pitchkit/core": "*"
29
+ },
30
+ "peerDependencies": {
31
+ "react": ">=18",
32
+ "react-dom": ">=18"
33
+ },
34
+ "devDependencies": {
35
+ "@testing-library/react": "^16",
36
+ "@types/react": "^19",
37
+ "@types/react-dom": "^19",
38
+ "@vitest/coverage-v8": "^3",
39
+ "happy-dom": "^20.10.6",
40
+ "react": "^19",
41
+ "react-dom": "^19",
42
+ "tsup": "^8",
43
+ "typescript": "^5",
44
+ "vitest": "^3"
45
+ }
46
+ }