Skip to content

Commit

Permalink
[#365] Modal 컴포넌트 (#387)
Browse files Browse the repository at this point in the history
* feat: 모달 UI 컴포넌트 구현, storybook 작성

* fix: useDisclosure 훅 별도 구현 및 모달의 컨텐츠 영역 분리

* fix: storybook delete 내용 수정

* chore: fragment 삭제

* fix: px단위를 rem단위로 변경 및 피그마 디자인에 맞게 모달 배경색 및 투명도 변경
  • Loading branch information
WooDaeHyun authored Aug 1, 2023
1 parent 91ce726 commit e5f8fcd
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/hooks/useDisclosure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useState } from 'react';

const useDisclosure = () => {
const [isOpen, setIsOpen] = useState<boolean>(false);

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

const onClose = () => {
setIsOpen(false);
};

return { isOpen, onOpen, onClose };
};

export default useDisclosure;
82 changes: 82 additions & 0 deletions src/stories/Base/Modal.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Meta, StoryObj } from '@storybook/react';
import Modal from '@/ui/Base/Modal';
import useDisclosure from '@/hooks/useDisclosure';
import Button from '@/ui/Base/Button';
import { Fragment } from 'react';

const meta: Meta<typeof Modal> = {
title: 'Base/Modal',
component: Modal,
tags: ['autodocs'],
};

export default meta;

type Story = StoryObj<typeof Modal>;

const BaseModal = () => {
const { isOpen, onOpen, onClose } = useDisclosure();

return (
<>
<Button
onClick={() => {
onOpen();
}}
>
Open Modal
</Button>
<Modal isOpen={isOpen} onClose={onClose}></Modal>
</>
);
};

const DeleteModal = () => {
const { isOpen, onOpen, onClose } = useDisclosure();

const handleClick = () => {
alert('삭제되었습니다.');
onClose();
};

return (
<>
<Button
onClick={() => {
onOpen();
}}
>
Open Modal
</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<div className="text-lg font-bold">
정말 삭제할까요?
<p className="text-xs font-normal text-black-500">
한번 삭제하면 되돌릴 수 없어요.
</p>
</div>
<div className="flex justify-end gap-[1rem]">
<Button
onClick={onClose}
fill={false}
colorScheme="grey"
size="small"
>
취소
</Button>
<Button onClick={handleClick} size="small">
확인
</Button>
</div>
</Modal>
</>
);
};

export const Default: Story = {
render: () => <BaseModal />,
};

export const Delete: Story = {
render: () => <DeleteModal />,
};
48 changes: 48 additions & 0 deletions src/ui/Base/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Dialog, Transition } from '@headlessui/react';
import { Fragment, ReactNode } from 'react';

interface ModalProps {
isOpen: boolean;
onClose: () => void;
children?: ReactNode;
}

const Modal = ({ isOpen, onClose, children }: ModalProps) => {
return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={onClose}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-overlay bg-opacity-60" />
</Transition.Child>

<div className="fixed inset-0 overflow-y-auto">
<div className="flex min-h-full items-center justify-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="flex w-[31.3rem] transform flex-col gap-[2.5rem] overflow-hidden rounded-[0.4rem] bg-white px-[2.5rem] py-[2rem] transition-all">
{children}
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
);
};

export default Modal;

0 comments on commit e5f8fcd

Please sign in to comment.