import { useLocation, useNavigate, useSearchParams } from 'react-router'; // 시트/드로어/모달 같은 "오버레이" 열림 상태를 쿼리스트링으로 표현하는 단일 출처. // 로컬 useState 대신 URL 에 담아 딥링크·뒤로가기·새로고침을 지원한다. // 같은 그룹(keys) 안에서는 한 번에 하나만 연다(상호배타: 열 때 나머지 키 제거). // // const overlay = useOverlayRouter(['detail', 'new', 'modal']); // overlay.get('detail') // ?detail= 의 값(없으면 null) — 값 있는 오버레이 // overlay.has('new') // ?new 존재 여부 — 플래그 오버레이 // overlay.open('detail', id) // ?detail= (다른 오버레이 키는 지움) — 히스토리 push // overlay.open('new') // ?new (값 생략 시 '1') // overlay.open('detail', id, { replace: true }) // 같은 오버레이 내 값만 교체(히스토리 안 쌓음) // overlay.close() // 그룹 내 모든 오버레이 키 제거 const OVERLAY_PUSHED = '__overlayPushed'; export function useOverlayRouter(keys: readonly K[]) { const [searchParams] = useSearchParams(); const navigate = useNavigate(); const location = useLocation(); const get = (key: K) => searchParams.get(key); const has = (key: K) => searchParams.has(key); // 현재 쿼리에서 그룹 키를 모두 지운 뒤 mutate 를 적용해 search 문자열을 만든다. const buildSearch = (mutate: (params: URLSearchParams) => void) => { const next = new URLSearchParams(searchParams); keys.forEach((k) => next.delete(k)); mutate(next); const s = next.toString(); return s ? `?${s}` : ''; }; const open = (key: K, value = '1', opts?: { replace?: boolean }) => { const replace = opts?.replace ?? false; navigate( { pathname: location.pathname, search: buildSearch((p) => p.set(key, value)) }, { replace, // push: 새 히스토리 → 닫을 때 navigate(-1)로 빠지게 표식. // replace(같은 오버레이 안에서 값만 교체, 예: 차수 전환): 히스토리를 안 쌓고, // 원래 열림이 push였는지 표식을 그대로 물려준다(닫기 동작이 일관되게 리스트로 빠지도록). state: { ...(location.state ?? {}), [OVERLAY_PUSHED]: replace ? location.state?.[OVERLAY_PUSHED] ?? false : true, }, }, ); }; const close = () => { if (location.state?.[OVERLAY_PUSHED]) { navigate(-1); return; } navigate( { pathname: location.pathname, search: buildSearch(() => {}) }, { replace: true }, ); }; return { get, has, open, close }; }