@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
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
|
-
import { useTheme } from '@mui/material/styles';
|
|
3
2
|
import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';
|
|
4
3
|
/**
|
|
5
4
|
*
|
|
6
5
|
* @param props {fill: color to be filled for icon, color: color of the tick icon}
|
|
7
6
|
*/
|
|
8
7
|
const UserIcon = (props: SvgIconProps) => {
|
|
9
|
-
const { palette } = useTheme();
|
|
10
|
-
const strokeColor = palette.primary.main;
|
|
11
8
|
return (
|
|
12
|
-
<SvgIcon viewBox="0 0 24 24"
|
|
9
|
+
<SvgIcon viewBox="0 0 24 24" data-testid="userIcon" xmlns="http://www.w3.org/2000/svg" {...props}>
|
|
13
10
|
<path
|
|
14
11
|
fillRule="evenodd"
|
|
15
12
|
clipRule="evenodd"
|
|
16
13
|
d="M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23Z"
|
|
17
|
-
stroke={
|
|
14
|
+
stroke={props.color}
|
|
18
15
|
strokeWidth="2"
|
|
19
16
|
/>
|
|
20
17
|
<path
|
|
21
18
|
d="M19 20C18.9425 19.3229 19 17.5669 17.3793 17.2226C14.7126 16.6144 13.931 16.4078 14.1034 14.2272C15.8046 13.0796 15.7816 11.0252 15.7471 8.74139C15.7471 6.67508 14.0695 5 12 5C9.93052 5 8.25287 6.67508 8.25287 8.74139C8.25287 11.0367 8.25287 13.137 9.89655 14.2272C10.0575 16.4078 9.28736 16.6144 6.62069 17.2226C5 17.5669 5.05747 19.3229 5 20"
|
|
22
|
-
stroke={
|
|
19
|
+
stroke={props.color}
|
|
23
20
|
strokeWidth="2"
|
|
24
21
|
strokeLinecap="round"
|
|
25
22
|
/>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
2
|
+
import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';
|
|
3
|
+
|
|
4
|
+
function UserOutline(props: SvgIconProps) {
|
|
5
|
+
return (
|
|
6
|
+
<SvgIcon
|
|
7
|
+
data-testid="userOutline"
|
|
8
|
+
width="24"
|
|
9
|
+
height="24"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
fill="none"
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
13
|
+
>
|
|
14
|
+
<path
|
|
15
|
+
fill-rule="evenodd"
|
|
16
|
+
clip-rule="evenodd"
|
|
17
|
+
d="M12 1.25C6.06294 1.25 1.25 6.06294 1.25 12C1.25 17.9371 6.06294 22.75 12 22.75C17.9371 22.75 22.75 17.9371 22.75 12C22.75 6.06294 17.9371 1.25 12 1.25ZM2.75 12C2.75 6.89137 6.89137 2.75 12 2.75C17.1086 2.75 21.25 6.89137 21.25 12C21.25 14.5514 20.217 16.8615 18.5465 18.535C18.5373 18.5053 18.5278 18.4757 18.5177 18.4462C18.2909 17.7811 17.7908 17.0816 16.7743 16.861C16.1976 16.7279 15.7597 16.6249 15.4126 16.5154C15.0619 16.4048 14.8722 16.3075 14.7621 16.2197C14.6519 16.1318 14.5229 15.9893 14.534 15.3824C15.2564 14.7722 15.6208 13.9828 15.7989 13.145C15.9917 12.2377 15.9765 11.218 15.9621 10.2575L15.9618 10.2367C15.9587 8.04108 14.1928 6.25 12 6.25C9.80523 6.25 8.03818 8.04427 8.03818 10.2425L8.03818 10.2902C8.03812 11.2492 8.03807 12.2685 8.23093 13.1685C8.40828 13.9961 8.76096 14.7856 9.46415 15.382C9.47219 15.9884 9.34391 16.1319 9.23338 16.2204C9.12398 16.3079 8.93522 16.4051 8.58559 16.5155C8.23946 16.6249 7.80232 16.728 7.22572 16.861C6.20921 17.0816 5.70909 17.7811 5.48226 18.4462C5.47222 18.4757 5.46266 18.5053 5.45354 18.535C3.78298 16.8615 2.75 14.5514 2.75 12ZM6.77658 19.6351C8.26295 20.6539 10.0619 21.25 12 21.25C13.9381 21.25 15.7371 20.6539 17.2234 19.6351C17.206 19.3999 17.1779 19.1646 17.098 18.9304C16.9903 18.6146 16.822 18.4054 16.4533 18.3262L16.4423 18.3239L16.4423 18.3238C15.8787 18.1938 15.3772 18.0771 14.9615 17.946C14.5483 17.8157 14.1512 17.6513 13.8266 17.3922C13.0849 16.8004 12.9768 15.9412 13.0552 14.9385L13.0833 14.58L13.3803 14.3774C13.9081 14.0173 14.1862 13.5172 14.3317 12.8331C14.4843 12.1148 14.477 11.265 14.4619 10.2537L14.4617 10.2425H14.4618C14.4618 8.8592 13.3529 7.75 12 7.75C10.6471 7.75 9.53818 8.8592 9.53818 10.2425C9.53818 11.259 9.54149 12.1256 9.69764 12.8542C9.84777 13.5548 10.1225 14.0439 10.6148 14.3741L10.9184 14.5777L10.9451 14.9423C11.0181 15.9429 10.9092 16.8005 10.1706 17.3915C9.84647 17.6509 9.45024 17.8154 9.03756 17.9458C8.62239 18.077 8.12144 18.1938 7.55771 18.3238L7.54669 18.3263L7.54667 18.3262C7.17801 18.4054 7.00968 18.6146 6.90197 18.9304C6.8221 19.1646 6.79403 19.3999 6.77658 19.6351Z"
|
|
18
|
+
fill={props.color || '#272525'}
|
|
19
|
+
/>
|
|
20
|
+
</SvgIcon>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default UserOutline;
|
|
@@ -24,7 +24,7 @@ const WarningIcon = (props: SvgIconProps) => {
|
|
|
24
24
|
15.5143276 0.328282319,15.6093523 0.505163987,15.6123832 L17.5120236,15.6123832 C17.6889052,15.6093523 17.8513135,15.5143276 17.940195,15.3618609 C18.0290766,
|
|
25
25
|
15.2093943 18.0314841,15.0216954 17.9465423,14.8670135 Z"
|
|
26
26
|
id="Shape"
|
|
27
|
-
fill=
|
|
27
|
+
fill={props.color || '#FEBD00'}
|
|
28
28
|
fillRule="nonzero"
|
|
29
29
|
></path>
|
|
30
30
|
<path
|
|
@@ -3,7 +3,7 @@ import { SvgIconProps, SvgIcon } from '@mui/material';
|
|
|
3
3
|
|
|
4
4
|
const Home = (props: SvgIconProps) => {
|
|
5
5
|
return (
|
|
6
|
-
<SvgIcon viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
<SvgIcon viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" data-testid="home" {...props}>
|
|
7
7
|
<path
|
|
8
8
|
fillRule="evenodd"
|
|
9
9
|
clipRule="evenodd"
|
|
@@ -1,10 +1,60 @@
|
|
|
1
1
|
import { render, screen } from '@/test-utils/index';
|
|
2
|
-
import NsImage from '
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { NsImage } from '../';
|
|
3
|
+
|
|
4
|
+
describe('NsImage component', () => {
|
|
5
|
+
it('1. renders', () => {
|
|
6
|
+
const alt = 'test image';
|
|
7
|
+
render(<NsImage src="image.jpg" width={300} height={300} alt={alt} />);
|
|
8
|
+
const imgElement = screen.getByAltText(alt);
|
|
8
9
|
expect(imgElement).toBeInTheDocument();
|
|
9
10
|
});
|
|
11
|
+
|
|
12
|
+
it('2. renders with correct src and alt attributes', () => {
|
|
13
|
+
const src = 'image.jpg';
|
|
14
|
+
const alt = 'test image';
|
|
15
|
+
const { getByAltText } = render(<NsImage src={src} alt={alt} />);
|
|
16
|
+
const image = getByAltText(alt);
|
|
17
|
+
expect(image).toHaveAttribute('src', src);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('3. renders with width and height if variant is not provided', () => {
|
|
21
|
+
const { getByAltText } = render(<NsImage src="image.jpg" alt="test image" width={300} height={300} />);
|
|
22
|
+
const image = getByAltText('test image');
|
|
23
|
+
expect(image).toHaveAttribute('width', '300');
|
|
24
|
+
expect(image).toHaveAttribute('height', '300');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('4. renders with correct width and height based on variant', () => {
|
|
28
|
+
const { getByAltText } = render(<NsImage src="image.jpg" alt="test image" variant="icon" />);
|
|
29
|
+
const image = getByAltText('test image');
|
|
30
|
+
expect(image).toHaveAttribute('width', '60');
|
|
31
|
+
expect(image).toHaveAttribute('height', '60');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('5. renders with correct width and height if variant is "fill"', () => {
|
|
35
|
+
const { getByAltText } = render(<NsImage src="image.jpg" alt="test image" variant="fill" />);
|
|
36
|
+
const image = getByAltText('test image');
|
|
37
|
+
expect(image).toHaveAttribute('width', '100%');
|
|
38
|
+
expect(image).toHaveAttribute('height', 'auto');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('6. renders with correct width and height if variant is "award"', () => {
|
|
42
|
+
const { getByAltText } = render(<NsImage src="image.jpg" alt="test image" variant="award" />);
|
|
43
|
+
const image = getByAltText('test image');
|
|
44
|
+
expect(image).toHaveAttribute('width', '130');
|
|
45
|
+
expect(image).toHaveAttribute('height', '130');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('7. renders with correct width and height if variant is "product"', () => {
|
|
49
|
+
const { getByAltText } = render(<NsImage src="image.jpg" alt="test image" variant="product" />);
|
|
50
|
+
const image = getByAltText('test image');
|
|
51
|
+
expect(image).toHaveAttribute('width', '300');
|
|
52
|
+
expect(image).toHaveAttribute('height', '300');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('8. renders with additional props', () => {
|
|
56
|
+
const { getByAltText } = render(<NsImage src="image.jpg" alt="test image" className="custom-image" />);
|
|
57
|
+
const image = getByAltText('test image');
|
|
58
|
+
expect(image).toHaveClass('custom-image');
|
|
59
|
+
});
|
|
10
60
|
});
|
|
@@ -2,18 +2,30 @@ import { NsImageProps } from './types.d';
|
|
|
2
2
|
|
|
3
3
|
// eslint-disable-next-line no-unused-vars
|
|
4
4
|
const NsImage = ({ src, width, height, alt, variant, ...rest }: NsImageProps) => {
|
|
5
|
-
let cHeight
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
let cHeight, cWidth;
|
|
6
|
+
switch (variant) {
|
|
7
|
+
case 'product':
|
|
8
|
+
cHeight = 300;
|
|
9
|
+
cWidth = 300;
|
|
10
|
+
break;
|
|
11
|
+
case 'icon':
|
|
12
|
+
cHeight = 60;
|
|
13
|
+
cWidth = 60;
|
|
14
|
+
break;
|
|
15
|
+
case 'award':
|
|
16
|
+
cHeight = 130;
|
|
17
|
+
cWidth = 130;
|
|
18
|
+
break;
|
|
19
|
+
case 'fill':
|
|
20
|
+
cHeight = 'auto';
|
|
21
|
+
cWidth = '100%';
|
|
22
|
+
break;
|
|
23
|
+
default:
|
|
24
|
+
cHeight = height;
|
|
25
|
+
cWidth = width;
|
|
26
|
+
break;
|
|
15
27
|
}
|
|
16
28
|
// eslint-disable-next-line @next/next/no-img-element
|
|
17
|
-
return <img src={src} alt={alt} height={cHeight} width={cWidth} />;
|
|
29
|
+
return <img src={src} alt={alt} height={cHeight} width={cWidth} {...rest} />;
|
|
18
30
|
};
|
|
19
31
|
export default NsImage;
|
package/src/common/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export * from './accordion';
|
|
2
2
|
export * from './alert';
|
|
3
3
|
export * from './auth-dropdown';
|
|
4
|
-
export * from './autocomplete';
|
|
5
4
|
export * from './banner';
|
|
5
|
+
|
|
6
6
|
export * from './breadcrumb';
|
|
7
7
|
export * from './brand-components';
|
|
8
8
|
export * from './button';
|
|
@@ -13,16 +13,20 @@ export * from './column-control';
|
|
|
13
13
|
export * from './checkbox';
|
|
14
14
|
export * from './common.types.d';
|
|
15
15
|
export * from './dropdown';
|
|
16
|
+
export * from './email-simple';
|
|
16
17
|
export * from './flag';
|
|
18
|
+
export * from './hooks';
|
|
17
19
|
export * from './icon';
|
|
18
20
|
export * from './image';
|
|
19
21
|
export * from './input';
|
|
20
22
|
export * from './label';
|
|
21
23
|
export * from './link';
|
|
24
|
+
export * from './modal';
|
|
22
25
|
export * from './nav-tab';
|
|
23
26
|
export * from './nav-product-card';
|
|
27
|
+
export * from './radiogroup';
|
|
28
|
+
export * from './spinner';
|
|
24
29
|
export * from './text-strip';
|
|
25
30
|
export * from './table';
|
|
26
31
|
export * from './typography';
|
|
27
|
-
export * from './
|
|
28
|
-
export * from './radiogroup';
|
|
32
|
+
export * from './utility';
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import { Box } from '@mui/material';
|
|
2
|
-
import { styled, nuskinTheme } from '@nuskin/foundation-theme';
|
|
3
|
-
import {
|
|
2
|
+
import { styled, nuskinTheme, ColorUtils, FoundationTheme } from '@nuskin/foundation-theme';
|
|
3
|
+
import {fieldStateType} from './types.d';
|
|
4
4
|
|
|
5
|
+
const { isDarkMode } = ColorUtils;
|
|
5
6
|
const { colors } = nuskinTheme;
|
|
6
7
|
|
|
7
8
|
const options = {
|
|
8
9
|
shouldForwardProp: (propKey: string) => propKey !== 'fieldState',
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
const getInputBorderColor = (
|
|
12
|
+
const getInputBorderColor = (
|
|
13
|
+
palette: FoundationTheme.Theme['palette'],
|
|
14
|
+
fieldState: fieldStateType,
|
|
15
|
+
isLight = true
|
|
16
|
+
): string => {
|
|
12
17
|
if (fieldState === 'success') {
|
|
13
|
-
return
|
|
18
|
+
return colors.success[40];
|
|
14
19
|
} else if (fieldState === 'error') {
|
|
15
20
|
return isLight ? colors.red[40] : colors.red[20];
|
|
16
21
|
} else {
|
|
17
|
-
return palette
|
|
22
|
+
return palette?.primary.main ?? '';
|
|
18
23
|
}
|
|
19
24
|
};
|
|
20
25
|
|
|
@@ -28,7 +33,7 @@ const InputWrapper = styled(
|
|
|
28
33
|
)<InputWrapperType>(({ theme, fieldState }) => {
|
|
29
34
|
/* default value added so that unit tests do not fail */
|
|
30
35
|
const { palette = { primary: { main: '', contrastText: '' } } } = theme;
|
|
31
|
-
const isLight =
|
|
36
|
+
const isLight = isDarkMode({ theme });
|
|
32
37
|
const inputFocusedBorder = isLight ? colors.accentColorB[20] : colors.accentColorB[30];
|
|
33
38
|
const inputDisabledBg = isLight ? colors.neutral[30] : colors.neutral[70];
|
|
34
39
|
const inputDisabledBorder = isLight ? colors.neutral[60] : colors.neutral[80];
|
|
@@ -56,7 +61,7 @@ const InputWrapper = styled(
|
|
|
56
61
|
},
|
|
57
62
|
},
|
|
58
63
|
fieldset: {
|
|
59
|
-
border: `1px solid ${getInputBorderColor(palette
|
|
64
|
+
border: `1px solid ${getInputBorderColor(palette, fieldState, isLight)}`,
|
|
60
65
|
},
|
|
61
66
|
input: {
|
|
62
67
|
color: palette.primary.main,
|
|
@@ -55,7 +55,7 @@ const NsInputField = (props: NsInputFieldProps) => {
|
|
|
55
55
|
} = props;
|
|
56
56
|
/** EndIcon is created so that we can automatically add success and error icon based of fieldState,
|
|
57
57
|
* it will override iconEnd. Also to note, InputProps is given to override both iconStart, iconEnd and EndIcon */
|
|
58
|
-
|
|
58
|
+
const EndIcon: AdornmentPropsType = getAdornmentProps({ disabled, fieldState, iconEnd, iconStart });
|
|
59
59
|
|
|
60
60
|
return (
|
|
61
61
|
<InputFieldWrapper>
|
|
@@ -16,7 +16,6 @@ export const Default: Story = {
|
|
|
16
16
|
args: {
|
|
17
17
|
children: 'Label',
|
|
18
18
|
required: false,
|
|
19
|
-
size: 16,
|
|
20
19
|
},
|
|
21
20
|
};
|
|
22
21
|
|
|
@@ -24,7 +23,6 @@ export const Optional: Story = {
|
|
|
24
23
|
args: {
|
|
25
24
|
children: 'Label',
|
|
26
25
|
showOptional: true,
|
|
27
|
-
size: 16,
|
|
28
26
|
},
|
|
29
27
|
};
|
|
30
28
|
|
|
@@ -33,6 +31,5 @@ export const Required: Story = {
|
|
|
33
31
|
children: 'Label',
|
|
34
32
|
showOptional: true,
|
|
35
33
|
required: true,
|
|
36
|
-
size: 16,
|
|
37
34
|
},
|
|
38
35
|
};
|
|
@@ -27,7 +27,7 @@ const StyledLabel = styled(FormLabel)<{ fontSize?: number; style?: CSSProperties
|
|
|
27
27
|
const NsLabel = (props: NsLabelProps) => {
|
|
28
28
|
const { required, showOptional, children, size } = props;
|
|
29
29
|
return (
|
|
30
|
-
<StyledLabel
|
|
30
|
+
<StyledLabel fontSize={size} {...props} required={required}>
|
|
31
31
|
{children}
|
|
32
32
|
{!required && showOptional ? <span className="optional-label">{' (Optional)'}</span> : null}
|
|
33
33
|
</StyledLabel>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@/test-utils/index';
|
|
3
|
+
import NsModal from './NsModal';
|
|
4
|
+
import { NsModalData } from './stories/mock';
|
|
5
|
+
import { NsModalProps } from './types';
|
|
6
|
+
|
|
7
|
+
describe('NsModal', () => {
|
|
8
|
+
const onHandleClose = jest.fn();
|
|
9
|
+
|
|
10
|
+
const NsModalProp = NsModalData as NsModalProps;
|
|
11
|
+
|
|
12
|
+
test('1. check NsModal component open', () => {
|
|
13
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
14
|
+
expect(getByTestId('nsmodal-dialog')).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('2. should render NsModal default component', () => {
|
|
18
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
19
|
+
expect(getByTestId('modal-default')).toBeInTheDocument();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('3. should render NsModal status component', () => {
|
|
23
|
+
const VariantProps: NsModalProps = {
|
|
24
|
+
...NsModalProp,
|
|
25
|
+
variant: 'info',
|
|
26
|
+
};
|
|
27
|
+
const { getByTestId } = render(<NsModal {...VariantProps} handleClose={onHandleClose} />);
|
|
28
|
+
expect(getByTestId('modal-status')).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('4. should render NsModal title with close button', () => {
|
|
32
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
33
|
+
expect(getByTestId('modal-title')).toBeInTheDocument();
|
|
34
|
+
expect(getByTestId('modal-close-button')).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('5. should render NsModal body content', () => {
|
|
38
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
39
|
+
expect(getByTestId('modal-body-content')).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('6. should render NsModal footer', () => {
|
|
43
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
44
|
+
expect(getByTestId('modal-footer')).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
+
import { NsButton } from '../button';
|
|
3
|
+
import { DialogActions } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
export const NsInfoWrapper = styled.div`
|
|
6
|
+
display: flex;
|
|
7
|
+
.status-icon {
|
|
8
|
+
padding: 16px 0px 0px 24px;
|
|
9
|
+
}
|
|
10
|
+
.title-icon {
|
|
11
|
+
padding-right: 10px;
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
export const CloseButton = styled(NsButton)`
|
|
16
|
+
position: absolute;
|
|
17
|
+
right: 8px;
|
|
18
|
+
top: 8px;
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
export const ModalFooter = styled(DialogActions)`
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: space-around;
|
|
24
|
+
padding: 20px 0px 10px 0px;
|
|
25
|
+
button {
|
|
26
|
+
width: 100%;
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Dialog from '@mui/material/Dialog';
|
|
3
|
+
import { useMediaQuery } from '@mui/material';
|
|
4
|
+
import { useTheme } from '@mui/material/styles';
|
|
5
|
+
import { ModalVariantMap } from './model/NsModalVariantMap';
|
|
6
|
+
import { NsModalProps } from './types';
|
|
7
|
+
|
|
8
|
+
const NsModal = (props: NsModalProps) => {
|
|
9
|
+
const { open, handleClose, header, body, additionalProps, footer, statusInfo, variant = 'default' } = props;
|
|
10
|
+
|
|
11
|
+
const { className, scrollType = 'paper', ariaLabel } = additionalProps || {};
|
|
12
|
+
|
|
13
|
+
const { ariaLabelledby = 'alert-dialog-title', ariaDescribedby = 'alert-dialog-description' } = ariaLabel || {};
|
|
14
|
+
|
|
15
|
+
const theme = useTheme();
|
|
16
|
+
|
|
17
|
+
const fullScreen: boolean = useMediaQuery(theme.breakpoints.down('md'));
|
|
18
|
+
|
|
19
|
+
const Component = ModalVariantMap[variant];
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Dialog
|
|
23
|
+
data-testid="nsmodal-dialog"
|
|
24
|
+
fullScreen={fullScreen}
|
|
25
|
+
open={open}
|
|
26
|
+
scroll={scrollType}
|
|
27
|
+
onClose={handleClose}
|
|
28
|
+
aria-labelledby={ariaLabelledby}
|
|
29
|
+
aria-describedby={ariaDescribedby}
|
|
30
|
+
className={className}
|
|
31
|
+
>
|
|
32
|
+
<Component {...{ header, handleClose, body, footer, additionalProps, statusInfo, variant, open }} />
|
|
33
|
+
</Dialog>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default NsModal;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { DialogContent } from '@mui/material';
|
|
3
|
+
import { NsModalComponentProps } from '../types';
|
|
4
|
+
import NsModalTitle from './NsModalTitle';
|
|
5
|
+
import { NsTypography } from '../..';
|
|
6
|
+
|
|
7
|
+
const NsModalContentBox = ({ handleClose, statusInfo }: NsModalComponentProps) => {
|
|
8
|
+
const { title, description } = statusInfo || {};
|
|
9
|
+
|
|
10
|
+
const header = useMemo(() => {
|
|
11
|
+
return {
|
|
12
|
+
show: true,
|
|
13
|
+
children: (
|
|
14
|
+
<NsTypography variant="h5" weight="bold">
|
|
15
|
+
{title}
|
|
16
|
+
</NsTypography>
|
|
17
|
+
),
|
|
18
|
+
isCloseIcon: true,
|
|
19
|
+
};
|
|
20
|
+
}, [title]);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div>
|
|
24
|
+
<NsModalTitle header={header} handleClose={handleClose} />
|
|
25
|
+
<DialogContent>
|
|
26
|
+
<NsTypography variant="p-xs">{description}</NsTypography>
|
|
27
|
+
</DialogContent>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default NsModalContentBox;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DialogContent } from '@mui/material';
|
|
2
|
+
import NsModalTitle from './NsModalTitle';
|
|
3
|
+
import { NsModalComponentProps } from '../types';
|
|
4
|
+
import { ModalFooter } from '../NsModal.styled';
|
|
5
|
+
import { Show } from '../../utility';
|
|
6
|
+
|
|
7
|
+
const NsDefaultModal = ({ header, handleClose, body, footer, additionalProps }: NsModalComponentProps) => {
|
|
8
|
+
const { dividers } = additionalProps || {};
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div data-testid="modal-default">
|
|
12
|
+
<NsModalTitle header={header} handleClose={handleClose} />
|
|
13
|
+
<DialogContent dividers={dividers}>
|
|
14
|
+
<Show when={body?.show ?? false}>
|
|
15
|
+
<div data-testid="modal-body-content">{body?.children}</div>
|
|
16
|
+
</Show>
|
|
17
|
+
<Show when={footer?.show ?? false}>
|
|
18
|
+
<ModalFooter data-testid="modal-footer">{footer?.children}</ModalFooter>
|
|
19
|
+
</Show>
|
|
20
|
+
</DialogContent>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default NsDefaultModal;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NsInfoWrapper } from '../NsModal.styled';
|
|
2
|
+
import { NsModalComponentProps } from '../types';
|
|
3
|
+
import NsModalContentBox from './NsModalContentBox';
|
|
4
|
+
import NsModalStatusIcon from './NsModalStatusIcon';
|
|
5
|
+
|
|
6
|
+
const NsStatusModal = ({ handleClose, statusInfo, variant }: NsModalComponentProps) => {
|
|
7
|
+
return (
|
|
8
|
+
<NsInfoWrapper data-testid="modal-status">
|
|
9
|
+
<NsModalStatusIcon {...{ variant }} />
|
|
10
|
+
<NsModalContentBox {...{ handleClose, statusInfo }} />
|
|
11
|
+
</NsInfoWrapper>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default NsStatusModal;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NsIcon, NsIconNameType } from '../../';
|
|
2
|
+
import { StatusIconMap } from '../model/NsModalVariantMap';
|
|
3
|
+
import { NsModalComponentProps, NsModalVariant } from '../types';
|
|
4
|
+
|
|
5
|
+
const NsModalStatusIcon = ({ variant }: NsModalComponentProps) => {
|
|
6
|
+
const iconName = variant ? StatusIconMap[variant] : null;
|
|
7
|
+
return (
|
|
8
|
+
<div className="status-icon">
|
|
9
|
+
<NsIcon name={iconName as NsIconNameType} size="medium" color={variant as NsModalVariant} />
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default NsModalStatusIcon;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NsIcon } from '../..';
|
|
2
|
+
import { DialogTitle } from '@mui/material';
|
|
3
|
+
import { CloseButton, NsInfoWrapper } from '../NsModal.styled';
|
|
4
|
+
import { NsModalComponentProps } from '../types';
|
|
5
|
+
import { Show } from '../../utility';
|
|
6
|
+
|
|
7
|
+
const NsModalTitle = ({ header, handleClose }: NsModalComponentProps) => {
|
|
8
|
+
const { show, children, isCloseIcon, iconName } = header || {};
|
|
9
|
+
return (
|
|
10
|
+
<Show when={show}>
|
|
11
|
+
<DialogTitle data-testid="modal-title">
|
|
12
|
+
<NsInfoWrapper>
|
|
13
|
+
{iconName ? <NsIcon name={iconName} className="title-icon" /> : null}
|
|
14
|
+
{children}
|
|
15
|
+
</NsInfoWrapper>
|
|
16
|
+
<Show when={isCloseIcon}>
|
|
17
|
+
<CloseButton aria-label="close" onClick={handleClose} data-testid="modal-close-button">
|
|
18
|
+
<NsIcon name="close" size="small" />
|
|
19
|
+
</CloseButton>
|
|
20
|
+
</Show>
|
|
21
|
+
</DialogTitle>
|
|
22
|
+
</Show>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default NsModalTitle;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ElementType } from 'react';
|
|
2
|
+
import NsDefaultModal from '../helper-component/NsModalDefault';
|
|
3
|
+
import NsStatusModal from '../helper-component/NsModalStatus';
|
|
4
|
+
import { StatusIconMapProps } from '../types';
|
|
5
|
+
|
|
6
|
+
type ModalMapType = {
|
|
7
|
+
[key: string]: ElementType;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const ModalVariantMap: ModalMapType = {
|
|
11
|
+
default: NsDefaultModal,
|
|
12
|
+
confirmation: NsDefaultModal,
|
|
13
|
+
success: NsStatusModal,
|
|
14
|
+
warning: NsStatusModal,
|
|
15
|
+
error: NsStatusModal,
|
|
16
|
+
info: NsStatusModal,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const StatusIconMap: StatusIconMapProps = {
|
|
20
|
+
success: 'success',
|
|
21
|
+
warning: 'warning',
|
|
22
|
+
error: 'error',
|
|
23
|
+
info: 'infoFilled',
|
|
24
|
+
};
|