@astryxdesign/lab 0.1.4-canary.37c19d3 → 0.1.4-canary.39ffd21

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.
Files changed (142) hide show
  1. package/dist/ChartV2/Chart.d.ts +32 -0
  2. package/dist/ChartV2/Chart.d.ts.map +1 -0
  3. package/dist/ChartV2/Chart.js +281 -0
  4. package/dist/ChartV2/ChartAxis.d.ts +36 -0
  5. package/dist/ChartV2/ChartAxis.d.ts.map +1 -0
  6. package/dist/ChartV2/ChartAxis.js +161 -0
  7. package/dist/ChartV2/ChartGrid.d.ts +20 -0
  8. package/dist/ChartV2/ChartGrid.d.ts.map +1 -0
  9. package/dist/ChartV2/ChartGrid.js +76 -0
  10. package/dist/ChartV2/ChartLegend.d.ts +14 -0
  11. package/dist/ChartV2/ChartLegend.d.ts.map +1 -0
  12. package/dist/ChartV2/ChartLegend.js +54 -0
  13. package/dist/ChartV2/ChartSwatch.d.ts +36 -0
  14. package/dist/ChartV2/ChartSwatch.d.ts.map +1 -0
  15. package/dist/ChartV2/ChartSwatch.js +82 -0
  16. package/dist/ChartV2/ChartTooltip.d.ts +46 -0
  17. package/dist/ChartV2/ChartTooltip.d.ts.map +1 -0
  18. package/dist/ChartV2/ChartTooltip.js +267 -0
  19. package/dist/ChartV2/ChartV2Context.d.ts +4 -0
  20. package/dist/ChartV2/ChartV2Context.d.ts.map +1 -0
  21. package/dist/ChartV2/ChartV2Context.js +12 -0
  22. package/dist/ChartV2/index.d.ts +13 -0
  23. package/dist/ChartV2/index.d.ts.map +1 -0
  24. package/dist/ChartV2/index.js +10 -0
  25. package/dist/ChartV2/layout.d.ts +25 -0
  26. package/dist/ChartV2/layout.d.ts.map +1 -0
  27. package/dist/ChartV2/layout.js +195 -0
  28. package/dist/ChartV2/legend.d.ts +18 -0
  29. package/dist/ChartV2/legend.d.ts.map +1 -0
  30. package/dist/ChartV2/legend.js +24 -0
  31. package/dist/ChartV2/marks/area.d.ts +19 -0
  32. package/dist/ChartV2/marks/area.d.ts.map +1 -0
  33. package/dist/ChartV2/marks/area.js +109 -0
  34. package/dist/ChartV2/marks/band.d.ts +9 -0
  35. package/dist/ChartV2/marks/band.d.ts.map +1 -0
  36. package/dist/ChartV2/marks/band.js +59 -0
  37. package/dist/ChartV2/marks/bar.d.ts +17 -0
  38. package/dist/ChartV2/marks/bar.d.ts.map +1 -0
  39. package/dist/ChartV2/marks/bar.js +120 -0
  40. package/dist/ChartV2/marks/candlestick.d.ts +15 -0
  41. package/dist/ChartV2/marks/candlestick.d.ts.map +1 -0
  42. package/dist/ChartV2/marks/candlestick.js +83 -0
  43. package/dist/ChartV2/marks/dot.d.ts +15 -0
  44. package/dist/ChartV2/marks/dot.d.ts.map +1 -0
  45. package/dist/ChartV2/marks/dot.js +65 -0
  46. package/dist/ChartV2/marks/dotGL.d.ts +16 -0
  47. package/dist/ChartV2/marks/dotGL.d.ts.map +1 -0
  48. package/dist/ChartV2/marks/dotGL.js +178 -0
  49. package/dist/ChartV2/marks/dotGLInteractive.d.ts +30 -0
  50. package/dist/ChartV2/marks/dotGLInteractive.d.ts.map +1 -0
  51. package/dist/ChartV2/marks/dotGLInteractive.js +464 -0
  52. package/dist/ChartV2/marks/errorBar.d.ts +27 -0
  53. package/dist/ChartV2/marks/errorBar.d.ts.map +1 -0
  54. package/dist/ChartV2/marks/errorBar.js +87 -0
  55. package/dist/ChartV2/marks/heatmapGL.d.ts +23 -0
  56. package/dist/ChartV2/marks/heatmapGL.d.ts.map +1 -0
  57. package/dist/ChartV2/marks/heatmapGL.js +242 -0
  58. package/dist/ChartV2/marks/index.d.ts +13 -0
  59. package/dist/ChartV2/marks/index.d.ts.map +1 -0
  60. package/dist/ChartV2/marks/index.js +14 -0
  61. package/dist/ChartV2/marks/line.d.ts +18 -0
  62. package/dist/ChartV2/marks/line.d.ts.map +1 -0
  63. package/dist/ChartV2/marks/line.js +76 -0
  64. package/dist/ChartV2/marks/referenceLine.d.ts +35 -0
  65. package/dist/ChartV2/marks/referenceLine.d.ts.map +1 -0
  66. package/dist/ChartV2/marks/referenceLine.js +186 -0
  67. package/dist/ChartV2/marks/streamGL.d.ts +36 -0
  68. package/dist/ChartV2/marks/streamGL.d.ts.map +1 -0
  69. package/dist/ChartV2/marks/streamGL.js +204 -0
  70. package/dist/ChartV2/tooltip.d.ts +38 -0
  71. package/dist/ChartV2/tooltip.d.ts.map +1 -0
  72. package/dist/ChartV2/tooltip.js +54 -0
  73. package/dist/ChartV2/types.d.ts +115 -0
  74. package/dist/ChartV2/types.d.ts.map +1 -0
  75. package/dist/ChartV2/types.js +35 -0
  76. package/dist/CodeEditor/CodeEditor.d.ts +1 -4
  77. package/dist/CodeEditor/CodeEditor.d.ts.map +1 -1
  78. package/dist/CodeEditor/CodeEditor.js +0 -3
  79. package/dist/Sankey/SankeyChart.d.ts.map +1 -1
  80. package/dist/Sankey/SankeyChart.js +0 -3
  81. package/dist/Schedule/ListView.d.ts.map +1 -1
  82. package/dist/Schedule/ListView.js +4 -7
  83. package/dist/Schedule/MonthlyView.js +2 -3
  84. package/dist/Schedule/Schedule.d.ts +1 -3
  85. package/dist/Schedule/Schedule.d.ts.map +1 -1
  86. package/dist/Schedule/Schedule.js +4 -9
  87. package/dist/Schedule/TimeGridView.js +2 -3
  88. package/dist/Schedule/context.d.ts +0 -2
  89. package/dist/Schedule/context.d.ts.map +1 -1
  90. package/dist/index.d.ts +1 -1
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js +2 -5
  93. package/dist/lab.css +15 -6
  94. package/package.json +2 -2
  95. package/src/ChartV2/Chart.tsx +348 -0
  96. package/src/ChartV2/ChartAxis.tsx +209 -0
  97. package/src/ChartV2/ChartGrid.tsx +99 -0
  98. package/src/ChartV2/ChartLegend.tsx +69 -0
  99. package/src/ChartV2/ChartSwatch.doc.mjs +17 -0
  100. package/src/ChartV2/ChartSwatch.tsx +86 -0
  101. package/src/ChartV2/ChartTooltip.tsx +382 -0
  102. package/src/ChartV2/ChartV2.doc.mjs +16 -0
  103. package/src/ChartV2/ChartV2Context.ts +15 -0
  104. package/src/ChartV2/index.ts +62 -0
  105. package/src/ChartV2/layout.ts +223 -0
  106. package/src/ChartV2/legend.ts +32 -0
  107. package/src/ChartV2/marks/area.tsx +122 -0
  108. package/src/ChartV2/marks/band.tsx +70 -0
  109. package/src/ChartV2/marks/bar.tsx +159 -0
  110. package/src/ChartV2/marks/candlestick.tsx +106 -0
  111. package/src/ChartV2/marks/dot.tsx +64 -0
  112. package/src/ChartV2/marks/dotGL.tsx +202 -0
  113. package/src/ChartV2/marks/dotGLInteractive.tsx +546 -0
  114. package/src/ChartV2/marks/errorBar.tsx +89 -0
  115. package/src/ChartV2/marks/heatmapGL.tsx +299 -0
  116. package/src/ChartV2/marks/index.ts +14 -0
  117. package/src/ChartV2/marks/line.tsx +94 -0
  118. package/src/ChartV2/marks/referenceLine.tsx +224 -0
  119. package/src/ChartV2/marks/streamGL.tsx +251 -0
  120. package/src/ChartV2/tooltip.ts +70 -0
  121. package/src/ChartV2/types.ts +129 -0
  122. package/src/CodeEditor/CodeEditor.tsx +0 -5
  123. package/src/Sankey/SankeyChart.tsx +0 -3
  124. package/src/Schedule/ListView.tsx +2 -5
  125. package/src/Schedule/MonthlyView.tsx +2 -2
  126. package/src/Schedule/Schedule.test.tsx +0 -39
  127. package/src/Schedule/Schedule.tsx +0 -8
  128. package/src/Schedule/TimeGridView.tsx +2 -2
  129. package/src/Schedule/context.tsx +0 -2
  130. package/src/index.ts +46 -5
  131. package/dist/InfoTip/InfoTip.d.ts +0 -58
  132. package/dist/InfoTip/InfoTip.d.ts.map +0 -1
  133. package/dist/InfoTip/InfoTip.js +0 -91
  134. package/dist/InfoTip/index.d.ts +0 -6
  135. package/dist/InfoTip/index.d.ts.map +0 -1
  136. package/dist/InfoTip/index.js +0 -8
  137. package/src/CodeEditor/CodeEditor.test.tsx +0 -21
  138. package/src/InfoTip/InfoTip.doc.mjs +0 -97
  139. package/src/InfoTip/InfoTip.test.tsx +0 -169
  140. package/src/InfoTip/InfoTip.tsx +0 -155
  141. package/src/InfoTip/index.ts +0 -10
  142. package/src/Sankey/SankeyChart.test.tsx +0 -77
@@ -0,0 +1,251 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file marks/streamGL.tsx
5
+ * @output WebGL streaming time-series line — ring buffer, canvas outside SVG
6
+ *
7
+ * Data is pushed imperatively via the returned handle, not from the static dataset.
8
+ * The chart's xScale/yScale map pushed values to pixel coordinates.
9
+ */
10
+
11
+ import {
12
+ useRef,
13
+ useEffect,
14
+ useImperativeHandle,
15
+ useCallback,
16
+ type MutableRefObject,
17
+ } from 'react';
18
+ import type {SeriesDef} from '../types';
19
+ import {useChartV2} from '../ChartV2Context';
20
+ import {
21
+ hexToGL,
22
+ getWebGLContext,
23
+ setupGLState,
24
+ sizeCanvas,
25
+ mountCanvasOverSVG,
26
+ createProgram,
27
+ } from '../../Chart/webgl';
28
+
29
+ export interface StreamGLHandle {
30
+ push(x: number, y: number): void;
31
+ clear(): void;
32
+ }
33
+
34
+ export interface StreamGLOptions {
35
+ color: string;
36
+ bufferSize?: number;
37
+ lineWidth?: number;
38
+ opacity?: number;
39
+ /** Ref to receive the push/clear handle */
40
+ handleRef?: MutableRefObject<StreamGLHandle | null>;
41
+ }
42
+
43
+ const VERT = `
44
+ attribute vec2 a_position;
45
+ uniform vec2 u_resolution;
46
+ void main() {
47
+ vec2 clip = (a_position / u_resolution) * 2.0 - 1.0;
48
+ gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);
49
+ }
50
+ `;
51
+
52
+ const FRAG = `
53
+ precision mediump float;
54
+ uniform vec3 u_color;
55
+ uniform float u_opacity;
56
+ void main() {
57
+ float a = u_opacity;
58
+ gl_FragColor = vec4(u_color * a, a);
59
+ }
60
+ `;
61
+
62
+ /**
63
+ * Inline component — manages the ring buffer, canvas, and rAF draw loop.
64
+ */
65
+ function StreamGLCanvas({
66
+ color,
67
+ bufferSize,
68
+ lineWidth,
69
+ opacity,
70
+ width,
71
+ height,
72
+ handleRef,
73
+ }: {
74
+ color: string;
75
+ bufferSize: number;
76
+ lineWidth: number;
77
+ opacity: number;
78
+ width: number;
79
+ height: number;
80
+ handleRef?: MutableRefObject<StreamGLHandle | null>;
81
+ }) {
82
+ const {xScale, yScale} = useChartV2();
83
+ const canvasRef = useRef<HTMLCanvasElement | null>(null);
84
+ const glRef = useRef<WebGLRenderingContext | null>(null);
85
+ const programRef = useRef<WebGLProgram | null>(null);
86
+ const bufRef = useRef<WebGLBuffer | null>(null);
87
+ const markerRef = useRef<SVGGElement>(null);
88
+
89
+ const ring = useRef({
90
+ data: new Float32Array(bufferSize * 2),
91
+ head: 0,
92
+ count: 0,
93
+ });
94
+
95
+ // Mount canvas outside SVG
96
+ useEffect(() => {
97
+ const marker = markerRef.current;
98
+ if (!marker) {
99
+ return;
100
+ }
101
+ if (!canvasRef.current) {
102
+ canvasRef.current = document.createElement('canvas');
103
+ }
104
+ return mountCanvasOverSVG(marker, canvasRef.current, width, height);
105
+ }, [width, height]);
106
+
107
+ // Size canvas
108
+ useEffect(() => {
109
+ const canvas = canvasRef.current;
110
+ if (!canvas || width <= 0 || height <= 0) {
111
+ return;
112
+ }
113
+ sizeCanvas(canvas, width, height);
114
+ }, [width, height]);
115
+
116
+ const draw = useCallback(() => {
117
+ const canvas = canvasRef.current;
118
+ if (!canvas) {
119
+ return;
120
+ }
121
+ if (!glRef.current) {
122
+ glRef.current = getWebGLContext(canvas);
123
+ }
124
+ const gl = glRef.current;
125
+ if (!gl) {
126
+ return;
127
+ }
128
+
129
+ if (!programRef.current) {
130
+ programRef.current = createProgram(gl, VERT, FRAG);
131
+ }
132
+ const program = programRef.current;
133
+ if (!program) {
134
+ return;
135
+ }
136
+
137
+ if (!bufRef.current) {
138
+ bufRef.current = gl.createBuffer();
139
+ }
140
+
141
+ const {data: ringData, head, count} = ring.current;
142
+ if (count < 2) {
143
+ return;
144
+ }
145
+
146
+ const linearX = xScale as (v: number) => number;
147
+ const drawBuf = new Float32Array(count * 2);
148
+ for (let i = 0; i < count; i++) {
149
+ const idx = ((head - count + i + bufferSize) % bufferSize) * 2;
150
+ drawBuf[i * 2] = linearX(ringData[idx]);
151
+ drawBuf[i * 2 + 1] = yScale(ringData[idx + 1]);
152
+ }
153
+
154
+ gl.viewport(0, 0, canvas.width, canvas.height);
155
+ setupGLState(gl);
156
+ gl.useProgram(program);
157
+
158
+ gl.bindBuffer(gl.ARRAY_BUFFER, bufRef.current);
159
+ gl.bufferData(gl.ARRAY_BUFFER, drawBuf, gl.DYNAMIC_DRAW);
160
+
161
+ const aPos = gl.getAttribLocation(program, 'a_position');
162
+ gl.enableVertexAttribArray(aPos);
163
+ gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
164
+
165
+ const [r, g, b] = hexToGL(color);
166
+ gl.uniform2f(gl.getUniformLocation(program, 'u_resolution'), width, height);
167
+ gl.uniform3f(gl.getUniformLocation(program, 'u_color'), r, g, b);
168
+ gl.uniform1f(gl.getUniformLocation(program, 'u_opacity'), opacity);
169
+
170
+ gl.lineWidth(lineWidth);
171
+ gl.drawArrays(gl.LINE_STRIP, 0, count);
172
+ }, [width, height, color, lineWidth, opacity, bufferSize, xScale, yScale]);
173
+
174
+ // Expose push/clear handle via ref
175
+ useImperativeHandle(
176
+ handleRef as MutableRefObject<StreamGLHandle | null>,
177
+ () => ({
178
+ push(x: number, y: number) {
179
+ const r = ring.current;
180
+ const idx = r.head * 2;
181
+ r.data[idx] = x;
182
+ r.data[idx + 1] = y;
183
+ r.head = (r.head + 1) % bufferSize;
184
+ r.count = Math.min(r.count + 1, bufferSize);
185
+ draw();
186
+ },
187
+ clear() {
188
+ ring.current.head = 0;
189
+ ring.current.count = 0;
190
+ const gl = glRef.current;
191
+ if (gl) {
192
+ gl.clearColor(0, 0, 0, 0);
193
+ gl.clear(gl.COLOR_BUFFER_BIT);
194
+ }
195
+ },
196
+ }),
197
+ [bufferSize, draw],
198
+ );
199
+
200
+ if (width <= 0 || height <= 0) {
201
+ return null;
202
+ }
203
+ return <g ref={markerRef} />;
204
+ }
205
+
206
+ /**
207
+ * WebGL streaming line. Data is pushed imperatively via handleRef,
208
+ * not from the chart's static dataset. Internally uses a ring buffer.
209
+ *
210
+ * @example
211
+ * ```
212
+ * const streamRef = useRef<StreamGLHandle>(null);
213
+ * // Push data points in a rAF loop or event handler:
214
+ * streamRef.current?.push(Date.now(), value);
215
+ *
216
+ * <Chart series={[streamGL({color: '#10b981', handleRef: streamRef})]} />
217
+ * ```
218
+ */
219
+ export function streamGL(options: StreamGLOptions): SeriesDef {
220
+ const {color} = options;
221
+ const bufferSize = options.bufferSize ?? 500;
222
+ const lineWidth = options.lineWidth ?? 2;
223
+ const opacity = options.opacity ?? 1;
224
+ const handleRef = options.handleRef;
225
+
226
+ return {
227
+ type: 'streamGL',
228
+ key: 'stream',
229
+ dataKeys: [],
230
+ layout: {},
231
+
232
+ // Streaming data is pushed, not in the static dataset
233
+ resolve() {
234
+ return [];
235
+ },
236
+
237
+ render(_resolved, ctx) {
238
+ return (
239
+ <StreamGLCanvas
240
+ color={color}
241
+ bufferSize={bufferSize}
242
+ lineWidth={lineWidth}
243
+ opacity={opacity}
244
+ width={ctx.width}
245
+ height={ctx.height}
246
+ handleRef={handleRef}
247
+ />
248
+ );
249
+ },
250
+ };
251
+ }
@@ -0,0 +1,70 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file tooltip.ts
5
+ * @output Tooltip types + series-value derivation
6
+ * @position Used by Chart to bridge series + hovered datum → tooltip rows.
7
+ * Mirrors the legend.ts split: data shaping lives here, presentation
8
+ * lives in ChartTooltip.tsx.
9
+ */
10
+
11
+ import {isUtilityMarkType, type SeriesDef} from './types';
12
+
13
+ /**
14
+ * One row of tooltip data — represents a single series' value at the
15
+ * hovered x-position. Stable shape so custom `render` functions can rely on it.
16
+ */
17
+ export interface TooltipSeriesValue {
18
+ /** Series key (matches SeriesDef.key) */
19
+ key: string;
20
+ /** Display label — falls back to key when not set on the series */
21
+ label: string;
22
+ /** Series color token */
23
+ color: string;
24
+ /** Mark type — drives swatch variant in the default render */
25
+ type: string;
26
+ /** Raw value at the hovered x for this series */
27
+ value: unknown;
28
+ }
29
+
30
+ /**
31
+ * Build the ordered list of tooltip rows for a given hovered datum.
32
+ * Skips utility marks and any series the layout couldn't resolve.
33
+ *
34
+ * Pure / synchronous — safe to memoize on the caller.
35
+ */
36
+ export function deriveTooltipSeriesValues(
37
+ series: readonly SeriesDef[],
38
+ datum: Record<string, unknown> | undefined,
39
+ resolvedKeys: ReadonlySet<string>,
40
+ ): TooltipSeriesValue[] {
41
+ if (!datum) {
42
+ return [];
43
+ }
44
+ const out: TooltipSeriesValue[] = [];
45
+ for (const s of series) {
46
+ if (isUtilityMarkType(s.type)) {
47
+ continue;
48
+ }
49
+ if (!resolvedKeys.has(s.key)) {
50
+ continue;
51
+ }
52
+ out.push({
53
+ key: s.key,
54
+ label: s.label ?? s.key,
55
+ color: s.color ?? 'var(--color-text-primary)',
56
+ type: s.type,
57
+ value: datum[s.dataKeys[0]],
58
+ });
59
+ }
60
+ return out;
61
+ }
62
+
63
+ /**
64
+ * Whether a series should render a hover dot at the focused index.
65
+ * Bars get a band-highlight rect instead, and utility marks have no
66
+ * data point to highlight.
67
+ */
68
+ export function shouldRenderHoverDot(seriesType: string): boolean {
69
+ return seriesType !== 'bar' && !isUtilityMarkType(seriesType);
70
+ }
@@ -0,0 +1,129 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file types.ts
5
+ * @output Core types for the v2 chart architecture
6
+ * @position Foundation — consumed by layout, renderers, and interactions
7
+ */
8
+
9
+ import type {ReactNode} from 'react';
10
+ import type {ScaleLinear, ScaleBand} from 'd3-scale';
11
+
12
+ export type ChartScale = ScaleLinear<number, number> | ScaleBand<string>;
13
+
14
+ export interface ChartMargin {
15
+ top: number;
16
+ right: number;
17
+ bottom: number;
18
+ left: number;
19
+ }
20
+
21
+ /** Resolved pixel position for a single data point in a series */
22
+ export interface ResolvedPoint {
23
+ /** Pixel x in plot area coordinates */
24
+ px: number;
25
+ /** Pixel y in plot area coordinates (top of mark) */
26
+ py: number;
27
+ /** Pixel y baseline (bottom of mark) — differs from py when stacked */
28
+ py0: number;
29
+ /** Index into the data array */
30
+ dataIndex: number;
31
+ }
32
+
33
+ /** Context passed to resolve() and render() on each series */
34
+ export interface SeriesContext {
35
+ data: Record<string, unknown>[];
36
+ xKey: string;
37
+ xScale: ChartScale;
38
+ yScale: ScaleLinear<number, number>;
39
+ /** Width of the plot area */
40
+ width: number;
41
+ /** Height of the plot area */
42
+ height: number;
43
+ }
44
+
45
+ /**
46
+ * The standardized shape every mark helper returns.
47
+ * Each mark type is self-contained: it knows how to resolve positions
48
+ * and how to render itself. The chart root just iterates and calls.
49
+ */
50
+ export interface SeriesDef {
51
+ /** Mark type identifier */
52
+ readonly type: string;
53
+ /** Unique key for this series (typically the dataKey) */
54
+ readonly key: string;
55
+ /** Data keys this series reads from — used to compute y domain */
56
+ readonly dataKeys: string[];
57
+ /** Whether this series is the topmost in its stack (set during layout) */
58
+ _isTopOfStack?: boolean;
59
+ /** Static color for legend display. Undefined if color is dynamic (accessor function). */
60
+ readonly color?: string;
61
+ /** Human-readable label for legend. Falls back to key if not provided. */
62
+ readonly label?: string;
63
+ /** Layout hints the chart root uses for cross-series coordination */
64
+ readonly layout: {
65
+ /** Stack group — series with same stack accumulate */
66
+ stack?: string;
67
+ /** Bar group — series with same group subdivide bandwidth */
68
+ group?: string;
69
+ /** Whether this series contributes to y-domain zero inclusion */
70
+ includeZero?: boolean;
71
+ };
72
+ /**
73
+ * Resolve pixel positions for each data point.
74
+ * Called by the chart root during the layout pass.
75
+ * Receives pre-computed stack offsets if stacked.
76
+ */
77
+ resolve(
78
+ ctx: SeriesContext,
79
+ stackOffsets?: {y0: number; y1: number}[],
80
+ groupInfo?: {index: number; count: number},
81
+ ): ResolvedPoint[];
82
+ /**
83
+ * Render the mark given resolved positions.
84
+ * Called by the chart root during the render pass.
85
+ * Returns SVG elements (or manages its own canvas for WebGL).
86
+ */
87
+ render(resolved: ResolvedPoint[], ctx: SeriesContext): ReactNode;
88
+ }
89
+
90
+ /** Resolved positions for all series */
91
+ export type ResolvedPositions = Map<string, ResolvedPoint[]>;
92
+
93
+ /** Pointer event normalized to plot-area coordinates */
94
+ export interface ChartPointerEvent {
95
+ x: number;
96
+ y: number;
97
+ nearest: (ResolvedPoint & {seriesKey: string}) | null;
98
+ active: boolean;
99
+ }
100
+
101
+ /** Context provided by Chart to interaction children */
102
+ export interface ChartV2Context {
103
+ width: number;
104
+ height: number;
105
+ margin: ChartMargin;
106
+ data: Record<string, unknown>[];
107
+ xKey: string;
108
+ xScale: ChartScale;
109
+ yScale: ScaleLinear<number, number>;
110
+ resolved: Map<string, ResolvedPoint[]>;
111
+ onPointer: (handler: (e: ChartPointerEvent) => void) => () => void;
112
+ svgRef: React.RefObject<SVGSVGElement | null>;
113
+ }
114
+
115
+ /**
116
+ * Series mark types that are utility / annotation marks rather than primary
117
+ * data. They're skipped from chrome surfaces (legend, tooltip rows) since
118
+ * they don't represent values the user is comparing.
119
+ */
120
+ export const UTILITY_MARK_TYPES: ReadonlySet<string> = new Set([
121
+ 'referenceLine',
122
+ 'errorBar',
123
+ 'band',
124
+ ]);
125
+
126
+ /** True if the series type is a utility / annotation mark. */
127
+ export function isUtilityMarkType(type: string): boolean {
128
+ return UTILITY_MARK_TYPES.has(type);
129
+ }
@@ -131,8 +131,6 @@ export interface CodeEditorProps extends Omit<
131
131
  onChange: (value: string) => void;
132
132
  /** Language for highlighting. @default "plaintext" */
133
133
  language?: string;
134
- /** Label for the code editor — used as the accessible name of the editable region. */
135
- label: string;
136
134
  /** Show line numbers. @default false */
137
135
  hasLineNumbers?: boolean;
138
136
  /** Read-only mode. @default false */
@@ -184,7 +182,6 @@ let editorInstanceCounter = 0;
184
182
  * ```tsx
185
183
  * const [code, setCode] = useState('');
186
184
  * <CodeEditor
187
- * label="Source code"
188
185
  * value={code}
189
186
  * onChange={setCode}
190
187
  * language="typescript"
@@ -202,7 +199,6 @@ export function CodeEditor({
202
199
  maxHeight,
203
200
  size = 'md',
204
201
  tokenizer: customTokenizer,
205
- label,
206
202
  xstyle,
207
203
  className,
208
204
  style,
@@ -451,7 +447,6 @@ export function CodeEditor({
451
447
  contentEditable={isReadOnly ? false : ('plaintext-only' as any)}
452
448
  role="textbox"
453
449
  aria-multiline="true"
454
- aria-label={label}
455
450
  aria-readonly={isReadOnly}
456
451
  spellCheck={false}
457
452
  onInput={handleInput}
@@ -202,9 +202,6 @@ export function SankeyChart({
202
202
  <div ref={containerRef} style={{width: '100%'}}>
203
203
  {ctx && (
204
204
  <div
205
- role={needsScroll ? 'group' : undefined}
206
- aria-label={needsScroll ? 'Sankey chart' : undefined}
207
- tabIndex={needsScroll ? 0 : undefined}
208
205
  style={
209
206
  needsScroll ? {overflowX: 'auto', overflowY: 'hidden'} : undefined
210
207
  }>
@@ -52,7 +52,7 @@ export interface ScheduleListViewOptions {
52
52
  function ScheduleListView(
53
53
  _props: ScheduleViewComponentProps<ScheduleListViewOptions>,
54
54
  ) {
55
- const {events, timezoneID, range, isLoading, headingLevel} = useScheduleContext();
55
+ const {events, timezoneID, range, isLoading} = useScheduleContext();
56
56
  const days = enumerateDates(range.startDate, range.endDate);
57
57
  const currentTime = useCurrentTime();
58
58
  const currentPlainDate = plainDateFromInstant(currentTime, timezoneID);
@@ -97,7 +97,6 @@ function ScheduleListView(
97
97
  day={day}
98
98
  isCurrentDay={isCurrentDay}
99
99
  timezoneID={timezoneID}
100
- headingLevel={headingLevel}
101
100
  />
102
101
  <div {...stylex.props(styles.listEvents)}>
103
102
  {renderListRows({
@@ -118,16 +117,14 @@ function ListDayHeading({
118
117
  day,
119
118
  isCurrentDay,
120
119
  timezoneID,
121
- headingLevel,
122
120
  }: {
123
121
  day: PlainDate;
124
122
  isCurrentDay: boolean;
125
123
  timezoneID: string;
126
- headingLevel: 2 | 3 | 4 | 5 | 6;
127
124
  }) {
128
125
  return (
129
126
  <Heading
130
- level={headingLevel}
127
+ level={4}
131
128
  color="secondary"
132
129
  display="block"
133
130
  aria-label={formatFullDate(day, timezoneID)}
@@ -57,7 +57,7 @@ export interface ScheduleMonthlyViewOptions {
57
57
  function ScheduleMonthlyView(
58
58
  _props: ScheduleViewComponentProps<ScheduleMonthlyViewOptions>,
59
59
  ) {
60
- const {events, categories, date, focusDate, timezoneID, range, isLoading, headingLevel} =
60
+ const {events, categories, date, focusDate, timezoneID, range, isLoading} =
61
61
  useScheduleContext();
62
62
  const rangeDate = date.toPlainDate();
63
63
  const highlightedDate = focusDate.toPlainDate();
@@ -86,7 +86,7 @@ function ScheduleMonthlyView(
86
86
  aria-colindex={index + 1}
87
87
  {...stylex.props(styles.weekdayLabel)}>
88
88
  <Heading
89
- level={headingLevel}
89
+ level={4}
90
90
  color="secondary"
91
91
  display="block"
92
92
  xstyle={styles.weekdayHeading}>
@@ -99,45 +99,6 @@ describe('Schedule', () => {
99
99
  expect(screen.queryByText('Outside range')).not.toBeInTheDocument();
100
100
  });
101
101
 
102
- it('renders monthly weekday headings at the configured headingLevel (default 3)', async () => {
103
- render(
104
- <Schedule
105
- view={createScheduleMonthlyView()}
106
- events={events}
107
- categories={categories}
108
- date={Date.UTC(2026, 4, 13)}
109
- focusDate={Date.UTC(2026, 4, 13)}
110
- timezoneID="UTC"
111
- />,
112
- );
113
-
114
- await waitFor(() => {
115
- expect(screen.getByText('Visible sync')).toBeInTheDocument();
116
- });
117
- expect(
118
- screen.getAllByRole('heading', {level: 3}).length,
119
- ).toBeGreaterThan(0);
120
- });
121
-
122
- it('renders list day headings at the configured headingLevel (default 3)', async () => {
123
- render(
124
- <Schedule
125
- view={createScheduleListView({days: 7})}
126
- events={events}
127
- categories={categories}
128
- date={Date.UTC(2026, 4, 13)}
129
- timezoneID="UTC"
130
- />,
131
- );
132
-
133
- await waitFor(() => {
134
- expect(screen.getByText('Visible sync')).toBeInTheDocument();
135
- });
136
- expect(
137
- screen.getAllByRole('heading', {level: 3}).length,
138
- ).toBeGreaterThan(0);
139
- });
140
-
141
102
  it('loads async events with Instant range boundaries', async () => {
142
103
  const loader = vi.fn(
143
104
  async (_start: Instant, _end: Instant) =>
@@ -56,8 +56,6 @@ export interface ScheduleProps<
56
56
  timezoneID?: string;
57
57
  /** Header/rendering plugins. Defaults to pagination controls. */
58
58
  plugins?: ReadonlyArray<SchedulePlugin>;
59
- /** Heading level for sub-headings (day labels, weekday headers) within the schedule. @default 3 */
60
- headingLevel?: 2 | 3 | 4 | 5 | 6;
61
59
  }
62
60
 
63
61
  interface EventRecord {
@@ -160,7 +158,6 @@ function ScheduleViewContent<Options extends ScheduleViewOptions>({
160
158
  onNextDate,
161
159
  nextDateLabel,
162
160
  plugins,
163
- headingLevel,
164
161
  }: {
165
162
  view: ScheduleView<Options>;
166
163
  eventSource: ScheduleEventSource;
@@ -174,7 +171,6 @@ function ScheduleViewContent<Options extends ScheduleViewOptions>({
174
171
  onNextDate: () => void;
175
172
  nextDateLabel: string;
176
173
  plugins: ReadonlyArray<SchedulePlugin>;
177
- headingLevel: 2 | 3 | 4 | 5 | 6;
178
174
  }) {
179
175
  const Component = view.component;
180
176
  const range = getRange(view, date);
@@ -199,7 +195,6 @@ function ScheduleViewContent<Options extends ScheduleViewOptions>({
199
195
  nextDateLabel,
200
196
  view,
201
197
  plugins,
202
- headingLevel,
203
198
  }}>
204
199
  <Component options={view.options} />
205
200
  </ScheduleContext.Provider>
@@ -215,7 +210,6 @@ export function Schedule({
215
210
  onChangeDate,
216
211
  timezoneID: timezoneIDProp,
217
212
  plugins = defaultSchedulePlugins,
218
- headingLevel = 3,
219
213
  xstyle,
220
214
  className,
221
215
  style,
@@ -291,7 +285,6 @@ export function Schedule({
291
285
  onNextDate={onNextDate}
292
286
  nextDateLabel={nextDateRange.label}
293
287
  plugins={plugins}
294
- headingLevel={headingLevel}
295
288
  />
296
289
  }>
297
290
  <ScheduleViewContent
@@ -307,7 +300,6 @@ export function Schedule({
307
300
  onNextDate={onNextDate}
308
301
  nextDateLabel={nextDateRange.label}
309
302
  plugins={plugins}
310
- headingLevel={headingLevel}
311
303
  />
312
304
  </Suspense>
313
305
  </div>
@@ -65,7 +65,7 @@ export function TimeGridView({
65
65
  maxHour: number;
66
66
  hourHeight: number;
67
67
  }) {
68
- const {categories, headingLevel} = useScheduleContext();
68
+ const {categories} = useScheduleContext();
69
69
  const normalizedMinHour = Math.max(0, Math.min(23, Math.floor(minHour)));
70
70
  const normalizedMaxHour = Math.max(
71
71
  normalizedMinHour + 1,
@@ -114,7 +114,7 @@ export function TimeGridView({
114
114
  index === days.length - 1 && styles.timeGridHeaderCellLast,
115
115
  )}>
116
116
  <Heading
117
- level={headingLevel}
117
+ level={4}
118
118
  color="secondary"
119
119
  display="block"
120
120
  xstyle={styles.timeGridHeaderHeading}>
@@ -34,8 +34,6 @@ export interface ScheduleContextValue {
34
34
  nextDateLabel: string;
35
35
  view: ScheduleViewBase;
36
36
  plugins: ReadonlyArray<SchedulePlugin>;
37
- /** Heading level used for sub-headings within the schedule (day labels, weekday headers). */
38
- headingLevel: 2 | 3 | 4 | 5 | 6;
39
37
  }
40
38
 
41
39
  export const ScheduleContext = createContext<ScheduleContextValue | null>(