All files / web/src/arcade-games/know-your-world/components RegionRenderContext.tsx

0% Statements 0/127
0% Branches 0/1
0% Functions 0/1
0% Lines 0/127

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
}