@rooks/use-fullscreen
Version:
A React Hooks package for fullscreen.
266 lines (256 loc) • 10.5 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('tslib'), require('react')) :
typeof define === 'function' && define.amd ? define(['tslib', 'react'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.useFullscreen = factory(global.tslib, global.React));
}(this, (function (tslib, react) { 'use strict';
/**
* useIsomorphicEffect
* Resolves to useEffect when "window" is not in scope and useLayout effect in the browser
* @param {function} callback Callback function to be called on mount
*/
const useIsomorphicEffect = typeof window === "undefined" ? react.useEffect : react.useLayoutEffect;
/**
* useFreshRef
* @param value The value which needs to be fresh at all times. Probably
* best used with functions
* @param preferLayoutEffect Should the value be updated using a layout effect
* or a passive effect. Defaults to false.
* @returns A ref containing the fresh value
*/
function useFreshRef(value, preferLayoutEffect = false) {
const useEffectToUse = preferLayoutEffect ? useIsomorphicEffect : react.useEffect;
const ref = react.useRef(value);
useEffectToUse(() => {
ref.current = value;
});
return ref;
}
function useFreshTick(callback) {
const freshRef = useFreshRef(callback);
function tick(...args) {
if (freshRef && typeof freshRef.current === "function") {
freshRef.current(...args);
}
}
return tick;
}
/**
* useGlobalObjectEventListener hook
*
* A react hook to an event listener to a global object
*
* @param {Window|Document} globalObject The global object to add event onto
* @param {string} eventName The event to track
* @param {function} callback The callback to be called on event
* @param {object} conditions The options to be passed to the event listener
* @param {boolean} when Should the event listener be active
* @param {boolean} isLayoutEffect Should it use layout effect. Defaults to false
* @return {undefined}
*/
function useGlobalObjectEventListener(globalObject, eventName, callback, listenerOptions = {}, when = true, isLayoutEffect = false) {
const freshCallback = useFreshTick(callback);
const { capture, passive, once } = listenerOptions;
const useEffectToRun = isLayoutEffect ? useIsomorphicEffect : react.useEffect;
useEffectToRun(() => {
if (typeof globalObject !== "undefined" && globalObject.addEventListener && when) {
globalObject.addEventListener(eventName, freshCallback, listenerOptions);
return () => {
globalObject.removeEventListener(eventName, freshCallback, listenerOptions);
};
}
}, [eventName, capture, passive, once]);
}
/**
* useDocumentEventListener hook
*
* A react hook to an event listener to the document
*
* @param {string} eventName The event to track
* @param {function} callback The callback to be called on event
* @param {object} conditions The options to be passed to the event listener
* @param {boolean} isLayoutEffect Should it use layout effect. Defaults to false
* @return {undefined}
*/
function useDocumentEventListener(eventName, callback, listenerOptions = {}, isLayoutEffect = false) {
if (typeof document !== "undefined") {
useGlobalObjectEventListener(document, eventName, callback, listenerOptions, true, isLayoutEffect);
}
else {
console.warn("useDocumentEventListener can't attach an event listener as document is undefined.");
}
}
const __DEV__ = process.env.NODE_ENV !== 'production';
let warning = function () { };
if (__DEV__) {
const printWarning = function printWarning(...actualMessage) {
const message = `Warning: ${actualMessage}`;
if (typeof console !== 'undefined') {
console.error(message);
}
try {
// --- Welcome to debugging React ---
// This error was thrown as a convenience so that you can use this stack
// to find the callsite that caused this warning to fire.
throw new Error(message);
}
catch (x) { }
};
warning = function (condition, actualMessage) {
if (!condition) {
printWarning(actualMessage);
}
};
}
const getFullscreenControls = () => {
const fnMap = [
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror',
],
// New WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror',
],
// Old WebKit
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror',
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror',
],
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError',
],
];
const ret = {};
fnMap.forEach((fnSet) => {
if (fnSet && fnSet[1] in document) {
fnSet.forEach((_fn, i) => {
ret[fnMap[0][i]] = fnSet[i];
});
}
});
return ret;
};
const noop = () => { };
const defaultValue = {
isEnabled: false,
toggle: noop,
onChange: noop,
onError: noop,
request: noop,
exit: noop,
isFullscreen: false,
element: undefined,
};
function warnDeprecatedOnChangeAndOnErrorUsage() {
warning(false, `Using onChange and onError from the return value is deprecated and
will be removed in the next major version.
Please use it with arguments instead.
For eg: useFullscreen({onChange: function() {}, onError: function(){}})
`);
}
/**
* useFullscreen
* A hook that helps make the document fullscreen
*/
function useFullscreen(options = {}) {
if (typeof window === 'undefined') {
return defaultValue;
}
const { onChange: onChangeArg, onError: onErrorArg } = options;
const fullscreenControls = getFullscreenControls();
const [isFullscreen, setIsFullscreen] = react.useState(Boolean(document[fullscreenControls.fullscreenElement]));
const [element, setElement] = react.useState(document[fullscreenControls.fullscreenElement]);
const request = react.useCallback((element) => tslib.__awaiter(this, void 0, void 0, function* () {
try {
const finalElem = element || document.documentElement;
return yield finalElem[fullscreenControls.requestFullscreen]();
}
catch (err) {
console.log(err);
}
}), []);
const exit = react.useCallback(() => tslib.__awaiter(this, void 0, void 0, function* () {
if (element) {
try {
return yield document[fullscreenControls.exitFullscreen]();
}
catch (err) {
console.warn(err);
}
}
}), [element]);
const toggle = react.useCallback((newElement) => Boolean(element) ? exit() : newElement ? request(newElement) : null, [element]);
const onChangeDeprecatedHandlerRef = react.useRef(noop);
const onErrorDeprecatedHandlerRef = react.useRef(noop);
// Hack to not break it for everyone
// Honestly these two functions are tragedy and must be removed in v5
const onChangeDeprecated = react.useCallback((callback) => {
warnDeprecatedOnChangeAndOnErrorUsage();
return (onChangeDeprecatedHandlerRef.current = callback);
}, []);
const onErrorDeprecated = react.useCallback((callback) => {
warnDeprecatedOnChangeAndOnErrorUsage();
return (onErrorDeprecatedHandlerRef.current = callback);
}, []);
useDocumentEventListener(fullscreenControls.fullscreenchange, function (event) {
var _a;
const currentFullscreenElement = document[fullscreenControls.fullscreenElement];
const isOpen = Boolean(currentFullscreenElement);
if (isOpen) {
//fullscreen was enabled
setIsFullscreen(true);
setElement(currentFullscreenElement);
}
else {
//fullscreen was disabled
setIsFullscreen(false);
setElement(null);
}
onChangeArg === null || onChangeArg === void 0 ? void 0 : onChangeArg.call(document, event, isOpen);
(_a = onChangeDeprecatedHandlerRef.current) === null || _a === void 0 ? void 0 : _a.call(document, event, isOpen);
});
useDocumentEventListener(fullscreenControls.fullscreenerror, function (event) {
var _a;
onErrorArg === null || onErrorArg === void 0 ? void 0 : onErrorArg.call(document, event);
(_a = onErrorDeprecatedHandlerRef.current) === null || _a === void 0 ? void 0 : _a.call(document, event);
});
return {
isEnabled: Boolean(document[fullscreenControls.fullscreenEnabled]),
toggle,
onChange: onChangeDeprecated,
onError: onErrorDeprecated,
request,
exit,
isFullscreen,
element,
};
}
return useFullscreen;
})));
//# sourceMappingURL=index.js.map