@scality/core-ui 0.162.0 → 0.163.0

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 (68) hide show
  1. package/dist/components/barchartv2/Barchart.component.d.ts +0 -2
  2. package/dist/components/barchartv2/Barchart.component.d.ts.map +1 -1
  3. package/dist/components/barchartv2/Barchart.component.js +11 -1
  4. package/dist/components/barchartv2/utils.d.ts +25 -2
  5. package/dist/components/barchartv2/utils.d.ts.map +1 -1
  6. package/dist/components/barchartv2/utils.js +35 -3
  7. package/dist/components/chartlegend/ChartLegend.d.ts +8 -0
  8. package/dist/components/chartlegend/ChartLegend.d.ts.map +1 -0
  9. package/dist/components/chartlegend/ChartLegend.js +65 -0
  10. package/dist/components/chartlegend/ChartLegendWrapper.d.ts +17 -0
  11. package/dist/components/chartlegend/ChartLegendWrapper.d.ts.map +1 -0
  12. package/dist/components/chartlegend/ChartLegendWrapper.js +50 -0
  13. package/dist/components/date/FormattedDateTime.d.ts +3 -1
  14. package/dist/components/date/FormattedDateTime.d.ts.map +1 -1
  15. package/dist/components/date/FormattedDateTime.js +19 -1
  16. package/dist/components/date/FormattedDateTime.spec.js +12 -0
  17. package/dist/components/icon/Icon.component.d.ts +5 -5
  18. package/dist/components/icon/Icon.component.d.ts.map +1 -1
  19. package/dist/components/icon/Icon.component.js +33 -31
  20. package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts +33 -0
  21. package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts.map +1 -0
  22. package/dist/components/linetimeseriechart/linetimeseriechart.component.js +249 -0
  23. package/dist/components/selectv2/Selectv2.component.d.ts.map +1 -1
  24. package/dist/components/selectv2/Selectv2.component.js +11 -6
  25. package/dist/components/steppers/Stepper.component.d.ts.map +1 -1
  26. package/dist/components/steppers/Stepper.component.js +9 -8
  27. package/dist/components/toast/ToastProvider.d.ts.map +1 -1
  28. package/dist/components/toast/ToastProvider.js +4 -5
  29. package/dist/components/vegachartv2/SyncedCursorCharts.d.ts.map +1 -1
  30. package/dist/components/vegachartv2/SyncedCursorCharts.js +3 -5
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -0
  34. package/dist/next.d.ts +1 -0
  35. package/dist/next.d.ts.map +1 -1
  36. package/dist/next.js +1 -0
  37. package/dist/style/theme.d.ts +1 -0
  38. package/dist/style/theme.d.ts.map +1 -1
  39. package/dist/style/theme.js +28 -0
  40. package/package.json +2 -2
  41. package/src/lib/components/accordion/Accordion.test.tsx +7 -15
  42. package/src/lib/components/barchartv2/Barchart.component.test.tsx +82 -101
  43. package/src/lib/components/barchartv2/Barchart.component.tsx +14 -2
  44. package/src/lib/components/barchartv2/utils.test.ts +117 -0
  45. package/src/lib/components/barchartv2/utils.ts +54 -6
  46. package/src/lib/components/chartlegend/ChartLegend.tsx +113 -0
  47. package/src/lib/components/chartlegend/ChartLegendWrapper.tsx +85 -0
  48. package/src/lib/components/date/FormattedDateTime.spec.tsx +24 -0
  49. package/src/lib/components/date/FormattedDateTime.tsx +36 -2
  50. package/src/lib/components/healthselectorv2/HealthSelector.component.test.tsx +3 -3
  51. package/src/lib/components/icon/Icon.component.tsx +48 -60
  52. package/src/lib/components/inlineinput/InlineInput.test.tsx +22 -19
  53. package/src/lib/components/inputlist/InputList.test.tsx +21 -19
  54. package/src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx +502 -0
  55. package/src/lib/components/searchinput/SearchInput.test.tsx +3 -7
  56. package/src/lib/components/selectv2/Selectv2.component.tsx +13 -5
  57. package/src/lib/components/selectv2/selectv2.test.tsx +62 -57
  58. package/src/lib/components/steppers/Stepper.component.tsx +10 -8
  59. package/src/lib/components/tablev2/TableSync.test.tsx +8 -11
  60. package/src/lib/components/tablev2/Tablev2.test.tsx +36 -37
  61. package/src/lib/components/toast/ToastProvider.tsx +14 -6
  62. package/src/lib/components/vegachartv2/SyncedCursorCharts.tsx +5 -7
  63. package/src/lib/index.ts +1 -0
  64. package/src/lib/next.ts +1 -0
  65. package/src/lib/style/theme.ts +29 -0
  66. package/stories/BarChart/barchart.stories.tsx +292 -125
  67. package/stories/format.mdx +4 -2
  68. package/stories/linetimeseriechart.stories.tsx +485 -0
@@ -1,15 +1,10 @@
1
- import { screen, render as testingRender } from '@testing-library/react';
1
+ import { act, screen, render as testingRender, waitFor } from '@testing-library/react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import React, { useState, useRef } from 'react';
4
- import { QueryClient, QueryClientProvider } from 'react-query';
5
4
  import { Option, Select, SelectRef } from '../selectv2/Selectv2.component';
6
5
 
7
6
  const render = (args) => {
8
- return testingRender(
9
- <QueryClientProvider client={new QueryClient()}>
10
- {args}
11
- </QueryClientProvider>,
12
- );
7
+ return testingRender(args);
13
8
  };
14
9
 
15
10
  const generateOptionsData = (n: number) =>
@@ -74,27 +69,29 @@ describe('SelectV2', () => {
74
69
  expect(() => render(<Option value="Option 1" />)).toThrowError();
75
70
  });
76
71
 
77
- it('should open/close on click', () => {
72
+ it('should open/close on click', async () => {
78
73
  render(<SelectWrapper />);
74
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
79
75
  const select = selectors.select();
80
76
  expect(select).toBeInTheDocument();
81
77
  let options = selectors.options();
82
78
  expect(options).toHaveLength(0);
83
79
 
84
80
  // should open on click
85
- userEvent.click(select);
81
+ await act(() => userEvent.click(select));
86
82
  simpleOptions.forEach((opt) => {
87
83
  const option = selectors.option(opt.props.label);
88
84
  expect(option).toBeInTheDocument();
89
85
  });
90
86
 
91
- userEvent.click(select);
87
+ await act(() => userEvent.click(select));
92
88
  options = selectors.options();
93
89
  expect(options).toHaveLength(0);
94
90
  });
95
91
 
96
- it('should open/close with keyboard', () => {
92
+ it('should open/close with keyboard', async () => {
97
93
  render(<SelectWrapper />);
94
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
98
95
  const select = selectors.select();
99
96
  expect(select).toBeInTheDocument();
100
97
  const options = selectors.options();
@@ -102,7 +99,7 @@ describe('SelectV2', () => {
102
99
 
103
100
  // should open on Enter
104
101
  userEvent.tab();
105
- userEvent.keyboard('{Enter}');
102
+ await act(() => userEvent.keyboard('{Enter}'));
106
103
  simpleOptions.forEach((opt) => {
107
104
  const option = selectors.option(opt.props.label);
108
105
  expect(option).toBeInTheDocument();
@@ -121,13 +118,14 @@ describe('SelectV2', () => {
121
118
  });
122
119
  });
123
120
 
124
- it('should display custom placeholder', () => {
121
+ it('should display custom placeholder', async () => {
125
122
  const placeholder = 'My placeholder...';
126
123
  render(<SelectWrapper placeholder={placeholder} />);
124
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
127
125
  expect(screen.getByText(placeholder)).toBeInTheDocument();
128
126
  });
129
127
 
130
- it('should be disabled', () => {
128
+ it('should be disabled', async () => {
131
129
  render(
132
130
  <SelectWrapper value="1" disabled={true}>
133
131
  {simpleOptions}
@@ -139,27 +137,29 @@ describe('SelectV2', () => {
139
137
  // use input instead of select because select will still trigger the open/close action
140
138
  // despite select container not being clickable and input being disabled
141
139
  const input = selectors.input();
142
- userEvent.click(input);
140
+ await act(() => userEvent.click(input));
143
141
  const options = selectors.options();
144
142
  expect(options).toHaveLength(0);
145
143
  });
146
144
 
147
- it('should display no option', () => {
145
+ it('should display no option', async () => {
148
146
  render(
149
147
  <SelectWrapper>
150
148
  <></>
151
149
  </SelectWrapper>,
152
150
  );
151
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
153
152
  const select = selectors.select();
154
- userEvent.click(select);
153
+ await act(() => userEvent.click(select));
155
154
  const noOptions = selectors.noOptions();
156
155
  expect(noOptions).toBeInTheDocument();
157
156
  });
158
157
 
159
- it('should filter and highlight on search', () => {
158
+ it('should filter and highlight on search', async () => {
160
159
  render(<SelectWrapper>{optionsWithScrollSearchBar} </SelectWrapper>);
160
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
161
161
  const select = selectors.select(true);
162
- userEvent.click(select);
162
+ await act(() => userEvent.click(select));
163
163
  const input = selectors.input();
164
164
 
165
165
  userEvent.type(input, '2');
@@ -169,25 +169,26 @@ describe('SelectV2', () => {
169
169
  expect(searchedText).toHaveTextContent('2');
170
170
  });
171
171
 
172
- it('should unfocus the search input when the select is closed', () => {
172
+ it('should unfocus the search input when the select is closed', async () => {
173
173
  render(<SelectWrapper>{optionsWithScrollSearchBar} </SelectWrapper>);
174
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
174
175
  const select = selectors.select(true);
175
- userEvent.click(select);
176
+ await act(() => userEvent.click(select));
176
177
  let input = selectors.input();
177
178
  expect(input).toHaveFocus();
178
179
  const option = selectors.option(/Item 1/);
179
- userEvent.click(option);
180
+ await act(() => userEvent.click(option));
180
181
  input = selectors.input();
181
182
  expect(input).not.toHaveFocus();
182
183
  });
183
184
 
184
- it('should be possible to use searchbar when option is selected', () => {
185
+ it('should be possible to use searchbar when option is selected', async () => {
185
186
  render(
186
187
  <SelectWrapper value="1">{optionsWithScrollSearchBar}</SelectWrapper>,
187
188
  );
188
189
  expect(screen.getByText(/Item 1/)).toBeVisible();
189
190
  const select = selectors.select(true);
190
- userEvent.click(select);
191
+ await act(() => userEvent.click(select));
191
192
  const input = selectors.input();
192
193
  userEvent.type(input, '2');
193
194
  expect(screen.queryByText(/Item 1/)).not.toBeInTheDocument();
@@ -195,47 +196,48 @@ describe('SelectV2', () => {
195
196
  expect(options).toHaveLength(1);
196
197
  });
197
198
 
198
- it('should select/unselect option with keyboard', () => {
199
+ it('should select/unselect option with keyboard', async () => {
199
200
  render(<SelectWrapper />);
201
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
200
202
  const select = selectors.select();
201
203
  userEvent.tab();
202
- userEvent.keyboard('{ArrowDown}');
204
+ act(() => userEvent.keyboard('{ArrowDown}'));
203
205
 
204
206
  // should select first option
205
- userEvent.keyboard('{Enter}');
207
+ await act(() => userEvent.keyboard('{Enter}'));
206
208
  expect(select).toHaveTextContent('Item 0');
207
209
 
208
210
  // should select second option
209
211
  userEvent.tab();
210
- userEvent.keyboard('{ArrowDown}');
211
- userEvent.keyboard('{ArrowDown}');
212
+ await act(() => userEvent.keyboard('{ArrowDown}'));
213
+ await act(() => userEvent.keyboard('{ArrowDown}'));
212
214
 
213
- userEvent.keyboard('{Enter}');
215
+ await act(() => userEvent.keyboard('{Enter}'));
214
216
  expect(select).toHaveTextContent('Item 1');
215
217
  });
216
218
 
217
- it('should scroll to selected value when opening select', () => {
219
+ it('should scroll to selected value when opening select', async () => {
218
220
  render(
219
221
  <SelectWrapper value={optionsWithScrollSearchBar[9].props.value}>
220
222
  {optionsWithScrollSearchBar}
221
223
  </SelectWrapper>,
222
224
  );
223
225
  const select = selectors.select(true);
224
- userEvent.click(select);
226
+ await act(() => userEvent.click(select));
225
227
  const option = selectors.option(/Item 9/);
226
228
  expect(screen.queryByRole('option', { name: /Item 1/i })).toBeNull();
227
229
  expect(option).toBeVisible();
228
230
  });
229
231
 
230
- it('should be able to reset the value', () => {
232
+ it('should be able to reset the value', async () => {
231
233
  render(<SelectReset>{simpleOptions}</SelectReset>);
232
234
  const button = screen.getByText(/reset/);
233
- userEvent.click(button);
235
+ await act(() => userEvent.click(button));
234
236
  const select = selectors.select();
235
237
  expect(select).toHaveTextContent('Select...');
236
238
  });
237
239
 
238
- it('should not be possible to select an option if it is disabled', () => {
240
+ it('should not be possible to select an option if it is disabled', async () => {
239
241
  render(
240
242
  <SelectWrapper>
241
243
  <Option value="1" disabled>
@@ -245,15 +247,15 @@ describe('SelectV2', () => {
245
247
  </SelectWrapper>,
246
248
  );
247
249
  const select = selectors.select();
248
- userEvent.click(select);
250
+ await act(() => userEvent.click(select));
249
251
  const option = selectors.option(/Item 1/);
250
252
 
251
- userEvent.click(option);
253
+ await act(() => userEvent.click(option));
252
254
  const option2 = selectors.option(/Item 2/);
253
255
  expect(option2).toBeVisible();
254
256
  });
255
257
 
256
- it('should display a tooltip if the option is disabled with a reason', () => {
258
+ it('should display a tooltip if the option is disabled with a reason', async () => {
257
259
  render(
258
260
  <SelectWrapper>
259
261
  <Option value="1" disabled disabledReason="This option is disabled">
@@ -262,10 +264,10 @@ describe('SelectV2', () => {
262
264
  </SelectWrapper>,
263
265
  );
264
266
  const select = selectors.select();
265
- userEvent.click(select);
267
+ await act(() => userEvent.click(select));
266
268
  const option = selectors.option(/Item 1/);
267
269
  expect(option).toHaveAttribute('aria-disabled', 'true');
268
- userEvent.hover(option);
270
+ await act(() => userEvent.hover(option));
269
271
  const tooltip = screen.getByText(/This option is disabled/);
270
272
  expect(tooltip).toBeInTheDocument();
271
273
  });
@@ -309,9 +311,9 @@ describe('SelectV2', () => {
309
311
  // It's not our case here, so it makes thing difficult to select the right select
310
312
  // I workaround this by using setting the aria-label to the select container (cf: test below)
311
313
  const singleSelect = screen.getByRole('listbox');
312
- await userEvent.click(singleSelect);
314
+ await act(() => userEvent.click(singleSelect));
313
315
 
314
- await userEvent.click(screen.getByRole('option', { name: /account 1/i }));
316
+ await act(() => userEvent.click(screen.getByRole('option', { name: /account 1/i })));
315
317
  });
316
318
 
317
319
  it('should be testable if we have several select', async () => {
@@ -372,13 +374,13 @@ describe('SelectV2', () => {
372
374
 
373
375
  render(<MyWrapperWith2Select />);
374
376
 
375
- await userEvent.click(screen.getByLabelText(/select account/i));
377
+ await act(() => userEvent.click(screen.getByLabelText(/select account/i)));
376
378
 
377
- await userEvent.click(screen.getByRole('option', { name: /account 1/i }));
379
+ await act(() => userEvent.click(screen.getByRole('option', { name: /account 1/i })));
378
380
 
379
- await userEvent.click(screen.getByLabelText(/select user/i));
381
+ await act(() => userEvent.click(screen.getByLabelText(/select user/i)));
380
382
 
381
- await userEvent.click(screen.getByRole('option', { name: /user 1/i }));
383
+ await act(() => userEvent.click(screen.getByRole('option', { name: /user 1/i })));
382
384
  });
383
385
 
384
386
  it('should be testable even if we have several select with the same value, the placeholder should be different', async () => {
@@ -439,8 +441,8 @@ describe('SelectV2', () => {
439
441
 
440
442
  render(<MyWrapperWith2Select />);
441
443
 
442
- await userEvent.click(screen.getByLabelText(/select account/i));
443
- await userEvent.click(screen.getByLabelText(/Select Second Account/i));
444
+ await act(() => userEvent.click(screen.getByLabelText(/select account/i)));
445
+ await act(() => userEvent.click(screen.getByLabelText(/Select Second Account/i)));
444
446
 
445
447
  /**
446
448
  * This is possible because only 1 select can be open at a time
@@ -450,7 +452,7 @@ describe('SelectV2', () => {
450
452
  * const selectContainer = select?.parentElement?.parentElement;
451
453
  * const option = within(selectContainer).getByRole('option', { name: /account 1/i });
452
454
  */
453
- await userEvent.click(screen.getByRole('option', { name: /account 1/i }));
455
+ await act(() => userEvent.click(screen.getByRole('option', { name: /account 1/i })));
454
456
  });
455
457
 
456
458
  describe('Ref API', () => {
@@ -478,7 +480,7 @@ describe('SelectV2', () => {
478
480
  render(<RefTestComponent />);
479
481
  expect(selectors.input()).not.toHaveFocus();
480
482
 
481
- userEvent.click(screen.getByRole('button', { name: /Focus/i }));
483
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Focus/i })));
482
484
  expect(selectors.input()).toHaveFocus();
483
485
  });
484
486
 
@@ -511,14 +513,14 @@ describe('SelectV2', () => {
511
513
  render(<RefTestComponent />);
512
514
  expect(selectors.options()).toHaveLength(0);
513
515
 
514
- userEvent.click(screen.getByRole('button', { name: /Open Menu/i }));
516
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Open Menu/i })));
515
517
  expect(selectors.options().length).toBeGreaterThan(0);
516
518
  simpleOptions.forEach((opt) => {
517
519
  const option = selectors.option(opt.props.label);
518
520
  expect(option).toBeInTheDocument();
519
521
  });
520
522
 
521
- userEvent.click(screen.getByRole('button', { name: /Close Menu/i }));
523
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Close Menu/i })));
522
524
  expect(selectors.options()).toHaveLength(0);
523
525
  });
524
526
 
@@ -565,13 +567,16 @@ describe('SelectV2', () => {
565
567
 
566
568
  render(<RefTestComponent />);
567
569
 
568
- const select = selectors.select();
570
+ let select;
571
+ await act(() => {
572
+ select = selectors.select();
573
+ });
569
574
  expect(select).toHaveTextContent('Select with ref');
570
575
 
571
- userEvent.click(screen.getByRole('button', { name: /Set Value/i }));
576
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Set Value/i })));
572
577
  expect(select).toHaveTextContent('Item 0');
573
578
 
574
- userEvent.click(screen.getByRole('button', { name: /Clear/i }));
579
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Clear/i })));
575
580
  expect(select).toHaveTextContent('Select with ref');
576
581
  });
577
582
 
@@ -599,10 +604,10 @@ describe('SelectV2', () => {
599
604
 
600
605
  render(<RefTestComponent />);
601
606
 
602
- userEvent.click(screen.getByRole('button', { name: /Focus/i }));
607
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Focus/i })));
603
608
  expect(selectors.input()).toHaveFocus();
604
609
 
605
- userEvent.click(screen.getByRole('button', { name: /Blur/i }));
610
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Blur/i })));
606
611
  expect(selectors.input()).not.toHaveFocus();
607
612
  });
608
613
  });
@@ -1,5 +1,5 @@
1
1
  /// <reference path="./Stepper.component.d.ts" />
2
- import { createContext, useContext, useState } from 'react';
2
+ import { createContext, useContext, useState, useCallback, useMemo } from 'react';
3
3
  import { Steppers } from './Steppers.component';
4
4
  import { Box } from '../box/Box';
5
5
  export interface StepperContextType {
@@ -33,19 +33,21 @@ export const Stepper: Stepper = ({ steps }) => {
33
33
  props: Record<string, unknown>;
34
34
  }>({ step: 0, props: {} });
35
35
 
36
- const next = (props: Record<string, unknown>) => {
37
- setStepProps({ step: stepProps.step + 1, props });
38
- };
36
+ const next = useCallback((props: Record<string, unknown>) => {
37
+ setStepProps(current => ({ step: current.step + 1, props }));
38
+ }, []);
39
39
 
40
- const prev = (props: Record<string, unknown>) => {
41
- setStepProps({ step: stepProps.step - 1, props });
42
- };
40
+ const prev = useCallback((props: Record<string, unknown>) => {
41
+ setStepProps(current => ({ step: current.step - 1, props }));
42
+ }, []);
43
43
 
44
44
  const { Component } = steps[stepProps.step];
45
45
  const StepperContext = window.StepperContext;
46
46
 
47
+ const stepperValue = useMemo(() => ({ next, prev }), [next, prev]);
48
+
47
49
  return (
48
- <StepperContext.Provider value={{ next, prev }}>
50
+ <StepperContext.Provider value={stepperValue}>
49
51
  <Box display="flex" gap={32} flex={1} height="100%">
50
52
  <Steppers
51
53
  activeStep={stepProps.step}
@@ -1,31 +1,28 @@
1
- import { fireEvent, render, screen } from '@testing-library/react';
1
+ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
2
2
  import React from 'react';
3
3
  import { TableSync } from './TableSync';
4
- import { QueryClient, QueryClientProvider } from 'react-query';
5
4
 
6
5
  describe('TableSync', () => {
7
- it('should render correctly', () => {
6
+ it('should render correctly', async () => {
8
7
  const onSync = jest.fn();
9
8
  render(
10
- <QueryClientProvider client={new QueryClient()}>
11
- <TableSync onSync={onSync} />
12
- </QueryClientProvider>,
9
+ <TableSync onSync={onSync} />
13
10
  );
11
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
14
12
 
15
13
  const button = screen.getByRole('button');
16
14
  expect(button).toBeInTheDocument();
17
15
  });
18
16
 
19
- it('should call onSync when clicked', () => {
17
+ it('should call onSync when clicked', async () => {
20
18
  const onSync = jest.fn();
21
19
  render(
22
- <QueryClientProvider client={new QueryClient()}>
23
- <TableSync onSync={onSync} />
24
- </QueryClientProvider>,
20
+ <TableSync onSync={onSync} />
25
21
  );
22
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
26
23
 
27
24
  const button = screen.getByRole('button');
28
- fireEvent.click(button);
25
+ await act(() => fireEvent.click(button));
29
26
  expect(onSync).toHaveBeenCalledTimes(1);
30
27
  });
31
28
  });
@@ -1,7 +1,6 @@
1
1
  import { Table } from './Tablev2.component';
2
2
  import React from 'react';
3
- import { render } from '@testing-library/react';
4
- import { QueryClient, QueryClientProvider } from 'react-query';
3
+ import { render, screen, waitFor } from '@testing-library/react';
5
4
 
6
5
  jest.mock('./TableUtils', () => ({
7
6
  ...jest.requireActual('./TableUtils'),
@@ -66,17 +65,17 @@ const columns = [
66
65
  describe('TableV2', () => {
67
66
  test('it should display all the data', async () => {
68
67
  const { getAllByRole } = render(
69
- <QueryClientProvider client={new QueryClient()}>
70
- <div>
71
- <Table columns={columns} data={data} defaultSortingKey={'health'}>
72
- <Table.SingleSelectableContent
73
- rowHeight="h40"
74
- separationLineVariant="backgroundLevel3"
75
- />
76
- </Table>
77
- </div>
78
- </QueryClientProvider>,
68
+ <div>
69
+ <Table columns={columns} data={data} defaultSortingKey={'health'}>
70
+ <Table.SingleSelectableContent
71
+ rowHeight="h40"
72
+ separationLineVariant="backgroundLevel3"
73
+ />
74
+ </Table>
75
+ </div>
79
76
  );
77
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
78
+
80
79
  // we check that the table is displaying all the data
81
80
  const rows = getAllByRole('row');
82
81
  expect(rows[4]).toHaveTextContent(/Ninette/i);
@@ -85,17 +84,17 @@ describe('TableV2', () => {
85
84
  });
86
85
  test('it should sort by defaultSortingKey', async () => {
87
86
  const { getAllByRole } = render(
88
- <QueryClientProvider client={new QueryClient()}>
89
- <div>
90
- <Table columns={columns} data={data} defaultSortingKey={'firstName'}>
91
- <Table.SingleSelectableContent
92
- rowHeight="h40"
93
- separationLineVariant="backgroundLevel3"
94
- />
95
- </Table>
96
- </div>
97
- </QueryClientProvider>,
87
+ <div>
88
+ <Table columns={columns} data={data} defaultSortingKey={'firstName'}>
89
+ <Table.SingleSelectableContent
90
+ rowHeight="h40"
91
+ separationLineVariant="backgroundLevel3"
92
+ />
93
+ </Table>
94
+ </div>
98
95
  );
96
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
97
+
99
98
  // we check that the table is displaying all the data
100
99
  const rows = getAllByRole('row');
101
100
  expect(rows[1]).toHaveTextContent(/ninette/i);
@@ -104,22 +103,22 @@ describe('TableV2', () => {
104
103
  });
105
104
  test('it should filterGlobally', async () => {
106
105
  const { getAllByRole } = render(
107
- <QueryClientProvider client={new QueryClient()}>
108
- <div>
109
- <Table
110
- columns={columns}
111
- data={data}
112
- defaultSortingKey={'firstName'}
113
- globalFilter="an"
114
- >
115
- <Table.SingleSelectableContent
116
- rowHeight="h40"
117
- separationLineVariant="backgroundLevel3"
118
- />
119
- </Table>
120
- </div>
121
- </QueryClientProvider>,
106
+ <div>
107
+ <Table
108
+ columns={columns}
109
+ data={data}
110
+ defaultSortingKey={'firstName'}
111
+ globalFilter="an"
112
+ >
113
+ <Table.SingleSelectableContent
114
+ rowHeight="h40"
115
+ separationLineVariant="backgroundLevel3"
116
+ />
117
+ </Table>
118
+ </div>
122
119
  );
120
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
121
+
123
122
  // we check that the table is displaying all the data
124
123
  const rows = getAllByRole('row');
125
124
  expect(rows[1]).toHaveTextContent(/an/i); //first name yoh-an-n
@@ -1,4 +1,4 @@
1
- import { ReactNode, createContext, useContext, useState } from 'react';
1
+ import { ReactNode, createContext, useCallback, useContext, useMemo, useState } from 'react';
2
2
  import { Toast, ToastProps } from './Toast.component';
3
3
 
4
4
  export type ToastContextState = Omit<ToastProps, 'onClose'>;
@@ -14,20 +14,27 @@ export const ToastContext = createContext<ToastContextType | undefined>(
14
14
  interface ToastProviderProps {
15
15
  children: ReactNode;
16
16
  }
17
+
17
18
  export const ToastProvider: React.FC<
18
19
  React.PropsWithChildren<ToastProviderProps>
19
20
  > = ({ children }) => {
20
21
  const [toastProps, setToastProps] = useState<ToastContextState | null>(null);
21
22
 
22
- const showToast = (toastProps: ToastContextState) => {
23
- setToastProps(toastProps);
24
- };
23
+ const toastCtxValue = useMemo(
24
+ () => ({ showToast: setToastProps }),
25
+ [],
26
+ );
27
+
28
+ const closeToast = useCallback(
29
+ () => setToastProps(null),
30
+ []
31
+ );
25
32
 
26
33
  return (
27
- <ToastContext.Provider value={{ showToast }}>
34
+ <ToastContext.Provider value={toastCtxValue}>
28
35
  {children}
29
36
  {toastProps && (
30
- <Toast {...toastProps} onClose={() => setToastProps(null)} />
37
+ <Toast {...toastProps} onClose={closeToast} />
31
38
  )}
32
39
  </ToastContext.Provider>
33
40
  );
@@ -38,5 +45,6 @@ export const useToast = () => {
38
45
  if (!context) {
39
46
  throw new Error('useToast must be used within a ToastProvider');
40
47
  }
48
+
41
49
  return context;
42
50
  };
@@ -1,4 +1,4 @@
1
- import { useState, createContext, useContext } from 'react';
1
+ import { useState, createContext, useContext, useMemo, useCallback } from 'react';
2
2
  export const SyncedCursorChartsContext = createContext<{
3
3
  cursorX: number;
4
4
  setCursorX: (cursorX: number) => void;
@@ -17,13 +17,11 @@ export const useCursorX = (): {
17
17
  };
18
18
  export function SyncedCursorCharts({ children }: { children: JSX.Element }) {
19
19
  const [cursorX, setCursorX] = useState(0);
20
+
21
+ const contextValue = useMemo(() => ({cursorX, setCursorX}), [cursorX]);
22
+
20
23
  return (
21
- <SyncedCursorChartsContext.Provider
22
- value={{
23
- cursorX,
24
- setCursorX,
25
- }}
26
- >
24
+ <SyncedCursorChartsContext.Provider value={contextValue}>
27
25
  {children}
28
26
  </SyncedCursorChartsContext.Provider>
29
27
  );
package/src/lib/index.ts CHANGED
@@ -82,3 +82,4 @@ export { InfoMessage } from './components/infomessage/InfoMessage.component';
82
82
  export { InputList } from './components/inputlist/InputList.component';
83
83
  export { InlineInput } from './components/inlineinput/InlineInput';
84
84
  export { UnsuccessfulResult } from './components/UnsuccessfulResult.component';
85
+ export { LineTimeSerieChart } from './components/linetimeseriechart/linetimeseriechart.component';
package/src/lib/next.ts CHANGED
@@ -21,3 +21,4 @@ export {
21
21
  BarchartSortFn,
22
22
  BarchartTooltipFn,
23
23
  } from './components/barchartv2/Barchart.component';
24
+ export { ChartLegendWrapper } from './components/chartlegend/ChartLegendWrapper';
@@ -1,3 +1,4 @@
1
+ import { lighten, darken } from 'polished';
1
2
  //== Colors
2
3
  export const hotPink = '#E40046';
3
4
  export const pink = '#EB4962';
@@ -291,3 +292,31 @@ export const navbarItemWidth = '4.286rem';
291
292
  //sidebar
292
293
  export const sidebarItemHeight = spacing.sp40;
293
294
  export const sidebarWidth = spacing.sp40;
295
+
296
+ // We use 8 main color from the palette and decline them (lighter/ darker) when we have more than 8 datasets
297
+ export const lineTimeSeriesColorRange = [
298
+ lineColor1,
299
+ lineColor2,
300
+ lineColor3,
301
+ lineColor4,
302
+ lineColor5,
303
+ lineColor6,
304
+ lineColor7,
305
+ lineColor8,
306
+ lighten(0.3, lineColor1),
307
+ lighten(0.3, lineColor2),
308
+ lighten(0.3, lineColor3),
309
+ lighten(0.3, lineColor4),
310
+ lighten(0.3, lineColor5),
311
+ lighten(0.3, lineColor6),
312
+ lighten(0.3, lineColor7),
313
+ lighten(0.3, lineColor8),
314
+ darken(0.2, lineColor1),
315
+ darken(0.2, lineColor2),
316
+ darken(0.2, lineColor3),
317
+ darken(0.2, lineColor4),
318
+ darken(0.3, lineColor5),
319
+ darken(0.3, lineColor6),
320
+ darken(0.3, lineColor7),
321
+ darken(0.3, lineColor8),
322
+ ];