layerchart 2.0.0-next.43 → 2.0.0-next.45

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 (179) hide show
  1. package/LICENSE +1 -1
  2. package/dist/components/AnnotationLine.svelte +1 -1
  3. package/dist/components/AnnotationPoint.svelte +1 -1
  4. package/dist/components/AnnotationRange.svelte +16 -15
  5. package/dist/components/Arc.svelte +10 -10
  6. package/dist/components/Arc.svelte.d.ts +4 -4
  7. package/dist/components/Arc.svelte.test.d.ts +1 -0
  8. package/dist/components/Arc.svelte.test.js +868 -0
  9. package/dist/components/Area.svelte +9 -7
  10. package/dist/components/Axis.svelte +2 -1
  11. package/dist/components/Axis.svelte.d.ts +1 -0
  12. package/dist/components/Bar.svelte +3 -3
  13. package/dist/components/Bars.svelte +1 -1
  14. package/dist/components/Blur.svelte +3 -3
  15. package/dist/components/Bounds.svelte +1 -1
  16. package/dist/components/BrushContext.svelte +1 -1
  17. package/dist/components/Calendar.svelte +2 -2
  18. package/dist/components/Calendar.svelte.d.ts +1 -1
  19. package/dist/components/Chart.svelte +63 -137
  20. package/dist/components/Chart.svelte.d.ts +23 -88
  21. package/dist/components/ChartClipPath.svelte +1 -1
  22. package/dist/components/Circle.svelte +17 -8
  23. package/dist/components/Circle.svelte.d.ts +3 -0
  24. package/dist/components/ClipPath.svelte +4 -4
  25. package/dist/components/Connector.svelte +4 -4
  26. package/dist/components/Connector.svelte.d.ts +3 -3
  27. package/dist/components/Ellipse.svelte +7 -7
  28. package/dist/components/Frame.svelte +1 -1
  29. package/dist/components/GeoContext.svelte +4 -20
  30. package/dist/components/GeoContext.svelte.d.ts +2 -6
  31. package/dist/components/GeoEdgeFade.svelte +1 -1
  32. package/dist/components/GeoPath.svelte +42 -107
  33. package/dist/components/GeoPath.svelte.d.ts +5 -4
  34. package/dist/components/GeoPoint.svelte +5 -5
  35. package/dist/components/GeoSpline.svelte +2 -14
  36. package/dist/components/GeoSpline.svelte.d.ts +1 -1
  37. package/dist/components/GeoTile.svelte +7 -6
  38. package/dist/components/GeoVisible.svelte +1 -1
  39. package/dist/components/Graticule.svelte +4 -7
  40. package/dist/components/Graticule.svelte.d.ts +2 -1
  41. package/dist/components/Grid.svelte +1 -1
  42. package/dist/components/Group.svelte +8 -8
  43. package/dist/components/Highlight.svelte +18 -16
  44. package/dist/components/Hull.svelte +2 -2
  45. package/dist/components/Labels.svelte +1 -1
  46. package/dist/components/Legend.svelte +1 -1
  47. package/dist/components/Line.svelte +9 -7
  48. package/dist/components/LinearGradient.svelte +8 -7
  49. package/dist/components/MonthPath.svelte +5 -11
  50. package/dist/components/MonthPath.svelte.d.ts +2 -2
  51. package/dist/components/Pack.svelte +4 -6
  52. package/dist/components/Pack.svelte.d.ts +2 -4
  53. package/dist/components/Partition.svelte +4 -3
  54. package/dist/components/Partition.svelte.d.ts +2 -1
  55. package/dist/components/Path.svelte +344 -0
  56. package/dist/components/Path.svelte.d.ts +72 -0
  57. package/dist/components/Pattern.svelte +6 -6
  58. package/dist/components/Pie.svelte +2 -2
  59. package/dist/components/Pie.svelte.d.ts +1 -1
  60. package/dist/components/Point.svelte +1 -1
  61. package/dist/components/Points.svelte +1 -1
  62. package/dist/components/Polygon.svelte +8 -6
  63. package/dist/components/RadialGradient.svelte +7 -7
  64. package/dist/components/Rect.svelte +32 -10
  65. package/dist/components/Rect.svelte.d.ts +4 -1
  66. package/dist/components/Rule.svelte +1 -1
  67. package/dist/components/Sankey.svelte +1 -1
  68. package/dist/components/Spline.svelte +13 -337
  69. package/dist/components/Spline.svelte.d.ts +10 -73
  70. package/dist/components/Text.svelte +9 -7
  71. package/dist/components/Threshold.svelte +3 -3
  72. package/dist/components/TransformContext.svelte +10 -143
  73. package/dist/components/TransformControls.svelte +2 -2
  74. package/dist/components/TransformControls.svelte.d.ts +1 -1
  75. package/dist/components/Tree.svelte +4 -3
  76. package/dist/components/Tree.svelte.d.ts +2 -1
  77. package/dist/components/Treemap.svelte +4 -3
  78. package/dist/components/Treemap.svelte.d.ts +2 -1
  79. package/dist/components/Voronoi.svelte +5 -5
  80. package/dist/components/charts/ArcChart.svelte +14 -6
  81. package/dist/components/charts/ArcChart.svelte.d.ts +1 -1
  82. package/dist/components/charts/AreaChart.svelte +12 -6
  83. package/dist/components/charts/BarChart.svelte +12 -6
  84. package/dist/components/charts/DefaultTooltip.svelte +1 -1
  85. package/dist/components/charts/LineChart.svelte +12 -6
  86. package/dist/components/charts/PieChart.svelte +14 -6
  87. package/dist/components/charts/PieChart.svelte.d.ts +1 -1
  88. package/dist/components/charts/ScatterChart.svelte +11 -9
  89. package/dist/components/charts/types.d.ts +7 -6
  90. package/dist/components/index.d.ts +14 -12
  91. package/dist/components/index.js +14 -12
  92. package/dist/components/{layout → layers}/Canvas.svelte +13 -60
  93. package/dist/components/{layout → layers}/Canvas.svelte.d.ts +2 -32
  94. package/dist/components/{layout → layers}/Html.svelte +18 -3
  95. package/dist/components/{layout → layers}/Html.svelte.d.ts +7 -0
  96. package/dist/components/layers/Layer.svelte +85 -0
  97. package/dist/components/{layout → layers}/Layer.svelte.d.ts +7 -3
  98. package/dist/components/{layout → layers}/Svg.svelte +18 -3
  99. package/dist/components/{layout → layers}/Svg.svelte.d.ts +7 -0
  100. package/dist/components/{layout → layers}/WebGL.svelte +1 -1
  101. package/dist/components/{layout → layers}/WebGL.svelte.d.ts +3 -3
  102. package/dist/components/tests/TestHarness.svelte +76 -0
  103. package/dist/components/tests/TestHarness.svelte.d.ts +19 -0
  104. package/dist/components/tooltip/Tooltip.svelte +3 -3
  105. package/dist/components/tooltip/Tooltip.svelte.d.ts +1 -1
  106. package/dist/components/tooltip/TooltipContext.svelte +13 -45
  107. package/dist/components/tooltip/TooltipContext.svelte.d.ts +2 -14
  108. package/dist/components/tooltip/tooltipMetaContext.d.ts +2 -2
  109. package/dist/components/tooltip/tooltipMetaContext.js +2 -2
  110. package/dist/contexts/canvas.d.ts +33 -0
  111. package/dist/contexts/canvas.js +14 -0
  112. package/dist/contexts/chart.d.ts +84 -0
  113. package/dist/contexts/chart.js +10 -0
  114. package/dist/contexts/geo.d.ts +6 -0
  115. package/dist/contexts/geo.js +12 -0
  116. package/dist/contexts/index.d.ts +6 -0
  117. package/dist/contexts/index.js +6 -0
  118. package/dist/contexts/layer.d.ts +3 -0
  119. package/dist/contexts/layer.js +8 -0
  120. package/dist/contexts/settings.d.ts +4 -0
  121. package/dist/contexts/settings.js +10 -0
  122. package/dist/contexts/tooltip.d.ts +15 -0
  123. package/dist/contexts/tooltip.js +8 -0
  124. package/dist/contexts/transform.d.ts +95 -0
  125. package/dist/contexts/transform.js +10 -0
  126. package/dist/index.d.ts +1 -0
  127. package/dist/index.js +1 -0
  128. package/dist/states/settings.svelte.d.ts +12 -0
  129. package/dist/states/settings.svelte.js +10 -0
  130. package/dist/states/transform.svelte.d.ts +9 -0
  131. package/dist/states/transform.svelte.js +31 -0
  132. package/dist/styles/skeleton-4.css +15 -0
  133. package/dist/utils/arcText.svelte.d.ts +1 -1
  134. package/dist/utils/canvas.d.ts +7 -3
  135. package/dist/utils/canvas.js +78 -11
  136. package/dist/utils/color.js +11 -8
  137. package/dist/utils/common.d.ts +8 -1
  138. package/dist/utils/common.js +9 -10
  139. package/dist/utils/index.d.ts +2 -0
  140. package/dist/utils/index.js +2 -0
  141. package/dist/utils/motion.svelte.js +0 -1
  142. package/dist/utils/rect.svelte.d.ts +1 -1
  143. package/dist/utils/rect.svelte.js +17 -9
  144. package/dist/utils/string.d.ts +3 -1
  145. package/package.json +32 -54
  146. package/README.md +0 -41
  147. package/dist/components/layout/Layer.svelte +0 -41
  148. package/dist/docs/Blockquote.svelte +0 -17
  149. package/dist/docs/Blockquote.svelte.d.ts +0 -5
  150. package/dist/docs/Code.svelte +0 -80
  151. package/dist/docs/Code.svelte.d.ts +0 -14
  152. package/dist/docs/ConnectorSweepMenuField.svelte +0 -17
  153. package/dist/docs/ConnectorSweepMenuField.svelte.d.ts +0 -7
  154. package/dist/docs/ConnectorTypeMenuField.svelte +0 -17
  155. package/dist/docs/ConnectorTypeMenuField.svelte.d.ts +0 -7
  156. package/dist/docs/CurveMenuField.svelte +0 -44
  157. package/dist/docs/CurveMenuField.svelte.d.ts +0 -9
  158. package/dist/docs/GeoDebug.svelte +0 -60
  159. package/dist/docs/GeoDebug.svelte.d.ts +0 -4
  160. package/dist/docs/Header1.svelte +0 -16
  161. package/dist/docs/Header1.svelte.d.ts +0 -5
  162. package/dist/docs/Json.svelte +0 -36
  163. package/dist/docs/Json.svelte.d.ts +0 -10
  164. package/dist/docs/Layout.svelte +0 -21
  165. package/dist/docs/Layout.svelte.d.ts +0 -8
  166. package/dist/docs/Link.svelte +0 -9
  167. package/dist/docs/Link.svelte.d.ts +0 -5
  168. package/dist/docs/PathDataMenuField.svelte +0 -78
  169. package/dist/docs/PathDataMenuField.svelte.d.ts +0 -9
  170. package/dist/docs/Preview.svelte +0 -104
  171. package/dist/docs/Preview.svelte.d.ts +0 -13
  172. package/dist/docs/TilesetField.svelte +0 -136
  173. package/dist/docs/TilesetField.svelte.d.ts +0 -6
  174. package/dist/docs/TransformDebug.svelte +0 -22
  175. package/dist/docs/TransformDebug.svelte.d.ts +0 -20
  176. package/dist/docs/ViewSourceButton.svelte +0 -53
  177. package/dist/docs/ViewSourceButton.svelte.d.ts +0 -11
  178. /package/dist/{utils → contexts}/legendPayload.d.ts +0 -0
  179. /package/dist/{utils → contexts}/legendPayload.js +0 -0
@@ -0,0 +1,868 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { render } from 'vitest-browser-svelte';
3
+ import { page } from 'vitest/browser';
4
+ import TestHarness, { componentTestId } from './tests/TestHarness.svelte';
5
+ import Arc from './Arc.svelte';
6
+ import Text from './Text.svelte';
7
+ const defaultProps = {
8
+ fill: 'currentColor',
9
+ };
10
+ let el; // resuable
11
+ describe(`Arc`, () => {
12
+ it('should render Arc element', async () => {
13
+ render(TestHarness, {
14
+ component: Arc,
15
+ componentProps: {
16
+ ...defaultProps,
17
+ value: 50,
18
+ },
19
+ });
20
+ el = page.getByTestId(componentTestId);
21
+ await expect.element(el).toBeInTheDocument();
22
+ });
23
+ it('should render track', async () => {
24
+ render(TestHarness, {
25
+ component: Arc,
26
+ componentProps: {
27
+ ...defaultProps,
28
+ value: 50,
29
+ track: { class: 'fill-none stroke-surface-content/10', 'data-testid': 'arc-track' },
30
+ },
31
+ });
32
+ el = page.getByTestId('arc-track');
33
+ await expect.element(el).toBeInTheDocument();
34
+ });
35
+ describe('props', () => {
36
+ // value
37
+ it('should render an arc path with value', async () => {
38
+ render(TestHarness, {
39
+ component: Arc,
40
+ componentProps: {
41
+ ...defaultProps,
42
+ value: 50,
43
+ },
44
+ });
45
+ el = page.getByTestId(componentTestId).first();
46
+ await expect.element(el).toBeInTheDocument();
47
+ const d = el.element()?.getAttribute('d');
48
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
49
+ });
50
+ // domain
51
+ it('should render with custom domain', async () => {
52
+ render(TestHarness, {
53
+ component: Arc,
54
+ componentProps: {
55
+ ...defaultProps,
56
+ value: 50,
57
+ domain: [0, 200],
58
+ },
59
+ });
60
+ el = page.getByTestId(componentTestId).first();
61
+ await expect.element(el).toBeInTheDocument();
62
+ const d = el.element()?.getAttribute('d');
63
+ // 50 out of 200 = 25% of 360 = 90 degrees
64
+ expect(d).toBe('M0,-150A150,150,0,0,1,150,0L0,0Z');
65
+ });
66
+ // range
67
+ it('should render with custom range', async () => {
68
+ render(TestHarness, {
69
+ component: Arc,
70
+ componentProps: {
71
+ ...defaultProps,
72
+ value: 50,
73
+ range: [0, 180],
74
+ },
75
+ });
76
+ el = page.getByTestId(componentTestId).first();
77
+ await expect.element(el).toBeInTheDocument();
78
+ const d = el.element()?.getAttribute('d');
79
+ // 50% of 180 degrees = 90 degrees
80
+ expect(d).toBe('M0,-150A150,150,0,0,1,150,0L0,0Z');
81
+ });
82
+ it('should render with custom domain and range', async () => {
83
+ render(TestHarness, {
84
+ component: Arc,
85
+ componentProps: {
86
+ ...defaultProps,
87
+ value: 25,
88
+ domain: [0, 50],
89
+ range: [0, 180],
90
+ },
91
+ });
92
+ el = page.getByTestId(componentTestId).first();
93
+ await expect.element(el).toBeInTheDocument();
94
+ const d = el.element()?.getAttribute('d');
95
+ expect(d).toBe('M0,-150A150,150,0,0,1,150,0L0,0Z');
96
+ });
97
+ it('should handle custom start angle in range', async () => {
98
+ render(TestHarness, {
99
+ component: Arc,
100
+ componentProps: {
101
+ ...defaultProps,
102
+ value: 50,
103
+ range: [90, 270],
104
+ },
105
+ });
106
+ const el = page.getByTestId(componentTestId);
107
+ await expect.element(el).toBeInTheDocument();
108
+ const d = el.element()?.getAttribute('d');
109
+ expect(d).toBe('M150,0A150,150,0,0,1,0,150L0,0Z');
110
+ });
111
+ // startAngle
112
+ it('should render with startAngle in radians', async () => {
113
+ render(TestHarness, {
114
+ component: Arc,
115
+ componentProps: {
116
+ ...defaultProps,
117
+ value: 50,
118
+ startAngle: Math.PI / 2, // 90 degrees
119
+ },
120
+ });
121
+ el = page.getByTestId(componentTestId).first();
122
+ await expect.element(el).toBeInTheDocument();
123
+ const d = el.element()?.getAttribute('d');
124
+ // Arc starts at 90 degrees (pointing right), value=50 maps to 180 degrees of arc
125
+ expect(d).toBe('M150,0A150,150,0,0,1,0,150L0,0Z');
126
+ });
127
+ // endAngle
128
+ it('should render with endAngle in radians', async () => {
129
+ render(TestHarness, {
130
+ component: Arc,
131
+ componentProps: {
132
+ ...defaultProps,
133
+ value: 50,
134
+ endAngle: Math.PI, // 180 degrees, overrides value-based calculation
135
+ },
136
+ });
137
+ el = page.getByTestId(componentTestId).first();
138
+ await expect.element(el).toBeInTheDocument();
139
+ const d = el.element()?.getAttribute('d');
140
+ // endAngle overrides value, arc ends at 180 degrees
141
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
142
+ });
143
+ it('should render with both startAngle and endAngle', async () => {
144
+ render(TestHarness, {
145
+ component: Arc,
146
+ componentProps: {
147
+ ...defaultProps,
148
+ value: 50,
149
+ startAngle: 0,
150
+ endAngle: Math.PI / 2, // 90 degree arc
151
+ },
152
+ });
153
+ el = page.getByTestId(componentTestId).first();
154
+ await expect.element(el).toBeInTheDocument();
155
+ const d = el.element()?.getAttribute('d');
156
+ expect(d).toBe('M0,-150A150,150,0,0,1,150,0L0,0Z');
157
+ });
158
+ // innerRadius
159
+ it('should render with innerRadius', async () => {
160
+ render(TestHarness, {
161
+ component: Arc,
162
+ componentProps: {
163
+ ...defaultProps,
164
+ value: 50,
165
+ innerRadius: 50,
166
+ },
167
+ });
168
+ el = page.getByTestId(componentTestId).first();
169
+ await expect.element(el).toBeInTheDocument();
170
+ const d = el.element()?.getAttribute('d');
171
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150L0,50A50,50,0,1,0,0,-50Z');
172
+ });
173
+ // outerRadius
174
+ it('should render with outerRadius', async () => {
175
+ render(TestHarness, {
176
+ component: Arc,
177
+ componentProps: {
178
+ ...defaultProps,
179
+ value: 50,
180
+ outerRadius: 100,
181
+ },
182
+ });
183
+ el = page.getByTestId(componentTestId).first();
184
+ await expect.element(el).toBeInTheDocument();
185
+ const d = el.element()?.getAttribute('d');
186
+ expect(d).toBe('M0,-100A100,100,0,1,1,0,100L0,0Z');
187
+ });
188
+ it('should render with innerRadius and outerRadius', async () => {
189
+ render(TestHarness, {
190
+ component: Arc,
191
+ componentProps: {
192
+ ...defaultProps,
193
+ value: 75,
194
+ innerRadius: 30,
195
+ outerRadius: 50,
196
+ },
197
+ });
198
+ el = page.getByTestId(componentTestId).first();
199
+ await expect.element(el).toBeInTheDocument();
200
+ const d = el.element()?.getAttribute('d');
201
+ expect(d).toBe('M0,-50A50,50,0,1,1,-50,0L-30,0A30,30,0,1,0,0,-30Z');
202
+ });
203
+ // cornerRadius
204
+ it('should render with cornerRadius', async () => {
205
+ render(TestHarness, {
206
+ component: Arc,
207
+ componentProps: {
208
+ ...defaultProps,
209
+ value: 50,
210
+ cornerRadius: 5,
211
+ },
212
+ });
213
+ el = page.getByTestId(componentTestId).first();
214
+ await expect.element(el).toBeInTheDocument();
215
+ const d = el.element()?.getAttribute('d');
216
+ expect(d).toBe('M0,-144.914A5,5,0,0,1,5.172,-149.911A150,150,0,0,1,5.172,149.911A5,5,0,0,1,0,144.914L0,0Z');
217
+ });
218
+ // padAngle
219
+ it('should render with padAngle', async () => {
220
+ render(TestHarness, {
221
+ component: Arc,
222
+ componentProps: {
223
+ ...defaultProps,
224
+ value: 50,
225
+ padAngle: 0.02,
226
+ },
227
+ });
228
+ el = page.getByTestId(componentTestId).first();
229
+ await expect.element(el).toBeInTheDocument();
230
+ const d = el?.element()?.getAttribute('d');
231
+ expect(d).toBe('M1.5,-149.993A150,150,0,0,1,1.5,149.993L0,0Z');
232
+ });
233
+ // trackStartAngle
234
+ it('should render track with trackStartAngle', async () => {
235
+ render(TestHarness, {
236
+ component: Arc,
237
+ componentProps: {
238
+ ...defaultProps,
239
+ value: 50,
240
+ track: { 'data-testid': 'arc-track' },
241
+ trackStartAngle: Math.PI / 2, // 90 degrees
242
+ },
243
+ });
244
+ el = page.getByTestId('arc-track');
245
+ await expect.element(el).toBeInTheDocument();
246
+ const d = el.element()?.getAttribute('d');
247
+ // Track starts at 90 degrees (right), ends at default 360 degrees (top)
248
+ expect(d).toBe('M150,0A150,150,0,1,1,0,-150L0,0Z');
249
+ });
250
+ // trackEndAngle
251
+ it('should render track with trackEndAngle', async () => {
252
+ render(TestHarness, {
253
+ component: Arc,
254
+ componentProps: {
255
+ ...defaultProps,
256
+ value: 50,
257
+ track: { 'data-testid': 'arc-track' },
258
+ trackEndAngle: Math.PI, // 180 degrees
259
+ },
260
+ });
261
+ el = page.getByTestId('arc-track');
262
+ await expect.element(el).toBeInTheDocument();
263
+ const d = el.element()?.getAttribute('d');
264
+ // Track ends at 180 degrees
265
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
266
+ });
267
+ it('should render track with trackStartAngle and trackEndAngle', async () => {
268
+ render(TestHarness, {
269
+ component: Arc,
270
+ componentProps: {
271
+ ...defaultProps,
272
+ value: 50,
273
+ track: { 'data-testid': 'arc-track' },
274
+ trackStartAngle: 0,
275
+ trackEndAngle: Math.PI,
276
+ },
277
+ });
278
+ el = page.getByTestId('arc-track');
279
+ await expect.element(el).toBeInTheDocument();
280
+ const d = el.element()?.getAttribute('d');
281
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
282
+ });
283
+ // trackInnerRadius
284
+ it('should render track with trackInnerRadius', async () => {
285
+ render(TestHarness, {
286
+ component: Arc,
287
+ componentProps: {
288
+ ...defaultProps,
289
+ value: 50,
290
+ track: { 'data-testid': 'arc-track' },
291
+ trackInnerRadius: 50,
292
+ },
293
+ });
294
+ el = page.getByTestId('arc-track');
295
+ await expect.element(el).toBeInTheDocument();
296
+ const d = el.element()?.getAttribute('d');
297
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150A150,150,0,1,1,0,-150M0,-50A50,50,0,1,0,0,50A50,50,0,1,0,0,-50Z');
298
+ });
299
+ // trackOuterRadius
300
+ it('should render track with trackOuterRadius', async () => {
301
+ render(TestHarness, {
302
+ component: Arc,
303
+ componentProps: {
304
+ ...defaultProps,
305
+ value: 50,
306
+ track: { 'data-testid': 'arc-track' },
307
+ trackOuterRadius: 100,
308
+ },
309
+ });
310
+ el = page.getByTestId('arc-track');
311
+ await expect.element(el).toBeInTheDocument();
312
+ const d = el.element()?.getAttribute('d');
313
+ expect(d).toBe('M0,-100A100,100,0,1,1,0,100A100,100,0,1,1,0,-100Z');
314
+ });
315
+ it('should render track with trackInnerRadius and trackOuterRadius', async () => {
316
+ render(TestHarness, {
317
+ component: Arc,
318
+ componentProps: {
319
+ ...defaultProps,
320
+ value: 50,
321
+ track: { 'data-testid': 'arc-track' },
322
+ trackInnerRadius: 20,
323
+ trackOuterRadius: 60,
324
+ },
325
+ });
326
+ el = page.getByTestId('arc-track');
327
+ await expect.element(el).toBeInTheDocument();
328
+ const d = el.element()?.getAttribute('d');
329
+ expect(d).toBe('M0,-60A60,60,0,1,1,0,60A60,60,0,1,1,0,-60M0,-20A20,20,0,1,0,0,20A20,20,0,1,0,0,-20Z');
330
+ });
331
+ // trackCornerRadius
332
+ it('should render track with trackCornerRadius', async () => {
333
+ render(TestHarness, {
334
+ component: Arc,
335
+ componentProps: {
336
+ ...defaultProps,
337
+ value: 50,
338
+ track: { 'data-testid': 'arc-track' },
339
+ trackStartAngle: 0,
340
+ trackEndAngle: Math.PI, // half circle to make corner radius visible
341
+ trackCornerRadius: 10,
342
+ },
343
+ });
344
+ el = page.getByTestId('arc-track');
345
+ await expect.element(el).toBeInTheDocument();
346
+ const d = el.element()?.getAttribute('d');
347
+ // With corner radius, the path should have additional curve commands
348
+ expect(d).toContain('A10,10');
349
+ });
350
+ // trackPadAngle
351
+ it('should render track with trackPadAngle', async () => {
352
+ render(TestHarness, {
353
+ component: Arc,
354
+ componentProps: {
355
+ ...defaultProps,
356
+ value: 50,
357
+ track: { 'data-testid': 'arc-track' },
358
+ trackInnerRadius: 50,
359
+ trackStartAngle: 0,
360
+ trackEndAngle: Math.PI, // half circle so padAngle has visible effect
361
+ trackPadAngle: 0.1,
362
+ },
363
+ });
364
+ el = page.getByTestId('arc-track');
365
+ await expect.element(el).toBeInTheDocument();
366
+ const d = el.element()?.getAttribute('d');
367
+ // With pad angle, the arc path coordinates should be offset from start
368
+ expect(d).toContain('A150,150');
369
+ expect(d).toContain('A50,50');
370
+ // The start coordinates should not be exactly at 0,-150 due to padding
371
+ expect(d).not.toMatch(/^M0,-150/);
372
+ });
373
+ // offset
374
+ it('should apply offset to arc position', async () => {
375
+ render(TestHarness, {
376
+ component: Arc,
377
+ componentProps: {
378
+ ...defaultProps,
379
+ value: 50,
380
+ offset: 10,
381
+ },
382
+ });
383
+ const el = page.getByTestId(componentTestId);
384
+ await expect.element(el).toBeInTheDocument();
385
+ const transform = el.element()?.getAttribute('transform');
386
+ expect(transform).toContain('translate(-4.539904997395462, 8.91006524188368)');
387
+ });
388
+ it('should apply zero offset by default', async () => {
389
+ render(TestHarness, {
390
+ component: Arc,
391
+ componentProps: {
392
+ ...defaultProps,
393
+ value: 50,
394
+ },
395
+ });
396
+ const el = page.getByTestId(componentTestId);
397
+ await expect.element(el).toBeInTheDocument();
398
+ const transform = el.element()?.getAttribute('transform');
399
+ expect(transform).toBe('translate(0, 0)');
400
+ });
401
+ // track
402
+ it('should render track when track prop is provided', async () => {
403
+ render(TestHarness, {
404
+ component: Arc,
405
+ componentProps: {
406
+ ...defaultProps,
407
+ value: 50,
408
+ track: { 'data-testid': 'arc-track' },
409
+ },
410
+ });
411
+ el = page.getByTestId('arc-track');
412
+ await expect.element(el).toBeInTheDocument();
413
+ const d = el.element()?.getAttribute('d');
414
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150A150,150,0,1,1,0,-150Z');
415
+ });
416
+ it('should render track with custom class', async () => {
417
+ render(TestHarness, {
418
+ component: Arc,
419
+ componentProps: {
420
+ ...defaultProps,
421
+ value: 50,
422
+ track: { class: 'fill-none stroke-surface-content/10', 'data-testid': 'arc-track' },
423
+ },
424
+ });
425
+ const el = page.getByTestId('arc-track');
426
+ await expect.element(el).toBeInTheDocument();
427
+ await expect.element(el).toHaveClass('fill-none');
428
+ await expect.element(el).toHaveClass('stroke-surface-content/10');
429
+ });
430
+ // tooltipContext + data
431
+ it('should call tooltipContext.show on pointer enter with data', async () => {
432
+ const mockTooltipContext = {
433
+ show: vi.fn(),
434
+ hide: vi.fn(),
435
+ x: 0,
436
+ y: 0,
437
+ data: null,
438
+ payload: [],
439
+ mode: 'manual',
440
+ isHoveringTooltipArea: false,
441
+ isHoveringTooltipContent: false,
442
+ };
443
+ const testData = { label: 'Test', value: 50 };
444
+ render(TestHarness, {
445
+ component: Arc,
446
+ componentProps: {
447
+ ...defaultProps,
448
+ value: 50,
449
+ fill: 'blue',
450
+ tooltipContext: mockTooltipContext,
451
+ data: testData,
452
+ },
453
+ });
454
+ const el = page.getByTestId(componentTestId);
455
+ await expect.element(el).toBeInTheDocument();
456
+ await el.hover();
457
+ expect(mockTooltipContext.show).toHaveBeenCalled();
458
+ expect(mockTooltipContext.show.mock.calls[0][1]).toEqual(testData);
459
+ });
460
+ it('should call tooltipContext.hide on pointer leave', async () => {
461
+ const mockTooltipContext = {
462
+ show: vi.fn(),
463
+ hide: vi.fn(),
464
+ x: 0,
465
+ y: 0,
466
+ data: null,
467
+ payload: [],
468
+ mode: 'manual',
469
+ isHoveringTooltipArea: false,
470
+ isHoveringTooltipContent: false,
471
+ };
472
+ render(TestHarness, {
473
+ component: Arc,
474
+ componentProps: {
475
+ ...defaultProps,
476
+ value: 50,
477
+ fill: 'blue',
478
+ tooltipContext: mockTooltipContext,
479
+ data: { value: 50 },
480
+ },
481
+ });
482
+ const el = page.getByTestId(componentTestId);
483
+ await expect.element(el).toBeInTheDocument();
484
+ await el.hover();
485
+ // Move away from the element to trigger pointer leave
486
+ await page.getByTestId('test-lc-chart').hover({ position: { x: 0, y: 0 } });
487
+ expect(mockTooltipContext.hide).toHaveBeenCalled();
488
+ });
489
+ // fill
490
+ it('should apply fill color', async () => {
491
+ render(TestHarness, {
492
+ component: Arc,
493
+ componentProps: {
494
+ ...defaultProps,
495
+ value: 50,
496
+ fill: 'red',
497
+ },
498
+ });
499
+ const el = page.getByTestId(componentTestId);
500
+ await expect.element(el).toHaveAttribute('fill', 'red');
501
+ });
502
+ // fillOpacity
503
+ it('should apply fillOpacity', async () => {
504
+ render(TestHarness, {
505
+ component: Arc,
506
+ componentProps: {
507
+ ...defaultProps,
508
+ value: 50,
509
+ fillOpacity: 0.7,
510
+ },
511
+ });
512
+ const el = page.getByTestId(componentTestId);
513
+ await expect.element(el).toBeInTheDocument();
514
+ await expect.element(el).toHaveAttribute('fill-opacity', '0.7');
515
+ });
516
+ // stroke
517
+ it('should have stroke="none" by default', async () => {
518
+ render(TestHarness, {
519
+ component: Arc,
520
+ componentProps: {
521
+ ...defaultProps,
522
+ value: 50,
523
+ },
524
+ });
525
+ const el = page.getByTestId(componentTestId);
526
+ await expect.element(el).toBeInTheDocument();
527
+ await expect.element(el).toHaveAttribute('stroke', 'none');
528
+ });
529
+ it('should apply stroke color', async () => {
530
+ render(TestHarness, {
531
+ component: Arc,
532
+ componentProps: {
533
+ ...defaultProps,
534
+ value: 50,
535
+ stroke: 'blue',
536
+ },
537
+ });
538
+ const el = page.getByTestId(componentTestId);
539
+ await expect.element(el).toBeInTheDocument();
540
+ await expect.element(el).toHaveAttribute('stroke', 'blue');
541
+ });
542
+ // strokeWidth
543
+ it('should apply strokeWidth', async () => {
544
+ render(TestHarness, {
545
+ component: Arc,
546
+ componentProps: {
547
+ ...defaultProps,
548
+ value: 50,
549
+ stroke: 'blue',
550
+ strokeWidth: 3,
551
+ },
552
+ });
553
+ const el = page.getByTestId(componentTestId);
554
+ await expect.element(el).toBeInTheDocument();
555
+ await expect.element(el).toHaveAttribute('stroke-width', '3');
556
+ });
557
+ // opacity
558
+ it('should apply opacity', async () => {
559
+ render(TestHarness, {
560
+ component: Arc,
561
+ componentProps: {
562
+ ...defaultProps,
563
+ value: 50,
564
+ opacity: 0.5,
565
+ },
566
+ });
567
+ const el = page.getByTestId(componentTestId);
568
+ await expect.element(el).toBeInTheDocument();
569
+ await expect.element(el).toHaveAttribute('opacity', '0.5');
570
+ });
571
+ // class
572
+ it('should apply custom class', async () => {
573
+ render(TestHarness, {
574
+ component: Arc,
575
+ componentProps: {
576
+ ...defaultProps,
577
+ value: 50,
578
+ class: 'custom-arc-class',
579
+ },
580
+ });
581
+ const el = page.getByTestId(componentTestId);
582
+ await expect.element(el).toBeInTheDocument();
583
+ await expect.element(el).toHaveClass('custom-arc-class');
584
+ });
585
+ });
586
+ describe('events', () => {
587
+ it('should handle pointer enter events', async () => {
588
+ const onPointerEnter = vi.fn();
589
+ render(TestHarness, {
590
+ component: Arc,
591
+ componentProps: {
592
+ ...defaultProps,
593
+ value: 50,
594
+ onpointerenter: onPointerEnter,
595
+ fill: 'blue',
596
+ },
597
+ });
598
+ const el = page.getByTestId(componentTestId);
599
+ await expect.element(el).toBeInTheDocument();
600
+ await el.hover();
601
+ expect(onPointerEnter).toHaveBeenCalled();
602
+ });
603
+ it('should handle pointer move events', async () => {
604
+ const onPointerMove = vi.fn();
605
+ render(TestHarness, {
606
+ component: Arc,
607
+ componentProps: {
608
+ ...defaultProps,
609
+ value: 50,
610
+ onpointermove: onPointerMove,
611
+ fill: 'blue',
612
+ },
613
+ });
614
+ const el = page.getByTestId(componentTestId);
615
+ await expect.element(el).toBeInTheDocument();
616
+ await el.hover();
617
+ expect(onPointerMove).toHaveBeenCalled();
618
+ });
619
+ it('should handle touch move events', async () => {
620
+ const onTouchMove = vi.fn();
621
+ render(TestHarness, {
622
+ component: Arc,
623
+ componentProps: {
624
+ ...defaultProps,
625
+ value: 50,
626
+ ontouchmove: onTouchMove,
627
+ },
628
+ });
629
+ const el = page.getByTestId(componentTestId);
630
+ await expect.element(el).toBeInTheDocument();
631
+ const element = el.element();
632
+ element.dispatchEvent(new TouchEvent('touchmove', { bubbles: true }));
633
+ expect(onTouchMove).toHaveBeenCalled();
634
+ });
635
+ });
636
+ describe('edge cases', () => {
637
+ it('should handle value of 0', async () => {
638
+ render(TestHarness, {
639
+ component: Arc,
640
+ componentProps: {
641
+ ...defaultProps,
642
+ value: 0,
643
+ },
644
+ });
645
+ const el = page.getByTestId(componentTestId);
646
+ await expect.element(el).toBeInTheDocument();
647
+ const d = el.element()?.getAttribute('d');
648
+ expect(d).toBe('M0,-150L0,0Z');
649
+ });
650
+ it('should handle value at max domain', async () => {
651
+ render(TestHarness, {
652
+ component: Arc,
653
+ componentProps: {
654
+ ...defaultProps,
655
+ value: 100,
656
+ domain: [0, 100],
657
+ },
658
+ });
659
+ const el = page.getByTestId(componentTestId);
660
+ await expect.element(el).toBeInTheDocument();
661
+ const d = el.element()?.getAttribute('d');
662
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150A150,150,0,1,1,0,-150Z');
663
+ });
664
+ it('should handle negative domain values', async () => {
665
+ render(TestHarness, {
666
+ component: Arc,
667
+ componentProps: {
668
+ ...defaultProps,
669
+ value: 0,
670
+ domain: [-50, 50],
671
+ },
672
+ });
673
+ const el = page.getByTestId(componentTestId);
674
+ await expect.element(el).toBeInTheDocument();
675
+ const d = el.element()?.getAttribute('d');
676
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
677
+ });
678
+ it('should handle innerRadius of 0 (pie slice)', async () => {
679
+ render(TestHarness, {
680
+ component: Arc,
681
+ componentProps: {
682
+ ...defaultProps,
683
+ value: 50,
684
+ innerRadius: 0,
685
+ },
686
+ });
687
+ const el = page.getByTestId(componentTestId);
688
+ await expect.element(el).toBeInTheDocument();
689
+ const d = el.element()?.getAttribute('d');
690
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
691
+ });
692
+ it('should handle full circle (360 degree range)', async () => {
693
+ render(TestHarness, {
694
+ component: Arc,
695
+ componentProps: {
696
+ ...defaultProps,
697
+ value: 100,
698
+ domain: [0, 100],
699
+ range: [0, 360],
700
+ },
701
+ });
702
+ const el = page.getByTestId(componentTestId);
703
+ await expect.element(el).toBeInTheDocument();
704
+ const d = el.element()?.getAttribute('d');
705
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150A150,150,0,1,1,0,-150Z');
706
+ });
707
+ it('should handle partial arc (e.g., 180 degrees)', async () => {
708
+ render(TestHarness, {
709
+ component: Arc,
710
+ componentProps: {
711
+ ...defaultProps,
712
+ value: 100,
713
+ domain: [0, 100],
714
+ range: [0, 180],
715
+ },
716
+ });
717
+ const el = page.getByTestId(componentTestId);
718
+ await expect.element(el).toBeInTheDocument();
719
+ const d = el.element()?.getAttribute('d');
720
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
721
+ });
722
+ it('should handle value exceeding domain max', async () => {
723
+ render(TestHarness, {
724
+ component: Arc,
725
+ componentProps: {
726
+ ...defaultProps,
727
+ value: 150,
728
+ domain: [0, 100],
729
+ },
730
+ });
731
+ const el = page.getByTestId(componentTestId);
732
+ await expect.element(el).toBeInTheDocument();
733
+ const d = el.element()?.getAttribute('d');
734
+ expect(d).toBe('M0,-150A150,150,0,1,1,0,150A150,150,0,1,1,0,-150Z');
735
+ });
736
+ it('should handle value below domain min', async () => {
737
+ render(TestHarness, {
738
+ component: Arc,
739
+ componentProps: {
740
+ ...defaultProps,
741
+ value: -10,
742
+ domain: [0, 100],
743
+ },
744
+ });
745
+ const el = page.getByTestId(componentTestId);
746
+ await expect.element(el).toBeInTheDocument();
747
+ const d = el.element()?.getAttribute('d');
748
+ expect(d).toBe('M0,-150A150,150,0,0,0,-88.168,-121.353L0,0Z');
749
+ });
750
+ });
751
+ describe('snippets', () => {
752
+ it('should render text inner, middle, outer Text children', async () => {
753
+ render(TestHarness, {
754
+ chartProps: {
755
+ height: 400,
756
+ padding: '50',
757
+ },
758
+ component: Arc,
759
+ componentProps: {
760
+ ...defaultProps,
761
+ fill: 'blue',
762
+ value: 50,
763
+ innerRadius: 70,
764
+ outerRadius: 140,
765
+ cornerRadius: 8,
766
+ },
767
+ childComponents: [
768
+ {
769
+ component: Text,
770
+ props: ({ getArcTextProps }) => ({
771
+ ...getArcTextProps('inner'),
772
+ 'data-testid': 'inner-text',
773
+ value: 'Inner',
774
+ class: 'text-lg',
775
+ }),
776
+ },
777
+ {
778
+ component: Text,
779
+ props: ({ getArcTextProps }) => ({
780
+ ...getArcTextProps('outer'),
781
+ 'data-testid': 'outer-text',
782
+ value: 'Outer',
783
+ class: 'text-lg',
784
+ }),
785
+ },
786
+ {
787
+ component: Text,
788
+ props: ({ getArcTextProps }) => ({
789
+ ...getArcTextProps('middle'),
790
+ 'data-testid': 'middle-text',
791
+ value: 'Middle',
792
+ class: 'text-lg',
793
+ }),
794
+ },
795
+ ],
796
+ });
797
+ const inner = page.getByTestId('inner-text');
798
+ await expect.element(inner).toBeInTheDocument();
799
+ await expect.element(inner).toHaveTextContent('Inner');
800
+ const middle = page.getByTestId('middle-text');
801
+ await expect.element(middle).toBeInTheDocument();
802
+ await expect.element(middle).toHaveTextContent('Middle');
803
+ const outer = page.getByTestId('outer-text');
804
+ await expect.element(outer).toBeInTheDocument();
805
+ await expect.element(outer).toHaveTextContent('Outer');
806
+ });
807
+ });
808
+ describe.skip('motion', () => {
809
+ // TODO: not sure how to test this, check before motion applied?
810
+ // no prop to control inital wait, may need screenshot testing?
811
+ it('should start at initialValue', async () => {
812
+ render(TestHarness, {
813
+ component: Arc,
814
+ componentProps: {
815
+ ...defaultProps,
816
+ motion: { type: 'tween', duration: 300 },
817
+ value: 100,
818
+ initialValue: 0,
819
+ },
820
+ });
821
+ // Initially should render (motion will animate from initialValue to value)
822
+ const el = page.getByTestId(componentTestId);
823
+ await expect.element(el).toBeInTheDocument();
824
+ const d = el.element()?.getAttribute('d');
825
+ expect(d).toBe('M0,-150L0,0Z');
826
+ });
827
+ it('should accept spring motion config', async () => {
828
+ render(TestHarness, {
829
+ component: Arc,
830
+ componentProps: {
831
+ ...defaultProps,
832
+ value: 50,
833
+ initialValue: 0,
834
+ motion: { type: 'spring', stiffness: 100, damping: 10 },
835
+ },
836
+ });
837
+ const el = page.getByTestId(componentTestId);
838
+ await expect.element(el).toBeInTheDocument();
839
+ // Initial state (value=0) - just a line
840
+ const initialD = el.element()?.getAttribute('d');
841
+ expect(initialD).toBe('M0,-150L0,0Z');
842
+ // Wait for spring animation to settle at final state (value=50)
843
+ await expect
844
+ .poll(() => el.element()?.getAttribute('d'), { timeout: 3000 })
845
+ .toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
846
+ });
847
+ it('should accept tween motion config', async () => {
848
+ render(TestHarness, {
849
+ component: Arc,
850
+ componentProps: {
851
+ ...defaultProps,
852
+ value: 50,
853
+ initialValue: 0,
854
+ motion: { type: 'tween', duration: 300 },
855
+ },
856
+ });
857
+ const el = page.getByTestId(componentTestId);
858
+ await expect.element(el).toBeInTheDocument();
859
+ // Initial state (value=0) - just a line
860
+ const initialD = el.element()?.getAttribute('d');
861
+ expect(initialD).toBe('M0,-150L0,0Z');
862
+ // Wait for tween animation to complete at final state (value=50)
863
+ await expect
864
+ .poll(() => el.element()?.getAttribute('d'), { timeout: 1000 })
865
+ .toBe('M0,-150A150,150,0,1,1,0,150L0,0Z');
866
+ });
867
+ });
868
+ });