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 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | /**
* 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
}
|