123 lines
3.8 KiB
TypeScript
123 lines
3.8 KiB
TypeScript
import { useState, useCallback, useEffect, type RefObject } from 'react';
|
|
|
|
interface UseFullscreenReturn {
|
|
/** Whether the element is currently fullscreen */
|
|
isFullscreen: boolean;
|
|
/** Enter fullscreen mode */
|
|
enterFullscreen: () => Promise<void>;
|
|
/** Exit fullscreen mode */
|
|
exitFullscreen: () => Promise<void>;
|
|
/** Toggle fullscreen mode */
|
|
toggleFullscreen: () => void;
|
|
}
|
|
|
|
/**
|
|
* Hook to manage fullscreen mode for a container element.
|
|
* Uses the Fullscreen API with fallback styling.
|
|
*
|
|
* @param containerRef - Ref to the element to make fullscreen
|
|
* @returns Object with fullscreen state and control functions
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* const containerRef = useRef<HTMLDivElement>(null);
|
|
* const { isFullscreen, toggleFullscreen } = useFullscreen(containerRef);
|
|
*
|
|
* return (
|
|
* <div ref={containerRef} className={isFullscreen ? 'fullscreen' : ''}>
|
|
* <button onClick={toggleFullscreen}>
|
|
* {isFullscreen ? 'Exit' : 'Enter'} Fullscreen
|
|
* </button>
|
|
* <div>Content here</div>
|
|
* </div>
|
|
* );
|
|
* ```
|
|
*/
|
|
export function useFullscreen(containerRef: RefObject<HTMLElement | null>): UseFullscreenReturn {
|
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
|
|
const enterFullscreen = useCallback(async () => {
|
|
const container = containerRef.current;
|
|
if (!container) return;
|
|
|
|
try {
|
|
if (container.requestFullscreen) {
|
|
await container.requestFullscreen();
|
|
} else if ((container as any).webkitRequestFullscreen) {
|
|
await (container as any).webkitRequestFullscreen();
|
|
} else if ((container as any).msRequestFullscreen) {
|
|
await (container as any).msRequestFullscreen();
|
|
}
|
|
} catch (err) {
|
|
console.warn('Fullscreen API not available, using CSS fallback');
|
|
// CSS fallback handled by isFullscreen state
|
|
setIsFullscreen(true);
|
|
}
|
|
}, [containerRef]);
|
|
|
|
const exitFullscreen = useCallback(async () => {
|
|
try {
|
|
if (document.exitFullscreen) {
|
|
await document.exitFullscreen();
|
|
} else if ((document as any).webkitExitFullscreen) {
|
|
await (document as any).webkitExitFullscreen();
|
|
} else if ((document as any).msExitFullscreen) {
|
|
await (document as any).msExitFullscreen();
|
|
}
|
|
} catch (err) {
|
|
// CSS fallback
|
|
setIsFullscreen(false);
|
|
}
|
|
}, []);
|
|
|
|
const toggleFullscreen = useCallback(() => {
|
|
if (isFullscreen) {
|
|
exitFullscreen();
|
|
} else {
|
|
enterFullscreen();
|
|
}
|
|
}, [isFullscreen, enterFullscreen, exitFullscreen]);
|
|
|
|
// Listen for fullscreen change events
|
|
useEffect(() => {
|
|
const handleFullscreenChange = () => {
|
|
const isCurrentlyFullscreen = !!(
|
|
document.fullscreenElement ||
|
|
(document as any).webkitFullscreenElement ||
|
|
(document as any).msFullscreenElement
|
|
);
|
|
setIsFullscreen(isCurrentlyFullscreen);
|
|
};
|
|
|
|
document.addEventListener('fullscreenchange', handleFullscreenChange);
|
|
document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
|
|
document.addEventListener('MSFullscreenChange', handleFullscreenChange);
|
|
|
|
return () => {
|
|
document.removeEventListener('fullscreenchange', handleFullscreenChange);
|
|
document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);
|
|
document.removeEventListener('MSFullscreenChange', handleFullscreenChange);
|
|
};
|
|
}, []);
|
|
|
|
// Handle Escape key for CSS fallback mode
|
|
useEffect(() => {
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape' && isFullscreen && !document.fullscreenElement) {
|
|
setIsFullscreen(false);
|
|
}
|
|
};
|
|
|
|
document.addEventListener('keydown', handleKeyDown);
|
|
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
}, [isFullscreen]);
|
|
|
|
return {
|
|
isFullscreen,
|
|
enterFullscreen,
|
|
exitFullscreen,
|
|
toggleFullscreen,
|
|
};
|
|
}
|
|
|
|
export default useFullscreen;
|