@nuskin/foundation-ui-components 1.1.0 → 1.2.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/package.json +18 -14
- package/src/common/accordion/NsAccordion.tsx +32 -40
- package/src/common/accordion/NsAccordionHeader.tsx +29 -8
- package/src/common/accordion/NsAccordionItem.tsx +24 -4
- package/src/common/accordion/NsCollapse.tsx +96 -35
- package/src/common/accordion/NsToggleSection.tsx +16 -3
- package/src/common/accordion/ToggleSection.styled.tsx +11 -7
- package/src/common/accordion/colorMap.ts +117 -0
- package/src/common/accordion/enums.ts +18 -0
- package/src/common/accordion/index.ts +1 -0
- package/src/common/accordion/specs/NsAccordion.spec.tsx +101 -31
- package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +77 -10
- package/src/common/accordion/specs/NsAccordionItem.spec.tsx +27 -10
- package/src/common/accordion/specs/NsCollapse.spec.tsx +109 -17
- package/src/common/accordion/specs/NsToggleSection.spec.tsx +50 -14
- package/src/common/accordion/stories/NsAccordion.stories.tsx +31 -13
- package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +5 -1
- package/src/common/accordion/stories/NsAccordionItem.stories.tsx +8 -3
- package/src/common/accordion/stories/NsCollapse.stories.tsx +19 -4
- package/src/common/accordion/stories/NsToggleSection.stories.tsx +6 -3
- package/src/common/accordion/stories/data.tsx +140 -19
- package/src/common/accordion/types.d.ts +55 -47
- package/src/common/alert/Header.tsx +29 -0
- package/src/common/alert/NsAlert.spec.tsx +46 -13
- package/src/common/alert/NsAlert.stories.tsx +1 -1
- package/src/common/alert/{NsAlert.styled.ts → NsAlert.styled.tsx} +22 -22
- package/src/common/alert/NsAlert.tsx +22 -87
- package/src/common/alert/types.d.ts +7 -7
- package/src/common/auth-dropdown/NsAuthDropdown.spec.tsx +23 -5
- package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +9 -2
- package/src/common/auth-dropdown/NsAuthDropdown.tsx +11 -6
- package/src/common/autocomplete/NsAutocomplete.spec.tsx +37 -14
- package/src/common/autocomplete/NsAutocomplete.stories.tsx +18 -2
- package/src/common/autocomplete/NsAutocomplete.tsx +63 -24
- package/src/common/autocomplete/mock/MockData.ts +51 -7
- package/src/common/autocomplete/mock/MockUI.tsx +2 -1
- package/src/common/autocomplete/types.d.ts +7 -4
- package/src/common/banner/NsBanner.spec.tsx +12 -3
- package/src/common/brand-components/NsBrandComponent.tsx +2 -2
- package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +8 -3
- package/src/common/breadcrumb/data.ts +8 -5
- package/src/common/button/NsButton.spec.tsx +65 -49
- package/src/common/button/NsButton.stories.tsx +39 -4
- package/src/common/button/NsButton.styled.tsx +49 -66
- package/src/common/button/NsButton.tsx +1 -2
- package/src/common/button/helper.ts +82 -0
- package/src/common/card/NsFfgCard.tsx +13 -7
- package/src/common/card/specs/NsFfgCard.spec.tsx +18 -8
- package/src/common/card/stories/NsFfgCard.stories.tsx +47 -14
- package/src/common/card/styled/NsFfgStyled.tsx +9 -7
- package/src/common/card/types.d.ts +7 -4
- package/src/common/cart-icon/NsCartIcon.spec.tsx +7 -18
- package/src/common/cart-icon/NsCartIcon.stories.tsx +1 -1
- package/src/common/cart-icon/NsCartIcon.styled.ts +7 -33
- package/src/common/cart-icon/NsCartIcon.tsx +5 -14
- package/src/common/cart-icon/types.d.ts +1 -0
- package/src/common/checkbox/NsCheckbox.styled.tsx +15 -16
- package/src/common/checkbox/NsCheckbox.tsx +1 -1
- package/src/common/checkbox/types.d.ts +1 -1
- package/src/common/column-control/styled/common.ts +1 -1
- package/src/common/column-control/utils.ts +4 -4
- package/src/common/common.types.d.ts +14 -5
- package/src/common/dropdown/NsDropdown.styled.tsx +23 -18
- package/src/common/dropdown/NsDropdown.tsx +7 -2
- package/src/common/hooks/index.ts +2 -0
- package/src/common/hooks/specs/useWindowSize.spec.tsx +19 -0
- package/src/common/hooks/useAccordionMap.tsx +39 -0
- package/src/common/hooks/useOnClickOutside.tsx +25 -0
- package/src/common/hooks/useWindowSize.tsx +30 -0
- package/src/common/icon/NsIcon.spec.tsx +1 -1
- package/src/common/icon/NsIcon.stories.tsx +3 -0
- package/src/common/icon/NsIcon.tsx +6 -2
- package/src/common/icon/NsIconVariants.ts +3 -0
- package/src/common/icon/icons/AlertErrorIcon.tsx +2 -2
- package/src/common/icon/icons/ArrowLeft.tsx +3 -6
- package/src/common/icon/icons/ArrowRight.tsx +6 -8
- package/src/common/icon/icons/Cart.tsx +7 -32
- package/src/common/icon/icons/CartBadge.tsx +2 -2
- package/src/common/icon/icons/CloseIcon.tsx +1 -1
- package/src/common/icon/icons/ErrorIcon.tsx +2 -2
- package/src/common/icon/icons/HamburgerIcon.tsx +5 -2
- package/src/common/icon/icons/SearchIcon.tsx +1 -1
- package/src/common/icon/icons/SuccessIcon.tsx +2 -7
- package/src/common/icon/icons/TrashIcon.tsx +1 -1
- package/src/common/icon/icons/UserIcon.tsx +3 -6
- package/src/common/icon/icons/UserOutline.tsx +24 -0
- package/src/common/icon/icons/WarningIcon.tsx +1 -1
- package/src/common/icon/icons/home.tsx +1 -1
- package/src/common/image/NsImage.spec.tsx +56 -6
- package/src/common/image/NsImage.tsx +23 -11
- package/src/common/index.ts +7 -3
- package/src/common/input/InputWrapper.tsx +12 -7
- package/src/common/input/NsInputField.tsx +1 -1
- package/src/common/label/NsLabel.stories.tsx +0 -3
- package/src/common/label/NsLabel.tsx +1 -1
- package/src/common/modal/NsModal.spec.tsx +46 -0
- package/src/common/modal/NsModal.styled.tsx +28 -0
- package/src/common/modal/NsModal.tsx +37 -0
- package/src/common/modal/helper-component/NsModalContentBox.tsx +32 -0
- package/src/common/modal/helper-component/NsModalDefault.tsx +25 -0
- package/src/common/modal/helper-component/NsModalStatus.tsx +15 -0
- package/src/common/modal/helper-component/NsModalStatusIcon.tsx +14 -0
- package/src/common/modal/helper-component/NsModalTitle.tsx +26 -0
- package/src/common/modal/index.ts +2 -0
- package/src/common/modal/model/NsModalVariantMap.tsx +24 -0
- package/src/common/modal/stories/NsModal.stories.tsx +85 -0
- package/src/common/modal/stories/mock.tsx +46 -0
- package/src/common/modal/types.ts +56 -0
- package/src/common/nav-tab/NavDrawer.tsx +34 -0
- package/src/common/nav-tab/NavTitles.tsx +52 -0
- package/src/common/nav-tab/NsNavTab.spec.tsx +4 -5
- package/src/common/nav-tab/NsNavTab.stories.tsx +3 -3
- package/src/common/nav-tab/NsNavTab.styled.tsx +13 -7
- package/src/common/nav-tab/NsNavTab.tsx +21 -75
- package/src/common/nav-tab/index.ts +1 -1
- package/src/common/nav-tab/types.d.ts +3 -3
- package/src/common/progress/NsProgress.spec.tsx +47 -0
- package/src/common/progress/NsProgress.stories.tsx +37 -0
- package/src/common/progress/NsProgress.styled.tsx +39 -0
- package/src/common/progress/NsProgress.tsx +27 -0
- package/src/common/progress/index.ts +2 -0
- package/src/common/progress/types.d.ts +21 -0
- package/src/common/radiogroup/NsRadioGroup.spec.tsx +24 -25
- package/src/common/radiogroup/NsRadioGroup.stories.tsx +13 -31
- package/src/common/radiogroup/NsRadioGroup.styled.tsx +17 -15
- package/src/common/radiogroup/NsRadioGroup.tsx +6 -5
- package/src/common/search-bar/NsSearchBar.tsx +1 -3
- package/src/common/select/NsSelect.spec.tsx +107 -33
- package/src/common/select/NsSelect.styled.tsx +89 -39
- package/src/common/select/NsSelect.tsx +109 -44
- package/src/common/select/NsSelectOption.tsx +0 -1
- package/src/common/select/stories/NsSelect.stories.tsx +33 -24
- package/src/common/select/types.d.ts +6 -4
- package/src/common/spinner/NsSpinner.spec.tsx +21 -0
- package/src/common/spinner/NsSpinner.stories.tsx +26 -0
- package/src/common/spinner/NsSpinner.styled.tsx +344 -0
- package/src/common/spinner/NsSpinner.tsx +14 -0
- package/src/common/spinner/icons/Spinner.tsx +161 -0
- package/src/common/spinner/index.ts +2 -0
- package/src/common/spinner/types.ts +5 -0
- package/src/common/table/NsTable.tsx +32 -49
- package/src/common/table/NsTableHeader.tsx +30 -51
- package/src/common/util.ts +1 -0
- package/src/common/utility/Show.tsx +13 -0
- package/src/common/utility/index.ts +1 -0
- package/src/common/videos/types.d.ts +1 -1
- /package/src/common/brand-components/{NsBrandContanier.styled.tsx → NsBrandContainer.styled.tsx} +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { NsProgressProps } from './types';
|
|
4
|
+
import StyledLinearProgress, { PercentDiv, StyledCheckCircle } from './NsProgress.styled';
|
|
5
|
+
|
|
6
|
+
const NsProgress = (props: NsProgressProps) => {
|
|
7
|
+
const { color, backgroundColor, height, value, body } = props;
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<PercentDiv>
|
|
11
|
+
{value}
|
|
12
|
+
{body}
|
|
13
|
+
</PercentDiv>
|
|
14
|
+
<StyledLinearProgress
|
|
15
|
+
variant="determinate"
|
|
16
|
+
role="progressbar"
|
|
17
|
+
color={color}
|
|
18
|
+
value={value}
|
|
19
|
+
height={height}
|
|
20
|
+
backgroundColor={backgroundColor}
|
|
21
|
+
/>
|
|
22
|
+
<StyledCheckCircle />
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default NsProgress;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FoundationTheme } from '@nuskin/foundation-theme';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
declare module '@mui/material/LinearProgress' {
|
|
5
|
+
// eslint-disable-next-line no-unused-vars
|
|
6
|
+
interface LinearProgressPropsColorOverrides {
|
|
7
|
+
neutral: true;
|
|
8
|
+
accentColorA: true;
|
|
9
|
+
accentColorB: true;
|
|
10
|
+
accentColorC: true;
|
|
11
|
+
accentColorD: true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type NsProgressProps = {
|
|
16
|
+
color?: FoundationTheme.PaletteColors;
|
|
17
|
+
backgroundColor?: string;
|
|
18
|
+
height?: string;
|
|
19
|
+
value: number;
|
|
20
|
+
body?: ReactNode;
|
|
21
|
+
};
|
|
@@ -3,14 +3,12 @@ import { render, fireEvent, screen } from '@testing-library/react';
|
|
|
3
3
|
import { NsRadioGroup } from './';
|
|
4
4
|
import { FoundationTheme } from '@nuskin/foundation-theme';
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
describe('NsRadioGroup', () => {
|
|
8
|
-
|
|
9
7
|
const options = [
|
|
10
8
|
{ id: 'Option1', label: 'Option 1', value: 'Option1' },
|
|
11
9
|
{ id: 'Option2', label: 'Option 2', value: 'Option2' },
|
|
12
10
|
{ id: 'Option3', label: 'Option 3', value: 'Option3' },
|
|
13
|
-
]
|
|
11
|
+
];
|
|
14
12
|
|
|
15
13
|
const props = {
|
|
16
14
|
disable: false,
|
|
@@ -27,38 +25,39 @@ describe('NsRadioGroup', () => {
|
|
|
27
25
|
};
|
|
28
26
|
const onChange = jest.fn();
|
|
29
27
|
|
|
30
|
-
it('renders options correctly', () => {
|
|
31
|
-
render(
|
|
32
|
-
<NsRadioGroup {...props} onChange={onChange}
|
|
33
|
-
/>,
|
|
34
|
-
);
|
|
28
|
+
it('1. renders options correctly', () => {
|
|
29
|
+
render(<NsRadioGroup {...props} onChange={onChange} />);
|
|
35
30
|
|
|
36
31
|
options.forEach((option) => {
|
|
37
32
|
const radioOption = screen.getByLabelText(option.label) as HTMLInputElement;
|
|
38
33
|
expect(radioOption).toBeInTheDocument();
|
|
39
|
-
expect(radioOption.value).toBe(option.value)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
expect(radioOption.value).toBe(option.value);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it('2. renders options correctly without additional slot', () => {
|
|
38
|
+
render(<NsRadioGroup {...props} onChange={onChange} additionalSlot={''} />);
|
|
43
39
|
|
|
44
|
-
|
|
40
|
+
options.forEach((option) => {
|
|
41
|
+
const radioOption = screen.getByLabelText(option.label) as HTMLInputElement;
|
|
42
|
+
expect(radioOption).toBeInTheDocument();
|
|
43
|
+
expect(radioOption.value).toBe(option.value);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
it('3. calls OnChange when selecting option', () => {
|
|
48
|
+
render(<NsRadioGroup {...props} onChange={onChange} />);
|
|
47
49
|
|
|
48
|
-
const radioOption = screen.getByLabelText('Option 2') as HTMLInputElement
|
|
50
|
+
const radioOption = screen.getByLabelText('Option 2') as HTMLInputElement;
|
|
49
51
|
fireEvent.click(radioOption);
|
|
50
52
|
expect(onChange).toHaveBeenCalledTimes(1);
|
|
53
|
+
});
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
it('does not call Onchange when the same option is clicked', () => {
|
|
55
|
+
it('4. does not call Onchange when the same option is clicked', () => {
|
|
55
56
|
const onChange = jest.fn();
|
|
56
|
-
render(<NsRadioGroup {...props} onChange={onChange} />)
|
|
57
|
+
render(<NsRadioGroup {...props} onChange={onChange} />);
|
|
57
58
|
|
|
58
|
-
const radioOption = screen.getByLabelText('Option 1') as HTMLInputElement
|
|
59
|
-
fireEvent.click(radioOption)
|
|
59
|
+
const radioOption = screen.getByLabelText('Option 1') as HTMLInputElement;
|
|
60
|
+
fireEvent.click(radioOption);
|
|
60
61
|
expect(onChange).not.toHaveBeenCalled();
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
})
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
1
|
import type { StoryObj, Meta } from '@storybook/react';
|
|
3
2
|
import { within, userEvent } from '@storybook/testing-library';
|
|
4
3
|
import { expect } from '@storybook/jest';
|
|
5
|
-
import { NsRadioGroup } from './'
|
|
4
|
+
import { NsRadioGroup } from './';
|
|
6
5
|
import { FoundationTheme } from '@nuskin/foundation-theme';
|
|
7
6
|
|
|
8
7
|
type ComponentType = typeof NsRadioGroup;
|
|
@@ -14,43 +13,29 @@ export default {
|
|
|
14
13
|
title: 'Components/Inputs/NsRadioGroup',
|
|
15
14
|
argTypes: {
|
|
16
15
|
disable: {
|
|
17
|
-
description:
|
|
18
|
-
'Indicates whether the radio button is enabled/disabled',
|
|
19
|
-
|
|
16
|
+
description: 'Indicates whether the radio button is enabled/disabled',
|
|
20
17
|
},
|
|
21
18
|
items: {
|
|
22
|
-
description:
|
|
23
|
-
'Value of the component to be emitted when selected.',
|
|
19
|
+
description: 'Value of the component to be emitted when selected.',
|
|
24
20
|
},
|
|
25
21
|
name: {
|
|
26
|
-
description:
|
|
27
|
-
'Name of the component',
|
|
28
|
-
|
|
22
|
+
description: 'Name of the component',
|
|
29
23
|
},
|
|
30
24
|
label: {
|
|
31
|
-
description:
|
|
32
|
-
'Label of the radio group',
|
|
33
|
-
|
|
25
|
+
description: 'Label of the radio group',
|
|
34
26
|
},
|
|
35
27
|
color: {
|
|
36
|
-
description:
|
|
37
|
-
'Color of the radio button',
|
|
38
|
-
|
|
28
|
+
description: 'Color of the radio button',
|
|
39
29
|
},
|
|
40
30
|
size: {
|
|
41
|
-
description:
|
|
42
|
-
'Margin Left for Additional Slot text',
|
|
43
|
-
|
|
31
|
+
description: 'Margin Left for Additional Slot text',
|
|
44
32
|
},
|
|
45
33
|
labelFontSize: {
|
|
46
|
-
description:
|
|
47
|
-
'Used to change font-size of the label'
|
|
34
|
+
description: 'Used to change font-size of the label',
|
|
48
35
|
},
|
|
49
36
|
additionalSlot: {
|
|
50
|
-
description:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
37
|
+
description: 'An additional slot allows for more text',
|
|
38
|
+
},
|
|
54
39
|
},
|
|
55
40
|
} as MetaStory;
|
|
56
41
|
|
|
@@ -61,7 +46,7 @@ export const RadioGroup: Story = {
|
|
|
61
46
|
{
|
|
62
47
|
id: 'individual',
|
|
63
48
|
label: `Vendeur à domicile indépendant mandataire (The VDI mandataire
|
|
64
|
-
enters into sales or service agreements
|
|
49
|
+
enters into sales or service agreements
|
|
65
50
|
with customers in the name and on behalf of the company.
|
|
66
51
|
His remuneration will be based on commissions made
|
|
67
52
|
on the sales of products to customers.)`,
|
|
@@ -70,7 +55,7 @@ export const RadioGroup: Story = {
|
|
|
70
55
|
{
|
|
71
56
|
id: ' retailer',
|
|
72
57
|
label: `Vendeur à domicile indépendant acheteur-revendeur
|
|
73
|
-
(The VDI acheteur-revendeur sells the company's products in his own name and behalf.
|
|
58
|
+
(The VDI acheteur-revendeur sells the company's products in his own name and behalf.
|
|
74
59
|
His remuneration will be based on commissions and on the margins made on the sales of
|
|
75
60
|
products to customers.)`,
|
|
76
61
|
value: 'retailer',
|
|
@@ -91,12 +76,9 @@ export const RadioGroup: Story = {
|
|
|
91
76
|
await userEvent.hover(canvas.getByTestId('radio-group'));
|
|
92
77
|
await expect(
|
|
93
78
|
canvas.getByText(
|
|
79
|
+
// eslint-disable-next-line max-len
|
|
94
80
|
'Vendeur à domicile indépendant mandataire (The VDI mandataire enters into sales or service agreements with customers in the name and on behalf of the company. His remuneration will be based on commissions made on the sales of products to customers.)'
|
|
95
81
|
)
|
|
96
82
|
).toBeInTheDocument();
|
|
97
83
|
},
|
|
98
84
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Radio, FormControlLabel, FormLabel, RadioGroup } from '@mui/material';
|
|
2
2
|
import { ColorUtils, FoundationTheme, styled } from '@nuskin/foundation-theme';
|
|
3
|
+
import { skipDarkModeEnabled } from '../util';
|
|
3
4
|
|
|
4
5
|
const { paletteColor, isDarkMode, color } = ColorUtils;
|
|
5
6
|
|
|
@@ -23,7 +24,7 @@ export const StyledLabel = styled(FormLabel)`
|
|
|
23
24
|
`;
|
|
24
25
|
|
|
25
26
|
export const StyledRadio = styled(Radio)`
|
|
26
|
-
color: ${(props) =>
|
|
27
|
+
color: ${(props) => color('primary', !isDarkMode(props) ? 'black' : 'white')(props)};
|
|
27
28
|
`;
|
|
28
29
|
|
|
29
30
|
export const StyledFormControlLabel = styled(FormControlLabel)<{ darkModeEnabled?: boolean }>((props) => {
|
|
@@ -31,20 +32,21 @@ export const StyledFormControlLabel = styled(FormControlLabel)<{ darkModeEnabled
|
|
|
31
32
|
color: paletteColor('primary')(props),
|
|
32
33
|
marginBottom: '10px',
|
|
33
34
|
'.MuiFormControlLabel-label.Mui-disabled': {
|
|
34
|
-
color: `${
|
|
35
|
+
color: `${color('neutral', !isDarkMode(props) ? 60 : 20)(props)}`,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
const options = {
|
|
40
|
+
shouldForwardProp: skipDarkModeEnabled,
|
|
41
|
+
};
|
|
42
|
+
export const StyledRadioGroup = styled(
|
|
43
|
+
RadioGroup,
|
|
44
|
+
options
|
|
45
|
+
)<{ color: FoundationTheme.PaletteColors; darkModeEnabled?: boolean }>(({ theme, color, darkModeEnabled }) => {
|
|
46
|
+
return {
|
|
47
|
+
marginTop: '10px',
|
|
48
|
+
'.MuiRadio-root.custom-radio.Mui-checked': {
|
|
49
|
+
color: paletteColor(color)({ theme, darkModeEnabled }),
|
|
35
50
|
},
|
|
36
51
|
};
|
|
37
52
|
});
|
|
38
|
-
|
|
39
|
-
export const StyledRadioGroup = styled(RadioGroup)<
|
|
40
|
-
{ color: FoundationTheme.PaletteColors; darkModeEnabled?: boolean }
|
|
41
|
-
>(
|
|
42
|
-
({ theme, color, darkModeEnabled }) => {
|
|
43
|
-
return {
|
|
44
|
-
marginTop: '10px',
|
|
45
|
-
'.MuiRadio-root.custom-radio.Mui-checked': {
|
|
46
|
-
color: paletteColor(color)({ theme, darkModeEnabled })
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
);
|
|
@@ -22,7 +22,7 @@ const NsRadioGroup = (props: NsRadioGroupProps) => {
|
|
|
22
22
|
size,
|
|
23
23
|
additionalProps,
|
|
24
24
|
labelFontSize,
|
|
25
|
-
darkModeEnabled = true
|
|
25
|
+
darkModeEnabled = true,
|
|
26
26
|
} = props;
|
|
27
27
|
|
|
28
28
|
return (
|
|
@@ -50,10 +50,11 @@ const NsRadioGroup = (props: NsRadioGroupProps) => {
|
|
|
50
50
|
))}
|
|
51
51
|
</StyledRadioGroup>
|
|
52
52
|
</FormControl>
|
|
53
|
-
{additionalSlot ?
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
{additionalSlot ? (
|
|
54
|
+
<StyledHelperText className={`ml-${size}`}>
|
|
55
|
+
<StyledSpan className="text-sm">{additionalSlot}</StyledSpan>
|
|
56
|
+
</StyledHelperText>
|
|
57
|
+
) : null}
|
|
57
58
|
</>
|
|
58
59
|
);
|
|
59
60
|
};
|
|
@@ -2,8 +2,6 @@ import React from 'react';
|
|
|
2
2
|
import InputBase from '@mui/material/InputBase';
|
|
3
3
|
import { styled } from '@nuskin/foundation-theme';
|
|
4
4
|
|
|
5
|
-
interface NsSearchBarProps {}
|
|
6
|
-
|
|
7
5
|
const Search = styled('div')`
|
|
8
6
|
position: relative;
|
|
9
7
|
borderRadius: 0;
|
|
@@ -31,7 +29,7 @@ const StyledInputBase = styled(InputBase)(() => ({
|
|
|
31
29
|
},
|
|
32
30
|
}));
|
|
33
31
|
|
|
34
|
-
const NsSearchBar: React.FC
|
|
32
|
+
const NsSearchBar: React.FC = () => {
|
|
35
33
|
return (
|
|
36
34
|
<div>
|
|
37
35
|
<Search>
|
|
@@ -8,12 +8,10 @@ function createSelectOptions(options: { value: string; label: string }[]) {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
describe('NsSelectOption', () => {
|
|
11
|
-
|
|
11
|
+
it('1. renders NsSelectOption component without errors', () => {
|
|
12
12
|
const value = 'option1';
|
|
13
13
|
const label = 'Option 1';
|
|
14
|
-
const { getByTestId, getByText } = render(
|
|
15
|
-
<NsSelectOption value={value} label={label} />
|
|
16
|
-
);
|
|
14
|
+
const { getByTestId, getByText } = render(<NsSelectOption value={value} label={label} />);
|
|
17
15
|
|
|
18
16
|
// Check if the option container element exists
|
|
19
17
|
const optionContainer = getByTestId(`option-${value}`);
|
|
@@ -23,18 +21,15 @@ describe('NsSelectOption', () => {
|
|
|
23
21
|
const optionLabel = getByText(label);
|
|
24
22
|
expect(optionLabel).toBeInTheDocument();
|
|
25
23
|
});
|
|
26
|
-
|
|
24
|
+
it('2. clicking on NsSelectOption selects the option', () => {
|
|
27
25
|
const value = 'option1';
|
|
28
26
|
const label = 'Option 1';
|
|
29
27
|
const onSelect = jest.fn();
|
|
30
|
-
const { getByTestId } = render(
|
|
31
|
-
<NsSelectOption value={value} label={label} onSelect={onSelect} />
|
|
32
|
-
);
|
|
28
|
+
const { getByTestId } = render(<NsSelectOption value={value} label={label} onSelect={onSelect} />);
|
|
33
29
|
const optionElement = getByTestId(`option-${value}`);
|
|
34
30
|
fireEvent.click(optionElement);
|
|
35
31
|
expect(onSelect).toHaveBeenCalledWith(value);
|
|
36
32
|
});
|
|
37
|
-
|
|
38
33
|
});
|
|
39
34
|
|
|
40
35
|
describe('NsSelect', () => {
|
|
@@ -48,7 +43,7 @@ describe('NsSelect', () => {
|
|
|
48
43
|
{ value: 'Option3', label: 'Option 3' },
|
|
49
44
|
];
|
|
50
45
|
|
|
51
|
-
it('renders the placeholder text when no value is selected', () => {
|
|
46
|
+
it('1. renders the placeholder text when no value is selected', () => {
|
|
52
47
|
render(
|
|
53
48
|
<NsSelect
|
|
54
49
|
placeholder="Select an option"
|
|
@@ -63,14 +58,11 @@ describe('NsSelect', () => {
|
|
|
63
58
|
expect(screen.getByText('Select an option')).toBeInTheDocument();
|
|
64
59
|
});
|
|
65
60
|
|
|
66
|
-
|
|
67
|
-
// const value = 'option1';
|
|
68
|
-
// const label = 'Option 1';
|
|
61
|
+
it('2. clicking outside the select container closes the dropdown', () => {
|
|
69
62
|
const onSelect = jest.fn();
|
|
70
63
|
const selectedLabel = 'Option 1';
|
|
71
64
|
const { getByTestId, queryByTestId } = render(
|
|
72
|
-
<NsSelect selectedValue="Option1" selectedLabel={selectedLabel} onSelect={onSelect}
|
|
73
|
-
</NsSelect>
|
|
65
|
+
<NsSelect selectedValue="Option1" selectedLabel={selectedLabel} onSelect={onSelect} />
|
|
74
66
|
);
|
|
75
67
|
const selectButton = getByTestId('select-head');
|
|
76
68
|
fireEvent.mouseDown(selectButton);
|
|
@@ -80,7 +72,7 @@ describe('NsSelect', () => {
|
|
|
80
72
|
expect(queryByTestId('option-Option1')).toBeNull();
|
|
81
73
|
});
|
|
82
74
|
|
|
83
|
-
it('renders the selected value label', () => {
|
|
75
|
+
it('3. renders the selected value label', () => {
|
|
84
76
|
const selectedLabel = 'Option 1';
|
|
85
77
|
render(
|
|
86
78
|
<NsSelect selectedValue="Option1" selectedLabel={selectedLabel} onSelect={onSelect}>
|
|
@@ -91,7 +83,7 @@ describe('NsSelect', () => {
|
|
|
91
83
|
expect(screen.getByText(selectedLabel)).toBeInTheDocument();
|
|
92
84
|
});
|
|
93
85
|
|
|
94
|
-
|
|
86
|
+
it('4. clicking on select button opens the dropdown', () => {
|
|
95
87
|
const { getByTestId, getByText } = render(
|
|
96
88
|
<NsSelect selectedValue="Option1" selectedLabel={selectedLabel} onSelect={onSelect}>
|
|
97
89
|
{createSelectOptions(options)}
|
|
@@ -111,7 +103,7 @@ describe('NsSelect', () => {
|
|
|
111
103
|
expect(option2).toBeInTheDocument();
|
|
112
104
|
});
|
|
113
105
|
|
|
114
|
-
|
|
106
|
+
it('5. disabling the select component prevents interaction', () => {
|
|
115
107
|
const onSelect = jest.fn();
|
|
116
108
|
const { getByTestId, queryByTestId } = render(
|
|
117
109
|
<NsSelect selectedValue="Option1" selectedLabel={selectedLabel} onSelect={onSelect} disabled>
|
|
@@ -130,14 +122,9 @@ describe('NsSelect', () => {
|
|
|
130
122
|
expect(onSelect).not.toHaveBeenCalled();
|
|
131
123
|
});
|
|
132
124
|
|
|
133
|
-
it('select closes on mouse leave when closeOnMouseLeave is set to true', async () => {
|
|
125
|
+
it('6. select closes on mouse leave when closeOnMouseLeave is set to true', async () => {
|
|
134
126
|
render(
|
|
135
|
-
<NsSelect
|
|
136
|
-
closeOnMouseLeave
|
|
137
|
-
selectedValue={selectedValue}
|
|
138
|
-
selectedLabel={selectedLabel}
|
|
139
|
-
onSelect={onSelect}
|
|
140
|
-
>
|
|
127
|
+
<NsSelect closeOnMouseLeave selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect}>
|
|
141
128
|
{createSelectOptions(options)}
|
|
142
129
|
</NsSelect>
|
|
143
130
|
);
|
|
@@ -157,7 +144,7 @@ describe('NsSelect', () => {
|
|
|
157
144
|
expect(option3).not.toBeInTheDocument();
|
|
158
145
|
});
|
|
159
146
|
});
|
|
160
|
-
it('select does not open when disabled', () => {
|
|
147
|
+
it('7. select does not open when disabled', () => {
|
|
161
148
|
render(
|
|
162
149
|
<NsSelect selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect} disabled>
|
|
163
150
|
{createSelectOptions(options)}
|
|
@@ -170,7 +157,7 @@ describe('NsSelect', () => {
|
|
|
170
157
|
expect(screen.queryByTestId('select-list')).not.toBeInTheDocument();
|
|
171
158
|
});
|
|
172
159
|
|
|
173
|
-
it('opens the select on "ArrowDown" key press', () => {
|
|
160
|
+
it('8. opens the select on "ArrowDown" key press', () => {
|
|
174
161
|
render(
|
|
175
162
|
<NsSelect selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect}>
|
|
176
163
|
{createSelectOptions(options)}
|
|
@@ -183,18 +170,105 @@ describe('NsSelect', () => {
|
|
|
183
170
|
expect(selectHead).toBeInTheDocument();
|
|
184
171
|
});
|
|
185
172
|
|
|
186
|
-
|
|
187
|
-
const
|
|
173
|
+
it('9. closes the select when closeSelect is called', () => {
|
|
174
|
+
const { getByTestId } = render(
|
|
175
|
+
<NsSelect selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect} closeOnMouseLeave>
|
|
176
|
+
{createSelectOptions(options)}
|
|
177
|
+
</NsSelect>
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const selectContainer = getByTestId('select-container');
|
|
181
|
+
fireEvent.mouseLeave(selectContainer);
|
|
182
|
+
|
|
183
|
+
expect(screen.queryByTestId('select-list')).not.toBeInTheDocument();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('10. does not open the select when disabled', () => {
|
|
188
187
|
render(
|
|
189
|
-
<NsSelect selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect}
|
|
188
|
+
<NsSelect selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect} disabled>
|
|
190
189
|
{createSelectOptions(options)}
|
|
191
190
|
</NsSelect>
|
|
192
191
|
);
|
|
193
192
|
|
|
194
|
-
const
|
|
193
|
+
const selectHead = screen.getByTestId('select-head');
|
|
194
|
+
fireEvent.mouseDown(selectHead);
|
|
195
195
|
|
|
196
|
-
expect(
|
|
197
|
-
expect(selectContainer).toHaveStyle('color: red');
|
|
196
|
+
expect(screen.queryByTestId('select-list')).not.toBeInTheDocument();
|
|
198
197
|
});
|
|
199
198
|
|
|
199
|
+
it('11. selects the next option on arrow right click', () => {
|
|
200
|
+
// Render the NsSelect component with options and onSelect function
|
|
201
|
+
const onSelect = jest.fn();
|
|
202
|
+
const { getByTestId } = render(
|
|
203
|
+
<NsSelect selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect} hasArrows>
|
|
204
|
+
{createSelectOptions(options)}
|
|
205
|
+
</NsSelect>
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
// Simulate the arrow right click on the NsSelect component
|
|
209
|
+
const selectHead = getByTestId('select-head');
|
|
210
|
+
fireEvent.mouseDown(selectHead);
|
|
211
|
+
|
|
212
|
+
const rightArrow = document.getElementsByClassName('RightArrow')[0];
|
|
213
|
+
fireEvent.click(rightArrow);
|
|
214
|
+
|
|
215
|
+
// Verify that the next option is selected and the onSelect function is called
|
|
216
|
+
expect(onSelect).toHaveBeenCalledWith('Option1');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('12. selects the previous option on arrow left click', () => {
|
|
220
|
+
const { getByTestId } = render(
|
|
221
|
+
<NsSelect
|
|
222
|
+
selectedValue={selectedValue}
|
|
223
|
+
selectedLabel={selectedLabel}
|
|
224
|
+
onSelect={onSelect}
|
|
225
|
+
hasArrows
|
|
226
|
+
reverseArrowControls
|
|
227
|
+
>
|
|
228
|
+
{createSelectOptions(options)}
|
|
229
|
+
</NsSelect>
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
const selectHead = getByTestId('select-head');
|
|
233
|
+
fireEvent.mouseDown(selectHead);
|
|
234
|
+
|
|
235
|
+
const leftArrow = document.getElementsByClassName('LeftArrow')[0];
|
|
236
|
+
fireEvent.click(leftArrow);
|
|
237
|
+
|
|
238
|
+
expect(onSelect).toHaveBeenCalledWith('Option1');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('13. renders an error message with red styles', () => {
|
|
242
|
+
const errorMessage = 'Invalid value';
|
|
243
|
+
const { getByText } = render(
|
|
244
|
+
<NsSelect
|
|
245
|
+
selectedValue={selectedValue}
|
|
246
|
+
selectedLabel={selectedLabel}
|
|
247
|
+
onSelect={onSelect}
|
|
248
|
+
errorMessage={errorMessage}
|
|
249
|
+
>
|
|
250
|
+
{createSelectOptions(options)}
|
|
251
|
+
</NsSelect>
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
// Check if the error message is rendered correctly with red styles
|
|
255
|
+
const errorText = getByText(errorMessage);
|
|
256
|
+
expect(errorText).toBeInTheDocument();
|
|
257
|
+
});
|
|
258
|
+
it('14. selecting an option calls the onSelect callback', () => {
|
|
259
|
+
const onSelect = jest.fn();
|
|
260
|
+
const { getByTestId } = render(
|
|
261
|
+
<NsSelect selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect}>
|
|
262
|
+
{createSelectOptions(options)}
|
|
263
|
+
</NsSelect>
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const selectHead = getByTestId('select-head');
|
|
267
|
+
fireEvent.mouseDown(selectHead);
|
|
268
|
+
|
|
269
|
+
const option1 = getByTestId('option-Option1');
|
|
270
|
+
fireEvent.click(option1);
|
|
271
|
+
|
|
272
|
+
expect(onSelect).toHaveBeenCalledWith('Option1');
|
|
273
|
+
});
|
|
200
274
|
});
|