fix(pop-modal): 중첩 모달 닫기 시 모든 모달이 한꺼번에 닫히는 버그 수정

- handleCloseModal(index) -> handleCloseTopModal()로 변경 (최상위 1개만 닫기)
- onOpenChange에 isTopModal 가드 추가 (하위 모달 연쇄 반응 방지)
- onInteractOutside/onEscapeKeyDown에 isTopModal 가드 추가

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
SeongHyun Kim 2026-02-23 14:03:55 +09:00
parent df8cbb3e80
commit fc0e913b8a
1 changed files with 8 additions and 8 deletions

View File

@ -91,9 +91,9 @@ export default function PopViewerWithModals({
}; };
}, [subscribe, layout.modals]); }, [subscribe, layout.modals]);
// 특정 인덱스의 모달 닫기 // 최상위 모달만 닫기 (X 버튼, overlay 클릭, ESC)
const handleCloseModal = useCallback((index: number) => { const handleCloseTopModal = useCallback(() => {
setModalStack(prev => prev.slice(0, index)); setModalStack(prev => prev.slice(0, -1));
}, []); }, []);
return ( return (
@ -112,10 +112,10 @@ export default function PopViewerWithModals({
{/* 모달 스택 렌더링 */} {/* 모달 스택 렌더링 */}
{modalStack.map((modal, index) => { {modalStack.map((modal, index) => {
const { definition } = modal; const { definition } = modal;
const isTopModal = index === modalStack.length - 1;
const closeOnOverlay = definition.frameConfig?.closeOnOverlay !== false; const closeOnOverlay = definition.frameConfig?.closeOnOverlay !== false;
const closeOnEsc = definition.frameConfig?.closeOnEsc !== false; const closeOnEsc = definition.frameConfig?.closeOnEsc !== false;
// 모달의 layout 구성 (모달 자체를 하나의 레이아웃으로)
const modalLayout: PopLayoutDataV5 = { const modalLayout: PopLayoutDataV5 = {
...layout, ...layout,
gridConfig: definition.gridConfig, gridConfig: definition.gridConfig,
@ -123,7 +123,6 @@ export default function PopViewerWithModals({
overrides: definition.overrides, overrides: definition.overrides,
}; };
// sizeConfig 기반 모달 너비 계산
const detectedMode = currentMode || detectGridMode(viewportWidth); const detectedMode = currentMode || detectGridMode(viewportWidth);
const modalWidth = resolveModalWidth(definition.sizeConfig, detectedMode, viewportWidth); const modalWidth = resolveModalWidth(definition.sizeConfig, detectedMode, viewportWidth);
const isFull = modalWidth >= viewportWidth; const isFull = modalWidth >= viewportWidth;
@ -134,7 +133,7 @@ export default function PopViewerWithModals({
key={`${definition.id}-${index}`} key={`${definition.id}-${index}`}
open={true} open={true}
onOpenChange={(open) => { onOpenChange={(open) => {
if (!open) handleCloseModal(index); if (!open && isTopModal) handleCloseTopModal();
}} }}
> >
<DialogContent <DialogContent
@ -147,10 +146,11 @@ export default function PopViewerWithModals({
width: `${modalWidth}px`, width: `${modalWidth}px`,
}} }}
onInteractOutside={(e) => { onInteractOutside={(e) => {
if (!closeOnOverlay) e.preventDefault(); // 최상위 모달이 아니면 overlay 클릭 무시 (하위 모달이 먼저 닫히는 것 방지)
if (!isTopModal || !closeOnOverlay) e.preventDefault();
}} }}
onEscapeKeyDown={(e) => { onEscapeKeyDown={(e) => {
if (!closeOnEsc) e.preventDefault(); if (!isTopModal || !closeOnEsc) e.preventDefault();
}} }}
> >
<DialogHeader className={isFull ? "px-4 pt-3 pb-2" : "px-4 pt-4 pb-2"}> <DialogHeader className={isFull ? "px-4 pt-3 pb-2" : "px-4 pt-4 pb-2"}>