@scality/core-ui 0.161.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.
- package/README.md +15 -15
- package/dist/components/accordion/Accordion.component.d.ts +0 -1
- package/dist/components/accordion/Accordion.component.d.ts.map +1 -1
- package/dist/components/barchartv2/Barchart.component.d.ts +53 -0
- package/dist/components/barchartv2/Barchart.component.d.ts.map +1 -0
- package/dist/components/barchartv2/Barchart.component.js +86 -0
- package/dist/components/barchartv2/utils.d.ts +118 -0
- package/dist/components/barchartv2/utils.d.ts.map +1 -0
- package/dist/components/barchartv2/utils.js +337 -0
- package/dist/components/buttonv2/Buttonv2.component.d.ts +1 -1
- package/dist/components/buttonv2/Buttonv2.component.d.ts.map +1 -1
- package/dist/components/chartlegend/ChartLegend.d.ts +8 -0
- package/dist/components/chartlegend/ChartLegend.d.ts.map +1 -0
- package/dist/components/chartlegend/ChartLegend.js +65 -0
- package/dist/components/chartlegend/ChartLegendWrapper.d.ts +17 -0
- package/dist/components/chartlegend/ChartLegendWrapper.d.ts.map +1 -0
- package/dist/components/chartlegend/ChartLegendWrapper.js +50 -0
- package/dist/components/constrainedtext/Constrainedtext.component.d.ts +2 -1
- package/dist/components/constrainedtext/Constrainedtext.component.d.ts.map +1 -1
- package/dist/components/constrainedtext/Constrainedtext.component.js +5 -4
- package/dist/components/coreuithemeprovider/CoreUiThemeProvider.d.ts +0 -1
- package/dist/components/coreuithemeprovider/CoreUiThemeProvider.d.ts.map +1 -1
- package/dist/components/date/FormattedDateTime.d.ts +4 -1
- package/dist/components/date/FormattedDateTime.d.ts.map +1 -1
- package/dist/components/date/FormattedDateTime.js +24 -1
- package/dist/components/date/FormattedDateTime.spec.js +12 -0
- package/dist/components/emptytable/Emptytable.component.d.ts +0 -1
- package/dist/components/emptytable/Emptytable.component.d.ts.map +1 -1
- package/dist/components/emptytable/Emptytable.component.js +1 -0
- package/dist/components/error-pages/ErrorPage401.component.d.ts +0 -1
- package/dist/components/error-pages/ErrorPage401.component.d.ts.map +1 -1
- package/dist/components/error-pages/ErrorPage404.component.d.ts +0 -1
- package/dist/components/error-pages/ErrorPage404.component.d.ts.map +1 -1
- package/dist/components/error-pages/ErrorPage500.component.d.ts +0 -1
- package/dist/components/error-pages/ErrorPage500.component.d.ts.map +1 -1
- package/dist/components/error-pages/ErrorPageAuth.component.d.ts.map +1 -1
- package/dist/components/form/Form.component.d.ts +2 -2
- package/dist/components/form/Form.component.d.ts.map +1 -1
- package/dist/components/icon/Icon.component.d.ts +5 -5
- package/dist/components/icon/Icon.component.d.ts.map +1 -1
- package/dist/components/icon/Icon.component.js +33 -31
- package/dist/components/infomessage/InfoMessage.component.d.ts +0 -1
- package/dist/components/infomessage/InfoMessage.component.d.ts.map +1 -1
- package/dist/components/lateralnavbarlayout/LateralNavbarLayout.component.d.ts.map +1 -1
- package/dist/components/layout/Layout.component.d.ts.map +1 -1
- package/dist/components/layout/v2/panels.d.ts.map +1 -1
- package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts +33 -0
- package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts.map +1 -0
- package/dist/components/linetimeseriechart/linetimeseriechart.component.js +249 -0
- package/dist/components/modal/Modal.component.js +2 -2
- package/dist/components/navbar/Navbar.component.js +2 -2
- package/dist/components/scrollbarwrapper/ScrollbarWrapper.component.d.ts +0 -1
- package/dist/components/scrollbarwrapper/ScrollbarWrapper.component.d.ts.map +1 -1
- package/dist/components/searchinput/SearchInput.component.d.ts +1 -2
- package/dist/components/searchinput/SearchInput.component.d.ts.map +1 -1
- package/dist/components/selectv2/Selectv2.component.d.ts +5 -5
- package/dist/components/selectv2/Selectv2.component.d.ts.map +1 -1
- package/dist/components/selectv2/Selectv2.component.js +11 -6
- package/dist/components/statuswrapper/Statuswrapper.component.d.ts +0 -1
- package/dist/components/statuswrapper/Statuswrapper.component.d.ts.map +1 -1
- package/dist/components/steppers/Stepper.component.d.ts.map +1 -1
- package/dist/components/steppers/Stepper.component.js +9 -8
- package/dist/components/tablev2/Search.js +2 -2
- package/dist/components/tablev2/SingleSelectableContent.d.ts +1 -2
- package/dist/components/tablev2/SingleSelectableContent.d.ts.map +1 -1
- package/dist/components/tablev2/TableCommon.d.ts +2 -2
- package/dist/components/tablev2/TableCommon.d.ts.map +1 -1
- package/dist/components/tablev2/TableSync.d.ts +8 -0
- package/dist/components/tablev2/TableSync.d.ts.map +1 -0
- package/dist/components/tablev2/TableSync.js +11 -0
- package/dist/components/tablev2/Tablev2.component.d.ts +2 -1
- package/dist/components/tablev2/Tablev2.component.d.ts.map +1 -1
- package/dist/components/tablev2/Tablev2.component.js +10 -9
- package/dist/components/tabsv2/ScrollButton.d.ts +1 -2
- package/dist/components/tabsv2/ScrollButton.d.ts.map +1 -1
- package/dist/components/tabsv2/ScrollButton.js +2 -2
- package/dist/components/tabsv2/Tabsv2.component.d.ts +2 -2
- package/dist/components/tabsv2/Tabsv2.component.d.ts.map +1 -1
- package/dist/components/tabsv2/Tabsv2.component.js +2 -2
- package/dist/components/text/Text.component.d.ts +0 -1
- package/dist/components/text/Text.component.d.ts.map +1 -1
- package/dist/components/textarea/TextArea.component.d.ts +3 -3
- package/dist/components/textarea/TextArea.component.d.ts.map +1 -1
- package/dist/components/textbadge/TextBadge.component.d.ts +0 -1
- package/dist/components/textbadge/TextBadge.component.d.ts.map +1 -1
- package/dist/components/toast/Toast.component.d.ts +1 -1
- package/dist/components/toast/Toast.component.d.ts.map +1 -1
- package/dist/components/toast/ToastProvider.d.ts.map +1 -1
- package/dist/components/toast/ToastProvider.js +4 -5
- package/dist/components/vegachartv2/SyncedCursorCharts.d.ts +1 -2
- package/dist/components/vegachartv2/SyncedCursorCharts.d.ts.map +1 -1
- package/dist/components/vegachartv2/SyncedCursorCharts.js +3 -5
- package/dist/components/vegachartv2/VegaChartV2.component.d.ts +1 -2
- package/dist/components/vegachartv2/VegaChartV2.component.d.ts.map +1 -1
- package/dist/components/vegachartv2/VegaChartV2.component.js +2 -2
- package/dist/icons/branding.d.ts.map +1 -1
- package/dist/icons/scality-loading.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/next.d.ts +2 -0
- package/dist/next.d.ts.map +1 -1
- package/dist/next.js +2 -0
- package/dist/style/theme.d.ts +20 -0
- package/dist/style/theme.d.ts.map +1 -1
- package/dist/style/theme.js +46 -1
- package/package.json +7 -4
- package/setupTests.js +6 -0
- package/src/lib/components/accordion/Accordion.component.tsx +1 -1
- package/src/lib/components/accordion/Accordion.test.tsx +7 -15
- package/src/lib/components/barchartv2/Barchart.component.test.tsx +364 -0
- package/src/lib/components/barchartv2/Barchart.component.tsx +321 -0
- package/src/lib/components/barchartv2/utils.test.ts +899 -0
- package/src/lib/components/barchartv2/utils.ts +534 -0
- package/src/lib/components/buttonv2/Buttonv2.component.tsx +1 -1
- package/src/lib/components/chartlegend/ChartLegend.tsx +113 -0
- package/src/lib/components/chartlegend/ChartLegendWrapper.tsx +85 -0
- package/src/lib/components/constrainedtext/Constrainedtext.component.tsx +22 -3
- package/src/lib/components/coreuithemeprovider/CoreUiThemeProvider.tsx +0 -1
- package/src/lib/components/date/FormattedDateTime.spec.tsx +24 -0
- package/src/lib/components/date/FormattedDateTime.tsx +42 -2
- package/src/lib/components/emptytable/Emptytable.component.tsx +1 -1
- package/src/lib/components/error-pages/ErrorPage401.component.tsx +0 -1
- package/src/lib/components/error-pages/ErrorPage404.component.tsx +0 -1
- package/src/lib/components/error-pages/ErrorPage500.component.tsx +0 -1
- package/src/lib/components/error-pages/ErrorPageAuth.component.tsx +0 -1
- package/src/lib/components/form/Form.component.tsx +1 -1
- package/src/lib/components/healthselectorv2/HealthSelector.component.test.tsx +3 -3
- package/src/lib/components/icon/Icon.component.tsx +48 -60
- package/src/lib/components/infomessage/InfoMessage.component.tsx +0 -1
- package/src/lib/components/inlineinput/InlineInput.test.tsx +22 -19
- package/src/lib/components/inputlist/InputList.test.tsx +21 -19
- package/src/lib/components/lateralnavbarlayout/LateralNavbarLayout.component.tsx +0 -1
- package/src/lib/components/layout/Layout.component.tsx +0 -1
- package/src/lib/components/layout/v2/panels.tsx +1 -1
- package/src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx +502 -0
- package/src/lib/components/modal/Modal.component.tsx +2 -2
- package/src/lib/components/navbar/Navbar.component.tsx +2 -2
- package/src/lib/components/scrollbarwrapper/ScrollbarWrapper.component.tsx +0 -1
- package/src/lib/components/searchinput/SearchInput.component.tsx +0 -1
- package/src/lib/components/searchinput/SearchInput.test.tsx +3 -7
- package/src/lib/components/selectv2/Selectv2.component.tsx +24 -14
- package/src/lib/components/selectv2/selectv2.test.tsx +62 -57
- package/src/lib/components/sidebar/Sidebar.component.tsx +1 -1
- package/src/lib/components/statuswrapper/Statuswrapper.component.tsx +0 -1
- package/src/lib/components/steppers/Stepper.component.tsx +10 -8
- package/src/lib/components/tablev2/Search.tsx +2 -2
- package/src/lib/components/tablev2/SingleSelectableContent.tsx +2 -2
- package/src/lib/components/tablev2/TableCommon.tsx +1 -1
- package/src/lib/components/tablev2/TableSync.test.tsx +28 -0
- package/src/lib/components/tablev2/TableSync.tsx +36 -0
- package/src/lib/components/tablev2/Tablev2.component.tsx +11 -9
- package/src/lib/components/tablev2/Tablev2.test.tsx +36 -37
- package/src/lib/components/tabsv2/ScrollButton.tsx +2 -2
- package/src/lib/components/tabsv2/Tabsv2.component.tsx +6 -6
- package/src/lib/components/text/Text.component.tsx +4 -5
- package/src/lib/components/textarea/TextArea.component.tsx +3 -2
- package/src/lib/components/textbadge/TextBadge.component.tsx +0 -1
- package/src/lib/components/toast/Toast.component.tsx +1 -1
- package/src/lib/components/toast/ToastProvider.tsx +17 -7
- package/src/lib/components/vegachartv2/SyncedCursorCharts.tsx +5 -7
- package/src/lib/components/vegachartv2/VegaChartV2.component.tsx +2 -2
- package/src/lib/icons/branding.tsx +0 -2
- package/src/lib/icons/scality-loading.tsx +0 -2
- package/src/lib/index.ts +1 -0
- package/src/lib/next.ts +6 -0
- package/src/lib/style/theme.ts +53 -1
- package/stories/BarChart/barchart.stories.tsx +822 -0
- package/stories/areachart.stories.tsx +0 -1
- package/stories/format.mdx +4 -2
- package/stories/linetimeseriechart.stories.tsx +485 -0
- package/stories/tablev2.stories.tsx +41 -0
- package/tsconfig.json +5 -2
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
3
|
import { SearchInput, Props } from './SearchInput.component';
|
|
4
|
-
import { QueryClient, QueryClientProvider } from 'react-query';
|
|
5
4
|
import userEvent from '@testing-library/user-event';
|
|
6
5
|
|
|
7
|
-
const queryClient = new QueryClient();
|
|
8
|
-
|
|
9
6
|
const SearchInputRender = (props: Props) => {
|
|
10
7
|
return (
|
|
11
|
-
<
|
|
12
|
-
<SearchInput {...props} />
|
|
13
|
-
</QueryClientProvider>
|
|
8
|
+
<SearchInput {...props} />
|
|
14
9
|
);
|
|
15
10
|
};
|
|
16
11
|
|
|
@@ -19,8 +14,9 @@ describe('SearchInput', () => {
|
|
|
19
14
|
searchInput: () => screen.getByRole('searchbox'),
|
|
20
15
|
clearButton: () => screen.queryByRole('button'),
|
|
21
16
|
};
|
|
22
|
-
it('should render the SearchInput component', () => {
|
|
17
|
+
it('should render the SearchInput component', async () => {
|
|
23
18
|
render(<SearchInputRender value="" onChange={() => {}} />);
|
|
19
|
+
await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
|
|
24
20
|
|
|
25
21
|
const searchInput = selectors.searchInput();
|
|
26
22
|
expect(searchInput).toBeInTheDocument();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
2
|
createContext,
|
|
3
3
|
useContext,
|
|
4
4
|
useState,
|
|
@@ -8,6 +8,10 @@ import React, {
|
|
|
8
8
|
ForwardRefExoticComponent,
|
|
9
9
|
RefAttributes,
|
|
10
10
|
useImperativeHandle,
|
|
11
|
+
ReactNode,
|
|
12
|
+
Ref,
|
|
13
|
+
useMemo,
|
|
14
|
+
useCallback,
|
|
11
15
|
} from 'react';
|
|
12
16
|
import { ScrollbarWrapper, Tooltip } from '../../index';
|
|
13
17
|
import {
|
|
@@ -31,10 +35,10 @@ const NOPT_SEARCH = 8;
|
|
|
31
35
|
export type OptionProps = {
|
|
32
36
|
title?: string;
|
|
33
37
|
disabled?: boolean;
|
|
34
|
-
icon?:
|
|
35
|
-
children?:
|
|
38
|
+
icon?: ReactNode;
|
|
39
|
+
children?: ReactNode;
|
|
36
40
|
value: string;
|
|
37
|
-
disabledReason?:
|
|
41
|
+
disabledReason?: ReactNode;
|
|
38
42
|
};
|
|
39
43
|
const usePreviousValue = (value) => {
|
|
40
44
|
const ref = useRef(null);
|
|
@@ -335,7 +339,7 @@ export type SelectProps = {
|
|
|
335
339
|
id: string;
|
|
336
340
|
placeholder?: string;
|
|
337
341
|
disabled?: boolean;
|
|
338
|
-
children?:
|
|
342
|
+
children?: ReactNode;
|
|
339
343
|
value?: string;
|
|
340
344
|
onFocus?: (event: FocusEvent) => void;
|
|
341
345
|
onBlur?: (event: FocusEvent) => void;
|
|
@@ -349,11 +353,11 @@ export type SelectProps = {
|
|
|
349
353
|
|
|
350
354
|
type SelectOptionProps = {
|
|
351
355
|
value: string;
|
|
352
|
-
label:
|
|
356
|
+
label: ReactNode;
|
|
353
357
|
isDisabled: boolean;
|
|
354
|
-
icon?:
|
|
358
|
+
icon?: ReactNode;
|
|
355
359
|
optionProps: any;
|
|
356
|
-
disabledReason?:
|
|
360
|
+
disabledReason?: ReactNode;
|
|
357
361
|
};
|
|
358
362
|
|
|
359
363
|
type SelectComponentType<
|
|
@@ -388,7 +392,7 @@ function SelectBox<
|
|
|
388
392
|
selectRef,
|
|
389
393
|
...rest
|
|
390
394
|
}: SelectProps & {
|
|
391
|
-
selectRef?:
|
|
395
|
+
selectRef?: Ref<SelectRef<OptionType, IsMulti, GroupType>>;
|
|
392
396
|
}) {
|
|
393
397
|
const [keyboardFocusEnabled, setKeyboardFocusEnabled] = useState(false);
|
|
394
398
|
const [searchSelection, setSearchSelection] = useState('');
|
|
@@ -560,22 +564,28 @@ const SelectWithOptionContext = forwardRef<
|
|
|
560
564
|
>((props, ref) => {
|
|
561
565
|
const [options, setOptions] = useState<Record<string, SelectOptionProps>>({});
|
|
562
566
|
|
|
563
|
-
const register = (option: SelectOptionProps) => {
|
|
567
|
+
const register = useCallback((option: SelectOptionProps) => {
|
|
564
568
|
setOptions((prevOptions) => ({
|
|
565
569
|
...prevOptions,
|
|
566
570
|
[option.value]: option,
|
|
567
571
|
}));
|
|
568
|
-
};
|
|
572
|
+
}, []);
|
|
569
573
|
|
|
570
|
-
const unregister = (value: string) => {
|
|
574
|
+
const unregister = useCallback((value: string) => {
|
|
571
575
|
setOptions((prevOptions) => {
|
|
572
576
|
const { [value]: _, ...rest } = prevOptions;
|
|
573
577
|
return rest;
|
|
574
578
|
});
|
|
575
|
-
};
|
|
579
|
+
}, []);
|
|
580
|
+
|
|
581
|
+
const contextValue = useMemo(() => ({
|
|
582
|
+
options,
|
|
583
|
+
register,
|
|
584
|
+
unregister
|
|
585
|
+
}), [options, register, unregister]);
|
|
576
586
|
|
|
577
587
|
return (
|
|
578
|
-
<OptionContext.Provider value={
|
|
588
|
+
<OptionContext.Provider value={contextValue}>
|
|
579
589
|
<>
|
|
580
590
|
<SelectBox {...props} selectRef={ref} />
|
|
581
591
|
{props.children}
|
|
@@ -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
|
-
|
|
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:
|
|
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:
|
|
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={
|
|
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,5 +1,5 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import styled from 'styled-components';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
3
|
import { useTableContext } from './Tablev2.component';
|
|
4
4
|
import { SearchInput } from '../searchinput/SearchInput.component';
|
|
5
5
|
import { Props } from '../searchinput/SearchInput.component';
|
|
@@ -74,7 +74,7 @@ export function TableSearch(props: SearchProps) {
|
|
|
74
74
|
entityName = { en: { singular: 'result', plural: 'results' } },
|
|
75
75
|
} = useTableContext();
|
|
76
76
|
const totalDispayedRows = totalCount ? totalCount : rows.length;
|
|
77
|
-
|
|
77
|
+
useEffect(() => {
|
|
78
78
|
setGlobalFilter(value);
|
|
79
79
|
}, [value, setGlobalFilter, preGlobalFilteredRows]);
|
|
80
80
|
return (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { memo, useEffect } from 'react';
|
|
2
2
|
import { areEqual } from 'react-window';
|
|
3
3
|
import { Row } from 'react-table';
|
|
4
4
|
import { useTableContext } from './Tablev2.component';
|
|
@@ -32,7 +32,7 @@ export type SingleSelectableContentProps<
|
|
|
32
32
|
customItemKey?: (index: number, data: DATA_ROW) => string;
|
|
33
33
|
hasScrollbar?: boolean;
|
|
34
34
|
isLoadingMoreItems?: boolean;
|
|
35
|
-
children?: (rows:
|
|
35
|
+
children?: (rows: JSX.Element) => JSX.Element;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
export function SingleSelectableContent<
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { TableSync } from './TableSync';
|
|
4
|
+
|
|
5
|
+
describe('TableSync', () => {
|
|
6
|
+
it('should render correctly', async () => {
|
|
7
|
+
const onSync = jest.fn();
|
|
8
|
+
render(
|
|
9
|
+
<TableSync onSync={onSync} />
|
|
10
|
+
);
|
|
11
|
+
await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
|
|
12
|
+
|
|
13
|
+
const button = screen.getByRole('button');
|
|
14
|
+
expect(button).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should call onSync when clicked', async () => {
|
|
18
|
+
const onSync = jest.fn();
|
|
19
|
+
render(
|
|
20
|
+
<TableSync onSync={onSync} />
|
|
21
|
+
);
|
|
22
|
+
await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
|
|
23
|
+
|
|
24
|
+
const button = screen.getByRole('button');
|
|
25
|
+
await act(() => fireEvent.click(button));
|
|
26
|
+
expect(onSync).toHaveBeenCalledTimes(1);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { Button } from '../buttonv2/Buttonv2.component';
|
|
4
|
+
import { Icon } from '../icon/Icon.component';
|
|
5
|
+
|
|
6
|
+
export type TableSyncProps = {
|
|
7
|
+
onSync: () => void;
|
|
8
|
+
tooltipOverlay?: string;
|
|
9
|
+
loading?: boolean;
|
|
10
|
+
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>;
|
|
11
|
+
|
|
12
|
+
const TableSyncContainer = styled.div`
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export function TableSync({
|
|
18
|
+
onSync,
|
|
19
|
+
tooltipOverlay,
|
|
20
|
+
loading = false,
|
|
21
|
+
...rest
|
|
22
|
+
}: TableSyncProps) {
|
|
23
|
+
return (
|
|
24
|
+
<TableSyncContainer>
|
|
25
|
+
<Button
|
|
26
|
+
icon={<Icon name="Sync" />}
|
|
27
|
+
tooltip={tooltipOverlay ? { overlay: tooltipOverlay } : undefined}
|
|
28
|
+
onClick={onSync}
|
|
29
|
+
aria-label="Synchronize table data"
|
|
30
|
+
role="button"
|
|
31
|
+
isLoading={loading}
|
|
32
|
+
{...rest}
|
|
33
|
+
/>
|
|
34
|
+
</TableSyncContainer>
|
|
35
|
+
);
|
|
36
|
+
}
|