Skip to content

Commit

Permalink
[#472] Drawer 컴포넌트 (#477)
Browse files Browse the repository at this point in the history
* fix: Button 컴포넌트 스타일 오버라이드 가능하도록 수정

* feat: Drawer 구현
  • Loading branch information
gxxrxn committed Jun 17, 2024
1 parent 0a4705d commit 5e54b72
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 1 deletion.
73 changes: 73 additions & 0 deletions src/stories/base/Drawer.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Meta, StoryObj } from '@storybook/react';

import useDisclosure from '@/hooks/useDisclosure';

import Button from '@/v1/base/Button';
import Drawer from '@/v1/base/Drawer';

const meta: Meta<typeof Drawer> = {
title: 'Base/Drawer',
component: Drawer,
};

export default meta;

type Story = StoryObj<typeof Drawer>;

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

return (
<>
<Button onClick={onOpen}>Drawer 열기</Button>
<Drawer isOpen={isOpen} onClose={onClose}>
<Drawer.Header>
<Drawer.CloseButton position="top-right" />
<Drawer.Title text="Drawer Header" />
</Drawer.Header>
<Drawer.Content>
<p>Drawer Content</p>
</Drawer.Content>
</Drawer>
</>
);
};

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

return (
<>
<Button onClick={onOpen}>모임 글 작성하기</Button>
<Drawer isOpen={isOpen} onClose={onClose}>
<Drawer.Header>
<Drawer.CloseButton position="top-left" />
<Drawer.Title text="모임 게시글 작성하기" />
<Button
colorScheme="main"
fill={false}
size="medium"
className="flex-shrink-0 border-none !p-0"
onClick={onClose}
>
완료
</Button>
</Drawer.Header>
<Drawer.Content>
<textarea
className="h-[60vh] w-full resize-none border-none text-md focus:outline-none"
placeholder="책에 대한 여러분의 자유로운 생각을 들려주세요"
/>
</Drawer.Content>
</Drawer>
</>
);
};

export const Default: Story = {
render: BaseDrawer,
};

export const AddComment: Story = {
render: AddCommentDrawer,
};
3 changes: 2 additions & 1 deletion src/v1/base/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const Button = ({
colorScheme = 'main',
fill = true,
fullRadius = false,
className,
children,
...props
}: ButtonProps) => {
Expand All @@ -81,7 +82,7 @@ const Button = ({
return (
<button
type="button"
className={`${BASE_BUTTON_CLASSES} ${computedClasses}`}
className={`${BASE_BUTTON_CLASSES} ${computedClasses} ` + className}
{...props}
>
{children}
Expand Down
95 changes: 95 additions & 0 deletions src/v1/base/Drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { createContext, PropsWithChildren, ReactNode, useContext } from 'react';

import { IconClose } from '@public/icons';
import Portal from './Portal';

interface DrawerProps {
isOpen: boolean;
onClose?: () => void;
}

type DrawerContextValue = DrawerProps;

const DrawerContext = createContext({} as DrawerContextValue);
const useDrawerContext = () => useContext(DrawerContext);

const Drawer = ({
isOpen,
onClose,
children,
}: PropsWithChildren<DrawerProps>) => {
return (
<DrawerContext.Provider value={{ isOpen, onClose }}>
<Portal id="drawer">
<div
className={`absolute inset-0 z-10 transform overflow-hidden ease-in-out ${
isOpen
? 'translate-x-0 scale-x-100 opacity-100 transition-opacity duration-500'
: 'translate-x-full scale-x-0 opacity-0 transition-all delay-100 duration-500'
}`}
>
<section
className={`duration-400 absolute right-0 flex h-full w-full max-w-[43rem] transform flex-col gap-[2rem] overflow-hidden bg-white p-[2rem] shadow-bookcard transition-all ease-in-out ${
isOpen ? 'translate-x-0' : 'translate-x-full'
}`}
>
{isOpen && children}
</section>
{/** overlay */}
<section className="h-full w-full" onClick={onClose}></section>
</div>
</Portal>
</DrawerContext.Provider>
);
};

const DrawerHeader = ({ children }: { children?: ReactNode }) => {
return (
<div className="flex items-center justify-between py-[0.5rem]">
{children}
</div>
);
};

const DrawerContent = ({ children }: { children?: ReactNode }) => {
return <div className="w-full text-md">{children}</div>;
};

const Title = ({ text }: { text?: string }) => {
return (
<h1 className="flex-grow truncate pl-[2.5rem] text-center text-md">
{text}
</h1>
);
};

type Position = 'top-left' | 'top-right';

const getPositionClasses = (postion: Position) => {
switch (postion) {
case 'top-right':
return 'top-[2.7rem] right-[2rem]';
case 'top-left':
default:
return 'top-[2.7rem] left-[2rem]';
}
};

const CloseButton = ({ position = 'top-left' }: { position?: Position }) => {
const { onClose } = useDrawerContext();
const positionClasses = getPositionClasses(position);

return (
<IconClose
className={`absolute h-[2rem] w-[2rem] cursor-pointer fill-black-900 ${positionClasses}`}
onClick={onClose}
/>
);
};

Drawer.Header = DrawerHeader;
Drawer.Content = DrawerContent;
Drawer.Title = Title;
Drawer.CloseButton = CloseButton;

export default Drawer;

0 comments on commit 5e54b72

Please sign in to comment.