UNPKG

grommet

Version:

The most advanced UX framework for enterprise applications.

387 lines (339 loc) 14.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactDom = require('react-dom'); var _classnames2 = require('classnames'); var _classnames3 = _interopRequireDefault(_classnames2); var _CSSClassnames = require('../utils/CSSClassnames'); var _CSSClassnames2 = _interopRequireDefault(_CSSClassnames); var _Props = require('../utils/Props'); var _Props2 = _interopRequireDefault(_Props); var _Controls = require('./video/Controls'); var _Controls2 = _interopRequireDefault(_Controls); var _Overlay = require('./video/Overlay'); var _Overlay2 = _interopRequireDefault(_Overlay); var _Throttle = require('../utils/Throttle'); var _Throttle2 = _interopRequireDefault(_Throttle); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 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; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP var CLASS_ROOT = _CSSClassnames2.default.VIDEO; var BACKGROUND_COLOR_INDEX = _CSSClassnames2.default.BACKGROUND_COLOR_INDEX; var Video = function (_Component) { _inherits(Video, _Component); function Video(props, context) { _classCallCheck(this, Video); var _this = _possibleConstructorReturn(this, (Video.__proto__ || Object.getPrototypeOf(Video)).call(this, props, context)); _this._hasPlayed = false; _this._play = _this._play.bind(_this); _this._pause = _this._pause.bind(_this); _this._togglePlay = _this._togglePlay.bind(_this); _this._toggleMute = _this._toggleMute.bind(_this); _this._seek = _this._seek.bind(_this); _this._mute = _this._mute.bind(_this); _this._unmute = _this._unmute.bind(_this); _this._fullscreen = _this._fullscreen.bind(_this); _this._onInterationStart = _this._onInterationStart.bind(_this); _this._onInteractionOver = _this._onInteractionOver.bind(_this); _this._renderControls = _this._renderControls.bind(_this); _this.state = { mouseActive: false }; return _this; } _createClass(Video, [{ key: 'componentWillMount', value: function componentWillMount() { this._update = (0, _Throttle2.default)(this._update.bind(this), 100, this); this._mediaEventProps = this._injectUpdateVideoEvents(); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { // Dynamically modifying a source element and its attribute when // the element is already inserted in a video or audio element will // have no effect. // From HTML Specs: // https://html.spec.whatwg.org/multipage/embedded-content.html // #the-source-element // Using forceUpdate to force redraw of video when receiving new <source> this.forceUpdate(); } }, { key: '_injectUpdateVideoEvents', value: function _injectUpdateVideoEvents() { var _this2 = this; var videoEvents = ['onAbort', 'onCanPlay', 'onCanPlayThrough', 'onDurationChange', 'onEmptied', 'onEncrypted', 'onEnded', 'onError', 'onLoadedData', 'onLoadedMetadata', 'onLoadStart', 'onPause', 'onPlay', 'onPlaying', 'onProgress', 'onRateChange', 'onSeeked', 'onSeeking', 'onStalled', 'onSuspend', 'onTimeUpdate', 'onVolumeChange', 'onWaiting']; return videoEvents.reduce(function (previousValue, currentValue) { previousValue[currentValue] = function () { if (currentValue in _this2.props && typeof _this2.props[currentValue] === 'function') { _this2.props[currentValue](); } _this2._update(); }; return previousValue; }, {}); } }, { key: '_update', value: function _update() { // Set flag for Video first play if (!this._hasPlayed && !this._video.paused && !this._video.loading) { this._hasPlayed = true; } var interacting = this.state.interacting; if (this._video.ended) { interacting = false; }; this.setState({ duration: this._video.duration, currentTime: this._video.currentTime, buffered: this._video.buffered, paused: this._video.paused, muted: this._video.muted, volume: this._video.volume, ended: this._video.ended, readyState: this._video.readyState, interacting: interacting, // computed values hasPlayed: this._hasPlayed, playing: !this._video.paused && !this._video.loading, percentageBuffered: this._video.buffered.length && this._video.buffered.end(this._video.buffered.length - 1) / this._video.duration * 100, percentagePlayed: this._video.currentTime / this._video.duration * 100, loading: this._video.readyState < this._video.HAVE_ENOUGH_DATA }); } }, { key: '_play', value: function _play() { this._video.play(); } }, { key: '_pause', value: function _pause() { this._video.pause(); } }, { key: '_togglePlay', value: function _togglePlay() { if (this.state.paused) { this._play(); } else { this._pause(); } } }, { key: '_seek', value: function _seek(time) { this._video.currentTime = typeof time !== 'undefined' ? time : this._video.currentTime; } }, { key: '_unmute', value: function _unmute() { this._video.muted = false; } }, { key: '_mute', value: function _mute() { this._video.muted = true; } }, { key: '_toggleMute', value: function _toggleMute() { if (!this.state.muted) { this._mute(); } else { this._unmute(); } } }, { key: '_fullscreen', value: function _fullscreen() { if (this._video.requestFullscreen) { this._video.requestFullscreen(); } else if (this._video.msRequestFullscreen) { this._video.msRequestFullscreen(); } else if (this._video.mozRequestFullScreen) { this._video.mozRequestFullScreen(); } else if (this._video.webkitRequestFullscreen) { this._video.webkitRequestFullscreen(); } else { console.warn('Your browser doesn\'t support fullscreen.'); } } }, { key: '_onInterationStart', value: function _onInterationStart() { this.setState({ interacting: true }); } }, { key: '_onInteractionOver', value: function _onInteractionOver() { var focus = this.state.focus; if (!focus) { this.setState({ interacting: false }); } } }, { key: '_renderControls', value: function _renderControls() { var _this3 = this; var extendedProps = _extends({ title: this.props.title, togglePlay: this._togglePlay, toggleMute: this._toggleMute, play: this._play, pause: this._pause, mute: this._mute, unmute: this._unmute, seek: this._seek, timeline: this.props.timeline, fullscreen: this._fullscreen, shareLink: this.props.shareLink, shareHeadline: this.props.shareHeadline, shareText: this.props.shareText, allowFullScreen: this.props.allowFullScreen, size: this.props.size }, this.state); return _react2.default.createElement( 'div', null, _react2.default.createElement(_Overlay2.default, extendedProps), _react2.default.createElement(_Controls2.default, _extends({ ref: function ref(_ref) { return _this3._controlRef = _ref; } }, extendedProps)) ); } }, { key: 'render', value: function render() { var _classnames, _this4 = this; var _props = this.props, align = _props.align, autoPlay = _props.autoPlay, className = _props.className, colorIndex = _props.colorIndex, fit = _props.fit, full = _props.full, loop = _props.loop, muted = _props.muted, poster = _props.poster, showControls = _props.showControls, size = _props.size; var _state = this.state, ended = _state.ended, hasPlayed = _state.hasPlayed, interacting = _state.interacting, mouseActive = _state.mouseActive, playing = _state.playing; var classes = (0, _classnames3.default)(CLASS_ROOT, (_classnames = {}, _defineProperty(_classnames, CLASS_ROOT + '--' + size, size), _defineProperty(_classnames, CLASS_ROOT + '--' + fit, fit), _defineProperty(_classnames, CLASS_ROOT + '--full', fit || full), _defineProperty(_classnames, CLASS_ROOT + '--interacting', interacting), _defineProperty(_classnames, CLASS_ROOT + '--playing', playing), _defineProperty(_classnames, CLASS_ROOT + '--hasPlayed', hasPlayed), _defineProperty(_classnames, CLASS_ROOT + '--ended', ended), _defineProperty(_classnames, BACKGROUND_COLOR_INDEX + '--' + colorIndex, colorIndex), _defineProperty(_classnames, CLASS_ROOT + '--align-top', align && align.top), _defineProperty(_classnames, CLASS_ROOT + '--align-bottom', align && align.bottom), _defineProperty(_classnames, CLASS_ROOT + '--align-left', align && align.left), _defineProperty(_classnames, CLASS_ROOT + '--align-right', align && align.right), _classnames), className); var restProps = _Props2.default.omit(this.props, Object.keys(Video.propTypes)); return _react2.default.createElement( 'div', { className: classes, ref: function ref(_ref2) { return _this4._containerRef = _ref2; }, onMouseEnter: function onMouseEnter() { if (!ended) { _this4._onInterationStart(); } }, onMouseMove: function onMouseMove(event) { // needed to avoid react synthatic event pooling event.persist(); if (!ended || (0, _reactDom.findDOMNode)(_this4._controlRef).contains(event.target)) { _this4._onInterationStart(); } else if (ended) { _this4._onInteractionOver(); } clearTimeout(_this4._moveTimer); _this4._moveTimer = setTimeout(function () { var element = (0, _reactDom.findDOMNode)(_this4._controlRef); if (element && !element.contains(event.target)) { _this4._onInteractionOver(); } }, 1000); }, onMouseLeave: this._onInteractionOver, onMouseDown: function onMouseDown() { _this4.setState({ mouseActive: true }); }, onMouseUp: function onMouseUp() { _this4.setState({ mouseActive: false }); }, onFocus: function onFocus() { if (mouseActive === false) { _this4._onInterationStart(); _this4.setState({ focus: true }); } }, onBlur: function onBlur() { _this4.setState({ focus: false }, function () { if (!_this4._containerRef.contains(document.activeElement)) { _this4._onInteractionOver(); } }); } }, _react2.default.createElement( 'video', _extends({ ref: function ref(el) { return _this4._video = el; } }, restProps, { poster: poster, autoPlay: autoPlay ? 'autoplay' : false, loop: loop ? 'loop' : false, muted: muted }, this._mediaEventProps), this.props.children ), showControls ? this._renderControls() : undefined ); } }]); return Video; }(_react.Component); Video.displayName = 'Video'; exports.default = Video; Video.propTypes = { align: _propTypes2.default.shape({ bottom: _propTypes2.default.boolean, left: _propTypes2.default.boolean, right: _propTypes2.default.boolean, top: _propTypes2.default.boolean }), allowFullScreen: _propTypes2.default.bool, autoPlay: _propTypes2.default.bool, colorIndex: _propTypes2.default.string, fit: _propTypes2.default.oneOf(['contain', 'cover']), full: _propTypes2.default.oneOf([true, 'horizontal', 'vertical', false]), loop: _propTypes2.default.bool, muted: _propTypes2.default.bool, poster: _propTypes2.default.string, shareLink: _propTypes2.default.string, shareHeadline: _propTypes2.default.string, shareText: _propTypes2.default.string, showControls: _propTypes2.default.bool, size: _propTypes2.default.oneOf(['small', 'medium', 'large']), timeline: _propTypes2.default.arrayOf(_propTypes2.default.shape({ label: _propTypes2.default.string, time: _propTypes2.default.number })), title: _propTypes2.default.node }; Video.defaultProps = { allowFullScreen: true, autoPlay: false, loop: false, muted: false, size: 'medium', showControls: true }; module.exports = exports['default'];