@nuskin/foundation-ui-components 1.1.0 → 1.1.1
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 +15 -11
- package/src/common/accordion/NsAccordion.tsx +32 -40
- package/src/common/accordion/NsAccordionHeader.tsx +29 -8
- package/src/common/accordion/NsAccordionItem.tsx +24 -4
- package/src/common/accordion/NsCollapse.tsx +96 -35
- package/src/common/accordion/NsToggleSection.tsx +16 -3
- package/src/common/accordion/ToggleSection.styled.tsx +11 -7
- package/src/common/accordion/colorMap.ts +117 -0
- package/src/common/accordion/enums.ts +18 -0
- package/src/common/accordion/index.ts +1 -0
- package/src/common/accordion/specs/NsAccordion.spec.tsx +101 -31
- package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +77 -10
- package/src/common/accordion/specs/NsAccordionItem.spec.tsx +27 -10
- package/src/common/accordion/specs/NsCollapse.spec.tsx +109 -17
- package/src/common/accordion/specs/NsToggleSection.spec.tsx +50 -14
- package/src/common/accordion/stories/NsAccordion.stories.tsx +31 -13
- package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +5 -1
- package/src/common/accordion/stories/NsAccordionItem.stories.tsx +8 -3
- package/src/common/accordion/stories/NsCollapse.stories.tsx +19 -4
- package/src/common/accordion/stories/NsToggleSection.stories.tsx +6 -3
- package/src/common/accordion/stories/data.tsx +140 -19
- package/src/common/accordion/types.d.ts +55 -47
- package/src/common/alert/Header.tsx +29 -0
- package/src/common/alert/NsAlert.spec.tsx +46 -13
- package/src/common/alert/NsAlert.stories.tsx +1 -1
- package/src/common/alert/{NsAlert.styled.ts → NsAlert.styled.tsx} +22 -22
- package/src/common/alert/NsAlert.tsx +22 -87
- package/src/common/alert/types.d.ts +7 -7
- package/src/common/auth-dropdown/NsAuthDropdown.spec.tsx +23 -5
- package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +9 -2
- package/src/common/auth-dropdown/NsAuthDropdown.tsx +4 -4
- package/src/common/autocomplete/NsAutocomplete.spec.tsx +34 -11
- package/src/common/autocomplete/NsAutocomplete.stories.tsx +18 -2
- package/src/common/autocomplete/NsAutocomplete.tsx +63 -24
- package/src/common/autocomplete/mock/MockData.ts +50 -7
- package/src/common/autocomplete/mock/MockUI.tsx +2 -1
- package/src/common/autocomplete/types.d.ts +7 -4
- package/src/common/banner/NsBanner.spec.tsx +12 -3
- package/src/common/brand-components/NsBrandComponent.tsx +2 -2
- package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +8 -3
- package/src/common/breadcrumb/data.ts +8 -5
- package/src/common/button/NsButton.spec.tsx +65 -49
- package/src/common/button/NsButton.stories.tsx +40 -4
- package/src/common/button/NsButton.styled.tsx +49 -66
- package/src/common/button/NsButton.tsx +1 -2
- package/src/common/button/helper.ts +82 -0
- package/src/common/card/NsFfgCard.tsx +13 -7
- package/src/common/card/specs/NsFfgCard.spec.tsx +18 -8
- package/src/common/card/stories/NsFfgCard.stories.tsx +47 -14
- package/src/common/card/styled/NsFfgStyled.tsx +10 -7
- package/src/common/card/types.d.ts +7 -4
- package/src/common/carousal/NsCarousal.tsx +3 -9
- package/src/common/cart-icon/NsCartIcon.spec.tsx +5 -16
- package/src/common/cart-icon/NsCartIcon.stories.tsx +1 -1
- package/src/common/cart-icon/NsCartIcon.styled.ts +7 -33
- package/src/common/cart-icon/NsCartIcon.tsx +5 -14
- package/src/common/cart-icon/types.d.ts +1 -0
- package/src/common/checkbox/NsCheckbox.styled.tsx +15 -16
- package/src/common/checkbox/NsCheckbox.tsx +1 -1
- package/src/common/column-control/styled/common.ts +1 -1
- package/src/common/column-control/utils.ts +4 -4
- package/src/common/common.types.d.ts +14 -5
- package/src/common/dropdown/NsDropdown.styled.tsx +23 -18
- package/src/common/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.spec.tsx +1 -1
- package/src/common/icon/NsIcon.stories.tsx +3 -0
- package/src/common/icon/NsIcon.tsx +6 -2
- package/src/common/icon/NsIconVariants.ts +4 -1
- package/src/common/icon/icons/AlertErrorIcon.tsx +2 -2
- package/src/common/icon/icons/ArrowLeft.tsx +3 -6
- package/src/common/icon/icons/ArrowRight.tsx +6 -8
- package/src/common/icon/icons/Cart.tsx +7 -32
- package/src/common/icon/icons/CartBadge.tsx +2 -2
- package/src/common/icon/icons/CloseIcon.tsx +1 -1
- package/src/common/icon/icons/ErrorIcon.tsx +2 -2
- package/src/common/icon/icons/HamburgerIcon.tsx +5 -2
- package/src/common/icon/icons/SearchIcon.tsx +1 -1
- package/src/common/icon/icons/SuccessIcon.tsx +2 -7
- package/src/common/icon/icons/TrashIcon.tsx +1 -1
- package/src/common/icon/icons/UserIcon.tsx +3 -6
- package/src/common/icon/icons/UserOutline.tsx +24 -0
- package/src/common/icon/icons/WarningIcon.tsx +1 -1
- package/src/common/icon/icons/home.tsx +1 -1
- package/src/common/image/NsImage.spec.tsx +56 -6
- package/src/common/image/NsImage.tsx +23 -11
- package/src/common/index.ts +6 -2
- package/src/common/input/InputWrapper.tsx +12 -7
- package/src/common/input/NsInputField.tsx +1 -1
- package/src/common/modal/NsModal.spec.tsx +46 -0
- package/src/common/modal/NsModal.styled.tsx +28 -0
- package/src/common/modal/NsModal.tsx +37 -0
- package/src/common/modal/helper-component/NsModalContentBox.tsx +32 -0
- package/src/common/modal/helper-component/NsModalDefault.tsx +25 -0
- package/src/common/modal/helper-component/NsModalStatus.tsx +15 -0
- package/src/common/modal/helper-component/NsModalStatusIcon.tsx +14 -0
- package/src/common/modal/helper-component/NsModalTitle.tsx +26 -0
- package/src/common/modal/index.ts +2 -0
- package/src/common/modal/model/NsModalVariantMap.tsx +24 -0
- package/src/common/modal/stories/NsModal.stories.tsx +85 -0
- package/src/common/modal/stories/mock.tsx +46 -0
- package/src/common/modal/types.ts +56 -0
- package/src/common/nav-tab/NavDrawer.tsx +34 -0
- package/src/common/nav-tab/NavTitles.tsx +52 -0
- package/src/common/nav-tab/NsNavTab.spec.tsx +4 -5
- package/src/common/nav-tab/NsNavTab.stories.tsx +3 -3
- package/src/common/nav-tab/NsNavTab.styled.tsx +13 -7
- package/src/common/nav-tab/NsNavTab.tsx +21 -75
- package/src/common/nav-tab/index.ts +1 -1
- package/src/common/nav-tab/types.d.ts +3 -3
- package/src/common/radiogroup/NsRadioGroup.spec.tsx +24 -25
- package/src/common/radiogroup/NsRadioGroup.stories.tsx +13 -31
- package/src/common/radiogroup/NsRadioGroup.styled.tsx +20 -19
- 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 +10 -10
- 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.tsx +32 -49
- package/src/common/table/NsTableHeader.tsx +30 -51
- package/src/common/util.ts +1 -0
- package/src/common/utility/Show.tsx +13 -0
- package/src/common/utility/index.ts +1 -0
- package/src/common/videos/types.d.ts +1 -1
- /package/src/common/brand-components/{NsBrandContanier.styled.tsx → NsBrandContainer.styled.tsx} +0 -0
|
@@ -4,24 +4,25 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
4
4
|
{
|
|
5
5
|
id: '1',
|
|
6
6
|
value: 'GS Facial Gels 2pk Subscription',
|
|
7
|
-
|
|
7
|
+
group: 'Popular Searches',
|
|
8
8
|
image: 'https://www.nuskin.com/content/products/86/99/01/86990168/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
id: '2',
|
|
12
12
|
value: 'GS Facial',
|
|
13
|
-
|
|
13
|
+
group: 'Popular Searches',
|
|
14
14
|
image: 'https://www.nuskin.com/content/products/01/55/00/01550014/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
id: '3',
|
|
18
|
-
value: 'GS Facial Spa',
|
|
18
|
+
value: 'GS Facial Spa',
|
|
19
|
+
group: 'Popular Searches',
|
|
19
20
|
image: 'https://www.nuskin.com/content/products/01/10/12/01101251/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
20
21
|
},
|
|
21
22
|
{
|
|
22
23
|
id: '4',
|
|
23
24
|
value: 'Nu Skin® Facial Spa',
|
|
24
|
-
group: 'Popular Searches',
|
|
25
|
+
group: 'Popular Searches',
|
|
25
26
|
image: 'https://www.nuskin.com/content/products/01/55/00/01550013/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
26
27
|
icon: 'cart',
|
|
27
28
|
groupBgColor: '#000',
|
|
@@ -29,7 +30,7 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
29
30
|
{
|
|
30
31
|
id: '5',
|
|
31
32
|
value: 'AP 24® Whitening Fluoride Toothpaste',
|
|
32
|
-
group: 'Popular Searches',
|
|
33
|
+
group: 'Popular Searches',
|
|
33
34
|
image: 'https://www.nuskin.com/content/products/86/99/01/86990100/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
34
35
|
icon: 'cart',
|
|
35
36
|
groupBgColor: '#000',
|
|
@@ -37,10 +38,52 @@ export const AutocompleteMockList: OptionsProps[] = [
|
|
|
37
38
|
{
|
|
38
39
|
id: '6',
|
|
39
40
|
value: 'PowerMask + LumiSpa Normal Subscription',
|
|
40
|
-
group: 'Popular Searches',
|
|
41
|
+
group: 'Popular Searches',
|
|
41
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',
|
|
42
43
|
icon: 'cart',
|
|
43
44
|
groupBgColor: '#000',
|
|
44
45
|
},
|
|
45
|
-
];
|
|
46
46
|
|
|
47
|
+
{
|
|
48
|
+
id: '7',
|
|
49
|
+
value: 'Rejuvenating Cream',
|
|
50
|
+
group: 'Popular Searches',
|
|
51
|
+
image: 'https://www.nuskin.com/content/products/86/99/01/86990168/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: '8',
|
|
55
|
+
value: 'Epoch® Firewalker® Foot Cream',
|
|
56
|
+
group: 'Popular Searches',
|
|
57
|
+
image: 'https://www.nuskin.com/content/products/01/55/00/01550014/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: '9',
|
|
61
|
+
value: 'Tri-Phasic White® Night Cream',
|
|
62
|
+
group: 'Popular Searches',
|
|
63
|
+
image: 'https://www.nuskin.com/content/products/01/10/12/01101251/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: '10',
|
|
67
|
+
value: 'ThirstFix Hydrating Gel Cream (Sample Size)',
|
|
68
|
+
group: 'Popular Searches',
|
|
69
|
+
image: 'https://www.nuskin.com/content/products/01/55/00/01550013/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
70
|
+
icon: 'cart',
|
|
71
|
+
groupBgColor: '#000',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: '11',
|
|
75
|
+
value: 'Epoch® Baby Hair',
|
|
76
|
+
group: 'Popular Searches',
|
|
77
|
+
image: 'https://www.nuskin.com/content/products/86/99/01/86990100/_jcr_content/fullImage.img.160.160.png.64.64.png',
|
|
78
|
+
icon: 'cart',
|
|
79
|
+
groupBgColor: '#000',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: '12',
|
|
83
|
+
value: '180° Face Wash',
|
|
84
|
+
group: 'Popular Searches',
|
|
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',
|
|
86
|
+
icon: 'cart',
|
|
87
|
+
groupBgColor: '#000',
|
|
88
|
+
},
|
|
89
|
+
];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @next/next/no-img-element */
|
|
1
2
|
import { ListStyled } from './Mock.styled';
|
|
2
3
|
import { NsTypography } from '../../typography';
|
|
3
4
|
import { NsIcon } from '../../icon';
|
|
@@ -5,7 +6,7 @@ import { ListUiProps } from '../types';
|
|
|
5
6
|
|
|
6
7
|
const OptionUiComponent = ({ option }: ListUiProps) => {
|
|
7
8
|
return (
|
|
8
|
-
<ListStyled
|
|
9
|
+
<ListStyled>
|
|
9
10
|
<div className="item-description" role="link" tabIndex={0}>
|
|
10
11
|
<NsTypography aria-label="Nu Skin Tumbler" variant="p-m" colorOverride="#63666A">
|
|
11
12
|
<img src={option.image} alt="No-image" />
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import React, { HTMLAttributes } from 'react';
|
|
2
|
+
|
|
3
|
+
import { ComponentsProps } from '@mui/material';
|
|
4
|
+
|
|
2
5
|
import { AdditionalProps } from '../common.types';
|
|
3
6
|
import { NsIconNameType } from '../icon';
|
|
4
|
-
import { ComponentsProps } from '@mui/material';
|
|
5
7
|
|
|
6
8
|
export type NsAutocompleteProps = {
|
|
7
9
|
id?: string;
|
|
8
10
|
options: OptionsProps[];
|
|
9
11
|
loading?: boolean;
|
|
10
|
-
|
|
12
|
+
OptionsUI: React.ComponentType<any>;
|
|
11
13
|
noOptionsText?: string;
|
|
12
14
|
// eslint-disable-next-line no-unused-vars
|
|
13
15
|
onSelect?: (params: string | OptionsProps | null) => void;
|
|
14
16
|
// eslint-disable-next-line no-unused-vars
|
|
15
17
|
onChange?: (params: string) => void;
|
|
16
18
|
clear?: {
|
|
17
|
-
text
|
|
19
|
+
text?: string;
|
|
18
20
|
show?: boolean; //default to false
|
|
19
21
|
onClear: () => void;
|
|
20
22
|
};
|
|
21
23
|
seeMore?: {
|
|
22
|
-
text
|
|
24
|
+
text?: string;
|
|
23
25
|
show?: boolean; //default to false
|
|
24
26
|
onSeeMore: () => void;
|
|
25
27
|
};
|
|
@@ -29,6 +31,7 @@ export type NsAutocompleteProps = {
|
|
|
29
31
|
iconEnd?: string | React.ReactNode;
|
|
30
32
|
inputValue: string;
|
|
31
33
|
value: string | OptionsProps | null;
|
|
34
|
+
isFilterEnabled?:boolean
|
|
32
35
|
} & AdditionalProps;
|
|
33
36
|
|
|
34
37
|
export type ListUiProps = {
|
|
@@ -3,9 +3,9 @@ import { render } from '@testing-library/react';
|
|
|
3
3
|
import { NsBanner } from '@/common/';
|
|
4
4
|
|
|
5
5
|
describe('Hero component', () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const childText = 'Welcome to My Website';
|
|
7
|
+
const imageURL = 'https://example.com/banner.jpg';
|
|
8
|
+
it('1. renders banner image and title', () => {
|
|
9
9
|
const { getByAltText, getByText } = render(
|
|
10
10
|
<NsBanner imageUrl={imageURL} altText="Banner image">
|
|
11
11
|
<h1>{childText}</h1>
|
|
@@ -16,4 +16,13 @@ describe('Hero component', () => {
|
|
|
16
16
|
expect(childElement).toBeInTheDocument();
|
|
17
17
|
expect(imageElement).toBeInTheDocument();
|
|
18
18
|
});
|
|
19
|
+
it('2. renders banner image and title without altText', () => {
|
|
20
|
+
const { getByAltText } = render(
|
|
21
|
+
<NsBanner imageUrl={imageURL}>
|
|
22
|
+
<h1>{childText}</h1>
|
|
23
|
+
</NsBanner>
|
|
24
|
+
);
|
|
25
|
+
const imageElement = getByAltText('NsBanner');
|
|
26
|
+
expect(imageElement).toBeInTheDocument();
|
|
27
|
+
});
|
|
19
28
|
});
|
|
@@ -5,7 +5,7 @@ import NSLogoMark from './icons/NSLogoMark';
|
|
|
5
5
|
import NSLogoPoweredBy from './icons/NSLogoPoweredBy';
|
|
6
6
|
import NSLogoStacked from './icons/NSLogoStacked';
|
|
7
7
|
import NSLogoWordMark from './icons/NSWordMark';
|
|
8
|
-
import LogoContainer from './
|
|
8
|
+
import LogoContainer from './NsBrandContainer.styled';
|
|
9
9
|
|
|
10
10
|
import { NsBrandComponentProps } from './types.d';
|
|
11
11
|
|
|
@@ -20,7 +20,7 @@ const VariantMap = {
|
|
|
20
20
|
const NsBrandComponent = (props: PropsWithChildren<NsBrandComponentProps>) => {
|
|
21
21
|
const { variant = 'stacked', size = '108px', color = 'primary' } = props;
|
|
22
22
|
const renderBrand = useCallback(() => {
|
|
23
|
-
const BrandComponent = VariantMap[variant
|
|
23
|
+
const BrandComponent = VariantMap[variant];
|
|
24
24
|
// [Todo - Add neutral as FoundationTheme.PaletteColor]
|
|
25
25
|
return <BrandComponent color={color as any} />;
|
|
26
26
|
}, [color, variant]);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import { NsBreadcrumb } from './';
|
|
4
|
-
import { breadcrumbItems } from './data';
|
|
4
|
+
import { breadcrumbItems, dummyItems } from './data';
|
|
5
5
|
const { getByText } = screen;
|
|
6
6
|
|
|
7
7
|
describe('Breadcrumb', () => {
|
|
8
|
-
it('renders breadcrumb items', () => {
|
|
8
|
+
it('1. renders breadcrumb items', () => {
|
|
9
9
|
render(<NsBreadcrumb items={breadcrumbItems} />);
|
|
10
10
|
expect(getByText('Home')).toBeInTheDocument();
|
|
11
11
|
expect(getByText('Products')).toBeInTheDocument();
|
|
@@ -13,11 +13,16 @@ describe('Breadcrumb', () => {
|
|
|
13
13
|
expect(getByText('Blue shirt')).toBeInTheDocument();
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
it('renders breadcrumb items with navigation icons', () => {
|
|
16
|
+
it('2. renders breadcrumb items with navigation icons', () => {
|
|
17
17
|
render(<NsBreadcrumb items={breadcrumbItems} iconVisibility />);
|
|
18
18
|
expect(getByText('Home')).toBeInTheDocument();
|
|
19
19
|
expect(getByText('Products')).toBeInTheDocument();
|
|
20
20
|
expect(getByText('Shirts')).toBeInTheDocument();
|
|
21
21
|
expect(getByText('Blue shirt')).toBeInTheDocument();
|
|
22
22
|
});
|
|
23
|
+
|
|
24
|
+
it('3. renders breadcrumb items with navigation icons', () => {
|
|
25
|
+
render(<NsBreadcrumb items={dummyItems} iconVisibility />);
|
|
26
|
+
expect(getByText('Home')).toBeInTheDocument();
|
|
27
|
+
});
|
|
23
28
|
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {ItemProps} from './types';
|
|
2
2
|
export const breadcrumbItems: ItemProps[] = [
|
|
3
|
-
{
|
|
4
|
-
{
|
|
5
|
-
{
|
|
6
|
-
{
|
|
3
|
+
{label: 'Home', href: '/', icon: 'home'},
|
|
4
|
+
{label: 'Products', href: '/products'},
|
|
5
|
+
{label: 'Shirts', href: '/products/shirts'},
|
|
6
|
+
{label: 'Blue shirt', href: '/products/shirts/blue'},
|
|
7
7
|
];
|
|
8
|
+
export const dummyItems: ItemProps[] = [
|
|
9
|
+
{label: 'Home', icon: 'home'}
|
|
10
|
+
]
|
|
@@ -1,68 +1,84 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render, screen } from '@/test-utils/index';
|
|
3
|
+
import { NsButton } from '../';
|
|
3
4
|
import { nuskinTheme } from '@nuskin/foundation-theme';
|
|
4
|
-
import Button from './NsButton';
|
|
5
5
|
|
|
6
6
|
const { palette } = nuskinTheme;
|
|
7
7
|
|
|
8
8
|
describe('<Button />', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
);
|
|
9
|
+
it('1. should render default primary button styles ', () => {
|
|
10
|
+
const text = 'Click Me';
|
|
11
|
+
render(
|
|
12
|
+
<NsButton color="primary" variant="contained">
|
|
13
|
+
{text}
|
|
14
|
+
</NsButton>
|
|
15
|
+
);
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
17
|
+
const button = screen.getByText(text);
|
|
18
|
+
expect(button).toBeInTheDocument();
|
|
19
|
+
expect(button).toHaveStyle(`color: ${palette?.primary?.contrastText}`);
|
|
20
|
+
expect(button).toHaveStyle(`background-color: ${palette?.primary?.buttonState?.pressed}`);
|
|
23
21
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
);
|
|
22
|
+
it('2. should render default secondary button styles', () => {
|
|
23
|
+
const text = 'Click Me';
|
|
24
|
+
render(
|
|
25
|
+
<NsButton color="success" variant="contained" size="large">
|
|
26
|
+
{text}
|
|
27
|
+
</NsButton>
|
|
28
|
+
);
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
const button = screen.getByText(text);
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
32
|
+
expect(button).toBeInTheDocument();
|
|
33
|
+
expect(button).toHaveStyle(`color: ${palette.success.contrastText}`);
|
|
34
|
+
expect(button).toHaveStyle(`background-color: ${palette.success.buttonState?.pressed}`);
|
|
39
35
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
36
|
+
it('3. should render outlined success button', () => {
|
|
37
|
+
render(
|
|
38
|
+
<NsButton color="success" variant="outlined" size="large">
|
|
39
|
+
Click Me
|
|
40
|
+
</NsButton>
|
|
41
|
+
);
|
|
47
42
|
|
|
48
|
-
|
|
43
|
+
const button = screen.getByText('Click Me');
|
|
44
|
+
expect(button).toBeInTheDocument();
|
|
45
|
+
expect(button).toHaveStyle(`color: ${palette.success.main}`);
|
|
46
|
+
});
|
|
47
|
+
it('4. should render outlined accentColorA button', () => {
|
|
48
|
+
render(
|
|
49
|
+
<NsButton color="accentColorA" variant="outlined" size="large">
|
|
50
|
+
Click Me
|
|
51
|
+
</NsButton>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const button = screen.getByText('Click Me');
|
|
55
|
+
expect(button).toBeInTheDocument();
|
|
56
|
+
expect(button).toHaveStyle(`color: ${palette?.accentColorA?.main}`);
|
|
57
|
+
});
|
|
58
|
+
it('5. should render text button styles', () => {
|
|
59
|
+
const text = 'Click Me';
|
|
60
|
+
render(
|
|
61
|
+
<NsButton color="success" variant="text" size="large">
|
|
62
|
+
{text}
|
|
63
|
+
</NsButton>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const button = screen.getByText(text);
|
|
49
67
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
});
|
|
68
|
+
expect(button).toBeInTheDocument();
|
|
69
|
+
expect(button).toHaveStyle(`color: ${palette.success.main}`);
|
|
53
70
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
it('6. iconOnly variant', () => {
|
|
72
|
+
const text = 'Click Me';
|
|
73
|
+
render(
|
|
74
|
+
<NsButton color="success" variant="text" size="large" iconOnly>
|
|
75
|
+
{text}
|
|
76
|
+
</NsButton>
|
|
77
|
+
);
|
|
61
78
|
|
|
62
|
-
|
|
79
|
+
const button = screen.getByText(text);
|
|
63
80
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
81
|
+
expect(button).toBeInTheDocument();
|
|
82
|
+
expect(button).toHaveStyle(`color: ${palette.success.main}`);
|
|
67
83
|
});
|
|
68
84
|
});
|
|
@@ -3,6 +3,11 @@ import type { StoryObj, Meta } from '@storybook/react';
|
|
|
3
3
|
import { NsButton } from './';
|
|
4
4
|
import { ShoppingCart } from '@mui/icons-material';
|
|
5
5
|
import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
|
|
6
|
+
import { within } from '@storybook/testing-library';
|
|
7
|
+
import { expect } from '@storybook/jest';
|
|
8
|
+
import { nuskinTheme } from '@nuskin/foundation-theme';
|
|
9
|
+
|
|
10
|
+
const { palette } = nuskinTheme;
|
|
6
11
|
|
|
7
12
|
type ComponentType = typeof NsButton;
|
|
8
13
|
type Story = StoryObj<ComponentType>;
|
|
@@ -21,7 +26,7 @@ export default {
|
|
|
21
26
|
color: { name: 'Color Variants' },
|
|
22
27
|
disabled: { control: 'boolean' },
|
|
23
28
|
fullWidth: { control: 'boolean' },
|
|
24
|
-
|
|
29
|
+
|
|
25
30
|
iconOnly: { control: 'hide' },
|
|
26
31
|
},
|
|
27
32
|
args: {
|
|
@@ -39,7 +44,7 @@ export default {
|
|
|
39
44
|
export const button: Story = {};
|
|
40
45
|
|
|
41
46
|
export const IconOnlyButton: Story = {
|
|
42
|
-
render: (args) => (
|
|
47
|
+
render: (args: any) => (
|
|
43
48
|
<NsButton {...args} iconOnly darkModeEnabled={false}>
|
|
44
49
|
<ShoppingCart />
|
|
45
50
|
</NsButton>
|
|
@@ -57,9 +62,8 @@ export const IconOnlyButton: Story = {
|
|
|
57
62
|
},
|
|
58
63
|
};
|
|
59
64
|
export const ButtonWithIcon: Story = {
|
|
60
|
-
render: (args) => (
|
|
65
|
+
render: (args: any) => (
|
|
61
66
|
<NsButton {...args} darkModeEnabled={false} startIcon={<ShoppingCart />}>
|
|
62
|
-
|
|
63
67
|
Add to Cart
|
|
64
68
|
</NsButton>
|
|
65
69
|
),
|
|
@@ -74,3 +78,35 @@ export const ButtonWithIcon: Story = {
|
|
|
74
78
|
},
|
|
75
79
|
};
|
|
76
80
|
|
|
81
|
+
export const TextVariant: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
color: 'success',
|
|
84
|
+
variant: 'text',
|
|
85
|
+
size: 'large',
|
|
86
|
+
children: 'click me! icon',
|
|
87
|
+
},
|
|
88
|
+
play: ({ canvasElement }) => {
|
|
89
|
+
const canvas = within(canvasElement);
|
|
90
|
+
const button = canvas.getByText('click me! icon');
|
|
91
|
+
expect(button).toBeInTheDocument();
|
|
92
|
+
expect(button).toHaveStyle(`color: ${palette.success.main}`);
|
|
93
|
+
expect(button).toHaveStyle('background-color: rgba(0, 0, 0, 0);');
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const IconOnly: Story = {
|
|
98
|
+
args: {
|
|
99
|
+
iconOnly: true,
|
|
100
|
+
color: 'success',
|
|
101
|
+
variant: 'text',
|
|
102
|
+
size: 'large',
|
|
103
|
+
children: 'click me! icon',
|
|
104
|
+
},
|
|
105
|
+
play: ({ canvasElement }) => {
|
|
106
|
+
const canvas = within(canvasElement);
|
|
107
|
+
const button = canvas.getByText('click me! icon');
|
|
108
|
+
expect(button).toBeInTheDocument();
|
|
109
|
+
expect(button).toHaveStyle(`color: ${palette.success.main}`);
|
|
110
|
+
expect(button).toHaveStyle('background-color: rgba(0, 0, 0, 0);');
|
|
111
|
+
},
|
|
112
|
+
};
|
|
@@ -4,6 +4,8 @@ import { styled, ColorUtils, FoundationTheme } from '@nuskin/foundation-theme';
|
|
|
4
4
|
import { ButtonConfig } from '@nuskin/foundation-theme/src/common/themes/types/button';
|
|
5
5
|
|
|
6
6
|
import { NsButtonProps } from './types.d';
|
|
7
|
+
import { generateContainedStyle, generateIconOnlyStyles, generateOutlinedStyle, generateTextStyles } from './helper';
|
|
8
|
+
import { skipDarkModeEnabled } from '../util';
|
|
7
9
|
|
|
8
10
|
const { buttonColor, paletteColor } = ColorUtils;
|
|
9
11
|
|
|
@@ -11,79 +13,60 @@ const getButtonConfig = (theme: FoundationTheme.Theme, attribute: keyof ButtonCo
|
|
|
11
13
|
const { config } = theme || {};
|
|
12
14
|
return config?.components?.button?.[attribute] || '';
|
|
13
15
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const options = {
|
|
17
|
+
shouldForwardProp: skipDarkModeEnabled,
|
|
18
|
+
};
|
|
19
|
+
const StyledButton = styled(MUIButton, options)<NsButtonProps>`
|
|
16
20
|
gap: 10px;
|
|
17
|
-
border-radius: ${({ theme }) =>
|
|
18
|
-
|
|
21
|
+
border-radius: ${({ theme }) => {
|
|
22
|
+
const borderRadius = getButtonConfig(theme, 'borderRadius');
|
|
23
|
+
return borderRadius || 0;
|
|
24
|
+
}};
|
|
25
|
+
|
|
26
|
+
&:focus {
|
|
19
27
|
border: 1px solid ${({ theme }) => getButtonConfig(theme, 'focusColor')} !important;
|
|
20
28
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
color: ${(
|
|
29
|
+
|
|
30
|
+
&:disabled {
|
|
31
|
+
background-color: ${({ color }) => buttonColor(color, 'disabled')};
|
|
32
|
+
color: ${({ color }) => buttonColor(color, 'disabledText')};
|
|
24
33
|
}
|
|
34
|
+
|
|
25
35
|
${({ theme: { config }, size }) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
if (size === 'medium') {
|
|
37
|
+
return config?.components?.button?.size?.medium?.padding;
|
|
38
|
+
} else if (size === 'large') {
|
|
39
|
+
return config?.components?.button?.size?.large?.padding;
|
|
40
|
+
} else {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
30
43
|
}}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
|
|
45
|
+
${({ variant, theme, color = 'primary', darkModeEnabled, iconOnly }) => {
|
|
46
|
+
if (variant === 'contained') {
|
|
47
|
+
const hovered = buttonColor(color, 'hovered')({ theme });
|
|
48
|
+
const pressed = buttonColor(color, 'pressed')({ theme });
|
|
49
|
+
const focused = buttonColor(color, 'focused')({ theme });
|
|
50
|
+
const textColor = paletteColor(color, 'contrastText')({ theme, darkModeEnabled });
|
|
51
|
+
const backgroundColor = paletteColor(color)({ theme, darkModeEnabled });
|
|
52
|
+
return generateContainedStyle({ backgroundColor, textColor, hovered, pressed, focused });
|
|
53
|
+
} else if (variant === 'outlined') {
|
|
54
|
+
const borderColor = paletteColor(color)({ theme, darkModeEnabled });
|
|
55
|
+
const activeColor = paletteColor(color)({ theme });
|
|
56
|
+
const hovered = buttonColor(color, 'hovered')({ theme });
|
|
57
|
+
const pressed = buttonColor(color, 'pressed')({ theme });
|
|
58
|
+
return generateOutlinedStyle({ borderColor, hovered, pressed, activeColor });
|
|
59
|
+
} else if (variant === 'text') {
|
|
60
|
+
const underlineColor = paletteColor(color)({ theme, darkModeEnabled });
|
|
61
|
+
const hovered = buttonColor(color, 'hovered')({ theme });
|
|
62
|
+
const pressed = buttonColor(color, 'pressed')({ theme });
|
|
63
|
+
return generateTextStyles({ underlineColor, hovered, pressed });
|
|
64
|
+
} else if (iconOnly) {
|
|
65
|
+
return generateIconOnlyStyles();
|
|
66
|
+
} else {
|
|
67
|
+
return '';
|
|
68
|
+
}
|
|
47
69
|
}}
|
|
48
|
-
${({ variant, theme, color = 'primary', darkModeEnabled }) =>
|
|
49
|
-
variant === 'outlined' &&
|
|
50
|
-
`
|
|
51
|
-
border-color: ${paletteColor(color)({ theme, darkModeEnabled })};
|
|
52
|
-
color: ${paletteColor(color)({ theme, darkModeEnabled })};
|
|
53
|
-
:hover {
|
|
54
|
-
border-color: ${buttonColor(color, 'hovered')({ theme })};
|
|
55
|
-
color: ${paletteColor(color)({ theme, darkModeEnabled })};
|
|
56
|
-
}
|
|
57
|
-
:active {
|
|
58
|
-
border-color: ${buttonColor(color, 'pressed')({ theme })};
|
|
59
|
-
color: ${paletteColor(color)({ theme })};
|
|
60
|
-
}
|
|
61
|
-
`}
|
|
62
|
-
${({ variant, theme, color = 'primary', darkModeEnabled }) =>
|
|
63
|
-
variant === 'text' &&
|
|
64
|
-
`
|
|
65
|
-
text-decoration: underline 1px !important;
|
|
66
|
-
text-underline-offset: 4px;
|
|
67
|
-
padding: 0;
|
|
68
|
-
min-width: auto;
|
|
69
|
-
background-color: transparent !important;
|
|
70
|
-
text-decoration-color: ${paletteColor(color)({ theme, darkModeEnabled })};
|
|
71
|
-
color: ${paletteColor(color)({ theme, darkModeEnabled })};
|
|
72
|
-
:hover {
|
|
73
|
-
color: ${buttonColor(color, 'hovered')({ theme })};
|
|
74
|
-
text-decoration-color: ${buttonColor(color, 'hovered')({ theme })};
|
|
75
|
-
}
|
|
76
|
-
:active {
|
|
77
|
-
color: ${paletteColor(color)};
|
|
78
|
-
text-decoration-color: ${buttonColor(color, 'pressed')({ theme })};
|
|
79
|
-
}
|
|
80
|
-
`}
|
|
81
|
-
${({ iconOnly }) =>
|
|
82
|
-
iconOnly &&
|
|
83
|
-
`
|
|
84
|
-
padding: 10px;
|
|
85
|
-
min-width: unset;
|
|
86
|
-
`}
|
|
87
70
|
`;
|
|
88
71
|
|
|
89
72
|
export default StyledButton;
|
|
@@ -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}
|