UNPKG

wix-style-react

Version:
223 lines (187 loc) • 6.83 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { Howl } from 'howler'; // A callback that keeps its instance and won't make Howler to re create every time var useStableCallback = function useStableCallback(callback) { var callbackRef = useRef(); callbackRef.current = callback; return useCallback(function () { return callbackRef.current && callbackRef.current.apply(callbackRef, arguments); }, []); }; var useRaf = function useRaf(_ref) { var callback = _ref.callback, enabled = _ref.enabled; var stableCallback = useStableCallback(callback); // we use useLayoutEffect here because it fires synchronously after all DOM mutations // and before the next requestAnimationFrame. If we use useEffect (which runs after requestAnimationFrame) // we'll get an endless loop of frames that causes a memory leak. useLayoutEffect(function () { if (enabled) { var id; var loop = function loop() { stableCallback(); id = requestAnimationFrame(loop); }; id = requestAnimationFrame(loop); return function () { cancelAnimationFrame(id); }; } }, [enabled, stableCallback]); }; export var useAudioManager = function useAudioManager(_ref2) { var src = _ref2.src, playing = _ref2.playing, format = _ref2.format, preload = _ref2.preload, webAudioAPI = _ref2.webAudioAPI, allowSeekLoop = _ref2.allowSeekLoop, onEnd = _ref2.onEnd, onLoad = _ref2.onLoad, onPlay = _ref2.onPlay, onPause = _ref2.onPause, onSeek = _ref2.onSeek, onLoadError = _ref2.onLoadError, onDestroy = _ref2.onDestroy; var stableOnEnd = useStableCallback(onEnd); var stableOnLoad = useStableCallback(onLoad); var stableOnPlay = useStableCallback(onPlay); var stableOnPause = useStableCallback(onPause); var stableOnSeek = useStableCallback(onSeek); var stableOnLoadError = useStableCallback(onLoadError); var stableOnDestroy = useStableCallback(onDestroy); var audioManager = useRef(); var _useState = useState(0), _useState2 = _slicedToArray(_useState, 2), _seek = _useState2[0], _setSeek = _useState2[1]; var _useState3 = useState('unloaded'), _useState4 = _slicedToArray(_useState3, 2), loadingState = _useState4[0], setLoadingState = _useState4[1]; var _useState5 = useState(false), _useState6 = _slicedToArray(_useState5, 2), wasEverPlayed = _useState6[0], setWasEverPlayed = _useState6[1]; var duration = useMemo(function () { if (!audioManager.current || loadingState !== 'loaded') { return 0; } return audioManager.current.duration(); }, [loadingState]); var _destroy = useCallback(function () { if (audioManager.current) { setLoadingState('unloaded'); setWasEverPlayed(false); _setSeek(0); audioManager.current.stop(); audioManager.current.unload(); audioManager.current = null; stableOnDestroy(); } }, [setLoadingState, setWasEverPlayed, _setSeek, stableOnDestroy]); var _onPlay = useCallback(function () { setWasEverPlayed(true); stableOnPlay(); }, [stableOnPlay, setWasEverPlayed]); var _onLoad = useCallback(function () { // Keeping a duplicate state because when Howler state changes it won't cause a render // and we want to react to this change. setLoadingState(audioManager.current.state()); stableOnLoad(); }, [stableOnLoad, setLoadingState]); var _onEnd = useCallback(function () { _setSeek(0); stableOnEnd(); }, [stableOnEnd, _setSeek]); var _onLoadError = useCallback(function (_, errorMsg) { stableOnLoadError(errorMsg); }, [stableOnLoadError]); var _load = useCallback(function () { if (audioManager.current) { audioManager.current.load(); setLoadingState(audioManager.current.state()); } }, [setLoadingState]); var _play = useCallback(function () { if (audioManager.current) { if (loadingState === 'unloaded') { _load(); } if (loadingState === 'loaded' && !audioManager.current.playing()) { audioManager.current.play(); } } }, [loadingState, _load]); var _pause = useCallback(function () { if (audioManager.current) { audioManager.current.pause(); } }, []); // There is an open bug in howler that if play is locked it returns the howler object when // getting "seek" instead of a number. this solves the issue until they fix it,. // https://github.com/goldfire/howler.js/issues/1189 var _readSeek = useCallback(function () { if (!audioManager.current || loadingState !== 'loaded') { return 0; } var currentSeek = audioManager.current.seek(); if (typeof currentSeek !== 'number') { var internalSeek = audioManager.current._sounds[0]._seek; if (typeof internalSeek !== 'number') { currentSeek = 0; } currentSeek = internalSeek; } return currentSeek; }, [loadingState]); var _updateSeek = useCallback(function () { // Keeping a duplicate seek state because when Howler seek changes it won't cause a render // and we want to react to this change (expose an updated seek to audioManager consumer). _setSeek(_readSeek()); }, [_readSeek]); var setSeek = useCallback(function (pos) { if (audioManager.current && loadingState === 'loaded') { audioManager.current.seek(pos); _setSeek(pos); } }, [loadingState]); // starts a request animation frame loop that updates the seek every frame. // stops the loop if paused or if slider is being dragged useRaf({ callback: _updateSeek, enabled: playing && allowSeekLoop }); useEffect(function () { if (src) { audioManager.current = new Howl({ src: src, format: format, preload: preload === 'none' ? false : preload === 'auto' ? true : preload, onload: _onLoad, html5: !webAudioAPI, onend: _onEnd, onplay: _onPlay, onloaderror: _onLoadError, onpause: stableOnPause, onseek: stableOnSeek }); } return function () { return _destroy(); }; }, [audioManager, _destroy, format, src, _onEnd, _onLoad, _onLoadError, stableOnPlay, stableOnPause, stableOnSeek, preload, webAudioAPI, _onPlay]); useEffect(function () { if (playing) { _play(); } if (!playing && wasEverPlayed) { _pause(); } }, [_pause, _play, playing, wasEverPlayed]); return useMemo(function () { return { loadingState: loadingState, duration: duration, seek: _seek, setSeek: setSeek }; }, [loadingState, duration, _seek, setSeek]); };