import * as React from "react" import { createOverlayScope, globalOverlayScope, type OverlayScope, } from "./scope" interface OverlayScopeContextValue { scope: OverlayScope scopes: Readonly> } const OverlayScopeContext = React.createContext({ scope: globalOverlayScope, scopes: { global: globalOverlayScope }, }) OverlayScopeContext.displayName = "OverlayScopeContext" export interface OverlayScopeProviderProps { children?: React.ReactNode /** Creates a local scope with this name when `scope` is omitted. */ name?: string scope?: OverlayScope scopes?: Readonly> } /** Provides scope lookup only; feature hosts remain explicit and tree-shakeable. */ export function OverlayScopeProvider({ children, name, scope, scopes, }: OverlayScopeProviderProps) { const parent = React.useContext(OverlayScopeContext) const [generatedScope] = React.useState(() => createOverlayScope({ name })) const currentScope = scope ?? (name ? generatedScope : parent.scope) const namedScopes = React.useMemo(() => { const next = { ...parent.scopes, ...scopes } if (name) next[name] = currentScope return next }, [currentScope, name, parent.scopes, scopes]) const value = React.useMemo( () => ({ scope: currentScope, scopes: namedScopes }), [currentScope, namedScopes] ) return ( {children} ) } export function useOverlayScope(name?: string) { const context = React.useContext(OverlayScopeContext) if (!name) return context.scope const scope = context.scopes[name] if (!scope) { throw new Error(`No overlay scope named "${name}" exists in this subtree`) } return scope } export function useOverlayScopes() { return React.useContext(OverlayScopeContext).scopes }