diff --git a/CHANGELOG.md b/CHANGELOG.md index 54c3a3e..4fb0956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,32 @@ ## [Unreleased] +## [0.2.5] - 2026-01-18 + +### Added + +- Modal 컴포넌트 actionButton에 아이콘 지원 + - `leftIcon`, `rightIcon` prop 추가 + - Button 컴포넌트와 동일한 방식으로 아이콘 렌더링 + - 스토리북 예시 추가 (`WithActionButtonLeftIcon`, `WithActionButtonRightIcon`) +- Modal actionButton 테스트 추가 + - leftIcon 단독 렌더링 테스트 + - rightIcon 단독 렌더링 테스트 + - 아이콘과 onClick 이벤트 통합 테스트 + +### Changed + +- Modal actionButton 인터페이스 확장 + - `actionButton.leftIcon?: ReactNode` - 버튼 왼쪽에 표시할 아이콘 + - `actionButton.rightIcon?: ReactNode` - 버튼 오른쪽에 표시할 아이콘 + +### Fixed + +- 잘못된 테스트 케이스 제거 + - Button 컴포넌트는 leftIcon과 rightIcon을 동시에 지원하지 않는 구조 + - leftIcon이 있으면 rightIcon은 무시되는 동작 + - 동시 렌더링 테스트 케이스 제거 + ## [0.2.4] - 2026-01-18 ### Added diff --git a/package.json b/package.json index baa59d2..b7348e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@team-numberone/daepiro-design-system", - "version": "0.2.4", + "version": "0.2.5", "description": "대피로 디자인 시스템 - React 컴포넌트 라이브러리", "private": false, "packageManager": "pnpm@10.25.0", diff --git a/src/components/modal/Modal.stories.tsx b/src/components/modal/Modal.stories.tsx index d3a62da..89cb040 100644 --- a/src/components/modal/Modal.stories.tsx +++ b/src/components/modal/Modal.stories.tsx @@ -327,6 +327,82 @@ export const WithActionButton: Story = { }, }; +export const WithActionButtonLeftIcon: Story = { + render: (args) => { + const [open, setOpen] = useState(false); + + return ( + <> + + 📞, + onClick: () => { + alert("119에 신고되었습니다!"); + setOpen(false); + }, + }} + > + {args.children} + + + ); + }, + args: { + size: "medium", + children: ( +
+

맞아요!

+

+ 119에 도움을 요청해보세요! (왼쪽 아이콘 포함) +

+
+ ), + }, +}; + +export const WithActionButtonRightIcon: Story = { + render: (args) => { + const [open, setOpen] = useState(false); + + return ( + <> + + →, + onClick: () => { + alert("다음 단계로 이동합니다!"); + setOpen(false); + }, + }} + > + {args.children} + + + ); + }, + args: { + size: "medium", + children: ( +
+

진행하시겠어요?

+

+ 다음 단계로 진행하려면 버튼을 클릭하세요. (오른쪽 아이콘 포함) +

+
+ ), + }, +}; + export const AllSizes: Story = { render: () => { const sizes = ["small", "medium", "large"] as const; diff --git a/src/components/modal/Modal.test.tsx b/src/components/modal/Modal.test.tsx index c082eb8..cb2c1ee 100644 --- a/src/components/modal/Modal.test.tsx +++ b/src/components/modal/Modal.test.tsx @@ -525,4 +525,66 @@ describe("Modal 컴파운드 패턴", () => { expect(actionButton).toBeInTheDocument(); }); }); + + describe("actionButton 아이콘", () => { + it("actionButton에 leftIcon이 표시되는지", () => { + render( + {}} + actionButton={{ + label: "확인", + leftIcon: , + }} + > + 모달 내용 + + ); + + expect(screen.getByTestId("left-icon")).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /확인/ })).toBeInTheDocument(); + }); + + it("actionButton에 rightIcon이 표시되는지", () => { + render( + {}} + actionButton={{ + label: "확인", + rightIcon: , + }} + > + 모달 내용 + + ); + + expect(screen.getByTestId("right-icon")).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /확인/ })).toBeInTheDocument(); + }); + + it("actionButton의 아이콘과 onClick이 함께 동작하는지", async () => { + const handleActionClick = vi.fn(); + const user = userEvent.setup(); + render( + {}} + actionButton={{ + label: "확인", + onClick: handleActionClick, + leftIcon: , + }} + > + 모달 내용 + + ); + + const actionButton = screen.getByRole("button", { name: /확인/ }); + expect(screen.getByTestId("left-icon")).toBeInTheDocument(); + + await user.click(actionButton); + expect(handleActionClick).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/src/components/modal/Modal.tsx b/src/components/modal/Modal.tsx index 36d576f..bf172f2 100644 --- a/src/components/modal/Modal.tsx +++ b/src/components/modal/Modal.tsx @@ -200,6 +200,8 @@ export interface ModalProps extends ModalRootProps { actionButton?: { label: string; onClick?: () => void; + leftIcon?: ReactNode; + rightIcon?: ReactNode; }; } @@ -222,7 +224,13 @@ export function Modal({ display: "flex", }} > -