ahooks
Version:
react hooks library
129 lines (128 loc) • 4.23 kB
JavaScript
import { useEffect, useState, useRef } from 'react';
import screenfull from 'screenfull';
import useLatest from '../useLatest';
import useMemoizedFn from '../useMemoizedFn';
import { getTargetElement } from '../utils/domTarget';
import { isBoolean } from '../utils';
const useFullscreen = (target, options) => {
const { onExit, onEnter, pageFullscreen = false } = options || {};
const { className = 'ahooks-page-fullscreen', zIndex = 999999 } = isBoolean(pageFullscreen) || !pageFullscreen ? {} : pageFullscreen;
const onExitRef = useLatest(onExit);
const onEnterRef = useLatest(onEnter);
// The state of full screen may be changed by other scripts/components,
// so the initial value needs to be computed dynamically.
const [state, setState] = useState(getIsFullscreen);
const stateRef = useRef(getIsFullscreen());
function getIsFullscreen() {
return (screenfull.isEnabled &&
!!screenfull.element &&
screenfull.element === getTargetElement(target));
}
const invokeCallback = (fullscreen) => {
var _a, _b;
if (fullscreen) {
(_a = onEnterRef.current) === null || _a === void 0 ? void 0 : _a.call(onEnterRef);
}
else {
(_b = onExitRef.current) === null || _b === void 0 ? void 0 : _b.call(onExitRef);
}
};
const updateFullscreenState = (fullscreen) => {
// Prevent repeated calls when the state is not changed.
if (stateRef.current !== fullscreen) {
invokeCallback(fullscreen);
setState(fullscreen);
stateRef.current = fullscreen;
}
};
const onScreenfullChange = () => {
const fullscreen = getIsFullscreen();
updateFullscreenState(fullscreen);
};
const togglePageFullscreen = (fullscreen) => {
const el = getTargetElement(target);
if (!el) {
return;
}
let styleElem = document.getElementById(className);
if (fullscreen) {
el.classList.add(className);
if (!styleElem) {
styleElem = document.createElement('style');
styleElem.setAttribute('id', className);
styleElem.textContent = `
.${className} {
position: fixed; left: 0; top: 0; right: 0; bottom: 0;
width: 100% !important; height: 100% !important;
z-index: ${zIndex};
}`;
el.appendChild(styleElem);
}
}
else {
el.classList.remove(className);
if (styleElem) {
styleElem.remove();
}
}
updateFullscreenState(fullscreen);
};
const enterFullscreen = () => {
const el = getTargetElement(target);
if (!el) {
return;
}
if (pageFullscreen) {
togglePageFullscreen(true);
return;
}
if (screenfull.isEnabled) {
try {
screenfull.request(el);
}
catch (error) {
console.error(error);
}
}
};
const exitFullscreen = () => {
const el = getTargetElement(target);
if (!el) {
return;
}
if (pageFullscreen) {
togglePageFullscreen(false);
return;
}
if (screenfull.isEnabled && screenfull.element === el) {
screenfull.exit();
}
};
const toggleFullscreen = () => {
if (state) {
exitFullscreen();
}
else {
enterFullscreen();
}
};
useEffect(() => {
if (!screenfull.isEnabled || pageFullscreen) {
return;
}
screenfull.on('change', onScreenfullChange);
return () => {
screenfull.off('change', onScreenfullChange);
};
}, []);
return [
state,
{
enterFullscreen: useMemoizedFn(enterFullscreen),
exitFullscreen: useMemoizedFn(exitFullscreen),
toggleFullscreen: useMemoizedFn(toggleFullscreen),
isEnabled: screenfull.isEnabled,
},
];
};
export default useFullscreen;