@nuskin/foundation-ui-components 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +18 -14
- package/src/common/accordion/NsAccordion.tsx +32 -40
- package/src/common/accordion/NsAccordionHeader.tsx +29 -8
- package/src/common/accordion/NsAccordionItem.tsx +24 -4
- package/src/common/accordion/NsCollapse.tsx +96 -35
- package/src/common/accordion/NsToggleSection.tsx +16 -3
- package/src/common/accordion/ToggleSection.styled.tsx +11 -7
- package/src/common/accordion/colorMap.ts +117 -0
- package/src/common/accordion/enums.ts +18 -0
- package/src/common/accordion/index.ts +1 -0
- package/src/common/accordion/specs/NsAccordion.spec.tsx +101 -31
- package/src/common/accordion/specs/NsAccordionHeader.spec.tsx +77 -10
- package/src/common/accordion/specs/NsAccordionItem.spec.tsx +27 -10
- package/src/common/accordion/specs/NsCollapse.spec.tsx +109 -17
- package/src/common/accordion/specs/NsToggleSection.spec.tsx +50 -14
- package/src/common/accordion/stories/NsAccordion.stories.tsx +31 -13
- package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +5 -1
- package/src/common/accordion/stories/NsAccordionItem.stories.tsx +8 -3
- package/src/common/accordion/stories/NsCollapse.stories.tsx +19 -4
- package/src/common/accordion/stories/NsToggleSection.stories.tsx +6 -3
- package/src/common/accordion/stories/data.tsx +140 -19
- package/src/common/accordion/types.d.ts +55 -47
- package/src/common/alert/Header.tsx +29 -0
- package/src/common/alert/NsAlert.spec.tsx +46 -13
- package/src/common/alert/NsAlert.stories.tsx +1 -1
- package/src/common/alert/{NsAlert.styled.ts → NsAlert.styled.tsx} +22 -22
- package/src/common/alert/NsAlert.tsx +22 -87
- package/src/common/alert/types.d.ts +7 -7
- package/src/common/auth-dropdown/NsAuthDropdown.spec.tsx +23 -5
- package/src/common/auth-dropdown/NsAuthDropdown.styled.ts +9 -2
- package/src/common/auth-dropdown/NsAuthDropdown.tsx +11 -6
- package/src/common/autocomplete/NsAutocomplete.spec.tsx +37 -14
- package/src/common/autocomplete/NsAutocomplete.stories.tsx +18 -2
- package/src/common/autocomplete/NsAutocomplete.tsx +63 -24
- package/src/common/autocomplete/mock/MockData.ts +51 -7
- package/src/common/autocomplete/mock/MockUI.tsx +2 -1
- package/src/common/autocomplete/types.d.ts +7 -4
- package/src/common/banner/NsBanner.spec.tsx +12 -3
- package/src/common/brand-components/NsBrandComponent.tsx +2 -2
- package/src/common/breadcrumb/NsBreadcrumb.spec.tsx +8 -3
- package/src/common/breadcrumb/data.ts +8 -5
- package/src/common/button/NsButton.spec.tsx +65 -49
- package/src/common/button/NsButton.stories.tsx +39 -4
- package/src/common/button/NsButton.styled.tsx +49 -66
- package/src/common/button/NsButton.tsx +1 -2
- package/src/common/button/helper.ts +82 -0
- package/src/common/card/NsFfgCard.tsx +13 -7
- package/src/common/card/specs/NsFfgCard.spec.tsx +18 -8
- package/src/common/card/stories/NsFfgCard.stories.tsx +47 -14
- package/src/common/card/styled/NsFfgStyled.tsx +9 -7
- package/src/common/card/types.d.ts +7 -4
- package/src/common/cart-icon/NsCartIcon.spec.tsx +7 -18
- package/src/common/cart-icon/NsCartIcon.stories.tsx +1 -1
- package/src/common/cart-icon/NsCartIcon.styled.ts +7 -33
- package/src/common/cart-icon/NsCartIcon.tsx +5 -14
- package/src/common/cart-icon/types.d.ts +1 -0
- package/src/common/checkbox/NsCheckbox.styled.tsx +15 -16
- package/src/common/checkbox/NsCheckbox.tsx +1 -1
- package/src/common/checkbox/types.d.ts +1 -1
- package/src/common/column-control/styled/common.ts +1 -1
- package/src/common/column-control/utils.ts +4 -4
- package/src/common/common.types.d.ts +14 -5
- package/src/common/dropdown/NsDropdown.styled.tsx +23 -18
- package/src/common/dropdown/NsDropdown.tsx +7 -2
- package/src/common/hooks/index.ts +2 -0
- package/src/common/hooks/specs/useWindowSize.spec.tsx +19 -0
- package/src/common/hooks/useAccordionMap.tsx +39 -0
- package/src/common/hooks/useOnClickOutside.tsx +25 -0
- package/src/common/hooks/useWindowSize.tsx +30 -0
- package/src/common/icon/NsIcon.spec.tsx +1 -1
- package/src/common/icon/NsIcon.stories.tsx +3 -0
- package/src/common/icon/NsIcon.tsx +6 -2
- package/src/common/icon/NsIconVariants.ts +3 -0
- package/src/common/icon/icons/AlertErrorIcon.tsx +2 -2
- package/src/common/icon/icons/ArrowLeft.tsx +3 -6
- package/src/common/icon/icons/ArrowRight.tsx +6 -8
- package/src/common/icon/icons/Cart.tsx +7 -32
- package/src/common/icon/icons/CartBadge.tsx +2 -2
- package/src/common/icon/icons/CloseIcon.tsx +1 -1
- package/src/common/icon/icons/ErrorIcon.tsx +2 -2
- package/src/common/icon/icons/HamburgerIcon.tsx +5 -2
- package/src/common/icon/icons/SearchIcon.tsx +1 -1
- package/src/common/icon/icons/SuccessIcon.tsx +2 -7
- package/src/common/icon/icons/TrashIcon.tsx +1 -1
- package/src/common/icon/icons/UserIcon.tsx +3 -6
- package/src/common/icon/icons/UserOutline.tsx +24 -0
- package/src/common/icon/icons/WarningIcon.tsx +1 -1
- package/src/common/icon/icons/home.tsx +1 -1
- package/src/common/image/NsImage.spec.tsx +56 -6
- package/src/common/image/NsImage.tsx +23 -11
- package/src/common/index.ts +7 -3
- package/src/common/input/InputWrapper.tsx +12 -7
- package/src/common/input/NsInputField.tsx +1 -1
- package/src/common/label/NsLabel.stories.tsx +0 -3
- package/src/common/label/NsLabel.tsx +1 -1
- package/src/common/modal/NsModal.spec.tsx +46 -0
- package/src/common/modal/NsModal.styled.tsx +28 -0
- package/src/common/modal/NsModal.tsx +37 -0
- package/src/common/modal/helper-component/NsModalContentBox.tsx +32 -0
- package/src/common/modal/helper-component/NsModalDefault.tsx +25 -0
- package/src/common/modal/helper-component/NsModalStatus.tsx +15 -0
- package/src/common/modal/helper-component/NsModalStatusIcon.tsx +14 -0
- package/src/common/modal/helper-component/NsModalTitle.tsx +26 -0
- package/src/common/modal/index.ts +2 -0
- package/src/common/modal/model/NsModalVariantMap.tsx +24 -0
- package/src/common/modal/stories/NsModal.stories.tsx +85 -0
- package/src/common/modal/stories/mock.tsx +46 -0
- package/src/common/modal/types.ts +56 -0
- package/src/common/nav-tab/NavDrawer.tsx +34 -0
- package/src/common/nav-tab/NavTitles.tsx +52 -0
- package/src/common/nav-tab/NsNavTab.spec.tsx +4 -5
- package/src/common/nav-tab/NsNavTab.stories.tsx +3 -3
- package/src/common/nav-tab/NsNavTab.styled.tsx +13 -7
- package/src/common/nav-tab/NsNavTab.tsx +21 -75
- package/src/common/nav-tab/index.ts +1 -1
- package/src/common/nav-tab/types.d.ts +3 -3
- package/src/common/progress/NsProgress.spec.tsx +47 -0
- package/src/common/progress/NsProgress.stories.tsx +37 -0
- package/src/common/progress/NsProgress.styled.tsx +39 -0
- package/src/common/progress/NsProgress.tsx +27 -0
- package/src/common/progress/index.ts +2 -0
- package/src/common/progress/types.d.ts +21 -0
- package/src/common/radiogroup/NsRadioGroup.spec.tsx +24 -25
- package/src/common/radiogroup/NsRadioGroup.stories.tsx +13 -31
- package/src/common/radiogroup/NsRadioGroup.styled.tsx +17 -15
- package/src/common/radiogroup/NsRadioGroup.tsx +6 -5
- package/src/common/search-bar/NsSearchBar.tsx +1 -3
- package/src/common/select/NsSelect.spec.tsx +107 -33
- package/src/common/select/NsSelect.styled.tsx +89 -39
- package/src/common/select/NsSelect.tsx +109 -44
- package/src/common/select/NsSelectOption.tsx +0 -1
- package/src/common/select/stories/NsSelect.stories.tsx +33 -24
- package/src/common/select/types.d.ts +6 -4
- package/src/common/spinner/NsSpinner.spec.tsx +21 -0
- package/src/common/spinner/NsSpinner.stories.tsx +26 -0
- package/src/common/spinner/NsSpinner.styled.tsx +344 -0
- package/src/common/spinner/NsSpinner.tsx +14 -0
- package/src/common/spinner/icons/Spinner.tsx +161 -0
- package/src/common/spinner/index.ts +2 -0
- package/src/common/spinner/types.ts +5 -0
- package/src/common/table/NsTable.tsx +32 -49
- package/src/common/table/NsTableHeader.tsx +30 -51
- package/src/common/util.ts +1 -0
- package/src/common/utility/Show.tsx +13 -0
- package/src/common/utility/index.ts +1 -0
- package/src/common/videos/types.d.ts +1 -1
- /package/src/common/brand-components/{NsBrandContanier.styled.tsx → NsBrandContainer.styled.tsx} +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* eslint-disable @next/next/no-img-element */
|
|
2
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
3
|
+
import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
|
|
4
|
+
import NsModal from '../NsModal';
|
|
5
|
+
import { NsButton } from '../../button';
|
|
6
|
+
import { Grid, Typography } from '@mui/material';
|
|
7
|
+
import { useState } from 'react';
|
|
8
|
+
import { NsModalProps } from '../types';
|
|
9
|
+
import { NsModalData } from './mock';
|
|
10
|
+
|
|
11
|
+
type ComponentType = typeof NsModal;
|
|
12
|
+
type Story = StoryObj<ComponentType>;
|
|
13
|
+
type MetaStory = Meta<ComponentType>;
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
title: 'Components/NsModal',
|
|
17
|
+
component: NsModal,
|
|
18
|
+
decorators: [withCenterDecorator],
|
|
19
|
+
argTypes: {},
|
|
20
|
+
args: {
|
|
21
|
+
...NsModalData,
|
|
22
|
+
},
|
|
23
|
+
} as MetaStory;
|
|
24
|
+
|
|
25
|
+
const RenderNsModal = (args: NsModalProps) => {
|
|
26
|
+
const [isOpen, setOpen] = useState(false);
|
|
27
|
+
|
|
28
|
+
const onModalHandler = () => {
|
|
29
|
+
setOpen(!isOpen);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<NsButton onClick={onModalHandler}>Open Modal</NsButton>
|
|
35
|
+
<NsModal {...args} open={isOpen} handleClose={onModalHandler} />
|
|
36
|
+
</>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Modal: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
header: {
|
|
43
|
+
...NsModalData?.header,
|
|
44
|
+
isCloseIcon: false,
|
|
45
|
+
},
|
|
46
|
+
} as NsModalProps,
|
|
47
|
+
render: RenderNsModal,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const WithCloseIcon: Story = {
|
|
51
|
+
render: RenderNsModal,
|
|
52
|
+
};
|
|
53
|
+
const imageURL =
|
|
54
|
+
'https://www.nuskin.com/content/products/01/55/00/01550014/_jcr_content/fullImage.img.160.160.png.64.64.png';
|
|
55
|
+
export const ImageWidthText: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
header: {
|
|
58
|
+
show: true,
|
|
59
|
+
isCloseIcon: true,
|
|
60
|
+
},
|
|
61
|
+
body: {
|
|
62
|
+
show: true,
|
|
63
|
+
children: (
|
|
64
|
+
<Grid container spacing={2}>
|
|
65
|
+
<Grid xs={6}>
|
|
66
|
+
<img src={imageURL} alt={'NsImage'} />
|
|
67
|
+
</Grid>
|
|
68
|
+
<Grid xs={6} className="p-5">
|
|
69
|
+
<Typography gutterBottom variant="h5" component="div">
|
|
70
|
+
Lizard
|
|
71
|
+
</Typography>
|
|
72
|
+
<Typography variant="body2" color="text.secondary">
|
|
73
|
+
Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging across
|
|
74
|
+
all continents except Antarctica
|
|
75
|
+
</Typography>
|
|
76
|
+
</Grid>
|
|
77
|
+
</Grid>
|
|
78
|
+
),
|
|
79
|
+
},
|
|
80
|
+
footer: {
|
|
81
|
+
show: false,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
render: RenderNsModal,
|
|
85
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { NsButton } from '../../button';
|
|
2
|
+
import { NsTypography } from '../../typography';
|
|
3
|
+
|
|
4
|
+
export const NsModalData = {
|
|
5
|
+
open: true,
|
|
6
|
+
handleClose: () => {},
|
|
7
|
+
variant: 'default',
|
|
8
|
+
header: {
|
|
9
|
+
show: true,
|
|
10
|
+
children: (
|
|
11
|
+
<NsTypography variant="h4" weight="bold">
|
|
12
|
+
Dialog with hero icon
|
|
13
|
+
</NsTypography>
|
|
14
|
+
),
|
|
15
|
+
isCloseIcon: true,
|
|
16
|
+
iconName: 'infoOutlined',
|
|
17
|
+
},
|
|
18
|
+
body: {
|
|
19
|
+
show: true,
|
|
20
|
+
children: (
|
|
21
|
+
<NsTypography variant="p-s">
|
|
22
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquet sed odio donec tellus nibh dictum quis.
|
|
23
|
+
Dis tempus aliquam tristique auctor justo, lacus in pellentesque. Quam semper facilisi posuere hendrerit
|
|
24
|
+
scelerisque sed.
|
|
25
|
+
</NsTypography>
|
|
26
|
+
),
|
|
27
|
+
},
|
|
28
|
+
statusInfo: {
|
|
29
|
+
title: 'Are you sure you want to delete your account?',
|
|
30
|
+
description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit,
|
|
31
|
+
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`,
|
|
32
|
+
},
|
|
33
|
+
footer: {
|
|
34
|
+
show: true,
|
|
35
|
+
children: (
|
|
36
|
+
<>
|
|
37
|
+
<NsButton onClick={() => {}} variant="outlined">
|
|
38
|
+
Cancel
|
|
39
|
+
</NsButton>
|
|
40
|
+
<NsButton onClick={() => {}} variant="contained">
|
|
41
|
+
Confirm
|
|
42
|
+
</NsButton>
|
|
43
|
+
</>
|
|
44
|
+
),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { NsIconNameType } from '../icon';
|
|
3
|
+
|
|
4
|
+
export interface DialogTitleProps {
|
|
5
|
+
id: string;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface NsModalProps extends NsModalComponentProps {
|
|
11
|
+
open: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface NsModalComponentProps {
|
|
15
|
+
handleClose?: () => void;
|
|
16
|
+
additionalProps?: NsModalAdditionalProps;
|
|
17
|
+
variant?: NsModalVariant | 'default';
|
|
18
|
+
header?: NsModalContentProps;
|
|
19
|
+
body?: NsModalContentProps;
|
|
20
|
+
footer?: NsModalContentProps;
|
|
21
|
+
statusInfo?: NsModalStatusProps;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface NsModalContentProps {
|
|
25
|
+
show?: boolean;
|
|
26
|
+
children?: string | ReactNode;
|
|
27
|
+
isCloseIcon?: boolean;
|
|
28
|
+
iconName?: NsIconNameType;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface NsModalStatusProps {
|
|
32
|
+
title: string;
|
|
33
|
+
description: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface NsModalAdditionalProps {
|
|
37
|
+
className?: string;
|
|
38
|
+
scrollType?: 'paper' | 'body';
|
|
39
|
+
ariaLabel?: NsModalAriaLabelProps;
|
|
40
|
+
dividers?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface NsModalAriaLabelProps {
|
|
44
|
+
ariaLabelledby?: string;
|
|
45
|
+
ariaDescribedby?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type NsModalVariant = 'success' | 'warning' | 'error' | 'info';
|
|
49
|
+
|
|
50
|
+
export interface StatusIconMapProps {
|
|
51
|
+
success: string;
|
|
52
|
+
warning: string;
|
|
53
|
+
error: string;
|
|
54
|
+
info: string;
|
|
55
|
+
default?: string;
|
|
56
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { Show } from '../utility';
|
|
3
|
+
import { NavDrawerContainer, NavDrawerStyled } from './NsNavTab.styled';
|
|
4
|
+
|
|
5
|
+
type NavDrawerProps = {
|
|
6
|
+
active: string | null;
|
|
7
|
+
showDrawer: boolean;
|
|
8
|
+
content: ReactNode;
|
|
9
|
+
};
|
|
10
|
+
export const NavDrawer = ({ active, showDrawer, content }: NavDrawerProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<NavDrawerStyled data-testid="nav-drawer-container" className="nav-drawer">
|
|
13
|
+
<Show when={Boolean(active) && showDrawer}>
|
|
14
|
+
<NavDrawerContainer
|
|
15
|
+
data-testid="nav-drawer"
|
|
16
|
+
initial={{
|
|
17
|
+
height: 0,
|
|
18
|
+
}}
|
|
19
|
+
animate={{
|
|
20
|
+
height: 'auto',
|
|
21
|
+
}}
|
|
22
|
+
exit={{
|
|
23
|
+
height: 0,
|
|
24
|
+
}}
|
|
25
|
+
transition={{
|
|
26
|
+
duration: 0.3,
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
<div className="drawer-container">{content}</div>
|
|
30
|
+
</NavDrawerContainer>
|
|
31
|
+
</Show>
|
|
32
|
+
</NavDrawerStyled>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NsTypography } from '../';
|
|
2
|
+
import { NavTabBox, NavTabUnderLine, NavTitlesBox } from './NsNavTab.styled';
|
|
3
|
+
import { Show } from '../utility';
|
|
4
|
+
|
|
5
|
+
type NavTitlesProps = {
|
|
6
|
+
tabs: any[];
|
|
7
|
+
// eslint-disable-next-line no-unused-vars
|
|
8
|
+
setActive(_x: string): void;
|
|
9
|
+
active: string | null;
|
|
10
|
+
tabTitleClassName?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const NavTitles = ({ tabs, setActive, active, tabTitleClassName }: NavTitlesProps) => {
|
|
14
|
+
return (
|
|
15
|
+
<NavTitlesBox className="desktop-nav-titles">
|
|
16
|
+
{tabs?.map((tab) => {
|
|
17
|
+
const handleMouseEnter = () => {
|
|
18
|
+
setActive(tab.tabName);
|
|
19
|
+
};
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
key={tab?.tabName}
|
|
23
|
+
data-testid={tab?.tabName}
|
|
24
|
+
className="relative cursor-pointer"
|
|
25
|
+
onMouseEnter={handleMouseEnter}
|
|
26
|
+
>
|
|
27
|
+
<NavTabBox
|
|
28
|
+
className="nav-tab-box"
|
|
29
|
+
data-testid={tab.tabName + '-list'}
|
|
30
|
+
transition={{
|
|
31
|
+
duration: 0.3,
|
|
32
|
+
}}
|
|
33
|
+
animate
|
|
34
|
+
>
|
|
35
|
+
<NsTypography
|
|
36
|
+
variant={tab.textVariant}
|
|
37
|
+
additionalProps={{ ...tab?.liveTag }}
|
|
38
|
+
className={`${tabTitleClassName} ${!active ? 'opacity-8' : ''}`}
|
|
39
|
+
color={tab.tabName === active ? tab.activeColor : tab.color}
|
|
40
|
+
>
|
|
41
|
+
{tab.tabName}
|
|
42
|
+
</NsTypography>
|
|
43
|
+
</NavTabBox>
|
|
44
|
+
<Show when={active === tab.tabName}>
|
|
45
|
+
<NavTabUnderLine data-testid="underline" layoutId="underline" color={tab.activeColor} />
|
|
46
|
+
</Show>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
})}
|
|
50
|
+
</NavTitlesBox>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { fireEvent } from '@testing-library/react';
|
|
2
2
|
import { NsNavTabComponent } from './NsNavTab';
|
|
3
|
-
import { NavTabs } from './types
|
|
3
|
+
import { NavTabs } from './types';
|
|
4
4
|
import { render } from '@/test-utils/index';
|
|
5
5
|
|
|
6
6
|
const tabs: NavTabs[] = [
|
|
7
7
|
{
|
|
8
8
|
tabName: 'Skin & Beauty',
|
|
9
9
|
tabContent: <>Skin & Beauty</>,
|
|
10
|
-
color: 'primary',
|
|
11
10
|
activeColor: 'success',
|
|
12
11
|
textVariant: 'h5',
|
|
13
12
|
},
|
|
@@ -37,7 +36,7 @@ const tabs: NavTabs[] = [
|
|
|
37
36
|
describe('Nav Bar Component', () => {
|
|
38
37
|
it('1. should render Nav Bar Component with variant', () => {
|
|
39
38
|
const { container } = render(
|
|
40
|
-
<NsNavTabComponent tabTitleClassName="text-center"
|
|
39
|
+
<NsNavTabComponent tabTitleClassName="text-center" className="mb-2" tabs={tabs} />
|
|
41
40
|
);
|
|
42
41
|
const li = container.querySelectorAll('li');
|
|
43
42
|
expect(li.length).toBe(4);
|
|
@@ -45,7 +44,7 @@ describe('Nav Bar Component', () => {
|
|
|
45
44
|
expect(container).toBeInTheDocument();
|
|
46
45
|
});
|
|
47
46
|
|
|
48
|
-
it('should
|
|
47
|
+
it('2. should open and close the drawer', () => {
|
|
49
48
|
const { container, getByTestId } = render(<NsNavTabComponent showDrawer className="mb-2" tabs={tabs} />);
|
|
50
49
|
const li = container.querySelectorAll('li');
|
|
51
50
|
expect(li.length).toBe(4);
|
|
@@ -57,7 +56,7 @@ describe('Nav Bar Component', () => {
|
|
|
57
56
|
expect(getByTestId('nav-drawer-container').firstChild).not.toBeInTheDocument();
|
|
58
57
|
});
|
|
59
58
|
|
|
60
|
-
it('should show the underline on hover', () => {
|
|
59
|
+
it('3. should show the underline on hover', () => {
|
|
61
60
|
const { getByTestId } = render(<NsNavTabComponent showDrawer={false} className="mb-2" tabs={tabs} />);
|
|
62
61
|
fireEvent.mouseOver(getByTestId('Skin & Beauty'));
|
|
63
62
|
expect(getByTestId('underline')).toBeInTheDocument();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
2
|
import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
|
|
3
|
-
import { NsNavTab } from '
|
|
3
|
+
import { NsNavTab } from '.';
|
|
4
4
|
|
|
5
5
|
type ComponentType = typeof NsNavTab;
|
|
6
6
|
type Story = StoryObj<ComponentType>;
|
|
@@ -19,14 +19,14 @@ export default {
|
|
|
19
19
|
tabName: 'Tab One',
|
|
20
20
|
activeColor: 'info',
|
|
21
21
|
color: 'primary',
|
|
22
|
-
tabContent: '
|
|
22
|
+
tabContent: 'Tab one content',
|
|
23
23
|
textVariant: 'h5',
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
tabName: 'Tab Two',
|
|
27
27
|
activeColor: 'info',
|
|
28
28
|
color: 'primary',
|
|
29
|
-
tabContent: '
|
|
29
|
+
tabContent: 'Tab two content',
|
|
30
30
|
textVariant: 'h5',
|
|
31
31
|
},
|
|
32
32
|
],
|
|
@@ -3,14 +3,13 @@ import { motion } from 'framer-motion';
|
|
|
3
3
|
|
|
4
4
|
const { paletteColor } = ColorUtils;
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
export const NavTabContainer = styled.div`
|
|
8
7
|
.shadow {
|
|
9
8
|
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.15);
|
|
10
9
|
}
|
|
11
10
|
`;
|
|
12
11
|
|
|
13
|
-
export const
|
|
12
|
+
export const NavTabBox = styled(motion.li)`
|
|
14
13
|
margin: 0px 14px;
|
|
15
14
|
align-items: center;
|
|
16
15
|
white-space: normal;
|
|
@@ -19,17 +18,17 @@ export const NavTabLine = styled(motion.li)`
|
|
|
19
18
|
list-style: none;
|
|
20
19
|
position: relative;
|
|
21
20
|
min-width: 60px;
|
|
21
|
+
padding: 8px 4px;
|
|
22
22
|
`;
|
|
23
23
|
|
|
24
24
|
export const NavTabUnderLine = styled(motion.div)<{ color?: FoundationTheme.PaletteColors }>`
|
|
25
25
|
width: 100%;
|
|
26
26
|
position: absolute;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
background-color: ${({ theme, color = 'primary' }) => paletteColor(color)({ theme })};
|
|
27
|
+
height: 3px;
|
|
28
|
+
background-color: ${({ theme, color }) => paletteColor(color)({ theme })};
|
|
30
29
|
`;
|
|
31
30
|
|
|
32
|
-
export const
|
|
31
|
+
export const NavDrawerStyled = styled.div`
|
|
33
32
|
position: absolute;
|
|
34
33
|
left: 0;
|
|
35
34
|
display: flex;
|
|
@@ -63,6 +62,13 @@ export const NavDrawerContainer = styled(motion.div)`
|
|
|
63
62
|
max-height: 590px;
|
|
64
63
|
overflow: auto;
|
|
65
64
|
.drawer-container {
|
|
66
|
-
max-width:
|
|
65
|
+
max-width: 1024px;
|
|
66
|
+
margin: 0 auto;
|
|
67
|
+
overflow: hidden;
|
|
67
68
|
}
|
|
68
69
|
`;
|
|
70
|
+
|
|
71
|
+
export const NavTitlesBox = styled.div`
|
|
72
|
+
display: flex;
|
|
73
|
+
height: 39px;
|
|
74
|
+
`;
|
|
@@ -1,89 +1,35 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
2
2
|
import { LayoutGroup } from 'framer-motion';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { NavTabContainer } from './NsNavTab.styled';
|
|
4
|
+
import { NavDrawer } from './NavDrawer';
|
|
5
|
+
import { NsNavTabComponentProps } from './types.d';
|
|
6
|
+
import { NavTitles } from './NavTitles';
|
|
6
7
|
|
|
7
|
-
export const NsNavTabComponent = (
|
|
8
|
-
|
|
8
|
+
export const NsNavTabComponent = ({
|
|
9
|
+
tabs,
|
|
10
|
+
className,
|
|
11
|
+
tabTitleClassName,
|
|
12
|
+
showDrawer = true,
|
|
13
|
+
}: NsNavTabComponentProps) => {
|
|
9
14
|
const [active, setActive] = useState<string | null>(null);
|
|
10
15
|
|
|
11
16
|
const activeTab = tabs?.find((tab) => tab.tabName === active);
|
|
12
17
|
|
|
13
|
-
const handleLeave = () => {
|
|
18
|
+
const handleLeave = useCallback(() => {
|
|
14
19
|
setActive(null);
|
|
15
|
-
};
|
|
20
|
+
}, []);
|
|
16
21
|
|
|
17
22
|
return (
|
|
18
|
-
<NavTabContainer data-testid="nav-container" className={className}>
|
|
23
|
+
<NavTabContainer data-testid="nav-container" className={`${className} ns-nav-tab-component`}>
|
|
19
24
|
<LayoutGroup>
|
|
20
25
|
<div onMouseLeave={handleLeave} data-testid="nav-container-draw" className="p-0 m-0">
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<div
|
|
29
|
-
key={tab?.tabName}
|
|
30
|
-
data-testid={tab?.tabName}
|
|
31
|
-
className="relative cursor-pointer"
|
|
32
|
-
onMouseEnter={handleMouseEnter}
|
|
33
|
-
>
|
|
34
|
-
<NavTabLine
|
|
35
|
-
data-testid={tab.tabName + '-list'}
|
|
36
|
-
transition={{
|
|
37
|
-
duration: 0.3,
|
|
38
|
-
}}
|
|
39
|
-
animate
|
|
40
|
-
>
|
|
41
|
-
<NsTypography
|
|
42
|
-
variant={tab.textVariant}
|
|
43
|
-
additionalProps={{ ...tab?.liveTag }}
|
|
44
|
-
className={`mb-2 ${tabTitleClassName} ${!active ? 'opacity-8' : ''}`}
|
|
45
|
-
color={tab.tabName === active ? tab.activeColor : tab.color}
|
|
46
|
-
>
|
|
47
|
-
{tab.tabName}
|
|
48
|
-
</NsTypography>
|
|
49
|
-
</NavTabLine>
|
|
50
|
-
{active === tab.tabName && (
|
|
51
|
-
<NavTabUnderLine
|
|
52
|
-
data-testid="underline"
|
|
53
|
-
layoutId="underline"
|
|
54
|
-
color={tab.activeColor}
|
|
55
|
-
/>
|
|
56
|
-
)}
|
|
57
|
-
</div>
|
|
58
|
-
);
|
|
59
|
-
})}
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
<NavDrawer data-testid="nav-drawer-container">
|
|
63
|
-
{active && showDrawer ? (
|
|
64
|
-
<NavDrawerContainer
|
|
65
|
-
data-testid="nav-drawer"
|
|
66
|
-
initial={{
|
|
67
|
-
height: 0,
|
|
68
|
-
}}
|
|
69
|
-
animate={{
|
|
70
|
-
height: 'auto',
|
|
71
|
-
}}
|
|
72
|
-
exit={{
|
|
73
|
-
height: 0,
|
|
74
|
-
}}
|
|
75
|
-
transition={{
|
|
76
|
-
duration: 0.3,
|
|
77
|
-
}}
|
|
78
|
-
>
|
|
79
|
-
{active ? (
|
|
80
|
-
<div className="flex w-full overflow-hidden justify-center">
|
|
81
|
-
<div className="drawer-container w-full">{activeTab?.tabContent}</div>
|
|
82
|
-
</div>
|
|
83
|
-
) : null}
|
|
84
|
-
</NavDrawerContainer>
|
|
85
|
-
) : null}
|
|
86
|
-
</NavDrawer>
|
|
26
|
+
<NavTitles
|
|
27
|
+
tabTitleClassName={tabTitleClassName}
|
|
28
|
+
tabs={tabs}
|
|
29
|
+
active={active}
|
|
30
|
+
setActive={setActive}
|
|
31
|
+
/>
|
|
32
|
+
<NavDrawer active={active} content={activeTab?.tabContent} showDrawer={showDrawer} />
|
|
87
33
|
</div>
|
|
88
34
|
</LayoutGroup>
|
|
89
35
|
</NavTabContainer>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { NsNavTabComponent as NsNavTab } from './NsNavTab';
|
|
2
|
-
export type {
|
|
2
|
+
export type { NsNavTabComponentProps, NavTabs } from './types';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { FoundationTheme } from '@nuskin/foundation-theme';
|
|
3
3
|
import { Variants } from '../typography/types';
|
|
4
|
-
import { AdditionalProps,
|
|
4
|
+
import { AdditionalProps, CslpTag } from '../common.types';
|
|
5
5
|
|
|
6
6
|
export type NavTabs = {
|
|
7
7
|
tabName: string;
|
|
@@ -9,10 +9,10 @@ export type NavTabs = {
|
|
|
9
9
|
activeColor: FoundationTheme.PaletteColors;
|
|
10
10
|
color?: FoundationTheme.PaletteColors;
|
|
11
11
|
textVariant: Variants;
|
|
12
|
-
liveTag?:
|
|
12
|
+
liveTag?: CslpTag;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
export type
|
|
15
|
+
export type NsNavTabComponentProps = {
|
|
16
16
|
tabs: NavTabs[];
|
|
17
17
|
className?: string;
|
|
18
18
|
tabTitleClassName?: string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import Progress from './NsProgress';
|
|
4
|
+
|
|
5
|
+
describe(' NsProgress Component', () => {
|
|
6
|
+
test('should render Progress bar', () => {
|
|
7
|
+
render(<Progress color="primary" value={10}></Progress>);
|
|
8
|
+
|
|
9
|
+
const pbar = screen.getByRole('progressbar');
|
|
10
|
+
|
|
11
|
+
expect(pbar).toBeInTheDocument();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('matches the height of the progress bar to the width of the container', () => {
|
|
15
|
+
// Define the props
|
|
16
|
+
const value = 50;
|
|
17
|
+
|
|
18
|
+
// Render the StyledProgress component with the value prop
|
|
19
|
+
const { container } = render(<Progress color="primary" value={value} />);
|
|
20
|
+
|
|
21
|
+
// Get the progress bar element
|
|
22
|
+
const progressBar = container.querySelector('.MuiLinearProgress-bar');
|
|
23
|
+
|
|
24
|
+
// Check if the progress bar element exists
|
|
25
|
+
if (progressBar) {
|
|
26
|
+
// Retrieve the computed width of the container element
|
|
27
|
+
const containerWidth = container.clientWidth;
|
|
28
|
+
|
|
29
|
+
// Retrieve the computed styles of the progress bar
|
|
30
|
+
const progressBarStyle = getComputedStyle(progressBar);
|
|
31
|
+
const progressBarHeight = parseFloat(progressBarStyle.height);
|
|
32
|
+
const progressBarPadding =
|
|
33
|
+
parseFloat(progressBarStyle.paddingTop) + parseFloat(progressBarStyle.paddingBottom);
|
|
34
|
+
const progressBarBorder =
|
|
35
|
+
parseFloat(progressBarStyle.borderTopWidth) + parseFloat(progressBarStyle.borderBottomWidth);
|
|
36
|
+
|
|
37
|
+
// Calculate the expected height of the progress bar
|
|
38
|
+
const expectedHeight = containerWidth - progressBarPadding - progressBarBorder;
|
|
39
|
+
|
|
40
|
+
// Assert that the height of the progress bar matches the width of the container
|
|
41
|
+
expect(progressBarHeight).toBe(expectedHeight);
|
|
42
|
+
} else {
|
|
43
|
+
// Handle the case where the progress bar element is not found
|
|
44
|
+
throw new Error('Progress bar element not found');
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
|
|
2
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
3
|
+
import NsProgress from './NsProgress';
|
|
4
|
+
|
|
5
|
+
type ComponentType = typeof NsProgress;
|
|
6
|
+
type Story = StoryObj<ComponentType>;
|
|
7
|
+
type MetaStory = Meta<ComponentType>;
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
component: NsProgress,
|
|
11
|
+
title: 'Input/NsProgress',
|
|
12
|
+
decorators: [withCenterDecorator],
|
|
13
|
+
argTypes: {
|
|
14
|
+
color: {
|
|
15
|
+
description: 'defines the color for the completed progress',
|
|
16
|
+
},
|
|
17
|
+
height: {
|
|
18
|
+
description: 'height of the bar',
|
|
19
|
+
},
|
|
20
|
+
value: {
|
|
21
|
+
description: 'value of the progress done',
|
|
22
|
+
},
|
|
23
|
+
backgroundColor: {
|
|
24
|
+
description: 'color of incomplete progress',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
} as MetaStory;
|
|
28
|
+
|
|
29
|
+
export const ProgressBar: Story = {
|
|
30
|
+
args: {
|
|
31
|
+
color: 'primary',
|
|
32
|
+
backgroundColor: '#19dbdb',
|
|
33
|
+
value: undefined,
|
|
34
|
+
height: '10px',
|
|
35
|
+
body: <span>{'% Complete'}</span>,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { styled, ColorUtils } from '@nuskin/foundation-theme';
|
|
2
|
+
import { LinearProgress } from '@mui/material';
|
|
3
|
+
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
4
|
+
import { NsProgressProps } from './types';
|
|
5
|
+
|
|
6
|
+
const { color } = ColorUtils;
|
|
7
|
+
export const StyledCheckCircle = styled(CheckCircleIcon)`
|
|
8
|
+
color: ${color('neutral', '50')};
|
|
9
|
+
padding-top: 0.6em;
|
|
10
|
+
padding-right: 0.5em;
|
|
11
|
+
justify-self: flex-end;
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
export const PercentDiv = styled('div')`
|
|
15
|
+
color: ${color('primary', '100')};
|
|
16
|
+
display: flex;
|
|
17
|
+
justify-content: flex-end;
|
|
18
|
+
font-family: Inter;
|
|
19
|
+
font-size: 12px;
|
|
20
|
+
font-style: normal;
|
|
21
|
+
font-weight: 700;
|
|
22
|
+
text-transform: uppercase;
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
export const StyledLinearProgress = styled(LinearProgress)<Omit<NsProgressProps, 'value'>>(
|
|
26
|
+
({ height, backgroundColor, color }) => ({
|
|
27
|
+
width: '334px',
|
|
28
|
+
height,
|
|
29
|
+
backgroundColor,
|
|
30
|
+
borderRadius: '3px',
|
|
31
|
+
display: 'inline-block',
|
|
32
|
+
|
|
33
|
+
'.MuiLinearProgress-bar': {
|
|
34
|
+
backgroundColor: color,
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export default StyledLinearProgress;
|