layerchart 2.0.0-next.53 → 2.0.0-next.54

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 (48) hide show
  1. package/dist/components/Arc.svelte +8 -7
  2. package/dist/components/Arc.svelte.test.js +1 -1
  3. package/dist/components/ArcLabel.svelte +1 -1
  4. package/dist/components/ClipPath.svelte +1 -1
  5. package/dist/components/GeoClipPath.svelte +75 -0
  6. package/dist/components/GeoClipPath.svelte.d.ts +29 -0
  7. package/dist/components/Hull.svelte +20 -2
  8. package/dist/components/Hull.svelte.d.ts +2 -2
  9. package/dist/components/Pie.svelte +8 -2
  10. package/dist/components/Text.svelte +63 -16
  11. package/dist/components/Text.svelte.d.ts +10 -0
  12. package/dist/components/charts/BarChart.svelte.test.js +1 -1
  13. package/dist/components/charts/DefaultTooltip.svelte.test.js +18 -18
  14. package/dist/components/charts/LineChart.svelte.test.js +1 -1
  15. package/dist/components/charts/PieChart.svelte.test.js +2 -2
  16. package/dist/components/charts/__screenshots__/BarChart.svelte.test.ts/BarChart-series-tooltip-should-use-explicit-series-colors--not-color-scale-1.png +0 -0
  17. package/dist/components/charts/__screenshots__/BarChart.svelte.test.ts/BarChart-series-tooltip-should-use-explicit-series-colors--not-color-scale-2.png +0 -0
  18. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-AreaChart--multi-series--quadtree-x-mode--should-fade-non-highlighted-tooltip-series-items-on-hover-1.png +0 -0
  19. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-AreaChart--multi-series--quadtree-x-mode--should-fade-non-highlighted-tooltip-series-items-on-hover-2.png +0 -0
  20. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-AreaChart--multi-series--quadtree-x-mode--should-show-header-and-all-series-items-1.png +0 -0
  21. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-AreaChart--multi-series--quadtree-x-mode--should-show-header-and-all-series-items-2.png +0 -0
  22. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-AreaChart--multi-series--quadtree-x-mode--should-show-series-colors-in-tooltip-items-1.png +0 -0
  23. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-AreaChart--multi-series--quadtree-x-mode--should-show-series-colors-in-tooltip-items-2.png +0 -0
  24. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-AreaChart--multi-series--quadtree-x-mode--should-show-single-series-without-total-1.png +0 -0
  25. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-AreaChart--multi-series--quadtree-x-mode--should-show-single-series-without-total-2.png +0 -0
  26. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-LineChart--multi-series--quadtree-x-mode--should-show-header-and-all-series-items-1.png +0 -0
  27. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-LineChart--multi-series--quadtree-x-mode--should-show-header-and-all-series-items-2.png +0 -0
  28. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-ScatterChart--single-point--quadtree-mode--should-show-series-header-for-multi-series-1.png +0 -0
  29. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-ScatterChart--single-point--quadtree-mode--should-show-series-header-for-multi-series-2.png +0 -0
  30. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-ScatterChart--single-point--quadtree-mode--should-show-x--y--and-r-items-when-r-is-configured-1.png +0 -0
  31. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-ScatterChart--single-point--quadtree-mode--should-show-x--y--and-r-items-when-r-is-configured-2.png +0 -0
  32. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-ScatterChart--single-point--quadtree-mode--should-show-x-and-y-items-in-tooltip-1.png +0 -0
  33. package/dist/components/charts/__screenshots__/DefaultTooltip.svelte.test.ts/DefaultTooltip-ScatterChart--single-point--quadtree-mode--should-show-x-and-y-items-in-tooltip-2.png +0 -0
  34. package/dist/components/charts/__screenshots__/LineChart.svelte.test.ts/LineChart-tooltip-should-prefer-cScale-color-over-default-series-color-when-cScale-is-explicitly-provided-1.png +0 -0
  35. package/dist/components/charts/__screenshots__/LineChart.svelte.test.ts/LineChart-tooltip-should-prefer-cScale-color-over-default-series-color-when-cScale-is-explicitly-provided-2.png +0 -0
  36. package/dist/components/charts/__screenshots__/PieChart.svelte.test.ts/PieChart-uses-hovered-slice-identity-for-implicit-tooltip-series-1.png +0 -0
  37. package/dist/components/charts/__screenshots__/PieChart.svelte.test.ts/PieChart-uses-hovered-slice-identity-for-implicit-tooltip-series-2.png +0 -0
  38. package/dist/components/index.d.ts +2 -0
  39. package/dist/components/index.js +2 -0
  40. package/dist/components/tooltip/Tooltip.svelte +145 -29
  41. package/dist/components/tooltip/Tooltip.svelte.d.ts +16 -0
  42. package/dist/components/tooltip/Tooltip.svelte.test.d.ts +1 -0
  43. package/dist/components/tooltip/Tooltip.svelte.test.js +294 -0
  44. package/dist/components/tooltip/__screenshots__/Tooltip.svelte.test.ts/Tooltip-portal-should-portal-tooltip-to-a-custom-selector-target-1.png +0 -0
  45. package/dist/components/tooltip/__screenshots__/Tooltip.svelte.test.ts/Tooltip-portal-should-portal-tooltip-to-a-custom-selector-target-2.png +0 -0
  46. package/dist/components/tooltip/__screenshots__/Tooltip.svelte.test.ts/Tooltip-portal-should-render-tooltip-inline-when-portal-is-false-1.png +0 -0
  47. package/dist/components/tooltip/__screenshots__/Tooltip.svelte.test.ts/Tooltip-portal-should-render-tooltip-inline-when-portal-is-false-2.png +0 -0
  48. package/package.json +13 -13
@@ -254,7 +254,10 @@
254
254
  const ctx = getChartContext();
255
255
 
256
256
  const endAngle = $derived(
257
- endAngleProp ?? degreesToRadians(ctx.xRange ? max(ctx.xRange) : max(range))
257
+ endAngleProp ??
258
+ degreesToRadians(
259
+ (ctx.config.xRange ? max(ctx.config.xRange as number[]) : max(range))!
260
+ )
258
261
  );
259
262
 
260
263
  const motionEndAngle = createMotion(initialValue, () => value, motion);
@@ -279,13 +282,11 @@
279
282
  }
280
283
  }
281
284
 
282
- const outerRadius = $derived(
283
- getOuterRadius(outerRadiusProp, (Math.min(ctx.xRange[1], ctx.yRange[0]) ?? 0) / 2)
284
- );
285
+ const chartRadius = $derived((Math.min(ctx.width, ctx.height) ?? 0) / 2);
286
+
287
+ const outerRadius = $derived(getOuterRadius(outerRadiusProp, chartRadius));
285
288
  const trackOuterRadius = $derived(
286
- trackOuterRadiusProp
287
- ? getOuterRadius(trackOuterRadiusProp, (Math.min(ctx.xRange[1], ctx.yRange[0]) ?? 0) / 2)
288
- : outerRadius
289
+ trackOuterRadiusProp ? getOuterRadius(trackOuterRadiusProp, chartRadius) : outerRadius
289
290
  );
290
291
 
291
292
  function getInnerRadius(innerRadius: number | undefined, outerRadius: number) {
@@ -383,7 +383,7 @@ describe(`Arc`, () => {
383
383
  const el = page.getByTestId(componentTestId);
384
384
  await expect.element(el).toBeInTheDocument();
385
385
  const transform = el.element()?.getAttribute('transform');
386
- expect(transform).toContain('translate(-4.539904997395462, 8.91006524188368)');
386
+ expect(transform).toContain('translate(1.2246467991473533e-15, 10)');
387
387
  });
388
388
  it('should apply zero offset by default', async () => {
389
389
  render(TestHarness, {
@@ -222,7 +222,7 @@
222
222
  y: offsetCentroid[1],
223
223
  textAnchor: 'middle' as const,
224
224
  verticalAnchor: 'middle' as const,
225
- transform: `rotate(${centroidRotation}, ${offsetCentroid[0]}, ${offsetCentroid[1]})`,
225
+ rotate: centroidRotation,
226
226
  };
227
227
  }
228
228
  return getArcTextProps?.('centroid', { startOffset, outerPadding }) ?? {};
@@ -84,7 +84,7 @@
84
84
  ctx.clip();
85
85
  }
86
86
  },
87
- deps: () => canvasClipDeps?.() ?? [],
87
+ deps: () => [disabled, ...(canvasClipDeps?.() ?? [])],
88
88
  },
89
89
  });
90
90
  }
@@ -0,0 +1,75 @@
1
+ <script lang="ts" module>
2
+ import type { GeoPermissibleObjects } from 'd3-geo';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ import type { ClipPathPropsWithoutHTML } from './ClipPath.svelte';
6
+ import type { GeoPathPropsWithoutHTML } from './GeoPath.svelte';
7
+ import type { Without } from '../utils/types.js';
8
+
9
+ export type BaseGeoClipPathPropsWithoutHTML = {
10
+ /**
11
+ * A unique id for the clipPath.
12
+ */
13
+ id?: string;
14
+
15
+ /**
16
+ * GeoJSON data defining the clip boundary.
17
+ */
18
+ geojson: GeoPermissibleObjects;
19
+
20
+ /**
21
+ * Whether to disable clipping (show all).
22
+ *
23
+ * @default false
24
+ */
25
+ disabled?: boolean;
26
+
27
+ /**
28
+ * The children snippet to render content inside the clipPath.
29
+ */
30
+ children?: ClipPathPropsWithoutHTML['children'];
31
+ };
32
+
33
+ export type GeoClipPathPropsWithoutHTML = BaseGeoClipPathPropsWithoutHTML &
34
+ Without<GeoPathPropsWithoutHTML, BaseGeoClipPathPropsWithoutHTML>;
35
+
36
+ export type GeoClipPathProps = GeoClipPathPropsWithoutHTML;
37
+ </script>
38
+
39
+ <script lang="ts">
40
+ import { geoPath as d3GeoPath } from 'd3-geo';
41
+
42
+ import ClipPath from './ClipPath.svelte';
43
+ import GeoPath from './GeoPath.svelte';
44
+ import { createId } from '../utils/createId.js';
45
+ import { extractLayerProps } from '../utils/attributes.js';
46
+ import { getGeoContext } from '../contexts/geo.js';
47
+
48
+ const uid = $props.id();
49
+
50
+ let {
51
+ id = createId('clipPath-', uid),
52
+ geojson,
53
+ disabled = false,
54
+ children,
55
+ ...restProps
56
+ }: GeoClipPathProps = $props();
57
+
58
+ const geo = getGeoContext();
59
+
60
+ function canvasClip(ctx: CanvasRenderingContext2D) {
61
+ if (!geo.projection || !geojson) return;
62
+ const pathGen = d3GeoPath(geo.projection, ctx);
63
+ pathGen(geojson);
64
+ }
65
+
66
+ function canvasClipDeps() {
67
+ return [geojson, geo.projection];
68
+ }
69
+ </script>
70
+
71
+ <ClipPath {id} {disabled} {children} {canvasClip} {canvasClipDeps}>
72
+ {#snippet clip()}
73
+ <GeoPath {geojson} class="stroke-none" {...extractLayerProps(restProps, 'lc-clip-path-geo')} />
74
+ {/snippet}
75
+ </ClipPath>
@@ -0,0 +1,29 @@
1
+ import type { GeoPermissibleObjects } from 'd3-geo';
2
+ import type { ClipPathPropsWithoutHTML } from './ClipPath.svelte';
3
+ import type { GeoPathPropsWithoutHTML } from './GeoPath.svelte';
4
+ import type { Without } from '../utils/types.js';
5
+ export type BaseGeoClipPathPropsWithoutHTML = {
6
+ /**
7
+ * A unique id for the clipPath.
8
+ */
9
+ id?: string;
10
+ /**
11
+ * GeoJSON data defining the clip boundary.
12
+ */
13
+ geojson: GeoPermissibleObjects;
14
+ /**
15
+ * Whether to disable clipping (show all).
16
+ *
17
+ * @default false
18
+ */
19
+ disabled?: boolean;
20
+ /**
21
+ * The children snippet to render content inside the clipPath.
22
+ */
23
+ children?: ClipPathPropsWithoutHTML['children'];
24
+ };
25
+ export type GeoClipPathPropsWithoutHTML = BaseGeoClipPathPropsWithoutHTML & Without<GeoPathPropsWithoutHTML, BaseGeoClipPathPropsWithoutHTML>;
26
+ export type GeoClipPathProps = GeoClipPathPropsWithoutHTML;
27
+ declare const GeoClipPath: import("svelte").Component<GeoClipPathPropsWithoutHTML, {}, "">;
28
+ type GeoClipPath = ReturnType<typeof GeoClipPath>;
29
+ export default GeoClipPath;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts" module>
2
- import type { Without } from '../utils/types.js';
2
+ import type { Without, CommonStyleProps } from '../utils/types.js';
3
3
  import type { SVGAttributes } from 'svelte/elements';
4
4
  import type { ComponentProps } from 'svelte';
5
5
 
@@ -47,7 +47,7 @@
47
47
  * @bindable
48
48
  */
49
49
  ref?: SVGGElement;
50
- };
50
+ } & CommonStyleProps;
51
51
 
52
52
  export type HullProps = HullPropsWithoutHTML & Without<GroupProps, HullPropsWithoutHTML>;
53
53
  </script>
@@ -79,6 +79,12 @@
79
79
  onpointermove,
80
80
  onclick,
81
81
  onpointerleave,
82
+ fill,
83
+ fillOpacity,
84
+ stroke,
85
+ strokeOpacity,
86
+ strokeWidth,
87
+ opacity,
82
88
  class: className,
83
89
  ref: refProp = $bindable(),
84
90
  ...restProps
@@ -112,6 +118,12 @@
112
118
  <GeoPath
113
119
  geojson={polygon}
114
120
  {curve}
121
+ {fill}
122
+ {fillOpacity}
123
+ {stroke}
124
+ {strokeOpacity}
125
+ {strokeWidth}
126
+ {opacity}
115
127
  class={['lc-hull-path', classes.path]}
116
128
  onclick={(e) => onclick?.(e, { points, polygon })}
117
129
  onpointermove={(e) => onpointermove?.(e, { points, polygon })}
@@ -125,6 +137,12 @@
125
137
  x={(d) => d[0]}
126
138
  y={(d) => d[1]}
127
139
  {curve}
140
+ {fill}
141
+ {fillOpacity}
142
+ {stroke}
143
+ {strokeOpacity}
144
+ {strokeWidth}
145
+ {opacity}
128
146
  class={['lc-hull-class', classes.path]}
129
147
  onclick={(e) => onclick?.(e, { points, polygon })}
130
148
  onpointermove={(e) => onpointermove?.(e, { points, polygon })}
@@ -1,4 +1,4 @@
1
- import type { Without } from '../utils/types.js';
1
+ import type { Without, CommonStyleProps } from '../utils/types.js';
2
2
  import type { ComponentProps } from 'svelte';
3
3
  export type HullPropsWithoutHTML = {
4
4
  /**
@@ -32,7 +32,7 @@ export type HullPropsWithoutHTML = {
32
32
  * @bindable
33
33
  */
34
34
  ref?: SVGGElement;
35
- };
35
+ } & CommonStyleProps;
36
36
  export type HullProps = HullPropsWithoutHTML & Without<GroupProps, HullPropsWithoutHTML>;
37
37
  import { Delaunay } from 'd3-delaunay';
38
38
  import { type GroupProps } from './Group.svelte';
@@ -108,7 +108,10 @@
108
108
  const ctx = getChartContext();
109
109
 
110
110
  const endAngle = $derived(
111
- endAngleProp ?? degreesToRadians(ctx.config.xRange ? max(ctx.xRange) : max(range))
111
+ endAngleProp ??
112
+ degreesToRadians(
113
+ (ctx.config.xRange ? max(ctx.config.xRange as number[]) : max(range))!
114
+ )
112
115
  );
113
116
 
114
117
  const motionEndAngle = createMotion(0, () => endAngle, motion);
@@ -116,7 +119,10 @@
116
119
  const pie = $derived.by(() => {
117
120
  let _pie = d3pie<any>()
118
121
  .startAngle(
119
- startAngleProp ?? degreesToRadians(ctx.config.xRange ? min(ctx.xRange) : min(range))
122
+ startAngleProp ??
123
+ degreesToRadians(
124
+ (ctx.config.xRange ? min(ctx.config.xRange as number[]) : min(range))!
125
+ )
120
126
  )
121
127
  .endAngle(motionEndAngle.current)
122
128
  .padAngle(padAngle)
@@ -24,6 +24,11 @@
24
24
  return false;
25
25
  }
26
26
 
27
+ export type TextSegment = {
28
+ value: string | number;
29
+ class?: string;
30
+ };
31
+
27
32
  export type TextPropsWithoutHTML = {
28
33
  /**
29
34
  * Text value to render.
@@ -36,6 +41,13 @@
36
41
  */
37
42
  value?: string | number | ((d: any) => string | number);
38
43
 
44
+ /**
45
+ * Array of styled text segments for inline mixed styling.
46
+ * Each segment has its own value and optional class.
47
+ * Mutually exclusive with `value`.
48
+ */
49
+ segments?: TextSegment[];
50
+
39
51
  /**
40
52
  * Maximum width to occupy (approximate as words are not split)
41
53
  */
@@ -256,6 +268,7 @@
256
268
 
257
269
  let {
258
270
  value,
271
+ segments,
259
272
  x = 0,
260
273
  initialX,
261
274
  y = 0,
@@ -670,14 +683,30 @@
670
683
  const textAlign = textAnchor === 'middle' ? 'center' : textAnchor === 'end' ? 'end' : 'start';
671
684
  ctx.textAlign = textAlign;
672
685
 
673
- for (let index = 0; index < wordsByLines.length; index++) {
674
- const line = wordsByLines[index];
675
- const text = line.words.join(' ');
686
+ if (segments) {
687
+ let xOffset = baseX;
688
+ for (const segment of segments) {
689
+ const segStyles = getTextStyles(undefined, undefined, undefined, undefined, undefined, segment.class);
690
+ const text = String(segment.value);
691
+ // Set font before rendering and measuring so width is accurate
692
+ const segComputedStyles = getComputedStyles(ctx.canvas, segStyles);
693
+ const fontWeight = segComputedStyles.fontWeight || '';
694
+ const fontSize = segComputedStyles.fontSize || '10px';
695
+ const fontFamily = segComputedStyles.fontFamily || 'sans-serif';
696
+ ctx.font = `${fontWeight} ${fontSize} ${fontFamily}`.trim();
697
+ renderText(ctx, text, { x: xOffset, y: baseY }, segStyles);
698
+ xOffset += ctx.measureText(text).width;
699
+ }
700
+ } else {
701
+ for (let index = 0; index < wordsByLines.length; index++) {
702
+ const line = wordsByLines[index];
703
+ const text = line.words.join(' ');
676
704
 
677
- const xPos = baseX;
678
- const yPos = baseY + index * effectiveLineHeight;
705
+ const xPos = baseX;
706
+ const yPos = baseY + index * effectiveLineHeight;
679
707
 
680
- renderText(ctx, text, { x: xPos, y: yPos }, styles);
708
+ renderText(ctx, text, { x: xPos, y: yPos }, styles);
709
+ }
681
710
  }
682
711
 
683
712
  ctx.restore();
@@ -708,6 +737,7 @@
708
737
  dataMode,
709
738
  dataMode ? resolvedItems : null,
710
739
  value,
740
+ segments,
711
741
  motionX.current,
712
742
  motionY.current,
713
743
  fillKey!.current,
@@ -806,15 +836,26 @@
806
836
  opacity={staticOpacity}
807
837
  class={['lc-text', staticClassName]}
808
838
  >
809
- {#each wordsByLines as line, index}
810
- <tspan
811
- x={motionX.current}
812
- dy={index === 0 ? startDy : getPixelValue(lineHeight)}
813
- class="lc-text-tspan"
814
- >
815
- {line.words.join(' ')}
816
- </tspan>
817
- {/each}
839
+ {#if segments}
840
+ {#each segments as segment, index (index)}
841
+ <tspan
842
+ dy={index === 0 ? startDy : 0}
843
+ class={['lc-text-tspan', segment.class]}
844
+ >
845
+ {segment.value}
846
+ </tspan>
847
+ {/each}
848
+ {:else}
849
+ {#each wordsByLines as line, index (index)}
850
+ <tspan
851
+ x={motionX.current}
852
+ dy={index === 0 ? startDy : getPixelValue(lineHeight)}
853
+ class="lc-text-tspan"
854
+ >
855
+ {line.words.join(' ')}
856
+ </tspan>
857
+ {/each}
858
+ {/if}
818
859
  </text>
819
860
  {/if}
820
861
  </svg>
@@ -864,7 +905,13 @@
864
905
  style:line-height={lineHeight}
865
906
  class={['lc-text', staticClassName]}
866
907
  >
867
- {textValue}
908
+ {#if segments}
909
+ {#each segments as segment}
910
+ <span class={segment.class}>{segment.value}</span>
911
+ {/each}
912
+ {:else}
913
+ {textValue}
914
+ {/if}
868
915
  </div>
869
916
  {/if}
870
917
  {/if}
@@ -9,6 +9,10 @@ import type { FormatType, FormatConfig } from '@layerstack/utils';
9
9
  * Strings are data props unless they look like CSS values (e.g. "50%", "1em").
10
10
  */
11
11
  export declare function isTextDataProp(value: any): boolean;
12
+ export type TextSegment = {
13
+ value: string | number;
14
+ class?: string;
15
+ };
12
16
  export type TextPropsWithoutHTML = {
13
17
  /**
14
18
  * Text value to render.
@@ -20,6 +24,12 @@ export type TextPropsWithoutHTML = {
20
24
  * @default 0
21
25
  */
22
26
  value?: string | number | ((d: any) => string | number);
27
+ /**
28
+ * Array of styled text segments for inline mixed styling.
29
+ * Each segment has its own value and optional class.
30
+ * Mutually exclusive with `value`.
31
+ */
32
+ segments?: TextSegment[];
23
33
  /**
24
34
  * Maximum width to occupy (approximate as words are not split)
25
35
  */
@@ -254,7 +254,7 @@ describe('BarChart', () => {
254
254
  tooltipRect.dispatchEvent(new PointerEvent('pointerenter', eventInit));
255
255
  tooltipRect.dispatchEvent(new PointerEvent('pointermove', eventInit));
256
256
  await vi.waitFor(() => {
257
- const colorDots = container.querySelectorAll('.lc-tooltip-item-color');
257
+ const colorDots = document.querySelectorAll('.lc-tooltip-item-color');
258
258
  expect(colorDots.length).toBe(4);
259
259
  const colors = Array.from(colorDots).map((dot) => dot.style.getPropertyValue('--color'));
260
260
  expect(colors).toEqual([
@@ -50,14 +50,14 @@ describe('DefaultTooltip', () => {
50
50
  await expect.element(tooltipCtx).toBeInTheDocument();
51
51
  triggerTooltip(tooltipCtx);
52
52
  await vi.waitFor(() => {
53
- // Should have a header
54
- const header = container.querySelector('.lc-tooltip-header');
53
+ // Should have a header (portaled to body)
54
+ const header = document.querySelector('.lc-tooltip-header');
55
55
  expect(header).not.toBeNull();
56
56
  // Should have 4 tooltip items (3 series + 1 total)
57
- const items = container.querySelectorAll('.lc-tooltip-item-root');
57
+ const items = document.querySelectorAll('.lc-tooltip-item-root');
58
58
  expect(items.length).toBe(4);
59
59
  // Labels should match series keys + total
60
- const labels = container.querySelectorAll('.lc-tooltip-item-label');
60
+ const labels = document.querySelectorAll('.lc-tooltip-item-label');
61
61
  expect(labels.length).toBe(4);
62
62
  const labelTexts = Array.from(labels).map((l) => l.textContent?.trim());
63
63
  expect(labelTexts).toEqual(['apples', 'bananas', 'oranges', 'total']);
@@ -75,7 +75,7 @@ describe('DefaultTooltip', () => {
75
75
  await expect.element(tooltipCtx).toBeInTheDocument();
76
76
  triggerTooltip(tooltipCtx);
77
77
  await vi.waitFor(() => {
78
- const colorDots = container.querySelectorAll('.lc-tooltip-item-color');
78
+ const colorDots = document.querySelectorAll('.lc-tooltip-item-color');
79
79
  expect(colorDots.length).toBe(3);
80
80
  const colors = Array.from(colorDots).map((dot) => dot.style.getPropertyValue('--color'));
81
81
  expect(colors).toEqual(['rgb(255, 0, 0)', 'rgb(0, 128, 0)', 'rgb(255, 165, 0)']);
@@ -93,11 +93,11 @@ describe('DefaultTooltip', () => {
93
93
  await expect.element(tooltipCtx).toBeInTheDocument();
94
94
  triggerTooltip(tooltipCtx);
95
95
  await vi.waitFor(() => {
96
- const items = container.querySelectorAll('.lc-tooltip-item-root');
96
+ const items = document.querySelectorAll('.lc-tooltip-item-root');
97
97
  expect(items.length).toBe(4);
98
98
  });
99
- const items = Array.from(container.querySelectorAll('.lc-tooltip-item-root'));
100
- const labels = Array.from(container.querySelectorAll('.lc-tooltip-item-label'));
99
+ const items = Array.from(document.querySelectorAll('.lc-tooltip-item-root'));
100
+ const labels = Array.from(document.querySelectorAll('.lc-tooltip-item-label'));
101
101
  triggerPointerEvent(items[0], 'pointerenter');
102
102
  await vi.waitFor(() => {
103
103
  expect(items[0].dataset.highlighted).toBe('true');
@@ -133,7 +133,7 @@ describe('DefaultTooltip', () => {
133
133
  await expect.element(tooltipCtx).toBeInTheDocument();
134
134
  triggerTooltip(tooltipCtx);
135
135
  await vi.waitFor(() => {
136
- const items = container.querySelectorAll('.lc-tooltip-item-root');
136
+ const items = document.querySelectorAll('.lc-tooltip-item-root');
137
137
  // 1 series item, no total
138
138
  expect(items.length).toBe(1);
139
139
  });
@@ -152,12 +152,12 @@ describe('DefaultTooltip', () => {
152
152
  await expect.element(tooltipCtx).toBeInTheDocument();
153
153
  triggerTooltip(tooltipCtx);
154
154
  await vi.waitFor(() => {
155
- const header = container.querySelector('.lc-tooltip-header');
155
+ const header = document.querySelector('.lc-tooltip-header');
156
156
  expect(header).not.toBeNull();
157
157
  // 3 series + 1 total = 4 items
158
- const items = container.querySelectorAll('.lc-tooltip-item-root');
158
+ const items = document.querySelectorAll('.lc-tooltip-item-root');
159
159
  expect(items.length).toBe(4);
160
- const labels = container.querySelectorAll('.lc-tooltip-item-label');
160
+ const labels = document.querySelectorAll('.lc-tooltip-item-label');
161
161
  const labelTexts = Array.from(labels).map((l) => l.textContent?.trim());
162
162
  expect(labelTexts).toEqual(['apples', 'bananas', 'oranges', 'total']);
163
163
  });
@@ -176,10 +176,10 @@ describe('DefaultTooltip', () => {
176
176
  await expect.element(tooltipCtx).toBeInTheDocument();
177
177
  triggerTooltip(tooltipCtx);
178
178
  await vi.waitFor(() => {
179
- const items = container.querySelectorAll('.lc-tooltip-item-root');
179
+ const items = document.querySelectorAll('.lc-tooltip-item-root');
180
180
  // Should show x and y items
181
181
  expect(items.length).toBe(2);
182
- const labels = Array.from(container.querySelectorAll('.lc-tooltip-item-label')).map((l) => l.textContent?.trim());
182
+ const labels = Array.from(document.querySelectorAll('.lc-tooltip-item-label')).map((l) => l.textContent?.trim());
183
183
  expect(labels).toEqual(['x', 'y']);
184
184
  });
185
185
  });
@@ -196,10 +196,10 @@ describe('DefaultTooltip', () => {
196
196
  await expect.element(tooltipCtx).toBeInTheDocument();
197
197
  triggerTooltip(tooltipCtx);
198
198
  await vi.waitFor(() => {
199
- const items = container.querySelectorAll('.lc-tooltip-item-root');
199
+ const items = document.querySelectorAll('.lc-tooltip-item-root');
200
200
  // Should show x, y, and r items
201
201
  expect(items.length).toBe(3);
202
- const labels = Array.from(container.querySelectorAll('.lc-tooltip-item-label')).map((l) => l.textContent?.trim());
202
+ const labels = Array.from(document.querySelectorAll('.lc-tooltip-item-label')).map((l) => l.textContent?.trim());
203
203
  expect(labels).toEqual(['x', 'y', 'size']);
204
204
  });
205
205
  });
@@ -219,11 +219,11 @@ describe('DefaultTooltip', () => {
219
219
  triggerTooltip(tooltipCtx);
220
220
  await vi.waitFor(() => {
221
221
  // Should show a header with the series name
222
- const header = container.querySelector('.lc-tooltip-header');
222
+ const header = document.querySelector('.lc-tooltip-header');
223
223
  expect(header).not.toBeNull();
224
224
  expect(header.textContent).not.toBe('');
225
225
  // Should show x and y items
226
- const items = container.querySelectorAll('.lc-tooltip-item-root');
226
+ const items = document.querySelectorAll('.lc-tooltip-item-root');
227
227
  expect(items.length).toBe(2);
228
228
  });
229
229
  });
@@ -33,7 +33,7 @@ describe('LineChart', () => {
33
33
  tooltipRect.dispatchEvent(new PointerEvent('pointerenter', eventInit));
34
34
  tooltipRect.dispatchEvent(new PointerEvent('pointermove', eventInit));
35
35
  await vi.waitFor(() => {
36
- const colorDot = container.querySelector('.lc-tooltip-item-color');
36
+ const colorDot = document.querySelector('.lc-tooltip-item-color');
37
37
  expect(colorDot).not.toBeNull();
38
38
  const color = colorDot.style.getPropertyValue('--color');
39
39
  // Should NOT be the default series color
@@ -27,8 +27,8 @@ describe('PieChart', () => {
27
27
  arc.dispatchEvent(new PointerEvent('pointerenter', eventInit));
28
28
  arc.dispatchEvent(new PointerEvent('pointermove', eventInit));
29
29
  await vi.waitFor(() => {
30
- const tooltipLabel = container.querySelector('.lc-tooltip-item-label');
31
- const tooltipValue = container.querySelector('.lc-tooltip-item-value');
30
+ const tooltipLabel = document.querySelector('.lc-tooltip-item-label');
31
+ const tooltipValue = document.querySelector('.lc-tooltip-item-value');
32
32
  expect(tooltipLabel?.textContent).toContain('chrome');
33
33
  expect(tooltipValue?.textContent).toContain('275');
34
34
  });
@@ -66,6 +66,8 @@ export { default as GeoProjection } from './GeoProjection.svelte';
66
66
  export * from './GeoProjection.svelte';
67
67
  export { default as GeoEdgeFade } from './GeoEdgeFade.svelte';
68
68
  export * from './GeoEdgeFade.svelte';
69
+ export { default as GeoClipPath } from './GeoClipPath.svelte';
70
+ export * from './GeoClipPath.svelte';
69
71
  export { default as GeoPath } from './GeoPath.svelte';
70
72
  export * from './GeoPath.svelte';
71
73
  export { default as GeoPoint } from './GeoPoint.svelte';
@@ -66,6 +66,8 @@ export { default as GeoProjection } from './GeoProjection.svelte';
66
66
  export * from './GeoProjection.svelte';
67
67
  export { default as GeoEdgeFade } from './GeoEdgeFade.svelte';
68
68
  export * from './GeoEdgeFade.svelte';
69
+ export { default as GeoClipPath } from './GeoClipPath.svelte';
70
+ export * from './GeoClipPath.svelte';
69
71
  export { default as GeoPath } from './GeoPath.svelte';
70
72
  export * from './GeoPath.svelte';
71
73
  export { default as GeoPoint } from './GeoPoint.svelte';