/** * PageNavigationContext * * Context provider for sharing page navigation state with child components. * Wraps the usePageNavigationState hook to provide state machine access * throughout the component tree without prop drilling. * * Usage: * ```tsx * // In parent (constructor.tsx or RuntimePresentation.tsx) * * * * * * // In child components * const { phase, onBackgroundReady, isSwitching } = usePageNavigationContext(); * ``` */ import React, { createContext, useContext, ReactNode, useMemo } from 'react'; import { usePageNavigationState, UsePageNavigationStateOptions, UsePageNavigationStateResult, } from '../hooks/usePageNavigationState'; // ============================================================================ // Context // ============================================================================ const PageNavigationContext = createContext(null); // ============================================================================ // Provider // ============================================================================ export interface PageNavigationProviderProps extends UsePageNavigationStateOptions { children: ReactNode; } /** * Provider component that wraps usePageNavigationState and exposes it via context. * * @example * ```tsx * * * * * ``` */ export function PageNavigationProvider({ children, ...options }: PageNavigationProviderProps) { const navState = usePageNavigationState(options); return ( {children} ); } // ============================================================================ // Hooks // ============================================================================ /** * Hook to access page navigation state from context. * Must be used within a PageNavigationProvider. * * @throws Error if used outside of PageNavigationProvider * * @example * ```tsx * function CanvasBackground() { * const { onBackgroundReady, isSwitching, isNewBgReady } = usePageNavigationContext(); * * return ( * * ); * } * ``` */ export function usePageNavigationContext(): UsePageNavigationStateResult { const ctx = useContext(PageNavigationContext); if (!ctx) { throw new Error( 'usePageNavigationContext must be used within a PageNavigationProvider', ); } return ctx; } /** * Hook to optionally access page navigation state from context. * Returns null if used outside of PageNavigationProvider. * Useful for components that may be used both inside and outside the provider. * * @example * ```tsx * function FlexibleComponent() { * const navState = usePageNavigationContextOptional(); * * if (navState) { * // Inside provider - use navigation state * return
Phase: {navState.phase}
; * } * * // Outside provider - render without navigation state * return
Standalone mode
; * } * ``` */ export function usePageNavigationContextOptional(): UsePageNavigationStateResult | null { return useContext(PageNavigationContext); } // ============================================================================ // Selector Hook // ============================================================================ /** * Hook to select specific parts of the navigation state. * Helps with performance by allowing components to subscribe to only what they need. * * @example * ```tsx * // Only re-render when phase changes * const phase = usePageNavigationSelector(state => state.phase); * * // Get multiple values * const { isSwitching, isNewBgReady } = usePageNavigationSelector(state => ({ * isSwitching: state.isSwitching, * isNewBgReady: state.isNewBgReady, * })); * ``` */ export function usePageNavigationSelector( selector: (state: UsePageNavigationStateResult) => T, ): T { const ctx = usePageNavigationContext(); // Note: This doesn't prevent re-renders on its own since the context value changes. // For true selector optimization, consider using useSyncExternalStore or a state management library. // This is primarily for code organization/readability. return useMemo(() => selector(ctx), [ctx, selector]); } // ============================================================================ // Exports // ============================================================================ export type { UsePageNavigationStateResult } from '../hooks/usePageNavigationState';