@redsift/charts 8.0.0 → 8.0.1

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 (218) hide show
  1. package/coverage/clover.xml +1070 -0
  2. package/coverage/coverage-final.json +60 -0
  3. package/coverage/lcov-report/ChartEmptyState/ChartEmptyState.tsx.html +679 -0
  4. package/coverage/lcov-report/ChartEmptyState/index.html +146 -0
  5. package/coverage/lcov-report/ChartEmptyState/index.ts.html +91 -0
  6. package/coverage/lcov-report/ChartEmptyState/styles.ts.html +184 -0
  7. package/coverage/lcov-report/HorizontalBarChart/HorizontalBarChart.tsx.html +775 -0
  8. package/coverage/lcov-report/HorizontalBarChart/HorizontalBarChartAxisBottom.tsx.html +259 -0
  9. package/coverage/lcov-report/HorizontalBarChart/HorizontalBarChartBar.tsx.html +421 -0
  10. package/coverage/lcov-report/HorizontalBarChart/index.html +191 -0
  11. package/coverage/lcov-report/HorizontalBarChart/index.ts.html +94 -0
  12. package/coverage/lcov-report/HorizontalBarChart/styles.ts.html +451 -0
  13. package/coverage/lcov-report/HorizontalBarChart/types.ts.html +433 -0
  14. package/coverage/lcov-report/PieChart/PieChart.tsx.html +1105 -0
  15. package/coverage/lcov-report/PieChart/PieChartArc.tsx.html +412 -0
  16. package/coverage/lcov-report/PieChart/index.html +176 -0
  17. package/coverage/lcov-report/PieChart/index.ts.html +94 -0
  18. package/coverage/lcov-report/PieChart/styles.ts.html +616 -0
  19. package/coverage/lcov-report/PieChart/types.ts.html +472 -0
  20. package/coverage/lcov-report/PieChart.tsx.html +1045 -0
  21. package/coverage/lcov-report/PieChartArc.tsx.html +271 -0
  22. package/coverage/lcov-report/StaticPieChart.tsx.html +286 -0
  23. package/coverage/lcov-report/base.css +224 -0
  24. package/coverage/lcov-report/block-navigation.js +87 -0
  25. package/coverage/lcov-report/components/Arc/Arc.tsx.html +304 -0
  26. package/coverage/lcov-report/components/Arc/index.html +146 -0
  27. package/coverage/lcov-report/components/Arc/index.ts.html +94 -0
  28. package/coverage/lcov-report/components/Arc/styles.ts.html +208 -0
  29. package/coverage/lcov-report/components/Arcs/Arcs.tsx.html +427 -0
  30. package/coverage/lcov-report/components/Arcs/index.html +146 -0
  31. package/coverage/lcov-report/components/Arcs/index.ts.html +94 -0
  32. package/coverage/lcov-report/components/Arcs/styles.ts.html +106 -0
  33. package/coverage/lcov-report/components/Axis/Axis.tsx.html +754 -0
  34. package/coverage/lcov-report/components/Axis/computeTicks.ts.html +481 -0
  35. package/coverage/lcov-report/components/Axis/index.html +176 -0
  36. package/coverage/lcov-report/components/Axis/index.ts.html +94 -0
  37. package/coverage/lcov-report/components/Axis/styles.ts.html +148 -0
  38. package/coverage/lcov-report/components/Axis/types.ts.html +253 -0
  39. package/coverage/lcov-report/components/Bar/Bar.tsx.html +421 -0
  40. package/coverage/lcov-report/components/Bar/index.html +161 -0
  41. package/coverage/lcov-report/components/Bar/index.ts.html +94 -0
  42. package/coverage/lcov-report/components/Bar/styles.ts.html +247 -0
  43. package/coverage/lcov-report/components/Bar/types.ts.html +178 -0
  44. package/coverage/lcov-report/components/BarChart/BarChart.tsx.html +355 -0
  45. package/coverage/lcov-report/components/BarChart/EmptyBarChart.tsx.html +259 -0
  46. package/coverage/lcov-report/components/BarChart/LoadingBarChart.tsx.html +145 -0
  47. package/coverage/lcov-report/components/BarChart/RenderedBarChart.tsx.html +496 -0
  48. package/coverage/lcov-report/components/BarChart/index.html +206 -0
  49. package/coverage/lcov-report/components/BarChart/index.ts.html +94 -0
  50. package/coverage/lcov-report/components/BarChart/styles.ts.html +190 -0
  51. package/coverage/lcov-report/components/BarChart/utils.ts.html +145 -0
  52. package/coverage/lcov-report/components/ChartContainer/ChartContainer.tsx.html +433 -0
  53. package/coverage/lcov-report/components/ChartContainer/index.html +146 -0
  54. package/coverage/lcov-report/components/ChartContainer/index.ts.html +94 -0
  55. package/coverage/lcov-report/components/ChartContainer/intl/index.html +116 -0
  56. package/coverage/lcov-report/components/ChartContainer/intl/index.ts.html +106 -0
  57. package/coverage/lcov-report/components/ChartContainer/styles.ts.html +211 -0
  58. package/coverage/lcov-report/components/DataPoint/DataPoint.tsx.html +442 -0
  59. package/coverage/lcov-report/components/DataPoint/index.html +146 -0
  60. package/coverage/lcov-report/components/DataPoint/index.ts.html +94 -0
  61. package/coverage/lcov-report/components/DataPoint/styles.ts.html +109 -0
  62. package/coverage/lcov-report/components/Dot/Dot.tsx.html +232 -0
  63. package/coverage/lcov-report/components/Dot/index.html +146 -0
  64. package/coverage/lcov-report/components/Dot/index.ts.html +94 -0
  65. package/coverage/lcov-report/components/Dot/styles.ts.html +184 -0
  66. package/coverage/lcov-report/components/Legend/Legend.tsx.html +268 -0
  67. package/coverage/lcov-report/components/Legend/index.html +146 -0
  68. package/coverage/lcov-report/components/Legend/index.ts.html +94 -0
  69. package/coverage/lcov-report/components/Legend/styles.ts.html +130 -0
  70. package/coverage/lcov-report/components/LegendItem/LegendItem.tsx.html +403 -0
  71. package/coverage/lcov-report/components/LegendItem/index.html +146 -0
  72. package/coverage/lcov-report/components/LegendItem/index.ts.html +94 -0
  73. package/coverage/lcov-report/components/LegendItem/styles.ts.html +205 -0
  74. package/coverage/lcov-report/components/PieChart/EmptyPieChart.tsx.html +343 -0
  75. package/coverage/lcov-report/components/PieChart/LoadingPieChart.tsx.html +145 -0
  76. package/coverage/lcov-report/components/PieChart/PieChart.tsx.html +388 -0
  77. package/coverage/lcov-report/components/PieChart/RenderedPieChart.tsx.html +571 -0
  78. package/coverage/lcov-report/components/PieChart/index.html +221 -0
  79. package/coverage/lcov-report/components/PieChart/index.ts.html +94 -0
  80. package/coverage/lcov-report/components/PieChart/styles.ts.html +376 -0
  81. package/coverage/lcov-report/components/PieChart/types.ts.html +352 -0
  82. package/coverage/lcov-report/components/PieChart/utils.ts.html +199 -0
  83. package/coverage/lcov-report/components/ScatterPlot/EmptyScatterPlot.tsx.html +295 -0
  84. package/coverage/lcov-report/components/ScatterPlot/LoadingScatterPlot.tsx.html +145 -0
  85. package/coverage/lcov-report/components/ScatterPlot/RenderedScatterPlot.tsx.html +910 -0
  86. package/coverage/lcov-report/components/ScatterPlot/ScatterPlot.tsx.html +379 -0
  87. package/coverage/lcov-report/components/ScatterPlot/index.html +221 -0
  88. package/coverage/lcov-report/components/ScatterPlot/index.ts.html +94 -0
  89. package/coverage/lcov-report/components/ScatterPlot/styles.ts.html +196 -0
  90. package/coverage/lcov-report/components/ScatterPlot/types.ts.html +376 -0
  91. package/coverage/lcov-report/components/ScatterPlot/utils.ts.html +388 -0
  92. package/coverage/lcov-report/favicon.png +0 -0
  93. package/coverage/lcov-report/hooks/index.html +176 -0
  94. package/coverage/lcov-report/hooks/index.ts.html +97 -0
  95. package/coverage/lcov-report/hooks/useBrush.tsx.html +430 -0
  96. package/coverage/lcov-report/hooks/useColor.tsx.html +163 -0
  97. package/coverage/lcov-report/hooks/useFormatCategoricalData.tsx.html +289 -0
  98. package/coverage/lcov-report/hooks/useZoom.tsx.html +235 -0
  99. package/coverage/lcov-report/index.html +311 -0
  100. package/coverage/lcov-report/index.ts.html +94 -0
  101. package/coverage/lcov-report/prettify.css +1 -0
  102. package/coverage/lcov-report/prettify.js +2 -0
  103. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  104. package/coverage/lcov-report/sorter.js +196 -0
  105. package/coverage/lcov-report/styles.ts.html +631 -0
  106. package/coverage/lcov-report/types.ts.html +457 -0
  107. package/coverage/lcov.info +2272 -0
  108. package/dist/index.js +6326 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/package.json +98 -0
  111. package/index.ts +1 -0
  112. package/jest.config.js +3 -0
  113. package/package.json +2 -3
  114. package/rollup.config.js +13 -0
  115. package/src/components/Arc/Arc.test.tsx +92 -0
  116. package/src/components/Arc/Arc.tsx +73 -0
  117. package/src/components/Arc/index.ts +3 -0
  118. package/src/components/Arc/styles.ts +41 -0
  119. package/src/components/Arc/types.ts +18 -0
  120. package/src/components/Arcs/Arcs.stories.tsx +177 -0
  121. package/src/components/Arcs/Arcs.tsx +114 -0
  122. package/src/components/Arcs/index.ts +3 -0
  123. package/src/components/Arcs/styles.ts +7 -0
  124. package/src/components/Arcs/types.ts +26 -0
  125. package/src/components/Axis/Axis.stories.tsx +297 -0
  126. package/src/components/Axis/Axis.tsx +223 -0
  127. package/src/components/Axis/computeTicks.ts +132 -0
  128. package/src/components/Axis/index.ts +3 -0
  129. package/src/components/Axis/styles.ts +21 -0
  130. package/src/components/Axis/types.ts +56 -0
  131. package/src/components/Bar/Bar.stories.tsx +152 -0
  132. package/src/components/Bar/Bar.test.tsx +158 -0
  133. package/src/components/Bar/Bar.tsx +112 -0
  134. package/src/components/Bar/index.ts +3 -0
  135. package/src/components/Bar/styles.ts +54 -0
  136. package/src/components/Bar/types.ts +31 -0
  137. package/src/components/BarChart/BarChart.stories.tsx +80 -0
  138. package/src/components/BarChart/BarChart.test.tsx +189 -0
  139. package/src/components/BarChart/BarChart.tsx +90 -0
  140. package/src/components/BarChart/EmptyBarChart.tsx +58 -0
  141. package/src/components/BarChart/LoadingBarChart.tsx +20 -0
  142. package/src/components/BarChart/RenderedBarChart.tsx +137 -0
  143. package/src/components/BarChart/__snapshots__/BarChart.test.tsx.snap +6932 -0
  144. package/src/components/BarChart/index.ts +3 -0
  145. package/src/components/BarChart/styles.ts +35 -0
  146. package/src/components/BarChart/types.ts +58 -0
  147. package/src/components/BarChart/utils.ts +20 -0
  148. package/src/components/ChartContainer/ChartContainer.stories.tsx +81 -0
  149. package/src/components/ChartContainer/ChartContainer.test.tsx +75 -0
  150. package/src/components/ChartContainer/ChartContainer.tsx +116 -0
  151. package/src/components/ChartContainer/index.ts +3 -0
  152. package/src/components/ChartContainer/intl/en-US.json +3 -0
  153. package/src/components/ChartContainer/intl/fr-FR.json +3 -0
  154. package/src/components/ChartContainer/intl/index.ts +7 -0
  155. package/src/components/ChartContainer/styles.ts +42 -0
  156. package/src/components/ChartContainer/types.ts +24 -0
  157. package/src/components/DataPoint/DataPoint.tsx +119 -0
  158. package/src/components/DataPoint/index.ts +3 -0
  159. package/src/components/DataPoint/styles.ts +8 -0
  160. package/src/components/DataPoint/types.ts +33 -0
  161. package/src/components/Dot/Dot.stories.tsx +157 -0
  162. package/src/components/Dot/Dot.test.tsx +136 -0
  163. package/src/components/Dot/Dot.tsx +49 -0
  164. package/src/components/Dot/index.ts +3 -0
  165. package/src/components/Dot/styles.ts +33 -0
  166. package/src/components/Dot/types.ts +16 -0
  167. package/src/components/Legend/Legend.stories.tsx +108 -0
  168. package/src/components/Legend/Legend.tsx +61 -0
  169. package/src/components/Legend/index.ts +3 -0
  170. package/src/components/Legend/styles.ts +15 -0
  171. package/src/components/Legend/types.ts +27 -0
  172. package/src/components/LegendItem/LegendItem.test.tsx +69 -0
  173. package/src/components/LegendItem/LegendItem.tsx +106 -0
  174. package/src/components/LegendItem/index.ts +3 -0
  175. package/src/components/LegendItem/styles.ts +40 -0
  176. package/src/components/LegendItem/types.ts +30 -0
  177. package/src/components/PieChart/EmptyPieChart.tsx +86 -0
  178. package/src/components/PieChart/LoadingPieChart.tsx +20 -0
  179. package/src/components/PieChart/PieChart.stories.tsx +91 -0
  180. package/src/components/PieChart/PieChart.test.tsx +201 -0
  181. package/src/components/PieChart/PieChart.tsx +101 -0
  182. package/src/components/PieChart/RenderedPieChart.tsx +162 -0
  183. package/src/components/PieChart/__snapshots__/PieChart.stories.storyshot +7843 -0
  184. package/src/components/PieChart/__snapshots__/PieChart.test.tsx.snap +20540 -0
  185. package/src/components/PieChart/index.ts +3 -0
  186. package/src/components/PieChart/styles.ts +97 -0
  187. package/src/components/PieChart/types.ts +89 -0
  188. package/src/components/PieChart/utils.ts +38 -0
  189. package/src/components/ScatterPlot/EmptyScatterPlot.tsx +70 -0
  190. package/src/components/ScatterPlot/LoadingScatterPlot.tsx +20 -0
  191. package/src/components/ScatterPlot/RenderedScatterPlot.tsx +275 -0
  192. package/src/components/ScatterPlot/ScatterPlot.stories.tsx +95 -0
  193. package/src/components/ScatterPlot/ScatterPlot.test.tsx +44 -0
  194. package/src/components/ScatterPlot/ScatterPlot.tsx +98 -0
  195. package/src/components/ScatterPlot/__snapshots__/ScatterPlot.test.tsx.snap +88352 -0
  196. package/src/components/ScatterPlot/index.ts +3 -0
  197. package/src/components/ScatterPlot/styles.ts +37 -0
  198. package/src/components/ScatterPlot/types.ts +97 -0
  199. package/src/components/ScatterPlot/utils.ts +101 -0
  200. package/src/config.ts +10 -0
  201. package/src/hooks/index.ts +4 -0
  202. package/src/hooks/useBrush.tsx +115 -0
  203. package/src/hooks/useColor.tsx +26 -0
  204. package/src/hooks/useFormatCategoricalData.tsx +68 -0
  205. package/src/hooks/useZoom.tsx +50 -0
  206. package/src/index.ts +15 -0
  207. package/src/scheme.ts +221 -0
  208. package/src/types/data.ts +52 -0
  209. package/src/types/index.ts +5 -0
  210. package/src/types/legend.ts +19 -0
  211. package/src/types/scale.ts +79 -0
  212. package/src/types/size.ts +17 -0
  213. package/src/types/theme.ts +27 -0
  214. package/tsconfig.json +3 -0
  215. package/index.js +0 -2606
  216. package/index.js.map +0 -1
  217. /package/{CONTRIBUTING.md → dist/CONTRIBUTING.md} +0 -0
  218. /package/{index.d.ts → dist/index.d.ts} +0 -0
@@ -0,0 +1,189 @@
1
+ import React from 'react';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+
5
+ import { composeStory } from '@storybook/react';
6
+ import Meta, { Controls } from './BarChart.stories';
7
+
8
+ import { BarChart } from './BarChart';
9
+ import { ChartSize, ChartTheme, ColorTheme, TooltipVariant } from '../../types';
10
+ import { DataVizColorPalette } from '@redsift/design-system';
11
+
12
+ jest.mock('react', () => ({
13
+ ...jest.requireActual('react'),
14
+ useId: () => '123',
15
+ }));
16
+
17
+ const themes = {
18
+ ...ColorTheme,
19
+ 'success-warning-danger': {
20
+ success: 'Bread',
21
+ warning: 'Tea',
22
+ danger: 'Coffee',
23
+ },
24
+ 'success-warning-danger-neutral': {
25
+ success: 'Bread',
26
+ warning: 'Tea',
27
+ danger: 'Coffee',
28
+ neutral: 'Pastry',
29
+ },
30
+ custom: {
31
+ Coffee: DataVizColorPalette.purple,
32
+ Bread: DataVizColorPalette.pink,
33
+ Tea: DataVizColorPalette.aqua,
34
+ },
35
+ };
36
+
37
+ const data = [
38
+ { key: 'Dogs', value: 350 },
39
+ { key: 'Cats', value: 500 },
40
+ { key: 'Fish', value: 150 },
41
+ ];
42
+
43
+ describe('BarChart', () => {
44
+ const onClickSpy = jest.fn();
45
+
46
+ afterEach(() => {
47
+ onClickSpy.mockClear();
48
+ });
49
+
50
+ it('should match snapshot', () => {
51
+ const ComposedStory = composeStory(Controls, Meta);
52
+ const tree = render(
53
+ <>
54
+ {Object.values(ChartSize).map((size, i) =>
55
+ Object.values(TooltipVariant).map((tooltipVariant, j) => (
56
+ <ComposedStory
57
+ key={`${size}-${tooltipVariant}`}
58
+ tooltipVariant={tooltipVariant}
59
+ size={size}
60
+ theme={
61
+ Object.keys(themes)[
62
+ (i * Object.values(TooltipVariant).length + j) %
63
+ Object.keys(themes).length
64
+ ] as ChartTheme
65
+ }
66
+ />
67
+ ))
68
+ )}
69
+ </>
70
+ );
71
+ expect(tree).toMatchSnapshot();
72
+ });
73
+
74
+ it('supports custom className', () => {
75
+ const tree = render(
76
+ <BarChart aria-label="Chart" data={data} className="test" />
77
+ );
78
+ const component = tree.asFragment().firstChild;
79
+
80
+ expect(component).toHaveAttribute('class', expect.stringContaining('test'));
81
+ });
82
+
83
+ it('supports custom data attributes', () => {
84
+ const tree = render(
85
+ <BarChart aria-label="Chart" data={data} data-testid="test" />
86
+ );
87
+ const component = tree.asFragment().firstChild;
88
+ expect(component).toHaveAttribute('data-testid', 'test');
89
+ });
90
+
91
+ it('can be labelled using a title', () => {
92
+ const { getByLabelText } = render(<BarChart data={data} title="Label" />);
93
+ const component = getByLabelText('Label');
94
+ expect(component).toHaveAttribute('aria-labelledby', 'id123__title');
95
+ });
96
+
97
+ it('can be labelled using an aria-label', () => {
98
+ const { getByLabelText } = render(
99
+ <BarChart data={data} aria-label="Label" />
100
+ );
101
+ const component = getByLabelText('Label');
102
+ expect(component).toHaveAttribute('aria-label', 'Label');
103
+ });
104
+
105
+ it('can be labelled using an aria-labelledby', () => {
106
+ const { getByLabelText } = render(
107
+ <>
108
+ <h1 id="123">Label</h1>
109
+ <BarChart data={data} aria-labelledby="123" />
110
+ </>
111
+ );
112
+ const component = getByLabelText('Label');
113
+ expect(component).toHaveAttribute('aria-labelledby', '123');
114
+ });
115
+
116
+ it('supports click on the bars', async () => {
117
+ const user = userEvent.setup();
118
+ const { getAllByRole } = render(
119
+ <BarChart aria-label="Chart" data={data} onBarClick={onClickSpy} />
120
+ );
121
+
122
+ const bars = getAllByRole('button');
123
+ expect(bars.length).toBe(3);
124
+
125
+ await user.click(bars[0]);
126
+ await user.click(bars[1]);
127
+ await user.click(bars[2]);
128
+
129
+ expect(onClickSpy).toHaveBeenCalledWith({
130
+ data: { key: 'Cats', value: 500, percent: 0.5 },
131
+ });
132
+ expect(onClickSpy).toHaveBeenCalledWith({
133
+ data: { key: 'Dogs', value: 350, percent: 0.35 },
134
+ });
135
+ expect(onClickSpy).toHaveBeenCalledWith({
136
+ data: { key: 'Fish', value: 150, percent: 0.15 },
137
+ });
138
+ expect(onClickSpy).toHaveBeenCalledTimes(3);
139
+ });
140
+
141
+ it('supports keydown on the bars', async () => {
142
+ const { getAllByRole } = render(
143
+ <BarChart aria-label="Chart" data={data} onBarClick={onClickSpy} />
144
+ );
145
+
146
+ const bars = getAllByRole('button');
147
+ expect(bars.length).toBe(3);
148
+
149
+ userEvent.keyboard('[Tab]');
150
+ userEvent.keyboard('[Enter]');
151
+ userEvent.keyboard('[Tab]');
152
+ userEvent.keyboard('[Space]');
153
+ userEvent.keyboard('[Tab]');
154
+ userEvent.keyboard('[Enter]');
155
+
156
+ expect(onClickSpy).toHaveBeenCalledWith({
157
+ data: { key: 'Cats', value: 500, percent: 0.5 },
158
+ });
159
+ expect(onClickSpy).toHaveBeenCalledWith({
160
+ data: { key: 'Dogs', value: 350, percent: 0.35 },
161
+ });
162
+ expect(onClickSpy).toHaveBeenCalledWith({
163
+ data: { key: 'Fish', value: 150, percent: 0.15 },
164
+ });
165
+ expect(onClickSpy).toHaveBeenCalledTimes(3);
166
+ });
167
+
168
+ it('shows a tooltip when hovering on the bars ', async () => {
169
+ const user = userEvent.setup();
170
+ const { getAllByRole } = render(
171
+ <BarChart
172
+ aria-label="Chart"
173
+ data={data}
174
+ // The onBarClick gives the bar the role "button" which is then used to access the bars.
175
+ onBarClick={onClickSpy}
176
+ />
177
+ );
178
+
179
+ const bars = getAllByRole('button');
180
+ expect(bars.length).toBe(3);
181
+
182
+ await user.hover(bars[0]);
183
+ await waitFor(() => {
184
+ expect(screen.getByRole('tooltip', { exact: true })).toBeInTheDocument();
185
+ });
186
+ const tooltip = screen.getByRole('tooltip');
187
+ expect(tooltip.textContent).toContain('Cats');
188
+ });
189
+ });
@@ -0,0 +1,90 @@
1
+ import React, { forwardRef, useId } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ import { Comp } from '@redsift/design-system';
5
+
6
+ import { ChartSize, ColorTheme, TooltipVariant } from '../../types';
7
+ import { BarChartProps } from './types';
8
+ import { EmptyBarChart } from './EmptyBarChart';
9
+ import { LoadingBarChart } from './LoadingBarChart';
10
+ import { RenderedBarChart } from './RenderedBarChart';
11
+
12
+ const COMPONENT_NAME = 'BarChart';
13
+ const CLASSNAME = 'redsift-barchart';
14
+ const DEFAULT_PROPS: Partial<BarChartProps> = {
15
+ isBarSelected: () => true,
16
+ others: true,
17
+ size: ChartSize.medium,
18
+ theme: ColorTheme.default,
19
+ tooltipVariant: TooltipVariant.value,
20
+ localeText: {
21
+ emptyChartText: 'No Data',
22
+ },
23
+ };
24
+
25
+ export const BarChart: Comp<BarChartProps, HTMLDivElement> = forwardRef(
26
+ (props, ref) => {
27
+ const {
28
+ areXLabelsRotated,
29
+ caping,
30
+ chartRef,
31
+ className,
32
+ data: propsData,
33
+ emptyComponent,
34
+ id: propsId,
35
+ isBarSelected,
36
+ labelDecorator,
37
+ localeText,
38
+ onBarClick,
39
+ others,
40
+ size,
41
+ barRole,
42
+ theme,
43
+ tooltipVariant,
44
+ ...forwardedProps
45
+ } = props;
46
+ const id = propsId ?? useId();
47
+
48
+ if (propsData === undefined || propsData === null) {
49
+ return <LoadingBarChart id={id} {...forwardedProps} ref={ref} />;
50
+ }
51
+
52
+ if (propsData.length === 0) {
53
+ return (
54
+ <EmptyBarChart
55
+ data={propsData}
56
+ emptyComponent={emptyComponent}
57
+ id={id}
58
+ localeText={localeText}
59
+ size={size}
60
+ {...forwardedProps}
61
+ ref={ref}
62
+ />
63
+ );
64
+ }
65
+
66
+ return (
67
+ <RenderedBarChart
68
+ areXLabelsRotated={areXLabelsRotated}
69
+ barRole={barRole}
70
+ caping={caping}
71
+ chartRef={chartRef}
72
+ className={classNames(BarChart.className, className)}
73
+ data={propsData}
74
+ id={id}
75
+ isBarSelected={isBarSelected}
76
+ labelDecorator={labelDecorator}
77
+ onBarClick={onBarClick}
78
+ others={others}
79
+ size={size}
80
+ theme={theme}
81
+ tooltipVariant={tooltipVariant}
82
+ {...forwardedProps}
83
+ ref={ref}
84
+ />
85
+ );
86
+ }
87
+ );
88
+ BarChart.className = CLASSNAME;
89
+ BarChart.defaultProps = DEFAULT_PROPS;
90
+ BarChart.displayName = COMPONENT_NAME;
@@ -0,0 +1,58 @@
1
+ import React, { forwardRef, RefObject, useRef } from 'react';
2
+ import { scaleLinear as d3scaleLinear, ScaleLinear as d3ScaleLinear } from 'd3';
3
+
4
+ import { AnyScale } from '../../types';
5
+ import { BarChartProps } from './types';
6
+ import { StyledBarChart, StyledBarChartEmptyText } from './styles';
7
+ import { Axis } from '../Axis';
8
+ import { sizeToDimension } from './utils';
9
+
10
+ export const EmptyBarChart = forwardRef<HTMLDivElement, BarChartProps>(
11
+ (props, ref) => {
12
+ const { className, emptyComponent, size, localeText, ...forwardedProps } =
13
+ props;
14
+
15
+ const chartDimensions = sizeToDimension(size!);
16
+ const width = chartDimensions.width;
17
+ const height = chartDimensions.height;
18
+ const margins = { top: 16, left: 16, right: 16, bottom: 32 };
19
+ const chartHeight = height - margins.top - margins.bottom;
20
+ const chartWidth = width - margins.left - margins.right;
21
+
22
+ const scaleRef = useRef<d3ScaleLinear<number, number>>();
23
+ if (!scaleRef.current) {
24
+ scaleRef.current = d3scaleLinear().domain([]).range([0, chartWidth]);
25
+ }
26
+
27
+ return (
28
+ <StyledBarChart
29
+ {...forwardedProps}
30
+ className={className}
31
+ ref={ref as RefObject<HTMLDivElement>}
32
+ >
33
+ {emptyComponent ?? (
34
+ <>
35
+ <StyledBarChartEmptyText
36
+ $maxWidth={width}
37
+ $textSize={chartDimensions.fontSize / 2}
38
+ >
39
+ <span>{localeText?.emptyChartText}</span>
40
+ </StyledBarChartEmptyText>
41
+ <svg width={width} height={height}>
42
+ <g transform={`translate(${margins.left},${margins.top})`}>
43
+ <Axis
44
+ position="bottom"
45
+ length={chartWidth}
46
+ scale={scaleRef.current as AnyScale}
47
+ x={0}
48
+ y={chartHeight}
49
+ tickValues={4}
50
+ />
51
+ </g>
52
+ </svg>
53
+ </>
54
+ )}
55
+ </StyledBarChart>
56
+ );
57
+ }
58
+ );
@@ -0,0 +1,20 @@
1
+ import React, { forwardRef, RefObject } from 'react';
2
+
3
+ import { BarChartProps } from './types';
4
+ import { StyledBarChart } from './styles';
5
+
6
+ export const LoadingBarChart = forwardRef<HTMLDivElement, BarChartProps>(
7
+ (props, ref) => {
8
+ const { className, ...forwardedProps } = props;
9
+
10
+ return (
11
+ <StyledBarChart
12
+ {...forwardedProps}
13
+ className={className}
14
+ ref={ref as RefObject<HTMLDivElement>}
15
+ >
16
+ Loading...
17
+ </StyledBarChart>
18
+ );
19
+ }
20
+ );
@@ -0,0 +1,137 @@
1
+ import React, {
2
+ forwardRef,
3
+ RefObject,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ } from 'react';
8
+ import {
9
+ scaleLinear as d3scaleLinear,
10
+ ScaleLinear as d3ScaleLinear,
11
+ sum as d3sum,
12
+ } from 'd3';
13
+
14
+ import { AnyScale, CategoryData } from '../../types';
15
+ import { BarChartProps } from './types';
16
+ import { StyledBarChart } from './styles';
17
+ import { Bar } from '../Bar';
18
+ import { Axis } from '../Axis';
19
+ import { useFormatCategoricalData } from '../../hooks';
20
+ import { sizeToDimension } from './utils';
21
+
22
+ interface RenderedBarChartProps
23
+ extends Required<Pick<BarChartProps, 'data'>>,
24
+ Omit<BarChartProps, 'data'> {}
25
+
26
+ export const RenderedBarChart = forwardRef<
27
+ HTMLDivElement,
28
+ RenderedBarChartProps
29
+ >((props, ref) => {
30
+ const {
31
+ areXLabelsRotated,
32
+ barProps,
33
+ caping,
34
+ className,
35
+ data: propsData,
36
+ id,
37
+ isBarSelected,
38
+ labelDecorator,
39
+ onBarClick,
40
+ others,
41
+ size,
42
+ barRole,
43
+ theme,
44
+ tooltipVariant,
45
+ ...forwardedProps
46
+ } = props;
47
+
48
+ const cache = useRef<CategoryData>();
49
+
50
+ const { data, colorScale } = useFormatCategoricalData({
51
+ data: propsData,
52
+ theme: theme!,
53
+ caping,
54
+ others,
55
+ });
56
+
57
+ useEffect(() => {
58
+ cache.current = data;
59
+ });
60
+
61
+ const chartDimensions = sizeToDimension(size!);
62
+ const width = chartDimensions.width;
63
+ const height = chartDimensions.height;
64
+ const margins = { top: 16, left: 16, right: 16, bottom: 32 };
65
+ const chartHeight = height - margins.top - margins.bottom;
66
+ const chartWidth = width - margins.left - margins.right;
67
+ const numberOfRows = data.length;
68
+ const gap = 5;
69
+
70
+ const scale = useMemo<d3ScaleLinear<number, number>>(
71
+ () =>
72
+ d3scaleLinear()
73
+ .domain([0, Math.max(...data.map(({ value }) => value))])
74
+ .range([0, chartWidth]),
75
+ [size]
76
+ );
77
+
78
+ const barHeight = (chartHeight - (numberOfRows + 1) * gap) / numberOfRows;
79
+ const total = d3sum(data, (d) => d.value);
80
+
81
+ return (
82
+ <StyledBarChart
83
+ {...forwardedProps}
84
+ id={id}
85
+ className={className}
86
+ ref={ref as RefObject<HTMLDivElement>}
87
+ >
88
+ <svg width={width} height={height}>
89
+ <g transform={`translate(${margins.left},${margins.top})`}>
90
+ <Axis
91
+ position="bottom"
92
+ length={chartWidth}
93
+ scale={scale as AnyScale}
94
+ x={0}
95
+ y={chartHeight}
96
+ tickValues={4}
97
+ tickRotation={areXLabelsRotated ? -45 : 0}
98
+ />
99
+ {data
100
+ .filter((datum) => datum.value)
101
+ .map((datum, index) => {
102
+ const percent = datum.value / total;
103
+ const to = {
104
+ data: {
105
+ ...datum,
106
+ percent,
107
+ },
108
+ };
109
+ const from = cache.current
110
+ ? { data: cache.current[index] }
111
+ : undefined;
112
+
113
+ return (
114
+ <Bar
115
+ {...barProps}
116
+ color={colorScale?.(to.data.key)!}
117
+ data={to}
118
+ gap={gap}
119
+ height={barHeight}
120
+ id={`id${id}__bar-${index}`}
121
+ index={index}
122
+ isSelected={Boolean(isBarSelected!(to))}
123
+ key={`bar _${index}`}
124
+ labelDecorator={labelDecorator}
125
+ onClick={onBarClick}
126
+ previousData={from!}
127
+ role={barRole}
128
+ scale={scale!}
129
+ tooltipVariant={tooltipVariant}
130
+ />
131
+ );
132
+ })}
133
+ </g>
134
+ </svg>
135
+ </StyledBarChart>
136
+ );
137
+ });