Skip to content

Commit

Permalink
feat: (#17) Modal 컴포넌트 구현 및 스토리 작성
Browse files Browse the repository at this point in the history
Modal 컴포넌트는 3가지 상태 - Default, Wide(디바이스 width가 넓은 경우), With Close Button(모달 안에 취소 버튼이 있는 경우)로 구성된다
  • Loading branch information
inyeong-kang committed Jul 11, 2023
1 parent a8edc4d commit 9d9c633
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 0 deletions.
81 changes: 81 additions & 0 deletions frontend/src/components/Modal/Modal.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { Meta, StoryObj } from '@storybook/react';

import { useState } from 'react';

import * as S from './style';

import Modal from '.';

const meta: Meta<typeof Modal> = {
component: Modal,
};

export default meta;
type Story = StoryObj<typeof Modal>;

export const Default = () => {
const [isOpen, setIsOpen] = useState(false);

const openModal = () => {
setIsOpen(true);
};

return (
<>
<button onClick={openModal}>Open Modal</button>
{isOpen && (
<Modal size="sm" onModalClose={setIsOpen}>
<p>This is Default Modal</p>
</Modal>
)}
</>
);
};

export const Wide = () => {
const [isOpen, setIsOpen] = useState(false);

const openModal = () => {
setIsOpen(true);
};

return (
<>
<button onClick={openModal}>Open Modal</button>
{isOpen && (
<Modal size="lg" onModalClose={setIsOpen}>
<p>This is Default Modal</p>
</Modal>
)}
</>
);
};

export const WithCloseButton = () => {
const [isOpen, setIsOpen] = useState(false);

const openModal = () => {
setIsOpen(true);
};

const closeModal = () => {
if (isOpen === true) setIsOpen(false);
};

return (
<>
<button onClick={openModal}>Open Modal</button>
{isOpen && (
<Modal size="sm" onModalClose={setIsOpen}>
<>
<S.Header>
<p>Modal Title</p>
<S.CloseButton onClick={closeModal}>X</S.CloseButton>
</S.Header>
<S.Body>Modal Content</S.Body>
</>
</Modal>
)}
</>
);
};
40 changes: 40 additions & 0 deletions frontend/src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useEffect, useRef, Dispatch } from 'react';

import { ModalSizeType } from '@type/modalSize';

import * as S from './style';

export interface ModalProps {
onModalClose: Dispatch<React.SetStateAction<boolean>>;
children: React.JSX.Element;
size: ModalSizeType;
}

export type ModalContainerProps = Pick<ModalProps, 'size'>;

export default function Modal({ onModalClose, children, size }: ModalProps) {
const BackDropRef = useRef<HTMLDivElement>(null);

const closeModal = () => {
onModalClose(false);
};

useEffect(() => {
const handler = (e: MouseEvent) => {
if (e.target === BackDropRef.current) {
closeModal();
}
};

document.addEventListener('click', handler);

return () => document.removeEventListener('click', handler);
}, [BackDropRef, closeModal]);

return (
<S.All>
<S.Backdrop ref={BackDropRef}></S.Backdrop>
<S.Container size={size}>{children}</S.Container>
</S.All>
);
}
71 changes: 71 additions & 0 deletions frontend/src/components/Modal/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { styled } from 'styled-components';

import { ModalContainerProps } from '.';

export const All = styled.div`
display: flex;
justify-content: center;
align-items: center;
`;

export const Backdrop = styled.div`
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.35);
`;

export const Container = styled.div<ModalContainerProps>`
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: grid;
grid-template-rows: 1fr 6fr;
width: ${props => (props.size === 'sm' ? '290px' : '700px')};
height: 290px;
font-size: 1rem;
border-radius: 12px;
border: 2px solid #f6f6f6;
background-color: white;
padding: 5px;
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5);
`;

export const Header = styled.div`
display: flex;
justify-content: space-between;
alignt-items: center;
width: 100%;
padding: 10px;
border-bottom: 1px solid #f6f6f6;
font-size: 1.5rem;
font-weight: bold;
`;

export const Body = styled.div`
font-size: 1.2rem;
padding: 10px;
`;

export const Description = styled.div`
color: gray;
padding: 10px;
`;

export const CloseButton = styled.button`
width: 20px;
height: 20px;
`;
1 change: 1 addition & 0 deletions frontend/src/types/modalSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type ModalSizeType = 'sm' | 'lg';

0 comments on commit 9d9c633

Please sign in to comment.