Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /** * Region Render Context * * Provides global rendering state to RegionPath components. * This avoids passing the same props to every region instance. * * Only values that are the SAME for all regions go here. * Per-region state (isHovered, isCelebrating, etc.) should still be props. */ 'use client' import { createContext, type ReactNode, useContext } from 'react' // ============================================================================ // Types // ============================================================================ export interface RegionRenderState { // ------------------------------------------------------------------------- // Theme // ------------------------------------------------------------------------- /** Whether dark mode is active */ isDark: boolean // ------------------------------------------------------------------------- // Device Capabilities // ------------------------------------------------------------------------- /** Whether pointer lock is active (disables native hover) */ pointerLocked: boolean /** Whether device has fine pointer (hides native cursor) */ hasAnyFinePointer: boolean // ------------------------------------------------------------------------- // Animation Progress (0-1) // ------------------------------------------------------------------------- /** Give-up reveal flash progress */ giveUpFlashProgress: number /** Hint animation flash progress */ hintFlashProgress: number /** Celebration flash progress */ celebrationFlashProgress: number /** Whether give-up animation is currently running (dims other regions) */ isGiveUpAnimating: boolean /** Whether celebration is in progress (disables clicks) */ celebrationActive: boolean } // ============================================================================ // Context // ============================================================================ const RegionRenderContext = createContext<RegionRenderState | null>(null) // ============================================================================ // Provider // ============================================================================ interface RegionRenderProviderProps extends RegionRenderState { children: ReactNode } /** * Provider for global region rendering state. * * Wrap your region list with this provider to avoid passing * the same props to every RegionPath component. * * @example * ```tsx * <RegionRenderProvider * isDark={isDark} * pointerLocked={pointerLocked} * hasAnyFinePointer={hasAnyFinePointer} * giveUpFlashProgress={giveUpFlashProgress} * hintFlashProgress={hintFlashProgress} * celebrationFlashProgress={celebrationFlashProgress} * isGiveUpAnimating={isGiveUpAnimating} * celebrationActive={!!celebration} * > * {regions.map(region => <RegionPath key={region.id} ... />)} * </RegionRenderProvider> * ``` */ export function RegionRenderProvider({ children, isDark, pointerLocked, hasAnyFinePointer, giveUpFlashProgress, hintFlashProgress, celebrationFlashProgress, isGiveUpAnimating, celebrationActive, }: RegionRenderProviderProps) { const value: RegionRenderState = { isDark, pointerLocked, hasAnyFinePointer, giveUpFlashProgress, hintFlashProgress, celebrationFlashProgress, isGiveUpAnimating, celebrationActive, } return <RegionRenderContext.Provider value={value}>{children}</RegionRenderContext.Provider> } // ============================================================================ // Hook // ============================================================================ /** * Access global region rendering state. * * Must be used within a RegionRenderProvider. * * @throws Error if used outside of provider */ export function useRegionRenderState(): RegionRenderState { const context = useContext(RegionRenderContext) if (!context) { throw new Error('useRegionRenderState must be used within a RegionRenderProvider') } return context } |