UNPKG

@vime/core

Version:

Customizable, extensible, accessible and framework agnostic media player.

142 lines (141 loc) 5.33 kB
var _a, _b; import { listen } from './dom'; import { isFunction, isUndefined, noop } from './unit'; export const IS_CLIENT = typeof window !== 'undefined'; export const UA = IS_CLIENT ? (_a = window.navigator) === null || _a === void 0 ? void 0 : _a.userAgent.toLowerCase() : ''; export const IS_IOS = /iphone|ipad|ipod|ios|CriOS|FxiOS/.test(UA); export const IS_ANDROID = /android/.test(UA); export const IS_MOBILE = IS_CLIENT && (IS_IOS || IS_ANDROID); export const IS_IPHONE = IS_CLIENT && /(iPhone|iPod)/gi.test((_b = window.navigator) === null || _b === void 0 ? void 0 : _b.platform); export const IS_FIREFOX = /firefox/.test(UA); export const IS_CHROME = IS_CLIENT && window.chrome; export const IS_SAFARI = IS_CLIENT && !IS_CHROME && (window.safari || IS_IOS || /(apple|safari)/.test(UA)); export const ORIGIN = window.location.protocol !== 'file:' ? `${window.location.protocol}//${window.location.hostname}` : undefined; export const onMobileChange = (callback) => { if (!IS_CLIENT || isUndefined(window.ResizeObserver)) { callback(IS_MOBILE); return noop; } function onResize() { callback(window.innerWidth <= 480 || IS_MOBILE); } callback(window.innerWidth <= 480 || IS_MOBILE); return listen(window, 'resize', onResize); }; export const onTouchInputChange = (callback) => { if (!IS_CLIENT) return noop; let lastTouchTime = 0; const offTouchListener = listen(document, 'touchstart', () => { lastTouchTime = new Date().getTime(); callback(true); }, true); const offMouseListener = listen(document, 'mousemove', () => { // Filter emulated events coming from touch events if (new Date().getTime() - lastTouchTime < 500) return; callback(false); }, true); return () => { offTouchListener(); offMouseListener(); }; }; /** * Checks if a video player can enter fullscreen. * * @see https://developer.apple.com/documentation/webkitjs/htmlvideoelement/1633500-webkitenterfullscreen */ export const canFullscreenVideo = () => { if (!IS_CLIENT) return false; const video = document.createElement('video'); return isFunction(video.webkitEnterFullscreen); }; /** * Checks if the screen orientation can be changed. * * @see https://developer.mozilla.org/en-US/docs/Web/API/Screen/orientation */ export const canRotateScreen = () => IS_CLIENT && window.screen.orientation && !!window.screen.orientation.lock; /** * Reduced motion iOS & MacOS setting. * * @see https://webkit.org/blog/7551/responsive-design-for-motion/ */ export const isReducedMotionPreferred = () => IS_CLIENT && 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches; /** * Checks if the native HTML5 video player can play HLS. */ export const canPlayHLSNatively = () => { if (!IS_CLIENT) return false; const video = document.createElement('video'); return video.canPlayType('application/vnd.apple.mpegurl').length > 0; }; /** * Checks if the native HTML5 video player can enter picture-in-picture (PIP) mode when using * the Chrome browser. * * @see https://developers.google.com/web/updates/2018/10/watch-video-using-picture-in-picture */ export const canUsePiPInChrome = () => { if (!IS_CLIENT) return false; const video = document.createElement('video'); return !!document.pictureInPictureEnabled && !video.disablePictureInPicture; }; /** * Checks if the native HTML5 video player can enter picture-in-picture (PIP) mode when using * the desktop Safari browser, iOS Safari appears to "support" PiP through the check, however PiP * does not function. * * @see https://developer.apple.com/documentation/webkitjs/adding_picture_in_picture_to_your_safari_media_controls */ export const canUsePiPInSafari = () => { if (!IS_CLIENT) return false; const video = document.createElement('video'); return (isFunction(video.webkitSupportsPresentationMode) && isFunction(video.webkitSetPresentationMode) && !IS_IPHONE); }; // Checks if the native HTML5 video player can enter PIP. export const canUsePiP = () => canUsePiPInChrome() || canUsePiPInSafari(); /** * To detect autoplay, we create a video element and call play on it, if it is `paused` after * a `play()` call, autoplay is supported. Although this unintuitive, it works across browsers * and is currently the lightest way to detect autoplay without using a data source. * * @see https://github.com/ampproject/amphtml/blob/9bc8756536956780e249d895f3e1001acdee0bc0/src/utils/video.js#L25 */ export const canAutoplay = (muted = true, playsinline = true) => { if (!IS_CLIENT) return Promise.resolve(false); const video = document.createElement('video'); if (muted) { video.setAttribute('muted', ''); video.muted = true; } if (playsinline) { video.setAttribute('playsinline', ''); video.setAttribute('webkit-playsinline', ''); } video.setAttribute('height', '0'); video.setAttribute('width', '0'); video.style.position = 'fixed'; video.style.top = '0'; video.style.width = '0'; video.style.height = '0'; video.style.opacity = '0'; // Promise wrapped this way to catch both sync throws and async rejections. // More info: https://github.com/tc39/proposal-promise-try new Promise(resolve => resolve(video.play())).catch(noop); return Promise.resolve(!video.paused); };