layerchart 2.0.0-next.2 → 2.0.0-next.3

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.
@@ -17,8 +17,11 @@
17
17
  /** Placement of the label */
18
18
  labelPlacement?: Placement;
19
19
 
20
- /** Offset of the label */
21
- labelOffset?: number;
20
+ /** X offset of the label */
21
+ labelXOffset?: number;
22
+
23
+ /** Y offset of the label */
24
+ labelYOffset?: number;
22
25
 
23
26
  /** Classes for inner elements */
24
27
  props?: {
@@ -44,7 +47,8 @@
44
47
  y,
45
48
  label,
46
49
  labelPlacement = 'top-right',
47
- labelOffset = 0,
50
+ labelXOffset = 0,
51
+ labelYOffset = 0,
48
52
  props,
49
53
  }: AnnotationLineProps = $props();
50
54
 
@@ -62,25 +66,17 @@
62
66
  const labelProps = $derived<ComponentProps<typeof Text>>(
63
67
  isVertical
64
68
  ? {
65
- x:
66
- line.x1 +
67
- (['top', 'bottom'].includes(labelPlacement)
68
- ? 0 // Offset applies to `y`
69
- : labelPlacement.includes('left')
70
- ? -labelOffset
71
- : labelOffset),
69
+ x: line.x1 + (labelPlacement.includes('left') ? -labelXOffset : labelXOffset),
72
70
  y:
73
71
  (labelPlacement.includes('top')
74
72
  ? line.y2
75
73
  : labelPlacement.includes('bottom')
76
74
  ? line.y1
77
75
  : (line.y1 - line.y2) / 2) +
78
- (labelPlacement === 'top'
79
- ? -labelOffset
80
- : labelPlacement === 'bottom'
81
- ? labelOffset
82
- : 0),
83
- dy: -2, // adjust for smaler font size
76
+ (['top', 'bottom-left', 'bottom-right'].includes(labelPlacement)
77
+ ? -labelYOffset
78
+ : labelYOffset),
79
+ dy: -2, // adjust for smaller font size
84
80
  textAnchor: labelPlacement.includes('left')
85
81
  ? 'end'
86
82
  : labelPlacement.includes('right')
@@ -104,19 +100,11 @@
104
100
  : labelPlacement.includes('right')
105
101
  ? line.x2
106
102
  : (line.x2 - line.x1) / 2) +
107
- (labelPlacement === 'left'
108
- ? -labelOffset
109
- : labelPlacement === 'right'
110
- ? labelOffset
111
- : 0),
112
- y:
113
- line.y1 +
114
- (['left', 'right'].includes(labelPlacement)
115
- ? 0 // Offset applies to `x`
116
- : labelPlacement.includes('top')
117
- ? -labelOffset
118
- : labelOffset),
119
- dy: -2, // adjust for smaler font size
103
+ (['left', 'top-right', 'bottom-right'].includes(labelPlacement)
104
+ ? -labelXOffset
105
+ : labelXOffset),
106
+ y: line.y1 + (labelPlacement.includes('top') ? -labelYOffset : labelYOffset),
107
+ dy: -2, // adjust for smaller font size
120
108
  textAnchor:
121
109
  labelPlacement === 'left'
122
110
  ? 'end' // place beside line
@@ -11,8 +11,10 @@ export type AnnotationLinePropsWithoutHTML = {
11
11
  label?: string;
12
12
  /** Placement of the label */
13
13
  labelPlacement?: Placement;
14
- /** Offset of the label */
15
- labelOffset?: number;
14
+ /** X offset of the label */
15
+ labelXOffset?: number;
16
+ /** Y offset of the label */
17
+ labelYOffset?: number;
16
18
  /** Classes for inner elements */
17
19
  props?: {
18
20
  label?: Partial<ComponentProps<typeof Text>>;
@@ -20,8 +20,11 @@
20
20
  /** Placement of the label */
21
21
  labelPlacement?: Placement;
22
22
 
23
- /** Offset of the label */
24
- labelOffset?: number;
23
+ /** X offset of the label */
24
+ labelXOffset?: number;
25
+
26
+ /** Y offset of the label */
27
+ labelYOffset?: number;
25
28
 
26
29
  /** Details (description, etc) useful to display in tooltip */
27
30
  details?: any;
@@ -51,7 +54,8 @@
51
54
  r = 4,
52
55
  label,
53
56
  labelPlacement = 'center',
54
- labelOffset = 0,
57
+ labelXOffset = 0,
58
+ labelYOffset = 0,
55
59
  details,
56
60
  props,
57
61
  }: AnnotationPointProps = $props();
@@ -66,18 +70,12 @@
66
70
  const labelProps = $derived<ComponentProps<typeof Text>>({
67
71
  x:
68
72
  point.x +
69
- (labelPlacement.includes('left')
70
- ? -(r + labelOffset)
71
- : labelPlacement.includes('right')
72
- ? r + labelOffset
73
- : 0),
73
+ ((['top', 'center', 'bottom'].includes(labelPlacement) ? 0 : r) + labelXOffset) *
74
+ (labelPlacement.includes('left') ? -1 : 1),
74
75
  y:
75
76
  point.y +
76
- (labelPlacement.includes('top')
77
- ? -(r + labelOffset)
78
- : labelPlacement.includes('bottom')
79
- ? r + labelOffset
80
- : 0),
77
+ ((['left', 'center', 'right'].includes(labelPlacement) ? 0 : r) + labelYOffset) *
78
+ (labelPlacement.includes('top') ? -1 : 1),
81
79
  dy: -2, // adjust for smaler font size
82
80
  textAnchor: labelPlacement.includes('left')
83
81
  ? 'end'
@@ -13,8 +13,10 @@ export type AnnotationPointPropsWithoutHTML = {
13
13
  label?: string;
14
14
  /** Placement of the label */
15
15
  labelPlacement?: Placement;
16
- /** Offset of the label */
17
- labelOffset?: number;
16
+ /** X offset of the label */
17
+ labelXOffset?: number;
18
+ /** Y offset of the label */
19
+ labelYOffset?: number;
18
20
  /** Details (description, etc) useful to display in tooltip */
19
21
  details?: any;
20
22
  /** Classes for inner elements */
@@ -104,13 +104,11 @@
104
104
  };
105
105
 
106
106
  export type AxisProps<In extends Transition = Transition> = AxisPropsWithoutHTML<In> &
107
- Without<SVGAttributes<SVGGElement>, AxisPropsWithoutHTML<In>>;
107
+ Without<GroupProps, AxisPropsWithoutHTML<In>>;
108
108
  </script>
109
109
 
110
110
  <script lang="ts" generics="T extends Transition = Transition">
111
111
  import { type ComponentProps, type Snippet } from 'svelte';
112
- import { fade } from 'svelte/transition';
113
- import { cubicIn } from 'svelte/easing';
114
112
  import type { SVGAttributes } from 'svelte/elements';
115
113
 
116
114
  import { extent } from 'd3-array';
@@ -119,6 +117,7 @@
119
117
  import { format as formatValue, type FormatType } from '@layerstack/utils';
120
118
  import { cls } from '@layerstack/tailwind';
121
119
 
120
+ import Group, { type GroupProps } from './Group.svelte';
122
121
  import Line from './Line.svelte';
123
122
  import Rule from './Rule.svelte';
124
123
  import Text from './Text.svelte';
@@ -126,7 +125,7 @@
126
125
 
127
126
  import { getChartContext } from './Chart.svelte';
128
127
  import { extractLayerProps, layerClass } from '../utils/attributes.js';
129
- import { extractTweenConfig, type MotionProp } from '../utils/motion.svelte.js';
128
+ import { type MotionProp } from '../utils/motion.svelte.js';
130
129
  import { resolveTickVals, type TicksConfig } from '../utils/ticks.js';
131
130
 
132
131
  let {
@@ -142,8 +141,8 @@
142
141
  format,
143
142
  tickLabelProps,
144
143
  motion,
145
- transitionIn: transitionInProp,
146
- transitionInParams: transitionInParamsProp,
144
+ transitionIn,
145
+ transitionInParams,
147
146
  scale: scaleProp,
148
147
  classes = {},
149
148
  class: className,
@@ -151,13 +150,6 @@
151
150
  ...restProps
152
151
  }: AxisProps<T> = $props();
153
152
 
154
- const transitionIn = $derived(
155
- transitionInProp ? transitionInProp : extractTweenConfig(motion)?.options ? fade : () => {}
156
- ) as T;
157
- const transitionInParams = $derived(
158
- transitionInParamsProp ? transitionInParamsProp : { easing: cubicIn }
159
- );
160
-
161
153
  const ctx = getChartContext();
162
154
 
163
155
  const orientation = $derived(
@@ -342,7 +334,7 @@
342
334
  }) satisfies ComponentProps<typeof Text>;
343
335
  </script>
344
336
 
345
- <g
337
+ <Group
346
338
  {...restProps}
347
339
  data-placement={placement}
348
340
  class={cls(layerClass('axis'), `placement-${placement}`, classes.root, className)}
@@ -364,7 +356,7 @@
364
356
  <Text {...resolvedLabelProps} />
365
357
  {/if}
366
358
 
367
- {#each tickVals as tick, index (tick)}
359
+ {#each tickVals as tick, index (tick.toString())}
368
360
  {@const tickCoords = getCoords(tick)}
369
361
  {@const [radialTickCoordsX, radialTickCoordsY] = pointRadial(tickCoords.x, tickCoords.y)}
370
362
  {@const [radialTickMarkCoordsX, radialTickMarkCoordsY] = pointRadial(
@@ -386,7 +378,7 @@
386
378
  ),
387
379
  }}
388
380
 
389
- <g in:transitionIn={transitionInParams} class={layerClass('axis-tick-group')}>
381
+ <Group {transitionIn} {transitionInParams} class={layerClass('axis-tick-group')}>
390
382
  {#if grid !== false}
391
383
  {@const ruleProps = extractLayerProps(grid, 'axis-grid')}
392
384
  <Rule
@@ -404,7 +396,6 @@
404
396
  'stroke-surface-content/50',
405
397
  classes.tick
406
398
  )}
407
- <!-- Tick marks -->
408
399
  {#if orientation === 'horizontal'}
409
400
  <Line
410
401
  x1={tickCoords.x}
@@ -434,13 +425,12 @@
434
425
  />
435
426
  {/if}
436
427
  {/if}
437
- <!-- TODO: Add tick marks for radial (angle)? -->
438
428
 
439
429
  {#if tickLabel}
440
430
  {@render tickLabel({ props: resolvedTickLabelProps, index })}
441
431
  {:else}
442
432
  <Text {...resolvedTickLabelProps} />
443
433
  {/if}
444
- </g>
434
+ </Group>
445
435
  {/each}
446
- </g>
436
+ </Group>
@@ -89,10 +89,11 @@ export type AxisPropsWithoutHTML<In extends Transition = Transition> = {
89
89
  };
90
90
  motion?: MotionProp;
91
91
  };
92
- export type AxisProps<In extends Transition = Transition> = AxisPropsWithoutHTML<In> & Without<SVGAttributes<SVGGElement>, AxisPropsWithoutHTML<In>>;
92
+ export type AxisProps<In extends Transition = Transition> = AxisPropsWithoutHTML<In> & Without<GroupProps, AxisPropsWithoutHTML<In>>;
93
93
  import { type ComponentProps, type Snippet } from 'svelte';
94
94
  import type { SVGAttributes } from 'svelte/elements';
95
95
  import { type FormatType } from '@layerstack/utils';
96
+ import { type GroupProps } from './Group.svelte';
96
97
  import Rule from './Rule.svelte';
97
98
  import Text from './Text.svelte';
98
99
  import { type MotionProp } from '../utils/motion.svelte.js';
@@ -2,7 +2,10 @@
2
2
  import { createDimensionGetter, type Insets } from '../utils/rect.svelte.js';
3
3
 
4
4
  export type BarPropsWithoutHTML = {
5
- bar: Object;
5
+ /**
6
+ * data to render the bar from
7
+ */
8
+ data: Object;
6
9
 
7
10
  /**
8
11
  * Override `x` from context. Useful for multiple Bar instances
@@ -89,7 +92,7 @@
89
92
  const ctx = getChartContext();
90
93
 
91
94
  let {
92
- bar,
95
+ data,
93
96
  x = ctx.x,
94
97
  y = ctx.y,
95
98
  x1,
@@ -122,11 +125,11 @@
122
125
  }))
123
126
  );
124
127
 
125
- const dimensions = $derived(getDimensions(bar) ?? { x: 0, y: 0, width: 0, height: 0 });
128
+ const dimensions = $derived(getDimensions(data) ?? { x: 0, y: 0, width: 0, height: 0 });
126
129
 
127
130
  const isVertical = $derived(isScaleBand(ctx.xScale));
128
131
  const valueAccessor = $derived(accessor(isVertical ? y : x));
129
- const value = $derived(valueAccessor(bar));
132
+ const value = $derived(valueAccessor(data));
130
133
  const resolvedValue = $derived(Array.isArray(value) ? greatestAbs(value) : value);
131
134
 
132
135
  // Resolved `rounded="edge"` based on orientation and value
@@ -1,6 +1,9 @@
1
1
  import { type Insets } from '../utils/rect.svelte.js';
2
2
  export type BarPropsWithoutHTML = {
3
- bar: Object;
3
+ /**
4
+ * data to render the bar from
5
+ */
6
+ data: Object;
4
7
  /**
5
8
  * Override `x` from context. Useful for multiple Bar instances
6
9
  *
@@ -21,16 +21,19 @@
21
21
  children?: Snippet;
22
22
  // TODO: investigate
23
23
  [key: string]: any;
24
- } & Omit<BarPropsWithoutHTML, 'bar' | 'children'>;
24
+ } & Omit<BarPropsWithoutHTML, 'data' | 'children'>;
25
25
 
26
- export type BarsProps = BarsPropsWithoutHTML & Omit<BarProps, 'bar'>;
26
+ export type BarsProps = BarsPropsWithoutHTML & Omit<BarProps, 'data'>;
27
27
  </script>
28
28
 
29
29
  <script lang="ts">
30
+ import type { Snippet } from 'svelte';
31
+
30
32
  import Bar, { type BarProps, type BarPropsWithoutHTML } from './Bar.svelte';
33
+ import Group from './Group.svelte';
34
+
31
35
  import { chartDataArray } from '../utils/common.js';
32
36
  import { getChartContext } from './Chart.svelte';
33
- import type { Snippet } from 'svelte';
34
37
  import { extractLayerProps, layerClass } from '../utils/attributes.js';
35
38
 
36
39
  let {
@@ -49,20 +52,20 @@
49
52
  const data = $derived(chartDataArray(dataProp ?? ctx.data));
50
53
  </script>
51
54
 
52
- <g class={layerClass('bars')}>
55
+ <Group class={layerClass('bars')}>
53
56
  {#if children}
54
57
  {@render children()}
55
58
  {:else}
56
59
  {#each data as d, i (key(d, i))}
57
60
  <Bar
61
+ data={d}
58
62
  {radius}
59
63
  {strokeWidth}
60
64
  {stroke}
61
- bar={d}
62
65
  fill={fill ?? (ctx.config.c ? ctx.cGet(d) : null)}
63
66
  onclick={(e) => onBarClick(e, { data: d })}
64
67
  {...extractLayerProps(restProps, 'bars-bar')}
65
68
  />
66
69
  {/each}
67
70
  {/if}
68
- </g>
71
+ </Group>
@@ -18,10 +18,10 @@ export type BarsPropsWithoutHTML = {
18
18
  }) => void;
19
19
  children?: Snippet;
20
20
  [key: string]: any;
21
- } & Omit<BarPropsWithoutHTML, 'bar' | 'children'>;
22
- export type BarsProps = BarsPropsWithoutHTML & Omit<BarProps, 'bar'>;
23
- import { type BarProps, type BarPropsWithoutHTML } from './Bar.svelte';
21
+ } & Omit<BarPropsWithoutHTML, 'data' | 'children'>;
22
+ export type BarsProps = BarsPropsWithoutHTML & Omit<BarProps, 'data'>;
24
23
  import type { Snippet } from 'svelte';
24
+ import { type BarProps, type BarPropsWithoutHTML } from './Bar.svelte';
25
25
  declare const Bars: import("svelte").Component<BarsProps, {}, "">;
26
26
  type Bars = ReturnType<typeof Bars>;
27
27
  export default Bars;
@@ -21,22 +21,28 @@
21
21
  </script>
22
22
 
23
23
  <script lang="ts">
24
+ import type { Snippet } from 'svelte';
25
+ import { getRenderContext } from './Chart.svelte';
24
26
  import { createId } from '../utils/createId.js';
25
27
  import { layerClass } from '../utils/attributes.js';
26
- import type { Snippet } from 'svelte';
28
+
27
29
  const uid = $props.id();
28
30
 
29
31
  let { id = createId('blur-', uid), stdDeviation = 5, children }: BlurProps = $props();
32
+
33
+ const renderContext = getRenderContext();
30
34
  </script>
31
35
 
32
- <defs>
33
- <filter {id} class={layerClass('blur-filter')}>
34
- <feGaussianBlur in="SourceGraphic" {stdDeviation} />
35
- </filter>
36
- </defs>
36
+ {#if renderContext === 'svg'}
37
+ <defs>
38
+ <filter {id} class={layerClass('blur-filter')}>
39
+ <feGaussianBlur in="SourceGraphic" {stdDeviation} />
40
+ </filter>
41
+ </defs>
37
42
 
38
- {#if children}
39
- <g filter="url(#{id})" class={layerClass('blur-g')}>
40
- {@render children({ id, url: `url(#${id})` })}
41
- </g>
43
+ {#if children}
44
+ <g filter="url(#{id})" class={layerClass('blur-g')}>
45
+ {@render children({ id, url: `url(#${id})` })}
46
+ </g>
47
+ {/if}
42
48
  {/if}
@@ -4,6 +4,7 @@
4
4
  import { layerClass } from '../utils/attributes.js';
5
5
  import type { Snippet } from 'svelte';
6
6
  import type { SVGAttributes } from 'svelte/elements';
7
+ import { getRenderContext } from './Chart.svelte';
7
8
 
8
9
  export type ClipPathPropsWithoutHTML = {
9
10
  /**
@@ -55,20 +56,24 @@
55
56
  }: ClipPathPropsWithoutHTML = $props();
56
57
 
57
58
  const url = $derived(`url(#${id})`);
59
+
60
+ const renderContext = getRenderContext();
58
61
  </script>
59
62
 
60
- <defs>
61
- <clipPath {id} {...restProps}>
62
- {@render clip?.({ id })}
63
+ {#if renderContext === 'svg'}
64
+ <defs>
65
+ <clipPath {id} {...restProps}>
66
+ {@render clip?.({ id })}
63
67
 
64
- {#if useId}
65
- <use href="#{useId}" />
66
- {/if}
67
- </clipPath>
68
- </defs>
68
+ {#if useId}
69
+ <use href="#{useId}" />
70
+ {/if}
71
+ </clipPath>
72
+ </defs>
73
+ {/if}
69
74
 
70
75
  {#if children}
71
- {#if disabled}
76
+ {#if disabled || renderContext !== 'svg'}
72
77
  {@render children({ id, url, useId })}
73
78
  {:else}
74
79
  <g style:clip-path={url} class={layerClass('clip-path-g')}>
@@ -15,7 +15,7 @@
15
15
  };
16
16
 
17
17
  export type GeoEdgeFadeProps = GeoEdgeFadePropsWithoutHTML &
18
- Without<SVGAttributes<SVGGElement>, GeoEdgeFadePropsWithoutHTML>;
18
+ Without<GroupProps, GeoEdgeFadePropsWithoutHTML>;
19
19
  </script>
20
20
 
21
21
  <script lang="ts">
@@ -23,6 +23,7 @@
23
23
  import { geoDistance } from 'd3-geo';
24
24
 
25
25
  import { getGeoContext } from './GeoContext.svelte';
26
+ import Group, { type GroupProps } from './Group.svelte';
26
27
  import { extractLayerProps } from '../utils/attributes.js';
27
28
 
28
29
  let {
@@ -55,6 +56,6 @@
55
56
  const opacity = $derived(opacityProp ?? clamper(fade(distance)));
56
57
  </script>
57
58
 
58
- <g {opacity} bind:this={ref} {...extractLayerProps(restProps, 'geo-edge-fade')}>
59
+ <Group {opacity} bind:ref {...extractLayerProps(restProps, 'geo-edge-fade')}>
59
60
  {@render children?.()}
60
- </g>
61
+ </Group>
@@ -1,6 +1,5 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { Without } from '../utils/types.js';
3
- import type { SVGAttributes } from 'svelte/elements';
4
3
  export type GeoEdgeFadePropsWithoutHTML = {
5
4
  link: {
6
5
  source: [number, number];
@@ -13,7 +12,8 @@ export type GeoEdgeFadePropsWithoutHTML = {
13
12
  ref?: SVGGElement;
14
13
  children?: Snippet;
15
14
  };
16
- export type GeoEdgeFadeProps = GeoEdgeFadePropsWithoutHTML & Without<SVGAttributes<SVGGElement>, GeoEdgeFadePropsWithoutHTML>;
15
+ export type GeoEdgeFadeProps = GeoEdgeFadePropsWithoutHTML & Without<GroupProps, GeoEdgeFadePropsWithoutHTML>;
16
+ import { type GroupProps } from './Group.svelte';
17
17
  declare const GeoEdgeFade: import("svelte").Component<GeoEdgeFadeProps, {}, "ref">;
18
18
  type GeoEdgeFade = ReturnType<typeof GeoEdgeFade>;
19
19
  export default GeoEdgeFade;
@@ -16,6 +16,7 @@
16
16
  <script lang="ts">
17
17
  import { geoGraticule } from 'd3-geo';
18
18
  import { extractLayerProps, layerClass } from '../utils/attributes.js';
19
+ import Group from './Group.svelte';
19
20
 
20
21
  let { lines, outline, step = [10, 10], ...restProps }: GraticuleProps = $props();
21
22
 
@@ -26,7 +27,7 @@
26
27
  });
27
28
  </script>
28
29
 
29
- <g class={layerClass('graticule-g')}>
30
+ <Group class={layerClass('graticule-g')}>
30
31
  <!-- TODO: Any reason to still render the single `MultiLineString` path if using `lines` and/or `outline` -->
31
32
  {#if !lines && !outline}
32
33
  <GeoPath geojson={graticule()} {...extractLayerProps(restProps, 'graticule-geo-path')} />
@@ -44,4 +45,4 @@
44
45
  {...extractLayerProps(outline, 'graticule-geo-outline')}
45
46
  />
46
47
  {/if}
47
- </g>
48
+ </Group>
@@ -77,7 +77,7 @@
77
77
  };
78
78
 
79
79
  export type GridProps<In extends Transition = Transition> = Omit<
80
- GridPropsWithoutHTML<In> & Without<SVGAttributes<SVGGElement>, GridPropsWithoutHTML<In>>,
80
+ GridPropsWithoutHTML<In> & Without<GroupProps, GridPropsWithoutHTML<In>>,
81
81
  'children'
82
82
  >;
83
83
  </script>
@@ -93,6 +93,7 @@
93
93
  import { isScaleBand } from '../utils/scales.svelte.js';
94
94
 
95
95
  import Circle from './Circle.svelte';
96
+ import Group, { type GroupProps } from './Group.svelte';
96
97
  import Line from './Line.svelte';
97
98
  import Rule from './Rule.svelte';
98
99
  import Spline from './Spline.svelte';
@@ -150,11 +151,11 @@
150
151
  );
151
152
  </script>
152
153
 
153
- <g bind:this={ref} class={cls(layerClass('grid'), classes.root, className)} {...restProps}>
154
+ <Group bind:ref class={cls(layerClass('grid'), classes.root, className)} {...restProps}>
154
155
  {#if x}
155
156
  {@const splineProps = extractLayerProps(x, 'grid-x-line')}
156
157
 
157
- <g in:transitionIn={transitionInParams} class={layerClass('grid-x')}>
158
+ <Group {transitionIn} {transitionInParams} class={layerClass('grid-x')}>
158
159
  {#each xTickVals as x (x)}
159
160
  {#if ctx.radial}
160
161
  {@const [x1, y1] = pointRadial(ctx.xScale(x), ctx.yRange[0])}
@@ -204,12 +205,12 @@
204
205
  )}
205
206
  />
206
207
  {/if}
207
- </g>
208
+ </Group>
208
209
  {/if}
209
210
 
210
211
  {#if y}
211
212
  {@const splineProps = extractLayerProps(y, 'grid-y-line')}
212
- <g in:transitionIn={transitionInParams} class={layerClass('grid-y')}>
213
+ <Group {transitionIn} {transitionInParams} class={layerClass('grid-y')}>
213
214
  {#each yTickVals as y (y)}
214
215
  {#if ctx.radial}
215
216
  {#if radialY === 'circle'}
@@ -285,6 +286,6 @@
285
286
  />
286
287
  {/if}
287
288
  {/if}
288
- </g>
289
+ </Group>
289
290
  {/if}
290
- </g>
291
+ </Group>
@@ -63,7 +63,8 @@ export type GridPropsWithoutHTML<In extends Transition = Transition> = {
63
63
  ref?: SVGGElement;
64
64
  motion?: MotionProp;
65
65
  };
66
- export type GridProps<In extends Transition = Transition> = Omit<GridPropsWithoutHTML<In> & Without<SVGAttributes<SVGGElement>, GridPropsWithoutHTML<In>>, 'children'>;
66
+ export type GridProps<In extends Transition = Transition> = Omit<GridPropsWithoutHTML<In> & Without<GroupProps, GridPropsWithoutHTML<In>>, 'children'>;
67
+ import { type GroupProps } from './Group.svelte';
67
68
  import { type TicksConfig } from '../utils/ticks.js';
68
69
  declare const Grid: import("svelte").Component<GridProps<Transition>, {}, "ref">;
69
70
  type Grid = ReturnType<typeof Grid>;
@@ -1,10 +1,10 @@
1
1
  <script lang="ts" module>
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes, TouchEventHandler } from 'svelte/elements';
4
- import type { Without } from '../utils/types.js';
5
- import { createMotion, type MotionProp } from '../utils/motion.svelte.js';
4
+ import type { Transition, TransitionParams, Without } from '../utils/types.js';
5
+ import { createMotion, extractTweenConfig, type MotionProp } from '../utils/motion.svelte.js';
6
6
 
7
- export type GroupPropsWithoutHTML = {
7
+ export type GroupPropsWithoutHTML<In extends Transition = Transition> = {
8
8
  /**
9
9
  * Translate x
10
10
  */
@@ -44,6 +44,11 @@
44
44
  */
45
45
  preventTouchMove?: boolean;
46
46
 
47
+ /**
48
+ * The opacity of the element. (0 to 1)
49
+ */
50
+ opacity?: number;
51
+
47
52
  children?: Snippet;
48
53
 
49
54
  /**
@@ -56,13 +61,28 @@
56
61
  ref?: Element;
57
62
 
58
63
  motion?: MotionProp;
64
+
65
+ /**
66
+ * Transition function for entering elements
67
+ * @default defaults to fade if the motion prop is set to tweened
68
+ */
69
+ transitionIn?: In;
70
+
71
+ /**
72
+ * Parameters for the transitionIn function
73
+ * @default { easing: cubicIn }
74
+ */
75
+ transitionInParams?: TransitionParams<In>;
59
76
  };
60
77
 
61
78
  export type GroupProps = GroupPropsWithoutHTML &
62
79
  Without<HTMLAttributes<Element>, GroupPropsWithoutHTML>;
63
80
  </script>
64
81
 
65
- <script lang="ts">
82
+ <script lang="ts" generics="T extends Transition = Transition">
83
+ import { fade } from 'svelte/transition';
84
+ import { cubicIn } from 'svelte/easing';
85
+
66
86
  import { cls } from '@layerstack/tailwind';
67
87
 
68
88
  import { getRenderContext } from './Chart.svelte';
@@ -80,7 +100,10 @@
80
100
  initialY: initialYProp,
81
101
  center = false,
82
102
  preventTouchMove = false,
103
+ opacity = 1,
83
104
  motion,
105
+ transitionIn: transitionInProp,
106
+ transitionInParams: transitionInParamsProp,
84
107
  class: className,
85
108
  children,
86
109
  ref: refProp = $bindable(),
@@ -101,6 +124,13 @@
101
124
  const motionX = createMotion(initialX, () => trueX, motion);
102
125
  const motionY = createMotion(initialY, () => trueY, motion);
103
126
 
127
+ const transitionIn = $derived(
128
+ transitionInProp ? transitionInProp : extractTweenConfig(motion)?.options ? fade : () => {}
129
+ ) as T;
130
+ const transitionInParams = $derived(
131
+ transitionInParamsProp ? transitionInParamsProp : { easing: cubicIn }
132
+ );
133
+
104
134
  const transform = $derived.by(() => {
105
135
  if (center || x != null || y != null) {
106
136
  return `translate(${motionX.current}px, ${motionY.current}px)`;
@@ -113,7 +143,13 @@
113
143
  registerCanvasComponent({
114
144
  name: 'Group',
115
145
  render: (ctx) => {
146
+ const currentGlobalAlpha = ctx.globalAlpha;
147
+ ctx.globalAlpha = opacity;
148
+
116
149
  ctx.translate(motionX.current ?? 0, motionY.current ?? 0);
150
+
151
+ // Restore in case it was modified by `opacity`
152
+ ctx.globalAlpha = currentGlobalAlpha;
117
153
  },
118
154
  retainState: true,
119
155
  events: {
@@ -124,7 +160,7 @@
124
160
  pointerleave: restProps.onpointerleave,
125
161
  pointerdown: restProps.onpointerdown,
126
162
  },
127
- deps: () => [motionX.current, motionY.current],
163
+ deps: () => [motionX.current, motionY.current, opacity],
128
164
  });
129
165
  }
130
166
 
@@ -143,6 +179,8 @@
143
179
  <g
144
180
  style:transform
145
181
  class={cls(layerClass('group-g'), className)}
182
+ in:transitionIn={transitionInParams}
183
+ {opacity}
146
184
  {...restProps}
147
185
  ontouchmove={handleTouchMove}
148
186
  bind:this={ref}
@@ -153,6 +191,8 @@
153
191
  <div
154
192
  bind:this={ref}
155
193
  style:transform
194
+ style:opacity
195
+ in:transitionIn={transitionInParams}
156
196
  {...restProps}
157
197
  class={cls(layerClass('group-div'), 'absolute', className)}
158
198
  ontouchmove={handleTouchMove}
@@ -1,8 +1,8 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import type { Without } from '../utils/types.js';
3
+ import type { Transition, TransitionParams, Without } from '../utils/types.js';
4
4
  import { type MotionProp } from '../utils/motion.svelte.js';
5
- export type GroupPropsWithoutHTML = {
5
+ export type GroupPropsWithoutHTML<In extends Transition = Transition> = {
6
6
  /**
7
7
  * Translate x
8
8
  */
@@ -36,6 +36,10 @@ export type GroupPropsWithoutHTML = {
36
36
  * @default false
37
37
  */
38
38
  preventTouchMove?: boolean;
39
+ /**
40
+ * The opacity of the element. (0 to 1)
41
+ */
42
+ opacity?: number;
39
43
  children?: Snippet;
40
44
  /**
41
45
  * A reference to the rendered DOM element, which could be
@@ -46,8 +50,32 @@ export type GroupPropsWithoutHTML = {
46
50
  */
47
51
  ref?: Element;
48
52
  motion?: MotionProp;
53
+ /**
54
+ * Transition function for entering elements
55
+ * @default defaults to fade if the motion prop is set to tweened
56
+ */
57
+ transitionIn?: In;
58
+ /**
59
+ * Parameters for the transitionIn function
60
+ * @default { easing: cubicIn }
61
+ */
62
+ transitionInParams?: TransitionParams<In>;
49
63
  };
50
64
  export type GroupProps = GroupPropsWithoutHTML & Without<HTMLAttributes<Element>, GroupPropsWithoutHTML>;
51
- declare const Group: import("svelte").Component<GroupProps, {}, "ref">;
52
- type Group = ReturnType<typeof Group>;
65
+ declare class __sveltets_Render<T extends Transition = Transition> {
66
+ props(): GroupProps;
67
+ events(): {};
68
+ slots(): {};
69
+ bindings(): "ref";
70
+ exports(): {};
71
+ }
72
+ interface $$IsomorphicComponent {
73
+ new <T extends Transition = Transition>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
74
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
75
+ } & ReturnType<__sveltets_Render<T>['exports']>;
76
+ <T extends Transition = Transition>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
77
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
78
+ }
79
+ declare const Group: $$IsomorphicComponent;
80
+ type Group<T extends Transition = Transition> = InstanceType<typeof Group<T>>;
53
81
  export default Group;
@@ -471,7 +471,7 @@
471
471
  {:else}
472
472
  <Bar
473
473
  motion={motion === 'spring' ? 'spring' : undefined}
474
- bar={highlightData}
474
+ data={highlightData}
475
475
  {...barProps}
476
476
  class={cls(!barProps.fill && 'fill-primary', barProps.class)}
477
477
  onclick={onBarClick && ((e) => onBarClick(e, { data: highlightData }))}
@@ -49,8 +49,7 @@
49
49
  ref?: SVGGElement;
50
50
  };
51
51
 
52
- export type HullProps = HullPropsWithoutHTML &
53
- Without<SVGAttributes<SVGElement>, HullPropsWithoutHTML>;
52
+ export type HullProps = HullPropsWithoutHTML & Without<GroupProps, HullPropsWithoutHTML>;
54
53
  </script>
55
54
 
56
55
  <script lang="ts">
@@ -62,6 +61,7 @@
62
61
  import { cls } from '@layerstack/tailwind';
63
62
 
64
63
  import GeoPath from './GeoPath.svelte';
64
+ import Group, { type GroupProps } from './Group.svelte';
65
65
  import Spline from './Spline.svelte';
66
66
  import { getChartContext } from './Chart.svelte';
67
67
  import { getGeoContext } from './GeoContext.svelte';
@@ -104,7 +104,7 @@
104
104
  );
105
105
  </script>
106
106
 
107
- <g {...restProps} class={cls(layerClass('hull-g'), classes.root, className)} bind:this={ref}>
107
+ <Group {...restProps} class={cls(layerClass('hull-g'), classes.root, className)} bind:ref>
108
108
  {#if geoCtx.projection}
109
109
  {@const polygon = geoVoronoi().hull(points)}
110
110
  <GeoPath
@@ -129,4 +129,4 @@
129
129
  {onpointerleave}
130
130
  />
131
131
  {/if}
132
- </g>
132
+ </Group>
@@ -1,5 +1,4 @@
1
1
  import type { Without } from '../utils/types.js';
2
- import type { SVGAttributes } from 'svelte/elements';
3
2
  import type { ComponentProps } from 'svelte';
4
3
  export type HullPropsWithoutHTML = {
5
4
  /**
@@ -34,8 +33,9 @@ export type HullPropsWithoutHTML = {
34
33
  */
35
34
  ref?: SVGGElement;
36
35
  };
37
- export type HullProps = HullPropsWithoutHTML & Without<SVGAttributes<SVGElement>, HullPropsWithoutHTML>;
36
+ export type HullProps = HullPropsWithoutHTML & Without<GroupProps, HullPropsWithoutHTML>;
38
37
  import { Delaunay } from 'd3-delaunay';
38
+ import { type GroupProps } from './Group.svelte';
39
39
  import Spline from './Spline.svelte';
40
40
  declare const Hull: import("svelte").Component<HullProps, {}, "ref">;
41
41
  type Hull = ReturnType<typeof Hull>;
@@ -73,6 +73,7 @@
73
73
 
74
74
  import { isScaleBand } from '../utils/scales.svelte.js';
75
75
  import { getChartContext } from './Chart.svelte';
76
+ import Group from './Group.svelte';
76
77
  import { extractLayerProps, layerClass } from '../utils/attributes.js';
77
78
 
78
79
  const ctx = getChartContext();
@@ -172,7 +173,7 @@
172
173
  }
173
174
  </script>
174
175
 
175
- <g class={layerClass('labels-g')}>
176
+ <Group class={layerClass('labels-g')}>
176
177
  <Points {data} {x} {y}>
177
178
  {#snippet children({ points })}
178
179
  {#each points as point, i (key(point.data, i))}
@@ -196,4 +197,4 @@
196
197
  {/each}
197
198
  {/snippet}
198
199
  </Points>
199
- </g>
200
+ </Group>
@@ -52,6 +52,7 @@
52
52
  import { cls } from '@layerstack/tailwind';
53
53
 
54
54
  import Circle from './Circle.svelte';
55
+ import Group from './Group.svelte';
55
56
  import Line, { type LinePropsWithoutHTML } from './Line.svelte';
56
57
  import { getChartContext } from './Chart.svelte';
57
58
  import { layerClass } from '../utils/attributes.js';
@@ -87,7 +88,7 @@
87
88
  }
88
89
  </script>
89
90
 
90
- <g class={layerClass('rule-g')}>
91
+ <Group class={layerClass('rule-g')}>
91
92
  {#if showRule(x, 'x')}
92
93
  {@const xCoord =
93
94
  x === true || x === 'left'
@@ -153,4 +154,4 @@
153
154
  />
154
155
  {/if}
155
156
  {/if}
156
- </g>
157
+ </Group>
@@ -50,7 +50,7 @@
50
50
  };
51
51
 
52
52
  export type VoronoiProps = VoronoiPropsWithoutHTML &
53
- Without<Omit<SVGAttributes<SVGGElement>, 'children'>, VoronoiPropsWithoutHTML>;
53
+ Without<Omit<GroupProps, 'children'>, VoronoiPropsWithoutHTML>;
54
54
  </script>
55
55
 
56
56
  <script lang="ts">
@@ -63,6 +63,7 @@
63
63
  import { cls } from '@layerstack/tailwind';
64
64
 
65
65
  import GeoPath from './GeoPath.svelte';
66
+ import Group, { type GroupProps } from './Group.svelte';
66
67
  import Spline from './Spline.svelte';
67
68
  import { getChartContext } from './Chart.svelte';
68
69
  import { getGeoContext } from './GeoContext.svelte';
@@ -110,7 +111,7 @@
110
111
  const boundHeight = $derived(Math.max(ctx.height, 0));
111
112
  </script>
112
113
 
113
- <g {...restProps} class={cls(layerClass('voronoi-g'), classes.root, className)}>
114
+ <Group {...restProps} class={cls(layerClass('voronoi-g'), classes.root, className)}>
114
115
  {#if geo.projection}
115
116
  {@const polygons = geoVoronoi().polygons(points)}
116
117
  {#each polygons.features as feature}
@@ -158,4 +159,4 @@
158
159
  {/if}
159
160
  {/each}
160
161
  {/if}
161
- </g>
162
+ </Group>
@@ -1,5 +1,4 @@
1
1
  import type { Without } from '../utils/types.js';
2
- import type { SVGAttributes } from 'svelte/elements';
3
2
  export type VoronoiPropsWithoutHTML = {
4
3
  /**
5
4
  * Override data instead of using context
@@ -35,8 +34,9 @@ export type VoronoiPropsWithoutHTML = {
35
34
  feature?: GeoPermissibleObjects;
36
35
  }) => void;
37
36
  };
38
- export type VoronoiProps = VoronoiPropsWithoutHTML & Without<Omit<SVGAttributes<SVGGElement>, 'children'>, VoronoiPropsWithoutHTML>;
37
+ export type VoronoiProps = VoronoiPropsWithoutHTML & Without<Omit<GroupProps, 'children'>, VoronoiPropsWithoutHTML>;
39
38
  import type { GeoPermissibleObjects } from 'd3-geo';
39
+ import { type GroupProps } from './Group.svelte';
40
40
  declare const Voronoi: import("svelte").Component<VoronoiProps, {}, "">;
41
41
  type Voronoi = ReturnType<typeof Voronoi>;
42
42
  export default Voronoi;
@@ -4,7 +4,7 @@ import type { SeriesData } from './types.js';
4
4
  import type Legend from '../Legend.svelte';
5
5
  export declare class HighlightKey<TData, SeriesComponent extends Component> {
6
6
  current: string | null;
7
- set(seriesKey: typeof this.current): void;
7
+ set: (seriesKey: typeof this.current) => void;
8
8
  }
9
9
  export declare class SeriesState<TData, TComponent extends Component> {
10
10
  #private;
@@ -2,9 +2,9 @@ import { SelectionState } from '@layerstack/svelte-state';
2
2
  import { scaleOrdinal } from 'd3-scale';
3
3
  export class HighlightKey {
4
4
  current = $state(null);
5
- set(seriesKey) {
5
+ set = (seriesKey) => {
6
6
  this.current = seriesKey;
7
- }
7
+ };
8
8
  }
9
9
  export class SeriesState {
10
10
  #series = $state.raw([]);
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "author": "Sean Lynch <techniq35@gmail.com>",
5
5
  "license": "MIT",
6
6
  "repository": "techniq/layerchart",
7
- "version": "2.0.0-next.2",
7
+ "version": "2.0.0-next.3",
8
8
  "devDependencies": {
9
9
  "@changesets/cli": "^2.29.2",
10
10
  "@mdi/js": "^7.4.47",