diff --git a/packages/usehooks-ts/src/index.ts b/packages/usehooks-ts/src/index.ts index 9577bd16..20ecf4dc 100644 --- a/packages/usehooks-ts/src/index.ts +++ b/packages/usehooks-ts/src/index.ts @@ -9,6 +9,7 @@ export * from './useDebounceValue' export * from './useDocumentTitle' export * from './useEventCallback' export * from './useEventListener' +export * from './useFullScreen' export * from './useHover' export * from './useIntersectionObserver' export * from './useInterval' diff --git a/packages/usehooks-ts/src/useFullScreen/index.ts b/packages/usehooks-ts/src/useFullScreen/index.ts new file mode 100644 index 00000000..9f6693c7 --- /dev/null +++ b/packages/usehooks-ts/src/useFullScreen/index.ts @@ -0,0 +1 @@ +export * from './useFullScreen' diff --git a/packages/usehooks-ts/src/useFullScreen/useFullscreen.demo.tsx b/packages/usehooks-ts/src/useFullScreen/useFullscreen.demo.tsx new file mode 100644 index 00000000..18ccc0ca --- /dev/null +++ b/packages/usehooks-ts/src/useFullScreen/useFullscreen.demo.tsx @@ -0,0 +1,70 @@ +import React, { useRef } from 'react'; +import { useFullscreen } from './useFullscreen'; + +const Component: React.FC = () => { + const containerRef = useRef(null); + const { isFullscreen, toggleFullscreen, exitFullscreen } = useFullscreen(containerRef); + + return ( +
+
+

{isFullscreen ? 'Fullscreen Mode' : 'Click to Enter Fullscreen'}

+
+
+ + {isFullscreen && ( + + )} +
+
+ ); +}; + +export default Component; diff --git a/packages/usehooks-ts/src/useFullScreen/useFullscreen.md b/packages/usehooks-ts/src/useFullScreen/useFullscreen.md new file mode 100644 index 00000000..8be45b48 --- /dev/null +++ b/packages/usehooks-ts/src/useFullScreen/useFullscreen.md @@ -0,0 +1,15 @@ +# useFullscreen Hook + +`useFullscreen` is a custom React hook that manages fullscreen functionality for a specific container element. It provides methods to toggle fullscreen mode, exit fullscreen, and track whether the element is currently in fullscreen mode. + +## Features +- Manage fullscreen state for a specific element. +- Toggle fullscreen mode for any container. +- Exit fullscreen programmatically. +- Automatically updates state on `fullscreenchange` events. + +## Installation +To use this hook, copy the `useFullscreen` code into your project. + +```typescript +import { useFullscreen } from 'usehooks-ts'; diff --git a/packages/usehooks-ts/src/useFullScreen/useFullscreen.test.ts b/packages/usehooks-ts/src/useFullScreen/useFullscreen.test.ts new file mode 100644 index 00000000..232a7d6d --- /dev/null +++ b/packages/usehooks-ts/src/useFullScreen/useFullscreen.test.ts @@ -0,0 +1,52 @@ +import { renderHook, act } from '@testing-library/react-hooks'; +import { useFullscreen } from './useFullscreen'; + +describe('useFullscreen', () => { + test('should initialize with default values', () => { + const containerRef = { current: null } as any; + const { result } = renderHook(() => useFullscreen(containerRef)); + + expect(result.current.isFullscreen).toBe(false); + }); + + test('should toggle fullscreen mode when toggleFullscreen is called', () => { + const containerRef = { + current: { + requestFullscreen: jest.fn(), + }, + } as any; + + const { result } = renderHook(() => useFullscreen(containerRef)); + + act(() => result.current.toggleFullscreen()); + expect(containerRef.current.requestFullscreen).toHaveBeenCalled(); + }); + + test('should exit fullscreen mode when exitFullscreen is called', () => { + document.exitFullscreen = jest.fn(); + + const containerRef = { current: null } as any; + const { result } = renderHook(() => useFullscreen(containerRef)); + + act(() => result.current.exitFullscreen()); + expect(document.exitFullscreen).toHaveBeenCalled(); + }); + + test('should update isFullscreen state when fullscreenchange event occurs', () => { + const containerRef = { current: null } as any; + const { result } = renderHook(() => useFullscreen(containerRef)); + + act(() => { + document.dispatchEvent(new Event('fullscreenchange')); + }); + + expect(result.current.isFullscreen).toBe(false); + + act(() => { + Object.defineProperty(document, 'fullscreenElement', { value: {}, configurable: true }); + document.dispatchEvent(new Event('fullscreenchange')); + }); + + expect(result.current.isFullscreen).toBe(true); + }); +}); diff --git a/packages/usehooks-ts/src/useFullScreen/useFullscreen.ts b/packages/usehooks-ts/src/useFullScreen/useFullscreen.ts new file mode 100644 index 00000000..fb39e35d --- /dev/null +++ b/packages/usehooks-ts/src/useFullScreen/useFullscreen.ts @@ -0,0 +1,93 @@ +import { useEffect, useState, RefObject } from 'react'; + +/** + * Structure of the return value for `useFullscreen`. + */ +type UseFullscreenReturn = { + /** State indicating if fullscreen mode is active. */ + isFullscreen: boolean; + /** Function to toggle fullscreen mode. */ + toggleFullscreen: () => void; + /** Function to exit fullscreen mode. */ + exitFullscreen: () => void; +}; + +/** + * Custom hook to manage fullscreen functionality for a given container. + * + * This hook provides: + * - `isFullscreen`: Boolean state indicating if fullscreen mode is active. + * - `toggleFullscreen`: A function to toggle fullscreen mode for the specified container. + * - `exitFullscreen`: A function to exit fullscreen mode. + * + * By default, the fullscreen state is `false`. This hook listens to the + * `fullscreenchange` event to automatically update the `isFullscreen` state. + * + * @param {RefObject} containerRef - A ref to the container element to manage fullscreen mode. + * @returns {UseFullscreenReturn} Object containing fullscreen state and control functions. + * + * @example + * ```tsx + * const containerRef = useRef(null); + * const { isFullscreen, toggleFullscreen, exitFullscreen } = useFullscreen(containerRef); + * ``` + * + * @public + */ +export function useFullscreen(containerRef: RefObject): UseFullscreenReturn { + const [isFullscreen, setIsFullscreen] = useState(false); + + /** + * Toggles fullscreen mode for the referenced container. + */ + const toggleFullscreen = (): void => { + if (!containerRef.current) return; + + if (!document.fullscreenElement) { + const element = containerRef.current; + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if ((element as any).mozRequestFullScreen) { + (element as any).mozRequestFullScreen(); // For older Firefox + } else if ((element as any).webkitRequestFullscreen) { + (element as any).webkitRequestFullscreen(); // For Safari + } else if ((element as any).msRequestFullscreen) { + (element as any).msRequestFullscreen(); // For older IE + } + } else { + exitFullscreen(); + } + }; + + /** + * Exits fullscreen mode. + */ + const exitFullscreen = (): void => { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if ((document as any).mozCancelFullScreen) { + (document as any).mozCancelFullScreen(); // For older Firefox + } else if ((document as any).webkitExitFullscreen) { + (document as any).webkitExitFullscreen(); // For Safari + } else if ((document as any).msExitFullscreen) { + (document as any).msExitFullscreen(); // For older IE + } + }; + + useEffect(() => { + const handleFullscreenChange = () => { + setIsFullscreen(!!document.fullscreenElement); + }; + + document.addEventListener('fullscreenchange', handleFullscreenChange); + return () => { + document.removeEventListener('fullscreenchange', handleFullscreenChange); + }; + }, []); + + return { + isFullscreen, + toggleFullscreen, + exitFullscreen, + }; +}