@nuskin/foundation-ui-components 1.0.2 → 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 +105 -101
- 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 +32 -14
- package/src/common/accordion/stories/NsAccordionHeader.stories.tsx +6 -2
- package/src/common/accordion/stories/NsAccordionItem.stories.tsx +9 -4
- package/src/common/accordion/stories/NsCollapse.stories.tsx +20 -5
- package/src/common/accordion/stories/NsToggleSection.stories.tsx +7 -4
- 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 +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 +34 -11
- package/src/common/autocomplete/NsAutocomplete.stories.tsx +19 -3
- 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/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/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/NsFfgCard.tsx +13 -7
- package/src/common/card/specs/NsFfgCard.spec.tsx +18 -8
- 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 +48 -15
- 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/carousal/stories/NSCarousal.stories.tsx +1 -1
- package/src/common/carousal/stories/NsScrollingCarousal.stories.tsx +1 -1
- package/src/common/cart-icon/NsCartIcon.spec.tsx +5 -16
- package/src/common/cart-icon/NsCartIcon.stories.tsx +2 -2
- 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.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 +14 -5
- 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.spec.tsx +1 -1
- package/src/common/icon/NsIcon.stories.tsx +4 -1
- 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.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 +6 -2
- 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/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-product-card/NsNavProductCard.stories.tsx +1 -1
- 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 +4 -4
- 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 +14 -32
- 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 +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/utility/Show.tsx +13 -0
- package/src/common/utility/index.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
|
@@ -55,7 +55,7 @@ const NsInputField = (props: NsInputFieldProps) => {
|
|
|
55
55
|
} = props;
|
|
56
56
|
/** EndIcon is created so that we can automatically add success and error icon based of fieldState,
|
|
57
57
|
* it will override iconEnd. Also to note, InputProps is given to override both iconStart, iconEnd and EndIcon */
|
|
58
|
-
|
|
58
|
+
const EndIcon: AdornmentPropsType = getAdornmentProps({ disabled, fieldState, iconEnd, iconStart });
|
|
59
59
|
|
|
60
60
|
return (
|
|
61
61
|
<InputFieldWrapper>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@/test-utils/index';
|
|
3
|
+
import NsModal from './NsModal';
|
|
4
|
+
import { NsModalData } from './stories/mock';
|
|
5
|
+
import { NsModalProps } from './types';
|
|
6
|
+
|
|
7
|
+
describe('NsModal', () => {
|
|
8
|
+
const onHandleClose = jest.fn();
|
|
9
|
+
|
|
10
|
+
const NsModalProp = NsModalData as NsModalProps;
|
|
11
|
+
|
|
12
|
+
test('1. check NsModal component open', () => {
|
|
13
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
14
|
+
expect(getByTestId('nsmodal-dialog')).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('2. should render NsModal default component', () => {
|
|
18
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
19
|
+
expect(getByTestId('modal-default')).toBeInTheDocument();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('3. should render NsModal status component', () => {
|
|
23
|
+
const VariantProps: NsModalProps = {
|
|
24
|
+
...NsModalProp,
|
|
25
|
+
variant: 'info',
|
|
26
|
+
};
|
|
27
|
+
const { getByTestId } = render(<NsModal {...VariantProps} handleClose={onHandleClose} />);
|
|
28
|
+
expect(getByTestId('modal-status')).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('4. should render NsModal title with close button', () => {
|
|
32
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
33
|
+
expect(getByTestId('modal-title')).toBeInTheDocument();
|
|
34
|
+
expect(getByTestId('modal-close-button')).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('5. should render NsModal body content', () => {
|
|
38
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
39
|
+
expect(getByTestId('modal-body-content')).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('6. should render NsModal footer', () => {
|
|
43
|
+
const { getByTestId } = render(<NsModal {...NsModalProp} handleClose={onHandleClose} />);
|
|
44
|
+
expect(getByTestId('modal-footer')).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { styled } from '@nuskin/foundation-theme';
|
|
2
|
+
import { NsButton } from '../button';
|
|
3
|
+
import { DialogActions } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
export const NsInfoWrapper = styled.div`
|
|
6
|
+
display: flex;
|
|
7
|
+
.status-icon {
|
|
8
|
+
padding: 16px 0px 0px 24px;
|
|
9
|
+
}
|
|
10
|
+
.title-icon {
|
|
11
|
+
padding-right: 10px;
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
export const CloseButton = styled(NsButton)`
|
|
16
|
+
position: absolute;
|
|
17
|
+
right: 8px;
|
|
18
|
+
top: 8px;
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
export const ModalFooter = styled(DialogActions)`
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: space-around;
|
|
24
|
+
padding: 20px 0px 10px 0px;
|
|
25
|
+
button {
|
|
26
|
+
width: 100%;
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Dialog from '@mui/material/Dialog';
|
|
3
|
+
import { useMediaQuery } from '@mui/material';
|
|
4
|
+
import { useTheme } from '@mui/material/styles';
|
|
5
|
+
import { ModalVariantMap } from './model/NsModalVariantMap';
|
|
6
|
+
import { NsModalProps } from './types';
|
|
7
|
+
|
|
8
|
+
const NsModal = (props: NsModalProps) => {
|
|
9
|
+
const { open, handleClose, header, body, additionalProps, footer, statusInfo, variant = 'default' } = props;
|
|
10
|
+
|
|
11
|
+
const { className, scrollType = 'paper', ariaLabel } = additionalProps || {};
|
|
12
|
+
|
|
13
|
+
const { ariaLabelledby = 'alert-dialog-title', ariaDescribedby = 'alert-dialog-description' } = ariaLabel || {};
|
|
14
|
+
|
|
15
|
+
const theme = useTheme();
|
|
16
|
+
|
|
17
|
+
const fullScreen: boolean = useMediaQuery(theme.breakpoints.down('md'));
|
|
18
|
+
|
|
19
|
+
const Component = ModalVariantMap[variant];
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Dialog
|
|
23
|
+
data-testid="nsmodal-dialog"
|
|
24
|
+
fullScreen={fullScreen}
|
|
25
|
+
open={open}
|
|
26
|
+
scroll={scrollType}
|
|
27
|
+
onClose={handleClose}
|
|
28
|
+
aria-labelledby={ariaLabelledby}
|
|
29
|
+
aria-describedby={ariaDescribedby}
|
|
30
|
+
className={className}
|
|
31
|
+
>
|
|
32
|
+
<Component {...{ header, handleClose, body, footer, additionalProps, statusInfo, variant, open }} />
|
|
33
|
+
</Dialog>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default NsModal;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { DialogContent } from '@mui/material';
|
|
3
|
+
import { NsModalComponentProps } from '../types';
|
|
4
|
+
import NsModalTitle from './NsModalTitle';
|
|
5
|
+
import { NsTypography } from '../..';
|
|
6
|
+
|
|
7
|
+
const NsModalContentBox = ({ handleClose, statusInfo }: NsModalComponentProps) => {
|
|
8
|
+
const { title, description } = statusInfo || {};
|
|
9
|
+
|
|
10
|
+
const header = useMemo(() => {
|
|
11
|
+
return {
|
|
12
|
+
show: true,
|
|
13
|
+
children: (
|
|
14
|
+
<NsTypography variant="h5" weight="bold">
|
|
15
|
+
{title}
|
|
16
|
+
</NsTypography>
|
|
17
|
+
),
|
|
18
|
+
isCloseIcon: true,
|
|
19
|
+
};
|
|
20
|
+
}, [title]);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div>
|
|
24
|
+
<NsModalTitle header={header} handleClose={handleClose} />
|
|
25
|
+
<DialogContent>
|
|
26
|
+
<NsTypography variant="p-xs">{description}</NsTypography>
|
|
27
|
+
</DialogContent>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default NsModalContentBox;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { DialogContent } from '@mui/material';
|
|
2
|
+
import NsModalTitle from './NsModalTitle';
|
|
3
|
+
import { NsModalComponentProps } from '../types';
|
|
4
|
+
import { ModalFooter } from '../NsModal.styled';
|
|
5
|
+
import { Show } from '../../utility';
|
|
6
|
+
|
|
7
|
+
const NsDefaultModal = ({ header, handleClose, body, footer, additionalProps }: NsModalComponentProps) => {
|
|
8
|
+
const { dividers } = additionalProps || {};
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div data-testid="modal-default">
|
|
12
|
+
<NsModalTitle header={header} handleClose={handleClose} />
|
|
13
|
+
<DialogContent dividers={dividers}>
|
|
14
|
+
<Show when={body?.show ?? false}>
|
|
15
|
+
<div data-testid="modal-body-content">{body?.children}</div>
|
|
16
|
+
</Show>
|
|
17
|
+
<Show when={footer?.show ?? false}>
|
|
18
|
+
<ModalFooter data-testid="modal-footer">{footer?.children}</ModalFooter>
|
|
19
|
+
</Show>
|
|
20
|
+
</DialogContent>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default NsDefaultModal;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NsInfoWrapper } from '../NsModal.styled';
|
|
2
|
+
import { NsModalComponentProps } from '../types';
|
|
3
|
+
import NsModalContentBox from './NsModalContentBox';
|
|
4
|
+
import NsModalStatusIcon from './NsModalStatusIcon';
|
|
5
|
+
|
|
6
|
+
const NsStatusModal = ({ handleClose, statusInfo, variant }: NsModalComponentProps) => {
|
|
7
|
+
return (
|
|
8
|
+
<NsInfoWrapper data-testid="modal-status">
|
|
9
|
+
<NsModalStatusIcon {...{ variant }} />
|
|
10
|
+
<NsModalContentBox {...{ handleClose, statusInfo }} />
|
|
11
|
+
</NsInfoWrapper>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default NsStatusModal;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NsIcon, NsIconNameType } from '../../';
|
|
2
|
+
import { StatusIconMap } from '../model/NsModalVariantMap';
|
|
3
|
+
import { NsModalComponentProps, NsModalVariant } from '../types';
|
|
4
|
+
|
|
5
|
+
const NsModalStatusIcon = ({ variant }: NsModalComponentProps) => {
|
|
6
|
+
const iconName = variant ? StatusIconMap[variant] : null;
|
|
7
|
+
return (
|
|
8
|
+
<div className="status-icon">
|
|
9
|
+
<NsIcon name={iconName as NsIconNameType} size="medium" color={variant as NsModalVariant} />
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default NsModalStatusIcon;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NsIcon } from '../..';
|
|
2
|
+
import { DialogTitle } from '@mui/material';
|
|
3
|
+
import { CloseButton, NsInfoWrapper } from '../NsModal.styled';
|
|
4
|
+
import { NsModalComponentProps } from '../types';
|
|
5
|
+
import { Show } from '../../utility';
|
|
6
|
+
|
|
7
|
+
const NsModalTitle = ({ header, handleClose }: NsModalComponentProps) => {
|
|
8
|
+
const { show, children, isCloseIcon, iconName } = header || {};
|
|
9
|
+
return (
|
|
10
|
+
<Show when={show}>
|
|
11
|
+
<DialogTitle data-testid="modal-title">
|
|
12
|
+
<NsInfoWrapper>
|
|
13
|
+
{iconName ? <NsIcon name={iconName} className="title-icon" /> : null}
|
|
14
|
+
{children}
|
|
15
|
+
</NsInfoWrapper>
|
|
16
|
+
<Show when={isCloseIcon}>
|
|
17
|
+
<CloseButton aria-label="close" onClick={handleClose} data-testid="modal-close-button">
|
|
18
|
+
<NsIcon name="close" size="small" />
|
|
19
|
+
</CloseButton>
|
|
20
|
+
</Show>
|
|
21
|
+
</DialogTitle>
|
|
22
|
+
</Show>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default NsModalTitle;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ElementType } from 'react';
|
|
2
|
+
import NsDefaultModal from '../helper-component/NsModalDefault';
|
|
3
|
+
import NsStatusModal from '../helper-component/NsModalStatus';
|
|
4
|
+
import { StatusIconMapProps } from '../types';
|
|
5
|
+
|
|
6
|
+
type ModalMapType = {
|
|
7
|
+
[key: string]: ElementType;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const ModalVariantMap: ModalMapType = {
|
|
11
|
+
default: NsDefaultModal,
|
|
12
|
+
confirmation: NsDefaultModal,
|
|
13
|
+
success: NsStatusModal,
|
|
14
|
+
warning: NsStatusModal,
|
|
15
|
+
error: NsStatusModal,
|
|
16
|
+
info: NsStatusModal,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const StatusIconMap: StatusIconMapProps = {
|
|
20
|
+
success: 'success',
|
|
21
|
+
warning: 'warning',
|
|
22
|
+
error: 'error',
|
|
23
|
+
info: 'infoFilled',
|
|
24
|
+
};
|
|
@@ -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
|
+
}
|
|
@@ -7,7 +7,7 @@ type Story = StoryObj<ComponentType>;
|
|
|
7
7
|
type MetaStory = Meta<ComponentType>;
|
|
8
8
|
|
|
9
9
|
export default {
|
|
10
|
-
title: 'Components/NsNavProductCard',
|
|
10
|
+
title: 'Components/Navigation/NsNavProductCard',
|
|
11
11
|
component: NsNavProductCard,
|
|
12
12
|
decorators: [withCenterDecorator],
|
|
13
13
|
args: {
|
|
@@ -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,13 +1,13 @@
|
|
|
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>;
|
|
7
7
|
type MetaStory = Meta<ComponentType>;
|
|
8
8
|
|
|
9
9
|
export default {
|
|
10
|
-
title: 'Components/NsNavTab',
|
|
10
|
+
title: 'Components/Navigation/NsNavTab',
|
|
11
11
|
component: NsNavTab,
|
|
12
12
|
decorators: [withCenterDecorator],
|
|
13
13
|
argTypes: {
|
|
@@ -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
|
],
|