diff --git a/src/components/ui/button/index.ts b/src/components/ui/button/index.ts index e69de29..31d66cb 100644 --- a/src/components/ui/button/index.ts +++ b/src/components/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button'; diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index bb80657..50198b7 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -1,4 +1,7 @@ -export { Notification } from '@/components/ui/modal/notification'; export { Table } from '@/components/ui/table'; +export { Button } from './button'; export { Dropdown } from './dropdown'; export { Icon } from './icon'; +export { Input } from './input'; +export { Modal, Notification } from './modal'; + diff --git a/src/components/ui/input/index.ts b/src/components/ui/input/index.ts index e69de29..3f24eca 100644 --- a/src/components/ui/input/index.ts +++ b/src/components/ui/input/index.ts @@ -0,0 +1 @@ +export { default as Input } from './input'; diff --git a/src/components/ui/modal/index.ts b/src/components/ui/modal/index.ts index a3db96e..e7f3887 100644 --- a/src/components/ui/modal/index.ts +++ b/src/components/ui/modal/index.ts @@ -1 +1,2 @@ -export { Notification } from '@/components/ui/modal/notification'; +export { default as Notification } from '@/components/ui/modal/notification'; +export { default as Modal } from './modal'; diff --git a/src/components/ui/modal/modal.tsx b/src/components/ui/modal/modal.tsx index c11bb02..699e54d 100644 --- a/src/components/ui/modal/modal.tsx +++ b/src/components/ui/modal/modal.tsx @@ -1,24 +1,25 @@ import { Icon } from '@/components/ui'; import Button from '@/components/ui/button/button'; import type { IconName } from '@/constants/icon'; +import { cn } from '@/lib/utils/cn'; import { ReactNode, useEffect } from 'react'; import { createPortal } from 'react-dom'; -type Variant = 'success' | 'warning'; //체크 아이콘 | 느낌표 아이콘 +type Variant = 'success' | 'warning'; type ModalProps = { - open: boolean; // 모달 열림 여부 - onClose: () => void; // 닫기 함수 - title: string; // 타이틀 (필수) - description?: ReactNode; // 본문 (선택) - variant?: Variant; // success | warning (기본 warning) - primaryText: string; // 주 버튼 라벨 - onPrimary: () => void; // 주 버튼 핸들러 - secondaryText?: string; // 보조 버튼 라벨 (선택) - onSecondary?: () => void; // 보조 버튼 핸들러 - closeOnDimmed?: boolean; // 딤 클릭 닫기 여부 (기본 true) - disablePortal?: boolean; // 포털 비활성화 (기본 false) - className?: string; // 커스텀 class 추가 + open: boolean; + onClose: () => void; + title: string; + description?: ReactNode; + variant?: Variant; + primaryText: string; + onPrimary: () => void; + secondaryText?: string; + onSecondary?: () => void; + closeOnDimmed?: boolean; + disablePortal?: boolean; + className?: string; }; const ICON_MAP: Record = { @@ -26,6 +27,79 @@ const ICON_MAP: Record = { warning: { circle: 'warningCircle', glyph: 'warning' }, }; +// ESC 닫기 +function useEscClose(open: boolean, onClose: () => void) { + useEffect(() => { + if (!open) return; + const onKey = (e: KeyboardEvent) => e.key === 'Escape' && onClose(); + window.addEventListener('keydown', onKey); + return () => window.removeEventListener('keydown', onKey); + }, [open, onClose]); +} + +/** Header */ +function ModalHeader({ variant, title }: { variant: Variant; title: string }) { + return ( +
+ + + + +

+ {title} +

+
+ ); +} + +/** Body (optional) */ +function ModalBody({ description }: { description?: ReactNode }) { + if (!description) return null; + return ( +
+ {description} +
+ ); +} + +/** Footer */ +function ModalFooter({ + primaryText, + onPrimary, + secondaryText, + onSecondary, +}: { + primaryText: string; + onPrimary: () => void; + secondaryText?: string; + onSecondary?: () => void; +}) { + return ( +
+ {secondaryText && onSecondary && ( + + )} + +
+ ); +} + export default function Modal({ open, onClose, @@ -38,15 +112,9 @@ export default function Modal({ onSecondary, closeOnDimmed = true, disablePortal = false, - className = '', + className, }: ModalProps) { - useEffect(() => { - if (!open) return; - const onKey = (e: KeyboardEvent) => e.key === 'Escape' && onClose(); - window.addEventListener('keydown', onKey); - return () => window.removeEventListener('keydown', onKey); - }, [open, onClose]); - + useEscClose(open, onClose); if (!open) return null; const node = ( @@ -67,53 +135,20 @@ export default function Modal({ )}
- {/* Header (아이콘, 제목) */} -
- - - - -

- {title} -

-
- - {/* Body(description ->선택) */} - {description && ( -
- {description} -
+ className )} - - {/* Footer (버튼)*/} -
- {secondaryText && ( - - )} - -
+ > + + +
); diff --git a/src/components/ui/modal/notification/index.ts b/src/components/ui/modal/notification/index.ts index 990ad9f..2159c1a 100644 --- a/src/components/ui/modal/notification/index.ts +++ b/src/components/ui/modal/notification/index.ts @@ -1 +1 @@ -export { default as Notification } from '@/components/ui/modal/notification/Notification'; +export { default } from '@/components/ui/modal/notification/Notification';