@nuskin/foundation-ui-components 1.0.0-cft-35.4 → 1.0.0-cft-35.5
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/CHANGELOG.md +12 -0
- package/package.json +6 -2
- package/src/common/brand-components/BrandComponent.tsx +7 -7
- package/src/common/brand-components/types.d.ts +2 -0
- package/src/common/button/Button.spec.tsx +5 -7
- package/src/common/button/Button.stories.tsx +2 -8
- package/src/common/card/NsBgCard.tsx +24 -0
- package/src/common/card/NsBrandLogo.tsx +16 -0
- package/src/common/card/NsBrandProductCard.tsx +47 -0
- package/src/common/card/NsBrandWrapper.tsx +26 -0
- package/src/common/card/index.ts +4 -0
- package/src/common/card/stories/NsBgCard.stories.tsx +19 -0
- package/src/common/card/stories/NsBrandProductCard.stories.tsx +18 -0
- package/src/common/card/stories/data.js +67 -0
- package/src/common/card/tests/BrandLogo.spec.tsx +13 -0
- package/src/common/card/tests/NsBgCard.spec.tsx +23 -0
- package/src/common/card/tests/NsBrandProductCard.spec.tsx +32 -0
- package/src/common/common.types.ts +0 -1
- package/src/common/link/NsLink.styled.tsx +5 -2
- package/src/common/nav-tab/NsNavTab.styled.tsx +3 -2
- package/src/common/nav-tab/NsNavTab.tsx +2 -1
- package/src/common/nav-tab/types.d.ts +2 -1
- package/src/common/slick/CarousalControl.tsx +44 -0
- package/src/common/slick/IconWrapper.tsx +32 -0
- package/src/common/slick/LeftChevron.tsx +34 -0
- package/src/common/slick/NsCarousal.tsx +51 -0
- package/src/common/slick/RenderBrand.tsx +18 -0
- package/src/common/slick/RightChevron.tsx +36 -0
- package/src/common/slick/index.ts +2 -0
- package/src/common/slick/slickSetting.ts +61 -0
- package/src/common/slick/stories/NSCarousal.stories.tsx +21 -0
- package/src/common/slick/tests/Chevron.spec.tsx +10 -0
- package/src/common/slick/tests/NsCarousal.spec.tsx +106 -0
- package/src/common/slick/tests/RenderBrand.spec.tsx +22 -0
- package/src/common/typography/Typography.styled.tsx +2 -1
- package/src/common/typography/types.d.ts +3 -1
- /package/src/common/brand-components/{BrandComponent.test.tsx → BrandComponent.spec.tsx} +0 -0
- /package/src/common/brand-components/icons/{Logo.test.tsx → Logo.spec.tsx} +0 -0
- /package/src/common/typography/{Typography.test.tsx → Typography.spec.tsx} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [1.0.0-cft-35.5](https://code.tls.nuskin.io/ns-am/content-foundation/foundation-ui-components/compare/v1.0.0-cft-35.4...v1.0.0-cft-35.5) (2023-03-29)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Fix
|
|
5
|
+
|
|
6
|
+
* Lint fixed ([929112c](https://code.tls.nuskin.io/ns-am/content-foundation/foundation-ui-components/commit/929112ce66e5e5e86dcf3a64ee50288cfe244e27))
|
|
7
|
+
|
|
8
|
+
### New
|
|
9
|
+
|
|
10
|
+
* adding card component for showing brands ([e5aad64](https://code.tls.nuskin.io/ns-am/content-foundation/foundation-ui-components/commit/e5aad64b0704f0054028d0eacc0ce603bbb814e4))
|
|
11
|
+
* Brand and Live Tag ([4913a03](https://code.tls.nuskin.io/ns-am/content-foundation/foundation-ui-components/commit/4913a031130fc28b3259038e6ab87d487690ac63))
|
|
12
|
+
|
|
1
13
|
# [1.0.0-cft-35.4](https://code.tls.nuskin.io/ns-am/content-foundation/foundation-ui-components/compare/v1.0.0-cft-35.3...v1.0.0-cft-35.4) (2023-03-28)
|
|
2
14
|
|
|
3
15
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuskin/foundation-ui-components",
|
|
3
|
-
"version": "1.0.0-cft-35.
|
|
3
|
+
"version": "1.0.0-cft-35.5",
|
|
4
4
|
"description": "It is a foundation library written in react, that provides commom components to all UI pages",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "src/common/index.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"build": "next build",
|
|
28
28
|
"start": "next start",
|
|
29
29
|
"lint": "next lint",
|
|
30
|
-
"storybook": "start-storybook -p
|
|
30
|
+
"storybook": "start-storybook -p 6007",
|
|
31
31
|
"test": "jest",
|
|
32
32
|
"test:coverage": "yarn test --coverage",
|
|
33
33
|
"test:watch": "jest --watch",
|
|
@@ -45,6 +45,9 @@
|
|
|
45
45
|
"next": "13.2.4",
|
|
46
46
|
"react": "18.2.0",
|
|
47
47
|
"react-dom": "18.2.0",
|
|
48
|
+
"react-material-ui-carousel": "^3.4.2",
|
|
49
|
+
"react-slick": "^0.29.0",
|
|
50
|
+
"slick-carousel": "^1.8.1",
|
|
48
51
|
"typescript": "4.9.5"
|
|
49
52
|
},
|
|
50
53
|
"devDependencies": {
|
|
@@ -68,6 +71,7 @@
|
|
|
68
71
|
"@types/node": "18.15.0",
|
|
69
72
|
"@types/react": "18.0.28",
|
|
70
73
|
"@types/react-dom": "18.0.11",
|
|
74
|
+
"@types/react-slick": "^0.23.10",
|
|
71
75
|
"@types/react-test-renderer": "^18.0.0",
|
|
72
76
|
"@types/testing-library__jest-dom": "^5.14.5",
|
|
73
77
|
"babel-jest": "^29.5.0",
|
|
@@ -8,18 +8,18 @@ import LogoContainer from './BrandContanier.styled';
|
|
|
8
8
|
import { BrandComponentProps } from './types';
|
|
9
9
|
|
|
10
10
|
const VariantMap = {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
stacked: NSLogoStacked,
|
|
12
|
+
horizontal: NSLogoHorizontal,
|
|
13
|
+
wordmark: NSLogoWordMark,
|
|
14
|
+
logomark: NSLogoMark,
|
|
15
|
+
poweredBy: NSLogoPoweredBy,
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
const BrandComponent = (props: PropsWithChildren<BrandComponentProps>) => {
|
|
19
|
-
const { variant = 'stacked', size = '108px' } = props;
|
|
19
|
+
const { variant = 'stacked', size = '108px', color = 'primary' } = props;
|
|
20
20
|
const renderBrand = useCallback(() => {
|
|
21
21
|
const BrandComponent = VariantMap[variant || 'stacked'];
|
|
22
|
-
return <BrandComponent color=
|
|
22
|
+
return <BrandComponent color={color as any} />;
|
|
23
23
|
}, [variant]);
|
|
24
24
|
return <LogoContainer size={size}>{renderBrand()}</LogoContainer>;
|
|
25
25
|
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { PaletteColorNames } from '@nuskin/foundation-theme/src/themes/types';
|
|
1
2
|
|
|
2
3
|
export type BrandComponentProps = {
|
|
3
4
|
variant?: 'stacked' | 'horizontal' | 'poweredBy' | 'logomark' | 'wordmark';
|
|
4
5
|
size?: string;
|
|
6
|
+
color?: PaletteColorNames;
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
export type SVGLogoProps = {
|
|
@@ -10,7 +10,7 @@ describe('<Button />', () => {
|
|
|
10
10
|
test('should render default button styles', () => {
|
|
11
11
|
render(
|
|
12
12
|
<Button color="primary" variant="contained">
|
|
13
|
-
|
|
13
|
+
Click Me
|
|
14
14
|
</Button>
|
|
15
15
|
);
|
|
16
16
|
|
|
@@ -25,7 +25,7 @@ describe('<Button />', () => {
|
|
|
25
25
|
test('should render default button styles', () => {
|
|
26
26
|
render(
|
|
27
27
|
<Button color="success" variant="contained" size="large">
|
|
28
|
-
|
|
28
|
+
Click Me
|
|
29
29
|
</Button>
|
|
30
30
|
);
|
|
31
31
|
|
|
@@ -40,7 +40,7 @@ describe('<Button />', () => {
|
|
|
40
40
|
test('should render outlined sucess button', () => {
|
|
41
41
|
render(
|
|
42
42
|
<Button color="success" variant="outlined" size="large">
|
|
43
|
-
|
|
43
|
+
Click Me
|
|
44
44
|
</Button>
|
|
45
45
|
);
|
|
46
46
|
|
|
@@ -55,7 +55,7 @@ describe('<Button />', () => {
|
|
|
55
55
|
test('should render outlined sucess button', () => {
|
|
56
56
|
render(
|
|
57
57
|
<Button color="accentColorA" variant="outlined" size="large">
|
|
58
|
-
|
|
58
|
+
Click Me
|
|
59
59
|
</Button>
|
|
60
60
|
);
|
|
61
61
|
|
|
@@ -63,9 +63,7 @@ describe('<Button />', () => {
|
|
|
63
63
|
|
|
64
64
|
expect(button).toBeInTheDocument();
|
|
65
65
|
expect(button).toHaveStyle(`color: ${palette?.accentColorA?.main}`);
|
|
66
|
-
expect(button).toHaveStyle(
|
|
67
|
-
`border-color: ${palette?.accentColorA?.main}`
|
|
68
|
-
);
|
|
66
|
+
expect(button).toHaveStyle(`border-color: ${palette?.accentColorA?.main}`);
|
|
69
67
|
});
|
|
70
68
|
});
|
|
71
69
|
});
|
|
@@ -6,11 +6,7 @@ import { ShoppingCart } from '@mui/icons-material';
|
|
|
6
6
|
export default {
|
|
7
7
|
title: 'Components/Button',
|
|
8
8
|
component: Button,
|
|
9
|
-
decorators: [
|
|
10
|
-
(story) => (
|
|
11
|
-
<div style={{ textAlign: 'center', marginTop: '20px' }}>{story()}</div>
|
|
12
|
-
),
|
|
13
|
-
],
|
|
9
|
+
decorators: [(story) => <div style={{ textAlign: 'center', marginTop: '20px' }}>{story()}</div>],
|
|
14
10
|
argTypes: {
|
|
15
11
|
children: {
|
|
16
12
|
control: 'text',
|
|
@@ -32,9 +28,7 @@ export default {
|
|
|
32
28
|
},
|
|
33
29
|
} as ComponentMeta<typeof Button>;
|
|
34
30
|
|
|
35
|
-
export const button: ComponentStory<typeof Button> = (args) =>
|
|
36
|
-
<Button {...args} />
|
|
37
|
-
);
|
|
31
|
+
export const button: ComponentStory<typeof Button> = (args) => <Button {...args} />;
|
|
38
32
|
|
|
39
33
|
export const IconOnlyButton: ComponentStory<typeof Button> = (args) => (
|
|
40
34
|
<Button {...args} iconOnly>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Card from '@mui/material/Card';
|
|
2
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
3
|
+
|
|
4
|
+
type NsBgCardProps = {
|
|
5
|
+
backgroundImageUrl: string;
|
|
6
|
+
};
|
|
7
|
+
const options = {
|
|
8
|
+
shouldForwardProp: (propKey: string) => propKey !== 'backgroundImageUrl',
|
|
9
|
+
};
|
|
10
|
+
const Component = ({ backgroundImageUrl }: NsBgCardProps) => {
|
|
11
|
+
const width = 256;
|
|
12
|
+
return {
|
|
13
|
+
backgroundImage: `url("${backgroundImageUrl}")`,
|
|
14
|
+
backgroundSize: 'cover',
|
|
15
|
+
backgroundPosition: 'center',
|
|
16
|
+
height: width * 1.2,
|
|
17
|
+
width,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/*
|
|
21
|
+
This styled component shows the background image on a card
|
|
22
|
+
*/
|
|
23
|
+
const NsBgCard = styled(Card, options)<NsBgCardProps>(Component);
|
|
24
|
+
export default NsBgCard;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import CardMedia from '@mui/material/CardMedia';
|
|
2
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
3
|
+
|
|
4
|
+
const NsBrandLogo = styled(CardMedia)<{
|
|
5
|
+
component: 'img';
|
|
6
|
+
}>({
|
|
7
|
+
width: 'auto',
|
|
8
|
+
height: 'auto',
|
|
9
|
+
maxWidth: '80%',
|
|
10
|
+
maxHeight: '80%',
|
|
11
|
+
display: 'flex',
|
|
12
|
+
alignItems: 'center',
|
|
13
|
+
justifyContent: 'center',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export default NsBrandLogo;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import Box from '@mui/material/Box';
|
|
2
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
3
|
+
import { Typography } from '../index';
|
|
4
|
+
import NsBrandWrapper from './NsBrandWrapper';
|
|
5
|
+
import NsBrandLogo from './NsBrandLogo';
|
|
6
|
+
import NsBgCard from './NsBgCard';
|
|
7
|
+
|
|
8
|
+
type NsBrandProductCardProps = {
|
|
9
|
+
title?: string;
|
|
10
|
+
brandImageUrl: string;
|
|
11
|
+
backgroundImageUrl: string;
|
|
12
|
+
};
|
|
13
|
+
const CardContainer = styled(Box)(() => {
|
|
14
|
+
return {
|
|
15
|
+
width: '256px',
|
|
16
|
+
display: 'flex',
|
|
17
|
+
alignItems: 'start',
|
|
18
|
+
justifyContent: 'center',
|
|
19
|
+
position: 'relative',
|
|
20
|
+
flexDirection: 'column',
|
|
21
|
+
'.brand-title': {
|
|
22
|
+
marginTop: '20px',
|
|
23
|
+
fontSize: '20px',
|
|
24
|
+
},
|
|
25
|
+
':hover': {
|
|
26
|
+
'.brand-title': {
|
|
27
|
+
opacity: '0.7',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
export default function NsBrandProductCard({ title, brandImageUrl, backgroundImageUrl }: NsBrandProductCardProps) {
|
|
33
|
+
return (
|
|
34
|
+
<CardContainer role="brand-card" component="div" data-testid="brand-product-card">
|
|
35
|
+
<NsBgCard backgroundImageUrl={backgroundImageUrl}>
|
|
36
|
+
<NsBrandWrapper>
|
|
37
|
+
<NsBrandLogo component="img" image={brandImageUrl} />
|
|
38
|
+
</NsBrandWrapper>
|
|
39
|
+
</NsBgCard>
|
|
40
|
+
{title ? (
|
|
41
|
+
<Typography variant="h3" className="brand-title">
|
|
42
|
+
{title}
|
|
43
|
+
</Typography>
|
|
44
|
+
) : null}
|
|
45
|
+
</CardContainer>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Box from '@mui/material/Box';
|
|
2
|
+
import { PropsWithChildren } from 'react';
|
|
3
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
4
|
+
|
|
5
|
+
const Wrapper = styled(Box)(() => {
|
|
6
|
+
return {
|
|
7
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
8
|
+
width: '100%',
|
|
9
|
+
height: '100%',
|
|
10
|
+
zIndex: 100,
|
|
11
|
+
display: 'flex',
|
|
12
|
+
flexDirection: 'column',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
justifyContent: 'center',
|
|
15
|
+
'&:hover': {
|
|
16
|
+
backgroundColor: 'rgba(0, 0, 0, 0)',
|
|
17
|
+
'& img': {
|
|
18
|
+
visibility: 'hidden',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export default function NsBrandWrapper({ children }: PropsWithChildren) {
|
|
25
|
+
return <Wrapper className="logo-wrapper">{children}</Wrapper>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
2
|
+
import NsBgCard from '../NsBgCard';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
component: NsBgCard,
|
|
6
|
+
title: 'Components/Card/NsBgCard',
|
|
7
|
+
argTypes: {},
|
|
8
|
+
decorators: [(story) => <div style={{ textAlign: 'center', marginTop: '20px' }}>{story()}</div>],
|
|
9
|
+
} as ComponentMeta<typeof NsBgCard>;
|
|
10
|
+
|
|
11
|
+
const Template: ComponentStory<typeof NsBgCard> = (args: any) => <NsBgCard {...args} />;
|
|
12
|
+
|
|
13
|
+
export const Default = Template.bind({});
|
|
14
|
+
Default.args = {
|
|
15
|
+
title: 'ageLOC LumiSpa',
|
|
16
|
+
backgroundImageUrl: 'https://media.nuskin.com/m/3604b5202b0b64c6/webimage-brand-lumispa-optweb.png',
|
|
17
|
+
// brandImageUrl:
|
|
18
|
+
// 'https://media.nuskin.com/m/2571a0407433a6e8/webimage-brand-lumispa.png',
|
|
19
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
2
|
+
import NsBrandProductCard from '../NsBrandProductCard';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
component: NsBrandProductCard,
|
|
6
|
+
title: 'Components/Card/NsBrandProductCard',
|
|
7
|
+
argTypes: {},
|
|
8
|
+
decorators: [(story) => <div style={{ textAlign: 'center', marginTop: '20px' }}>{story()}</div>],
|
|
9
|
+
} as ComponentMeta<typeof NsBrandProductCard>;
|
|
10
|
+
|
|
11
|
+
const Template: ComponentStory<typeof NsBrandProductCard> = (args: any) => <NsBrandProductCard {...args} />;
|
|
12
|
+
|
|
13
|
+
export const Default = Template.bind({});
|
|
14
|
+
Default.args = {
|
|
15
|
+
title: 'ageLOC LumiSpa',
|
|
16
|
+
backgroundImageUrl: 'https://media.nuskin.com/m/3604b5202b0b64c6/webimage-brand-lumispa-optweb.png',
|
|
17
|
+
brandImageUrl: 'https://media.nuskin.com/m/2571a0407433a6e8/webimage-brand-lumispa.png',
|
|
18
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export const brandImages = [
|
|
2
|
+
'https://media.nuskin.com/m/63a454ff90d038b4/webimage-brand-epoch.png',
|
|
3
|
+
'https://media.nuskin.com/m/3eb406f465d4b0fe/webimage-brand-sunright.png',
|
|
4
|
+
'https://media.nuskin.com/m/2d3276518912283b/webimage-brand-nu_colour.png',
|
|
5
|
+
'https://media.nuskin.com/m/3855d3836d920639/webimage-brand-nuskin180.png',
|
|
6
|
+
'https://media.nuskin.com/m/6245528b8f76ad32/webimage-brand-ageLOC.png',
|
|
7
|
+
'https://media.nuskin.com/m/2571a0407433a6e8/webimage-brand-lumispa.png',
|
|
8
|
+
'https://media.nuskin.com/m/4bd7ab9b46bd456d/webimage-brand-pharmanex.png',
|
|
9
|
+
'https://media.nuskin.com/m/501d638a8af80087/webimage-brand-ap24.png',
|
|
10
|
+
'https://media.nuskin.com/m/f3a91129cbbae32/webimage-brand-nutricentials.png',
|
|
11
|
+
'https://media.nuskin.com/m/63a454ff90d038b4/webimage-brand-epoch.png',
|
|
12
|
+
'https://media.nuskin.com/m/3eb406f465d4b0fe/webimage-brand-sunright.png',
|
|
13
|
+
'https://media.nuskin.com/m/2d3276518912283b/webimage-brand-nu_colour.png',
|
|
14
|
+
'https://media.nuskin.com/m/3855d3836d920639/webimage-brand-nuskin180.png',
|
|
15
|
+
'https://media.nuskin.com/m/6245528b8f76ad32/webimage-brand-ageLOC.png',
|
|
16
|
+
'https://media.nuskin.com/m/2571a0407433a6e8/webimage-brand-lumispa.png',
|
|
17
|
+
'https://media.nuskin.com/m/4bd7ab9b46bd456d/webimage-brand-pharmanex.png',
|
|
18
|
+
'https://media.nuskin.com/m/501d638a8af80087/webimage-brand-ap24.png',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export const brandBackImages = [
|
|
22
|
+
'https://media.nuskin.com/m/549aa3e5184434d8/webimage-brand-epoch-optweb.png',
|
|
23
|
+
'https://media.nuskin.com/m/14e238d7599e1811/webimage-brand-sunright.png',
|
|
24
|
+
'https://media.nuskin.com/m/2543e79419276727/webimage-brand-nu_colour-optweb.png',
|
|
25
|
+
'https://media.nuskin.com/m/446c7a2aad513f58/webimage-brand-nu_skin_180-optweb.png',
|
|
26
|
+
'https://media.nuskin.com/m/42911c8b05600476/webimage-brand-ageloc-optweb.png',
|
|
27
|
+
'https://media.nuskin.com/m/3604b5202b0b64c6/webimage-brand-lumispa-optweb.png',
|
|
28
|
+
'https://media.nuskin.com/m/4a1245a63c595262/webimage-brand-pharmanex-optweb.png',
|
|
29
|
+
'https://media.nuskin.com/m/14a0fd6ef63e5dbb/webimage-brand-ap_24.png',
|
|
30
|
+
'https://media.nuskin.com/m/298104036e885b40/webimage-brand-nutricentials.png',
|
|
31
|
+
'https://media.nuskin.com/m/549aa3e5184434d8/webimage-brand-epoch-optweb.png',
|
|
32
|
+
'https://media.nuskin.com/m/14e238d7599e1811/webimage-brand-sunright.png',
|
|
33
|
+
'https://media.nuskin.com/m/2543e79419276727/webimage-brand-nu_colour-optweb.png',
|
|
34
|
+
'https://media.nuskin.com/m/446c7a2aad513f58/webimage-brand-nu_skin_180-optweb.png',
|
|
35
|
+
'https://media.nuskin.com/m/42911c8b05600476/webimage-brand-ageloc-optweb.png',
|
|
36
|
+
'https://media.nuskin.com/m/3604b5202b0b64c6/webimage-brand-lumispa-optweb.png',
|
|
37
|
+
'https://media.nuskin.com/m/4a1245a63c595262/webimage-brand-pharmanex-optweb.png',
|
|
38
|
+
'https://media.nuskin.com/m/14a0fd6ef63e5dbb/webimage-brand-ap_24.png',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export const brandTitles = [
|
|
42
|
+
'Epoch',
|
|
43
|
+
'Sunright',
|
|
44
|
+
'Nu Colour',
|
|
45
|
+
'180 System',
|
|
46
|
+
'ageLOC',
|
|
47
|
+
'ageLOC LumiSpa',
|
|
48
|
+
'Pharmanex',
|
|
49
|
+
'AP 24',
|
|
50
|
+
'Nutricentials',
|
|
51
|
+
'Epoch',
|
|
52
|
+
'Sunright',
|
|
53
|
+
'Nu Colour',
|
|
54
|
+
'180 System',
|
|
55
|
+
'ageLOC',
|
|
56
|
+
'ageLOC LumiSpa',
|
|
57
|
+
'Pharmanex',
|
|
58
|
+
'AP 24',
|
|
59
|
+
];
|
|
60
|
+
export const brandEntries = brandTitles.map((title, index) => {
|
|
61
|
+
return {
|
|
62
|
+
title,
|
|
63
|
+
backgroundImage: brandBackImages[index],
|
|
64
|
+
brandImage: brandImages[index],
|
|
65
|
+
id: index,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import NsBrandLogo from '../NsBrandLogo';
|
|
3
|
+
|
|
4
|
+
describe('BrandLogo component', () => {
|
|
5
|
+
it('renders with cover size', () => {
|
|
6
|
+
const { container } = render(<NsBrandLogo component="img" />);
|
|
7
|
+
const cardElement = container.querySelector('img');
|
|
8
|
+
expect(cardElement).toHaveStyle(`
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
`);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import NsBgCard from '../NsBgCard';
|
|
3
|
+
|
|
4
|
+
describe('NsBgCard component', () => {
|
|
5
|
+
const props = {
|
|
6
|
+
backgroundImageUrl: 'https://media.nuskin.com/m/6245528b8f76ad32/webimage-brand-ageLOC.png',
|
|
7
|
+
};
|
|
8
|
+
it('renders with background image', () => {
|
|
9
|
+
const { container } = render(<NsBgCard {...props} />);
|
|
10
|
+
const cardElement = container.querySelector('div');
|
|
11
|
+
expect(cardElement).toHaveStyle(`
|
|
12
|
+
background-image: url(${props.backgroundImageUrl});
|
|
13
|
+
`);
|
|
14
|
+
});
|
|
15
|
+
it('renders with cover size', () => {
|
|
16
|
+
const { container } = render(<NsBgCard {...props} />);
|
|
17
|
+
const cardElement = container.querySelector('div');
|
|
18
|
+
expect(cardElement).toHaveStyle(`
|
|
19
|
+
background-size: cover;
|
|
20
|
+
background-position: center;
|
|
21
|
+
`);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import NsBrandProductCard from '../NsBrandProductCard';
|
|
3
|
+
|
|
4
|
+
describe('NSBgCard component', () => {
|
|
5
|
+
const props = {
|
|
6
|
+
title: 'Nutricentials',
|
|
7
|
+
brandImageUrl: 'https://media.nuskin.com/m/f3a91129cbbae32/webimage-brand-nutricentials.png',
|
|
8
|
+
backgroundImageUrl: 'https://media.nuskin.com/m/298104036e885b40/webimage-brand-nutricentials.png',
|
|
9
|
+
};
|
|
10
|
+
it('render brand image', () => {
|
|
11
|
+
const { container } = render(<NsBrandProductCard {...props} />);
|
|
12
|
+
const img = container.querySelector('img');
|
|
13
|
+
expect(img).toHaveAttribute('src', props.brandImageUrl);
|
|
14
|
+
});
|
|
15
|
+
it('render background image', () => {
|
|
16
|
+
const { container } = render(<NsBrandProductCard {...props} />);
|
|
17
|
+
const card = container.querySelector('div.MuiPaper-root');
|
|
18
|
+
expect(card).toHaveStyle(`
|
|
19
|
+
background-image: url(${props.backgroundImageUrl});
|
|
20
|
+
`);
|
|
21
|
+
});
|
|
22
|
+
it('renders title', () => {
|
|
23
|
+
const { getByText } = render(<NsBrandProductCard {...props} />);
|
|
24
|
+
const cardElement = getByText(props.title);
|
|
25
|
+
expect(cardElement).toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
it('does not render title, when title is not passed', () => {
|
|
28
|
+
const { container } = render(<NsBrandProductCard {...{ ...props, title: undefined }} />);
|
|
29
|
+
const cardElement = container.querySelector('.brand-title');
|
|
30
|
+
expect(cardElement).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -53,13 +53,16 @@ const getLinkStyles = ({ disabled, $underlineOnHover = true }: StyledProps) => {
|
|
|
53
53
|
}
|
|
54
54
|
return '';
|
|
55
55
|
};
|
|
56
|
+
const options = {
|
|
57
|
+
shouldForwardProp: (propKey: string) => propKey !== '$underlineOnHover',
|
|
58
|
+
};
|
|
56
59
|
|
|
57
|
-
export const StyledNextLink = styled(NextLink)<StyledProps>`
|
|
60
|
+
export const StyledNextLink = styled(NextLink, options)<StyledProps>`
|
|
58
61
|
${linkDefaultStyles};
|
|
59
62
|
${getLinkStyles}
|
|
60
63
|
`;
|
|
61
64
|
|
|
62
|
-
export const StyledLink = styled(MUILink)<StyledProps>`
|
|
65
|
+
export const StyledLink = styled(MUILink, options)<StyledProps>`
|
|
63
66
|
${linkDefaultStyles};
|
|
64
67
|
${getLinkStyles}
|
|
65
68
|
`;
|
|
@@ -3,6 +3,7 @@ import { PaletteColorNames } from '@nuskin/foundation-theme/src/themes/types';
|
|
|
3
3
|
import { motion } from 'framer-motion';
|
|
4
4
|
|
|
5
5
|
export const NavTabContainer = styled.div`
|
|
6
|
+
|
|
6
7
|
.shadow {
|
|
7
8
|
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.15);
|
|
8
9
|
}
|
|
@@ -38,7 +39,7 @@ export const NavDrawer = styled.div`
|
|
|
38
39
|
width: 100%;
|
|
39
40
|
max-height: 590px;
|
|
40
41
|
|
|
41
|
-
background-color:
|
|
42
|
+
background-color: ${({ theme }) => theme?.palette?.primary.contrastText};
|
|
42
43
|
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.15);
|
|
43
44
|
transition: all 0.15s ease-in-out;
|
|
44
45
|
overflow: hidden;
|
|
@@ -55,7 +56,7 @@ export const NavDrawerContainer = styled(motion.div)`
|
|
|
55
56
|
z-index: 1;
|
|
56
57
|
}
|
|
57
58
|
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.15);
|
|
58
|
-
background-color:
|
|
59
|
+
background-color: ${({ theme }) => theme?.palette?.primary.contrastText};
|
|
59
60
|
width: 100%;
|
|
60
61
|
text-align: left;
|
|
61
62
|
max-height: 590px;
|
|
@@ -40,7 +40,8 @@ export const NsNavTabComponent = (props: PropsWithChildren<NSNavTabComponentProp
|
|
|
40
40
|
>
|
|
41
41
|
<Typography
|
|
42
42
|
variant={tab.textVariant}
|
|
43
|
-
|
|
43
|
+
additionalProps={{ ...tab?.liveTag }}
|
|
44
|
+
className={`mb-2 ${tabTitleClassName} ${!active ? 'opacity-8' : ''}`}
|
|
44
45
|
color={tab.tabName === active ? tab.activeColor : tab.color}
|
|
45
46
|
>
|
|
46
47
|
{tab.tabName}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { PaletteColorNames } from '@nuskin/foundation-theme/src/themes/types';
|
|
3
3
|
import { Variants } from '../typography/types';
|
|
4
|
-
import { AdditionalProps } from '../common.types';
|
|
4
|
+
import { AdditionalProps, ContentStackLiveTags } from '../common.types';
|
|
5
5
|
|
|
6
6
|
export type NavTabs = {
|
|
7
7
|
tabName: string;
|
|
@@ -9,6 +9,7 @@ export type NavTabs = {
|
|
|
9
9
|
activeColor: PaletteColorNames;
|
|
10
10
|
color?: PaletteColorNames;
|
|
11
11
|
textVariant: Variants;
|
|
12
|
+
liveTag?: ContentStackLiveTags;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export type NSNavTabComponentProps = {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
+
import LeftChevron from './LeftChevron';
|
|
3
|
+
import IconWrapper from './IconWrapper';
|
|
4
|
+
import RightChevron from './RightChevron';
|
|
5
|
+
import { Typography } from '../';
|
|
6
|
+
import Link from 'next/link';
|
|
7
|
+
interface CarousalControlProps {
|
|
8
|
+
next(): void;
|
|
9
|
+
prev(): void;
|
|
10
|
+
viewAllUrl: string;
|
|
11
|
+
}
|
|
12
|
+
/*
|
|
13
|
+
This component is visible over the carousal and it has prev and next buttons and view all link
|
|
14
|
+
*/
|
|
15
|
+
const Wrapper = styled.div`
|
|
16
|
+
display: flex;
|
|
17
|
+
justify-content: flex-end;
|
|
18
|
+
padding: 0 30px;
|
|
19
|
+
margin: 10px 20px;
|
|
20
|
+
`;
|
|
21
|
+
const InnerWrapper = styled.div`
|
|
22
|
+
display: flex;
|
|
23
|
+
width: 220px;
|
|
24
|
+
gap: 20px;
|
|
25
|
+
align-items: center;
|
|
26
|
+
`;
|
|
27
|
+
const CarousalControl = ({ next, prev, viewAllUrl }: CarousalControlProps) => {
|
|
28
|
+
return (
|
|
29
|
+
<Wrapper>
|
|
30
|
+
<InnerWrapper>
|
|
31
|
+
<Link href={viewAllUrl}>
|
|
32
|
+
<Typography variant={'h5'}>View All</Typography>
|
|
33
|
+
</Link>
|
|
34
|
+
<IconWrapper onClick={prev} className="carousal-prev-button">
|
|
35
|
+
<LeftChevron />
|
|
36
|
+
</IconWrapper>
|
|
37
|
+
<IconWrapper onClick={next} className="carousal-next-button">
|
|
38
|
+
<RightChevron />
|
|
39
|
+
</IconWrapper>
|
|
40
|
+
</InnerWrapper>
|
|
41
|
+
</Wrapper>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
export default CarousalControl;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
3
|
+
import { Box } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
type IconWrapperProps = PropsWithChildren<{
|
|
6
|
+
onClick(): void;
|
|
7
|
+
className?: string;
|
|
8
|
+
}>;
|
|
9
|
+
const options = {};
|
|
10
|
+
const Wrapper = styled(
|
|
11
|
+
Box,
|
|
12
|
+
options
|
|
13
|
+
)(({ theme }) => {
|
|
14
|
+
const strokeColor = theme.palette?.primary?.main ?? '#252525';
|
|
15
|
+
return {
|
|
16
|
+
display: 'flex',
|
|
17
|
+
height: '20px',
|
|
18
|
+
width: '20px',
|
|
19
|
+
border: `2px solid ${strokeColor}`,
|
|
20
|
+
borderRadius: '3px',
|
|
21
|
+
cursor: 'pointer',
|
|
22
|
+
padding: '10px',
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
const IconWrapper = ({ children, onClick, className }: IconWrapperProps) => {
|
|
26
|
+
return (
|
|
27
|
+
<Wrapper component="span" className={className || ''} onClick={onClick}>
|
|
28
|
+
{children}
|
|
29
|
+
</Wrapper>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
export default IconWrapper;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useTheme } from '@mui/material/styles';
|
|
2
|
+
|
|
3
|
+
const LeftChevron = () => {
|
|
4
|
+
const { palette } = useTheme();
|
|
5
|
+
const strokeColor = palette.primary.main;
|
|
6
|
+
return (
|
|
7
|
+
<svg
|
|
8
|
+
data-testid="prev-chevron"
|
|
9
|
+
viewBox="0 0 24 24"
|
|
10
|
+
preserveAspectRatio="xMidYMid meet"
|
|
11
|
+
focusable="false"
|
|
12
|
+
style={{ pointerEvents: 'none', display: 'block' }}
|
|
13
|
+
>
|
|
14
|
+
<g
|
|
15
|
+
id="icon-narrow-angle-left-24"
|
|
16
|
+
stroke="none"
|
|
17
|
+
strokeWidth="1"
|
|
18
|
+
fill="none"
|
|
19
|
+
fillRule="evenodd"
|
|
20
|
+
strokeLinecap="round"
|
|
21
|
+
strokeLinejoin="round"
|
|
22
|
+
>
|
|
23
|
+
<g transform="translate(-196, -226)" stroke={strokeColor}>
|
|
24
|
+
<polyline
|
|
25
|
+
// eslint-disable-next-line max-len
|
|
26
|
+
transform="translate(209.000000, 237.500000) scale(-1.2, 1.2) rotate(90.000000) translate(-209.000000, -237.500000)"
|
|
27
|
+
points="200 242 209 233 218 242"
|
|
28
|
+
></polyline>
|
|
29
|
+
</g>
|
|
30
|
+
</g>
|
|
31
|
+
</svg>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
export default LeftChevron;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Box from '@mui/material/Box';
|
|
2
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
3
|
+
import { useRef, useCallback, ReactNode } from 'react';
|
|
4
|
+
import Slider from 'react-slick';
|
|
5
|
+
import 'slick-carousel/slick/slick.css';
|
|
6
|
+
import 'slick-carousel/slick/slick-theme.css';
|
|
7
|
+
import defaultCarousalSettings from './slickSetting';
|
|
8
|
+
import CarousalControl from './CarousalControl';
|
|
9
|
+
|
|
10
|
+
const SlickContainer = styled(Box)(() => {
|
|
11
|
+
return {
|
|
12
|
+
padding: '20px 0 50px',
|
|
13
|
+
'.slick-slide': {
|
|
14
|
+
display: 'flex',
|
|
15
|
+
justifyContent: 'center',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
interface CarousalProps<T = any> {
|
|
20
|
+
entries: T[];
|
|
21
|
+
// eslint-disable-next-line no-unused-vars
|
|
22
|
+
renderEntry(entry: T, index: number): ReactNode;
|
|
23
|
+
allEntryLink: string;
|
|
24
|
+
settings: any;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default function NsCarousal({ entries, renderEntry, allEntryLink, settings }: CarousalProps) {
|
|
28
|
+
const sliderRef = useRef();
|
|
29
|
+
const prev = useCallback(() => {
|
|
30
|
+
if (sliderRef.current) {
|
|
31
|
+
const slider = sliderRef.current as any;
|
|
32
|
+
slider.slickPrev();
|
|
33
|
+
}
|
|
34
|
+
}, [sliderRef]);
|
|
35
|
+
const next = useCallback(() => {
|
|
36
|
+
if (sliderRef.current) {
|
|
37
|
+
const slider = sliderRef.current as any;
|
|
38
|
+
slider.slickNext();
|
|
39
|
+
}
|
|
40
|
+
}, [sliderRef]);
|
|
41
|
+
return (
|
|
42
|
+
<SlickContainer className="brand-carousal">
|
|
43
|
+
<CarousalControl prev={prev} next={next} viewAllUrl={allEntryLink} />
|
|
44
|
+
<Slider {...{ ...defaultCarousalSettings, ...settings }} ref={sliderRef as any}>
|
|
45
|
+
{entries.map((entry, index) => {
|
|
46
|
+
return renderEntry(entry, index);
|
|
47
|
+
})}
|
|
48
|
+
</Slider>
|
|
49
|
+
</SlickContainer>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import NsBrandProductCard from '../card/NsBrandProductCard';
|
|
2
|
+
|
|
3
|
+
interface BrandType {
|
|
4
|
+
title: string;
|
|
5
|
+
backgroundImage: string;
|
|
6
|
+
brandImage: string;
|
|
7
|
+
}
|
|
8
|
+
export const RenderBrand = (entry: BrandType, index: number) => {
|
|
9
|
+
const { title, backgroundImage, brandImage } = entry;
|
|
10
|
+
return (
|
|
11
|
+
<NsBrandProductCard
|
|
12
|
+
key={title + index}
|
|
13
|
+
backgroundImageUrl={backgroundImage}
|
|
14
|
+
title={title}
|
|
15
|
+
brandImageUrl={brandImage}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useTheme } from '@mui/material/styles';
|
|
2
|
+
|
|
3
|
+
export const RightChevron = () => {
|
|
4
|
+
const { palette } = useTheme();
|
|
5
|
+
const strokeColor = palette.primary.main;
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<svg
|
|
9
|
+
data-testid="next-chevron"
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
preserveAspectRatio="xMidYMid meet"
|
|
12
|
+
focusable="false"
|
|
13
|
+
style={{ pointerEvents: 'none', display: 'block' }}
|
|
14
|
+
>
|
|
15
|
+
<g
|
|
16
|
+
id="icon-narrow-angle-right-24"
|
|
17
|
+
stroke="none"
|
|
18
|
+
strokeWidth="1"
|
|
19
|
+
fill="none"
|
|
20
|
+
fillRule="evenodd"
|
|
21
|
+
strokeLinecap="round"
|
|
22
|
+
strokeLinejoin="round"
|
|
23
|
+
>
|
|
24
|
+
<g transform="translate(-196, -226)" stroke={strokeColor}>
|
|
25
|
+
<polyline
|
|
26
|
+
// eslint-disable-next-line max-len
|
|
27
|
+
transform="translate(209.000000, 237.500000) scale(-1.2, 1.2) rotate(-90.000000) translate(-209.000000, -237.500000)"
|
|
28
|
+
points="200 242 209 233 218 242"
|
|
29
|
+
></polyline>
|
|
30
|
+
</g>
|
|
31
|
+
</g>
|
|
32
|
+
</svg>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default RightChevron;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const settings = {
|
|
2
|
+
dots: true,
|
|
3
|
+
infinite: false,
|
|
4
|
+
speed: 2000,
|
|
5
|
+
slidesToShow: 6,
|
|
6
|
+
slidesToScroll: 1,
|
|
7
|
+
swipeToSlide: true,
|
|
8
|
+
responsive: [
|
|
9
|
+
{
|
|
10
|
+
breakpoint: 1800,
|
|
11
|
+
settings: {
|
|
12
|
+
slidesToShow: 5,
|
|
13
|
+
slidesToScroll: 1,
|
|
14
|
+
infinite: true,
|
|
15
|
+
dots: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
breakpoint: 1480,
|
|
20
|
+
settings: {
|
|
21
|
+
slidesToShow: 4,
|
|
22
|
+
slidesToScroll: 1,
|
|
23
|
+
infinite: true,
|
|
24
|
+
dots: true,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
breakpoint: 1160,
|
|
29
|
+
settings: {
|
|
30
|
+
slidesToShow: 3,
|
|
31
|
+
slidesToScroll: 1,
|
|
32
|
+
infinite: true,
|
|
33
|
+
dots: true,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
breakpoint: 840,
|
|
38
|
+
settings: {
|
|
39
|
+
slidesToShow: 2,
|
|
40
|
+
slidesToScroll: 1,
|
|
41
|
+
initialSlide: 1,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
breakpoint: 580,
|
|
46
|
+
settings: {
|
|
47
|
+
slidesToShow: 1.5,
|
|
48
|
+
slidesToScroll: 1,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
breakpoint: 440,
|
|
53
|
+
settings: {
|
|
54
|
+
slidesToShow: 1,
|
|
55
|
+
slidesToScroll: 1,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default settings;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
2
|
+
import NsCarousal from '../NsCarousal';
|
|
3
|
+
import { brandEntries } from '../../card/stories/data';
|
|
4
|
+
import { RenderBrand } from '../RenderBrand';
|
|
5
|
+
import settings from '../slickSetting';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: 'Components/NsCarousal/Brand',
|
|
9
|
+
component: NsCarousal,
|
|
10
|
+
argTypes: {},
|
|
11
|
+
} as ComponentMeta<typeof NsCarousal>;
|
|
12
|
+
|
|
13
|
+
const Template: ComponentStory<typeof NsCarousal> = (args: any) => <NsCarousal {...args} />;
|
|
14
|
+
|
|
15
|
+
export const Default = Template.bind({});
|
|
16
|
+
Default.args = {
|
|
17
|
+
entries: brandEntries,
|
|
18
|
+
renderEntry: RenderBrand,
|
|
19
|
+
allEntryLink: '',
|
|
20
|
+
settings: settings,
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import IconWrapper from '../IconWrapper';
|
|
3
|
+
|
|
4
|
+
describe('IconCover', () => {
|
|
5
|
+
it('render the component', () => {
|
|
6
|
+
const { container } = render(<IconWrapper className="icon-cover" onClick={() => {}} />);
|
|
7
|
+
const element = container.querySelector('.icon-cover');
|
|
8
|
+
expect(element).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
+
import NsCarousal from '../NsCarousal';
|
|
3
|
+
|
|
4
|
+
const mockEntries = [
|
|
5
|
+
{ id: 1, title: 'First entry' },
|
|
6
|
+
{ id: 2, title: 'Second entry' },
|
|
7
|
+
{ id: 3, title: 'Third entry' },
|
|
8
|
+
{ id: 4, title: 'Fourth entry' },
|
|
9
|
+
{ id: 5, title: 'Fifth entry' },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const mockRenderEntry = (entry: any, index: number) => {
|
|
13
|
+
return <div key={index}>{entry.title}</div>;
|
|
14
|
+
};
|
|
15
|
+
const mockAllEntryLink = '/view-all';
|
|
16
|
+
const mockSettings = {
|
|
17
|
+
slidesToShow: 2,
|
|
18
|
+
slidesToScroll: 1,
|
|
19
|
+
};
|
|
20
|
+
describe('NsCarousal', () => {
|
|
21
|
+
it('should have prev and next chevron', () => {
|
|
22
|
+
const { getByTestId } = render(
|
|
23
|
+
<NsCarousal
|
|
24
|
+
entries={[]}
|
|
25
|
+
renderEntry={mockRenderEntry}
|
|
26
|
+
allEntryLink={mockAllEntryLink}
|
|
27
|
+
settings={mockSettings}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
const prevSvg = getByTestId('prev-chevron');
|
|
31
|
+
const nextSvg = getByTestId('next-chevron');
|
|
32
|
+
expect(prevSvg).toBeInTheDocument();
|
|
33
|
+
expect(nextSvg).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should view all link with correct href and slides', () => {
|
|
37
|
+
const { container } = render(
|
|
38
|
+
<NsCarousal
|
|
39
|
+
entries={mockEntries}
|
|
40
|
+
renderEntry={mockRenderEntry}
|
|
41
|
+
allEntryLink={mockAllEntryLink}
|
|
42
|
+
settings={mockSettings}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const viewAllLink = screen.getByRole('link', { name: /view all/i });
|
|
47
|
+
const slides = container.querySelectorAll('.slick-slide');
|
|
48
|
+
|
|
49
|
+
expect(viewAllLink).toBeInTheDocument();
|
|
50
|
+
expect(viewAllLink).toHaveAttribute('href', mockAllEntryLink);
|
|
51
|
+
expect(slides).toHaveLength(mockEntries.length);
|
|
52
|
+
expect(slides[0]).toHaveTextContent('First entry');
|
|
53
|
+
expect(slides[1]).toHaveTextContent('Second entry');
|
|
54
|
+
expect(slides[2]).toHaveTextContent('Third entry');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should change slides when clicking on prev or next buttons', () => {
|
|
58
|
+
const { container } = render(
|
|
59
|
+
<NsCarousal
|
|
60
|
+
entries={mockEntries}
|
|
61
|
+
renderEntry={mockRenderEntry}
|
|
62
|
+
allEntryLink="/view-all"
|
|
63
|
+
settings={mockSettings}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
let currentSlide = container.querySelector('.slick-slide.slick-current');
|
|
68
|
+
expect(currentSlide!.attributes['data-index' as any].value).toEqual('0');
|
|
69
|
+
|
|
70
|
+
/* this is library's button, not our button, it is used for changing slides,
|
|
71
|
+
clicking svg is not making any slide change in this test */
|
|
72
|
+
const nextButton = screen.getByRole('button', { name: /next/i });
|
|
73
|
+
fireEvent.click(nextButton);
|
|
74
|
+
|
|
75
|
+
let slickTrack = container.querySelector('.slick-track');
|
|
76
|
+
currentSlide = slickTrack!.querySelector('.slick-slide.slick-current');
|
|
77
|
+
expect(currentSlide!.attributes['data-index' as any].value).toEqual('1');
|
|
78
|
+
|
|
79
|
+
/* below code is commented because prev button is not working as expected in tests */
|
|
80
|
+
// const prevButton = screen.getByRole('button', { name: /prev/i })
|
|
81
|
+
// fireEvent.click(prevButton)
|
|
82
|
+
// screen.debug(prevButton)
|
|
83
|
+
// let slickList = container.querySelector('.slick-list')
|
|
84
|
+
// currentSlide = slickList!.querySelector('.slick-slide.slick-current')
|
|
85
|
+
// expect(currentSlide!.attributes['data-index' as any].value).toEqual('0')
|
|
86
|
+
|
|
87
|
+
// // currentSlide = screen.getByText(mockEntries[0].title)
|
|
88
|
+
// currentSlide = slickTrack!.querySelector('.slick-slide.slick-current')
|
|
89
|
+
// expect(currentSlide!.attributes['data-index' as any].value).toEqual('0')
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should change slides when clicking on prev or next buttons', () => {
|
|
93
|
+
const { container } = render(
|
|
94
|
+
<NsCarousal
|
|
95
|
+
entries={mockEntries}
|
|
96
|
+
renderEntry={mockRenderEntry}
|
|
97
|
+
allEntryLink="/view-all"
|
|
98
|
+
settings={mockSettings}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
let next = container.querySelector('.carousal-next-button');
|
|
102
|
+
let prev = container.querySelector('.carousal-prev-button');
|
|
103
|
+
fireEvent.click(next!);
|
|
104
|
+
fireEvent.click(prev!);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { RenderBrand } from '../RenderBrand';
|
|
3
|
+
|
|
4
|
+
const mockEntry = {
|
|
5
|
+
title: 'Epoch',
|
|
6
|
+
backgroundImage: 'https://media.nuskin.com/m/549aa3e5184434d8/webimage-brand-epoch-optweb.png',
|
|
7
|
+
brandImage: 'https://media.nuskin.com/m/63a454ff90d038b4/webimage-brand-epoch.png',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const mockIndex = 0;
|
|
11
|
+
|
|
12
|
+
describe('RenderBrand function', () => {
|
|
13
|
+
it('should render a BrandProductCard component with given props', () => {
|
|
14
|
+
render(RenderBrand(mockEntry, mockIndex));
|
|
15
|
+
|
|
16
|
+
const card = screen.getByRole('brand-card');
|
|
17
|
+
const title = screen.getByText(mockEntry.title);
|
|
18
|
+
|
|
19
|
+
expect(card).toBeInTheDocument();
|
|
20
|
+
expect(title).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -15,7 +15,8 @@ const variantStyles = {
|
|
|
15
15
|
'p-l': 'font-size: 18px; line-height: 24px',
|
|
16
16
|
'p-m': 'font-size: 16px; line-height: 22px',
|
|
17
17
|
'p-s': 'font-size: 14px; line-height: 20px',
|
|
18
|
-
'p-xs': 'font-size:
|
|
18
|
+
'p-xs': 'font-size: 12px; line-height: 16px',
|
|
19
|
+
'p-xxs': 'font-size: 11px; line-height: 14px',
|
|
19
20
|
CTA: 'font-size: 11px; line-height: 16px',
|
|
20
21
|
};
|
|
21
22
|
|
|
@@ -15,6 +15,7 @@ export type Variants =
|
|
|
15
15
|
| 'p-m'
|
|
16
16
|
| 'p-s'
|
|
17
17
|
| 'p-xs'
|
|
18
|
+
| 'p-xxs'
|
|
18
19
|
| 'CTA';
|
|
19
20
|
|
|
20
21
|
export type TypographyProps = {
|
|
@@ -23,5 +24,6 @@ export type TypographyProps = {
|
|
|
23
24
|
fontStyle?: 'italic' | 'normal';
|
|
24
25
|
weight?: 'bold' | 'normal' | 'light';
|
|
25
26
|
color?: PaletteColorNames;
|
|
27
|
+
component?: 'div' | 'span' | 'p'
|
|
26
28
|
className?: string;
|
|
27
|
-
} & AdditionalProps;
|
|
29
|
+
} & AdditionalProps;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|