@nuskin/foundation-ui-components 1.0.0-develop.7 → 1.0.0-develop.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/foundation-ui-components",
3
- "version": "1.0.0-develop.7",
3
+ "version": "1.0.0-develop.8",
4
4
  "description": "It is a foundation library written in react, that provides common components to all UI pages",
5
5
  "private": false,
6
6
  "main": "src/common/index.ts",
@@ -8,7 +8,7 @@ import { StyledAccordionWrapper } from './ToggleSection.styled';
8
8
  * multiple sections of accordion can remain open at a time
9
9
  *
10
10
  * we can define certain section to remain open by default using `isDefaultOpen` in the
11
- * contentArray item
11
+ * items
12
12
  * if there are multiple items available for default open, but `allowMultipleExpanded`
13
13
  * is false then only first item of default open is made open
14
14
  */
@@ -2,26 +2,31 @@ import { NsTypography, NsIcon, NsAccordionHeaderProps, AccordionVariant, NsIconP
2
2
  import { styled } from '@nuskin/foundation-theme';
3
3
  import { isValidIconName } from '../icon/NsIconVariants';
4
4
  import { getAccordionColor } from './colorMap';
5
+ const options = {
6
+ shouldForwardProp: (propKey: string) => !['variant', 'invert'].includes(propKey),
7
+ };
8
+ type StyledType = { variant: AccordionVariantType; invert: boolean };
5
9
 
6
- const StyledHeader = styled('header')<{ variant: AccordionVariantType; invert: boolean }>(
7
- ({ theme, variant, invert }) => {
8
- const { headBg, headText } = getAccordionColor({ theme, variant, invert, keys: ['headBg', 'headText'] });
9
- let borderBottom = 'none';
10
- if (variant === AccordionVariant.Compact) {
11
- borderBottom = '1px solid rgb(0,0,0,0.125)';
12
- }
13
- return {
14
- backgroundColor: headBg,
15
- color: headText,
16
- cursor: 'pointer',
17
- display: 'grid',
18
- gap: '4px',
19
- gridTemplateColumns: 'auto 1fr 24px',
20
- padding: '9px 16px',
21
- borderBottom,
22
- } as any;
10
+ const StyledHeader = styled(
11
+ 'header',
12
+ options
13
+ )<StyledType>(({ theme, variant, invert }) => {
14
+ const { headBg, headText } = getAccordionColor({ theme, variant, invert, keys: ['headBg', 'headText'] });
15
+ let borderBottom = 'none';
16
+ if (variant === AccordionVariant.Compact) {
17
+ borderBottom = '1px solid rgb(0,0,0,0.125)';
23
18
  }
24
- );
19
+ return {
20
+ backgroundColor: headBg,
21
+ color: headText,
22
+ cursor: 'pointer',
23
+ display: 'grid',
24
+ gap: '4px',
25
+ gridTemplateColumns: 'auto 1fr 24px',
26
+ padding: '9px 16px',
27
+ borderBottom,
28
+ } as any;
29
+ });
25
30
 
26
31
  /**
27
32
  * NsAccordionHeader is primarily used by NsToggleSection and NsAccordionItem
@@ -57,24 +57,22 @@ const NsCollapse = ({ isOpen, content, additionalProps, variant, level, invert,
57
57
  if (isValidElement(content)) {
58
58
  return content as ReactElement;
59
59
  }
60
- if (content?.type === 'html') {
60
+ const contentVar = content as unknown as ItemContent;
61
+ if (contentVar?.type === 'html') {
61
62
  return (
62
- <div
63
- className="nsa-content-padded"
64
- dangerouslySetInnerHTML={{ __html: (content as ItemContent)?.data as string }}
65
- />
63
+ <div className="nsa-content-padded" dangerouslySetInnerHTML={{ __html: contentVar?.data as string }} />
66
64
  );
67
- } else if (content?.type === 'text') {
68
- return <div className="p-4">{(content as ItemContent)?.data as string}</div>;
69
- } else if (content?.type === 'accordion') {
65
+ } else if (contentVar?.type === 'text') {
66
+ return <div className="p-4">{contentVar?.data as string}</div>;
67
+ } else if (contentVar?.type === 'accordion') {
70
68
  return (
71
69
  <NsAccordion
72
70
  isChild={true}
73
71
  invert={invert}
74
72
  level={level}
75
73
  variant={AccordionVariant.Gray}
76
- items={(content as ItemContent)?.data as AccordionItem[]}
77
- allowMultipleExpanded={(content as ItemContent)?.allowMultipleExpanded ?? false}
74
+ items={contentVar?.data as AccordionItem[]}
75
+ allowMultipleExpanded={contentVar?.allowMultipleExpanded ?? false}
78
76
  />
79
77
  );
80
78
  }
@@ -2,7 +2,10 @@ import { styled } from '@nuskin/foundation-theme';
2
2
  import { AccordionVariant, AccordionVariantType } from '../';
3
3
 
4
4
  const border = '1px solid rgb(0,0,0,0.125)';
5
- export const StyledToggleSection = styled('section')<{ variant: AccordionVariantType }>(({ variant }) => {
5
+
6
+ type StyledType = { variant: AccordionVariantType };
7
+
8
+ export const StyledToggleSection = styled('section')<StyledType>(({ variant }) => {
6
9
  if (variant === AccordionVariant.Compact) {
7
10
  return { borderRight: border };
8
11
  }
@@ -11,7 +14,7 @@ export const StyledToggleSection = styled('section')<{ variant: AccordionVariant
11
14
  };
12
15
  });
13
16
 
14
- export const StyledAccordionWrapper = styled('div')<{ variant: AccordionVariantType }>(({ variant }) => {
17
+ export const StyledAccordionWrapper = styled('div')<StyledType>(({ variant }) => {
15
18
  if (variant === AccordionVariant.Compact) {
16
19
  return {
17
20
  display: 'flex',
@@ -1,10 +1,3 @@
1
- /* eslint-disable no-unused-vars */
2
- // export enum AccordionVariant {
3
- // Basic = 'basic', // basic is as per figma
4
- // Compact = 'compact', // compact is as per test.nuskin.com
5
- // Gray = 'gray',
6
- // Stripe = 'stripe',
7
- // }
8
1
  export const AccordionVariant = {
9
2
  Basic: 'basic',
10
3
  Compact: 'compact',
@@ -22,6 +22,11 @@ const meta = {
22
22
  control: 'select',
23
23
  options: [...Object.values(AccordionVariant)],
24
24
  },
25
+ level: {
26
+ control: 'number',
27
+ description: `level = 1 means no padding on left from parent to child,
28
+ level = 2 means padding of 16px, level = 3 means padding of 32px and so on ..`,
29
+ },
25
30
  },
26
31
  args: {
27
32
  variant: AccordionVariant.Basic,
@@ -13,6 +13,7 @@ export * from './column-control';
13
13
  export * from './checkbox';
14
14
  export * from './common.types.d';
15
15
  export * from './dropdown';
16
+ export * from './email-simple';
16
17
  export * from './flag';
17
18
  export * from './hooks';
18
19
  export * from './icon';
@@ -20,11 +21,12 @@ export * from './image';
20
21
  export * from './input';
21
22
  export * from './label';
22
23
  export * from './link';
24
+ export * from './modal';
23
25
  export * from './nav-tab';
24
26
  export * from './nav-product-card';
27
+ export * from './radiogroup';
28
+ export * from './spinner';
25
29
  export * from './text-strip';
26
30
  export * from './table';
27
31
  export * from './typography';
28
- export * from './email-simple';
29
- export * from './radiogroup';
30
- export * from './spinner';
32
+ export * from './utility';
@@ -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,2 @@
1
+ export { default as NsModal } from './NsModal';
2
+ export type { NsModalProps } from './types';
@@ -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,86 @@
1
+ import type { StoryObj, Meta } from '@storybook/react';
2
+ import { withCenterDecorator } from '@/stories/decorators/withCenterDecorator';
3
+ import NsModal from '../NsModal';
4
+ import { NsButton } from '../../button';
5
+ import { Grid, Typography } from '@mui/material';
6
+ import { useState } from 'react';
7
+ import { NsModalProps } from '../types';
8
+ import { NsModalData } from './mock';
9
+
10
+ type ComponentType = typeof NsModal;
11
+ type Story = StoryObj<ComponentType>;
12
+ type MetaStory = Meta<ComponentType>;
13
+
14
+ export default {
15
+ title: 'Components/NsModal',
16
+ component: NsModal,
17
+ decorators: [withCenterDecorator],
18
+ argTypes: {},
19
+ args: {
20
+ ...NsModalData,
21
+ },
22
+ } as MetaStory;
23
+
24
+ const RenderNsModal = (args: NsModalProps) => {
25
+ const [isOpen, setOpen] = useState(false);
26
+
27
+ const onModalHandler = () => {
28
+ setOpen(!isOpen);
29
+ };
30
+
31
+ return (
32
+ <>
33
+ <NsButton onClick={onModalHandler}>Open Modal</NsButton>
34
+ <NsModal {...args} open={isOpen} handleClose={onModalHandler} />
35
+ </>
36
+ );
37
+ };
38
+
39
+ export const Modal: Story = {
40
+ args: {
41
+ header: {
42
+ ...NsModalData?.header,
43
+ isCloseIcon: false,
44
+ },
45
+ } as NsModalProps,
46
+ render: RenderNsModal,
47
+ };
48
+
49
+ export const WithCloseIcon: Story = {
50
+ render: RenderNsModal,
51
+ };
52
+
53
+ export const ImageWidthText: Story = {
54
+ args: {
55
+ header: {
56
+ show: true,
57
+ isCloseIcon: true,
58
+ },
59
+ body: {
60
+ show: true,
61
+ children: (
62
+ <Grid container spacing={2}>
63
+ <Grid xs={6}>
64
+ <img
65
+ src="https://www.nuskin.com/content/products/01/55/00/01550014/_jcr_content/fullImage.img.160.160.png.64.64.png"
66
+ alt={'NsImage'}
67
+ />
68
+ </Grid>
69
+ <Grid xs={6} className="p-5">
70
+ <Typography gutterBottom variant="h5" component="div">
71
+ Lizard
72
+ </Typography>
73
+ <Typography variant="body2" color="text.secondary">
74
+ Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging across
75
+ all continents except Antarctica
76
+ </Typography>
77
+ </Grid>
78
+ </Grid>
79
+ ),
80
+ },
81
+ footer: {
82
+ show: false,
83
+ },
84
+ },
85
+ render: RenderNsModal,
86
+ };
@@ -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,13 @@
1
+ import { PropsWithChildren, ReactElement } from 'react';
2
+
3
+ type ShowType = PropsWithChildren & {
4
+ when?: boolean;
5
+ elseContent?: ReactElement;
6
+ };
7
+ const Show = ({ when, children, elseContent }: ShowType): ReactElement => {
8
+ if (when) {
9
+ return <>{children}</>;
10
+ }
11
+ return <>{elseContent}</>;
12
+ };
13
+ export default Show;
@@ -0,0 +1 @@
1
+ export { default as Show } from './Show';