-
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.
Modal 컴포넌트는 3가지 상태 - Default, Wide(디바이스 width가 넓은 경우), With Close Button(모달 안에 취소 버튼이 있는 경우)로 구성된다
- Loading branch information
1 parent
a8edc4d
commit 9d9c633
Showing
4 changed files
with
193 additions
and
0 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
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> | ||
)} | ||
</> | ||
); | ||
}; |
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,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> | ||
); | ||
} |
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,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; | ||
`; |
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 @@ | ||
export type ModalSizeType = 'sm' | 'lg'; |