UNPKG

react-moskaj-audio-player

Version:

react h5 audio with customized icons_A React audio player with UI. Mobile compatible.

1,063 lines (941 loc) 32.1 kB
"use strict"; require("./styles.css"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _react2 = require("@iconify/react"); var _playCircle = _interopRequireDefault( require("@iconify/icons-mdi/play-circle-outline") ); var _pauseCircle = _interopRequireDefault( require("@iconify/icons-mdi/pause-circle-outline") ); var _skipPrevious = _interopRequireDefault( require("@iconify/icons-mdi/skip-previous-outline") ); var _skipNext = _interopRequireDefault( require("@iconify/icons-mdi/skip-next-outline") ); var _fastForward = _interopRequireDefault( require("@iconify/icons-mdi/fast-forward-10") ); var _rewind = _interopRequireDefault(require("@iconify/icons-mdi/rewind-10")); var _volumeHigh = _interopRequireDefault( require("@iconify/icons-mdi/volume-high") ); var _volumeMute = _interopRequireDefault( require("@iconify/icons-mdi/volume-off") ); var _repeat = _interopRequireDefault(require("@iconify/icons-mdi/repeat")); var _repeatOff = _interopRequireDefault( require("@iconify/icons-mdi/repeat-off") ); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if ( obj === null || (_typeof(obj) !== "object" && typeof obj !== "function") ) { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError( "this hasn't been initialised - super() hasn't been called" ); } return self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var H5AudioPlayer = /*#__PURE__*/ (function(_Component) { _inherits(H5AudioPlayer, _Component); function H5AudioPlayer() { var _getPrototypeOf2; var _this; _classCallCheck(this, H5AudioPlayer); for ( var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++ ) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn( this, (_getPrototypeOf2 = _getPrototypeOf(H5AudioPlayer)).call.apply( _getPrototypeOf2, [this].concat(args) ) ); _defineProperty(_assertThisInitialized(_this), "state", { duration: NaN, currentTime: NaN, currentTimePos: "0%", currentVolume: _this.props.muted ? 0 : _this.props.volume, currentVolumePos: _this.props.muted ? "0%" : "".concat(_this.props.volume * 100, "%"), isDraggingProgress: false, isDraggingVolume: false, isPlaying: false, isLoopEnabled: _this.props.loop }); _defineProperty(_assertThisInitialized(_this), "timeOnMouseMove", 0); _defineProperty( _assertThisInitialized(_this), "updateDisplayTime", function(currentTime) { var duration = _this.audio.duration; var left = "".concat((currentTime / duration) * 100, "%") || 0; _this.setState({ currentTime: currentTime, duration: duration, currentTimePos: left }); } ); _defineProperty( _assertThisInitialized(_this), "updateDisplayVolume", function(volume) { if (volume === 0) { return _this.setState({ currentVolume: 0, currentVolumePos: "0%" }); } _this.setState({ currentVolume: volume, currentVolumePos: "".concat(volume * 100, "%") }); } ); _defineProperty(_assertThisInitialized(_this), "togglePlay", function() { if (_this.audio.paused && _this.audio.src) { var audioPromise = _this.audio.play(); audioPromise.then(null)["catch"](function(err) { var onPlayError = _this.props.onPlayError; onPlayError && onPlayError(new Error(err)); }); } else if (!_this.audio.paused) { _this.audio.pause(); } }); _defineProperty( _assertThisInitialized(_this), "handleClickVolumeButton", function() { var currentVolume = _this.state.currentVolume; if (currentVolume > 0) { _this.lastVolume = _this.audio.volume; _this.audio.volume = 0; _this.updateDisplayVolume(0); } else { _this.audio.volume = _this.lastVolume; _this.updateDisplayVolume(_this.lastVolume); } } ); _defineProperty( _assertThisInitialized(_this), "handleVolumnControlMouseDown", function(event) { event.stopPropagation(); var isTouch = event.type.startsWith("touch"); var _this$getCurrentVolum = _this.getCurrentVolume(event, isTouch), currentVolume = _this$getCurrentVolum.currentVolume, currentVolumePos = _this$getCurrentVolum.currentVolumePos; _this.audio.volume = currentVolume; _this.setState({ isDraggingVolume: true, currentVolume: currentVolume, currentVolumePos: currentVolumePos }); if (isTouch) { window.addEventListener( "touchmove", _this.handleWindowMouseOrTouchMove ); window.addEventListener( "touchend", _this.handleWindowMouseOrTouchUp ); } else { window.addEventListener( "mousemove", _this.handleWindowMouseOrTouchMove ); window.addEventListener( "mouseup", _this.handleWindowMouseOrTouchUp ); } } ); _defineProperty( _assertThisInitialized(_this), "handleWindowMouseOrTouchMove", function(event) { event.stopPropagation(); // Prevent Chrome drag selection bug var windowSelection = window.getSelection(); if (windowSelection.type === "Range") { windowSelection.empty(); } var isTouch = event.type.startsWith("touch"); var _this$state = _this.state, isDraggingVolume = _this$state.isDraggingVolume, isDraggingProgress = _this$state.isDraggingProgress; if (isDraggingVolume) { var _this$getCurrentVolum2 = _this.getCurrentVolume(event, isTouch), currentVolume = _this$getCurrentVolum2.currentVolume, currentVolumePos = _this$getCurrentVolum2.currentVolumePos; _this.audio.volume = currentVolume; _this.setState({ currentVolume: currentVolume, currentVolumePos: currentVolumePos }); } else if (isDraggingProgress) { var _this$getCurrentProgr = _this.getCurrentProgress( event, isTouch ), currentTime = _this$getCurrentProgr.currentTime, currentTimePos = _this$getCurrentProgr.currentTimePos; _this.timeOnMouseMove = currentTime; _this.setState({ currentTime: currentTime, currentTimePos: currentTimePos }); } } ); _defineProperty( _assertThisInitialized(_this), "handleWindowMouseOrTouchUp", function(event) { event.stopPropagation(); _this.setState(function(prevState) { if ( prevState.isDraggingProgress && isFinite(_this.timeOnMouseMove) ) { _this.audio.currentTime = _this.timeOnMouseMove; } return { isDraggingVolume: false, isDraggingProgress: false }; }); var isTouch = event.type.startsWith("touch"); if (isTouch) { window.removeEventListener( "touchmove", _this.handleWindowMouseOrTouchMove ); window.removeEventListener( "touchend", _this.handleWindowMouseOrTouchUp ); } else { window.removeEventListener( "mousemove", _this.handleWindowMouseOrTouchMove ); window.removeEventListener( "mouseup", _this.handleWindowMouseOrTouchUp ); } } ); _defineProperty( _assertThisInitialized(_this), "getCurrentVolume", function(event, isTouch) { var volumeBarRect = _this.volumeControl.getBoundingClientRect(); var relativePos = _this.constructor.getPosX(event, isTouch) - volumeBarRect.left; var currentVolume; var currentVolumePos; if (relativePos < 0) { currentVolume = 0; currentVolumePos = "0%"; } else if (relativePos > volumeBarRect.width) { currentVolume = 1; currentVolumePos = "".concat( (volumeBarRect.width / volumeBarRect.width) * 100, "%" ); } else { currentVolume = relativePos / volumeBarRect.width; currentVolumePos = "".concat( (relativePos / volumeBarRect.width) * 100, "%" ); } return { currentVolume: currentVolume, currentVolumePos: currentVolumePos }; } ); _defineProperty( _assertThisInitialized(_this), "handleMouseDownProgressBar", function(event) { event.stopPropagation(); var isTouch = event.type.startsWith("touch"); var _this$getCurrentProgr2 = _this.getCurrentProgress(event, isTouch), currentTime = _this$getCurrentProgr2.currentTime, currentTimePos = _this$getCurrentProgr2.currentTimePos; if (isFinite(currentTime)) { _this.timeOnMouseMove = currentTime; _this.setState({ isDraggingProgress: true, currentTime: currentTime, currentTimePos: currentTimePos }); if (isTouch) { window.addEventListener( "touchmove", _this.handleWindowMouseOrTouchMove ); window.addEventListener( "touchend", _this.handleWindowMouseOrTouchUp ); } else { window.addEventListener( "mousemove", _this.handleWindowMouseOrTouchMove ); window.addEventListener( "mouseup", _this.handleWindowMouseOrTouchUp ); } } } ); _defineProperty( _assertThisInitialized(_this), "handleClickLoopButton", function() { _this.setState(function(prevState) { return { isLoopEnabled: !prevState.isLoopEnabled }; }); } ); _defineProperty( _assertThisInitialized(_this), "handleClickRewind", function() { _this.setJumpTime(-_this.props.jumpInterval); } ); _defineProperty( _assertThisInitialized(_this), "handleClickForward", function() { _this.setJumpTime(_this.props.jumpInterval); } ); _defineProperty(_assertThisInitialized(_this), "setJumpTime", function( time ) { var duration = _this.audio.duration; if (!isFinite(duration)) return; _this.setState(function(prevState) { var currentTime = prevState.currentTime + time / 1000; if (currentTime < 0) { _this.audio.currentTime = 0; currentTime = 0; } else if (currentTime > duration) { _this.audio.currentTime = duration; currentTime = duration; } else { _this.audio.currentTime = currentTime; } return { currentTime: currentTime, currentTimePos: "".concat((currentTime / duration) * 100, "%") }; }); }); _defineProperty( _assertThisInitialized(_this), "getCurrentProgress", function(event, isTouch) { if (!_this.audio.src || !isFinite(_this.audio.currentTime)) { return { currentTime: 0, currentTimePos: "0%" }; } var progressBarRect = _this.progressBar.getBoundingClientRect(); var maxRelativePos = progressBarRect.width; var relativePos = _this.constructor.getPosX(event, isTouch) - progressBarRect.left; if (relativePos < 0) { relativePos = 0; } else if (relativePos > maxRelativePos) { relativePos = maxRelativePos; } var currentTime = (_this.audio.duration * relativePos) / maxRelativePos; return { currentTime: currentTime, currentTimePos: relativePos }; } ); _defineProperty( _assertThisInitialized(_this), "getDisplayTimeBySeconds", function(seconds) { if (!isFinite(seconds)) { return "00:00"; } var addHeadingZero = _this.constructor.addHeadingZero; var min = addHeadingZero(Math.floor(seconds / 60)); var sec = addHeadingZero(Math.floor(seconds % 60)); return "".concat(min, ":").concat(sec); } ); _defineProperty( _assertThisInitialized(_this), "setListenTrack", function() { if (!_this.listenTracker) { var listenInterval = _this.props.listenInterval; _this.listenTracker = setInterval(function() { _this.props.onListen && _this.props.onListen(_this.audio.currentTime); }, listenInterval); } } ); _defineProperty( _assertThisInitialized(_this), "clearListenTrack", function() { if (_this.listenTracker) { clearInterval(_this.listenTracker); _this.listenTracker = null; } } ); return _this; } _createClass(H5AudioPlayer, [ { key: "componentDidMount", value: function componentDidMount() { var _this2 = this; // audio player object var audio = this.audio; this.lastVolume = audio.volume; this.intervalId = setInterval(function() { if ( !_this2.audio.paused && !_this2.state.isDraggingProgress && !!_this2.audio.duration ) { _this2.updateDisplayTime(_this2.audio.currentTime); } }, this.props.progressUpdateInterval); audio.addEventListener("error", function(e) { _this2.props.onError && _this2.props.onError(e); }); // When enough of the file has downloaded to start playing audio.addEventListener("canplay", function(e) { if (isFinite(_this2.audio.duration)) { _this2.setState({ duration: _this2.audio.duration }); } _this2.props.onCanPlay && _this2.props.onCanPlay(e); }); // When enough of the file has downloaded to play the entire file audio.addEventListener("canplaythrough", function(e) { _this2.props.onCanPlayThrough && _this2.props.onCanPlayThrough(e); }); // When audio play starts audio.addEventListener("play", function(e) { _this2.setState({ isPlaying: true }); _this2.setListenTrack(); _this2.props.onPlay && _this2.props.onPlay(e); }); // When unloading the audio player (switching to another src) audio.addEventListener("abort", function(e) { _this2.clearListenTrack(); _this2.props.onAbort && _this2.props.onAbort(e); }); // When the file has finished playing to the end audio.addEventListener("ended", function(e) { _this2.clearListenTrack(); _this2.props.onEnded && _this2.props.onEnded(e); }); // When the user pauses playback audio.addEventListener("pause", function(e) { _this2.clearListenTrack(); if (!_this2.audio) return; _this2.setState({ isPlaying: false }); _this2.props.onPause && _this2.props.onPause(e); }); } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { var _this$props = this.props, src = _this$props.src, autoPlay = _this$props.autoPlay; if (src !== prevProps.src && autoPlay) { this.audio.play(); } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { clearInterval(this.intervalId); } }, { key: "render", value: function render() { var _this3 = this; var _this$props2 = this.props, className = _this$props2.className, src = _this$props2.src, preload = _this$props2.preload, autoPlay = _this$props2.autoPlay, _this$props2$title = _this$props2.title, title = _this$props2$title === void 0 ? src : _this$props2$title, muted = _this$props2.muted, showLoopControl = _this$props2.showLoopControl, showVolumeControl = _this$props2.showVolumeControl, showSkipControls = _this$props2.showSkipControls, showJumpControls = _this$props2.showJumpControls, onClickPrevious = _this$props2.onClickPrevious, onClickNext = _this$props2.onClickNext; var _this$state2 = this.state, currentTime = _this$state2.currentTime, currentTimePos = _this$state2.currentTimePos, currentVolume = _this$state2.currentVolume, currentVolumePos = _this$state2.currentVolumePos, duration = _this$state2.duration, isPlaying = _this$state2.isPlaying, isLoopEnabled = _this$state2.isLoopEnabled; return _react["default"].createElement( "div", { className: "rhap_container ".concat(className) }, _react["default"].createElement("audio", { src: src, controls: false, title: title, muted: muted, loop: isLoopEnabled, volume: currentVolume, autoPlay: autoPlay, preload: preload, ref: function ref(_ref) { _this3.audio = _ref; } }), _react["default"].createElement( "div", { className: "rhap_progress-section" }, _react["default"].createElement( "div", { className: "rhap_time rhap_current-time" }, this.getDisplayTimeBySeconds(currentTime) ), _react["default"].createElement( "div", { className: "rhap_progress-container", ref: function ref(_ref2) { _this3.progressBar = _ref2; }, onMouseDown: this.handleMouseDownProgressBar, onTouchStart: this.handleMouseDownProgressBar }, _react["default"].createElement( "div", { className: "rhap_progress-bar" }, _react["default"].createElement("div", { className: "rhap_progress-indicator", style: { left: currentTimePos } }) ) ), _react["default"].createElement( "div", { className: "rhap_time rhap_total-time" }, this.getDisplayTimeBySeconds(duration) ) ), _react["default"].createElement( "div", { className: "rhap_controls-section" }, _react["default"].createElement( "div", { className: "rhap_additional-controls" }, showLoopControl && _react["default"].createElement( "button", { className: "rhap_button-clear rhap_repeat-button", onClick: this.handleClickLoopButton }, _react["default"].createElement(_react2.Icon, { icon: isLoopEnabled ? _repeat["default"] : _repeatOff["default"] }) ) ), _react["default"].createElement( "div", { className: "rhap_main-controls" }, showSkipControls && _react["default"].createElement( "button", { className: "rhap_button-clear rhap_main-controls-button rhap_skip-button", onClick: onClickPrevious }, _react["default"].createElement(_react2.Icon, { icon: _skipPrevious["default"] }) ), showJumpControls && _react["default"].createElement( "button", { className: "rhap_button-clear rhap_main-controls-button rhap_rewind-button", onClick: this.handleClickRewind }, _react["default"].createElement(_react2.Icon, { icon: _rewind["default"] }) ), _react["default"].createElement( "button", { className: "rhap_button-clear rhap_main-controls-button rhap_play-pause-button", onClick: this.togglePlay }, isPlaying ? _react["default"].createElement(_react2.Icon, { icon: _pauseCircle["default"] }) : _react["default"].createElement(_react2.Icon, { icon: _playCircle["default"] }) ), showJumpControls && _react["default"].createElement( "button", { className: "rhap_button-clear rhap_main-controls-button rhap_forward-button", onClick: this.handleClickForward }, _react["default"].createElement(_react2.Icon, { icon: _fastForward["default"] }) ), showSkipControls && _react["default"].createElement( "button", { className: "rhap_button-clear rhap_main-controls-button rhap_skip-button", onClick: onClickNext }, _react["default"].createElement(_react2.Icon, { icon: _skipNext["default"] }) ) ), _react["default"].createElement( "div", { className: "rhap_volume-controls" }, showVolumeControl && _react["default"].createElement( "div", { className: "rhap_volume-container" }, _react["default"].createElement( "button", { onClick: this.handleClickVolumeButton, className: "rhap_button-clear rhap_volume-button" }, _react["default"].createElement(_react2.Icon, { icon: currentVolume ? _volumeHigh["default"] : _volumeMute["default"] }) ), _react["default"].createElement( "div", { ref: function ref(_ref3) { _this3.volumeControl = _ref3; }, onMouseDown: this.handleVolumnControlMouseDown, onTouchStart: this.handleVolumnControlMouseDown, className: "rhap_volume-bar-area" }, _react["default"].createElement( "div", { className: "rhap_volume-bar" }, _react["default"].createElement("div", { className: "rhap_volume-indicator", style: { left: currentVolumePos } }) ) ) ) ) ) ); } } ]); return H5AudioPlayer; })(_react.Component); _defineProperty(H5AudioPlayer, "propTypes", { /** * HTML5 Audio tag autoPlay property */ autoPlay: _propTypes["default"].bool, /** * custom classNames */ className: _propTypes["default"].string, /** * The time interval to trigger onListen */ listenInterval: _propTypes["default"].number, jumpInterval: _propTypes["default"].number, loop: _propTypes["default"].bool, muted: _propTypes["default"].bool, onAbort: _propTypes["default"].func, onCanPlay: _propTypes["default"].func, onCanPlayThrough: _propTypes["default"].func, onEnded: _propTypes["default"].func, onError: _propTypes["default"].func, onListen: _propTypes["default"].func, onPause: _propTypes["default"].func, onPlay: _propTypes["default"].func, onClickPrevious: _propTypes["default"].func, onClickNext: _propTypes["default"].func, onPlayError: _propTypes["default"].func, /** * HTML5 Audio tag preload property */ preload: _propTypes["default"].oneOf(["auto", "metadata", "none"]), /** * Pregress indicator refresh interval */ progressUpdateInterval: _propTypes["default"].number, /** * HTML5 Audio tag src property */ src: _propTypes["default"].string, title: _propTypes["default"].string, volume: _propTypes["default"].number, showLoopControl: _propTypes["default"].bool, showVolumeControl: _propTypes["default"].bool, showJumpControls: _propTypes["default"].bool, showSkipControls: _propTypes["default"].bool }); _defineProperty(H5AudioPlayer, "defaultProps", { autoPlay: false, listenInterval: 1000, jumpInterval: 10000, loop: false, muted: false, preload: "auto", progressUpdateInterval: 20, src: "", volume: 1.0, className: "", showLoopControl: true, showVolumeControl: true, showJumpControls: true, showSkipControls: false, onClickPrevious: null, onClickNext: null, onPlayError: null }); _defineProperty(H5AudioPlayer, "addHeadingZero", function(num) { return num > 9 ? num.toString() : "0".concat(num); }); _defineProperty(H5AudioPlayer, "getPosX", function(event, isTouch) { var posX; if (isTouch) { posX = event.touches[0].pageX; } else { posX = event.pageX || event.clientX; } return posX; }); var _default = H5AudioPlayer; exports["default"] = _default;