UNPKG

react-youtube-playlist

Version:

A react component for displaying the contents of a user's YouTube playlist.

608 lines (477 loc) 19 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 _warning = require('warning'); var _warning2 = _interopRequireDefault(_warning); var _componentOrElement = require('react-prop-types/lib/componentOrElement'); var _componentOrElement2 = _interopRequireDefault(_componentOrElement); var _elementType = require('react-prop-types/lib/elementType'); var _elementType2 = _interopRequireDefault(_elementType); var _Portal = require('./Portal'); var _Portal2 = _interopRequireDefault(_Portal); var _ModalManager = require('./ModalManager'); var _ModalManager2 = _interopRequireDefault(_ModalManager); var _ownerDocument = require('./utils/ownerDocument'); var _ownerDocument2 = _interopRequireDefault(_ownerDocument); var _addEventListener = require('./utils/addEventListener'); var _addEventListener2 = _interopRequireDefault(_addEventListener); var _addFocusListener = require('./utils/addFocusListener'); var _addFocusListener2 = _interopRequireDefault(_addFocusListener); var _inDOM = require('dom-helpers/util/inDOM'); var _inDOM2 = _interopRequireDefault(_inDOM); var _activeElement = require('dom-helpers/activeElement'); var _activeElement2 = _interopRequireDefault(_activeElement); var _contains = require('dom-helpers/query/contains'); var _contains2 = _interopRequireDefault(_contains); var _getContainer = require('./utils/getContainer'); var _getContainer2 = _interopRequireDefault(_getContainer); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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; } /*eslint-disable react/prop-types */ var modalManager = new _ModalManager2.default(); /** * Love them or hate them, `<Modal/>` provides a solid foundation for creating dialogs, lightboxes, or whatever else. * The Modal component renders its `children` node in front of a backdrop component. * * The Modal offers a few helpful features over using just a `<Portal/>` component and some styles: * * - Manages dialog stacking when one-at-a-time just isn't enough. * - Creates a backdrop, for disabling interaction below the modal. * - It properly manages focus; moving to the modal content, and keeping it there until the modal is closed. * - It disables scrolling of the page content while open. * - Adds the appropriate ARIA roles are automatically. * - Easily pluggable animations via a `<Transition/>` component. * * Note that, in the same way the backdrop element prevents users from clicking or interacting * with the page content underneath the Modal, Screen readers also need to be signaled to not to * interact with page content while the Modal is open. To do this, we use a common technique of applying * the `aria-hidden='true'` attribute to the non-Modal elements in the Modal `container`. This means that for * a Modal to be truly modal, it should have a `container` that is _outside_ your app's * React hierarchy (such as the default: document.body). */ var Modal = function (_React$Component) { _inherits(Modal, _React$Component); function Modal() { var _ref; var _temp, _this, _ret; _classCallCheck(this, Modal); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Modal.__proto__ || Object.getPrototypeOf(Modal)).call.apply(_ref, [this].concat(args))), _this), _initialiseProps.call(_this), _temp), _possibleConstructorReturn(_this, _ret); } _createClass(Modal, [{ key: 'omitProps', value: function omitProps(props, propTypes) { var keys = Object.keys(props); var newProps = {}; keys.map(function (prop) { if (!Object.prototype.hasOwnProperty.call(propTypes, prop)) { newProps[prop] = props[prop]; } }); return newProps; } }, { key: 'render', value: function render() { var _props = this.props; var show = _props.show; var container = _props.container; var children = _props.children; var Transition = _props.transition; var backdrop = _props.backdrop; var dialogTransitionTimeout = _props.dialogTransitionTimeout; var className = _props.className; var style = _props.style; var onExit = _props.onExit; var onExiting = _props.onExiting; var onEnter = _props.onEnter; var onEntering = _props.onEntering; var onEntered = _props.onEntered; var dialog = _react2.default.Children.only(children); var filteredProps = this.omitProps(this.props, Modal.propTypes); var mountModal = show || Transition && !this.state.exited; if (!mountModal) { return null; } var _dialog$props = dialog.props; var role = _dialog$props.role; var tabIndex = _dialog$props.tabIndex; if (role === undefined || tabIndex === undefined) { dialog = (0, _react.cloneElement)(dialog, { role: role === undefined ? 'document' : role, tabIndex: tabIndex == null ? '-1' : tabIndex }); } if (Transition) { dialog = _react2.default.createElement( Transition, { transitionAppear: true, unmountOnExit: true, 'in': show, timeout: dialogTransitionTimeout, onExit: onExit, onExiting: onExiting, onExited: this.handleHidden, onEnter: onEnter, onEntering: onEntering, onEntered: onEntered }, dialog ); } return _react2.default.createElement( _Portal2.default, { ref: this.setMountNode, container: container }, _react2.default.createElement( 'div', _extends({ ref: this.setModalNode, role: role || 'dialog' }, filteredProps, { style: style, className: className }), backdrop && this.renderBackdrop(), dialog ) ); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.show) { this.setState({ exited: false }); } else if (!nextProps.transition) { // Otherwise let handleHidden take care of marking exited. this.setState({ exited: true }); } } }, { key: 'componentWillUpdate', value: function componentWillUpdate(nextProps) { if (!this.props.show && nextProps.show) { this.checkForFocus(); } } }, { key: 'componentDidMount', value: function componentDidMount() { this._isMounted = true; if (this.props.show) { this.onShow(); } } }, { key: 'componentDidUpdate', value: function componentDidUpdate(prevProps) { var transition = this.props.transition; if (prevProps.show && !this.props.show && !transition) { // Otherwise handleHidden will call this. this.onHide(); } else if (!prevProps.show && this.props.show) { this.onShow(); } } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { var _props2 = this.props; var show = _props2.show; var transition = _props2.transition; this._isMounted = false; if (show || transition && !this.state.exited) { this.onHide(); } } //instead of a ref, which might conflict with one the parent applied. }]); return Modal; }(_react2.default.Component); Modal.propTypes = _extends({}, _Portal2.default.propTypes, { /** * Set the visibility of the Modal */ show: _propTypes2.default.bool, /** * A Node, Component instance, or function that returns either. The Modal is appended to it's container element. * * For the sake of assistive technologies, the container should usually be the document body, so that the rest of the * page content can be placed behind a virtual backdrop as well as a visual one. */ container: _propTypes2.default.oneOfType([_componentOrElement2.default, _propTypes2.default.func]), /** * A callback fired when the Modal is opening. */ onShow: _propTypes2.default.func, /** * A callback fired when either the backdrop is clicked, or the escape key is pressed. * * The `onHide` callback only signals intent from the Modal, * you must actually set the `show` prop to `false` for the Modal to close. */ onHide: _propTypes2.default.func, /** * Include a backdrop component. */ backdrop: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.oneOf(['static'])]), /** * A function that returns a backdrop component. Useful for custom * backdrop rendering. * * ```js * renderBackdrop={props => <MyBackdrop {...props} />} * ``` */ renderBackdrop: _propTypes2.default.func, /** * A callback fired when the escape key, if specified in `keyboard`, is pressed. */ onEscapeKeyUp: _propTypes2.default.func, /** * A callback fired when the backdrop, if specified, is clicked. */ onBackdropClick: _propTypes2.default.func, /** * A style object for the backdrop component. */ backdropStyle: _propTypes2.default.object, /** * A css class or classes for the backdrop component. */ backdropClassName: _propTypes2.default.string, /** * A css class or set of classes applied to the modal container when the modal is open, * and removed when it is closed. */ containerClassName: _propTypes2.default.string, /** * Close the modal when escape key is pressed */ keyboard: _propTypes2.default.bool, /** * A `<Transition/>` component to use for the dialog and backdrop components. */ transition: _elementType2.default, /** * The `timeout` of the dialog transition if specified. This number is used to ensure that * transition callbacks are always fired, even if browser transition events are canceled. * * See the Transition `timeout` prop for more infomation. */ dialogTransitionTimeout: _propTypes2.default.number, /** * The `timeout` of the backdrop transition if specified. This number is used to * ensure that transition callbacks are always fired, even if browser transition events are canceled. * * See the Transition `timeout` prop for more infomation. */ backdropTransitionTimeout: _propTypes2.default.number, /** * When `true` The modal will automatically shift focus to itself when it opens, and * replace it to the last focused element when it closes. This also * works correctly with any Modal children that have the `autoFocus` prop. * * Generally this should never be set to `false` as it makes the Modal less * accessible to assistive technologies, like screen readers. */ autoFocus: _propTypes2.default.bool, /** * When `true` The modal will prevent focus from leaving the Modal while open. * * Generally this should never be set to `false` as it makes the Modal less * accessible to assistive technologies, like screen readers. */ enforceFocus: _propTypes2.default.bool, /** * When `true` The modal will restore focus to previously focused element once * modal is hidden */ restoreFocus: _propTypes2.default.bool, /** * Callback fired before the Modal transitions in */ onEnter: _propTypes2.default.func, /** * Callback fired as the Modal begins to transition in */ onEntering: _propTypes2.default.func, /** * Callback fired after the Modal finishes transitioning in */ onEntered: _propTypes2.default.func, /** * Callback fired right before the Modal transitions out */ onExit: _propTypes2.default.func, /** * Callback fired as the Modal begins to transition out */ onExiting: _propTypes2.default.func, /** * Callback fired after the Modal finishes transitioning out */ onExited: _propTypes2.default.func, /** * A ModalManager instance used to track and manage the state of open * Modals. Useful when customizing how modals interact within a container */ manager: _propTypes2.default.object.isRequired }); Modal.defaultProps = { show: false, backdrop: true, keyboard: true, autoFocus: true, enforceFocus: true, restoreFocus: true, onHide: function onHide() {}, manager: modalManager, renderBackdrop: function renderBackdrop(props) { return _react2.default.createElement('div', props); } }; var _initialiseProps = function _initialiseProps() { var _this2 = this; this.state = { exited: !this.props.show }; this.renderBackdrop = function () { var _props3 = _this2.props; var backdropStyle = _props3.backdropStyle; var backdropClassName = _props3.backdropClassName; var renderBackdrop = _props3.renderBackdrop; var Transition = _props3.transition; var backdropTransitionTimeout = _props3.backdropTransitionTimeout; var backdropRef = function backdropRef(ref) { return _this2.backdrop = ref; }; var backdrop = renderBackdrop({ ref: backdropRef, style: backdropStyle, className: backdropClassName, onClick: _this2.handleBackdropClick }); if (Transition) { backdrop = _react2.default.createElement( Transition, { transitionAppear: true, 'in': _this2.props.show, timeout: backdropTransitionTimeout }, backdrop ); } return backdrop; }; this.onShow = function () { var doc = (0, _ownerDocument2.default)(_this2); var container = (0, _getContainer2.default)(_this2.props.container, doc.body); _this2.props.manager.add(_this2, container, _this2.props.containerClassName); _this2._onDocumentKeyupListener = (0, _addEventListener2.default)(doc, 'keyup', _this2.handleDocumentKeyUp); _this2._onFocusinListener = (0, _addFocusListener2.default)(_this2.enforceFocus); _this2.focus(); if (_this2.props.onShow) { _this2.props.onShow(); } }; this.onHide = function () { _this2.props.manager.remove(_this2); _this2._onDocumentKeyupListener.remove(); _this2._onFocusinListener.remove(); if (_this2.props.restoreFocus) { _this2.restoreLastFocus(); } }; this.setMountNode = function (ref) { _this2.mountNode = ref ? ref.getMountNode() : ref; }; this.setModalNode = function (ref) { _this2.modalNode = ref; }; this.handleHidden = function () { _this2.setState({ exited: true }); _this2.onHide(); if (_this2.props.onExited) { var _props4; (_props4 = _this2.props).onExited.apply(_props4, arguments); } }; this.handleBackdropClick = function (e) { if (e.target !== e.currentTarget) { return; } if (_this2.props.onBackdropClick) { _this2.props.onBackdropClick(e); } if (_this2.props.backdrop === true) { _this2.props.onHide(); } }; this.handleDocumentKeyUp = function (e) { if (_this2.props.keyboard && e.keyCode === 27 && _this2.isTopModal()) { if (_this2.props.onEscapeKeyUp) { _this2.props.onEscapeKeyUp(e); } _this2.props.onHide(); } }; this.checkForFocus = function () { if (_inDOM2.default) { _this2.lastFocus = (0, _activeElement2.default)(); } }; this.focus = function () { var autoFocus = _this2.props.autoFocus; var modalContent = _this2.getDialogElement(); var current = (0, _activeElement2.default)((0, _ownerDocument2.default)(_this2)); var focusInModal = current && (0, _contains2.default)(modalContent, current); if (modalContent && autoFocus && !focusInModal) { _this2.lastFocus = current; if (!modalContent.hasAttribute('tabIndex')) { modalContent.setAttribute('tabIndex', -1); (0, _warning2.default)(false, 'The modal content node does not accept focus. ' + 'For the benefit of assistive technologies, the tabIndex of the node is being set to "-1".'); } modalContent.focus(); } }; this.restoreLastFocus = function () { // Support: <=IE11 doesn't support `focus()` on svg elements (RB: #917) if (_this2.lastFocus && _this2.lastFocus.focus) { _this2.lastFocus.focus(); _this2.lastFocus = null; } }; this.enforceFocus = function () { var enforceFocus = _this2.props.enforceFocus; if (!enforceFocus || !_this2._isMounted || !_this2.isTopModal()) { return; } var active = (0, _activeElement2.default)((0, _ownerDocument2.default)(_this2)); var modal = _this2.getDialogElement(); if (modal && modal !== active && !(0, _contains2.default)(modal, active)) { modal.focus(); } }; this.getDialogElement = function () { var node = _this2.modalNode; return node && node.lastChild; }; this.isTopModal = function () { return _this2.props.manager.isTopModal(_this2); }; }; Modal.Manager = _ModalManager2.default; exports.default = Modal; module.exports = exports['default'];