layerchart 2.0.0-next.55 → 2.0.0-next.56

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 (54) hide show
  1. package/dist/bench/ComposableLineChart.svelte +1 -1
  2. package/dist/bench/GeoBench.svelte +1 -8
  3. package/dist/components/AnnotationRange.svelte +3 -1
  4. package/dist/components/Arc.svelte +1 -3
  5. package/dist/components/ArcLabel.svelte.test.js +7 -7
  6. package/dist/components/Bar.svelte +4 -2
  7. package/dist/components/BoxPlot.svelte +4 -12
  8. package/dist/components/Cell.svelte +13 -8
  9. package/dist/components/Chart.svelte +69 -26
  10. package/dist/components/ChartChildren.svelte +22 -4
  11. package/dist/components/Circle.svelte +34 -12
  12. package/dist/components/ClipPath.svelte +3 -9
  13. package/dist/components/Ellipse.svelte +27 -6
  14. package/dist/components/GeoLegend.svelte +1 -3
  15. package/dist/components/GeoPoint.svelte +25 -3
  16. package/dist/components/GeoSpline.svelte +1 -4
  17. package/dist/components/GeoTile.svelte +8 -4
  18. package/dist/components/Group.svelte +11 -5
  19. package/dist/components/Highlight.svelte +3 -3
  20. package/dist/components/Image.svelte +42 -30
  21. package/dist/components/Labels.svelte +2 -4
  22. package/dist/components/Line.svelte +7 -6
  23. package/dist/components/LinearGradient.svelte +8 -4
  24. package/dist/components/Link.svelte +0 -1
  25. package/dist/components/Marker.svelte +9 -1
  26. package/dist/components/Path.svelte +43 -23
  27. package/dist/components/Pattern.svelte +101 -5
  28. package/dist/components/Pattern.svelte.d.ts +3 -1
  29. package/dist/components/Pie.svelte +2 -6
  30. package/dist/components/RadialGradient.svelte +8 -4
  31. package/dist/components/Rect.svelte +29 -12
  32. package/dist/components/Spline.svelte +22 -4
  33. package/dist/components/Text.svelte +9 -5
  34. package/dist/components/Trail.svelte +19 -7
  35. package/dist/components/Vector.svelte +37 -14
  36. package/dist/components/Violin.svelte +1 -2
  37. package/dist/components/charts/ArcChart.svelte +8 -5
  38. package/dist/components/charts/AreaChart.svelte +6 -1
  39. package/dist/components/charts/BarChart.svelte +3 -1
  40. package/dist/components/charts/LineChart.svelte +6 -1
  41. package/dist/components/charts/PieChart.svelte +10 -3
  42. package/dist/components/tooltip/Tooltip.svelte +2 -8
  43. package/dist/contexts/chart.d.ts +1 -1
  44. package/dist/contexts/chart.js +3 -1
  45. package/dist/server/TestBarChart.svelte +28 -28
  46. package/dist/server/TestLineChart.svelte +28 -28
  47. package/dist/server/index.js +1 -1
  48. package/dist/states/brush.svelte.js +16 -13
  49. package/dist/states/chart.svelte.test.js +24 -19
  50. package/dist/states/geo.svelte.js +1 -4
  51. package/dist/states/series.svelte.js +1 -1
  52. package/dist/utils/canvas.js +7 -4
  53. package/dist/utils/trail.js +3 -4
  54. package/package.json +1 -1
@@ -95,12 +95,30 @@
95
95
  const ctx = getChartContext();
96
96
  const geo = getGeoContext();
97
97
 
98
- let { data, x, y, seriesKey, defined, curve, stroke, fill, opacity, motion, ...restProps }: SplineProps = $props();
98
+ let {
99
+ data,
100
+ x,
101
+ y,
102
+ seriesKey,
103
+ defined,
104
+ curve,
105
+ stroke,
106
+ fill,
107
+ opacity,
108
+ motion,
109
+ ...restProps
110
+ }: SplineProps = $props();
99
111
 
100
112
  ctx.registerComponent({
101
113
  name: 'Spline',
102
114
  kind: 'mark',
103
- markInfo: () => ({ data, x, y, seriesKey, color: typeof stroke === 'string' ? stroke : undefined }),
115
+ markInfo: () => ({
116
+ data,
117
+ x,
118
+ y,
119
+ seriesKey,
120
+ color: typeof stroke === 'string' ? stroke : undefined,
121
+ }),
104
122
  });
105
123
 
106
124
  function getScaleValue(
@@ -267,8 +285,8 @@
267
285
 
268
286
  const seriesOpacity = $derived(
269
287
  series?.key == null ||
270
- ctx.series.visibleSeries.length <= 1 ||
271
- ctx.series.isHighlighted(series.key, true)
288
+ ctx.series.visibleSeries.length <= 1 ||
289
+ ctx.series.isHighlighted(series.key, true)
272
290
  ? 1
273
291
  : 0.1
274
292
  );
@@ -686,7 +686,14 @@
686
686
  if (segments) {
687
687
  let xOffset = baseX;
688
688
  for (const segment of segments) {
689
- const segStyles = getTextStyles(undefined, undefined, undefined, undefined, undefined, segment.class);
689
+ const segStyles = getTextStyles(
690
+ undefined,
691
+ undefined,
692
+ undefined,
693
+ undefined,
694
+ undefined,
695
+ segment.class
696
+ );
690
697
  const text = String(segment.value);
691
698
  // Set font before rendering and measuring so width is accurate
692
699
  const segComputedStyles = getComputedStyles(ctx.canvas, segStyles);
@@ -838,10 +845,7 @@
838
845
  >
839
846
  {#if segments}
840
847
  {#each segments as segment, index (index)}
841
- <tspan
842
- dy={index === 0 ? startDy : 0}
843
- class={['lc-text-tspan', segment.class]}
844
- >
848
+ <tspan dy={index === 0 ? startDy : 0} class={['lc-text-tspan', segment.class]}>
845
849
  {segment.value}
846
850
  </tspan>
847
851
  {/each}
@@ -180,9 +180,15 @@
180
180
  .map((d: any) => ({
181
181
  x: getScaleValue(d, ctx.xScale, xAccessor) + xOffset,
182
182
  y: getScaleValue(d, ctx.yScale, yAccessor) + yOffset,
183
- r: resolvedR != null
184
- ? resolveDataProp(resolvedR, d, ctx.rScale, typeof resolvedR === 'number' ? resolvedR : 4)
185
- : 4,
183
+ r:
184
+ resolvedR != null
185
+ ? resolveDataProp(
186
+ resolvedR,
187
+ d,
188
+ ctx.rScale,
189
+ typeof resolvedR === 'number' ? resolvedR : 4
190
+ )
191
+ : 4,
186
192
  }));
187
193
 
188
194
  return computeTrailPath(points, { curve, cap, tension, resolution });
@@ -206,9 +212,15 @@
206
212
  .map((d: any) => ({
207
213
  x: getScaleValue(d, ctx.xScale, xAccessor) + xOffset,
208
214
  y: baseline,
209
- r: resolvedR != null
210
- ? resolveDataProp(resolvedR, d, ctx.rScale, typeof resolvedR === 'number' ? resolvedR : 4)
211
- : 4,
215
+ r:
216
+ resolvedR != null
217
+ ? resolveDataProp(
218
+ resolvedR,
219
+ d,
220
+ ctx.rScale,
221
+ typeof resolvedR === 'number' ? resolvedR : 4
222
+ )
223
+ : 4,
212
224
  }));
213
225
 
214
226
  return computeTrailPath(points, { curve, cap, tension, resolution });
@@ -236,7 +248,7 @@
236
248
  <Path
237
249
  pathData={isTweened ? tweenState.current : trailPath}
238
250
  {fill}
239
- fillOpacity={fillOpacity}
251
+ {fillOpacity}
240
252
  {opacity}
241
253
  stroke="none"
242
254
  class={cls('lc-trail', className)}
@@ -127,10 +127,22 @@
127
127
  import { getGeoContext } from '../contexts/geo.js';
128
128
  import { getLayerContext } from '../contexts/layer.js';
129
129
  import { createMotion, createDataMotionMap, type MotionProp } from '../utils/motion.svelte.js';
130
- import { hasAnyDataProp, resolveDataProp, extractRawDataValue, resolveGeoDataPair, resolveStyleProp, resolveColorProp } from '../utils/dataProp.js';
130
+ import {
131
+ hasAnyDataProp,
132
+ resolveDataProp,
133
+ extractRawDataValue,
134
+ resolveGeoDataPair,
135
+ resolveStyleProp,
136
+ resolveColorProp,
137
+ } from '../utils/dataProp.js';
131
138
  import { chartDataArray } from '../utils/common.js';
132
139
  import { cls } from '@layerstack/tailwind';
133
- import { vectorArrowPath, vectorArrowFilledPath, vectorSpikePath, transformVectorPath } from '../utils/path.js';
140
+ import {
141
+ vectorArrowPath,
142
+ vectorArrowFilledPath,
143
+ vectorSpikePath,
144
+ transformVectorPath,
145
+ } from '../utils/path.js';
134
146
  import Path from './Path.svelte';
135
147
 
136
148
  let {
@@ -169,11 +181,11 @@
169
181
  // Per-item style mode: when any style prop is a function, we must render individual paths
170
182
  const hasPerItemStyles = $derived(
171
183
  typeof fill === 'function' ||
172
- typeof stroke === 'function' ||
173
- typeof fillOpacity === 'function' ||
174
- typeof strokeWidth === 'function' ||
175
- typeof opacity === 'function' ||
176
- typeof className === 'function'
184
+ typeof stroke === 'function' ||
185
+ typeof fillOpacity === 'function' ||
186
+ typeof strokeWidth === 'function' ||
187
+ typeof opacity === 'function' ||
188
+ typeof className === 'function'
177
189
  );
178
190
 
179
191
  // Contexts
@@ -182,9 +194,7 @@
182
194
  const layerCtx = getLayerContext();
183
195
 
184
196
  // Data to iterate over in data mode
185
- const resolvedData: any[] = $derived(
186
- dataMode ? (dataProp ?? chartDataArray(chartCtx.data)) : []
187
- );
197
+ const resolvedData: any[] = $derived(dataMode ? (dataProp ?? chartDataArray(chartCtx.data)) : []);
188
198
 
189
199
  // Resolve a single data item to pixel coordinates and values
190
200
  function resolveVector(d: any) {
@@ -200,8 +210,14 @@
200
210
  return {
201
211
  x: resolvedX,
202
212
  y: resolvedY,
203
- length: resolveDataProp(lengthProp, d, chartCtx.rScale, typeof lengthProp === 'number' ? lengthProp : 12),
204
- rotate: typeof rotateProp === 'number' ? rotateProp : (extractRawDataValue(rotateProp, d) ?? 0),
213
+ length: resolveDataProp(
214
+ lengthProp,
215
+ d,
216
+ chartCtx.rScale,
217
+ typeof lengthProp === 'number' ? lengthProp : 12
218
+ ),
219
+ rotate:
220
+ typeof rotateProp === 'number' ? rotateProp : (extractRawDataValue(rotateProp, d) ?? 0),
205
221
  };
206
222
  }
207
223
 
@@ -289,7 +305,11 @@
289
305
 
290
306
  const motionX = createMotion(initialX, () => (typeof x === 'number' ? x : 0), motion);
291
307
  const motionY = createMotion(initialY, () => (typeof y === 'number' ? y : 0), motion);
292
- const motionLength = createMotion(initialLength, () => (typeof lengthProp === 'number' ? lengthProp : 12), motion);
308
+ const motionLength = createMotion(
309
+ initialLength,
310
+ () => (typeof lengthProp === 'number' ? lengthProp : 12),
311
+ motion
312
+ );
293
313
 
294
314
  const pixelRotate = $derived(typeof rotateProp === 'number' ? rotateProp : 0);
295
315
 
@@ -346,7 +366,10 @@
346
366
  stroke={stroke as string}
347
367
  strokeWidth={strokeWidth as number}
348
368
  opacity={opacity as number}
349
- class="lc-vector {isFilled ? 'lc-vector-filled' : 'lc-vector-stroked'} {typeof className === 'string' ? className : ''}"
369
+ class="lc-vector {isFilled ? 'lc-vector-filled' : 'lc-vector-stroked'} {typeof className ===
370
+ 'string'
371
+ ? className
372
+ : ''}"
350
373
  />
351
374
  {/if}
352
375
 
@@ -148,8 +148,7 @@
148
148
  const ext: [number, number] = [sorted[0], sorted[sorted.length - 1]];
149
149
 
150
150
  // Silverman's rule of thumb for bandwidth
151
- const bw =
152
- bandwidthProp ?? 1.06 * (deviation(sorted) ?? 1) * Math.pow(sorted.length, -1 / 5);
151
+ const bw = bandwidthProp ?? 1.06 * (deviation(sorted) ?? 1) * Math.pow(sorted.length, -1 / 5);
153
152
 
154
153
  const kernelFn = epanechnikov(bw);
155
154
 
@@ -240,9 +240,7 @@
240
240
  );
241
241
 
242
242
  // Compute series colors locally to avoid derived_references_self cycle through context.series.allSeriesColors
243
- const allSeriesColors = $derived(
244
- series.map((s) => s.color).filter((c) => c != null) as string[]
245
- );
243
+ const allSeriesColors = $derived(series.map((s) => s.color).filter((c) => c != null) as string[]);
246
244
 
247
245
  // Custom tickFormat for ArcChart legends - uses data labels instead of series labels
248
246
  const legendTickFormat = (tick: any) => {
@@ -416,8 +414,13 @@
416
414
  value={valueAccessor(data)}
417
415
  color={snippetProps.context.cScale?.(snippetProps.context.c(data))}
418
416
  {format}
419
- onpointerenter={() => { if (snippetProps.context) snippetProps.context.series.highlightKey = keyAccessor(data); }}
420
- onpointerleave={() => { if (snippetProps.context) snippetProps.context.series.highlightKey = null; }}
417
+ onpointerenter={() => {
418
+ if (snippetProps.context)
419
+ snippetProps.context.series.highlightKey = keyAccessor(data);
420
+ }}
421
+ onpointerleave={() => {
422
+ if (snippetProps.context) snippetProps.context.series.highlightKey = null;
423
+ }}
421
424
  {...props.tooltip?.item}
422
425
  />
423
426
  </Tooltip.List>
@@ -108,7 +108,12 @@
108
108
  ...(typeof tooltipContext === 'object' ? tooltipContext : null),
109
109
  }}
110
110
  brush={brush
111
- ? { axis: 'x', zoomOnBrush: true, ...(typeof brush === 'object' ? brush : null), ...props.brush }
111
+ ? {
112
+ axis: 'x',
113
+ zoomOnBrush: true,
114
+ ...(typeof brush === 'object' ? brush : null),
115
+ ...props.brush,
116
+ }
112
117
  : false}
113
118
  {series}
114
119
  {seriesLayout}
@@ -184,7 +184,9 @@
184
184
  x1={valueAxis === 'y' && isGroupSeries ? (d) => s.value ?? s.key : undefined}
185
185
  y1={valueAxis === 'x' && isGroupSeries ? (d) => s.value ?? s.key : undefined}
186
186
  rounded={context.series.divergingEdgeKeys
187
- ? context.series.divergingEdgeKeys.has(s.key) ? 'edge' : 'none'
187
+ ? context.series.divergingEdgeKeys.has(s.key)
188
+ ? 'edge'
189
+ : 'none'
188
190
  : context.series.isStacked && i !== context.series.visibleSeries.length - 1
189
191
  ? 'none'
190
192
  : Array.isArray(xProp) || Array.isArray(yProp)
@@ -133,7 +133,12 @@
133
133
  ...(typeof tooltipContext === 'object' ? tooltipContext : null),
134
134
  }}
135
135
  brush={brush
136
- ? { axis: 'x', zoomOnBrush: true, ...(typeof brush === 'object' ? brush : null), ...props.brush }
136
+ ? {
137
+ axis: 'x',
138
+ zoomOnBrush: true,
139
+ ...(typeof brush === 'object' ? brush : null),
140
+ ...props.brush,
141
+ }
137
142
  : false}
138
143
  {series}
139
144
  highlight={highlightWithPointClick as any}
@@ -308,7 +308,9 @@
308
308
  startAngle: arc.startAngle,
309
309
  endAngle: arc.endAngle,
310
310
  outerRadius:
311
- (context?.series.visibleSeries.length ?? 0) > 1 ? seriesIndex * (outerRadius ?? 0) : outerRadius,
311
+ (context?.series.visibleSeries.length ?? 0) > 1
312
+ ? seriesIndex * (outerRadius ?? 0)
313
+ : outerRadius,
312
314
  innerRadius,
313
315
  cornerRadius,
314
316
  padAngle,
@@ -464,8 +466,13 @@
464
466
  value={valueAccessor(data)}
465
467
  color={snippetProps.context.cScale?.(snippetProps.context.c(data))}
466
468
  {format}
467
- onpointerenter={() => { if (snippetProps.context) snippetProps.context.series.highlightKey = keyAccessor(data); }}
468
- onpointerleave={() => { if (snippetProps.context) snippetProps.context.series.highlightKey = null; }}
469
+ onpointerenter={() => {
470
+ if (snippetProps.context)
471
+ snippetProps.context.series.highlightKey = keyAccessor(data);
472
+ }}
473
+ onpointerleave={() => {
474
+ if (snippetProps.context) snippetProps.context.series.highlightKey = null;
475
+ }}
469
476
  {...props.tooltip?.item}
470
477
  />
471
478
  </Tooltip.List>
@@ -377,10 +377,7 @@
377
377
  ) {
378
378
  rect.left = alignValue(xValue, 'end', xOffset, tooltipWidth);
379
379
  }
380
- if (
381
- (xAlign === 'end' || xAlign === 'center') &&
382
- containerRect.left + rect.left < 0
383
- ) {
380
+ if ((xAlign === 'end' || xAlign === 'center') && containerRect.left + rect.left < 0) {
384
381
  rect.left = alignValue(xValue, 'start', xOffset, tooltipWidth);
385
382
  }
386
383
  }
@@ -393,10 +390,7 @@
393
390
  ) {
394
391
  rect.top = alignValue(yValue, 'end', yOffset, tooltipHeight);
395
392
  }
396
- if (
397
- (yAlign === 'end' || yAlign === 'center') &&
398
- containerRect.top + rect.top < 0
399
- ) {
393
+ if ((yAlign === 'end' || yAlign === 'center') && containerRect.top + rect.top < 0) {
400
394
  rect.top = alignValue(yValue, 'start', yOffset, tooltipHeight);
401
395
  }
402
396
  }
@@ -1,6 +1,6 @@
1
1
  import type { ChartState } from '../states/chart.svelte.js';
2
2
  import type { AnyScale } from '../utils/scales.svelte.js';
3
3
  export type { ChartState };
4
- export type { NodeKind, ComponentNode, RegisterComponentOptions } from '../states/chart.svelte.js';
4
+ export type { NodeKind, ComponentNode, RegisterComponentOptions, } from '../states/chart.svelte.js';
5
5
  export declare function getChartContext<T, XScale extends AnyScale = AnyScale, YScale extends AnyScale = AnyScale>(): ChartState<T, XScale, YScale>;
6
6
  export declare function setChartContext<T, XScale extends AnyScale = AnyScale, YScale extends AnyScale = AnyScale>(context: ChartState<T, XScale, YScale>): ChartState<T, XScale, YScale>;
@@ -5,7 +5,9 @@ const _ChartContext = new Context('ChartContext');
5
5
  * Provides safe defaults to prevent runtime errors.
6
6
  */
7
7
  const fallbackContext = {
8
- registerMark: () => () => { },
8
+ registerMark: () => () => {
9
+ /* no-op */
10
+ },
9
11
  registerComponent: (_options) => ({
10
12
  id: Symbol('noop'),
11
13
  kind: 'mark',
@@ -1,35 +1,35 @@
1
1
  <script lang="ts">
2
- import { scaleBand } from 'd3-scale';
3
- import ServerChart from './ServerChart.svelte';
4
- import type { CaptureTarget } from './captureStore.js';
5
- import Bars from '../components/Bars.svelte';
2
+ import { scaleBand } from 'd3-scale';
3
+ import ServerChart from './ServerChart.svelte';
4
+ import type { CaptureTarget } from './captureStore.js';
5
+ import Bars from '../components/Bars.svelte';
6
6
 
7
- let {
8
- data,
9
- width,
10
- height,
11
- capture,
12
- onCapture
13
- }: {
14
- data: { category: string; value: number }[];
15
- width: number;
16
- height: number;
17
- capture?: CaptureTarget;
18
- onCapture?: (data: CaptureTarget) => void;
19
- } = $props();
7
+ let {
8
+ data,
9
+ width,
10
+ height,
11
+ capture,
12
+ onCapture,
13
+ }: {
14
+ data: { category: string; value: number }[];
15
+ width: number;
16
+ height: number;
17
+ capture?: CaptureTarget;
18
+ onCapture?: (data: CaptureTarget) => void;
19
+ } = $props();
20
20
  </script>
21
21
 
22
22
  <ServerChart
23
- {capture}
24
- {onCapture}
25
- {width}
26
- {height}
27
- {data}
28
- x="category"
29
- xScale={scaleBand().paddingInner(0.2).paddingOuter(0.1)}
30
- y="value"
31
- yDomain={[0, null]}
32
- padding={{ top: 20, right: 20, bottom: 30, left: 40 }}
23
+ {capture}
24
+ {onCapture}
25
+ {width}
26
+ {height}
27
+ {data}
28
+ x="category"
29
+ xScale={scaleBand().paddingInner(0.2).paddingOuter(0.1)}
30
+ y="value"
31
+ yDomain={[0, null]}
32
+ padding={{ top: 20, right: 20, bottom: 30, left: 40 }}
33
33
  >
34
- <Bars fill="rgb(59, 130, 246)" radius={4} />
34
+ <Bars fill="rgb(59, 130, 246)" radius={4} />
35
35
  </ServerChart>
@@ -1,35 +1,35 @@
1
1
  <script lang="ts">
2
- import ServerChart from './ServerChart.svelte';
3
- import type { CaptureTarget } from './captureStore.js';
4
- import Area from '../components/Area.svelte';
5
- import Spline from '../components/Spline.svelte';
2
+ import ServerChart from './ServerChart.svelte';
3
+ import type { CaptureTarget } from './captureStore.js';
4
+ import Area from '../components/Area.svelte';
5
+ import Spline from '../components/Spline.svelte';
6
6
 
7
- let {
8
- data,
9
- width,
10
- height,
11
- capture,
12
- onCapture
13
- }: {
14
- data: { date: number; value: number }[];
15
- width: number;
16
- height: number;
17
- capture?: CaptureTarget;
18
- onCapture?: (data: CaptureTarget) => void;
19
- } = $props();
7
+ let {
8
+ data,
9
+ width,
10
+ height,
11
+ capture,
12
+ onCapture,
13
+ }: {
14
+ data: { date: number; value: number }[];
15
+ width: number;
16
+ height: number;
17
+ capture?: CaptureTarget;
18
+ onCapture?: (data: CaptureTarget) => void;
19
+ } = $props();
20
20
  </script>
21
21
 
22
22
  <ServerChart
23
- {capture}
24
- {onCapture}
25
- {width}
26
- {height}
27
- {data}
28
- x="date"
29
- y="value"
30
- yDomain={[0, null]}
31
- padding={{ top: 20, right: 20, bottom: 20, left: 20 }}
23
+ {capture}
24
+ {onCapture}
25
+ {width}
26
+ {height}
27
+ {data}
28
+ x="date"
29
+ y="value"
30
+ yDomain={[0, null]}
31
+ padding={{ top: 20, right: 20, bottom: 20, left: 20 }}
32
32
  >
33
- <Area fill="rgba(59, 130, 246, 0.15)" stroke="none" />
34
- <Spline stroke="rgb(59, 130, 246)" strokeWidth={2} />
33
+ <Area fill="rgba(59, 130, 246, 0.15)" stroke="none" />
34
+ <Spline stroke="rgb(59, 130, 246)" strokeWidth={2} />
35
35
  </ServerChart>
@@ -64,7 +64,7 @@ export function renderChart(component, options) {
64
64
  const captureTarget = {};
65
65
  // SSR render to build the component tree and capture chart state
66
66
  const rendered = render(component, {
67
- props: { ...props, width, height, capture: captureTarget }
67
+ props: { ...props, width, height, capture: captureTarget },
68
68
  });
69
69
  // Force the SSR render to fully flush
70
70
  void rendered.body;
@@ -6,9 +6,7 @@ import { add } from '../utils/math.js';
6
6
  * For continuous scales, returns the domain unchanged.
7
7
  */
8
8
  export function expandBandBrushDomain(brushDomain, baseDomain) {
9
- if (brushDomain[0] == null ||
10
- brushDomain[1] == null ||
11
- typeof brushDomain[0] !== 'string') {
9
+ if (brushDomain[0] == null || brushDomain[1] == null || typeof brushDomain[0] !== 'string') {
12
10
  return brushDomain;
13
11
  }
14
12
  const startIdx = baseDomain.indexOf(brushDomain[0]);
@@ -109,8 +107,7 @@ export class BrushState {
109
107
  // Determine active state from current values
110
108
  const hasX = this.x[0] != null && this.x[1] != null;
111
109
  const hasY = this.y[0] != null && this.y[1] != null;
112
- this.active =
113
- this.axis === 'x' ? hasX : this.axis === 'y' ? hasY : hasX || hasY;
110
+ this.active = this.axis === 'x' ? hasX : this.axis === 'y' ? hasY : hasX || hasY;
114
111
  }
115
112
  /** Set brush to a new range, clamped to domain bounds */
116
113
  setRange(startValue, currentValue) {
@@ -177,12 +174,16 @@ export class BrushState {
177
174
  const yDomain = this.ctx?.baseYScale.domain() ?? [];
178
175
  const xCat = isCategoricalDomain(xDomain);
179
176
  const yCat = isCategoricalDomain(yDomain);
180
- const clampX = (v) => xCat ? clampByIndex(v, this.xDomainMin, this.xDomainMax, xDomain) : clamp(v, this.xDomainMin, this.xDomainMax);
181
- const clampY = (v) => yCat ? clampByIndex(v, this.yDomainMin, this.yDomainMax, yDomain) : clamp(v, this.yDomainMin, this.yDomainMax);
182
- const ltX = (a, b) => xCat ? xDomain.indexOf(a) < xDomain.indexOf(b) : a < +b;
183
- const gtX = (a, b) => xCat ? xDomain.indexOf(a) > xDomain.indexOf(b) : a > +b;
184
- const ltY = (a, b) => yCat ? yDomain.indexOf(a) < yDomain.indexOf(b) : a < +b;
185
- const gtY = (a, b) => yCat ? yDomain.indexOf(a) > yDomain.indexOf(b) : a > +b;
177
+ const clampX = (v) => xCat
178
+ ? clampByIndex(v, this.xDomainMin, this.xDomainMax, xDomain)
179
+ : clamp(v, this.xDomainMin, this.xDomainMax);
180
+ const clampY = (v) => yCat
181
+ ? clampByIndex(v, this.yDomainMin, this.yDomainMax, yDomain)
182
+ : clamp(v, this.yDomainMin, this.yDomainMax);
183
+ const ltX = (a, b) => (xCat ? xDomain.indexOf(a) < xDomain.indexOf(b) : a < +b);
184
+ const gtX = (a, b) => (xCat ? xDomain.indexOf(a) > xDomain.indexOf(b) : a > +b);
185
+ const ltY = (a, b) => (yCat ? yDomain.indexOf(a) < yDomain.indexOf(b) : a < +b);
186
+ const gtY = (a, b) => (yCat ? yDomain.indexOf(a) > yDomain.indexOf(b) : a > +b);
186
187
  switch (edge) {
187
188
  case 'top':
188
189
  this.y = [
@@ -218,10 +219,12 @@ export class BrushState {
218
219
  const newX = externalX ?? [null, null];
219
220
  const newY = externalY ?? [null, null];
220
221
  // Only write when values actually differ to avoid reactive loops
221
- if (this.x[0]?.valueOf() !== newX[0]?.valueOf() || this.x[1]?.valueOf() !== newX[1]?.valueOf()) {
222
+ if (this.x[0]?.valueOf() !== newX[0]?.valueOf() ||
223
+ this.x[1]?.valueOf() !== newX[1]?.valueOf()) {
222
224
  this.x = newX;
223
225
  }
224
- if (this.y[0]?.valueOf() !== newY[0]?.valueOf() || this.y[1]?.valueOf() !== newY[1]?.valueOf()) {
226
+ if (this.y[0]?.valueOf() !== newY[0]?.valueOf() ||
227
+ this.y[1]?.valueOf() !== newY[1]?.valueOf()) {
225
228
  this.y = newY;
226
229
  }
227
230
  const isXAxisActive = externalX != null &&
@@ -287,17 +287,23 @@ describe('ChartState mark registration', () => {
287
287
  flushSync();
288
288
  expect(state.seriesState.isDefaultSeries).toBe(false);
289
289
  expect(state.seriesState.series).toHaveLength(2);
290
- expect(state.seriesState.series[0]).toMatchObject({ key: 'apples', color: 'red', value: 'apples' });
291
- expect(state.seriesState.series[1]).toMatchObject({ key: 'bananas', color: 'yellow', value: 'bananas' });
290
+ expect(state.seriesState.series[0]).toMatchObject({
291
+ key: 'apples',
292
+ color: 'red',
293
+ value: 'apples',
294
+ });
295
+ expect(state.seriesState.series[1]).toMatchObject({
296
+ key: 'bananas',
297
+ color: 'yellow',
298
+ value: 'bananas',
299
+ });
292
300
  }
293
301
  finally {
294
302
  cleanup();
295
303
  }
296
304
  });
297
305
  it('should not generate implicit series when explicit series are provided', () => {
298
- const data = [
299
- { date: '2024-01', apples: 10, bananas: 15 },
300
- ];
306
+ const data = [{ date: '2024-01', apples: 10, bananas: 15 }];
301
307
  const { state, cleanup } = createChartState({
302
308
  data,
303
309
  x: 'date',
@@ -611,8 +617,16 @@ describe('ChartState geo projection skips markInfo', () => {
611
617
  // seriesKey/color/label should still create implicit series for legends
612
618
  expect(state.seriesState.isDefaultSeries).toBe(false);
613
619
  expect(state.seriesState.series).toHaveLength(2);
614
- expect(state.seriesState.series[0]).toMatchObject({ key: 'earthquakes', color: 'red', label: 'Earthquakes' });
615
- expect(state.seriesState.series[1]).toMatchObject({ key: 'volcanos', color: 'orange', label: 'Volcanos' });
620
+ expect(state.seriesState.series[0]).toMatchObject({
621
+ key: 'earthquakes',
622
+ color: 'red',
623
+ label: 'Earthquakes',
624
+ });
625
+ expect(state.seriesState.series[1]).toMatchObject({
626
+ key: 'volcanos',
627
+ color: 'orange',
628
+ label: 'Volcanos',
629
+ });
616
630
  // But flatData should not include extra mark data
617
631
  expect(state.flatData).toHaveLength(3);
618
632
  }
@@ -861,9 +875,7 @@ describe('ChartState implicit x/y from marks (no x/y on Chart)', () => {
861
875
  }
862
876
  });
863
877
  it('should deduplicate repeated mark x keys into a single accessor', () => {
864
- const data = [
865
- { date: new Date(2024, 0, 1), value: 10 },
866
- ];
878
+ const data = [{ date: new Date(2024, 0, 1), value: 10 }];
867
879
  const { state, cleanup } = createChartState({});
868
880
  try {
869
881
  // Two marks, same x='date' — should not create duplicate keys
@@ -878,9 +890,7 @@ describe('ChartState implicit x/y from marks (no x/y on Chart)', () => {
878
890
  }
879
891
  });
880
892
  it('should use explicit x/y from Chart props over mark-derived values', () => {
881
- const data = [
882
- { date: new Date(2024, 0, 1), value: 10 },
883
- ];
893
+ const data = [{ date: new Date(2024, 0, 1), value: 10 }];
884
894
  const { state, cleanup } = createChartState({
885
895
  x: 'value', // explicit — should override 'date' from marks
886
896
  y: 'value',
@@ -1250,12 +1260,7 @@ describe('ChartState group layout auto-derives x1/y1', () => {
1250
1260
  { year: '2016', apples: 480, bananas: 240, cherries: 120, grapes: 50 },
1251
1261
  { year: '2017', apples: 960, bananas: 480, cherries: 240, grapes: 100 },
1252
1262
  ];
1253
- const series = [
1254
- { key: 'apples' },
1255
- { key: 'bananas' },
1256
- { key: 'cherries' },
1257
- { key: 'grapes' },
1258
- ];
1263
+ const series = [{ key: 'apples' }, { key: 'bananas' }, { key: 'cherries' }, { key: 'grapes' }];
1259
1264
  it('should auto-derive x1Domain from series keys when seriesLayout=group and valueAxis=y', () => {
1260
1265
  const { state, cleanup } = createChartState({
1261
1266
  data: wideData,