fix: implement ref-based fullscreen element tracking for proper persistence

- Update FullscreenContext to use ref-based element tracking instead of document.documentElement
- Add setFullscreenElement function to register specific DOM elements for fullscreen
- Update arcade page to register its main div as the fullscreen target element
- Update memory matching game to register its main div as the fullscreen target element
- Use element-specific fullscreen control instead of document-wide fullscreen

This properly fixes fullscreen persistence when navigating between components
by ensuring each component registers its specific container element as the
fullscreen target, preventing fullscreen loss during navigation.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-09-27 19:38:18 -05:00
parent 25053352fe
commit 7b947f2617
3 changed files with 46 additions and 15 deletions

View File

@@ -1,12 +1,20 @@
'use client'
import { useEffect } from 'react'
import { useEffect, useRef } from 'react'
import { css } from '../../../styled-system/css'
import { EnhancedChampionArena } from '../../components/EnhancedChampionArena'
import { FullscreenProvider, useFullscreen } from '../../contexts/FullscreenContext'
function ArcadeContent() {
const { isFullscreen, enterFullscreen, exitFullscreen } = useFullscreen()
const { isFullscreen, enterFullscreen, exitFullscreen, setFullscreenElement } = useFullscreen()
const arcadeRef = useRef<HTMLDivElement>(null)
useEffect(() => {
// Register this component's main div as the fullscreen element
if (arcadeRef.current) {
setFullscreenElement(arcadeRef.current)
}
}, [setFullscreenElement])
useEffect(() => {
// Check if we should enter fullscreen (from games page navigation)
@@ -24,12 +32,14 @@ function ArcadeContent() {
}
return (
<div className={css({
minH: 'screen',
background: 'linear-gradient(135deg, #0f0f23 0%, #1a1a3a 50%, #2d1b69 100%)',
position: 'relative',
overflow: 'hidden'
})}>
<div
ref={arcadeRef}
className={css({
minH: 'screen',
background: 'linear-gradient(135deg, #0f0f23 0%, #1a1a3a 50%, #2d1b69 100%)',
position: 'relative',
overflow: 'hidden'
})}>
{/* Animated background elements */}
<div className={css({
position: 'absolute',

View File

@@ -1,6 +1,6 @@
'use client'
import { useEffect } from 'react'
import { useEffect, useRef } from 'react'
import { useMemoryPairs } from '../context/MemoryPairsContext'
import { useFullscreen } from '../../../../contexts/FullscreenContext'
import { SetupPhase } from './SetupPhase'
@@ -10,7 +10,15 @@ import { css } from '../../../../../styled-system/css'
export function MemoryPairsGame() {
const { state } = useMemoryPairs()
const { enterFullscreen } = useFullscreen()
const { enterFullscreen, setFullscreenElement } = useFullscreen()
const gameRef = useRef<HTMLDivElement>(null)
useEffect(() => {
// Register this component's main div as the fullscreen element
if (gameRef.current) {
setFullscreenElement(gameRef.current)
}
}, [setFullscreenElement])
useEffect(() => {
// Check if we should enter fullscreen (from URL parameter)
@@ -21,8 +29,10 @@ export function MemoryPairsGame() {
}, [enterFullscreen])
return (
<div className={css({
minHeight: '100vh',
<div
ref={gameRef}
className={css({
minHeight: '100vh',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
padding: '20px',
display: 'flex',

View File

@@ -1,18 +1,21 @@
'use client'
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'
import React, { createContext, useContext, useState, useEffect, useRef, useCallback, ReactNode } from 'react'
interface FullscreenContextType {
isFullscreen: boolean
enterFullscreen: () => Promise<void>
exitFullscreen: () => Promise<void>
toggleFullscreen: () => Promise<void>
setFullscreenElement: (element: HTMLElement | null) => void
fullscreenElementRef: React.MutableRefObject<HTMLElement | null>
}
const FullscreenContext = createContext<FullscreenContextType | null>(null)
export function FullscreenProvider({ children }: { children: ReactNode }) {
const [isFullscreen, setIsFullscreen] = useState(false)
const fullscreenElementRef = useRef<HTMLElement | null>(null)
useEffect(() => {
const handleFullscreenChange = () => {
@@ -32,9 +35,15 @@ export function FullscreenProvider({ children }: { children: ReactNode }) {
}
}, [])
const setFullscreenElement = useCallback((element: HTMLElement | null) => {
fullscreenElementRef.current = element
}, [])
const enterFullscreen = async () => {
try {
const element = document.documentElement
// Use the registered fullscreen element, fallback to document.documentElement
const element = fullscreenElementRef.current || document.documentElement
if (element.requestFullscreen) {
await element.requestFullscreen()
} else if ((element as any).webkitRequestFullscreen) {
@@ -78,7 +87,9 @@ export function FullscreenProvider({ children }: { children: ReactNode }) {
isFullscreen,
enterFullscreen,
exitFullscreen,
toggleFullscreen
toggleFullscreen,
setFullscreenElement,
fullscreenElementRef
}}>
{children}
</FullscreenContext.Provider>