@nuskin/foundation-ui-components 1.0.0-develop.5 → 1.0.0-develop.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +17 -12
- package/src/common/accordion/NsAccordion.tsx +29 -39
- package/src/common/accordion/NsAccordionHeader.tsx +32 -17
- package/src/common/accordion/NsAccordionItem.tsx +16 -4
- package/src/common/accordion/NsCollapse.tsx +73 -35
- package/src/common/accordion/NsToggleSection.tsx +14 -3
- package/src/common/accordion/ToggleSection.styled.tsx +8 -7
- package/src/common/accordion/colorMap.ts +117 -0
- package/src/common/accordion/enums.ts +15 -0
- package/src/common/accordion/index.ts +1 -0
- package/src/common/accordion/specs/NsAccordion.spec.tsx +100 -31
- package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +77 -10
- package/src/common/accordion/specs/NsAccordionItem.spec.tsx +23 -10
- package/src/common/accordion/specs/NsCollapse.spec.tsx +106 -17
- package/src/common/accordion/specs/NsToggleSection.spec.tsx +46 -14
- package/src/common/accordion/stories/NsAccordion.stories.tsx +27 -14
- package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +4 -1
- package/src/common/accordion/stories/NsAccordionItem.stories.tsx +3 -3
- package/src/common/accordion/stories/NsCollapse.stories.tsx +3 -3
- package/src/common/accordion/stories/NsToggleSection.stories.tsx +2 -3
- package/src/common/accordion/stories/data.tsx +157 -19
- package/src/common/accordion/types.d.ts +56 -49
- package/src/common/alert/Header.tsx +29 -0
- package/src/common/alert/NsAlert.spec.tsx +46 -13
- package/src/common/alert/NsAlert.stories.tsx +3 -3
- package/src/common/alert/{NsAlert.styled.ts → NsAlert.styled.tsx} +22 -22
- package/src/common/alert/NsAlert.tsx +22 -87
- package/src/common/alert/types.d.ts +7 -7
- package/src/common/auth-dropdown/NsAuthDropdown.spec.tsx +23 -5
- package/src/common/auth-dropdown/NsAuthDropdown.stories.tsx +1 -1
- package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +11 -7
- package/src/common/auth-dropdown/NsAuthDropdown.tsx +4 -4
- package/src/common/autocomplete/NsAutocomplete.spec.tsx +39 -6
- package/src/common/autocomplete/NsAutocomplete.stories.tsx +45 -7
- package/src/common/autocomplete/NsAutocomplete.tsx +31 -18
- package/src/common/autocomplete/mock/MockUI.tsx +1 -0
- package/src/common/autocomplete/types.d.ts +8 -6
- package/src/common/banner/NsBanner.spec.tsx +12 -3
- package/src/common/banner/NsBanner.stories.tsx +1 -1
- package/src/common/brand-components/NsBrand.stories.tsx +1 -1
- package/src/common/brand-components/NsBrandComponent.tsx +2 -2
- package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +8 -3
- package/src/common/breadcrumb/NsBreadcrumb.stories.tsx +1 -1
- package/src/common/breadcrumb/NsBreadcrumb.tsx +2 -2
- package/src/common/breadcrumb/data.ts +8 -5
- package/src/common/button/NsButton.spec.tsx +65 -49
- package/src/common/button/NsButton.stories.tsx +59 -2
- package/src/common/button/NsButton.styled.tsx +49 -66
- package/src/common/button/NsButton.tsx +1 -2
- package/src/common/button/helper.ts +82 -0
- package/src/common/button/types.d.ts +2 -0
- package/src/common/card/stories/NsBgCard.stories.tsx +1 -1
- package/src/common/card/stories/NsBrandProductCard.stories.tsx +1 -1
- package/src/common/card/stories/NsFfgCard.stories.tsx +5 -2
- package/src/common/card/styled/NsFfgStyled.tsx +1 -1
- package/src/common/carousal/stories/NSCarousal.stories.tsx +1 -1
- package/src/common/carousal/stories/NsScrollingCarousal.stories.tsx +1 -1
- package/src/common/cart-icon/NsCartIcon.stories.tsx +1 -1
- package/src/common/checkbox/NsCheckbox.stories.tsx +1 -1
- package/src/common/checkbox/NsCheckbox.styled.tsx +15 -16
- package/src/common/checkbox/NsCheckbox.tsx +1 -1
- package/src/common/column-control/stories/DivArray.stories.tsx +1 -1
- package/src/common/column-control/stories/NsColumnControl.stories.tsx +1 -1
- package/src/common/column-control/stories/NsFlexColumns.stories.tsx +1 -1
- package/src/common/column-control/stories/NsGridColumns.stories.tsx +1 -1
- package/src/common/column-control/styled/common.ts +1 -1
- package/src/common/column-control/utils.ts +4 -4
- package/src/common/common.types.d.ts +11 -1
- package/src/common/dropdown/NsDropdown.styled.tsx +23 -18
- package/src/common/dropdown/stories/NsDropdown.stories.tsx +1 -1
- package/src/common/dropdown/stories/NsDropdownCountry.stories.tsx +1 -1
- package/src/common/flag/NsFlag.stories.tsx +1 -1
- package/src/common/hooks/index.ts +2 -0
- package/src/common/hooks/specs/useWindowSize.spec.tsx +19 -0
- package/src/common/hooks/useAccordionMap.tsx +39 -0
- package/src/common/hooks/useWindowSize.tsx +30 -0
- package/src/common/icon/NsIcon.stories.tsx +1 -1
- package/src/common/icon/NsIconVariants.ts +1 -0
- package/src/common/image/NsImage.spec.tsx +56 -6
- package/src/common/image/NsImage.stories.tsx +1 -1
- package/src/common/image/NsImage.tsx +23 -11
- package/src/common/image/NsNextImage.stories.tsx +1 -1
- package/src/common/index.ts +2 -0
- package/src/common/input/InputWrapper.tsx +12 -7
- package/src/common/input/NsInputField.tsx +1 -1
- package/src/common/label/NsLabel.stories.tsx +1 -1
- package/src/common/link/NsLink.stories.tsx +1 -1
- package/src/common/nav-product-card/NsNavProductCard.stories.tsx +1 -1
- package/src/common/nav-tab/NsNavTab.stories.tsx +1 -1
- package/src/common/radiogroup/NsRadioGroup.spec.tsx +24 -25
- package/src/common/radiogroup/NsRadioGroup.stories.tsx +14 -32
- package/src/common/radiogroup/NsRadioGroup.styled.tsx +17 -15
- package/src/common/radiogroup/NsRadioGroup.tsx +6 -5
- package/src/common/search-bar/NsSearchBar.tsx +1 -3
- package/src/common/select/NsSelect.spec.tsx +10 -17
- package/src/common/select/NsSelect.styled.tsx +53 -34
- package/src/common/select/stories/NsSelect.stories.tsx +11 -11
- package/src/common/select/types.d.ts +3 -3
- package/src/common/spinner/NsSpinner.spec.tsx +21 -0
- package/src/common/spinner/NsSpinner.stories.tsx +26 -0
- package/src/common/spinner/NsSpinner.styled.tsx +344 -0
- package/src/common/spinner/NsSpinner.tsx +14 -0
- package/src/common/spinner/icons/Spinner.tsx +161 -0
- package/src/common/spinner/index.ts +2 -0
- package/src/common/spinner/types.ts +5 -0
- package/src/common/table/NsTable.stories.tsx +1 -1
- package/src/common/table/NsTable.tsx +32 -49
- package/src/common/table/NsTableHeader.tsx +30 -51
- package/src/common/text-strip/NsTextStrip.stories.tsx +1 -1
- package/src/common/typography/NsTypography.stories.tsx +1 -1
- package/src/common/util.ts +1 -0
- package/src/common/videos/NsVideo.stories.tsx +1 -1
- package/src/common/videos/types.d.ts +1 -1
- /package/src/common/brand-components/{NsBrandContanier.styled.tsx → NsBrandContainer.styled.tsx} +0 -0
|
@@ -4,12 +4,11 @@ import { useTheme } from '@mui/material/styles';
|
|
|
4
4
|
import StyledButton from './NsButton.styled';
|
|
5
5
|
|
|
6
6
|
import { NsButtonProps } from './types.d';
|
|
7
|
-
import { FoundationTheme } from '@nuskin/foundation-theme';
|
|
8
7
|
|
|
9
8
|
const NsButton = ({ children, darkModeEnabled = true, ...props }: PropsWithChildren<NsButtonProps>) => {
|
|
10
9
|
const { color } = props;
|
|
11
10
|
const { palette } = useTheme();
|
|
12
|
-
const btnColor =
|
|
11
|
+
const btnColor = color && palette?.[color] ? color : 'primary';
|
|
13
12
|
return (
|
|
14
13
|
<StyledButton {...props} color={btnColor} disableRipple darkModeEnabled={darkModeEnabled}>
|
|
15
14
|
{children}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type ContainedParams = {
|
|
2
|
+
backgroundColor: string;
|
|
3
|
+
textColor: string;
|
|
4
|
+
hovered: string;
|
|
5
|
+
pressed: string;
|
|
6
|
+
focused: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function generateContainedStyle({
|
|
10
|
+
backgroundColor,
|
|
11
|
+
textColor,
|
|
12
|
+
hovered,
|
|
13
|
+
pressed,
|
|
14
|
+
focused,
|
|
15
|
+
}: ContainedParams): string {
|
|
16
|
+
return `
|
|
17
|
+
background-color: ${backgroundColor};
|
|
18
|
+
color: ${textColor} !important;
|
|
19
|
+
&:hover {
|
|
20
|
+
background-color: ${hovered};
|
|
21
|
+
}
|
|
22
|
+
&:active {
|
|
23
|
+
background-color: ${pressed};
|
|
24
|
+
}
|
|
25
|
+
&:focus {
|
|
26
|
+
background-color: ${focused};
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
}
|
|
30
|
+
type OutlinedParams = {
|
|
31
|
+
borderColor: string;
|
|
32
|
+
hovered: string;
|
|
33
|
+
pressed: string;
|
|
34
|
+
activeColor: string;
|
|
35
|
+
};
|
|
36
|
+
export function generateOutlinedStyle({ borderColor, hovered, pressed, activeColor }: OutlinedParams) {
|
|
37
|
+
return `
|
|
38
|
+
border-color: ${borderColor};
|
|
39
|
+
color: ${borderColor};
|
|
40
|
+
&:hover {
|
|
41
|
+
border-color: ${hovered};
|
|
42
|
+
color: ${borderColor};
|
|
43
|
+
}
|
|
44
|
+
&:active {
|
|
45
|
+
border-color: ${pressed};
|
|
46
|
+
color: ${activeColor};
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type TextParams = {
|
|
52
|
+
underlineColor: string;
|
|
53
|
+
hovered: string;
|
|
54
|
+
pressed: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export function generateTextStyles({ underlineColor, hovered, pressed }: TextParams): string {
|
|
58
|
+
return `
|
|
59
|
+
text-decoration: underline 1px !important;
|
|
60
|
+
text-underline-offset: 4px;
|
|
61
|
+
padding: 0;
|
|
62
|
+
min-width: auto;
|
|
63
|
+
background-color: transparent !important;
|
|
64
|
+
text-decoration-color: ${underlineColor};
|
|
65
|
+
color: ${underlineColor};
|
|
66
|
+
&:hover {
|
|
67
|
+
color: ${hovered};
|
|
68
|
+
text-decoration-color: ${hovered};
|
|
69
|
+
}
|
|
70
|
+
&:active {
|
|
71
|
+
color: ${underlineColor};
|
|
72
|
+
text-decoration-color: ${pressed};
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function generateIconOnlyStyles() {
|
|
78
|
+
return `
|
|
79
|
+
padding: 10px;
|
|
80
|
+
min-width: unset;
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
@@ -8,7 +8,7 @@ type MetaStory = Meta<ComponentType>;
|
|
|
8
8
|
|
|
9
9
|
export default {
|
|
10
10
|
component: NsBrandProductCard,
|
|
11
|
-
title: 'Components/
|
|
11
|
+
title: 'Components/Containers/Card/NsBrandProductCard',
|
|
12
12
|
argTypes: {},
|
|
13
13
|
decorators: [withCenterDecorator],
|
|
14
14
|
} as MetaStory;
|
|
@@ -10,7 +10,7 @@ type MetaStory = Meta<ComponentType>;
|
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
12
|
component: NsFfgCard,
|
|
13
|
-
title: 'Components/
|
|
13
|
+
title: 'Components/Containers/Card/NsFfgCard',
|
|
14
14
|
argTypes: {},
|
|
15
15
|
decorators: [withCenterDecorator],
|
|
16
16
|
} as MetaStory;
|
|
@@ -19,8 +19,10 @@ export const Default: Story = {
|
|
|
19
19
|
args: {
|
|
20
20
|
actionText: 'LEARN MORE',
|
|
21
21
|
actionLink: 'https://www.forceforgood.org/',
|
|
22
|
+
// eslint-disable-next-line max-len
|
|
22
23
|
text: 'Every child deserves a chance to shine. Through our Nu Skin Force for Good Foundation, we’re empowering children around the world with hope for a brighter future.',
|
|
23
24
|
topImageUrl:
|
|
25
|
+
// eslint-disable-next-line max-len
|
|
24
26
|
'https://images.contentstack.io/v3/assets/blt594f30e2dc643eae/blt34cdb300dc9b93ff/645ccaa7520ba1a1af13a08a/nsffg-foundation.webp',
|
|
25
27
|
topImageAlt: 'Force for Good Foundation',
|
|
26
28
|
additionalProps: {
|
|
@@ -31,8 +33,9 @@ export const Default: Story = {
|
|
|
31
33
|
const canvas = within(canvasElement);
|
|
32
34
|
await userEvent.hover(canvas.getByTestId('ffg-card'));
|
|
33
35
|
await userEvent.hover(canvas.getByRole('link'));
|
|
34
|
-
|
|
36
|
+
expect(
|
|
35
37
|
canvas.getByText(
|
|
38
|
+
// eslint-disable-next-line max-len
|
|
36
39
|
'Every child deserves a chance to shine. Through our Nu Skin Force for Good Foundation, we’re empowering children around the world with hope for a brighter future.'
|
|
37
40
|
)
|
|
38
41
|
).toBeInTheDocument();
|
|
@@ -34,7 +34,7 @@ export const slides = [
|
|
|
34
34
|
},
|
|
35
35
|
];
|
|
36
36
|
export default {
|
|
37
|
-
title: 'Components/NsCarousal/NsScrollingCarousal',
|
|
37
|
+
title: 'Components/Containers/NsCarousal/NsScrollingCarousal',
|
|
38
38
|
component: NsScrollingCarousal,
|
|
39
39
|
decorators: [withCenterDecorator],
|
|
40
40
|
argTypes: {},
|
|
@@ -13,7 +13,7 @@ type MetaStory = Meta<ComponentType>;
|
|
|
13
13
|
const labelText = 'Checkbox Label';
|
|
14
14
|
// In this case, we're only passing the label prop.
|
|
15
15
|
export default {
|
|
16
|
-
title: 'Components/NsCheckbox',
|
|
16
|
+
title: 'Components/Inputs/NsCheckbox',
|
|
17
17
|
component: NsCheckbox,
|
|
18
18
|
decorators: [withCenterDecorator],
|
|
19
19
|
argTypes: {
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @author [vijayaprathap Kumar] (vpkumar@nuskin.com)
|
|
3
|
-
* checkbox.tsx
|
|
4
3
|
* @description Styled Components for Checkbox
|
|
5
4
|
*/
|
|
6
5
|
import DoneIcon from '@mui/icons-material/Done';
|
|
7
6
|
|
|
8
|
-
import { styled } from '@nuskin/foundation-theme';
|
|
7
|
+
import { styled, ColorUtils } from '@nuskin/foundation-theme';
|
|
9
8
|
import { NsFlag } from '../flag';
|
|
10
|
-
|
|
9
|
+
const { paletteColor, buttonColor } = ColorUtils;
|
|
11
10
|
/**
|
|
12
11
|
* Wrapper BpIcon for checkbox.tsx
|
|
13
12
|
* @params ( theme: { palette }) / Provide the color's to contaier from @nuskin/foundation-theme
|
|
14
13
|
*/
|
|
15
14
|
|
|
16
|
-
export const BpIcon = styled(DoneIcon)(({ theme
|
|
15
|
+
export const BpIcon = styled(DoneIcon)(({ theme }) => ({
|
|
17
16
|
border: '1px solid #8C8C8C',
|
|
18
17
|
path: {
|
|
19
18
|
display: 'none',
|
|
@@ -25,31 +24,31 @@ export const BpIcon = styled(DoneIcon)(({ theme: { palette } }) => ({
|
|
|
25
24
|
outline: '3px solid #94D6E9',
|
|
26
25
|
},
|
|
27
26
|
'input:disabled ~ &': {
|
|
28
|
-
background:
|
|
27
|
+
background: buttonColor('primary', 'hovered')({ theme }),
|
|
29
28
|
},
|
|
30
29
|
}));
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
32
|
* Wrapper BpCheckedIcon for checkbox.tsx
|
|
34
|
-
* @params ( theme: { palette }) / Provide the color's to
|
|
33
|
+
* @params ( theme: { palette }) / Provide the color's to container from @nuskin/foundation-theme
|
|
35
34
|
*/
|
|
36
35
|
|
|
37
|
-
export const BpCheckedIcon = styled(BpIcon)(({ theme
|
|
36
|
+
export const BpCheckedIcon = styled(BpIcon)(({ theme }) => ({
|
|
38
37
|
path: {
|
|
39
38
|
display: 'block',
|
|
40
39
|
},
|
|
41
|
-
background:
|
|
42
|
-
color:
|
|
40
|
+
background: paletteColor('primary', 'main')({ theme }),
|
|
41
|
+
color: paletteColor('primary', 'contrastText')({ theme }),
|
|
43
42
|
}));
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
${({ $hasDisabled, theme: { palette } }) =>
|
|
47
|
-
$hasDisabled &&
|
|
48
|
-
`
|
|
49
|
-
color: ${palette?.primary?.buttonState?.hovered};
|
|
50
|
-
`}
|
|
51
|
-
`;
|
|
44
|
+
const getLabelColor = (isDisabled: boolean, color: string) => (!isDisabled ? '' : `color: ${color}`);
|
|
52
45
|
|
|
46
|
+
export const StyledLabel = styled('span')<{ isDisabled: boolean }>`
|
|
47
|
+
${({ isDisabled, theme }) => {
|
|
48
|
+
const color = buttonColor('primary', 'hovered')({ theme });
|
|
49
|
+
return getLabelColor(isDisabled, color);
|
|
50
|
+
}}
|
|
51
|
+
`;
|
|
53
52
|
export const StyledFlagLabel = styled(NsFlag)`
|
|
54
53
|
margin-right: 16px;
|
|
55
54
|
`;
|
|
@@ -54,7 +54,7 @@ const NsCheckbox = (props: PropsWithChildren<NsCheckboxProps>) => {
|
|
|
54
54
|
() => (
|
|
55
55
|
<NsTypography variant="p-l">
|
|
56
56
|
<StyledFlagLabel {...flag} size={size} testId={`${name}-flag-label`} />
|
|
57
|
-
<StyledLabel className="checkbox-label-text"
|
|
57
|
+
<StyledLabel className="checkbox-label-text" isDisabled={disabled}>
|
|
58
58
|
{label}
|
|
59
59
|
</StyledLabel>
|
|
60
60
|
</NsTypography>
|
|
@@ -9,7 +9,7 @@ type Story = StoryObj<ComponentType>;
|
|
|
9
9
|
type MetaStory = Meta<ComponentType>;
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: 'Components/Column/NsColumnControl',
|
|
12
|
+
title: 'Components/Data Display/Column/NsColumnControl',
|
|
13
13
|
component: NsColumnControl,
|
|
14
14
|
decorators: [withCenterDecorator],
|
|
15
15
|
argTypes: {
|
|
@@ -9,7 +9,7 @@ type Story = StoryObj<ComponentType>;
|
|
|
9
9
|
type MetaStory = Meta<ComponentType>;
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: 'Components/Column/NsFlexColumns',
|
|
12
|
+
title: 'Components/Data Display/Column/NsFlexColumns',
|
|
13
13
|
component: NsFlexColumns,
|
|
14
14
|
decorators: [withCenterDecorator],
|
|
15
15
|
argTypes: {
|
|
@@ -9,7 +9,7 @@ type Story = StoryObj<ComponentType>;
|
|
|
9
9
|
type MetaStory = Meta<ComponentType>;
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: 'Components/Column/NsGridColumns',
|
|
12
|
+
title: 'Components/Data Display/Column/NsGridColumns',
|
|
13
13
|
component: NsGridColumns,
|
|
14
14
|
decorators: [withCenterDecorator],
|
|
15
15
|
argTypes: {
|
|
@@ -21,7 +21,7 @@ export const commonStyles = {
|
|
|
21
21
|
['1','2'] => ['27%','53%']
|
|
22
22
|
*/
|
|
23
23
|
export function getPercentArray(fractionArray?: string[] | number[]) {
|
|
24
|
-
|
|
24
|
+
const numbers = fractionArray?.map((numberString) => +numberString)?.filter((num) => 0 < num && num < 10) ?? [];
|
|
25
25
|
const sum = numbers.reduce((currentSum, currentNumber) => currentSum + currentNumber, 0);
|
|
26
26
|
return numbers.map((currentNumber) => ((currentNumber / sum) * 80).toFixed(2) + '%');
|
|
27
27
|
}
|
|
@@ -40,15 +40,15 @@ const sizeKeyMap: Record<ValueOf<typeof sizeKeyPrefix>, string> = {
|
|
|
40
40
|
* @returns {fractions:['1','1','1'], tabletFractions:['1','1'], mobileFractions:['1'] }
|
|
41
41
|
*/
|
|
42
42
|
export const getColumnSizes = (inputColumnClass: string): sizeObjectType => {
|
|
43
|
-
|
|
43
|
+
const columnClass = inputColumnClass.trim();
|
|
44
44
|
const validClasses = columnClass
|
|
45
45
|
.split(' ')
|
|
46
46
|
.filter((e) => Object.values(sizeKeyPrefix).some((prefix) => e.startsWith(prefix)));
|
|
47
47
|
const sizeObject: sizeObjectType = validClasses.reduce((acc: any, current: string) => {
|
|
48
|
-
for (
|
|
48
|
+
for (const key of Object.values(sizeKeyPrefix)) {
|
|
49
49
|
if (current.startsWith(key)) {
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
const interClass = current.replace(key, '');
|
|
51
|
+
const sizes = interClass.split('-').filter((e) => /^[1-9]$/.test(e));
|
|
52
52
|
acc[sizeKeyMap[key]] = sizes;
|
|
53
53
|
break;
|
|
54
54
|
}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
import { FoundationTheme } from '@nuskin/foundation-theme';
|
|
2
|
+
|
|
1
3
|
export type ContentStackLiveTags = {
|
|
2
4
|
'data-cslp'?: string;
|
|
3
5
|
};
|
|
4
6
|
|
|
5
7
|
export type AdditionalProps = {
|
|
6
|
-
darkModeEnabled?: boolean;
|
|
7
8
|
additionalProps?: {
|
|
8
9
|
ariaLabel?: string;
|
|
9
10
|
testid?: string;
|
|
10
11
|
className?: string;
|
|
12
|
+
'data-testid'?: string;
|
|
11
13
|
} & ContentStackLiveTags;
|
|
14
|
+
} & DarkModeEnabledOption;
|
|
15
|
+
|
|
16
|
+
export type Themed = {
|
|
17
|
+
theme: FoundationTheme.Theme;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type DarkModeEnabledOption = {
|
|
21
|
+
darkModeEnabled?: boolean;
|
|
12
22
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { styled, ColorUtils, FoundationTheme } from '@nuskin/foundation-theme';
|
|
2
|
-
|
|
2
|
+
import { Themed } from '../common.types';
|
|
3
|
+
const { color, paletteColor, isDarkMode } = ColorUtils;
|
|
3
4
|
|
|
4
5
|
export const DropdownContainer = styled.div<{ disabled: boolean }>`
|
|
5
6
|
position: relative;
|
|
@@ -7,15 +8,22 @@ export const DropdownContainer = styled.div<{ disabled: boolean }>`
|
|
|
7
8
|
opacity: ${({ disabled }) => (disabled ? '0.5' : '1')};
|
|
8
9
|
`;
|
|
9
10
|
|
|
11
|
+
/** this function also used for SelectHead */
|
|
12
|
+
export const getDropdownHeadBorder = ({ type, theme }: { type: string } & Themed) => {
|
|
13
|
+
if (type === 'outlined') {
|
|
14
|
+
const borderColor = color('primary', 'black')({ theme });
|
|
15
|
+
return `1px solid ${borderColor}`;
|
|
16
|
+
}
|
|
17
|
+
return 'none';
|
|
18
|
+
};
|
|
10
19
|
export const DropdownHead = styled.div<{ type: string; disabled: boolean }>`
|
|
11
20
|
cursor: ${({ disabled }) => (disabled ? 'inherit' : 'pointer')};
|
|
12
21
|
padding: 5px 10px;
|
|
13
22
|
display: flex;
|
|
14
23
|
justify-content: space-between;
|
|
15
24
|
align-items: center;
|
|
16
|
-
border: ${
|
|
17
|
-
|
|
18
|
-
color: ${({ theme }) => getPaletteColor(theme, 'primary')};
|
|
25
|
+
border: ${getDropdownHeadBorder}
|
|
26
|
+
color: ${paletteColor('primary')};
|
|
19
27
|
`;
|
|
20
28
|
|
|
21
29
|
export const DropdownButton = styled.div`
|
|
@@ -25,27 +33,19 @@ export const DropdownButton = styled.div`
|
|
|
25
33
|
export const DropdownList = styled.div<{ borderColor: FoundationTheme.PaletteColors }>`
|
|
26
34
|
position: absolute;
|
|
27
35
|
z-index: 100;
|
|
28
|
-
border: 1px solid ${({ borderColor, theme }) =>
|
|
36
|
+
border: 1px solid ${({ borderColor, theme }) => paletteColor(borderColor)({ theme })};
|
|
29
37
|
padding: 0;
|
|
30
38
|
margin: 0;
|
|
31
39
|
width: 100%;
|
|
32
|
-
color: ${(
|
|
33
|
-
background-color: ${(
|
|
40
|
+
color: ${paletteColor('primary', 'main')};
|
|
41
|
+
background-color: ${paletteColor('primary', 'contrastText')};
|
|
34
42
|
`;
|
|
35
|
-
const getIsLight = (theme: FoundationTheme.Theme) => {
|
|
36
|
-
const { palette = { primary: { main: '', contrastText: '' } } } = theme;
|
|
37
|
-
return palette.primary.main === getAppColor(theme, 'primary', 'black');
|
|
38
|
-
};
|
|
39
43
|
|
|
40
44
|
const getDividerColor = (theme: FoundationTheme.Theme) => {
|
|
41
|
-
|
|
42
|
-
const dividerColor = isLight ? getAppColor(theme, 'neutral', '30') : getAppColor(theme, 'neutral', '20');
|
|
43
|
-
return dividerColor;
|
|
45
|
+
return color('neutral', isDarkMode({ theme }) ? '20' : '30')({ theme });
|
|
44
46
|
};
|
|
45
47
|
const getListBgColor = (theme: FoundationTheme.Theme) => {
|
|
46
|
-
|
|
47
|
-
const bgColor = isLight ? getAppColor(theme, 'accentColorB', '10') : getAppColor(theme, 'accentColorB', '50');
|
|
48
|
-
return bgColor;
|
|
48
|
+
return color('accentColorB', isDarkMode({ theme }) ? '50' : '10')({ theme });
|
|
49
49
|
};
|
|
50
50
|
export const ListItemContainer = styled.div<{ showListDivider: boolean }>`
|
|
51
51
|
cursor: pointer;
|
|
@@ -61,7 +61,12 @@ export const ListItemContainer = styled.div<{ showListDivider: boolean }>`
|
|
|
61
61
|
}
|
|
62
62
|
`;
|
|
63
63
|
|
|
64
|
+
const getBorder = ({ isSelected, theme }: { isSelected: boolean } & Themed) => {
|
|
65
|
+
const borderColor = paletteColor('primary')({ theme });
|
|
66
|
+
return isSelected ? `2px solid ${borderColor}` : 'none';
|
|
67
|
+
};
|
|
68
|
+
|
|
64
69
|
export const ListItem = styled.span<{ isSelected: boolean }>`
|
|
65
70
|
padding: 5px 10px;
|
|
66
|
-
border-left: ${
|
|
71
|
+
border-left: ${getBorder};
|
|
67
72
|
`;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { renderHook, act } from '@testing-library/react-hooks';
|
|
2
|
+
import useWindowSize from '../useWindowSize';
|
|
3
|
+
|
|
4
|
+
describe('useWindowSize', () => {
|
|
5
|
+
it('should return the window size', () => {
|
|
6
|
+
const { result } = renderHook(useWindowSize);
|
|
7
|
+
expect(result.current).toEqual({ width: window.innerWidth, height: window.innerHeight });
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should update the window size when the window is resized', () => {
|
|
11
|
+
const { result } = renderHook(() => useWindowSize());
|
|
12
|
+
act(() => {
|
|
13
|
+
window.innerWidth = 500;
|
|
14
|
+
window.innerHeight = 500;
|
|
15
|
+
window.dispatchEvent(new Event('resize'));
|
|
16
|
+
});
|
|
17
|
+
expect(result.current).toEqual({ width: 500, height: 500 });
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
type ItemMap = Record<string, boolean>;
|
|
4
|
+
type UseAccordionProp = {
|
|
5
|
+
allowMultipleExpanded?: boolean;
|
|
6
|
+
defaultOpenIds?: string[];
|
|
7
|
+
};
|
|
8
|
+
const reducer = (map: ItemMap, id: string) => {
|
|
9
|
+
map[id] = true;
|
|
10
|
+
return map;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const useAccordionMap = ({ allowMultipleExpanded, defaultOpenIds }: UseAccordionProp) => {
|
|
14
|
+
const mapSetter = useCallback(() => {
|
|
15
|
+
let ids = defaultOpenIds;
|
|
16
|
+
if (!allowMultipleExpanded) {
|
|
17
|
+
ids = ids?.slice(0, 1) ?? [];
|
|
18
|
+
}
|
|
19
|
+
return ids?.reduce(reducer, {}) ?? {};
|
|
20
|
+
}, [defaultOpenIds, allowMultipleExpanded]);
|
|
21
|
+
|
|
22
|
+
const [itemStateMap, setItemMap] = useState<ItemMap>(mapSetter);
|
|
23
|
+
|
|
24
|
+
const toggleOpen = (index: string | number) => {
|
|
25
|
+
const key = index + '';
|
|
26
|
+
if (allowMultipleExpanded) {
|
|
27
|
+
setItemMap((prevState) => ({ ...prevState, [key]: !prevState[key] }));
|
|
28
|
+
} else {
|
|
29
|
+
setItemMap({ [key]: !itemStateMap[index] });
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
setItemMap(mapSetter);
|
|
35
|
+
}, [mapSetter]);
|
|
36
|
+
return { itemStateMap, toggleOpen };
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default useAccordionMap;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const useWindowSize = () => {
|
|
4
|
+
const [windowSize, setWindowSize] = useState({
|
|
5
|
+
width: window.innerWidth,
|
|
6
|
+
height: window.innerHeight,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
function handleResize() {
|
|
11
|
+
setWindowSize({
|
|
12
|
+
width: window?.innerWidth || 300,
|
|
13
|
+
height: window?.innerHeight || 300,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
if (typeof window !== 'undefined') {
|
|
17
|
+
window.addEventListener('resize', handleResize);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return () => {
|
|
21
|
+
if (typeof window !== 'undefined') {
|
|
22
|
+
window.removeEventListener('resize', handleResize);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
return windowSize;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default useWindowSize;
|