-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: (#17) App.tsx에서 Example 컴포넌트 import Button 컴포넌트 대신 Example 컴포넌트 import * feat: (#17) Modal 컴포넌트 구현 및 스토리 작성 Modal 컴포넌트는 3가지 상태 - Default, Wide(디바이스 width가 넓은 경우), With Close Button(모달 안에 취소 버튼이 있는 경우)로 구성된다 * chore: (#17) Modal 컴포넌트 common 폴더로 이동 * chore: (#17) Modal 컴포넌트 css property 정렬 * design: (#17) Modal 컴포넌트 내 Body, Description css 수정 * refactor: (#17) 파일 간 순환참조 코드 삭제 * refactor: (#17) Modal 컴포넌트 onModalClose props에 setStateAction 대신 일반함수(closeModal) 전달하도록 수정 * chore: (#17) 오타 수정 * refactor: (#17) story에서만 사용하는 style들 stories.tsx 로 이동 * refactor: (#17) size props의 타입 분리 대신 컴포넌트 파일 내에 명시 * refactor: (#17) 모달 사이즈 상수화 * chore: (#17) 불필요한 export 삭제
- Loading branch information
1 parent
1c2bec7
commit f738b28
Showing
4 changed files
with
212 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import type { Meta } from '@storybook/react'; | ||
|
||
import { useState } from 'react'; | ||
|
||
import { styled } from 'styled-components'; | ||
|
||
import Modal from '.'; | ||
|
||
const meta: Meta<typeof Modal> = { | ||
component: Modal, | ||
}; | ||
|
||
export default meta; | ||
|
||
export const Default = () => { | ||
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={closeModal}> | ||
<p>This is Default Modal</p> | ||
</Modal> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export const Wide = () => { | ||
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="lg" onModalClose={closeModal}> | ||
<p>This is Wide 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={closeModal}> | ||
<> | ||
<S.Header> | ||
<p>Modal Title</p> | ||
<S.CloseButton onClick={closeModal}>X</S.CloseButton> | ||
</S.Header> | ||
<S.Body> | ||
<S.Description>This is Description</S.Description> | ||
This is Content | ||
</S.Body> | ||
</> | ||
</Modal> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
const Header = styled.div` | ||
display: flex; | ||
justify-content: space-between; | ||
alignt-items: center; | ||
width: 100%; | ||
border-bottom: 1px solid #f6f6f6; | ||
padding: 10px; | ||
font-size: 1.5rem; | ||
font-weight: bold; | ||
`; | ||
|
||
const Body = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: start; | ||
gap: 5px; | ||
padding: 10px; | ||
font-size: 1.4rem; | ||
`; | ||
|
||
const Description = styled.div` | ||
color: gray; | ||
font-size: 1.2rem; | ||
`; | ||
|
||
const CloseButton = styled.button` | ||
width: 20px; | ||
height: 20px; | ||
`; | ||
|
||
const S = { | ||
Header, | ||
Body, | ||
Description, | ||
CloseButton, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import React, { useEffect, useRef } from 'react'; | ||
|
||
import * as S from './style'; | ||
|
||
interface ModalProps { | ||
onModalClose: () => void; | ||
children: React.JSX.Element; | ||
size: 'sm' | 'md' | 'lg'; | ||
} | ||
|
||
export default function Modal({ onModalClose, children, size }: ModalProps) { | ||
const BackDropRef = useRef<HTMLDivElement>(null); | ||
|
||
useEffect(() => { | ||
const handler = (e: MouseEvent) => { | ||
if (e.target === BackDropRef.current) { | ||
onModalClose(); | ||
} | ||
}; | ||
|
||
document.addEventListener('click', handler); | ||
|
||
return () => document.removeEventListener('click', handler); | ||
}, [BackDropRef, onModalClose]); | ||
|
||
return ( | ||
<S.All> | ||
<S.Backdrop ref={BackDropRef}></S.Backdrop> | ||
<S.Container size={size}>{children}</S.Container> | ||
</S.All> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { styled } from 'styled-components'; | ||
|
||
const modalSize: { | ||
[key: string]: string; | ||
} = { | ||
sm: '290px', | ||
md: '590px', | ||
lg: '700px', | ||
}; | ||
|
||
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<{ size: string }>` | ||
display: grid; | ||
grid-template-rows: 1fr 6fr; | ||
position: fixed; | ||
top: 50%; | ||
left: 50%; | ||
transform: translate(-50%, -50%); | ||
width: ${props => modalSize[props.size]}; | ||
height: 290px; | ||
border-radius: 12px; | ||
border: 2px solid #f6f6f6; | ||
padding: 5px; | ||
background-color: white; | ||
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5); | ||
`; |