モーダル積層管理
:LiTarget: 用途
複数モーダルを安全に積み重ねるパターン。z-indexとEscキー処理。
:LiSparkle: 特徴
- z-index自動管理
- Escキー処理
- スクロールロック
:LiCode: コード(コピペ用)
'use client';
import { useEffect, useRef, ReactNode } from 'react';
let stackDepth = 0;
// z-index 自動管理 + Esc キー対応モーダル
export function Modal({ open, onClose, children }: { open: boolean; onClose: () => void; children: ReactNode }) {
const z = useRef(0);
useEffect(() => {
if (!open) return;
stackDepth++;
z.current = 50 + stackDepth * 10;
// 一番上のモーダルだけ Esc を効かせる
const me = stackDepth;
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape' && me === stackDepth) onClose();
};
document.addEventListener('keydown', onKey);
// body スクロールロック(最初のモーダル時だけ)
if (stackDepth === 1) document.body.style.overflow = 'hidden';
return () => {
stackDepth--;
document.removeEventListener('keydown', onKey);
if (stackDepth === 0) document.body.style.overflow = '';
};
}, [open, onClose]);
if (!open) return null;
return (
<div className="fixed inset-0 bg-black/60 flex items-center justify-center p-4" style={{ zIndex: z.current }} onClick={onClose}>
<div className="bg-zinc-900 border border-zinc-800 rounded-2xl p-6 max-w-2xl w-full" onClick={(e) => e.stopPropagation()}>
{children}
</div>
</div>
);
}
:LiHandPointer: 使い方
対象プロジェクトに該当ファイルをコピーして、props を流し込むだけ。
:LiAlertCircle: 注意事項
- 依存パッケージを忘れず追加