import type { ReactNode } from 'react'; /** * SModal.confirm/loading/create 가 띄운 모달의 전역 목록. * * 왜 필요한가: 명령형 API 는 React 밖(버튼 핸들러·async 흐름)에서 호출되므로 렌더 트리에 * 노드를 끼워 넣을 방법이 없다. 그래서 원래는 호출할 때마다 `createRoot` 로 새 React 루트를 * 만들었는데, Context 는 DOM 이 아니라 렌더 트리를 타므로 그 루트에는 앱의 Provider * (QueryClient·Router·Theme 등)가 하나도 닿지 않았다. * * 이 스토어가 그 사이를 잇는다 — 명령형 호출은 여기에 push 만 하고, 앱 트리 안에 한 번 * 렌더된 `SModalOutlet` 이 구독해 `createPortal` 로 그린다. DOM 위치는 예전과 같은 body * 직속 host 지만 렌더 트리는 앱의 자식이 되어 Provider 가 전부 상속된다. * * outlet 이 없는 앱(구버전 부트스트랩)에서는 SModal 이 예전 `createRoot` 경로로 폴백한다. */ export interface SModalEntry { /** 스토어 내 식별자 — 제거 대상 지정에 쓴다 */ id: number; /** body 직속 host. 모달 자신은 다시 Portal 로 modal host 에 나가므로 보통 비어 있다 */ host: HTMLElement; /** 마운트 래퍼 엘리먼트 */ node: ReactNode; /** outlet 이 사라져 더 그릴 수 없게 됐을 때 — 콜백 마무리·정리를 엔트리 주인에게 맡긴다 */ onOrphan: () => void; } /** @internal useSyncExternalStore 구독 */ export declare function subscribeModalEntries(listener: () => void): () => void; /** @internal 현재 스냅샷 — 변경이 없으면 같은 참조를 유지해야 한다 */ export declare function getModalEntries(): readonly SModalEntry[]; /** @internal SSR 스냅샷 — 서버에서는 명령형 모달이 열려 있을 수 없다 */ export declare function getServerModalEntries(): readonly SModalEntry[]; /** * @internal outlet 존재 표시 — **렌더 단계에서** 호출한다. * * 커밋 후 effect 로 등록하면 늦다. effect 는 자식→부모 순으로 돌기 때문에, 페이지가 최초 * 마운트 effect 에서 모달을 열면 트리 뒤쪽에 있는 outlet 의 effect 가 아직 돌지 않아 * "outlet 없음"으로 판정되고 폴백 경로를 탄다 — 이 구조가 없애려던 Context 단절이 그대로 * 재현된다. 렌더는 어떤 effect 보다도 앞서므로 여기서 표시한다. (플래그 세팅뿐이라 멱등) */ export declare function markModalOutletRendered(): void; /** * @internal outlet 마운트 등록. 반환값을 effect cleanup 으로 호출한다. * (StrictMode 의 mount→unmount→mount 를 카운터로 견딘다) */ export declare function registerModalOutlet(): () => void; /** @internal outlet 이 앱 트리에 있는가 — SModal 이 마운트 방식을 고르는 기준 */ export declare function hasModalOutlet(): boolean; /** @internal outlet 이 이미 커밋돼 있는가 — 중복 outlet 개발 경고용 */ export declare function isModalOutletMounted(): boolean; /** @internal 모달 추가 → outlet 이 그린다. 반환한 id 로 나중에 제거한다 */ export declare function addModalEntry(host: HTMLElement, node: ReactNode, onOrphan: () => void): number; /** @internal 모달 제거 → outlet 이 언마운트하고 host 도 함께 정리한다 */ export declare function removeModalEntry(id: number): void;