Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui-kit): Modal 컴포넌트 추가 #50

Merged
merged 16 commits into from
Feb 28, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions ui-kit/src/components/Modal/ModalContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { ReactNode } from 'react';
import classnames from 'classnames';
import Text from 'components/Text';

interface ModalContentProps extends React.HTMLAttributes<HTMLDivElement> {
evan-moon marked this conversation as resolved.
Show resolved Hide resolved
size?: 'small' | 'medium';
children?: ReactNode;
isCustom?: boolean;
}

const ModalContent = ({ children, isCustom = false, size }: ModalContentProps) => {
const typography = size === 'small' ? 'p2' : 'p1';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요거 string으로 추론될 것 같은데, Typography 타입으로 어노테이팅해주면 더 좋을 것 같아요!


return (
<div className={classnames('lubycon-modal__content')}>
{isCustom ? children : <Text typography={typography}>{children}</Text>}
evan-moon marked this conversation as resolved.
Show resolved Hide resolved
</div>
);
};

export default ModalContent;
15 changes: 15 additions & 0 deletions ui-kit/src/components/Modal/ModalFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { ReactNode } from 'react';

interface ModalFooterProps {
children?: ReactNode;
}

const ModalFooter = ({ children }: ModalFooterProps) => {
return (
<div className="lubycon-modal__footer">
{children}
</div>
);
};

export default ModalFooter;
19 changes: 19 additions & 0 deletions ui-kit/src/components/Modal/ModalHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import Text from 'components/Text';

interface ModalHeaderProps {
size?: 'small' | 'medium';
title: string;
}

const ModalHeader = ({ size, title }: ModalHeaderProps) => {
const typography = size === 'small' ? 'subtitle' : 'h6';
evan-moon marked this conversation as resolved.
Show resolved Hide resolved

return (
<header className="lubycon-modal__title">
<Text typography={typography}>{title}</Text>
</header>
);
};

export default ModalHeader;
17 changes: 17 additions & 0 deletions ui-kit/src/components/Modal/ModalWindow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { ReactNode } from 'react';
import classnames from 'classnames';

interface ModalWindowProps {
children: ReactNode;
size: 'small' | 'medium';
}

const ModalWindow = ({ children, size }: ModalWindowProps) => {
return (
<div className={classnames('lubycon-modal__window', `lubycon-modal__window--${size}`)}>
{children}
</div>
);
};

export default ModalWindow;
95 changes: 20 additions & 75 deletions ui-kit/src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,19 @@
import React, { useEffect, useRef } from 'react';
import Button from 'components/Button';
import Text from 'components/Text';
import classnames from 'classnames';
import { colors } from 'constants/colors';
import React, { ReactElement, cloneElement, useRef } from 'react';
import ModalBackdrop from './ModalBackdrop';
import ModalWindow from './ModalWindow';
import classnames from 'classnames';
import { generateID } from 'utils/index';
import { useEffect } from 'react';

export interface ModalProps extends React.HTMLAttributes<HTMLDivElement> {
show: boolean;
modalIsNested?: boolean;
title?: string;
message?: string;
size?: 'small' | 'medium';
cancelButton?: boolean;
cancelButtonText?: string;
buttonText?: string;
handleClick?: () => void;
children: ReactElement[];
onOpen?: () => void;
onClose?: () => void;
evan-moon marked this conversation as resolved.
Show resolved Hide resolved
}

const Modal = ({
show = false,
modalIsNested = false,
title,
message,
size = 'small',
cancelButton = false,
cancelButtonText = '취소',
buttonText = '저장하기',
handleClick,
onClose,
style,
}: ModalProps) => {
const visibleClass = show ? 'lubycon-modal--visible' : null;
const Modal = ({ show, size = 'small', children, onClose }: ModalProps) => {
const backdropRef = useRef(null);
const onBackdropClick = (event: React.MouseEvent<HTMLDivElement>) => {
evan-moon marked this conversation as resolved.
Show resolved Hide resolved
if (!backdropRef.current) return;
evan-moon marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -48,56 +30,19 @@ const Modal = ({
};
}, []);

const modalWindowRef = useRef<HTMLDivElement>(null);
const handleBackdropClick = (event: React.MouseEvent<HTMLDivElement>) => {
if (event.target === modalWindowRef.current) onClose?.();
};

return (
<>
{!modalIsNested && <ModalBackdrop visibleClass={visibleClass} />}
<div
ref={modalWindowRef}
onClick={handleBackdropClick}
className={classnames('lubycon-modal', visibleClass)}
tabIndex={-1}
aria-hidden={true}
>
<div
className={classnames(
'lubycon-modal__window',
`lubycon-modal__window--${size}`,
'lubycon-shadow--3'
)}
style={style}
>
{title && (
<div className={classnames('lubycon-modal__title', 'lubycon-typography--subtitle')}>
<Text typography={size === 'small' ? 'subtitle' : 'h6'}>{title}</Text>
</div>
)}
<div className={classnames('lubycon-modal__message', 'lubycon-typography--p2')}>
<Text typography={size === 'small' ? 'p2' : 'p1'}>{message}</Text>
</div>
<div className="lubycon-modal__buttons">
{cancelButton && (
<Button
size={size}
style={{ color: colors.gray80, background: 'transparent', marginRight: '4px' }}
onClick={onClose}
>
{cancelButtonText}
</Button>
)}
<Button size={size} onClick={handleClick}>
{buttonText}
</Button>
</div>
</div>
</div>
</>
);
return show ? (
<div className={classnames('lubycon-modal')} tabIndex={-1} aria-hidden={true}>
<ModalBackdrop onClick={onBackdropClick} ref={backdropRef} />
<ModalWindow size={size}>
{children.map((element) => {
return cloneElement(element, { key: generateID('lubycon-modal__children'), size: size });
evan-moon marked this conversation as resolved.
Show resolved Hide resolved
})}
</ModalWindow>
</div>
) : null;
};

export default Modal;
export { default as ModalHeader } from './ModalHeader';
export { default as ModalContent } from './ModalContent';
export { default as ModalFooter } from './ModalFooter';
7 changes: 6 additions & 1 deletion ui-kit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ export { default as List, ListItem } from './components/List';
export { default as Input } from './components/Input';
export { default as ProgressBar } from './components/ProgressBar';
export { default as Accordion } from './components/Accordion';
export { default as Modal } from './components/Modal';
export {
default as Modal,
ModalHeader,
ModalContent,
ModalFooter,
} from './components/Modal';
export { Portal } from './contexts/Portal';
export { useToast } from './contexts/Toast';
export { useSnackbar } from './contexts/Snackbar';
Expand Down
17 changes: 7 additions & 10 deletions ui-kit/src/sass/components/_Modal.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
.lubycon-modal {
display: none;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: fixed;
top: 0;
right: 0;
Expand All @@ -8,12 +11,6 @@
overflow: auto;
z-index: 1000;

&--visible {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
&__overlay {
background-color: get-color('gray100');
opacity: 0.5;
Expand All @@ -22,6 +19,7 @@
background-color: get-color('gray10');
border-radius: 4px;
box-sizing: border-box;
z-index: 1001;
&--small {
width: 280px;
padding: 16px 20px;
Expand All @@ -36,13 +34,12 @@
margin-top: 0;
margin-bottom: 12px;
}
&__message {
&__content {
color: get-color('gray70');
margin-top: 0;
margin-bottom: 24px;
white-space: pre-wrap;
}
&__buttons {
&__footer {
display: flex;
align-items: center;
justify-content: flex-end;
Expand Down