Skip to content

Commit a92da85

Browse files
committed
[IMPL] useFullscreen hook
1 parent c50b887 commit a92da85

8 files changed

Lines changed: 151 additions & 9 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useFullscreen } from "../../../../../../packages/react-tools/src";
2+
3+
/**
4+
The component render a div with a label to indicate if it is in fullscreen mode or not and two button to enter and exit from fullscreen mode.
5+
*/
6+
export const UseFullscreen = () => {
7+
const [isFullscreen, cbRef, enterFullscreen, exitFullscreen] = useFullscreen();
8+
return (
9+
<div ref={cbRef}>
10+
<div style={{ marginBottom: 16 }}>{isFullscreen ? 'Fullscreen' : 'Not fullscreen'}</div>
11+
<div>
12+
<button type="button" onClick={()=>enterFullscreen()}>
13+
enter Fullscreen
14+
</button>
15+
<button type="button" onClick={exitFullscreen} style={{ margin: '0 8px' }}>
16+
exit Fullscreen
17+
</button>
18+
</div>
19+
</div>
20+
);
21+
}

apps/react-tools-demo/src/constants/components.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ export const COMPONENTS = [
7272
"useMediaQuery",
7373
"useColorScheme",
7474
"useTitle",
75-
"useIdle"
75+
"useIdle",
76+
"useFullscreen"
7677
]
7778
],
7879
//UTILS
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# useFullscreen
2+
Hook to use [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API).
3+
4+
## Usage
5+
6+
```tsx
7+
export const UseFullscreen = () => {
8+
const [isFullscreen, cbRef, enterFullscreen, exitFullscreen] = useFullscreen();
9+
return (
10+
<div ref={cbRef}>
11+
<div style={{ marginBottom: 16 }}>{isFullscreen ? 'Fullscreen' : 'Not fullscreen'}</div>
12+
<div>
13+
<button type="button" onClick={()=>enterFullscreen()}>
14+
enterFullscreen
15+
</button>
16+
<button type="button" onClick={exitFullscreen} style={{ margin: '0 8px' }}>
17+
exitFullscreen
18+
</button>
19+
</div>
20+
</div>
21+
);
22+
}
23+
```
24+
25+
> The component render a div with a label to indicate if it is in fullscreen mode or not and two button to enter and exit from fullscreen mode.
26+
27+
28+
## API
29+
30+
```tsx
31+
useFullscreen <T extends Element>(onEnter?: () => void|Promise<void>, onChange?: (evt: Event) => void, onExit?: () => void|Promise<void>): [boolean, RefCallback<T>, (opts?: FullscreenOptions) => Promise<void>, () => Promise<void>]
32+
```
33+
34+
> ### Params
35+
>
36+
> - __onEnter?__: _()=>void|Promise<void>_
37+
callback that will be executed before enter in fullscreen mode.
38+
> - __onChange?__: _(evt: Event)=>void_
39+
callback that will be executed when target element fullscreen change.
40+
> - __onExit?__: _()=>void|Promise<void>_
41+
callback that will be executed before exit from fullscreen mode.
42+
>
43+
44+
> ### Returns
45+
>
46+
> __result__: array with: _isFullscreen_: boolean to indicate if there is fullscreen or not; _refCallback_: ref callback to be attached at target element; _enter_: function to enter in fullscreen mode; _exit_: function to exit from fullscreen mode.
47+
> - __Array__:
48+
> - _boolean_
49+
> - _RefCallback<T>_
50+
> - _(opts?: FullscreenOptions) => Promise<void>_
51+
> - _() => Promise<void>_
52+
>

apps/react-tools-demo/src/markdown/useMeasure.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ Hook to measure and track element's dimensions.
77
export const UseMeasure = () => {
88
const [cbRef, state] = useMeasure<HTMLDivElement>();
99

10-
return <div>
11-
<p>Dimensions: {state.toString()}</p>
10+
return <div style={{margin: '0 auto'}}>
11+
<p>Dimensions: {JSON.stringify(state)}</p>
1212
<br />
13-
<div ref={cbRef} style={{width: 100, height: 100, resize: 'both', border: '1px solid lightblue'}}>
14-
15-
</div>
13+
<div ref={cbRef} style={{margin:'0 auto', width: 100, height: 100, overflow: 'auto', resize: 'both', border: '1px solid lightblue'}}/>
1614
</div>
1715
}
1816
```

packages/react-tools/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
- [x] useColorScheme
8787
- [x] useTitle (change document.title but also document.head.title nodeElement)
8888
- [x] useIdle
89-
- [ ] useFullscreen (check browser compatibility)
89+
- [x] useFullscreen (check browser compatibility)
9090
- [ ] useLanguage (?)
9191
- [ ] useScreenShare
9292
- [ ] useFetch (with suspense ???)

packages/react-tools/src/hooks/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,5 @@ export { useIntersectionObserver } from './useIntersectionObserver';
5353
export { useMutationObserver } from './useMutationObserver';
5454
export { useIdle } from './useIdle';
5555
export { useRaf } from './useRaf';
56-
export { useMeasure } from './useMeasure';
56+
export { useMeasure } from './useMeasure';
57+
export { useFullscreen } from './useFullscreen';
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { RefCallback, useCallback, useMemo, useRef } from "react";
2+
import { useSyncExternalStore } from "."
3+
4+
/**
5+
* **`useFullscreen`**: Hook to use [Fullscreen API](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API).
6+
* @param {()=>void|Promise<void>} [onEnter] - callback that will be executed before enter in fullscreen mode.
7+
* @param {(evt: Event)=>void} [onChange] - callback that will be executed when target element fullscreen change.
8+
* @param {()=>void|Promise<void>} [onExit] - callback that will be executed before exit from fullscreen mode.
9+
* @returns {[boolean, RefCallback<T>, (opts?: FullscreenOptions) => Promise<void>, () => Promise<void>]} result - array with: _isFullscreen_: boolean to indicate if there is fullscreen or not; _refCallback_: ref callback to be attached at target element; _enter_: function to enter in fullscreen mode; _exit_: function to exit from fullscreen mode.
10+
*/
11+
export const useFullscreen = <T extends Element>(onEnter?: () => void|Promise<void>, onChange?: (evt: Event) => void, onExit?: () => void|Promise<void>): [boolean, RefCallback<T>, (opts?: FullscreenOptions) => Promise<void>, () => Promise<void>] => {
12+
const notifRef = useRef<() => void>();
13+
const nodeRef = useRef<T>();
14+
const listener = useCallback((evt: Event) => {
15+
onChange && onChange(evt);
16+
notifRef.current && notifRef.current();
17+
}, [onChange]);
18+
19+
const cbRef = useCallback((node: T) => {
20+
if (node) {
21+
nodeRef.current = node;
22+
node.addEventListener("fullscreenchange", listener)
23+
node.addEventListener("webkitfullscreenchange", listener)
24+
} else {
25+
nodeRef.current?.removeEventListener("fullscreenchange", listener)
26+
nodeRef.current?.removeEventListener("webkitfullscreenchange", listener)
27+
nodeRef.current = undefined;
28+
}
29+
}, [listener]);
30+
31+
const enter = useCallback(async (opts?: FullscreenOptions) => {
32+
onEnter && await onEnter();
33+
await (nodeRef.current?.requestFullscreen
34+
? nodeRef.current?.requestFullscreen(opts)
35+
: (nodeRef.current as null | (T & { webkitRequestFullScreen: (opts?: FullscreenOptions) => Promise<void> }))?.webkitRequestFullScreen(opts))
36+
}, [onEnter]);
37+
38+
const exit = useCallback(async () => {
39+
onExit && await onExit();
40+
await document.exitFullscreen();
41+
}, [onExit]);
42+
43+
const isFullscreen = useSyncExternalStore(
44+
useCallback(notif => {
45+
notifRef.current = notif;
46+
return () => {
47+
notifRef.current = undefined;
48+
}
49+
}, []),
50+
useMemo(() => {
51+
let isFullscreenCached = document.fullscreenElement ?? (document as typeof document & {webkitFullscreenElement: Element|null}).webkitFullscreenElement;
52+
return () => {
53+
const isFullscreenCurrent = document.fullscreenElement ?? (document as typeof document & { webkitFullscreenElement: Element | null }).webkitFullscreenElement;
54+
if (isFullscreenCached !== isFullscreenCurrent) {
55+
isFullscreenCached = isFullscreenCurrent;
56+
}
57+
return isFullscreenCached !== null;
58+
}
59+
}, [])
60+
);
61+
62+
return [
63+
isFullscreen,
64+
cbRef,
65+
enter,
66+
exit
67+
];
68+
}

packages/react-tools/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ export {
6767
useMutationObserver,
6868
useIdle,
6969
useRaf,
70-
useMeasure
70+
useMeasure,
71+
useFullscreen
7172
} from './hooks'
7273

7374
export {

0 commit comments

Comments
 (0)