From 0971a7e6b2bc7d095738e57dd46532ff9b9bf8c7 Mon Sep 17 00:00:00 2001 From: Ward Oosterlijnck Date: Thu, 28 Mar 2019 07:57:23 +1100 Subject: [PATCH 1/2] useFullscreen --- docs/useFullscreen.md | 32 ++++++++++++ package.json | 7 +-- src/__stories__/useFullscreen.story.tsx | 24 +++++++++ src/index.ts | 2 + src/useFullscreen.ts | 68 +++++++++++++++++++++++++ yarn.lock | 5 ++ 6 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 docs/useFullscreen.md create mode 100644 src/__stories__/useFullscreen.story.tsx create mode 100644 src/useFullscreen.ts diff --git a/docs/useFullscreen.md b/docs/useFullscreen.md new file mode 100644 index 00000000..7b7d0b0a --- /dev/null +++ b/docs/useFullscreen.md @@ -0,0 +1,32 @@ +# `useFullscreen` + +Display an element full-screen, optional fallback for fullscreen video on iOS. + +## Usage + +```jsx +import React, { useRef } from 'react'; +import { useFullscreen } from 'react-use'; + +const Demo = () => { + const ref = useRef(null) + const videoRef = useRef(null) + const [fullscreen, toggle] = useFullscreen(ref, videoRef); + + return ( +
+
{fullscreen ? 'Fullscreen' : 'Not fullscreen'}
+ + + +
+ ); +}; +``` + +## Reference + +```ts +useFullscreen(ref: RefObject, videoRef?: RefObject); +``` diff --git a/package.json b/package.json index b14797ab..38ed234f 100644 --- a/package.json +++ b/package.json @@ -36,13 +36,11 @@ "dependencies": { "nano-css": "^5.1.0", "react-wait": "^0.3.0", + "screenfull": "^4.1.0", "throttle-debounce": "^2.0.1", "ts-easing": "^0.2.0" }, "devDependencies": { - "@types/react": "16.8.8", - "keyboardjs": "2.5.1", - "rebound": "0.1.0", "@semantic-release/changelog": "3.0.2", "@semantic-release/git": "7.0.8", "@semantic-release/npm": "5.1.4", @@ -51,13 +49,16 @@ "@storybook/addon-notes": "5.0.5", "@storybook/addon-options": "5.0.5", "@storybook/react": "5.0.5", + "@types/react": "16.8.8", "babel-core": "6.26.3", "fork-ts-checker-webpack-plugin": "1.0.0", "gh-pages": "2.0.1", + "keyboardjs": "2.5.1", "markdown-loader": "5.0.0", "react": "16.8.4", "react-dom": "16.8.4", "react-spring": "6.1.10", + "rebound": "0.1.0", "rimraf": "2.6.3", "rxjs": "6.4.0", "semantic-release": "15.13.3", diff --git a/src/__stories__/useFullscreen.story.tsx b/src/__stories__/useFullscreen.story.tsx new file mode 100644 index 00000000..fada7575 --- /dev/null +++ b/src/__stories__/useFullscreen.story.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import {storiesOf} from '@storybook/react'; +import {useFullscreen} from '..'; +import ShowDocs from '../util/ShowDocs'; + +const Demo = () => { + const ref = React.useRef(null) + const videoRef = React.useRef(null) + const [fullscreen, toggle] = useFullscreen(ref, videoRef); + + return ( +
+
{fullscreen ? 'Fullscreen' : 'Not fullscreen'}
+ + + +
+ ); +}; + +storiesOf('Side effects|useFullscreen', module) + .add('Docs', () => ) + .add('Demo', () => ) diff --git a/src/index.ts b/src/index.ts index da3afd58..91380a21 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ import useCounter from './useCounter'; import useCss from './useCss'; import useDebounce from './useDebounce'; import useFavicon from './useFavicon'; +import useFullscreen from './useFullscreen'; import useGeolocation from './useGeolocation'; import useGetSet from './useGetSet'; import useGetSetState from './useGetSetState'; @@ -68,6 +69,7 @@ export { useCss, useDebounce, useFavicon, + useFullscreen, useGeolocation, useGetSet, useGetSetState, diff --git a/src/useFullscreen.ts b/src/useFullscreen.ts new file mode 100644 index 00000000..55f3003b --- /dev/null +++ b/src/useFullscreen.ts @@ -0,0 +1,68 @@ +import {useEffect, RefObject, useCallback} from 'react'; +import screenfull from 'screenfull'; +import useToggle from './useToggle' + +export interface State { + fullscreen: boolean +} + +const useFullscreen = (ref: RefObject, videoRef?: RefObject): [boolean, (value?: boolean) => void] => { + const [fullscreen, toggle] = useToggle(false); + + useEffect(() => { + const onChange = () => { + if (screenfull) { + toggle(screenfull.isFullscreen) + } + } + + if (screenfull && screenfull.enabled) { + screenfull.on('change', onChange); + } + + return () => { + if (screenfull && screenfull.enabled) { + screenfull.off('change', onChange); + } + } + }, []); + + const toggleFullscreen = useCallback(async (nextValue?: boolean) => { + nextValue = typeof nextValue === 'undefined' ? !fullscreen : nextValue; + + if (screenfull && screenfull.enabled) { + try { + if (nextValue) { + await screenfull.request(ref.current || undefined); + } else { + await screenfull.exit(); + } + toggle(nextValue); + } catch {} + } else { + if (videoRef && videoRef.current) { + if (nextValue) { + if (videoRef.current.webkitEnterFullscreen) { + const onWebkitEndFullscreen = () => { + if (videoRef.current) { + videoRef.current.removeEventListener('webkitendfullscreen', onWebkitEndFullscreen); + toggle(false) + } + }; + + videoRef.current.webkitEnterFullscreen(); + toggle(true) + videoRef.current.addEventListener('webkitendfullscreen', onWebkitEndFullscreen); + } + } else if (videoRef.current.webkitExitFullscreen) { + videoRef.current.webkitExitFullscreen(); + toggle(false) + } + } + } + }, [fullscreen, toggle]) + + return [fullscreen, toggleFullscreen] +}; + +export default useFullscreen; diff --git a/yarn.lock b/yarn.lock index bd570045..146ded64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9684,6 +9684,11 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" +screenfull@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-4.1.0.tgz#30eb338f615941f5a2cdd96c14e36063d2d9d764" + integrity sha512-/qH0HAmc+ilbZ9Vf8J7RHjjecSdqmjIh98iMkA6uCSKcHdJK1TiXhTbR+cin8rG70xi4Peyz7wW1KJVP6sp30g== + select@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" From bf302bd5e76235ce1f15423655912e3badec0298 Mon Sep 17 00:00:00 2001 From: Ward Oosterlijnck Date: Thu, 28 Mar 2019 23:49:42 +1100 Subject: [PATCH 2/2] useFullscreen added to readme --- README.md | 1 + docs/useFullscreen.md | 5 ++++- src/__stories__/useFullscreen.story.tsx | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 40163a77..55c1bddb 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ - [`useAudio`](./docs/useAudio.md) — plays audio and exposes its controls. [![][img-demo]](https://codesandbox.io/s/2o4lo6rqy) - [`useClickAway`](./docs/useClickAway.md) — triggers callback when user clicks outside target area. - [`useCss`](./docs/useCss.md) — dynamically adjusts CSS. + - [`useFullscreen`](./docs/useFullscreen.md) — display an element or video full-screen. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/ui-usefullscreen--demo) - [`useSpeech`](./docs/useSpeech.md) — synthesizes speech from a text string. [![][img-demo]](https://codesandbox.io/s/n090mqz69m) - [`useVideo`](./docs/useVideo.md) — plays video, tracks its state, and exposes playback controls. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/ui-usevideo--demo) - [`useWait`](./docs/useWait.md) — complex waiting management for UIs. diff --git a/docs/useFullscreen.md b/docs/useFullscreen.md index 7b7d0b0a..5c0a5544 100644 --- a/docs/useFullscreen.md +++ b/docs/useFullscreen.md @@ -28,5 +28,8 @@ const Demo = () => { ## Reference ```ts -useFullscreen(ref: RefObject, videoRef?: RefObject); +useFullscreen( + ref: RefObject, + videoRef?: RefObject +): [boolean, (value?: boolean) => void]; ``` diff --git a/src/__stories__/useFullscreen.story.tsx b/src/__stories__/useFullscreen.story.tsx index fada7575..7f4d9ece 100644 --- a/src/__stories__/useFullscreen.story.tsx +++ b/src/__stories__/useFullscreen.story.tsx @@ -19,6 +19,6 @@ const Demo = () => { ); }; -storiesOf('Side effects|useFullscreen', module) +storiesOf('UI|useFullscreen', module) .add('Docs', () => ) .add('Demo', () => )