[
  {
    "path": ".editorconfig",
    "content": "# editorconfig.org\nroot = true\n\n[*.js]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.html]\n# すべてのファイルに適用する\ncharset = utf-8\n# 文字コードを統一\nindent_style = tab\n#インデントを統一する。「tab」か「 space」\nindent_size = 2\n# インデントの数を統一\ntrim_trailing_whitespace = true\n# 行末のホワイトスペースを削除\ninsert_final_newline = true\n# フォルダの最後の行に改行\nend_of_line = lf\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"env\": {\n    \"browser\": true\n  },\n  \"globals\": {\n    \"document\": true,\n    \"window\": true\n  },\n  \"rules\":{\n    \"comma-dangle\":0\n  },\n  \"parserOptions\": {\n    \"sourceType\": \"module\",\n    \"ecmaVersion\": 2015,\n    \"ecmaFeatures\": {\n      \"jsx\": true\n    }\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules/*\nyarn.lock\n.DS_Store\n.idea\ntest/dist"
  },
  {
    "path": ".node-version",
    "content": "18.12.1\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 appleple\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  presets: [\n    ['@babel/preset-env',\n      {\n        targets: {\n          ie: 11,\n        },\n        useBuiltIns: 'usage',\n        corejs: 3,\n      },\n    ],\n    ['@babel/preset-react'],\n  ]\n};\n"
  },
  {
    "path": "circle.yml",
    "content": "machine:\n  node:\n    version: 6.2.0\ndependencies:\n  override:\n    - \"npm install\"\ntest:\n  override:\n    - \"npm run test\""
  },
  {
    "path": "css/modal-video.css",
    "content": "@keyframes modal-video {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@keyframes modal-video-inner {\n  from {\n    transform: translate(0, 100px);\n  }\n  to {\n    transform: translate(0, 0);\n  }\n}\n.modal-video {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.5);\n  z-index: 1000000;\n  cursor: pointer;\n  opacity: 1;\n  animation-timing-function: ease-out;\n  animation-duration: 0.3s;\n  animation-name: modal-video;\n  -webkit-transition: opacity 0.3s ease-out;\n  -moz-transition: opacity 0.3s ease-out;\n  -ms-transition: opacity 0.3s ease-out;\n  -o-transition: opacity 0.3s ease-out;\n  transition: opacity 0.3s ease-out;\n}\n\n.modal-video-effect-exit {\n  opacity: 0;\n}\n.modal-video-effect-exit .modal-video-movie-wrap {\n  -webkit-transform: translate(0, 100px);\n  -moz-transform: translate(0, 100px);\n  -ms-transform: translate(0, 100px);\n  -o-transform: translate(0, 100px);\n  transform: translate(0, 100px);\n}\n\n.modal-video-body {\n  max-width: 960px;\n  width: 100%;\n  height: 100%;\n  margin: 0 auto;\n  padding: 0 10px;\n  display: flex;\n  justify-content: center;\n  box-sizing: border-box;\n}\n\n.modal-video-inner {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  width: 100%;\n  height: 100%;\n}\n@media (orientation: landscape) {\n  .modal-video-inner {\n    padding: 10px 60px;\n    box-sizing: border-box;\n  }\n}\n\n.modal-video-movie-wrap {\n  width: 100%;\n  height: 0;\n  position: relative;\n  padding-bottom: 56.25%;\n  background-color: #333;\n  animation-timing-function: ease-out;\n  animation-duration: 0.3s;\n  animation-name: modal-video-inner;\n  -webkit-transform: translate(0, 0);\n  -moz-transform: translate(0, 0);\n  -ms-transform: translate(0, 0);\n  -o-transform: translate(0, 0);\n  transform: translate(0, 0);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -moz-transition: -moz-transform 0.3s ease-out;\n  -ms-transition: -ms-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\n.modal-video-movie-wrap iframe {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n}\n\n.modal-video-close-btn {\n  position: absolute;\n  z-index: 2;\n  top: -45px;\n  right: 0px;\n  display: inline-block;\n  width: 35px;\n  height: 35px;\n  overflow: hidden;\n  border: none;\n  background: transparent;\n}\n@media (orientation: landscape) {\n  .modal-video-close-btn {\n    top: 0;\n    right: -45px;\n  }\n}\n.modal-video-close-btn:before {\n  transform: rotate(45deg);\n}\n.modal-video-close-btn:after {\n  transform: rotate(-45deg);\n}\n.modal-video-close-btn:before, .modal-video-close-btn:after {\n  content: \"\";\n  position: absolute;\n  height: 2px;\n  width: 100%;\n  top: 50%;\n  left: 0;\n  margin-top: -1px;\n  background: #fff;\n  border-radius: 5px;\n  margin-top: -6px;\n}\n"
  },
  {
    "path": "lib/index.js",
    "content": "\"use strict\";\n\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\nrequire(\"core-js/modules/es.object.to-string.js\");\nrequire(\"core-js/modules/es.reflect.construct.js\");\nrequire(\"core-js/modules/es.symbol.to-primitive.js\");\nrequire(\"core-js/modules/es.date.to-primitive.js\");\nrequire(\"core-js/modules/es.symbol.js\");\nrequire(\"core-js/modules/es.symbol.description.js\");\nrequire(\"core-js/modules/es.symbol.iterator.js\");\nrequire(\"core-js/modules/es.array.iterator.js\");\nrequire(\"core-js/modules/es.string.iterator.js\");\nrequire(\"core-js/modules/web.dom-collections.iterator.js\");\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\nrequire(\"core-js/modules/es.array.concat.js\");\nrequire(\"core-js/modules/es.number.constructor.js\");\nrequire(\"core-js/modules/es.object.get-prototype-of.js\");\nvar _react = _interopRequireDefault(require(\"react\"));\nvar _CSSTransition = _interopRequireDefault(require(\"react-transition-group/CSSTransition\"));\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _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, _toPropertyKey(descriptor.key), descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\nfunction _toPropertyKey(arg) { var key = _toPrimitive(arg, \"string\"); return _typeof(key) === \"symbol\" ? key : String(key); }\nfunction _toPrimitive(input, hint) { if (_typeof(input) !== \"object\" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || \"default\"); if (_typeof(res) !== \"object\") return res; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (hint === \"string\" ? String : Number)(input); }\nfunction _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 } }); Object.defineProperty(subClass, \"prototype\", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } else if (call !== void 0) { throw new TypeError(\"Derived constructors may only return object or undefined\"); } return _assertThisInitialized(self); }\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\nvar ModalVideo = /*#__PURE__*/function (_React$Component) {\n  _inherits(ModalVideo, _React$Component);\n  var _super = _createSuper(ModalVideo);\n  function ModalVideo(props) {\n    var _this;\n    _classCallCheck(this, ModalVideo);\n    _this = _super.call(this, props);\n    _this.state = {\n      isOpen: false,\n      modalVideoWidth: '100%'\n    };\n    _this.closeModal = _this.closeModal.bind(_assertThisInitialized(_this));\n    _this.updateFocus = _this.updateFocus.bind(_assertThisInitialized(_this));\n    _this.timeout; // used for resizing video.\n    return _this;\n  }\n  _createClass(ModalVideo, [{\n    key: \"openModal\",\n    value: function openModal() {\n      this.setState({\n        isOpen: true\n      });\n    }\n  }, {\n    key: \"closeModal\",\n    value: function closeModal() {\n      this.setState({\n        isOpen: false\n      });\n      if (typeof this.props.onClose === 'function') {\n        this.props.onClose();\n      }\n    }\n  }, {\n    key: \"keydownHandler\",\n    value: function keydownHandler(e) {\n      if (e.keyCode === 27) {\n        this.closeModal();\n      }\n    }\n  }, {\n    key: \"componentDidMount\",\n    value: function componentDidMount() {\n      document.addEventListener('keydown', this.keydownHandler.bind(this));\n      window.addEventListener('resize', this.resizeModalVideoWhenHeightGreaterThanWindowHeight.bind(this));\n      this.setState({\n        modalVideoWidth: this.getWidthFulfillAspectRatio(this.props.ratio, window.innerHeight, window.innerWidth)\n      });\n    }\n  }, {\n    key: \"componentWillUnmount\",\n    value: function componentWillUnmount() {\n      document.removeEventListener('keydown', this.keydownHandler.bind(this));\n      window.removeEventListener('resize', this.resizeModalVideoWhenHeightGreaterThanWindowHeight.bind(this));\n    }\n  }, {\n    key: \"componentDidUpdate\",\n    value: function componentDidUpdate() {\n      if (this.state.isOpen && this.modal) {\n        this.modal.focus();\n      }\n    }\n  }, {\n    key: \"updateFocus\",\n    value: function updateFocus(e) {\n      if (this.state.isOpen) {\n        e.preventDefault();\n        e.stopPropagation();\n        if (e.keyCode === 9) {\n          if (this.modal === document.activeElement) {\n            this.modaliflame.focus();\n          } else if (this.modalbtn === document.activeElement) {\n            this.modal.focus();\n          }\n        }\n      }\n    }\n\n    /**\n     * Resize modal-video-iframe-wrap when window size changed when the height of the video is greater than the height of the window.\n     */\n  }, {\n    key: \"resizeModalVideoWhenHeightGreaterThanWindowHeight\",\n    value: function resizeModalVideoWhenHeightGreaterThanWindowHeight() {\n      var _this2 = this;\n      clearTimeout(this.timeout);\n      this.timeout = setTimeout(function () {\n        var width = _this2.getWidthFulfillAspectRatio(_this2.props.ratio, window.innerHeight, window.innerWidth);\n        if (_this2.state.modalVideoWidth != width) {\n          _this2.setState({\n            modalVideoWidth: width\n          });\n        }\n      }, 10);\n    }\n  }, {\n    key: \"getQueryString\",\n    value: function getQueryString(obj) {\n      var url = '';\n      for (var key in obj) {\n        if (obj.hasOwnProperty(key)) {\n          if (obj[key] !== null) {\n            url += \"\".concat(key, \"=\").concat(obj[key], \"&\");\n          }\n        }\n      }\n      return url.substr(0, url.length - 1);\n    }\n  }, {\n    key: \"getYoutubeUrl\",\n    value: function getYoutubeUrl(youtube, videoId) {\n      var query = this.getQueryString(youtube);\n      return \"//www.youtube.com/embed/\".concat(videoId, \"?\").concat(query);\n    }\n  }, {\n    key: \"getVimeoUrl\",\n    value: function getVimeoUrl(vimeo, videoId) {\n      var query = this.getQueryString(vimeo);\n      return \"//player.vimeo.com/video/\".concat(videoId, \"?\").concat(query);\n    }\n  }, {\n    key: \"getYoukuUrl\",\n    value: function getYoukuUrl(youku, videoId) {\n      var query = this.getQueryString(youku);\n      return \"//player.youku.com/embed/\".concat(videoId, \"?\").concat(query);\n    }\n  }, {\n    key: \"getVideoUrl\",\n    value: function getVideoUrl(opt, videoId) {\n      if (opt.channel === 'youtube') {\n        return this.getYoutubeUrl(opt.youtube, videoId);\n      }\n      if (opt.channel === 'vimeo') {\n        return this.getVimeoUrl(opt.vimeo, videoId);\n      }\n      if (opt.channel === 'youku') {\n        return this.getYoukuUrl(opt.youku, videoId);\n      }\n      if (opt.channel === 'custom') {\n        return opt.url;\n      }\n    }\n  }, {\n    key: \"getPadding\",\n    value: function getPadding(ratio) {\n      var arr = ratio.split(':');\n      var width = Number(arr[0]);\n      var height = Number(arr[1]);\n      var padding = height * 100 / width;\n      return \"\".concat(padding, \"%\");\n    }\n\n    /**\n     * Calculate the width of the video fulfill aspect ratio.\n     * When the height of the video is greater than the height of the window,\n     * this function return the width that fulfill the aspect ratio for the height of the window.\n     * In other cases, this function return '100%'(the height relative to the width is determined by css).\n     *\n     * @param string ratio\n     * @param number maxWidth\n     * @returns number | '100%'\n     */\n  }, {\n    key: \"getWidthFulfillAspectRatio\",\n    value: function getWidthFulfillAspectRatio(ratio, maxHeight, maxWidth) {\n      var arr = ratio.split(':');\n      var width = Number(arr[0]);\n      var height = Number(arr[1]);\n\n      // Height that fulfill the aspect ratio for maxWidth.\n      var videoHeight = maxWidth * (height / width);\n      if (maxHeight < videoHeight) {\n        // when the height of the video is greater than the height of the window.\n        // calculate the width that fulfill the aspect ratio for the height of the window.\n\n        // ex: 16:9 aspect ratio\n        // 16:9 = width : height\n        // → width = 16 / 9 * height\n        return Math.floor(width / height * maxHeight);\n      }\n      return '100%';\n    }\n  }, {\n    key: \"render\",\n    value: function render() {\n      var _this3 = this;\n      var modalVideoInnerStyle = {\n        width: this.state.modalVideoWidth\n      };\n      var modalVideoIframeWrapStyle = {\n        paddingBottom: this.getPadding(this.props.ratio)\n      };\n      return /*#__PURE__*/_react.default.createElement(_CSSTransition.default, {\n        classNames: this.props.classNames.modalVideoEffect,\n        timeout: this.props.animationSpeed\n      }, function () {\n        if (!_this3.state.isOpen) {\n          return null;\n        }\n        return /*#__PURE__*/_react.default.createElement(\"div\", {\n          className: _this3.props.classNames.modalVideo,\n          tabIndex: \"-1\",\n          role: \"dialog\",\n          \"area-modal\": \"true\",\n          \"aria-label\": _this3.props.aria.openMessage,\n          onClick: _this3.closeModal,\n          ref: function ref(node) {\n            _this3.modal = node;\n          },\n          onKeyDown: _this3.updateFocus\n        }, /*#__PURE__*/_react.default.createElement(\"div\", {\n          className: _this3.props.classNames.modalVideoBody\n        }, /*#__PURE__*/_react.default.createElement(\"div\", {\n          className: _this3.props.classNames.modalVideoInner,\n          style: modalVideoInnerStyle\n        }, /*#__PURE__*/_react.default.createElement(\"div\", {\n          className: _this3.props.classNames.modalVideoIframeWrap,\n          style: modalVideoIframeWrapStyle\n        }, _this3.props.children || /*#__PURE__*/_react.default.createElement(\"iframe\", {\n          width: \"460\",\n          height: \"230\",\n          src: _this3.getVideoUrl(_this3.props, _this3.props.videoId),\n          frameBorder: \"0\",\n          allow: 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture',\n          allowFullScreen: _this3.props.allowFullScreen,\n          onKeyDown: _this3.updateFocus,\n          ref: function ref(node) {\n            _this3.modaliflame = node;\n          },\n          tabIndex: \"-1\"\n        }), /*#__PURE__*/_react.default.createElement(\"button\", {\n          className: _this3.props.classNames.modalVideoCloseBtn,\n          \"aria-label\": _this3.props.aria.dismissBtnMessage,\n          ref: function ref(node) {\n            _this3.modalbtn = node;\n          },\n          onKeyDown: _this3.updateFocus\n        })))));\n      });\n    }\n  }], [{\n    key: \"getDerivedStateFromProps\",\n    value: function getDerivedStateFromProps(props) {\n      return {\n        isOpen: props.isOpen\n      };\n    }\n  }]);\n  return ModalVideo;\n}(_react.default.Component);\nexports.default = ModalVideo;\nModalVideo.defaultProps = {\n  channel: 'youtube',\n  isOpen: false,\n  youtube: {\n    autoplay: 1,\n    cc_load_policy: 1,\n    color: null,\n    controls: 1,\n    disablekb: 0,\n    enablejsapi: 0,\n    end: null,\n    fs: 1,\n    h1: null,\n    iv_load_policy: 1,\n    list: null,\n    listType: null,\n    loop: 0,\n    modestbranding: null,\n    origin: null,\n    playlist: null,\n    playsinline: null,\n    rel: 0,\n    showinfo: 1,\n    start: 0,\n    wmode: 'transparent',\n    theme: 'dark',\n    mute: 0\n  },\n  ratio: '16:9',\n  vimeo: {\n    api: false,\n    autopause: true,\n    autoplay: true,\n    byline: true,\n    callback: null,\n    color: null,\n    height: null,\n    loop: false,\n    maxheight: null,\n    maxwidth: null,\n    player_id: null,\n    portrait: true,\n    title: true,\n    width: null,\n    xhtml: false\n  },\n  youku: {\n    autoplay: 1,\n    show_related: 0\n  },\n  allowFullScreen: true,\n  animationSpeed: 300,\n  classNames: {\n    modalVideoEffect: 'modal-video-effect',\n    modalVideo: 'modal-video',\n    modalVideoClose: 'modal-video-close',\n    modalVideoBody: 'modal-video-body',\n    modalVideoInner: 'modal-video-inner',\n    modalVideoIframeWrap: 'modal-video-movie-wrap',\n    modalVideoCloseBtn: 'modal-video-close-btn'\n  },\n  aria: {\n    openMessage: 'You just opened the modal video',\n    dismissBtnMessage: 'Close the modal by clicking here'\n  }\n};"
  },
  {
    "path": "nodemon.json",
    "content": "{\n    \"execMap\": {\n        \"js\": \"node\",\n        \"jsx\": \"jsx {{filename}} | node\"\n    },\n    \"ext\": \"jsx scss\",\n    \"ignore\": [\n        \"test/dist\",\n        \"node_modules\",\n        \"lib\"\n    ],\n    \"verbose\": true\n}"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-modal-video\",\n  \"version\": \"2.0.2\",\n  \"main\": \"lib/index.js\",\n  \"description\": \"Modal Video Viewer\",\n  \"author\": \"appleple\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"test\": \"eslint ./src/index.jsx --fix\",\n    \"build:js\": \"npm-run-all -p build:lib build:test\",\n    \"build:lib\": \"npm run babel\",\n    \"build:test\": \"browserify ./test/src/index.jsx -t babelify -o ./test/dist/index.js\",\n    \"build:sass\": \"npm-run-all -p sass sass:min\",\n    \"babel\": \"babel src --out-dir lib\",\n    \"sass\": \"sass ./scss/modal-video.scss ./css/modal-video.css --style expanded --no-source-map\",\n    \"sass:min\": \"sass ./scss/modal-video.scss ./css/modal-video.min.css --style compressed --no-source-map\",\n    \"watch:js\": \"onchange \\\"src/\\\" -- npm run build:js\",\n    \"watch:sass\": \"onchange \\\"scss\\\" -- npm run build:sass\",\n    \"watch:test\": \"onchange \\\"test/src\\\" -- npm run build:test\",\n    \"sync\": \"browser-sync start --server './' --files './test/dist/*.js' './css/*.css' --startPath '/test/index.html'\",\n    \"start\": \"npm-run-all -p watch:js watch:sass watch:test sync\",\n    \"deploy\": \"np --no-cleanup\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/appleple/react-modal-video.git\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.17.10\",\n    \"@babel/core\": \"^7.18.5\",\n    \"@babel/preset-env\": \"^7.20.2\",\n    \"@babel/preset-react\": \"^7.18.6\",\n    \"babelify\": \"^10.0.0\",\n    \"browser-sync\": \"^2.27.10\",\n    \"browserify\": \"^17.0.0\",\n    \"eslint\": \"^8.17.0\",\n    \"eslint-config-airbnb\": \"^19.0.4\",\n    \"eslint-config-airbnb-base\": \"^15.0.0\",\n    \"eslint-plugin-import\": \"^2.26.0\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"sass\": \"^1.52.3\",\n    \"onchange\": \"^7.1.0\",\n    \"np\": \"^7.6.1\"\n  },\n  \"dependencies\": {\n    \"core-js\": \"^3.27.2\",\n    \"react-transition-group\": \"^4.4.2\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"^17.0.0 || ^18.2.0\",\n    \"react-dom\": \"^17.0.0 || ^18.2.0\"\n  }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "# react-modal-video\n\nReact Modal Video Component\n\n## Features\n\n- Not affected by dom structure.\n- Beautiful transition\n- Accessible for keyboard navigation and screen readers.\n- Rich options for youtube API and Vimeo API\n\n## Demo\n\n[https://unpkg.com/react-modal-video@latest/test/index.html](https://unpkg.com/react-modal-video@latest/test/index.html)\n\n## Install\n\n### npm\n\n```sh\nnpm install react-modal-video\n```\n\n## Usage\n\nimport sass file to your project\n\n```scss\n@import 'node_modules/react-modal-video/scss/modal-video.scss';\n```\n\n### Functional Implementation with Hooks\n\n```jsx\nimport React, { useState } from 'react';\nimport ReactDOM from 'react-dom';\nimport ModalVideo from 'react-modal-video';\n\nconst App = () => {\n  const [isOpen, setOpen] = useState(false);\n\n  return (\n    <React.Fragment>\n      <ModalVideo\n\t\t\t\tchannel=\"youtube\"\n\t\t\t\tyoutube={{ mute: 0, autoplay: 0 }}\n\t\t\t\tisOpen={isOpen}\n\t\t\t\tvideoId=\"L61p2uyiMSo\"\n\t\t\t\tonClose={() => setOpen(false)} \n\t\t\t/>\n      <button className=\"btn-primary\" onClick={() => setOpen(true)}>\n        VIEW DEMO\n      </button>\n    </React.Fragment>\n  );\n};\n\nReactDOM.render(<App />, document.getElementById('root'));\n```\n\n### Class Implementation\n\nchange \"isOpen\" property to open and close the modal-video\n\n```jsx\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport ModalVideo from 'react-modal-video';\n\nclass App extends React.Component {\n  constructor() {\n    super();\n    this.state = {\n      isOpen: false,\n    };\n    this.openModal = this.openModal.bind(this);\n  }\n\n  openModal() {\n    this.setState({ isOpen: true });\n  }\n\n  render() {\n    return (\n      <React.Fragment>\n        <ModalVideo\n          channel=\"youtube\"\n          isOpen={this.state.isOpen}\n          videoId=\"L61p2uyiMSo\"\n          onClose={() => this.setState({ isOpen: false })}\n        />\n        <button onClick={this.openModal}>Open</button>\n      </React.Fragment>\n    );\n  }\n}\n\nReactDOM.render(<App />, document.getElementById('root'));\n```\n\n## Options\n\n- About YouTube options, please refer to https://developers.google.com/youtube/player_parameters?hl=en\n- About Vimeo options, please refer to https://developer.vimeo.com/apis/oembed\n\n<table style=\"min-width:100%;\">\n\t<tbody><tr>\n\t\t<th colspan=\"2\">properties</th>\n\t\t<th>default</th>\n\t</tr>\n\t<tr>\n\t\t<td colspan=\"2\">channel</td>\n\t\t<td>'youtube'</td>\n\t</tr>\n\t<tr>\n\t\t<td rowspan=\"23\">youtube</td>\n\t\t<td>autoplay</td>\n\t\t<td>1</td>\n\t</tr>\n\t<tr>\n\t\t<td>cc_load_policy</td>\n\t\t<td>1</td>\n\t</tr>\n\t<tr>\n\t\t<td>color</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>controls</td>\n\t\t<td>1</td>\n\t</tr>\n\t<tr>\n\t\t<td>disablekb</td>\n\t\t<td>0</td>\n\t</tr>\n\t<tr>\n\t\t<td>enablejsapi</td>\n\t\t<td>0</td>\n\t</tr>\n\t<tr>\n\t\t<td>end</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>fs</td>\n\t\t<td>1</td>\n\t</tr>\n\t<tr>\n\t\t<td>h1</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>iv_load_policy</td>\n\t\t<td>1</td>\n\t</tr>\n\t<tr>\n\t\t<td>list</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>listType</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>loop</td>\n\t\t<td>0</td>\n\t</tr>\n\t<tr>\n\t\t<td>modestbranding</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>origin</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>playlist</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>playsinline</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>rel</td>\n\t\t<td>0</td>\n\t</tr>\n\t<tr>\n\t\t<td>showinfo</td>\n\t\t<td>1</td>\n\t</tr>\n\t<tr>\n\t\t<td>start</td>\n\t\t<td>0</td>\n\t</tr>\n\t<tr>\n\t\t<td>wmode</td>\n\t\t<td>'transparent'</td>\n\t</tr>\n\t<tr>\n\t\t<td>theme</td>\n\t\t<td>'dark'</td>\n\t</tr>\n\t<tr>\n\t\t<td>mute</td>\n\t\t<td>0</td>\n\t</tr>\n\t<tr>\n\t\t<td rowspan=\"15\">vimeo</td>\n\t\t<td>api</td>\n\t\t<td>false</td>\n\t</tr>\n\t<tr>\n\t\t<td>autopause</td>\n\t\t<td>true</td>\n\t</tr>\n\t<tr>\n\t\t<td>autoplay</td>\n\t\t<td>true</td>\n\t</tr>\n\t<tr>\n\t\t<td>byline</td>\n\t\t<td>true</td>\n\t</tr>\n\t<tr>\n\t\t<td>callback</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>color</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>height</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>loop</td>\n\t\t<td>false</td>\n\t</tr>\n\t<tr>\n\t\t<td>maxheight</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>maxwidth</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>player_id</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>portrait</td>\n\t\t<td>true</td>\n\t</tr>\n\t<tr>\n\t\t<td>title</td>\n\t\t<td>true</td>\n\t</tr>\n\t<tr>\n\t\t<td>width</td>\n\t\t<td>null</td>\n\t</tr>\n\t<tr>\n\t\t<td>xhtml</td>\n\t\t<td>false</td>\n\t</tr>\n\t<tr>\n        <td rowspan=\"2\">youku</td>\n        <td>autoplay</td>\n        <td>1</td>\n    </tr>\n\t<tr>\n        <td>show_related</td>\n        <td>0</td>\n    </tr>\n\t<tr>\n        <td rowspan=\"1\">custom</td>\n        <td>url</td>\n        <td>MP4 URL / iframe URL</td>\n    </tr>\n\t<tr>\n\t\t<td colspan=\"2\">ratio</td>\n\t\t<td>'16:9'</td>\n\t</tr>\n\t<tr>\n\t\t<td colspan=\"2\">allowFullScreen</td>\n\t\t<td>true</td>\n\t</tr>\n\t<tr>\n\t\t<td colspan=\"2\">animationSpeed</td>\n\t\t<td>300</td>\n\t</tr>\n\t<tr>\n\t\t<td rowspan=\"6\">classNames</td>\n\t\t<td>modalVideo</td>\n\t\t<td>'modal-video'</td>\n\t</tr>\n\t<tr>\n\t\t<td>modalVideoClose</td>\n\t\t<td>'modal-video-close'</td>\n\t</tr>\n\t<tr>\n\t\t<td>modalVideoBody</td>\n\t\t<td>'modal-video-body'</td>\n\t</tr>\n\t<tr>\n\t\t<td>modalVideoInner</td>\n\t\t<td>'modal-video-inner'</td>\n\t</tr>\n\t<tr>\n\t\t<td>modalVideoIframeWrap</td>\n\t\t<td>'modal-video-movie-wrap'</td>\n\t</tr>\n\t<tr>\n\t\t<td>modalVideoCloseBtn</td>\n\t\t<td>'modal-video-close-btn'</td>\n\t</tr>\n\t<tr>\n\t\t<td rowspan=\"2\">aria</td>\n\t\t<td>openMessage</td>\n\t\t<td>'You just opened the modal video'</td>\n\t</tr>\n\t<tr>\n\t\t<td>dismissBtnMessage</td>\n\t\t<td>'Close the modal by clicking here'</td>\n\t</tr>\n</tbody></table>\n\n## FAQ\n\n### How to track YouTube videos playing in modal-video by GA4?</h3>\n\n1. Enable JS API. Turn `enablejsapi` property to `1`.\n2. Load YouTube Iframe API. Add `<script src=\"https://www.youtube.com/iframe_api\"></script>` in HTML file.\n\n## Licence\n\n[MIT](https://github.com/appleple/modal-video.js/blob/master/LICENSE)\n"
  },
  {
    "path": "scss/modal-video.scss",
    "content": "$animation-speed: .3s;\n$animation-function: ease-out;\n$backdrop-color: rgba(0, 0, 0, .5);\n\n@keyframes modal-video {\n\tfrom {\n\t\topacity: 0;\n\t}\n\n\tto {\n\t\topacity: 1;\n\t}\n}\n\n@keyframes modal-video-inner {\n\tfrom {\n\t\ttransform: translate(0, 100px);\n\t}\n\n\tto {\n\t\ttransform: translate(0, 0);\n\t}\n}\n\n.modal-video {\n\tposition: fixed;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tbackground-color: $backdrop-color;\n\tz-index: 1000000;\n\tcursor: pointer;\n\topacity: 1;\n\tanimation-timing-function: $animation-function;\n\tanimation-duration: $animation-speed;\n\tanimation-name: modal-video;\n\t-webkit-transition: opacity $animation-speed $animation-function;\n\t-moz-transition: opacity $animation-speed $animation-function;\n\t-ms-transition: opacity $animation-speed $animation-function;\n\t-o-transition: opacity $animation-speed $animation-function;\n\ttransition: opacity $animation-speed $animation-function;\n}\n\n.modal-video-effect-exit {\n\topacity: 0;\n\n\t& .modal-video-movie-wrap {\n\t\t-webkit-transform: translate(0, 100px);\n\t\t-moz-transform: translate(0, 100px);\n\t\t-ms-transform: translate(0, 100px);\n\t\t-o-transform: translate(0, 100px);\n\t\ttransform: translate(0, 100px);\n\t}\n}\n\n.modal-video-body {\n\tmax-width: 960px;\n\twidth: 100%;\n\theight: 100%;\n\tmargin: 0 auto;\n\tpadding: 0 10px;\n    display: flex;\n    justify-content: center;\n\tbox-sizing: border-box;\n}\n\n.modal-video-inner {\n\tdisplay: flex;\n    justify-content: center;\n    align-items: center;\n\twidth: 100%;\n\theight: 100%;\n\n    @media (orientation: landscape) {\n        padding: 10px 60px;\n        box-sizing: border-box;\n    }\n}\n\n.modal-video-movie-wrap {\n\twidth: 100%;\n\theight: 0;\n\tposition: relative;\n\tpadding-bottom: 56.25%;\n\tbackground-color: #333;\n\tanimation-timing-function: $animation-function;\n\tanimation-duration: $animation-speed;\n\tanimation-name: modal-video-inner;\n\t-webkit-transform: translate(0, 0);\n\t-moz-transform: translate(0, 0);\n\t-ms-transform: translate(0, 0);\n\t-o-transform: translate(0, 0);\n\ttransform: translate(0, 0);\n\t-webkit-transition: -webkit-transform $animation-speed $animation-function;\n\t-moz-transition: -moz-transform $animation-speed $animation-function;\n\t-ms-transition: -ms-transform $animation-speed $animation-function;\n\t-o-transition: -o-transform $animation-speed $animation-function;\n\ttransition: transform $animation-speed $animation-function;\n\n\t& iframe {\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t}\n}\n\n.modal-video-close-btn {\n\tposition: absolute;\n\tz-index: 2;\n\ttop: -45px;\n\tright: 0px;\n\tdisplay: inline-block;\n\twidth: 35px;\n\theight: 35px;\n\toverflow: hidden;\n\tborder: none;\n\tbackground: transparent;\n\n    @media (orientation: landscape) {\n        top: 0;\n        right: -45px;\n    }\n\n\t&:before {\n\t\ttransform: rotate(45deg);\n\t}\n\n\t&:after {\n\t\ttransform: rotate(-45deg);\n\t}\n\n\t&:before,\n\t&:after {\n\t\tcontent: '';\n\t\tposition: absolute;\n\t\theight: 2px;\n\t\twidth: 100%;\n\t\ttop: 50%;\n\t\tleft: 0;\n\t\tmargin-top: -1px;\n\t\tbackground: #fff;\n\t\tborder-radius: 5px;\n\t\tmargin-top: -6px;\n\t}\n}\n"
  },
  {
    "path": "src/index.jsx",
    "content": "import React from 'react';\nimport CSSTransition from 'react-transition-group/CSSTransition';\n\nexport default class ModalVideo extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      isOpen: false,\n      modalVideoWidth: '100%'\n    };\n    this.closeModal = this.closeModal.bind(this);\n    this.updateFocus = this.updateFocus.bind(this);\n\n    this.timeout; // used for resizing video.\n  }\n\n  openModal() {\n    this.setState({ isOpen: true });\n  }\n\n  closeModal() {\n    this.setState({ isOpen: false });\n    if (typeof this.props.onClose === 'function') {\n      this.props.onClose();\n    }\n  }\n\n  keydownHandler(e) {\n    if (e.keyCode === 27) {\n      this.closeModal();\n    }\n  }\n\n  componentDidMount() {\n    document.addEventListener('keydown', this.keydownHandler.bind(this));\n    window.addEventListener('resize', this.resizeModalVideoWhenHeightGreaterThanWindowHeight.bind(this));\n    this.setState({\n      modalVideoWidth: this.getWidthFulfillAspectRatio(this.props.ratio, window.innerHeight, window.innerWidth)\n    });\n  }\n\n  componentWillUnmount() {\n    document.removeEventListener('keydown', this.keydownHandler.bind(this));\n    window.removeEventListener('resize', this.resizeModalVideoWhenHeightGreaterThanWindowHeight.bind(this));\n  }\n\n  static getDerivedStateFromProps(props) {\n    return { isOpen: props.isOpen };\n  }\n\n  componentDidUpdate() {\n    if (this.state.isOpen && this.modal) {\n      this.modal.focus();\n    }\n  }\n\n  updateFocus(e) {\n    if (this.state.isOpen) {\n    e.preventDefault();\n    e.stopPropagation();\n\n      if (e.keyCode === 9) {\n        if (this.modal === document.activeElement) {\n          this.modaliflame.focus();\n        }\n        else if (this.modalbtn === document.activeElement) {\n          this.modal.focus(); \n        }\n      }\n    }\n  }\n\n  /**\n   * Resize modal-video-iframe-wrap when window size changed when the height of the video is greater than the height of the window.\n   */\n  resizeModalVideoWhenHeightGreaterThanWindowHeight() {\n    clearTimeout(this.timeout);\n\n    this.timeout = setTimeout(() => {\n      const width = this.getWidthFulfillAspectRatio(this.props.ratio, window.innerHeight, window.innerWidth);\n      if (this.state.modalVideoWidth != width) {\n        this.setState({\n          modalVideoWidth: width\n        });\n      }\n    }, 10);\n  }\n\n  getQueryString(obj) {\n    let url = '';\n    for (const key in obj) {\n      if (obj.hasOwnProperty(key)) {\n        if (obj[key] !== null) {\n          url += `${key}=${obj[key]}&`;\n        }\n      }\n    }\n    return url.substr(0, url.length - 1);\n  }\n\n  getYoutubeUrl(youtube, videoId) {\n    const query = this.getQueryString(youtube);\n    return `//www.youtube.com/embed/${videoId}?${query}`;\n  }\n\n  getVimeoUrl(vimeo, videoId) {\n    const query = this.getQueryString(vimeo);\n    return `//player.vimeo.com/video/${videoId}?${query}`;\n  }\n\n  getYoukuUrl(youku, videoId) {\n    const query = this.getQueryString(youku);\n    return `//player.youku.com/embed/${videoId}?${query}`;\n  }\n\n  getVideoUrl(opt, videoId) {\n    if (opt.channel === 'youtube') {\n      return this.getYoutubeUrl(opt.youtube, videoId);\n    } if (opt.channel === 'vimeo') {\n      return this.getVimeoUrl(opt.vimeo, videoId);\n    } if (opt.channel === 'youku') {\n      return this.getYoukuUrl(opt.youku, videoId);\n    } if (opt.channel === 'custom') {\n      return opt.url;\n    }\n  }\n\n  getPadding(ratio) {\n    const arr = ratio.split(':');\n    const width = Number(arr[0]);\n    const height = Number(arr[1]);\n    const padding = height * 100 / width;\n    return `${padding}%`;\n  }\n\n  /**\n   * Calculate the width of the video fulfill aspect ratio.\n   * When the height of the video is greater than the height of the window,\n   * this function return the width that fulfill the aspect ratio for the height of the window.\n   * In other cases, this function return '100%'(the height relative to the width is determined by css).\n   *\n   * @param string ratio\n   * @param number maxWidth\n   * @returns number | '100%'\n   */\n  getWidthFulfillAspectRatio(ratio, maxHeight, maxWidth) {\n    const arr = ratio.split(':');\n    const width = Number(arr[0]);\n    const height = Number(arr[1]);\n\n    // Height that fulfill the aspect ratio for maxWidth.\n    const videoHeight = maxWidth * (height / width);\n\n    if (maxHeight < videoHeight) {\n      // when the height of the video is greater than the height of the window.\n      // calculate the width that fulfill the aspect ratio for the height of the window.\n\n      // ex: 16:9 aspect ratio\n      // 16:9 = width : height\n      // → width = 16 / 9 * height\n      return Math.floor(width / height * maxHeight);\n    }\n\n    return '100%';\n  }\n\n  render() {\n    const modalVideoInnerStyle = {\n      width: this.state.modalVideoWidth\n    };\n\n    const modalVideoIframeWrapStyle = {\n      paddingBottom: this.getPadding(this.props.ratio)\n    };\n\n    return (\n      <CSSTransition\n        classNames={this.props.classNames.modalVideoEffect}\n        timeout={this.props.animationSpeed}\n      >\n        {() => {\n          if (!this.state.isOpen) {\n            return null;\n          }\n\n          return (\n            <div className={this.props.classNames.modalVideo} tabIndex='-1' role='dialog' area-modal=\"true\"\n              aria-label={this.props.aria.openMessage} onClick={this.closeModal} ref={(node) => {this.modal = node; }} onKeyDown={this.updateFocus}>\n              <div className={this.props.classNames.modalVideoBody}>\n                <div className={this.props.classNames.modalVideoInner} style={modalVideoInnerStyle}>\n                  <div className={this.props.classNames.modalVideoIframeWrap} style={modalVideoIframeWrapStyle}>\n                    {\n                      this.props.children\n                      || <iframe\n                          width='460'\n                          height='230'\n                          src={this.getVideoUrl(this.props, this.props.videoId)}\n                          frameBorder='0'\n                          allow={'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture'}\n                          allowFullScreen={this.props.allowFullScreen}\n                          onKeyDown={this.updateFocus}\n                          ref={(node) => {this.modaliflame = node; }}\n                          tabIndex='-1' />\n                    }\n                    <button\n                      className={this.props.classNames.modalVideoCloseBtn}\n                      aria-label={this.props.aria.dismissBtnMessage}\n                      ref={(node) => { this.modalbtn = node; }}\n                      onKeyDown={this.updateFocus} />\n                  </div>\n                </div>\n              </div>\n            </div>);\n        }}\n      </CSSTransition>\n    );\n  }\n}\n\nModalVideo.defaultProps = {\n  channel: 'youtube',\n  isOpen: false,\n  youtube: {\n    autoplay: 1,\n    cc_load_policy: 1,\n    color: null,\n    controls: 1,\n    disablekb: 0,\n    enablejsapi: 0,\n    end: null,\n    fs: 1,\n    h1: null,\n    iv_load_policy: 1,\n    list: null,\n    listType: null,\n    loop: 0,\n    modestbranding: null,\n    origin: null,\n    playlist: null,\n    playsinline: null,\n    rel: 0,\n    showinfo: 1,\n    start: 0,\n    wmode: 'transparent',\n    theme: 'dark',\n    mute: 0\n  },\n  ratio: '16:9',\n  vimeo: {\n    api: false,\n    autopause: true,\n    autoplay: true,\n    byline: true,\n    callback: null,\n    color: null,\n    height: null,\n    loop: false,\n    maxheight: null,\n    maxwidth: null,\n    player_id: null,\n    portrait: true,\n    title: true,\n    width: null,\n    xhtml: false\n  },\n  youku: {\n    autoplay: 1,\n    show_related: 0\n  },\n  allowFullScreen: true,\n  animationSpeed: 300,\n  classNames: {\n    modalVideoEffect: 'modal-video-effect',\n    modalVideo: 'modal-video',\n    modalVideoClose: 'modal-video-close',\n    modalVideoBody: 'modal-video-body',\n    modalVideoInner: 'modal-video-inner',\n    modalVideoIframeWrap: 'modal-video-movie-wrap',\n    modalVideoCloseBtn: 'modal-video-close-btn'\n  },\n  aria: {\n    openMessage: 'You just opened the modal video',\n    dismissBtnMessage: 'Close the modal by clicking here'\n  }\n};\n"
  },
  {
    "path": "test/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\t<link rel=\"stylesheet\" href=\"../css/modal-video.min.css\">\n  <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n  <title>modal-video.js</title>\n</head>\n<body>\n  <div id=\"root\"></div>\n  <script src=\"./dist/index.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "test/src/index.jsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport ModalVideo from '../../lib/index';\n\nclass App extends React.Component {\n  constructor() {\n    super();\n    this.state = {\n      isOpen: false,\n      isOpenYouku: false,\n      isOpenCustom: false,\n      customUrl: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',\n    };\n    this.openModal = this.openModal.bind(this);\n  }\n\n  openModal() {\n    this.setState({ isOpen: true });\n  }\n\n  render() {\n    return (\n      <React.Fragment>\n        <ModalVideo\n          channel=\"youtube\"\n          isOpen={this.state.isOpen}\n          videoId=\"L61p2uyiMSo\"\n          youtube={{ mute: 0, autoplay: 0 }}\n          onClose={() => this.setState({ isOpen: false })}\n        />\n        <button onClick={this.openModal}>Open YouTube</button>\n\n        <ModalVideo\n          channel=\"vimeo\"\n          isOpen={this.state.isOpenVimeo}\n          videoId=\"336257407\"\n          onClose={() => this.setState({ isOpenVimeo: false })}\n        />\n        <button onClick={() => this.setState({ isOpenVimeo: true })}>Open Vimeo</button>\n\n        <ModalVideo\n          channel=\"youku\"\n          isOpen={this.state.isOpenYouku}\n          videoId=\"XMTczNjgzMDYwNA=\"\n          onClose={() => this.setState({ isOpenYouku: false })}\n        />\n        <button onClick={() => this.setState({ isOpenYouku: true })}>Open youku</button>\n\n        <ModalVideo\n          channel=\"custom\"\n          isOpen={this.state.isOpenCustom}\n          url={this.state.customUrl}\n          onClose={() => this.setState({ isOpenCustom: false })}\n        />\n        <button onClick={() => this.setState({ isOpenCustom: true })}>Open Custom</button>\n      </React.Fragment>\n    );\n  }\n}\n\nReactDOM.render(<App />, document.getElementById('root'));\n"
  }
]