@nuskin/foundation-ui-components 1.0.0-develop.6 → 1.0.0-develop.8
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 +17 -12
- package/src/common/accordion/NsAccordion.tsx +30 -40
- package/src/common/accordion/NsAccordionHeader.tsx +27 -7
- package/src/common/accordion/NsAccordionItem.tsx +16 -4
- package/src/common/accordion/NsCollapse.tsx +71 -35
- package/src/common/accordion/NsToggleSection.tsx +14 -3
- package/src/common/accordion/ToggleSection.styled.tsx +11 -7
- package/src/common/accordion/colorMap.ts +117 -0
- package/src/common/accordion/enums.ts +8 -0
- package/src/common/accordion/index.ts +1 -0
- package/src/common/accordion/specs/NsAccordion.spec.tsx +100 -31
- package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +77 -10
- package/src/common/accordion/specs/NsAccordionItem.spec.tsx +23 -10
- package/src/common/accordion/specs/NsCollapse.spec.tsx +106 -17
- package/src/common/accordion/specs/NsToggleSection.spec.tsx +46 -14
- package/src/common/accordion/stories/NsAccordion.stories.tsx +32 -14
- package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +4 -1
- package/src/common/accordion/stories/NsAccordionItem.stories.tsx +3 -3
- package/src/common/accordion/stories/NsCollapse.stories.tsx +3 -3
- package/src/common/accordion/stories/NsToggleSection.stories.tsx +2 -3
- package/src/common/accordion/stories/data.tsx +157 -19
- package/src/common/accordion/types.d.ts +56 -49
- package/src/common/alert/Header.tsx +29 -0
- package/src/common/alert/NsAlert.spec.tsx +46 -13
- package/src/common/alert/NsAlert.stories.tsx +3 -3
- 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.stories.tsx +1 -1
- package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +11 -7
- package/src/common/auth-dropdown/NsAuthDropdown.tsx +4 -4
- package/src/common/autocomplete/NsAutocomplete.spec.tsx +29 -6
- package/src/common/autocomplete/NsAutocomplete.stories.tsx +1 -1
- package/src/common/autocomplete/NsAutocomplete.tsx +18 -8
- package/src/common/autocomplete/mock/MockUI.tsx +1 -0
- package/src/common/banner/NsBanner.spec.tsx +12 -3
- package/src/common/banner/NsBanner.stories.tsx +1 -1
- package/src/common/brand-components/NsBrand.stories.tsx +1 -1
- package/src/common/brand-components/NsBrandComponent.tsx +2 -2
- package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +8 -3
- package/src/common/breadcrumb/NsBreadcrumb.stories.tsx +1 -1
- package/src/common/breadcrumb/data.ts +8 -5
- package/src/common/button/NsButton.spec.tsx +65 -49
- package/src/common/button/NsButton.stories.tsx +59 -2
- 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/button/types.d.ts +2 -0
- package/src/common/card/stories/NsBgCard.stories.tsx +1 -1
- package/src/common/card/stories/NsBrandProductCard.stories.tsx +1 -1
- package/src/common/card/stories/NsFfgCard.stories.tsx +5 -2
- package/src/common/card/styled/NsFfgStyled.tsx +1 -1
- package/src/common/carousal/stories/NSCarousal.stories.tsx +1 -1
- package/src/common/carousal/stories/NsScrollingCarousal.stories.tsx +1 -1
- package/src/common/cart-icon/NsCartIcon.stories.tsx +1 -1
- package/src/common/checkbox/NsCheckbox.stories.tsx +1 -1
- package/src/common/checkbox/NsCheckbox.styled.tsx +15 -16
- package/src/common/checkbox/NsCheckbox.tsx +1 -1
- package/src/common/column-control/stories/DivArray.stories.tsx +1 -1
- package/src/common/column-control/stories/NsColumnControl.stories.tsx +1 -1
- package/src/common/column-control/stories/NsFlexColumns.stories.tsx +1 -1
- package/src/common/column-control/stories/NsGridColumns.stories.tsx +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 +11 -1
- package/src/common/dropdown/NsDropdown.styled.tsx +23 -18
- package/src/common/dropdown/stories/NsDropdown.stories.tsx +1 -1
- package/src/common/dropdown/stories/NsDropdownCountry.stories.tsx +1 -1
- package/src/common/flag/NsFlag.stories.tsx +1 -1
- 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/useWindowSize.tsx +30 -0
- package/src/common/icon/NsIcon.stories.tsx +1 -1
- package/src/common/icon/NsIconVariants.ts +1 -0
- package/src/common/image/NsImage.spec.tsx +56 -6
- package/src/common/image/NsImage.stories.tsx +1 -1
- package/src/common/image/NsImage.tsx +23 -11
- package/src/common/image/NsNextImage.stories.tsx +1 -1
- package/src/common/index.ts +6 -2
- package/src/common/input/InputWrapper.tsx +12 -7
- package/src/common/input/NsInputField.tsx +1 -1
- package/src/common/label/NsLabel.stories.tsx +1 -1
- package/src/common/link/NsLink.stories.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 +86 -0
- package/src/common/modal/stories/mock.tsx +46 -0
- package/src/common/modal/types.ts +56 -0
- package/src/common/nav-product-card/NsNavProductCard.stories.tsx +1 -1
- package/src/common/nav-tab/NsNavTab.stories.tsx +1 -1
- package/src/common/radiogroup/NsRadioGroup.spec.tsx +24 -25
- package/src/common/radiogroup/NsRadioGroup.stories.tsx +14 -32
- 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 +10 -17
- package/src/common/select/NsSelect.styled.tsx +53 -34
- package/src/common/select/stories/NsSelect.stories.tsx +11 -11
- package/src/common/select/types.d.ts +3 -3
- 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.stories.tsx +1 -1
- package/src/common/table/NsTable.tsx +32 -49
- package/src/common/table/NsTableHeader.tsx +30 -51
- package/src/common/text-strip/NsTextStrip.stories.tsx +1 -1
- package/src/common/typography/NsTypography.stories.tsx +1 -1
- 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/NsVideo.stories.tsx +1 -1
- package/src/common/videos/types.d.ts +1 -1
- /package/src/common/brand-components/{NsBrandContanier.styled.tsx → NsBrandContainer.styled.tsx} +0 -0
|
@@ -11,9 +11,7 @@ describe('NsSelectOption', () => {
|
|
|
11
11
|
test('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}`);
|
|
@@ -27,14 +25,11 @@ describe('NsSelectOption', () => {
|
|
|
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', () => {
|
|
@@ -69,8 +64,7 @@ describe('NsSelect', () => {
|
|
|
69
64
|
const onSelect = jest.fn();
|
|
70
65
|
const selectedLabel = 'Option 1';
|
|
71
66
|
const { getByTestId, queryByTestId } = render(
|
|
72
|
-
<NsSelect selectedValue="Option1" selectedLabel={selectedLabel} onSelect={onSelect}
|
|
73
|
-
</NsSelect>
|
|
67
|
+
<NsSelect selectedValue="Option1" selectedLabel={selectedLabel} onSelect={onSelect} />
|
|
74
68
|
);
|
|
75
69
|
const selectButton = getByTestId('select-head');
|
|
76
70
|
fireEvent.mouseDown(selectButton);
|
|
@@ -132,12 +126,7 @@ describe('NsSelect', () => {
|
|
|
132
126
|
|
|
133
127
|
it('select closes on mouse leave when closeOnMouseLeave is set to true', async () => {
|
|
134
128
|
render(
|
|
135
|
-
<NsSelect
|
|
136
|
-
closeOnMouseLeave
|
|
137
|
-
selectedValue={selectedValue}
|
|
138
|
-
selectedLabel={selectedLabel}
|
|
139
|
-
onSelect={onSelect}
|
|
140
|
-
>
|
|
129
|
+
<NsSelect closeOnMouseLeave selectedValue={selectedValue} selectedLabel={selectedLabel} onSelect={onSelect}>
|
|
141
130
|
{createSelectOptions(options)}
|
|
142
131
|
</NsSelect>
|
|
143
132
|
);
|
|
@@ -186,7 +175,12 @@ describe('NsSelect', () => {
|
|
|
186
175
|
test('renders SelectContainer with error styles when errorMessage is present', () => {
|
|
187
176
|
const errorMessage = 'Invalid value';
|
|
188
177
|
render(
|
|
189
|
-
<NsSelect
|
|
178
|
+
<NsSelect
|
|
179
|
+
selectedValue={selectedValue}
|
|
180
|
+
selectedLabel={selectedLabel}
|
|
181
|
+
onSelect={onSelect}
|
|
182
|
+
errorMessage={errorMessage}
|
|
183
|
+
>
|
|
190
184
|
{createSelectOptions(options)}
|
|
191
185
|
</NsSelect>
|
|
192
186
|
);
|
|
@@ -196,5 +190,4 @@ describe('NsSelect', () => {
|
|
|
196
190
|
expect(selectContainer).toHaveStyle('borderColor: red');
|
|
197
191
|
expect(selectContainer).toHaveStyle('color: red');
|
|
198
192
|
});
|
|
199
|
-
|
|
200
193
|
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { styled, ColorUtils, FoundationTheme } from '@nuskin/foundation-theme';
|
|
2
|
+
import { Themed } from '../common.types';
|
|
3
|
+
import { getDropdownHeadBorder } from '../dropdown/NsDropdown.styled';
|
|
2
4
|
const { color, paletteColor, isDarkMode } = ColorUtils;
|
|
3
5
|
|
|
4
6
|
export const SelectContainer = styled.div<{ disabled: boolean }>`
|
|
@@ -13,8 +15,7 @@ export const SelectHead = styled.div<{ type: string; disabled: boolean }>`
|
|
|
13
15
|
display: flex;
|
|
14
16
|
justify-content: space-between;
|
|
15
17
|
align-items: center;
|
|
16
|
-
border: ${
|
|
17
|
-
type === 'outlined' ? `1px solid ${color('primary', 'black')({ theme })}` : 'none'};
|
|
18
|
+
border: ${getDropdownHeadBorder}
|
|
18
19
|
color: ${paletteColor('primary')};
|
|
19
20
|
width: 207px;
|
|
20
21
|
position: relative;
|
|
@@ -36,47 +37,65 @@ export const SelectList = styled.div<{ borderColor: FoundationTheme.PaletteColor
|
|
|
36
37
|
background-color: ${paletteColor('primary', 'contrastText')};
|
|
37
38
|
`;
|
|
38
39
|
|
|
39
|
-
const getDividerColor = (props: { theme: FoundationTheme.Theme}) => {
|
|
40
|
-
|
|
41
|
-
return dividerColor;
|
|
40
|
+
const getDividerColor = (props: { theme: FoundationTheme.Theme }) => {
|
|
41
|
+
return !isDarkMode(props) ? color('neutral', '30')(props) : color('neutral', '20')(props);
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
const getListBgColor = (props: { theme: FoundationTheme.Theme }) => {
|
|
45
|
-
|
|
46
|
-
return bgColor;
|
|
45
|
+
return !isDarkMode(props) ? color('accentColorB', '10')(props) : color('accentColorB', '50')(props);
|
|
47
46
|
};
|
|
47
|
+
type ContainerParam = { borderBottom: string; bgColor: string; color: string; hoveredBg: string };
|
|
48
|
+
function createListContainerStyle({ borderBottom, bgColor, color, hoveredBg }: ContainerParam) {
|
|
49
|
+
return `
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
padding: 5px 0;
|
|
52
|
+
border-bottom: 1px solid ${borderBottom};
|
|
53
|
+
background-color: ${bgColor};
|
|
54
|
+
color: ${color};
|
|
48
55
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
padding: 5px 0;
|
|
53
|
-
border-bottom: 1px solid ${showListDivider ? getDividerColor({ theme }) : 'none'};
|
|
54
|
-
background-color: ${isSelected ? paletteColor('primary')({ theme }) : 'white'};
|
|
55
|
-
color: ${isSelected ? 'white' : 'black'};
|
|
56
|
-
|
|
57
|
-
&:hover {
|
|
58
|
-
background-color: ${getListBgColor({ theme })};
|
|
59
|
-
}
|
|
56
|
+
&:hover {
|
|
57
|
+
background-color: ${hoveredBg};
|
|
58
|
+
}
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
&:last-child {
|
|
61
|
+
border-bottom: none;
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
export const ListItemContainer = styled.div<{ showListDivider: boolean; isSelected: boolean }>`
|
|
66
|
+
${({ showListDivider, isSelected, theme }) => {
|
|
67
|
+
const borderBottom = showListDivider ? getDividerColor({ theme }) : 'none';
|
|
68
|
+
const bgColor = isSelected ? paletteColor('primary')({ theme }) : 'white';
|
|
69
|
+
const color = isSelected ? 'white' : 'black';
|
|
70
|
+
const hoveredBg = getListBgColor({ theme });
|
|
71
|
+
return createListContainerStyle({ borderBottom, bgColor, color, hoveredBg });
|
|
72
|
+
}}
|
|
65
73
|
`;
|
|
74
|
+
const getListItemBgColor = ({ isSelected, theme }: { isSelected: boolean } & Themed) => {
|
|
75
|
+
if (isSelected) {
|
|
76
|
+
return paletteColor('primary')({ theme });
|
|
77
|
+
}
|
|
78
|
+
return getListBgColor({ theme });
|
|
79
|
+
};
|
|
66
80
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
background-color: ${({ isSelected, theme }) =>
|
|
72
|
-
isSelected ? paletteColor('primary', 'main')({ theme }) : 'white'};
|
|
73
|
-
color: ${({ isSelected }) => (isSelected ? 'white' : 'black')};
|
|
74
|
-
&:hover {
|
|
75
|
-
background-color: ${({ isSelected, theme }) =>
|
|
76
|
-
isSelected ? paletteColor('primary')({ theme }) : getListBgColor({ theme })};
|
|
77
|
-
font-weight: bold;
|
|
81
|
+
const getListItemBorderLeftColor = ({ isSelected, theme }: { isSelected: boolean } & Themed) => {
|
|
82
|
+
if (isSelected) {
|
|
83
|
+
const color = paletteColor('primary')({ theme });
|
|
84
|
+
return `2px solid ${color}`;
|
|
78
85
|
}
|
|
79
|
-
|
|
86
|
+
return 'none';
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const ListItem = styled.div<{ isSelected: boolean }>(({ isSelected, theme }) => ({
|
|
90
|
+
padding: '5px 10px',
|
|
91
|
+
borderLeft: getListItemBorderLeftColor({ isSelected, theme }),
|
|
92
|
+
backgroundColor: isSelected ? paletteColor('primary', 'main')({ theme }) : 'white',
|
|
93
|
+
color: isSelected ? 'white' : 'black',
|
|
94
|
+
'&:hover': {
|
|
95
|
+
backgroundColor: getListItemBgColor({ isSelected, theme }),
|
|
96
|
+
fontWeight: 'bold',
|
|
97
|
+
},
|
|
98
|
+
}));
|
|
80
99
|
|
|
81
100
|
export const SelectLabel = styled.label`
|
|
82
101
|
display: block;
|
|
@@ -4,7 +4,7 @@ import NsSelect from '../NsSelect';
|
|
|
4
4
|
import NsSelectOption from '../NsSelectOption';
|
|
5
5
|
|
|
6
6
|
export default {
|
|
7
|
-
title: 'Components/NsSelect',
|
|
7
|
+
title: 'Components/Inputs/NsSelect',
|
|
8
8
|
decorators: [
|
|
9
9
|
(story) => <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>{story()}</div>,
|
|
10
10
|
],
|
|
@@ -21,11 +21,11 @@ export default {
|
|
|
21
21
|
showListDivider: { control: 'boolean' },
|
|
22
22
|
label: { control: 'text' },
|
|
23
23
|
name: { control: 'text' },
|
|
24
|
-
menuProps:{ control: 'text' },
|
|
25
|
-
reverseArrowControls:{ control: 'boolean' },
|
|
26
|
-
validateOnBlur:{ control: 'boolean' },
|
|
24
|
+
menuProps: { control: 'text' },
|
|
25
|
+
reverseArrowControls: { control: 'boolean' },
|
|
26
|
+
validateOnBlur: { control: 'boolean' },
|
|
27
27
|
autoComplete: { control: 'text' },
|
|
28
|
-
rules: {control: 'array'},
|
|
28
|
+
rules: { control: 'array' },
|
|
29
29
|
},
|
|
30
30
|
parameters: {
|
|
31
31
|
options: [
|
|
@@ -91,15 +91,15 @@ export default {
|
|
|
91
91
|
selectedValue: '',
|
|
92
92
|
selectedLabel: '',
|
|
93
93
|
label: 'State',
|
|
94
|
-
placeholder:'',
|
|
95
|
-
name:'',
|
|
96
|
-
menuProps:'auto',
|
|
94
|
+
placeholder: '',
|
|
95
|
+
name: '',
|
|
96
|
+
menuProps: 'auto',
|
|
97
97
|
reverseArrowControls: false,
|
|
98
|
-
itemText:'Text',
|
|
99
|
-
itemValue:'Value',
|
|
98
|
+
itemText: 'Text',
|
|
99
|
+
itemValue: 'Value',
|
|
100
100
|
validateOnBlur: false,
|
|
101
101
|
autoComplete: '',
|
|
102
|
-
rules:[]
|
|
102
|
+
rules: [],
|
|
103
103
|
},
|
|
104
104
|
} as ComponentMeta<typeof NsSelect>;
|
|
105
105
|
|
|
@@ -5,7 +5,7 @@ export interface SelectProps {
|
|
|
5
5
|
selectedValue: string;
|
|
6
6
|
selectedLabel: string;
|
|
7
7
|
onSelect: (arg: string) => void; // eslint-disable-line
|
|
8
|
-
children
|
|
8
|
+
children?: ReactNode | null;
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
type?: 'outlined' | 'unfilled';
|
|
11
11
|
placeholder?: string;
|
|
@@ -14,11 +14,11 @@ export interface SelectProps {
|
|
|
14
14
|
showListDivider?: boolean;
|
|
15
15
|
label?: string;
|
|
16
16
|
readOnly?: boolean;
|
|
17
|
-
name?: string;
|
|
17
|
+
name?: string;
|
|
18
18
|
errorMessage?: string;
|
|
19
19
|
menuProps?: string | object;
|
|
20
20
|
reverseArrowControls?: boolean;
|
|
21
|
-
itemText?: string;
|
|
21
|
+
itemText?: string;
|
|
22
22
|
itemValue?: string;
|
|
23
23
|
validateOnBlur?: boolean;
|
|
24
24
|
autoComplete?: string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@/test-utils/index';
|
|
3
|
+
import NsSpinner from './NsSpinner';
|
|
4
|
+
|
|
5
|
+
describe('NsSpinner', () => {
|
|
6
|
+
test('1.renders spinner', () => {
|
|
7
|
+
const { container } = render(<NsSpinner additionalProps={{ 'data-testid': 'spinner' }} />);
|
|
8
|
+
|
|
9
|
+
expect(screen.getByTestId('spinner')).toBeInTheDocument();
|
|
10
|
+
expect(container.getElementsByTagName('svg')).toHaveLength(1);
|
|
11
|
+
expect(screen.getByTestId('spinner')).toHaveStyle('width:100px');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('2.renders spinner with different size', () => {
|
|
15
|
+
render(<NsSpinner size={200} additionalProps={{ 'data-testid': 'spinner' }} />);
|
|
16
|
+
|
|
17
|
+
expect(screen.getByTestId('spinner')).toBeInTheDocument();
|
|
18
|
+
expect(screen.getByTestId('spinner')).toHaveStyle('width:200px');
|
|
19
|
+
expect(screen.getByTestId('spinner')).toHaveStyle('height:200px');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import NsSpinner from './NsSpinner';
|
|
3
|
+
import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
|
|
4
|
+
|
|
5
|
+
type ComponentType = typeof NsSpinner;
|
|
6
|
+
type Story = StoryObj<ComponentType>;
|
|
7
|
+
type MetaStory = Meta<ComponentType>;
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'Components/Feedback/NsSpinner',
|
|
11
|
+
component: NsSpinner,
|
|
12
|
+
decorators: [
|
|
13
|
+
(Story) => (
|
|
14
|
+
<div className="flex place-content-center">
|
|
15
|
+
<Story />
|
|
16
|
+
</div>
|
|
17
|
+
),
|
|
18
|
+
withCenterDecorator,
|
|
19
|
+
],
|
|
20
|
+
argTypes: {},
|
|
21
|
+
args: {
|
|
22
|
+
size: 200,
|
|
23
|
+
},
|
|
24
|
+
} as MetaStory;
|
|
25
|
+
|
|
26
|
+
export const Spinner: Story = {};
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
+
|
|
3
|
+
export const SpinnerContainer = styled.div<{ size: number }>`
|
|
4
|
+
width: ${(prop) => prop.size}px;
|
|
5
|
+
height: ${(prop) => prop.size}px;
|
|
6
|
+
svg {
|
|
7
|
+
width: ${(prop) => prop.size}px;
|
|
8
|
+
height: ${(prop) => prop.size}px;
|
|
9
|
+
}
|
|
10
|
+
#ns-spinner-7_tr {
|
|
11
|
+
animation: ns-spinner-7_tr__tr 4000ms linear infinite normal forwards;
|
|
12
|
+
}
|
|
13
|
+
@keyframes ns-spinner-7_tr__tr {
|
|
14
|
+
0% {
|
|
15
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
16
|
+
}
|
|
17
|
+
80% {
|
|
18
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
19
|
+
animation-timing-function: cubic-bezier(0.495, 0.49, 0.82, 0.11);
|
|
20
|
+
}
|
|
21
|
+
100% {
|
|
22
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
#ns-spinner-7 {
|
|
26
|
+
animation: ns-spinner-7_c_o 4000ms linear infinite normal forwards;
|
|
27
|
+
}
|
|
28
|
+
@keyframes ns-spinner-7_c_o {
|
|
29
|
+
0% {
|
|
30
|
+
opacity: 0;
|
|
31
|
+
}
|
|
32
|
+
77.500000% {
|
|
33
|
+
opacity: 0;
|
|
34
|
+
}
|
|
35
|
+
80% {
|
|
36
|
+
opacity: 1;
|
|
37
|
+
}
|
|
38
|
+
97.500000% {
|
|
39
|
+
opacity: 1;
|
|
40
|
+
}
|
|
41
|
+
100% {
|
|
42
|
+
opacity: 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
#ns-spinner-8_tr {
|
|
46
|
+
animation: ns-spinner-8_tr__tr 4000ms linear infinite normal forwards;
|
|
47
|
+
}
|
|
48
|
+
@keyframes ns-spinner-8_tr__tr {
|
|
49
|
+
0% {
|
|
50
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
51
|
+
}
|
|
52
|
+
77.500000% {
|
|
53
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
54
|
+
animation-timing-function: cubic-bezier(0.1, 0.365, 0.82, 0.11);
|
|
55
|
+
}
|
|
56
|
+
100% {
|
|
57
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
#ns-spinner-8 {
|
|
61
|
+
animation: ns-spinner-8_c_o 4000ms linear infinite normal forwards;
|
|
62
|
+
}
|
|
63
|
+
@keyframes ns-spinner-8_c_o {
|
|
64
|
+
0% {
|
|
65
|
+
opacity: 0;
|
|
66
|
+
}
|
|
67
|
+
75% {
|
|
68
|
+
opacity: 0;
|
|
69
|
+
}
|
|
70
|
+
77.500000% {
|
|
71
|
+
opacity: 1;
|
|
72
|
+
}
|
|
73
|
+
97.500000% {
|
|
74
|
+
opacity: 1;
|
|
75
|
+
}
|
|
76
|
+
100% {
|
|
77
|
+
opacity: 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
#ns-spinner-9_tr {
|
|
81
|
+
animation: ns-spinner-9_tr__tr 4000ms linear infinite normal forwards;
|
|
82
|
+
}
|
|
83
|
+
@keyframes ns-spinner-9_tr__tr {
|
|
84
|
+
0% {
|
|
85
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
86
|
+
}
|
|
87
|
+
30% {
|
|
88
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
89
|
+
animation-timing-function: cubic-bezier(0.5, 0.495, 0.82, 0.11);
|
|
90
|
+
}
|
|
91
|
+
50% {
|
|
92
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
93
|
+
}
|
|
94
|
+
100% {
|
|
95
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
#ns-spinner-9 {
|
|
99
|
+
animation: ns-spinner-9_c_o 4000ms linear infinite normal forwards;
|
|
100
|
+
}
|
|
101
|
+
@keyframes ns-spinner-9_c_o {
|
|
102
|
+
0% {
|
|
103
|
+
opacity: 0;
|
|
104
|
+
}
|
|
105
|
+
25% {
|
|
106
|
+
opacity: 0;
|
|
107
|
+
}
|
|
108
|
+
27.500000% {
|
|
109
|
+
opacity: 1;
|
|
110
|
+
}
|
|
111
|
+
47.500000% {
|
|
112
|
+
opacity: 1;
|
|
113
|
+
}
|
|
114
|
+
50% {
|
|
115
|
+
opacity: 0;
|
|
116
|
+
}
|
|
117
|
+
100% {
|
|
118
|
+
opacity: 0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
#ns-spinner-10_tr {
|
|
122
|
+
animation: ns-spinner-10_tr__tr 4000ms linear infinite normal forwards;
|
|
123
|
+
}
|
|
124
|
+
@keyframes ns-spinner-10_tr__tr {
|
|
125
|
+
0% {
|
|
126
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
127
|
+
}
|
|
128
|
+
27.500000% {
|
|
129
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
130
|
+
animation-timing-function: cubic-bezier(0.1, 0.365, 0.82, 0.11);
|
|
131
|
+
}
|
|
132
|
+
50% {
|
|
133
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
134
|
+
}
|
|
135
|
+
100% {
|
|
136
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
#ns-spinner-10 {
|
|
140
|
+
animation: ns-spinner-10_c_o 4000ms linear infinite normal forwards;
|
|
141
|
+
}
|
|
142
|
+
@keyframes ns-spinner-10_c_o {
|
|
143
|
+
0% {
|
|
144
|
+
opacity: 0;
|
|
145
|
+
}
|
|
146
|
+
25% {
|
|
147
|
+
opacity: 0;
|
|
148
|
+
}
|
|
149
|
+
27.500000% {
|
|
150
|
+
opacity: 1;
|
|
151
|
+
}
|
|
152
|
+
47.500000% {
|
|
153
|
+
opacity: 1;
|
|
154
|
+
}
|
|
155
|
+
50% {
|
|
156
|
+
opacity: 0;
|
|
157
|
+
}
|
|
158
|
+
100% {
|
|
159
|
+
opacity: 0;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
#ns-spinner-11_tr {
|
|
163
|
+
animation: ns-spinner-11_tr__tr 4000ms linear infinite normal forwards;
|
|
164
|
+
}
|
|
165
|
+
@keyframes ns-spinner-11_tr__tr {
|
|
166
|
+
0% {
|
|
167
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
168
|
+
}
|
|
169
|
+
55% {
|
|
170
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
171
|
+
animation-timing-function: cubic-bezier(0.495, 0.49, 0.82, 0.11);
|
|
172
|
+
}
|
|
173
|
+
75% {
|
|
174
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
175
|
+
}
|
|
176
|
+
100% {
|
|
177
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
#ns-spinner-11 {
|
|
181
|
+
animation: ns-spinner-11_c_o 4000ms linear infinite normal forwards;
|
|
182
|
+
}
|
|
183
|
+
@keyframes ns-spinner-11_c_o {
|
|
184
|
+
0% {
|
|
185
|
+
opacity: 0;
|
|
186
|
+
}
|
|
187
|
+
52.500000% {
|
|
188
|
+
opacity: 0;
|
|
189
|
+
}
|
|
190
|
+
55% {
|
|
191
|
+
opacity: 1;
|
|
192
|
+
}
|
|
193
|
+
72.500000% {
|
|
194
|
+
opacity: 1;
|
|
195
|
+
}
|
|
196
|
+
75% {
|
|
197
|
+
opacity: 0;
|
|
198
|
+
}
|
|
199
|
+
100% {
|
|
200
|
+
opacity: 0;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
#ns-spinner-12_tr {
|
|
204
|
+
animation: ns-spinner-12_tr__tr 4000ms linear infinite normal forwards;
|
|
205
|
+
}
|
|
206
|
+
@keyframes ns-spinner-12_tr__tr {
|
|
207
|
+
0% {
|
|
208
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
209
|
+
}
|
|
210
|
+
52.500000% {
|
|
211
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
212
|
+
animation-timing-function: cubic-bezier(0.1, 0.365, 0.82, 0.11);
|
|
213
|
+
}
|
|
214
|
+
75% {
|
|
215
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
216
|
+
}
|
|
217
|
+
100% {
|
|
218
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
#ns-spinner-12 {
|
|
222
|
+
animation: ns-spinner-12_c_o 4000ms linear infinite normal forwards;
|
|
223
|
+
}
|
|
224
|
+
@keyframes ns-spinner-12_c_o {
|
|
225
|
+
0% {
|
|
226
|
+
opacity: 0;
|
|
227
|
+
}
|
|
228
|
+
50% {
|
|
229
|
+
opacity: 0;
|
|
230
|
+
}
|
|
231
|
+
52.500000% {
|
|
232
|
+
opacity: 1;
|
|
233
|
+
}
|
|
234
|
+
72.500000% {
|
|
235
|
+
opacity: 1;
|
|
236
|
+
}
|
|
237
|
+
75% {
|
|
238
|
+
opacity: 0;
|
|
239
|
+
}
|
|
240
|
+
100% {
|
|
241
|
+
opacity: 0;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
#ns-spinner-13_tr {
|
|
245
|
+
animation: ns-spinner-13_tr__tr 4000ms linear infinite normal forwards;
|
|
246
|
+
}
|
|
247
|
+
@keyframes ns-spinner-13_tr__tr {
|
|
248
|
+
0% {
|
|
249
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
250
|
+
}
|
|
251
|
+
5% {
|
|
252
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
253
|
+
animation-timing-function: cubic-bezier(0.495, 0.49, 0.82, 0.11);
|
|
254
|
+
}
|
|
255
|
+
25% {
|
|
256
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
257
|
+
}
|
|
258
|
+
100% {
|
|
259
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
#ns-spinner-13 {
|
|
263
|
+
animation: ns-spinner-13_c_o 4000ms linear infinite normal forwards;
|
|
264
|
+
}
|
|
265
|
+
@keyframes ns-spinner-13_c_o {
|
|
266
|
+
0% {
|
|
267
|
+
opacity: 1;
|
|
268
|
+
}
|
|
269
|
+
5% {
|
|
270
|
+
opacity: 1;
|
|
271
|
+
}
|
|
272
|
+
25% {
|
|
273
|
+
opacity: 1;
|
|
274
|
+
}
|
|
275
|
+
27.500000% {
|
|
276
|
+
opacity: 0;
|
|
277
|
+
}
|
|
278
|
+
100% {
|
|
279
|
+
opacity: 0;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
#ns-spinner-14_tr {
|
|
283
|
+
animation: ns-spinner-14_tr__tr 4000ms linear infinite normal forwards;
|
|
284
|
+
}
|
|
285
|
+
@keyframes ns-spinner-14_tr__tr {
|
|
286
|
+
0% {
|
|
287
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
288
|
+
}
|
|
289
|
+
2.500000% {
|
|
290
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
291
|
+
animation-timing-function: cubic-bezier(0.1, 0.365, 0.82, 0.11);
|
|
292
|
+
}
|
|
293
|
+
25% {
|
|
294
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
295
|
+
}
|
|
296
|
+
100% {
|
|
297
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
#ns-spinner-14 {
|
|
301
|
+
animation: ns-spinner-14_c_o 4000ms linear infinite normal forwards;
|
|
302
|
+
}
|
|
303
|
+
@keyframes ns-spinner-14_c_o {
|
|
304
|
+
0% {
|
|
305
|
+
opacity: 1;
|
|
306
|
+
}
|
|
307
|
+
2.500000% {
|
|
308
|
+
opacity: 1;
|
|
309
|
+
}
|
|
310
|
+
25% {
|
|
311
|
+
opacity: 1;
|
|
312
|
+
}
|
|
313
|
+
27.500000% {
|
|
314
|
+
opacity: 0;
|
|
315
|
+
}
|
|
316
|
+
100% {
|
|
317
|
+
opacity: 0;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
#ns-spinner-15_tr {
|
|
321
|
+
animation: ns-spinner-15_tr__tr 4000ms linear infinite normal forwards;
|
|
322
|
+
}
|
|
323
|
+
@keyframes ns-spinner-15_tr__tr {
|
|
324
|
+
0% {
|
|
325
|
+
transform: translate(232.873721px, 220.430229px) rotate(71.000016deg);
|
|
326
|
+
animation-timing-function: cubic-bezier(0, 0.25, 0.795, 0.345);
|
|
327
|
+
}
|
|
328
|
+
25% {
|
|
329
|
+
transform: translate(232.873721px, 220.430229px) rotate(430deg);
|
|
330
|
+
animation-timing-function: cubic-bezier(0, 0.25, 0.795, 0.345);
|
|
331
|
+
}
|
|
332
|
+
50% {
|
|
333
|
+
transform: translate(232.873721px, 220.430229px) rotate(791deg);
|
|
334
|
+
animation-timing-function: cubic-bezier(0, 0.25, 0.795, 0.345);
|
|
335
|
+
}
|
|
336
|
+
75% {
|
|
337
|
+
transform: translate(232.873721px, 220.430229px) rotate(1151deg);
|
|
338
|
+
animation-timing-function: cubic-bezier(0, 0.25, 0.795, 0.345);
|
|
339
|
+
}
|
|
340
|
+
100% {
|
|
341
|
+
transform: translate(232.873721px, 220.430229px) rotate(1511deg);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import SpinnerIcon from './icons/Spinner';
|
|
3
|
+
import { SpinnerContainer } from './NsSpinner.styled';
|
|
4
|
+
import { NsSpinnerProps } from './types';
|
|
5
|
+
|
|
6
|
+
const NsSpinner: React.FC<NsSpinnerProps> = ({ size = 100, additionalProps }) => {
|
|
7
|
+
return (
|
|
8
|
+
<SpinnerContainer size={size} className="spinner" {...additionalProps}>
|
|
9
|
+
<SpinnerIcon />
|
|
10
|
+
</SpinnerContainer>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default NsSpinner;
|