Skip to content

Commit

Permalink
feat: Dialog 컴포넌트 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
Puterism committed Jan 27, 2024
1 parent f907cc7 commit a0b64fa
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 2 deletions.
18 changes: 18 additions & 0 deletions apps/admin/src/pages/HomePage/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import Header from '../../components/Header/Header';
import Layout from '../../components/Layout/Layout';
import { PATH } from '../../constants/routes';
import Styled from './HomePage.styles';
import { Dialog, useDialogState } from '@boolti/ui';

const HomePage = () => {
const toast = useToast();
const { open, openDialog, closeDialog } = useDialogState();

return (
<Layout
Expand Down Expand Up @@ -53,6 +55,22 @@ const HomePage = () => {
정보 제공 토스트 띄우기
</button>
</div>
<button
onClick={() => {
openDialog();
}}
>
Open Dialog
</button>
<Dialog
title="Dialog Title"
open={open}
onClose={() => {
closeDialog();
}}
>
<p>Dialog Content</p>
</Dialog>
</Layout>
);
};
Expand Down
27 changes: 27 additions & 0 deletions packages/ui/src/components/Dialog/CloseIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const CloseIcon = () => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_248_3217)">
<path
d="M18 6L6 18"
stroke="#6D747C"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M6 6L18 18"
stroke="#6D747C"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_248_3217">
<rect width="24" height="24" fill="white" />
</clipPath>
</defs>
</svg>
);

export default CloseIcon;
54 changes: 54 additions & 0 deletions packages/ui/src/components/Dialog/Dialog.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import styled from '@emotion/styled';

const DIALOG_WIDTH = '450px';

const DimmedArea = styled.div`
position: fixed;
inset: 0;
background-color: rgba(86, 86, 86, 0.25);
display: flex;
justify-content: center;
align-items: center;
`;

const Dialog = styled.div`
width: ${DIALOG_WIDTH};
border-radius: 8px;
background-color: ${({ theme }) => theme.palette.grey.w};
`;

const DialogHeader = styled.div`
padding: 16px 32px;
border-bottom: 1px solid ${({ theme }) => theme.palette.grey.g30};
position: relative;
`;

const DialogTitle = styled.h2`
${({ theme }) => theme.typo.sh2};
color: ${({ theme }) => theme.palette.grey.g70};
`;

const DialogCloseButton = styled.button`
position: absolute;
top: 17px;
right: 32px;
width: 24px;
height: 24px;
display: inline-flex;
justify-content: center;
align-items: center;
cursor: pointer;
`;

const DialogContent = styled.div`
padding: 32px;
`;

export default {
DimmedArea,
Dialog,
DialogHeader,
DialogTitle,
DialogCloseButton,
DialogContent,
};
32 changes: 32 additions & 0 deletions packages/ui/src/components/Dialog/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Portal from '../Portal';
import CloseIcon from './CloseIcon';
import Styled from './Dialog.styles';

interface DialogProps {
open: boolean;
children: React.ReactNode;
title?: string;
onClose?: () => void;
}

const Dialog = ({ open, children, title, onClose }: DialogProps) => {
if (!open) return null;

return (
<Portal>
<Styled.DimmedArea>
<Styled.Dialog>
<Styled.DialogHeader>
<Styled.DialogTitle>{title}</Styled.DialogTitle>
<Styled.DialogCloseButton aria-label="닫기" onClick={onClose}>
<CloseIcon />
</Styled.DialogCloseButton>
</Styled.DialogHeader>
<Styled.DialogContent>{children}</Styled.DialogContent>
</Styled.Dialog>
</Styled.DimmedArea>
</Portal>
);
};

export default Dialog;
10 changes: 10 additions & 0 deletions packages/ui/src/components/Portal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom';

interface PortalProps {
children: React.ReactNode;
}

const Portal = ({ children }: PortalProps) => ReactDOM.createPortal(children, document.body);

export default Portal;
3 changes: 2 additions & 1 deletion packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ import ThemeProvider from './ThemeProvider';
import Button from './Button';
import TextButton from './TextButton';
import Badge from './Badge';
import Dialog from './Dialog';

export { ThemeProvider, Button, TextButton, Badge };
export { ThemeProvider, Button, TextButton, Badge, Dialog };
3 changes: 2 additions & 1 deletion packages/ui/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import useToast from './useToast';
import useDialogState from './useDialogState';

export { useToast };
export { useToast, useDialogState };
25 changes: 25 additions & 0 deletions packages/ui/src/hooks/useDialogState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useCallback, useState } from 'react';

interface UseDialogParams {
defaultOpen?: boolean;
}

const useDialogState = (params?: UseDialogParams) => {
const [open, setOpen] = useState<boolean>(params?.defaultOpen ?? false);

const openDialog = useCallback(() => {
setOpen(true);
}, []);

const closeDialog = useCallback(() => {
setOpen(false);
}, []);

return {
open,
openDialog,
closeDialog,
};
};

export default useDialogState;

0 comments on commit a0b64fa

Please sign in to comment.