import { useState, type ReactNode, type CSSProperties } from 'react'; import { createPortal } from 'react-dom'; // The SDK theme tokens. A body-portaled node is outside the `.miu-messenger`/`.miu-inbox` // subtree that defines these, so we copy their resolved values onto the portal root. const THEME_VARS = [ '--miu-bg', '--miu-panel', '--miu-panel-2', '--miu-border', '--miu-text', '--miu-muted', '--miu-accent', '--miu-accent-text', '--miu-radius', ] as const; function copyThemeVars(): Record { if (typeof document === 'undefined') return {}; const src = document.querySelector('.miu-messenger, .miu-inbox'); if (!src) return {}; const cs = getComputedStyle(src); const out: Record = {}; for (const v of THEME_VARS) { const val = cs.getPropertyValue(v).trim(); if (val) out[v] = val; } return out; } /** * Render an overlay into document.body so it escapes the host's stacking context and overflow. * A host wrapper like `.view { position: relative; z-index: 1 }` traps a `position: fixed` overlay * BELOW a sibling sticky header no matter how high its z-index — the only robust fix is to leave * that stacking context entirely. Theme tokens are copied from the live surface (captured once on * mount, synchronously, so there is no unstyled first paint) and re-applied on the portal root. */ export function ModalPortal({ children }: { children: ReactNode }) { const [vars] = useState>(copyThemeVars); if (typeof document === 'undefined') return null; return createPortal(
{children}
, document.body); }