@redsift/charts 9.2.3-patch → 9.2.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.
Files changed (270) hide show
  1. package/coverage/clover.xml +1096 -0
  2. package/coverage/coverage-final.json +60 -0
  3. package/coverage/lcov-report/base.css +224 -0
  4. package/coverage/lcov-report/block-navigation.js +87 -0
  5. package/coverage/lcov-report/components/Arc/Arc.tsx.html +304 -0
  6. package/coverage/lcov-report/components/Arc/index.html +146 -0
  7. package/coverage/lcov-report/components/Arc/index.ts.html +94 -0
  8. package/coverage/lcov-report/components/Arc/styles.ts.html +208 -0
  9. package/coverage/lcov-report/components/Arcs/Arcs.tsx.html +409 -0
  10. package/coverage/lcov-report/components/Arcs/index.html +146 -0
  11. package/coverage/lcov-report/components/Arcs/index.ts.html +94 -0
  12. package/coverage/lcov-report/components/Arcs/styles.ts.html +106 -0
  13. package/coverage/lcov-report/components/Axis/Axis.tsx.html +754 -0
  14. package/coverage/lcov-report/components/Axis/computeTicks.ts.html +481 -0
  15. package/coverage/lcov-report/components/Axis/index.html +176 -0
  16. package/coverage/lcov-report/components/Axis/index.ts.html +94 -0
  17. package/coverage/lcov-report/components/Axis/styles.ts.html +148 -0
  18. package/coverage/lcov-report/components/Axis/types.ts.html +253 -0
  19. package/coverage/lcov-report/components/Bar/Bar.tsx.html +421 -0
  20. package/coverage/lcov-report/components/Bar/index.html +161 -0
  21. package/coverage/lcov-report/components/Bar/index.ts.html +94 -0
  22. package/coverage/lcov-report/components/Bar/styles.ts.html +247 -0
  23. package/coverage/lcov-report/components/Bar/types.ts.html +178 -0
  24. package/coverage/lcov-report/components/BarChart/BarChart.tsx.html +352 -0
  25. package/coverage/lcov-report/components/BarChart/EmptyBarChart.tsx.html +259 -0
  26. package/coverage/lcov-report/components/BarChart/LoadingBarChart.tsx.html +145 -0
  27. package/coverage/lcov-report/components/BarChart/RenderedBarChart.tsx.html +430 -0
  28. package/coverage/lcov-report/components/BarChart/index.html +206 -0
  29. package/coverage/lcov-report/components/BarChart/index.ts.html +94 -0
  30. package/coverage/lcov-report/components/BarChart/styles.ts.html +190 -0
  31. package/coverage/lcov-report/components/BarChart/utils.ts.html +145 -0
  32. package/coverage/lcov-report/components/BottomAxis/BottomAxis.tsx.html +247 -0
  33. package/coverage/lcov-report/components/BottomAxis/index.html +146 -0
  34. package/coverage/lcov-report/components/BottomAxis/index.ts.html +94 -0
  35. package/coverage/lcov-report/components/BottomAxis/styles.ts.html +139 -0
  36. package/coverage/lcov-report/components/ChartContainer/ChartContainer.tsx.html +361 -0
  37. package/coverage/lcov-report/components/ChartContainer/index.html +146 -0
  38. package/coverage/lcov-report/components/ChartContainer/index.ts.html +94 -0
  39. package/coverage/lcov-report/components/ChartContainer/intl/index.html +116 -0
  40. package/coverage/lcov-report/components/ChartContainer/intl/index.ts.html +106 -0
  41. package/coverage/lcov-report/components/ChartContainer/styles.ts.html +208 -0
  42. package/coverage/lcov-report/components/DataPoint/DataPoint.tsx.html +391 -0
  43. package/coverage/lcov-report/components/DataPoint/index.html +146 -0
  44. package/coverage/lcov-report/components/DataPoint/index.ts.html +94 -0
  45. package/coverage/lcov-report/components/DataPoint/styles.ts.html +109 -0
  46. package/coverage/lcov-report/components/Dot/Dot.tsx.html +232 -0
  47. package/coverage/lcov-report/components/Dot/index.html +146 -0
  48. package/coverage/lcov-report/components/Dot/index.ts.html +94 -0
  49. package/coverage/lcov-report/components/Dot/styles.ts.html +184 -0
  50. package/coverage/lcov-report/components/HorizontalBar/HorizontalBar.tsx.html +541 -0
  51. package/coverage/lcov-report/components/HorizontalBar/index.html +161 -0
  52. package/coverage/lcov-report/components/HorizontalBar/index.ts.html +94 -0
  53. package/coverage/lcov-report/components/HorizontalBar/styles.ts.html +187 -0
  54. package/coverage/lcov-report/components/HorizontalBar/types.ts.html +301 -0
  55. package/coverage/lcov-report/components/HorizontalBarChart/HorizontalBarChart.tsx.html +691 -0
  56. package/coverage/lcov-report/components/HorizontalBarChart/index.html +146 -0
  57. package/coverage/lcov-report/components/HorizontalBarChart/index.ts.html +94 -0
  58. package/coverage/lcov-report/components/HorizontalBarChart/styles.ts.html +196 -0
  59. package/coverage/lcov-report/components/HorizontalBarChart/types.ts.html +301 -0
  60. package/coverage/lcov-report/components/Legend/Legend.tsx.html +268 -0
  61. package/coverage/lcov-report/components/Legend/index.html +146 -0
  62. package/coverage/lcov-report/components/Legend/index.ts.html +94 -0
  63. package/coverage/lcov-report/components/Legend/styles.ts.html +130 -0
  64. package/coverage/lcov-report/components/LegendItem/LegendItem.tsx.html +325 -0
  65. package/coverage/lcov-report/components/LegendItem/index.html +146 -0
  66. package/coverage/lcov-report/components/LegendItem/index.ts.html +94 -0
  67. package/coverage/lcov-report/components/LegendItem/styles.ts.html +205 -0
  68. package/coverage/lcov-report/components/PieChart/EmptyPieChart.tsx.html +343 -0
  69. package/coverage/lcov-report/components/PieChart/LoadingPieChart.tsx.html +145 -0
  70. package/coverage/lcov-report/components/PieChart/PieChart.tsx.html +385 -0
  71. package/coverage/lcov-report/components/PieChart/RenderedPieChart.tsx.html +607 -0
  72. package/coverage/lcov-report/components/PieChart/index.html +221 -0
  73. package/coverage/lcov-report/components/PieChart/index.ts.html +94 -0
  74. package/coverage/lcov-report/components/PieChart/styles.ts.html +370 -0
  75. package/coverage/lcov-report/components/PieChart/types.ts.html +367 -0
  76. package/coverage/lcov-report/components/PieChart/utils.ts.html +199 -0
  77. package/coverage/lcov-report/components/ScatterPlot/EmptyScatterPlot.tsx.html +295 -0
  78. package/coverage/lcov-report/components/ScatterPlot/LoadingScatterPlot.tsx.html +145 -0
  79. package/coverage/lcov-report/components/ScatterPlot/RenderedScatterPlot.tsx.html +1048 -0
  80. package/coverage/lcov-report/components/ScatterPlot/ScatterPlot.tsx.html +367 -0
  81. package/coverage/lcov-report/components/ScatterPlot/index.html +221 -0
  82. package/coverage/lcov-report/components/ScatterPlot/index.ts.html +94 -0
  83. package/coverage/lcov-report/components/ScatterPlot/styles.ts.html +190 -0
  84. package/coverage/lcov-report/components/ScatterPlot/types.ts.html +394 -0
  85. package/coverage/lcov-report/components/ScatterPlot/utils.ts.html +388 -0
  86. package/coverage/lcov-report/core/Arc/Arc.tsx.html +304 -0
  87. package/coverage/lcov-report/core/Arc/index.html +146 -0
  88. package/coverage/lcov-report/core/Arc/index.ts.html +94 -0
  89. package/coverage/lcov-report/core/Arc/styles.ts.html +202 -0
  90. package/coverage/lcov-report/core/Arcs/Arcs.tsx.html +421 -0
  91. package/coverage/lcov-report/core/Arcs/index.html +146 -0
  92. package/coverage/lcov-report/core/Arcs/index.ts.html +94 -0
  93. package/coverage/lcov-report/core/Arcs/styles.ts.html +106 -0
  94. package/coverage/lcov-report/core/Axis/Axis.tsx.html +754 -0
  95. package/coverage/lcov-report/core/Axis/computeTicks.ts.html +481 -0
  96. package/coverage/lcov-report/core/Axis/index.html +176 -0
  97. package/coverage/lcov-report/core/Axis/index.ts.html +94 -0
  98. package/coverage/lcov-report/core/Axis/styles.ts.html +145 -0
  99. package/coverage/lcov-report/core/Axis/types.ts.html +253 -0
  100. package/coverage/lcov-report/core/Bar/Bar.tsx.html +421 -0
  101. package/coverage/lcov-report/core/Bar/index.html +161 -0
  102. package/coverage/lcov-report/core/Bar/index.ts.html +94 -0
  103. package/coverage/lcov-report/core/Bar/styles.ts.html +190 -0
  104. package/coverage/lcov-report/core/Bar/types.ts.html +178 -0
  105. package/coverage/lcov-report/core/BottomAxis/BottomAxis.tsx.html +277 -0
  106. package/coverage/lcov-report/core/BottomAxis/index.html +146 -0
  107. package/coverage/lcov-report/core/BottomAxis/index.ts.html +94 -0
  108. package/coverage/lcov-report/core/BottomAxis/styles.ts.html +139 -0
  109. package/coverage/lcov-report/core/ChartConfig/ChartConfig.ts.html +97 -0
  110. package/coverage/lcov-report/core/ChartConfig/index.html +131 -0
  111. package/coverage/lcov-report/core/ChartConfig/index.ts.html +88 -0
  112. package/coverage/lcov-report/core/ChartContainer/ChartContainer.tsx.html +421 -0
  113. package/coverage/lcov-report/core/ChartContainer/index.html +146 -0
  114. package/coverage/lcov-report/core/ChartContainer/index.ts.html +94 -0
  115. package/coverage/lcov-report/core/ChartContainer/intl/index.html +116 -0
  116. package/coverage/lcov-report/core/ChartContainer/intl/index.ts.html +106 -0
  117. package/coverage/lcov-report/core/ChartContainer/styles.ts.html +205 -0
  118. package/coverage/lcov-report/core/DataPoint/DataPoint.tsx.html +442 -0
  119. package/coverage/lcov-report/core/DataPoint/index.html +146 -0
  120. package/coverage/lcov-report/core/DataPoint/index.ts.html +94 -0
  121. package/coverage/lcov-report/core/DataPoint/styles.ts.html +109 -0
  122. package/coverage/lcov-report/core/Dot/Dot.tsx.html +232 -0
  123. package/coverage/lcov-report/core/Dot/index.html +146 -0
  124. package/coverage/lcov-report/core/Dot/index.ts.html +94 -0
  125. package/coverage/lcov-report/core/Dot/styles.ts.html +184 -0
  126. package/coverage/lcov-report/core/Legend/Legend.tsx.html +277 -0
  127. package/coverage/lcov-report/core/Legend/index.html +146 -0
  128. package/coverage/lcov-report/core/Legend/index.ts.html +94 -0
  129. package/coverage/lcov-report/core/Legend/styles.ts.html +172 -0
  130. package/coverage/lcov-report/core/Point/Point.tsx.html +484 -0
  131. package/coverage/lcov-report/core/Point/index.html +146 -0
  132. package/coverage/lcov-report/core/Point/index.ts.html +94 -0
  133. package/coverage/lcov-report/core/Point/styles.ts.html +169 -0
  134. package/coverage/lcov-report/favicon.png +0 -0
  135. package/coverage/lcov-report/gallery/HorizontalBarChart/HorizontalBarChart.tsx.html +706 -0
  136. package/coverage/lcov-report/gallery/HorizontalBarChart/index.html +161 -0
  137. package/coverage/lcov-report/gallery/HorizontalBarChart/index.ts.html +94 -0
  138. package/coverage/lcov-report/gallery/HorizontalBarChart/styles.ts.html +316 -0
  139. package/coverage/lcov-report/gallery/HorizontalBarChart/types.ts.html +310 -0
  140. package/coverage/lcov-report/gallery/PieChart/PieChart.tsx.html +1252 -0
  141. package/coverage/lcov-report/gallery/PieChart/index.html +161 -0
  142. package/coverage/lcov-report/gallery/PieChart/index.ts.html +94 -0
  143. package/coverage/lcov-report/gallery/PieChart/styles.ts.html +517 -0
  144. package/coverage/lcov-report/gallery/PieChart/types.ts.html +388 -0
  145. package/coverage/lcov-report/gallery/ScatterPlot/index.html +146 -0
  146. package/coverage/lcov-report/gallery/ScatterPlot/index.ts.html +94 -0
  147. package/coverage/lcov-report/gallery/ScatterPlot/styles.ts.html +343 -0
  148. package/coverage/lcov-report/gallery/ScatterPlot/types.ts.html +433 -0
  149. package/coverage/lcov-report/hooks/index.html +176 -0
  150. package/coverage/lcov-report/hooks/index.ts.html +97 -0
  151. package/coverage/lcov-report/hooks/useBrush.tsx.html +430 -0
  152. package/coverage/lcov-report/hooks/useColor.tsx.html +163 -0
  153. package/coverage/lcov-report/hooks/useFormatCategoricalData.tsx.html +289 -0
  154. package/coverage/lcov-report/hooks/useIsEmpty.tsx.html +118 -0
  155. package/coverage/lcov-report/hooks/useZoom.tsx.html +235 -0
  156. package/coverage/lcov-report/index.html +311 -0
  157. package/coverage/lcov-report/prettify.css +1 -0
  158. package/coverage/lcov-report/prettify.js +2 -0
  159. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  160. package/coverage/lcov-report/sorter.js +196 -0
  161. package/coverage/lcov.info +2345 -0
  162. package/coverage/storybook/coverage-storybook.json +79382 -0
  163. package/dist/package.json +98 -0
  164. package/index.ts +1 -0
  165. package/jest.config.js +3 -0
  166. package/package.json +2 -3
  167. package/rollup.config.js +13 -0
  168. package/src/components/Arc/Arc.test.tsx +80 -0
  169. package/src/components/Arc/Arc.tsx +73 -0
  170. package/src/components/Arc/index.ts +3 -0
  171. package/src/components/Arc/styles.ts +41 -0
  172. package/src/components/Arc/types.ts +18 -0
  173. package/src/components/Arcs/Arcs.stories.tsx +177 -0
  174. package/src/components/Arcs/Arcs.tsx +108 -0
  175. package/src/components/Arcs/index.ts +3 -0
  176. package/src/components/Arcs/styles.ts +7 -0
  177. package/src/components/Arcs/types.ts +26 -0
  178. package/src/components/Axis/Axis.stories.tsx +297 -0
  179. package/src/components/Axis/Axis.tsx +223 -0
  180. package/src/components/Axis/computeTicks.ts +132 -0
  181. package/src/components/Axis/index.ts +3 -0
  182. package/src/components/Axis/styles.ts +21 -0
  183. package/src/components/Axis/types.ts +56 -0
  184. package/src/components/Bar/Bar.stories.tsx +152 -0
  185. package/src/components/Bar/Bar.test.tsx +156 -0
  186. package/src/components/Bar/Bar.tsx +112 -0
  187. package/src/components/Bar/index.ts +3 -0
  188. package/src/components/Bar/styles.ts +54 -0
  189. package/src/components/Bar/types.ts +31 -0
  190. package/src/components/BarChart/BarChart.stories.tsx +74 -0
  191. package/src/components/BarChart/BarChart.test.tsx +178 -0
  192. package/src/components/BarChart/BarChart.tsx +89 -0
  193. package/src/components/BarChart/EmptyBarChart.tsx +58 -0
  194. package/src/components/BarChart/LoadingBarChart.tsx +20 -0
  195. package/src/components/BarChart/RenderedBarChart.tsx +115 -0
  196. package/src/components/BarChart/__snapshots__/BarChart.test.tsx.snap +7028 -0
  197. package/src/components/BarChart/index.ts +3 -0
  198. package/src/components/BarChart/styles.ts +35 -0
  199. package/src/components/BarChart/types.ts +58 -0
  200. package/src/components/BarChart/utils.ts +20 -0
  201. package/src/components/ChartContainer/ChartContainer.stories.tsx +81 -0
  202. package/src/components/ChartContainer/ChartContainer.test.tsx +71 -0
  203. package/src/components/ChartContainer/ChartContainer.tsx +92 -0
  204. package/src/components/ChartContainer/index.ts +3 -0
  205. package/src/components/ChartContainer/intl/en-US.json +3 -0
  206. package/src/components/ChartContainer/intl/fr-FR.json +3 -0
  207. package/src/components/ChartContainer/intl/index.ts +7 -0
  208. package/src/components/ChartContainer/styles.ts +41 -0
  209. package/src/components/ChartContainer/types.ts +26 -0
  210. package/src/components/DataPoint/DataPoint.tsx +102 -0
  211. package/src/components/DataPoint/index.ts +3 -0
  212. package/src/components/DataPoint/styles.ts +8 -0
  213. package/src/components/DataPoint/types.ts +33 -0
  214. package/src/components/Dot/Dot.stories.tsx +157 -0
  215. package/src/components/Dot/Dot.test.tsx +136 -0
  216. package/src/components/Dot/Dot.tsx +49 -0
  217. package/src/components/Dot/index.ts +3 -0
  218. package/src/components/Dot/styles.ts +33 -0
  219. package/src/components/Dot/types.ts +16 -0
  220. package/src/components/Legend/Legend.stories.tsx +108 -0
  221. package/src/components/Legend/Legend.tsx +61 -0
  222. package/src/components/Legend/index.ts +3 -0
  223. package/src/components/Legend/styles.ts +15 -0
  224. package/src/components/Legend/types.ts +27 -0
  225. package/src/components/LegendItem/LegendItem.test.tsx +69 -0
  226. package/src/components/LegendItem/LegendItem.tsx +80 -0
  227. package/src/components/LegendItem/index.ts +3 -0
  228. package/src/components/LegendItem/styles.ts +40 -0
  229. package/src/components/LegendItem/types.ts +30 -0
  230. package/src/components/PieChart/EmptyPieChart.tsx +86 -0
  231. package/src/components/PieChart/LoadingPieChart.tsx +20 -0
  232. package/src/components/PieChart/PieChart.stories.tsx +85 -0
  233. package/src/components/PieChart/PieChart.test.tsx +183 -0
  234. package/src/components/PieChart/PieChart.tsx +100 -0
  235. package/src/components/PieChart/RenderedPieChart.tsx +174 -0
  236. package/src/components/PieChart/__snapshots__/PieChart.test.tsx.snap +21020 -0
  237. package/src/components/PieChart/index.ts +3 -0
  238. package/src/components/PieChart/styles.ts +95 -0
  239. package/src/components/PieChart/types.ts +94 -0
  240. package/src/components/PieChart/utils.ts +38 -0
  241. package/src/components/ScatterPlot/EmptyScatterPlot.tsx +70 -0
  242. package/src/components/ScatterPlot/LoadingScatterPlot.tsx +20 -0
  243. package/src/components/ScatterPlot/RenderedScatterPlot.tsx +321 -0
  244. package/src/components/ScatterPlot/ScatterPlot.stories.tsx +101 -0
  245. package/src/components/ScatterPlot/ScatterPlot.test.tsx +61 -0
  246. package/src/components/ScatterPlot/ScatterPlot.tsx +94 -0
  247. package/src/components/ScatterPlot/__snapshots__/ScatterPlot.test.tsx.snap +91712 -0
  248. package/src/components/ScatterPlot/index.ts +3 -0
  249. package/src/components/ScatterPlot/styles.ts +35 -0
  250. package/src/components/ScatterPlot/types.ts +103 -0
  251. package/src/components/ScatterPlot/utils.ts +101 -0
  252. package/src/config.ts +10 -0
  253. package/src/hooks/index.ts +4 -0
  254. package/src/hooks/useBrush.tsx +115 -0
  255. package/src/hooks/useColor.tsx +26 -0
  256. package/src/hooks/useFormatCategoricalData.tsx +68 -0
  257. package/src/hooks/useZoom.tsx +50 -0
  258. package/src/index.ts +15 -0
  259. package/src/scheme.ts +213 -0
  260. package/src/types/data.ts +52 -0
  261. package/src/types/index.ts +5 -0
  262. package/src/types/legend.ts +19 -0
  263. package/src/types/scale.ts +79 -0
  264. package/src/types/size.ts +17 -0
  265. package/src/types/theme.ts +27 -0
  266. package/tsconfig.json +3 -0
  267. /package/{CONTRIBUTING.md → dist/CONTRIBUTING.md} +0 -0
  268. /package/{index.d.ts → dist/index.d.ts} +0 -0
  269. /package/{index.js → dist/index.js} +0 -0
  270. /package/{index.js.map → dist/index.js.map} +0 -0
@@ -0,0 +1,157 @@
1
+ import React from 'react';
2
+ // @ts-ignore
3
+ import type { StoryObj } from '@storybook/react';
4
+ import { scaleLinear as d3scaleLinear } from 'd3';
5
+
6
+ import { Dot, DotProps } from '.';
7
+ import { DotDatum, TooltipVariant } from '../../types';
8
+
9
+ const meta = {
10
+ title: 'Charts/Core/Dot',
11
+ component: Dot,
12
+ };
13
+
14
+ export default meta;
15
+ type Story = StoryObj<DotProps>;
16
+
17
+ const scaleX = d3scaleLinear().domain([0, 200]).range([0, 200]);
18
+ const scaleY = d3scaleLinear().domain([0, 200]).range([200, 0]);
19
+
20
+ export const Simple: Story = {
21
+ render: () => (
22
+ <svg width={200} height={200}>
23
+ <Dot
24
+ id="123"
25
+ index={0}
26
+ data={{
27
+ x: 50,
28
+ y: 50,
29
+ r: 10,
30
+ data: {
31
+ key: [50, 50, 'Croissant'],
32
+ value: 333,
33
+ },
34
+ }}
35
+ scaleX={scaleX}
36
+ scaleY={scaleY}
37
+ />
38
+ </svg>
39
+ ),
40
+ };
41
+
42
+ export const Clickable: Story = {
43
+ render: () => (
44
+ <svg width={200} height={200}>
45
+ <Dot
46
+ index={0}
47
+ isSelected={false}
48
+ onClick={(datum) => console.log(datum)}
49
+ data={{
50
+ x: 50,
51
+ y: 50,
52
+ r: 10,
53
+ data: {
54
+ key: [50, 50, 'Croissant'],
55
+ value: 333,
56
+ },
57
+ }}
58
+ scaleX={scaleX}
59
+ scaleY={scaleY}
60
+ />
61
+ <Dot
62
+ index={1}
63
+ isSelected
64
+ onClick={(datum) => {
65
+ window.open(
66
+ `https://en.wikipedia.org/wiki/${datum.data.key}`,
67
+ '_blank'
68
+ );
69
+ }}
70
+ data={{
71
+ x: 100,
72
+ y: 100,
73
+ r: 10,
74
+ data: {
75
+ key: [10, 100, 'Croissant'],
76
+ value: 333,
77
+ },
78
+ }}
79
+ role="link"
80
+ scaleX={scaleX}
81
+ scaleY={scaleY}
82
+ />
83
+ </svg>
84
+ ),
85
+ };
86
+
87
+ export const Selectable: Story = {
88
+ render: () => (
89
+ <svg width={200} height={200}>
90
+ <Dot
91
+ index={0}
92
+ isSelected={false}
93
+ data={{
94
+ x: 50,
95
+ y: 50,
96
+ r: 10,
97
+ data: {
98
+ key: [50, 50, 'Croissant'],
99
+ value: 333,
100
+ },
101
+ }}
102
+ role="option"
103
+ scaleX={scaleX}
104
+ scaleY={scaleY}
105
+ />
106
+ <Dot
107
+ index={1}
108
+ isSelected
109
+ data={{
110
+ x: 100,
111
+ y: 100,
112
+ r: 10,
113
+ data: {
114
+ key: [10, 100, 'Croissant'],
115
+ value: 333,
116
+ },
117
+ }}
118
+ role="option"
119
+ scaleX={scaleX}
120
+ scaleY={scaleY}
121
+ />
122
+ </svg>
123
+ ),
124
+ };
125
+
126
+ export const WithTooltip: Story = {
127
+ render: () => (
128
+ <svg width={200} height={200}>
129
+ {Object.keys(TooltipVariant).map((tooltipVariant, index) => (
130
+ <Dot
131
+ index={index}
132
+ isSelected
133
+ key={tooltipVariant}
134
+ labelDecorator={(datum: DotDatum) =>
135
+ `${datum.data.key[2]!.charAt(
136
+ 0
137
+ ).toUpperCase()}${datum.data.key[2]!.slice(1)}`
138
+ }
139
+ data={{
140
+ x: 50,
141
+ y: 50,
142
+ r: 10,
143
+ data: {
144
+ key: [50, 50, 'Croissant'],
145
+ value: 333,
146
+ percent: 0.05,
147
+ },
148
+ }}
149
+ tooltipVariant={tooltipVariant as TooltipVariant}
150
+ role="option"
151
+ scaleX={scaleX}
152
+ scaleY={scaleY}
153
+ />
154
+ ))}
155
+ </svg>
156
+ ),
157
+ };
@@ -0,0 +1,136 @@
1
+ import React from 'react';
2
+ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { scaleLinear as d3scaleLinear } from 'd3';
5
+
6
+ import { Dot } from './Dot';
7
+ import { TooltipVariant } from '../../types';
8
+
9
+ jest.mock('@redsift/design-system', () => ({
10
+ ...jest.requireActual('@redsift/design-system'),
11
+ useId: () => ['123'],
12
+ }));
13
+
14
+ const scaleX = d3scaleLinear().domain([0, 200]).range([0, 200]);
15
+ const scaleY = d3scaleLinear().domain([0, 200]).range([200, 0]);
16
+
17
+ describe('Dot', () => {
18
+ const onClickSpy = jest.fn();
19
+
20
+ afterEach(() => {
21
+ onClickSpy.mockClear();
22
+ });
23
+
24
+ it('supports click', async () => {
25
+ const { getByRole } = render(
26
+ <svg width={200} height={200}>
27
+ <Dot
28
+ id="123"
29
+ index={0}
30
+ data={{
31
+ x: 50,
32
+ y: 50,
33
+ r: 2,
34
+ data: {
35
+ key: [50, 50, 'Croissant'],
36
+ value: 333,
37
+ },
38
+ }}
39
+ onClick={onClickSpy}
40
+ scaleX={scaleX}
41
+ scaleY={scaleY}
42
+ />
43
+ </svg>
44
+ );
45
+
46
+ const point = getByRole('button');
47
+ fireEvent.click(point);
48
+ expect(onClickSpy).toHaveBeenCalledWith({
49
+ x: 50,
50
+ y: 50,
51
+ r: 2,
52
+ data: {
53
+ key: [50, 50, 'Croissant'],
54
+ value: 333,
55
+ },
56
+ });
57
+ });
58
+
59
+ it('supports keydown', async () => {
60
+ const { getByRole } = render(
61
+ <svg width={200} height={200}>
62
+ <Dot
63
+ id="123"
64
+ index={0}
65
+ data={{
66
+ x: 50,
67
+ y: 50,
68
+ r: 2,
69
+ data: {
70
+ key: [50, 50, 'Croissant'],
71
+ value: 333,
72
+ },
73
+ }}
74
+ onClick={onClickSpy}
75
+ scaleX={scaleX}
76
+ scaleY={scaleY}
77
+ />
78
+ </svg>
79
+ );
80
+
81
+ const point = getByRole('button');
82
+ fireEvent.keyDown(point, { key: 'Enter', code: 'Enter', charCode: 13 });
83
+ expect(onClickSpy).toHaveBeenCalledWith({
84
+ x: 50,
85
+ y: 50,
86
+ r: 2,
87
+ data: {
88
+ key: [50, 50, 'Croissant'],
89
+ value: 333,
90
+ },
91
+ });
92
+ fireEvent.keyDown(point, { key: 'Space', code: 'Space', charCode: 32 });
93
+ expect(onClickSpy).toHaveBeenCalledWith({
94
+ x: 50,
95
+ y: 50,
96
+ r: 2,
97
+ data: {
98
+ key: [50, 50, 'Croissant'],
99
+ value: 333,
100
+ },
101
+ });
102
+ });
103
+
104
+ it('shows a tooltip on hover', async () => {
105
+ const user = userEvent.setup();
106
+ const { getByRole } = render(
107
+ <svg width={200} height={200}>
108
+ <Dot
109
+ index={0}
110
+ // The onClick gives the point the role "button" which is then used to access the points.
111
+ onClick={onClickSpy}
112
+ data={{
113
+ x: 50,
114
+ y: 50,
115
+ r: 2,
116
+ data: {
117
+ key: [50, 50, 'Croissant'],
118
+ value: 333,
119
+ },
120
+ }}
121
+ tooltipVariant={TooltipVariant.label}
122
+ scaleX={scaleX}
123
+ scaleY={scaleY}
124
+ />
125
+ </svg>
126
+ );
127
+
128
+ const point = getByRole('button');
129
+ await user.hover(point);
130
+ await waitFor(() => {
131
+ expect(screen.getByRole('tooltip', { exact: true })).toBeInTheDocument();
132
+ });
133
+ const tooltip = screen.getByRole('tooltip');
134
+ expect(tooltip.textContent).toContain('Croissant');
135
+ });
136
+ });
@@ -0,0 +1,49 @@
1
+ import React, { forwardRef } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ import { Comp } from '@redsift/design-system';
5
+
6
+ import { DotProps } from './types';
7
+ import { StyledDot } from './styles';
8
+ import { monochrome } from '../../scheme';
9
+ import { DotDatum } from '../../types';
10
+
11
+ const COMPONENT_NAME = 'Dot';
12
+ const CLASSNAME = 'redsift-dot';
13
+ const DEFAULT_PROPS: Partial<DotProps> = {
14
+ color: monochrome,
15
+ index: 0,
16
+ labelDecorator: (datum: DotDatum) => {
17
+ return datum.data.key[2] !== undefined && datum.data.key[2] !== null
18
+ ? datum.data.key[2]
19
+ : `${datum.data.key[0]},${datum.data.key[1]}`;
20
+ },
21
+ };
22
+
23
+ export const Dot: Comp<DotProps, SVGGElement> = forwardRef((props, ref) => {
24
+ const { color, data, isSelected: propsIsSelected, onClick, role } = props;
25
+
26
+ const { className, scaleX, scaleY, ...forwardedProps } = props;
27
+
28
+ const isSelectable = role === 'option';
29
+ const isDeselected = isSelectable && propsIsSelected === false;
30
+
31
+ return (
32
+ <StyledDot
33
+ {...forwardedProps}
34
+ ref={ref}
35
+ className={classNames(Dot.className, className)}
36
+ $clickable={Boolean(onClick)}
37
+ >
38
+ <circle
39
+ cx={scaleX(data.x)}
40
+ cy={scaleY(data.y)}
41
+ r={data.r}
42
+ fill={isDeselected ? 'var(--redsift-color-neutral-lightgrey)' : color}
43
+ />
44
+ </StyledDot>
45
+ );
46
+ });
47
+ Dot.className = CLASSNAME;
48
+ Dot.defaultProps = DEFAULT_PROPS;
49
+ Dot.displayName = COMPONENT_NAME;
@@ -0,0 +1,3 @@
1
+ export * from './Dot';
2
+ export * from './types';
3
+ export * from './styles';
@@ -0,0 +1,33 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { StyledDotProps } from './types';
3
+ import { DataPoint } from '../DataPoint';
4
+
5
+ /**
6
+ * Component style.
7
+ */
8
+ export const StyledDot = styled(DataPoint)<StyledDotProps>`
9
+ circle {
10
+ fill-opacity: 0.7;
11
+ }
12
+
13
+ ${({ $clickable }) =>
14
+ $clickable
15
+ ? css`
16
+ cursor: pointer;
17
+
18
+ &:hover,
19
+ &:focus {
20
+ opacity: 0.5;
21
+ outline: none;
22
+ }
23
+
24
+ &:focus-visible {
25
+ circle {
26
+ stroke: var(--redsift-color-default-primary);
27
+ stroke-width: 4px;
28
+ paint-order: stroke;
29
+ }
30
+ }
31
+ `
32
+ : ''}}
33
+ `;
@@ -0,0 +1,16 @@
1
+ import { ScaleLinear as d3ScaleLinear } from 'd3';
2
+ import { DotDatum } from '../../types';
3
+ import { DataPointProps, StyledDataPointProps } from '../DataPoint';
4
+
5
+ /**
6
+ * Component props.
7
+ */
8
+ export interface DotProps extends DataPointProps<DotDatum> {
9
+ /** A linear continuous scale defined over a numeric domain used to determine the x position based on the coordinates. */
10
+ scaleX: d3ScaleLinear<number, number, never>;
11
+ /** A linear continuous scale defined over a numeric domain used to determine the y position based on the coordinates. */
12
+ scaleY: d3ScaleLinear<number, number, never>;
13
+ }
14
+
15
+ export type StyledDotProps = StyledDataPointProps &
16
+ Omit<DotProps, 'scaleX' | 'scaleY'>;
@@ -0,0 +1,108 @@
1
+ import React, { useState } from 'react';
2
+ // @ts-ignore
3
+ import type { StoryObj } from '@storybook/react';
4
+
5
+ import { Legend, LegendProps } from '.';
6
+ import { LabelVariant } from '../../types';
7
+ import { Flexbox } from '@redsift/design-system';
8
+
9
+ const meta = {
10
+ title: 'Charts/Core/Legend',
11
+ component: Legend,
12
+ };
13
+
14
+ export default meta;
15
+ type Story = StoryObj<LegendProps>;
16
+
17
+ const mockData = [
18
+ {
19
+ key: 'Coffee',
20
+ value: 5471,
21
+ color: '#56D58E',
22
+ },
23
+ {
24
+ key: 'Bread',
25
+ value: 3325,
26
+ color: '#D95CBA',
27
+ },
28
+ {
29
+ key: 'Tea',
30
+ value: 1435,
31
+ color: '#63EAE4',
32
+ },
33
+ {
34
+ key: 'Pastry',
35
+ value: 856,
36
+ color: '#C78348',
37
+ },
38
+ {
39
+ key: 'Croissant',
40
+ value: 771,
41
+ color: '#E06363',
42
+ },
43
+ {
44
+ key: 'Sandwich',
45
+ value: 771,
46
+ color: '#FFF741',
47
+ },
48
+ {
49
+ key: 'Hot chocolate',
50
+ value: 588,
51
+ color: '#965EDE',
52
+ },
53
+ {
54
+ key: 'Cookies',
55
+ value: 540,
56
+ color: '#FCBB54',
57
+ },
58
+ {
59
+ key: 'Toast',
60
+ value: 318,
61
+ color: '#73C5EB',
62
+ },
63
+ ];
64
+
65
+ export const Simple: Story = {
66
+ render: () => <Legend data={mockData} />,
67
+ };
68
+
69
+ export const AllVariants = () => (
70
+ <Flexbox flexDirection="column" alignItems="center">
71
+ {Object.keys(LabelVariant).map((labelVariant) => (
72
+ <Legend
73
+ data={mockData}
74
+ key={labelVariant}
75
+ variant={labelVariant as LabelVariant}
76
+ />
77
+ ))}
78
+ </Flexbox>
79
+ );
80
+
81
+ export const Clickable: Story = {
82
+ render: () => (
83
+ <Legend data={mockData} onLegendItemClick={(datum) => console.log(datum)} />
84
+ ),
85
+ };
86
+
87
+ export const Selectable: Story = {
88
+ render: () => {
89
+ const [selected, setSelected] = useState<string[]>([]);
90
+
91
+ return (
92
+ <Legend
93
+ data={mockData}
94
+ onLegendItemClick={(datum) => {
95
+ if (selected.includes(datum.data.key)) {
96
+ setSelected(selected.filter((s) => s !== datum.data.key));
97
+ } else {
98
+ setSelected([...selected, datum.data.key]);
99
+ }
100
+ }}
101
+ isLegendItemSelected={(datum) =>
102
+ !selected.length || selected.includes(datum.data.key)
103
+ }
104
+ legendItemRole="option"
105
+ />
106
+ );
107
+ },
108
+ };
@@ -0,0 +1,61 @@
1
+ import React, { forwardRef } from 'react';
2
+ import classNames from 'classnames';
3
+ import { sum as d3sum } from 'd3';
4
+
5
+ import { Comp } from '@redsift/design-system';
6
+
7
+ import { LegendProps } from './types';
8
+ import { StyledLegend } from './styles';
9
+ import { LabelVariant } from '../../types';
10
+ import { LegendItem } from '../LegendItem';
11
+
12
+ const COMPONENT_NAME = 'Legend';
13
+ const CLASSNAME = 'redsift-chart-legend';
14
+ const DEFAULT_PROPS: Partial<LegendProps> = {
15
+ isLegendItemSelected: () => true,
16
+ variant: LabelVariant.label,
17
+ };
18
+
19
+ export const Legend: Comp<LegendProps, HTMLUListElement> = forwardRef(
20
+ (props, ref) => {
21
+ const {
22
+ className,
23
+ data,
24
+ isLegendItemSelected,
25
+ labelDecorator,
26
+ legendItemRole,
27
+ onLegendItemClick,
28
+ variant,
29
+ width,
30
+ ...forwardedProps
31
+ } = props;
32
+ const total = d3sum(data, (d) => d.value);
33
+
34
+ return (
35
+ <StyledLegend
36
+ {...forwardedProps}
37
+ className={classNames(Legend.className, className)}
38
+ ref={ref}
39
+ $width={width}
40
+ >
41
+ {data.map(({ color, ...datum }, index) => (
42
+ <LegendItem
43
+ data={{ data: datum }}
44
+ color={color}
45
+ total={total}
46
+ variant={variant}
47
+ index={index}
48
+ isSelected={Boolean(isLegendItemSelected!({ data: datum }))}
49
+ key={`legend-item _${index}`}
50
+ labelDecorator={labelDecorator}
51
+ onClick={onLegendItemClick}
52
+ role={legendItemRole}
53
+ />
54
+ ))}
55
+ </StyledLegend>
56
+ );
57
+ }
58
+ );
59
+ Legend.className = CLASSNAME;
60
+ Legend.defaultProps = DEFAULT_PROPS;
61
+ Legend.displayName = COMPONENT_NAME;
@@ -0,0 +1,3 @@
1
+ export * from './Legend';
2
+ export * from './types';
3
+ export * from './styles';
@@ -0,0 +1,15 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { StyledLegendProps } from './types';
3
+
4
+ /**
5
+ * Component style.
6
+ */
7
+ export const StyledLegend = styled.ul<StyledLegendProps>`
8
+ max-width: 262px;
9
+ ${({ $width }) =>
10
+ $width !== undefined
11
+ ? css`
12
+ width: ${$width};
13
+ `
14
+ : null}
15
+ `;
@@ -0,0 +1,27 @@
1
+ import { ComponentProps } from 'react';
2
+ import { CategoryDatum, LabelVariant, LegendItemDatum } from '../../types';
3
+ import { LegendItemProps } from '../LegendItem';
4
+
5
+ /**
6
+ * Component props.
7
+ */
8
+ export interface LegendProps extends Omit<ComponentProps<'ul'>, 'onClick'> {
9
+ /** Data. */
10
+ data: (CategoryDatum & { color: string })[];
11
+ /** Method to determine whether a slice is selected or not. */
12
+ isLegendItemSelected?: (datum: LegendItemDatum) => void;
13
+ /** Method to override the data labels. */
14
+ labelDecorator?: (datum: LegendItemDatum) => string;
15
+ /** Method to be called on a click on a legend item. */
16
+ onLegendItemClick?: (datum: LegendItemDatum) => void;
17
+ /** LegendItem role. Used to indicate that legend items are to be considered buttons or links. If an onClick is provided, the legend items will have the role `button` unless specifically set to `link` with this prop. */
18
+ legendItemRole?: LegendItemProps['role'];
19
+ /** Variant. */
20
+ variant?: LabelVariant;
21
+ /** Width. */
22
+ width?: string;
23
+ }
24
+
25
+ export type StyledLegendProps = Omit<LegendProps, 'data'> & {
26
+ $width?: LegendProps['width'];
27
+ };
@@ -0,0 +1,69 @@
1
+ import React from 'react';
2
+ import { fireEvent, render } from '@testing-library/react';
3
+
4
+ import { LegendItem } from './LegendItem';
5
+
6
+ jest.mock('@redsift/design-system', () => ({
7
+ ...jest.requireActual('@redsift/design-system'),
8
+ useId: () => ['123'],
9
+ }));
10
+
11
+ describe('LegendItem', () => {
12
+ const onClickSpy = jest.fn();
13
+
14
+ afterEach(() => {
15
+ onClickSpy.mockClear();
16
+ });
17
+
18
+ it('supports click', async () => {
19
+ const { getByRole } = render(
20
+ <svg width={500} height={500}>
21
+ <LegendItem
22
+ id="123"
23
+ index={0}
24
+ data={{
25
+ data: {
26
+ key: 'Croissant',
27
+ value: 333,
28
+ },
29
+ }}
30
+ onClick={onClickSpy}
31
+ />
32
+ </svg>
33
+ );
34
+
35
+ const legendItem = getByRole('button');
36
+ fireEvent.click(legendItem);
37
+ expect(onClickSpy).toHaveBeenCalledWith({
38
+ data: { key: 'Croissant', value: 333 },
39
+ });
40
+ });
41
+
42
+ it('supports keydown', async () => {
43
+ const { getByRole } = render(
44
+ <svg width={500} height={500}>
45
+ <LegendItem
46
+ id="123"
47
+ index={0}
48
+ data={{
49
+ data: {
50
+ key: 'Croissant',
51
+ value: 333,
52
+ },
53
+ }}
54
+ onClick={onClickSpy}
55
+ />
56
+ </svg>
57
+ );
58
+
59
+ const legendItem = getByRole('button');
60
+ fireEvent.keyDown(legendItem, {
61
+ key: 'Enter',
62
+ code: 'Enter',
63
+ charCode: 13,
64
+ });
65
+ expect(onClickSpy).toHaveBeenCalledWith({
66
+ data: { key: 'Croissant', value: 333 },
67
+ });
68
+ });
69
+ });