@nuskin/foundation-ui-components 1.9.3 → 1.9.4
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 +6 -6
- package/src/common/autocomplete/NsAutocomplete.spec.tsx +22 -28
- package/src/common/autocomplete/NsAutocomplete.styled.tsx +6 -8
- package/src/common/autocomplete/NsAutocomplete.tsx +14 -8
- package/src/common/autocomplete/helper/LineLoader.tsx +37 -0
- package/src/common/autocomplete/helper/RecentClearAll.tsx +36 -0
- package/src/common/autocomplete/helper/SeeMoreButton.tsx +31 -4
- package/src/common/autocomplete/helper/index.ts +4 -0
- package/src/common/autocomplete/helper/renderGroupName.tsx +0 -1
- package/src/common/autocomplete/mock/MockData.ts +13 -14
- package/src/common/autocomplete/mock/MockUI.tsx +4 -5
- package/src/common/autocomplete/types.d.ts +1 -0
- package/src/common/card/CardButton.tsx +1 -1
- package/src/common/card/NsAwardCard.tsx +4 -3
- package/src/common/card/NsBrandCard.tsx +1 -0
- package/src/common/card/NsHeroCardLevel1.tsx +24 -17
- package/src/common/card/NsHeroCardLevel2.tsx +8 -21
- package/src/common/card/NsLargeCard.tsx +14 -9
- package/src/common/card/NsPost.tsx +8 -3
- package/src/common/card/NsSmallFullCard.tsx +3 -3
- package/src/common/card/NsXLargeCard.tsx +2 -2
- package/src/common/card/cardSizes.ts +4 -4
- package/src/common/card/specs/NsBrandCard.spec.tsx +5 -5
- package/src/common/card/stories/NsBrandCard.stories.tsx +1 -0
- package/src/common/card/stories/NsHeroCardLevel1.stories.tsx +1 -0
- package/src/common/autocomplete/helper/AutoCompleteButton.tsx +0 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuskin/foundation-ui-components",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"description": "It is a foundation library written in react, that provides common components to all UI pages",
|
|
5
5
|
"main": "src/common/index.ts",
|
|
6
6
|
"repository": {
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@emotion/react": "^11.11.1",
|
|
44
44
|
"@emotion/styled": "^11.11.0",
|
|
45
|
-
"@mui/icons-material": "^5.14.
|
|
46
|
-
"@mui/material": "5.14.
|
|
47
|
-
"@mui/utils": "^5.14.
|
|
45
|
+
"@mui/icons-material": "^5.14.16",
|
|
46
|
+
"@mui/material": "5.14.16",
|
|
47
|
+
"@mui/utils": "^5.14.16",
|
|
48
48
|
"@next/font": "13.5.6",
|
|
49
49
|
"@nuskin/foundation-theme": "1.2.0",
|
|
50
|
-
"@types/react": "^18.2.
|
|
50
|
+
"@types/react": "^18.2.34",
|
|
51
51
|
"@types/react-dom": "^18.2.14",
|
|
52
52
|
"cliui": "^8.0.1",
|
|
53
53
|
"framer-motion": "^10.16.4",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"@testing-library/jest-dom": "^6.1.4",
|
|
80
80
|
"@testing-library/react": "^14.0.0",
|
|
81
81
|
"@testing-library/react-hooks": "^8.0.1",
|
|
82
|
-
"@types/jest": "^29.5.
|
|
82
|
+
"@types/jest": "^29.5.7",
|
|
83
83
|
"@types/lodash": "^4.14.200",
|
|
84
84
|
"@types/node": "^20.8.7",
|
|
85
85
|
"@types/ramda": "^0.29.7",
|
|
@@ -2,9 +2,9 @@ import { render, screen, waitFor } from '@/test-utils/index';
|
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
|
|
5
|
-
import { AutocompleteMockList } from '
|
|
6
|
-
import { OptionUiComponent } from '
|
|
7
|
-
import NsAutocomplete from '
|
|
5
|
+
import { AutocompleteMockList } from '../autocomplete/mock/MockData';
|
|
6
|
+
import { OptionUiComponent } from '../autocomplete/mock/MockUI';
|
|
7
|
+
import NsAutocomplete from '../autocomplete/NsAutocomplete';
|
|
8
8
|
|
|
9
9
|
const commonProps = {
|
|
10
10
|
value: '',
|
|
@@ -14,6 +14,7 @@ const commonProps = {
|
|
|
14
14
|
options: AutocompleteMockList,
|
|
15
15
|
placeholder: 'autocomplete-input',
|
|
16
16
|
OptionsUI: OptionUiComponent,
|
|
17
|
+
// renderOption: (props: any) => <li {...props}>{props.value}</li>,
|
|
17
18
|
};
|
|
18
19
|
describe('CustomAutocomplete', () => {
|
|
19
20
|
it('1. should render autocomplete component', () => {
|
|
@@ -47,7 +48,7 @@ describe('CustomAutocomplete', () => {
|
|
|
47
48
|
it('4. selects an option when clicking on it', async () => {
|
|
48
49
|
const onChangeMock = jest.fn();
|
|
49
50
|
render(<NsAutocomplete {...commonProps} onChange={onChangeMock} />);
|
|
50
|
-
const autocompleteInput = screen.getByPlaceholderText(
|
|
51
|
+
const autocompleteInput = screen.getByPlaceholderText(commonProps.placeholder);
|
|
51
52
|
await userEvent.type(autocompleteInput, 'GS Facial');
|
|
52
53
|
await waitFor(async () => {
|
|
53
54
|
const optionLi = screen.getByText('GS Facial Spa');
|
|
@@ -57,39 +58,32 @@ describe('CustomAutocomplete', () => {
|
|
|
57
58
|
}, 40000);
|
|
58
59
|
|
|
59
60
|
it('5. should load more options when clicking load more button', async () => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
{...commonProps}
|
|
68
|
-
/>
|
|
69
|
-
);
|
|
70
|
-
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
61
|
+
const seeMore = {
|
|
62
|
+
text: 'See More',
|
|
63
|
+
show: true,
|
|
64
|
+
onSeeMore: jest.fn(),
|
|
65
|
+
};
|
|
66
|
+
render(<NsAutocomplete seeMore={seeMore} {...commonProps} />);
|
|
67
|
+
const autocompleteInput = screen.getByPlaceholderText(commonProps.placeholder);
|
|
71
68
|
await userEvent.type(autocompleteInput, 'GS Facial');
|
|
72
69
|
await waitFor(async () => {
|
|
73
|
-
const loadMoreButton = screen.
|
|
70
|
+
const loadMoreButton = screen.getByText(seeMore.text);
|
|
74
71
|
await userEvent.click(loadMoreButton);
|
|
75
72
|
});
|
|
73
|
+
expect(seeMore.onSeeMore).toHaveBeenCalled();
|
|
76
74
|
}, 40000);
|
|
77
75
|
|
|
78
76
|
it('6. should clear options when clicking clear button', async () => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
{...commonProps}
|
|
87
|
-
/>
|
|
88
|
-
);
|
|
89
|
-
const autocompleteInput = screen.getByPlaceholderText('autocomplete-input');
|
|
77
|
+
const clear = {
|
|
78
|
+
text: 'Clear All',
|
|
79
|
+
show: true,
|
|
80
|
+
onClear: jest.fn(),
|
|
81
|
+
};
|
|
82
|
+
render(<NsAutocomplete clear={clear} {...commonProps} />);
|
|
83
|
+
const autocompleteInput = screen.getByPlaceholderText(commonProps.placeholder);
|
|
90
84
|
await userEvent.type(autocompleteInput, 'GS Facial');
|
|
91
85
|
await waitFor(async () => {
|
|
92
|
-
const clearButton = screen.
|
|
86
|
+
const clearButton = screen.getByText(clear.text);
|
|
93
87
|
await userEvent.click(clearButton);
|
|
94
88
|
});
|
|
95
89
|
}, 40000);
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
-
|
|
1
|
+
import { styled, ColorUtils } from '@nuskin/foundation-theme';
|
|
3
2
|
import { NsInputField } from '../input';
|
|
3
|
+
const { getGenomeColor } = ColorUtils;
|
|
4
4
|
|
|
5
|
-
// TODO: why is .muiautocomplete-popupindicator added?
|
|
6
|
-
// TODO: ${({ theme }) => getGenomeColor(theme, 'N100')}; use forceMode light
|
|
7
5
|
export const StyledTextField = styled(NsInputField)`
|
|
8
6
|
.MuiAutocomplete-inputRoot {
|
|
9
7
|
padding-right: 10px !important;
|
|
10
8
|
}
|
|
11
|
-
.muiautocomplete-popupindicator {
|
|
12
|
-
display: none;
|
|
13
|
-
}
|
|
14
9
|
.styled-text-field.MuiOutlinedInput-root input#custom_autocomplete_dropdown::placeholder {
|
|
15
10
|
opacity: 1;
|
|
16
|
-
color:
|
|
11
|
+
color: ${({ theme }) => getGenomeColor(theme, 'N100', 'light')};
|
|
17
12
|
}
|
|
18
13
|
`;
|
|
14
|
+
// .muiautocomplete-popupindicator {
|
|
15
|
+
// display: none;
|
|
16
|
+
// }
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Autocomplete, AutocompleteRenderInputParams } from '@mui/material';
|
|
2
2
|
import React, { PropsWithChildren, useEffect, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { LineLoader } from './helper/LineLoader';
|
|
5
|
+
import { RecentClearAll } from './helper/RecentClearAll';
|
|
5
6
|
import { renderGroupBy, renderGroupName, renderOptionLabel } from './helper/renderGroupName';
|
|
6
7
|
import { SeeMoreButton } from './helper/SeeMoreButton';
|
|
7
8
|
import { StyledTextField } from './NsAutocomplete.styled';
|
|
@@ -48,11 +49,14 @@ const NsAutocomplete = ({
|
|
|
48
49
|
/>
|
|
49
50
|
);
|
|
50
51
|
|
|
51
|
-
const renderOption = (props: ComponentBoxProps, option: OptionsProps) =>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
const renderOption = (props: ComponentBoxProps, option: OptionsProps) =>
|
|
53
|
+
OptionsUI ? (
|
|
54
|
+
<OptionsUI {...props} option={option} key={props.id} />
|
|
55
|
+
) : (
|
|
56
|
+
<li {...props} key={props.id}>
|
|
57
|
+
{option.value}
|
|
58
|
+
</li>
|
|
59
|
+
);
|
|
56
60
|
|
|
57
61
|
const renderListBoxComponent = ({ children, ...rest }: ComponentBoxProps) => {
|
|
58
62
|
return (
|
|
@@ -64,11 +68,12 @@ const NsAutocomplete = ({
|
|
|
64
68
|
className={rest.className}
|
|
65
69
|
ref={listboxRef}
|
|
66
70
|
>
|
|
67
|
-
<
|
|
71
|
+
<RecentClearAll
|
|
68
72
|
show={clear?.show ?? false}
|
|
69
73
|
text={clear?.text ?? 'Clear All'}
|
|
70
74
|
onClick={clear?.onClear ?? noop}
|
|
71
75
|
testId="autocomplete-clear-id"
|
|
76
|
+
recentSearchText={clear?.recentSearchText ?? 'Your Recent Searches'}
|
|
72
77
|
/>
|
|
73
78
|
{children}
|
|
74
79
|
<SeeMoreButton
|
|
@@ -82,10 +87,11 @@ const NsAutocomplete = ({
|
|
|
82
87
|
</ul>
|
|
83
88
|
);
|
|
84
89
|
};
|
|
85
|
-
|
|
86
90
|
return (
|
|
87
91
|
<>
|
|
92
|
+
<LineLoader show={loading ?? false} />
|
|
88
93
|
<Autocomplete
|
|
94
|
+
openOnFocus
|
|
89
95
|
id={id}
|
|
90
96
|
disablePortal
|
|
91
97
|
className={className}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
+
|
|
3
|
+
const StyledLine = styled.div`
|
|
4
|
+
position: fixed;
|
|
5
|
+
top: 0px;
|
|
6
|
+
left: 0;
|
|
7
|
+
width: 100%;
|
|
8
|
+
height: 2px;
|
|
9
|
+
background: #fff;
|
|
10
|
+
z-index: 99999;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
.dot {
|
|
13
|
+
position: absolute;
|
|
14
|
+
height: 100%;
|
|
15
|
+
width: 150px;
|
|
16
|
+
background: #f00;
|
|
17
|
+
animation: dotleft 1s cubic-bezier(0.72, 0.03, 0.75, 0.54) infinite;
|
|
18
|
+
}
|
|
19
|
+
@keyframes dotleft {
|
|
20
|
+
0% {
|
|
21
|
+
left: 0%;
|
|
22
|
+
width: 150px;
|
|
23
|
+
}
|
|
24
|
+
100% {
|
|
25
|
+
left: 100%;
|
|
26
|
+
width: 900px;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
export const LineLoader = ({ show }: { show: boolean }) => {
|
|
32
|
+
return (
|
|
33
|
+
<StyledLine className={`${show ? '' : 'hidden '} line`}>
|
|
34
|
+
<div className="dot">{show}</div>
|
|
35
|
+
</StyledLine>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
+
import { NsTypography } from '../../typography';
|
|
3
|
+
|
|
4
|
+
type AutoCompleteButtonProps = {
|
|
5
|
+
text: string;
|
|
6
|
+
show: boolean;
|
|
7
|
+
onClick(): void;
|
|
8
|
+
testId?: string;
|
|
9
|
+
recentSearchText: string;
|
|
10
|
+
};
|
|
11
|
+
export const StyledClear = styled(NsTypography)`
|
|
12
|
+
:hover {
|
|
13
|
+
opacity: 0.5;
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
export const RecentClearAll = (props: AutoCompleteButtonProps) => {
|
|
17
|
+
const { show, onClick, text, testId, recentSearchText } = props;
|
|
18
|
+
if (!show) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return (
|
|
22
|
+
<li className="justify-between flex p-3" onClick={onClick}>
|
|
23
|
+
<NsTypography data-testid={testId} variant="body-m" weight="bold">
|
|
24
|
+
{recentSearchText}
|
|
25
|
+
</NsTypography>
|
|
26
|
+
<StyledClear
|
|
27
|
+
data-testid={testId}
|
|
28
|
+
variant="body-m"
|
|
29
|
+
weight="bold"
|
|
30
|
+
className="cursor-pointer hover:opacity-40"
|
|
31
|
+
>
|
|
32
|
+
{text}
|
|
33
|
+
</StyledClear>
|
|
34
|
+
</li>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { Dispatch, MutableRefObject, SetStateAction, useCallback } from 'react';
|
|
2
|
+
import { styled, ColorUtils } from '@nuskin/foundation-theme';
|
|
2
3
|
|
|
3
|
-
import { OptionsProps } from '../..';
|
|
4
|
-
|
|
4
|
+
import { NsTypography, OptionsProps } from '../..';
|
|
5
|
+
const { getGenomeColor } = ColorUtils;
|
|
6
|
+
export const ListStyled = styled.div`
|
|
7
|
+
display: flex;
|
|
8
|
+
width: 100%;
|
|
9
|
+
flex-direction: row;
|
|
10
|
+
align-items: center;
|
|
11
|
+
gap: 10px;
|
|
12
|
+
padding: 4px 12px;
|
|
13
|
+
cursor: pointer;
|
|
14
|
+
&:hover {
|
|
15
|
+
background: ${({ theme }) => getGenomeColor(theme, 'A10')};
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
5
18
|
|
|
6
19
|
type SeeMoreButtonProps = {
|
|
7
20
|
text?: string;
|
|
@@ -30,9 +43,23 @@ export const SeeMoreButton = (props: SeeMoreButtonProps) => {
|
|
|
30
43
|
setScrollTopPosition(lastScrollPosition);
|
|
31
44
|
}
|
|
32
45
|
}
|
|
33
|
-
if (
|
|
46
|
+
if (typeof onSeeMore === 'function') {
|
|
34
47
|
onSeeMore();
|
|
35
48
|
}
|
|
36
49
|
}, [listboxRef, onSeeMore, options?.length, setScrollTopPosition]);
|
|
37
|
-
|
|
50
|
+
if (!show) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return (
|
|
54
|
+
<ListStyled className="text-left p-3" onClick={handleSeeMore}>
|
|
55
|
+
<NsTypography
|
|
56
|
+
data-testid="autocomplete-loadmore-id"
|
|
57
|
+
variant="body-m"
|
|
58
|
+
decoration="underline"
|
|
59
|
+
className="cursor-pointer"
|
|
60
|
+
>
|
|
61
|
+
{text}
|
|
62
|
+
</NsTypography>
|
|
63
|
+
</ListStyled>
|
|
64
|
+
);
|
|
38
65
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable max-len */
|
|
2
1
|
import { OptionsProps } from '../types';
|
|
3
2
|
|
|
4
3
|
export const AutocompleteMockList: OptionsProps[] = [
|
|
@@ -6,19 +5,19 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
6
5
|
id: '1',
|
|
7
6
|
value: 'GS Facial Gels 2pk Subscription',
|
|
8
7
|
group: 'Popular Searches',
|
|
9
|
-
image: 'https://www.nuskin.com/content/products/86/99/01/86990168/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
8
|
+
image: 'https://www.nuskin.com/content/products/86/99/01/86990168/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
10
9
|
},
|
|
11
10
|
{
|
|
12
11
|
id: '2',
|
|
13
12
|
value: 'GS Facial',
|
|
14
13
|
group: 'Popular Searches',
|
|
15
|
-
image: 'https://www.nuskin.com/content/products/01/55/00/01550014/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
14
|
+
image: 'https://www.nuskin.com/content/products/01/55/00/01550014/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
16
15
|
},
|
|
17
16
|
{
|
|
18
17
|
id: '3',
|
|
19
18
|
value: 'GS Facial Spa',
|
|
20
19
|
group: 'Popular Searches',
|
|
21
|
-
image: 'https://www.nuskin.com/content/products/01/10/12/01101251/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
20
|
+
image: 'https://www.nuskin.com/content/products/01/10/12/01101251/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
22
21
|
},
|
|
23
22
|
{
|
|
24
23
|
id: '4',
|
|
@@ -26,7 +25,7 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
26
25
|
group: 'Popular Searches',
|
|
27
26
|
image: 'https://www.nuskin.com/content/products/01/55/00/01550013/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
28
27
|
icon: 'cart',
|
|
29
|
-
groupBgColor: '#000'
|
|
28
|
+
groupBgColor: '#000'
|
|
30
29
|
},
|
|
31
30
|
{
|
|
32
31
|
id: '5',
|
|
@@ -34,7 +33,7 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
34
33
|
group: 'Popular Searches',
|
|
35
34
|
image: 'https://www.nuskin.com/content/products/86/99/01/86990100/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
36
35
|
icon: 'cart',
|
|
37
|
-
groupBgColor: '#000'
|
|
36
|
+
groupBgColor: '#000'
|
|
38
37
|
},
|
|
39
38
|
{
|
|
40
39
|
id: '6',
|
|
@@ -42,26 +41,26 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
42
41
|
group: 'Popular Searches',
|
|
43
42
|
image: 'https://www.nuskin.com/content/products/01/00/16/01001647/jcr:content/fullImage.img.160.160.png/1611763135883-cache.png.64.64.png',
|
|
44
43
|
icon: 'cart',
|
|
45
|
-
groupBgColor: '#000'
|
|
44
|
+
groupBgColor: '#000'
|
|
46
45
|
},
|
|
47
46
|
|
|
48
47
|
{
|
|
49
48
|
id: '7',
|
|
50
49
|
value: 'Rejuvenating Cream',
|
|
51
50
|
group: 'Popular Searches',
|
|
52
|
-
image: 'https://www.nuskin.com/content/products/86/99/01/86990168/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
51
|
+
image: 'https://www.nuskin.com/content/products/86/99/01/86990168/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
53
52
|
},
|
|
54
53
|
{
|
|
55
54
|
id: '8',
|
|
56
55
|
value: 'Epoch® Firewalker® Foot Cream',
|
|
57
56
|
group: 'Popular Searches',
|
|
58
|
-
image: 'https://www.nuskin.com/content/products/01/55/00/01550014/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
57
|
+
image: 'https://www.nuskin.com/content/products/01/55/00/01550014/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
59
58
|
},
|
|
60
59
|
{
|
|
61
60
|
id: '9',
|
|
62
61
|
value: 'Tri-Phasic White® Night Cream',
|
|
63
62
|
group: 'Popular Searches',
|
|
64
|
-
image: 'https://www.nuskin.com/content/products/01/10/12/01101251/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
63
|
+
image: 'https://www.nuskin.com/content/products/01/10/12/01101251/_jcr_content/fullImage.img.160.160.png.64.64.png'
|
|
65
64
|
},
|
|
66
65
|
{
|
|
67
66
|
id: '10',
|
|
@@ -69,7 +68,7 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
69
68
|
group: 'Popular Searches',
|
|
70
69
|
image: 'https://www.nuskin.com/content/products/01/55/00/01550013/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
71
70
|
icon: 'cart',
|
|
72
|
-
groupBgColor: '#000'
|
|
71
|
+
groupBgColor: '#000'
|
|
73
72
|
},
|
|
74
73
|
{
|
|
75
74
|
id: '11',
|
|
@@ -77,7 +76,7 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
77
76
|
group: 'Popular Searches',
|
|
78
77
|
image: 'https://www.nuskin.com/content/products/86/99/01/86990100/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
79
78
|
icon: 'cart',
|
|
80
|
-
groupBgColor: '#000'
|
|
79
|
+
groupBgColor: '#000'
|
|
81
80
|
},
|
|
82
81
|
{
|
|
83
82
|
id: '12',
|
|
@@ -85,6 +84,6 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
85
84
|
group: 'Popular Searches',
|
|
86
85
|
image: 'https://www.nuskin.com/content/products/01/00/16/01001647/jcr:content/fullImage.img.160.160.png/1611763135883-cache.png.64.64.png',
|
|
87
86
|
icon: 'cart',
|
|
88
|
-
groupBgColor: '#000'
|
|
89
|
-
}
|
|
87
|
+
groupBgColor: '#000'
|
|
88
|
+
}
|
|
90
89
|
];
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/* eslint-disable @next/next/no-img-element */
|
|
2
|
+
import { ListUiProps, NsIcon, NsTypography } from '../..';
|
|
2
3
|
import { ListStyled } from './Mock.styled';
|
|
3
|
-
import { NsTypography } from '../../typography';
|
|
4
|
-
import { NsIcon } from '../../icon';
|
|
5
|
-
import { ListUiProps } from '../types';
|
|
6
4
|
|
|
7
|
-
const OptionUiComponent = (
|
|
5
|
+
const OptionUiComponent = (props: ListUiProps) => {
|
|
6
|
+
const { option } = props;
|
|
8
7
|
return (
|
|
9
|
-
<ListStyled>
|
|
8
|
+
<ListStyled {...props}>
|
|
10
9
|
<div className="item-description" role="link" tabIndex={0}>
|
|
11
10
|
<NsTypography aria-label="Nu Skin Tumbler" variant="body-m" colorOverride="#63666A">
|
|
12
11
|
<img src={option.image} alt="No-image" />
|
|
@@ -16,17 +16,18 @@ const CardContainer = styled(Box)(() => {
|
|
|
16
16
|
display: 'flex',
|
|
17
17
|
flexDirection: 'column',
|
|
18
18
|
position: 'relative',
|
|
19
|
-
backgroundColor: '#fff',
|
|
20
19
|
alignItems: 'center',
|
|
20
|
+
width: '160px',
|
|
21
|
+
height: 'auto',
|
|
21
22
|
'.image': {
|
|
22
|
-
width: '
|
|
23
|
+
width: '160px',
|
|
23
24
|
height: 'auto',
|
|
24
25
|
objectFit: 'cover',
|
|
25
|
-
backgroundColor: 'red',
|
|
26
26
|
},
|
|
27
27
|
'.content': {
|
|
28
28
|
display: 'flex',
|
|
29
29
|
flexDirection: 'column',
|
|
30
|
+
textAlign: 'center',
|
|
30
31
|
alignItems: 'center',
|
|
31
32
|
},
|
|
32
33
|
'.title': {
|
|
@@ -11,20 +11,25 @@ type NsHeroCardLevel1Props = {
|
|
|
11
11
|
backgroundImageAlt: string;
|
|
12
12
|
button?: NsCardButton;
|
|
13
13
|
className?: string;
|
|
14
|
+
imagePosition?: 'top' | 'bottom';
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
const CardContainer = styled(Box)(() => {
|
|
17
|
+
const CardContainer = styled((props: any) => <Box {...props} />)(({ imagePosition }) => {
|
|
18
|
+
const imageDirection = imagePosition === 'top' ? 'column' : 'column-reverse';
|
|
19
|
+
|
|
17
20
|
return {
|
|
18
21
|
backgroundClip: 'border-box',
|
|
19
22
|
display: 'flex',
|
|
20
|
-
flexDirection: 'row' as 'row',
|
|
21
23
|
wordWrap: 'break-word' as 'break-word',
|
|
22
24
|
position: 'relative',
|
|
23
25
|
overflow: 'hidden',
|
|
24
|
-
|
|
26
|
+
width: '100%',
|
|
27
|
+
height: '500px',
|
|
28
|
+
flexDirection: 'row',
|
|
25
29
|
'.content': {
|
|
26
30
|
width: '50%',
|
|
27
|
-
|
|
31
|
+
minWidth: '300px',
|
|
32
|
+
height: '500px',
|
|
28
33
|
padding: '50px',
|
|
29
34
|
paddingLeft: '100px',
|
|
30
35
|
display: 'flex',
|
|
@@ -34,10 +39,8 @@ const CardContainer = styled(Box)(() => {
|
|
|
34
39
|
left: 0,
|
|
35
40
|
boxSizing: 'border-box',
|
|
36
41
|
},
|
|
37
|
-
'.image': {
|
|
38
|
-
|
|
39
|
-
height: '100%',
|
|
40
|
-
display: 'block',
|
|
42
|
+
'.bg-image': {
|
|
43
|
+
objectFit: 'cover',
|
|
41
44
|
},
|
|
42
45
|
'.body-title': {
|
|
43
46
|
fontSize: '36px',
|
|
@@ -52,10 +55,16 @@ const CardContainer = styled(Box)(() => {
|
|
|
52
55
|
marginTop: '10px',
|
|
53
56
|
},
|
|
54
57
|
'@media (max-width: 768px)': {
|
|
55
|
-
|
|
58
|
+
'.content': {
|
|
59
|
+
paddingLeft: '20px',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
'@media (max-width: 430px)': {
|
|
56
63
|
height: 'auto',
|
|
57
64
|
backgroundColor: '#edece9',
|
|
65
|
+
flexDirection: imageDirection,
|
|
58
66
|
'.content': {
|
|
67
|
+
height: 'auto',
|
|
59
68
|
position: 'static',
|
|
60
69
|
width: '100%',
|
|
61
70
|
padding: '20px',
|
|
@@ -64,19 +73,18 @@ const CardContainer = styled(Box)(() => {
|
|
|
64
73
|
};
|
|
65
74
|
});
|
|
66
75
|
|
|
67
|
-
|
|
76
|
+
export default function NsHeroCardLevel1({
|
|
68
77
|
cardTitle,
|
|
69
78
|
cardDescription,
|
|
70
79
|
backgroundImageUrl,
|
|
71
80
|
backgroundImageAlt,
|
|
72
81
|
button,
|
|
73
82
|
className,
|
|
74
|
-
|
|
83
|
+
imagePosition = 'top',
|
|
84
|
+
}: NsHeroCardLevel1Props) {
|
|
75
85
|
return (
|
|
76
|
-
<CardContainer className={className} data-testid="hero-card-level-1">
|
|
77
|
-
<
|
|
78
|
-
<NsImage height={'auto'} width={'100%'} alt={backgroundImageAlt} src={backgroundImageUrl} />
|
|
79
|
-
</div>
|
|
86
|
+
<CardContainer className={className} data-testid="hero-card-level-1" imagePosition={imagePosition}>
|
|
87
|
+
<NsImage variant="fill" alt={backgroundImageAlt} src={backgroundImageUrl} className="bg-image" />
|
|
80
88
|
<div className="content">
|
|
81
89
|
<article className="body-title">{cardTitle}</article>
|
|
82
90
|
<article className="body-text">{cardDescription}</article>
|
|
@@ -84,5 +92,4 @@ const NsHeroCardLevel1 = ({
|
|
|
84
92
|
</div>
|
|
85
93
|
</CardContainer>
|
|
86
94
|
);
|
|
87
|
-
}
|
|
88
|
-
export default NsHeroCardLevel1;
|
|
95
|
+
}
|
|
@@ -22,7 +22,8 @@ const CardContainer = styled(Box)(() => {
|
|
|
22
22
|
wordWrap: 'break-word' as 'break-word',
|
|
23
23
|
position: 'relative',
|
|
24
24
|
overflow: 'hidden',
|
|
25
|
-
height: '
|
|
25
|
+
height: '250px',
|
|
26
|
+
width: '100%',
|
|
26
27
|
'.content': {
|
|
27
28
|
height: '100%',
|
|
28
29
|
padding: '50px',
|
|
@@ -33,10 +34,8 @@ const CardContainer = styled(Box)(() => {
|
|
|
33
34
|
left: 0,
|
|
34
35
|
boxSizing: 'border-box',
|
|
35
36
|
},
|
|
36
|
-
'.image': {
|
|
37
|
-
|
|
38
|
-
height: '100%',
|
|
39
|
-
display: 'block',
|
|
37
|
+
'.bg-image': {
|
|
38
|
+
objectFit: 'cover',
|
|
40
39
|
},
|
|
41
40
|
'.brand-container': {
|
|
42
41
|
backgroundColor: '#fff',
|
|
@@ -45,29 +44,19 @@ const CardContainer = styled(Box)(() => {
|
|
|
45
44
|
paddingRight: '10px',
|
|
46
45
|
},
|
|
47
46
|
'.body-title': {
|
|
48
|
-
fontSize: '
|
|
47
|
+
fontSize: '26px',
|
|
49
48
|
lineHeight: '44px',
|
|
50
49
|
marginBottom: '5px',
|
|
51
50
|
},
|
|
52
51
|
'.body-text': {
|
|
53
|
-
fontSize: '
|
|
52
|
+
fontSize: '12px',
|
|
54
53
|
fontWeight: 700,
|
|
55
54
|
marginBottom: '5px',
|
|
56
55
|
},
|
|
57
|
-
'@media (max-width:
|
|
56
|
+
'@media (max-width:768px)': {
|
|
58
57
|
'.content': {
|
|
59
58
|
padding: '5%',
|
|
60
59
|
},
|
|
61
|
-
'.body-title': {
|
|
62
|
-
fontSize: '18px',
|
|
63
|
-
lineHeight: '44px',
|
|
64
|
-
marginBottom: '5px',
|
|
65
|
-
},
|
|
66
|
-
'.body-text': {
|
|
67
|
-
fontSize: '12px',
|
|
68
|
-
fontWeight: 700,
|
|
69
|
-
marginBottom: '5px',
|
|
70
|
-
},
|
|
71
60
|
},
|
|
72
61
|
};
|
|
73
62
|
});
|
|
@@ -83,9 +72,7 @@ const NsHeroCardLevel2 = ({
|
|
|
83
72
|
}: NsHeroCardLevel2Props) => {
|
|
84
73
|
return (
|
|
85
74
|
<CardContainer className={className} data-testid="hero-card-level-2">
|
|
86
|
-
<
|
|
87
|
-
<NsImage height={'auto'} width={'100%'} alt={backgroundImageAlt} src={backgroundImageUrl} />
|
|
88
|
-
</div>
|
|
75
|
+
<NsImage variant="fill" alt={backgroundImageAlt} src={backgroundImageUrl} className="bg-image" />
|
|
89
76
|
<div className="content">
|
|
90
77
|
<div className="brand-container">
|
|
91
78
|
<article>{brandName}</article>
|
|
@@ -15,19 +15,21 @@ type NsLargeCardProps = {
|
|
|
15
15
|
className?: string;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
const CardContainer = styled((props: any) => <Box {...props} />)(({ isHorizontal }) => {
|
|
19
|
-
let width = '
|
|
18
|
+
const CardContainer = styled((props: any) => <Box {...props} />)(({ isHorizontal, matches }) => {
|
|
19
|
+
let width = '450px',
|
|
20
20
|
paddingLeft = '0px',
|
|
21
21
|
justifyContent,
|
|
22
22
|
fontSizeSub = '16px',
|
|
23
|
-
fontSizeTitle = '26px'
|
|
23
|
+
fontSizeTitle = '26px',
|
|
24
|
+
imageWidth = '100%';
|
|
24
25
|
|
|
25
26
|
if (isHorizontal) {
|
|
26
|
-
width = '
|
|
27
|
+
width = '600px';
|
|
27
28
|
paddingLeft = '30px';
|
|
28
29
|
justifyContent = 'center';
|
|
29
30
|
fontSizeSub = '16px';
|
|
30
|
-
fontSizeTitle = '
|
|
31
|
+
fontSizeTitle = '26px';
|
|
32
|
+
imageWidth = '50%';
|
|
31
33
|
}
|
|
32
34
|
let direction = isHorizontal ? ('row' as 'row') : ('column' as 'column');
|
|
33
35
|
|
|
@@ -36,10 +38,10 @@ const CardContainer = styled((props: any) => <Box {...props} />)(({ isHorizontal
|
|
|
36
38
|
flexDirection: direction,
|
|
37
39
|
position: 'relative',
|
|
38
40
|
width,
|
|
39
|
-
'.image': {
|
|
40
|
-
width: '375px',
|
|
41
|
-
height: 'auto',
|
|
41
|
+
'.bg-image': {
|
|
42
42
|
objectFit: 'cover',
|
|
43
|
+
height: '220px',
|
|
44
|
+
width: imageWidth,
|
|
43
45
|
},
|
|
44
46
|
'.content': {
|
|
45
47
|
display: 'flex',
|
|
@@ -60,6 +62,9 @@ const CardContainer = styled((props: any) => <Box {...props} />)(({ isHorizontal
|
|
|
60
62
|
'.cta': {
|
|
61
63
|
marginTop: '10px',
|
|
62
64
|
},
|
|
65
|
+
'@media (max-width: 768px)': {
|
|
66
|
+
width: '100%',
|
|
67
|
+
},
|
|
63
68
|
};
|
|
64
69
|
});
|
|
65
70
|
|
|
@@ -81,7 +86,7 @@ export default function NsLargeCard({
|
|
|
81
86
|
data-testid="large-card"
|
|
82
87
|
isHorizontal={isHorizontal}
|
|
83
88
|
>
|
|
84
|
-
<NsImage alt={backgroundImageAlt} src={backgroundImageUrl} className="image" />
|
|
89
|
+
<NsImage alt={backgroundImageAlt} src={backgroundImageUrl} className="bg-image" />
|
|
85
90
|
<div className="content">
|
|
86
91
|
<article className="subtitle">{subtitle}</article>
|
|
87
92
|
<article className="title">{title}</article>
|
|
@@ -18,20 +18,25 @@ const CardContainer = styled(Box)(() => {
|
|
|
18
18
|
wordWrap: 'break-word' as 'break-word',
|
|
19
19
|
position: 'relative',
|
|
20
20
|
overflow: 'hidden',
|
|
21
|
-
height: '
|
|
22
|
-
width: '
|
|
21
|
+
height: '350px',
|
|
22
|
+
width: '210px',
|
|
23
23
|
backgroundColor: '#fff',
|
|
24
24
|
'.content': {
|
|
25
25
|
padding: '10px',
|
|
26
26
|
display: 'flex',
|
|
27
27
|
flexDirection: 'column',
|
|
28
|
-
minHeight: '
|
|
28
|
+
minHeight: '80px',
|
|
29
29
|
justifyContent: 'space-between',
|
|
30
30
|
},
|
|
31
31
|
'.body-title': {
|
|
32
32
|
fontSize: '18px',
|
|
33
33
|
marginBottom: '5px',
|
|
34
34
|
fontWeight: 600,
|
|
35
|
+
display: '-webkit-box',
|
|
36
|
+
'-webkit-box-orient': 'vertical',
|
|
37
|
+
'-webkit-line-clamp': '3',
|
|
38
|
+
overflow: 'hidden',
|
|
39
|
+
textOverflow: 'ellipsis',
|
|
35
40
|
},
|
|
36
41
|
'.body-text': {
|
|
37
42
|
fontSize: '12px',
|
|
@@ -17,8 +17,8 @@ const CardContainer = styled(Box)(() => {
|
|
|
17
17
|
return {
|
|
18
18
|
backgroundColor: '#fff',
|
|
19
19
|
display: 'flex',
|
|
20
|
-
height: '
|
|
21
|
-
width: '
|
|
20
|
+
height: '275px',
|
|
21
|
+
width: '250px',
|
|
22
22
|
position: 'relative',
|
|
23
23
|
'.image': {
|
|
24
24
|
width: '100%',
|
|
@@ -49,7 +49,7 @@ const CardContainer = styled(Box)(() => {
|
|
|
49
49
|
},
|
|
50
50
|
'.title': {
|
|
51
51
|
color: '#fff',
|
|
52
|
-
fontSize: '
|
|
52
|
+
fontSize: '22px',
|
|
53
53
|
fontWeight: '400',
|
|
54
54
|
marginTop: '20px',
|
|
55
55
|
},
|
|
@@ -58,11 +58,11 @@ describe('NsBrandCard component', () => {
|
|
|
58
58
|
const cardContainer = container.firstChild;
|
|
59
59
|
const nsBgCardElement = cardContainer?.firstChild;
|
|
60
60
|
expect(cardContainer).toHaveStyle(`
|
|
61
|
-
width:
|
|
61
|
+
width: 180px;
|
|
62
62
|
`);
|
|
63
63
|
expect(nsBgCardElement).toHaveStyle(`
|
|
64
|
-
width:
|
|
65
|
-
height:
|
|
64
|
+
width: 180px;
|
|
65
|
+
height: 200px;
|
|
66
66
|
`);
|
|
67
67
|
});
|
|
68
68
|
|
|
@@ -71,7 +71,7 @@ describe('NsBrandCard component', () => {
|
|
|
71
71
|
const cardContainer = screen.getByTestId('brand-card') as HTMLElement;
|
|
72
72
|
const computedStyles = window.getComputedStyle(cardContainer);
|
|
73
73
|
|
|
74
|
-
expect(computedStyles.width).toBe('
|
|
74
|
+
expect(computedStyles.width).toBe('220px');
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
it('7. renders with default styles when size is not provided', () => {
|
|
@@ -79,6 +79,6 @@ describe('NsBrandCard component', () => {
|
|
|
79
79
|
const cardContainer = screen.getByTestId('brand-card') as HTMLElement;
|
|
80
80
|
const computedStyles = window.getComputedStyle(cardContainer);
|
|
81
81
|
|
|
82
|
-
expect(computedStyles.width).toBe('
|
|
82
|
+
expect(computedStyles.width).toBe('220px');
|
|
83
83
|
});
|
|
84
84
|
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { NsButton, NsTypography } from '../..';
|
|
2
|
-
|
|
3
|
-
type AutoCompleteButtonProps = {
|
|
4
|
-
text: string;
|
|
5
|
-
show: boolean;
|
|
6
|
-
onClick(): void;
|
|
7
|
-
testId?: string;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const AutoCompleteButton = (props: AutoCompleteButtonProps) => {
|
|
11
|
-
const { show, onClick, text, testId } = props;
|
|
12
|
-
if (!show) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
return (
|
|
16
|
-
<li className="text-right p-3">
|
|
17
|
-
<NsButton onClick={onClick} data-testid={testId}>
|
|
18
|
-
<NsTypography variant="body-xs" weight="bold">
|
|
19
|
-
{text}
|
|
20
|
-
</NsTypography>
|
|
21
|
-
</NsButton>
|
|
22
|
-
</li>
|
|
23
|
-
);
|
|
24
|
-
};
|