layerchart 2.0.0-next.38 → 2.0.0-next.39

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 (96) hide show
  1. package/dist/components/AnnotationLine.svelte +15 -2
  2. package/dist/components/AnnotationPoint.svelte +13 -2
  3. package/dist/components/AnnotationRange.svelte +16 -2
  4. package/dist/components/Arc.svelte +3 -3
  5. package/dist/components/Area.svelte +10 -2
  6. package/dist/components/Axis.svelte +43 -26
  7. package/dist/components/Bar.svelte +6 -5
  8. package/dist/components/Bar.svelte.d.ts +2 -2
  9. package/dist/components/Bars.svelte +3 -3
  10. package/dist/components/Blur.svelte +2 -3
  11. package/dist/components/BrushContext.svelte +44 -44
  12. package/dist/components/Calendar.svelte +21 -4
  13. package/dist/components/Chart.svelte +1 -2
  14. package/dist/components/ChartClipPath.svelte +1 -1
  15. package/dist/components/Circle.svelte +44 -3
  16. package/dist/components/CircleClipPath.svelte +8 -1
  17. package/dist/components/ClipPath.svelte +1 -2
  18. package/dist/components/ColorRamp.svelte +1 -1
  19. package/dist/components/ComputedStyles.svelte +9 -2
  20. package/dist/components/Connector.svelte +1 -1
  21. package/dist/components/Ellipse.svelte +44 -3
  22. package/dist/components/Frame.svelte +1 -1
  23. package/dist/components/GeoCircle.svelte +1 -1
  24. package/dist/components/GeoEdgeFade.svelte +1 -1
  25. package/dist/components/GeoPath.svelte +18 -3
  26. package/dist/components/GeoPoint.svelte +3 -3
  27. package/dist/components/GeoSpline.svelte +1 -1
  28. package/dist/components/GeoTile.svelte +1 -1
  29. package/dist/components/Graticule.svelte +5 -5
  30. package/dist/components/Grid.svelte +57 -60
  31. package/dist/components/Group.svelte +11 -6
  32. package/dist/components/Highlight.svelte +46 -22
  33. package/dist/components/Highlight.svelte.d.ts +4 -0
  34. package/dist/components/Hull.svelte +11 -4
  35. package/dist/components/Labels.svelte +21 -11
  36. package/dist/components/Legend.svelte +133 -67
  37. package/dist/components/Legend.svelte.d.ts +7 -3
  38. package/dist/components/Line.svelte +40 -3
  39. package/dist/components/LinearGradient.svelte +35 -4
  40. package/dist/components/Link.svelte +1 -1
  41. package/dist/components/Marker.svelte +37 -26
  42. package/dist/components/MonthPath.svelte +14 -3
  43. package/dist/components/MotionPath.svelte +1 -1
  44. package/dist/components/Pattern.svelte +5 -5
  45. package/dist/components/Pie.svelte +1 -2
  46. package/dist/components/Points.svelte +1 -1
  47. package/dist/components/Polygon.svelte +27 -3
  48. package/dist/components/RadialGradient.svelte +3 -3
  49. package/dist/components/Rect.svelte +55 -5
  50. package/dist/components/Rect.svelte.d.ts +2 -2
  51. package/dist/components/RectClipPath.svelte +4 -3
  52. package/dist/components/RectClipPath.svelte.d.ts +2 -2
  53. package/dist/components/Rule.svelte +30 -23
  54. package/dist/components/Spline.svelte +29 -10
  55. package/dist/components/Text.svelte +59 -13
  56. package/dist/components/TileImage.svelte +19 -4
  57. package/dist/components/TransformContext.svelte +9 -3
  58. package/dist/components/TransformControls.svelte +72 -17
  59. package/dist/components/Voronoi.svelte +12 -13
  60. package/dist/components/charts/ArcChart.svelte +40 -69
  61. package/dist/components/charts/AreaChart.svelte +19 -42
  62. package/dist/components/charts/BarChart.svelte +7 -18
  63. package/dist/components/charts/DefaultTooltip.svelte +2 -2
  64. package/dist/components/charts/DefaultTooltip.svelte.d.ts +1 -1
  65. package/dist/components/charts/LineChart.svelte +61 -66
  66. package/dist/components/charts/LineChart.svelte.d.ts +11 -5
  67. package/dist/components/charts/PieChart.svelte +41 -69
  68. package/dist/components/charts/ScatterChart.svelte +8 -19
  69. package/dist/components/charts/utils.svelte.d.ts +1 -19
  70. package/dist/components/charts/utils.svelte.js +7 -39
  71. package/dist/components/layout/Canvas.svelte +29 -20
  72. package/dist/components/layout/Html.svelte +15 -9
  73. package/dist/components/layout/Svg.svelte +19 -11
  74. package/dist/components/layout/WebGL.svelte +26 -6
  75. package/dist/components/layout/WebGL.svelte.d.ts +5 -2
  76. package/dist/components/tooltip/Tooltip.svelte +60 -29
  77. package/dist/components/tooltip/TooltipContext.svelte +73 -36
  78. package/dist/components/tooltip/TooltipContext.svelte.d.ts +7 -0
  79. package/dist/components/tooltip/TooltipHeader.svelte +27 -14
  80. package/dist/components/tooltip/TooltipItem.svelte +41 -33
  81. package/dist/components/tooltip/TooltipList.svelte +12 -10
  82. package/dist/components/tooltip/TooltipSeparator.svelte +18 -10
  83. package/dist/states/series.svelte.d.ts +30 -0
  84. package/dist/states/series.svelte.js +54 -0
  85. package/dist/styles/daisyui-5.css +6 -0
  86. package/dist/styles/shadcn-svelte.css +11 -0
  87. package/dist/styles/skeleton-3.css +15 -0
  88. package/dist/utils/attributes.d.ts +3 -13
  89. package/dist/utils/attributes.js +4 -18
  90. package/dist/utils/common.d.ts +9 -0
  91. package/dist/utils/common.js +18 -1
  92. package/dist/utils/common.test.js +26 -1
  93. package/dist/utils/math.d.ts +17 -0
  94. package/dist/utils/math.js +17 -0
  95. package/dist/utils/types.d.ts +15 -2
  96. package/package.json +5 -1
@@ -56,7 +56,6 @@
56
56
  <script lang="ts">
57
57
  import { format as formatUtil, type FormatType, type FormatConfig } from '@layerstack/utils';
58
58
  import { cls } from '@layerstack/tailwind';
59
- import { layerClass } from '../../utils/attributes.js';
60
59
 
61
60
  let {
62
61
  ref: refProp = $bindable(),
@@ -89,25 +88,14 @@
89
88
  </script>
90
89
 
91
90
  <div
92
- class={cls(
93
- layerClass('tooltip-header'),
94
- 'font-semibold whitespace-nowrap border-b mb-1 pb-1 flex items-center gap-2',
95
- classes.root,
96
- props.root?.class,
97
- className
98
- )}
91
+ class={cls('lc-tooltip-header', classes.root, props.root?.class, className)}
99
92
  {...restProps}
100
93
  bind:this={ref}
101
94
  >
102
95
  {#if color}
103
96
  <div
104
97
  bind:this={colorRef}
105
- class={cls(
106
- layerClass('tooltip-header-color'),
107
- 'color',
108
- 'inline-block size-2 rounded-full bg-[var(--color)]',
109
- classes.color
110
- )}
98
+ class={cls('lc-tooltip-header-color', classes.color)}
111
99
  style:--color={color}
112
100
  ></div>
113
101
  {/if}
@@ -118,3 +106,28 @@
118
106
  {format ? formatUtil(value, asAny(format)) : value}
119
107
  {/if}
120
108
  </div>
109
+
110
+ <style>
111
+ @layer component {
112
+ :where(.lc-tooltip-header) {
113
+ font-weight: 600;
114
+ white-space: nowrap;
115
+ border-bottom: 1px solid
116
+ color-mix(in oklab, var(--color-surface-content, currentColor) 20%, transparent);
117
+ margin-bottom: 4px;
118
+ padding-bottom: 4px;
119
+ display: flex;
120
+ align-items: center;
121
+ gap: 8px;
122
+ }
123
+
124
+ :where(.lc-tooltip-header-color) {
125
+ display: inline-block;
126
+ width: 8px;
127
+ height: 8px;
128
+ border-radius: 9999px; /* rounded-full */
129
+ background-color: var(--color);
130
+ flex-shrink: 0;
131
+ }
132
+ }
133
+ </style>
@@ -78,7 +78,6 @@
78
78
  import { format as formatUtil, type FormatType, type FormatConfig } from '@layerstack/utils';
79
79
  import { cls } from '@layerstack/tailwind';
80
80
  import type { Snippet } from 'svelte';
81
- import { layerClass } from '../../utils/attributes.js';
82
81
 
83
82
  let {
84
83
  ref: refProp = $bindable(),
@@ -129,37 +128,19 @@
129
128
 
130
129
  <div
131
130
  {...props.root}
132
- class={cls(
133
- layerClass('tooltip-item-root'),
134
- 'contents',
135
- classes.root,
136
- className,
137
- props.root?.class
138
- )}
131
+ class={cls('lc-tooltip-item-root', classes.root, className, props.root?.class)}
139
132
  {...restProps}
140
133
  bind:this={ref}
141
134
  >
142
135
  <div
143
136
  {...props.label}
144
- class={cls(
145
- layerClass('tooltip-item-label'),
146
- 'label',
147
- 'flex items-center gap-2 whitespace-nowrap',
148
- classes.label,
149
- props.label?.class
150
- )}
137
+ class={cls('lc-tooltip-item-label', 'label', classes.label, props.label?.class)}
151
138
  bind:this={labelRef}
152
139
  >
153
140
  {#if color}
154
141
  <div
155
142
  {...props.color}
156
- class={cls(
157
- layerClass('tooltip-item-color'),
158
- 'color',
159
- 'inline-block size-2 rounded-full bg-[var(--color)]',
160
- classes.color,
161
- props.color?.class
162
- )}
143
+ class={cls('lc-tooltip-item-color', 'color', classes.color, props.color?.class)}
163
144
  style:--color={color}
164
145
  bind:this={colorRef}
165
146
  ></div>
@@ -174,17 +155,8 @@
174
155
  <div
175
156
  bind:this={valueRef}
176
157
  {...props.value}
177
- class={cls(
178
- layerClass('tooltip-item-value'),
179
- 'value',
180
- 'tabular-nums',
181
- {
182
- 'text-right': valueAlign === 'right',
183
- 'text-center': valueAlign === 'center',
184
- },
185
- classes.value,
186
- props.value?.class
187
- )}
158
+ class={cls('lc-tooltip-item-value', 'value', classes.value, props.value?.class)}
159
+ data-align={valueAlign}
188
160
  >
189
161
  {#if children}
190
162
  {@render children()}
@@ -194,3 +166,39 @@
194
166
  {/if}
195
167
  </div>
196
168
  </div>
169
+
170
+ <style>
171
+ @layer component {
172
+ :where(.lc-tooltip-item-root) {
173
+ display: contents;
174
+ }
175
+
176
+ :where(.lc-tooltip-item-color) {
177
+ display: inline-block;
178
+ width: 8px;
179
+ height: 8px;
180
+ border-radius: 9999px; /* full */
181
+ background-color: var(--color);
182
+ }
183
+
184
+ :where(.lc-tooltip-item-label) {
185
+ display: flex;
186
+ align-items: center;
187
+ gap: 8px;
188
+ white-space: nowrap;
189
+ }
190
+
191
+ :where(.lc-tooltip-item-value) {
192
+ /* tabular-nums */
193
+ font-variant-numeric: tabular-nums;
194
+
195
+ &[data-align='right'] {
196
+ text-align: right;
197
+ }
198
+
199
+ &[data-align='center'] {
200
+ text-align: center;
201
+ }
202
+ }
203
+ }
204
+ </style>
@@ -1,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import { cls } from '@layerstack/tailwind';
3
- import { layerClass } from '../../utils/attributes.js';
4
3
  import type { HTMLAttributes } from 'svelte/elements';
5
4
 
6
5
  let {
@@ -19,14 +18,17 @@
19
18
  });
20
19
  </script>
21
20
 
22
- <div
23
- bind:this={ref}
24
- class={cls(
25
- layerClass('tooltip-list'),
26
- 'grid grid-cols-[1fr_auto] gap-x-2 gap-y-1 items-start',
27
- className
28
- )}
29
- {...restProps}
30
- >
21
+ <div bind:this={ref} class={cls('lc-tooltip-list', className)} {...restProps}>
31
22
  {@render children?.()}
32
23
  </div>
24
+
25
+ <style>
26
+ @layer component {
27
+ :where(.lc-tooltip-list) {
28
+ display: grid;
29
+ grid-template-columns: 1fr auto;
30
+ gap: 4px 8px;
31
+ align-items: start;
32
+ }
33
+ }
34
+ </style>
@@ -1,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import { cls } from '@layerstack/tailwind';
3
- import { layerClass } from '../../utils/attributes.js';
4
3
  import type { HTMLAttributes } from 'svelte/elements';
5
4
 
6
5
  let {
@@ -18,14 +17,23 @@
18
17
  });
19
18
  </script>
20
19
 
21
- <div
22
- bind:this={ref}
23
- class={cls(
24
- layerClass('tooltip-separator'),
25
- 'rounded-sm bg-surface-content/20 my-1 col-span-full h-px',
26
- className
27
- )}
28
- {...restProps}
29
- >
20
+ <div bind:this={ref} class={cls('lc-tooltip-separator', className)} {...restProps}>
30
21
  {@render children?.()}
31
22
  </div>
23
+
24
+ <style>
25
+ @layer component {
26
+ :where(.lc-tooltip-separator) {
27
+ height: 1px;
28
+ border-radius: 4px;
29
+ background-color: color-mix(
30
+ in oklab,
31
+ var(--color-surface-content, currentColor) 20%,
32
+ transparent
33
+ );
34
+ margin-top: 4px;
35
+ margin-bottom: 4px;
36
+ grid-column: 1 / -1; /* col-span-full */
37
+ }
38
+ }
39
+ </style>
@@ -0,0 +1,30 @@
1
+ import type { Component } from 'svelte';
2
+ import type { SeriesData } from '../components/charts/types.js';
3
+ import { SelectionState } from '@layerstack/svelte-state';
4
+ declare class HighlightKey<TData, SeriesComponent extends Component> {
5
+ current: string | null;
6
+ set: (seriesKey: typeof this.current) => void;
7
+ }
8
+ export declare class SeriesState<TData, TComponent extends Component> {
9
+ #private;
10
+ selectedKeys: SelectionState<string, false>;
11
+ highlightKey: HighlightKey<TData, TComponent>;
12
+ constructor(getSeries: () => SeriesData<TData, TComponent>[]);
13
+ get series(): SeriesData<TData, TComponent>[];
14
+ get isDefaultSeries(): boolean;
15
+ get visibleSeries(): SeriesData<TData, TComponent>[];
16
+ /**
17
+ * Check if series is visible
18
+ */
19
+ isVisible(seriesKey: SeriesData<TData, TComponent>['key']): boolean;
20
+ /**
21
+ * Check if series is highlighted
22
+ * Changing default to `true` is useful to determine if series should be faded
23
+ */
24
+ isHighlighted(seriesKey: SeriesData<TData, TComponent>['key'], defaultValue?: boolean): boolean;
25
+ get allSeriesData(): Array<TData & {
26
+ seriesKey: string;
27
+ }>;
28
+ get allSeriesColors(): Array<NonNullable<SeriesData<TData, TComponent>["color"]>>;
29
+ }
30
+ export {};
@@ -0,0 +1,54 @@
1
+ import { SelectionState } from '@layerstack/svelte-state';
2
+ class HighlightKey {
3
+ current = $state(null);
4
+ set = (seriesKey) => {
5
+ this.current = seriesKey;
6
+ };
7
+ }
8
+ export class SeriesState {
9
+ #series = $state.raw([]);
10
+ selectedKeys = new SelectionState();
11
+ highlightKey = new HighlightKey();
12
+ constructor(getSeries) {
13
+ this.#series = getSeries();
14
+ $effect.pre(() => {
15
+ // keep series state in sync with the prop
16
+ this.#series = getSeries();
17
+ });
18
+ }
19
+ get series() {
20
+ return this.#series;
21
+ }
22
+ get isDefaultSeries() {
23
+ return this.#series.length === 1 && this.#series[0].key === 'default';
24
+ }
25
+ get visibleSeries() {
26
+ return this.#series.filter((s) => this.isVisible(s.key));
27
+ }
28
+ /**
29
+ * Check if series is visible
30
+ */
31
+ isVisible(seriesKey) {
32
+ return this.selectedKeys.isEmpty() || this.selectedKeys.isSelected(seriesKey);
33
+ }
34
+ /**
35
+ * Check if series is highlighted
36
+ * Changing default to `true` is useful to determine if series should be faded
37
+ */
38
+ isHighlighted(seriesKey, defaultValue = false) {
39
+ if (this.highlightKey.current === null) {
40
+ return defaultValue;
41
+ }
42
+ else {
43
+ return this.highlightKey.current === seriesKey;
44
+ }
45
+ }
46
+ get allSeriesData() {
47
+ return this.#series
48
+ .flatMap((s) => s.data?.map((d) => ({ seriesKey: s.key, ...d })))
49
+ .filter((d) => d);
50
+ }
51
+ get allSeriesColors() {
52
+ return this.#series.map((s) => s.color).filter((c) => c != null);
53
+ }
54
+ }
@@ -0,0 +1,6 @@
1
+ .lc-root-container {
2
+ --color-surface-100: var(--color-base-100);
3
+ --color-surface-200: var(--color-base-200);
4
+ --color-surface-300: var(--color-base-300);
5
+ --color-surface-content: var(--color-base-content);
6
+ }
@@ -0,0 +1,11 @@
1
+ /*
2
+ When NOT using shadcn-svelte Chart component.
3
+ Not typically needed even when using built-in Chart, as defaults typically are sufficient
4
+ */
5
+ .lc-root-container {
6
+ --color-primary: var(--primary);
7
+ --color-surface-100: var(--card-background);
8
+ --color-surface-200: var(--card-muted);
9
+ /* No direct mapping, should add explicit color (light and dark mode) */
10
+ --color-surface-content: var(--card-foreground);
11
+ }
@@ -0,0 +1,15 @@
1
+ .lc-root-container {
2
+ --color-primary: var(--color-primary-500);
3
+
4
+ --color-surface-100: var(--color-surface-50);
5
+ --color-surface-200: var(--color-surface-100);
6
+ --color-surface-300: var(--color-surface-200);
7
+ --color-surface-content: var(--base-font-color);
8
+
9
+ html.dark & {
10
+ --color-surface-100: var(--color-surface-700);
11
+ --color-surface-200: var(--color-surface-800);
12
+ --color-surface-300: var(--color-surface-900);
13
+ --color-surface-content: var(--base-font-color-dark);
14
+ }
15
+ }
@@ -1,14 +1,4 @@
1
- /**
2
- * Creates a string containing a class name that can be used by
3
- * developers to target a specific layer/element within a LayerChart.
4
- *
5
- * This is a function so that the class names remain consistent and the
6
- * prefix/structure can be changed in the future if needed
7
- *
8
- * @param layerName - the name of the layer to be appended to the generated class name
9
- * @returns a string to be used as a class on an element
10
- */
11
- export declare function layerClass(layerName: string): string;
1
+ import type { ClassValue } from 'svelte/elements';
12
2
  type ExtractObjectType<T> = T extends object ? (T extends Function ? never : T) : never;
13
3
  type WithClass<T> = T & {
14
4
  class?: string;
@@ -21,9 +11,9 @@ type DefaultProps = WithClass<{
21
11
  * a class name to its class property to identify the layer for CSS targeting.
22
12
  *
23
13
  * @param props The props to be extracted, can be an object, function or any other type
24
- * @param layerName The name of the layer used to apply a layer classname for targeting styling
14
+ * @param className The class name to be applied to the layer for targeting styling (e.g. 'lc-layer')
25
15
  * @param extraClasses Additional classes to be applied to the layer if they don't exist in the props already
26
16
  * @returns a typed spreadable object with props for the layer
27
17
  */
28
- export declare function extractLayerProps<T>(props: T, layerName: string, extraClasses?: string): WithClass<ExtractObjectType<T> extends never ? DefaultProps : ExtractObjectType<T>>;
18
+ export declare function extractLayerProps<T>(props: T, className: string, ...extraClasses: ClassValue[]): WithClass<ExtractObjectType<T> extends never ? DefaultProps : ExtractObjectType<T>>;
29
19
  export {};
@@ -1,17 +1,4 @@
1
1
  import { cls } from '@layerstack/tailwind';
2
- /**
3
- * Creates a string containing a class name that can be used by
4
- * developers to target a specific layer/element within a LayerChart.
5
- *
6
- * This is a function so that the class names remain consistent and the
7
- * prefix/structure can be changed in the future if needed
8
- *
9
- * @param layerName - the name of the layer to be appended to the generated class name
10
- * @returns a string to be used as a class on an element
11
- */
12
- export function layerClass(layerName) {
13
- return `lc-${layerName}`;
14
- }
15
2
  // type guard to narrow props to an object with optional class
16
3
  // for extractLayerProps
17
4
  function isObjectWithClass(val) {
@@ -22,19 +9,18 @@ function isObjectWithClass(val) {
22
9
  * a class name to its class property to identify the layer for CSS targeting.
23
10
  *
24
11
  * @param props The props to be extracted, can be an object, function or any other type
25
- * @param layerName The name of the layer used to apply a layer classname for targeting styling
12
+ * @param className The class name to be applied to the layer for targeting styling (e.g. 'lc-layer')
26
13
  * @param extraClasses Additional classes to be applied to the layer if they don't exist in the props already
27
14
  * @returns a typed spreadable object with props for the layer
28
15
  */
29
- export function extractLayerProps(props, layerName, extraClasses) {
30
- const className = layerClass(layerName);
16
+ export function extractLayerProps(props, className, ...extraClasses) {
31
17
  if (isObjectWithClass(props)) {
32
18
  return {
33
19
  ...props,
34
- class: cls(className, props.class ?? '', extraClasses),
20
+ class: cls(className, ...extraClasses, props.class),
35
21
  };
36
22
  }
37
23
  return {
38
- class: cls(className, extraClasses),
24
+ class: cls(className, ...extraClasses),
39
25
  };
40
26
  }
@@ -16,3 +16,12 @@ export declare function defaultChartPadding<TData, SeriesComponent extends Compo
16
16
  * Handles complex objects such as `Date` by invoking `.valueOf()`
17
17
  */
18
18
  export declare function findRelatedData(data: any[], original: any, accessor: Function): any;
19
+ /**
20
+ * Return the object if the value is an object, otherwise return null.
21
+ * Functions (including Snippet types) are treated as non-objects and return null.
22
+ */
23
+ export declare function getObjectOrNull<T>(value: T): T extends object ? T extends Function ? null : T : T extends null ? null : T extends undefined ? undefined : null;
24
+ /**
25
+ * Call with args if function, otherwise return the value.
26
+ */
27
+ export declare function resolveMaybeFn<T>(value: T | ((...args: any[]) => T), ...args: any[]): any;
@@ -40,7 +40,7 @@ export function defaultChartPadding(axis = true, legend = false) {
40
40
  return {
41
41
  top: axis === true || axis === 'y' ? 4 : 0,
42
42
  left: axis === true || axis === 'y' ? 20 : 0,
43
- bottom: (axis === true || axis === 'x' ? 20 : 0) + (legend === true ? 32 : 0),
43
+ bottom: (axis === true || axis === 'x' ? 20 : 0) + (legend ? 32 : 0),
44
44
  right: axis === true || axis === 'x' ? 4 : 0,
45
45
  };
46
46
  }
@@ -54,3 +54,20 @@ export function findRelatedData(data, original, accessor) {
54
54
  return accessor(d)?.valueOf() === accessor(original)?.valueOf();
55
55
  });
56
56
  }
57
+ /**
58
+ * Return the object if the value is an object, otherwise return null.
59
+ * Functions (including Snippet types) are treated as non-objects and return null.
60
+ */
61
+ export function getObjectOrNull(value) {
62
+ if (typeof value === 'object')
63
+ return value;
64
+ if (value === undefined)
65
+ return undefined;
66
+ return null;
67
+ }
68
+ /**
69
+ * Call with args if function, otherwise return the value.
70
+ */
71
+ export function resolveMaybeFn(value, ...args) {
72
+ return typeof value === 'function' ? value(...args) : value;
73
+ }
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { accessor } from './common.js';
2
+ import { accessor, resolveMaybeFn, getObjectOrNull } from './common.js';
3
3
  export const testData = {
4
4
  one: 1,
5
5
  two: 2,
@@ -36,3 +36,28 @@ describe('accessor', () => {
36
36
  expect(actual).toEqual(testData);
37
37
  });
38
38
  });
39
+ describe('getObjectOrNull', () => {
40
+ it('returns null for non-object values', () => {
41
+ expect(getObjectOrNull(5)).toBeNull();
42
+ expect(getObjectOrNull('string')).toBeNull();
43
+ expect(getObjectOrNull(null)).toBeNull();
44
+ expect(getObjectOrNull(undefined)).toBeUndefined();
45
+ });
46
+ it('returns null for functions', () => {
47
+ const fn = () => { };
48
+ expect(getObjectOrNull(fn)).toBeNull();
49
+ });
50
+ it('returns the object if value is an object', () => {
51
+ const obj = { a: 1 };
52
+ expect(getObjectOrNull(obj)).toBe(obj);
53
+ });
54
+ });
55
+ describe('resolveMaybeFn', () => {
56
+ it('returns value if not a function', () => {
57
+ expect(resolveMaybeFn(5)).toBe(5);
58
+ });
59
+ it('calls function with args', () => {
60
+ const fn = (a, b) => a + b;
61
+ expect(resolveMaybeFn(fn, 2, 3)).toBe(5);
62
+ });
63
+ });
@@ -23,6 +23,23 @@ export declare function cartesianToPolar(x: number, y: number): {
23
23
  radius: number;
24
24
  radians: number;
25
25
  };
26
+ /**
27
+ * Calculate the angle and length between two points
28
+ * @param point1 - First point
29
+ * @param point2 - Second point
30
+ * @returns Angle in degrees and length
31
+ */
32
+ export declare function pointsToAngleAndLength(point1: {
33
+ x: number;
34
+ y: number;
35
+ }, point2: {
36
+ x: number;
37
+ y: number;
38
+ }): {
39
+ radians: number;
40
+ angle: number;
41
+ length: number;
42
+ };
26
43
  /** Convert celsius temperature to fahrenheit */
27
44
  export declare function celsiusToFahrenheit(temperature: number): number;
28
45
  /** Convert fahrenheit temperature to celsius */
@@ -37,6 +37,23 @@ export function cartesianToPolar(x, y) {
37
37
  radians,
38
38
  };
39
39
  }
40
+ /**
41
+ * Calculate the angle and length between two points
42
+ * @param point1 - First point
43
+ * @param point2 - Second point
44
+ * @returns Angle in degrees and length
45
+ */
46
+ export function pointsToAngleAndLength(point1, point2) {
47
+ const dx = point2.x - point1.x;
48
+ const dy = point2.y - point1.y;
49
+ const radians = Math.atan2(dy, dx);
50
+ const length = Math.sqrt(dx * dx + dy * dy);
51
+ return {
52
+ radians,
53
+ angle: radiansToDegrees(radians),
54
+ length,
55
+ };
56
+ }
40
57
  /** Convert celsius temperature to fahrenheit */
41
58
  export function celsiusToFahrenheit(temperature) {
42
59
  return temperature * (9 / 5) + 32;
@@ -1,7 +1,8 @@
1
+ import type { MouseEventHandler, PointerEventHandler } from 'svelte/elements';
2
+ import type { TransitionConfig } from 'svelte/transition';
1
3
  import type { HierarchyNode } from 'd3-hierarchy';
2
- import type { AnyScale } from './scales.svelte.js';
3
4
  import type { SankeyGraph } from 'd3-sankey';
4
- import type { TransitionConfig } from 'svelte/transition';
5
+ import type { AnyScale } from './scales.svelte.js';
5
6
  /**
6
7
  * Useful to workaround Svelte 3/4 markup type issues
7
8
  * TODO: Remove usage after migrating to Svelte 5
@@ -79,6 +80,18 @@ export type CommonStyleProps = {
79
80
  */
80
81
  opacity?: number;
81
82
  };
83
+ /**
84
+ * Events for primatives which support `SVGRectElement` and `HTMLDivElement` elements based on render context
85
+ */
86
+ export type CommonEvents = {
87
+ onclick?: MouseEventHandler<Element> | null;
88
+ ondblclick?: MouseEventHandler<Element> | null;
89
+ onpointerenter?: PointerEventHandler<Element> | null;
90
+ onpointermove?: PointerEventHandler<Element> | null;
91
+ onpointerleave?: PointerEventHandler<Element> | null;
92
+ onpointerover?: PointerEventHandler<Element> | null;
93
+ onpointerout?: PointerEventHandler<Element> | null;
94
+ };
82
95
  export type OnlyObjects<T> = T extends object ? T : never;
83
96
  export type Getter<T> = () => T;
84
97
  export type GetterValues<T> = {
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.38",
7
+ "version": "2.0.0-next.39",
8
8
  "devDependencies": {
9
9
  "@changesets/cli": "^2.29.6",
10
10
  "@iconify-json/lucide": "^1.2.62",
@@ -109,6 +109,10 @@
109
109
  "types": "./dist/utils/*.d.ts",
110
110
  "svelte": "./dist/utils/*.js",
111
111
  "default": "./dist/utils/*.js"
112
+ },
113
+ "./*.css": {
114
+ "style": "./dist/styles/*.css",
115
+ "default": "./dist/styles/*.css"
112
116
  }
113
117
  },
114
118
  "files": [