164 lines
4.9 KiB
TypeScript
164 lines
4.9 KiB
TypeScript
/**
|
|
* 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)
|
|
* <PageNavigationProvider preloadCache={preloadOrchestrator} transitionSettings={transitionSettings}>
|
|
* <CanvasBackground />
|
|
* <Elements />
|
|
* </PageNavigationProvider>
|
|
*
|
|
* // 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<UsePageNavigationStateResult | null>(null);
|
|
|
|
// ============================================================================
|
|
// Provider
|
|
// ============================================================================
|
|
|
|
export interface PageNavigationProviderProps
|
|
extends UsePageNavigationStateOptions {
|
|
children: ReactNode;
|
|
}
|
|
|
|
/**
|
|
* Provider component that wraps usePageNavigationState and exposes it via context.
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* <PageNavigationProvider
|
|
* preloadCache={preloadOrchestrator}
|
|
* transitionSettings={transitionSettings}
|
|
* >
|
|
* <CanvasBackground ... />
|
|
* <PageElements ... />
|
|
* </PageNavigationProvider>
|
|
* ```
|
|
*/
|
|
export function PageNavigationProvider({
|
|
children,
|
|
...options
|
|
}: PageNavigationProviderProps) {
|
|
const navState = usePageNavigationState(options);
|
|
|
|
return (
|
|
<PageNavigationContext.Provider value={navState}>
|
|
{children}
|
|
</PageNavigationContext.Provider>
|
|
);
|
|
}
|
|
|
|
// ============================================================================
|
|
// 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 (
|
|
* <img
|
|
* onLoad={onBackgroundReady}
|
|
* style={{ opacity: isNewBgReady ? 1 : 0 }}
|
|
* />
|
|
* );
|
|
* }
|
|
* ```
|
|
*/
|
|
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 <div>Phase: {navState.phase}</div>;
|
|
* }
|
|
*
|
|
* // Outside provider - render without navigation state
|
|
* return <div>Standalone mode</div>;
|
|
* }
|
|
* ```
|
|
*/
|
|
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<T>(
|
|
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';
|