Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Add useFullscreen Hook for Fullscreen Management #659

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/usehooks-ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
1 change: 1 addition & 0 deletions packages/usehooks-ts/src/useFullScreen/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useFullScreen'
70 changes: 70 additions & 0 deletions packages/usehooks-ts/src/useFullScreen/useFullscreen.demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useRef } from 'react';
import { useFullscreen } from './useFullscreen';

const Component: React.FC = () => {
const containerRef = useRef<HTMLDivElement>(null);
const { isFullscreen, toggleFullscreen, exitFullscreen } = useFullscreen(containerRef);

return (
<div
style={{
height: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f9f9f9',
}}
>
<div
ref={containerRef}
style={{
width: isFullscreen ? '100%' : '300px',
height: isFullscreen ? '100%' : '300px',
backgroundColor: '#4caf50',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'white',
textAlign: 'center',
borderRadius: isFullscreen ? '0' : '8px',
transition: 'all 0.3s ease',
}}
>
<p>{isFullscreen ? 'Fullscreen Mode' : 'Click to Enter Fullscreen'}</p>
</div>
<div style={{ marginTop: '20px', textAlign: 'center' }}>
<button
onClick={toggleFullscreen}
style={{
marginRight: '10px',
padding: '10px 20px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
}}
>
{isFullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'}
</button>
{isFullscreen && (
<button
onClick={exitFullscreen}
style={{
padding: '10px 20px',
backgroundColor: '#dc3545',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
}}
>
Exit Fullscreen
</button>
)}
</div>
</div>
);
};

export default Component;
15 changes: 15 additions & 0 deletions packages/usehooks-ts/src/useFullScreen/useFullscreen.md
Original file line number Diff line number Diff line change
@@ -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';
52 changes: 52 additions & 0 deletions packages/usehooks-ts/src/useFullScreen/useFullscreen.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
93 changes: 93 additions & 0 deletions packages/usehooks-ts/src/useFullScreen/useFullscreen.ts
Original file line number Diff line number Diff line change
@@ -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<HTMLElement>} 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<HTMLDivElement>(null);
* const { isFullscreen, toggleFullscreen, exitFullscreen } = useFullscreen(containerRef);
* ```
*
* @public
*/
export function useFullscreen(containerRef: RefObject<HTMLElement>): UseFullscreenReturn {
const [isFullscreen, setIsFullscreen] = useState<boolean>(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,
};
}