diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json
index 4dd7877..48e054d 100644
--- a/.codesandbox/ci.json
+++ b/.codesandbox/ci.json
@@ -1,3 +1,4 @@
{
- "buildCommand": "compile"
+ "buildCommand": "compile",
+ "sandboxes": ["/example"]
}
diff --git a/.eslintrc b/.eslintrc
index 68ececd..43723a2 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,16 +1,7 @@
{
- "parser": "babel-eslint",
- "extends": ["airbnb", "prettier"],
- "plugins": ["prettier"],
- "rules": {
- "linebreak-style": 0,
- "react/jsx-filename-extension": 0,
- "react/destructuring-assignment": 0,
- "import/no-extraneous-dependencies": 0,
- "prettier/prettier": "error"
- },
+ "extends": ["react-app", "plugin:prettier/recommended", "prettier/react"],
"env": {
"browser": true,
"jest": true
}
-}
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0d56df3..5654869 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
-node_modules
+node_modules/
npm-debug.log
-dist
-es
-.vscode/*
-.cache/*
-build/*
+dist/
+.vscode/
+.cache/
+build/
diff --git a/example/example.js b/example/example.js
deleted file mode 100644
index 1598aee..0000000
--- a/example/example.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import React, { useState } from 'react';
-import ReactDOM from 'react-dom';
-import YouTube from '../src/YouTube';
-
-const videoIdA = 'XxVg_s8xAms';
-const videoIdB = '-DX3vJiqxm4';
-
-function Example() {
- const [videoId, setVideoId] = useState(videoIdA);
- const [player, setPlayer] = useState(null);
-
- const onReady = (event) => {
- // eslint-disable-next-line
- console.log(`YouTube Player object for videoId: "${videoId}" has been saved to state.`);
- setPlayer(event.target);
- };
-
- const onPlayVideo = () => {
- player.playVideo();
- };
-
- const onPauseVideo = () => {
- player.pauseVideo();
- };
-
- const onChangeVideo = () => {
- setVideoId(videoId === videoIdA ? videoIdB : videoIdA);
- };
-
- return (
-
-
-
-
-
-
- );
-}
-
-ReactDOM.render(, document.getElementById('root'));
diff --git a/example/index.html b/example/index.html
index 65a804a..795f7c9 100644
--- a/example/index.html
+++ b/example/index.html
@@ -1,11 +1,13 @@
-
react-youtube example
+
+
-
-
+
+
+
diff --git a/example/package.json b/example/package.json
new file mode 100644
index 0000000..2db28cd
--- /dev/null
+++ b/example/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "react-youtube-example",
+ "version": "1.0.0",
+ "description": "react-youtube example starter project",
+ "main": "index.html",
+ "scripts": {
+ "start": "parcel index.html --open",
+ "build": "parcel build index.html"
+ },
+ "dependencies": {
+ "react": "16.13.1",
+ "react-dom": "16.13.1",
+ "react-youtube": "7.11.2"
+ },
+ "devDependencies": {
+ "@babel/core": "7.2.0",
+ "parcel-bundler": "^1.6.1"
+ },
+ "keywords": [
+ "javascript",
+ "starter"
+ ]
+}
diff --git a/example/src/index.js b/example/src/index.js
new file mode 100644
index 0000000..8e4e34b
--- /dev/null
+++ b/example/src/index.js
@@ -0,0 +1,116 @@
+import React, { Fragment, useState } from 'react';
+import ReactDOM from 'react-dom';
+import YouTube, { useYouTube } from 'react-youtube';
+
+import './styles.css';
+
+const VIDEOS = ['XxVg_s8xAms', '-DX3vJiqxm4'];
+
+function YouTubeHookExample() {
+ const [videoIndex, setVideoIndex] = useState(0);
+ const [width, setWidth] = useState(600);
+ const [hidden, setHidden] = useState(false);
+ const [autoplay, setAutoplay] = useState(false);
+
+ const { targetRef, player } = useYouTube({
+ videoId: VIDEOS[videoIndex],
+ autoplay,
+ width,
+ height: width * (9 / 16),
+ });
+
+ return (
+
+ );
+}
+
+function YouTubeComponentExample() {
+ const [player, setPlayer] = useState(0);
+ const [videoIndex, setVideoIndex] = useState(0);
+ const [width, setWidth] = useState(600);
+ const [hidden, setHidden] = useState(false);
+ const [autoplay, setAutoplay] = useState(false);
+
+ return (
+
+ );
+}
+
+ReactDOM.render(
+
+
+
+ ,
+ document.getElementById('app'),
+);
diff --git a/example/src/styles.css b/example/src/styles.css
new file mode 100644
index 0000000..6402c0e
--- /dev/null
+++ b/example/src/styles.css
@@ -0,0 +1,6 @@
+#app {
+ font-family: sans-serif;
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+}
diff --git a/package.json b/package.json
index 76061ac..fd7c509 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "7.9.0",
"description": "React.js powered YouTube player component",
"main": "dist/index.js",
- "module": "dist/index.esm.js",
+ "module": "dist/index.mjs",
"types": "index.d.ts",
"files": [
"dist",
@@ -41,6 +41,8 @@
"@testing-library/jest-dom": "5.3.0",
"@testing-library/react": "10.0.2",
"@types/youtube": "0.0.38",
+ "@typescript-eslint/eslint-plugin": "2.28.0",
+ "@typescript-eslint/parser": "2.28.0",
"babel-eslint": "10.1.0",
"babel-jest": "25.2.6",
"babel-loader": "8.1.0",
@@ -48,8 +50,9 @@
"cross-env": "7.0.2",
"cz-conventional-changelog": "3.1.0",
"eslint": "6.8.0",
- "eslint-config-airbnb": "18.1.0",
"eslint-config-prettier": "6.10.1",
+ "eslint-config-react-app": "5.2.1",
+ "eslint-plugin-flowtype": "4.7.0",
"eslint-plugin-import": "2.20.2",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-prettier": "3.1.2",
@@ -75,8 +78,8 @@
"scripts": {
"test": "jest",
"test:ci": "jest --ci --runInBand",
- "compile:cjs": "babel src/YouTube.js --out-file dist/index.js",
- "compile:es": "cross-env BABEL_ENV=es babel src/YouTube.js --out-file dist/index.esm.js",
+ "compile:cjs": "babel src --out-dir dist",
+ "compile:es": "cross-env BABEL_ENV=es babel src --out-dir dist --out-file-extension .mjs",
"compile": "npm-run-all --parallel compile:*",
"prepublishOnly": "npm run compile",
"lint": "eslint src example",
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..aac453b
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,19 @@
+import YouTube from './YouTube.js';
+import useYouTube from './useYouTube.js';
+
+export default YouTube;
+export { useYouTube };
+
+/**
+ * Expose PlayerState constants for convenience. These constants can also be
+ * accessed through the global YT object after the YouTube IFrame API is instantiated.
+ * https://developers.google.com/youtube/iframe_api_reference#onStateChange
+ */
+export const PlayerState = {
+ UNSTARTED: -1,
+ ENDED: 0,
+ PLAYING: 1,
+ PAUSED: 2,
+ BUFFERING: 3,
+ CUED: 5,
+};
diff --git a/src/useYouTube.js b/src/useYouTube.js
new file mode 100644
index 0000000..0d54913
--- /dev/null
+++ b/src/useYouTube.js
@@ -0,0 +1,226 @@
+import { useState, useEffect, useRef } from 'react';
+
+function loadScript(url) {
+ return new Promise((resolve, reject) => {
+ const script = Object.assign(document.createElement('script'), {
+ type: 'text/javascript',
+ charset: 'utf8',
+ src: url,
+ async: true,
+ onerror() {
+ reject(new Error(`Failed to load: ${url}`));
+ },
+ onload() {
+ resolve();
+ },
+ });
+
+ document.head.appendChild(script);
+ });
+}
+
+function loadYouTubeIframeApi() {
+ return new Promise((resolve, reject) => {
+ const previous = window.onYouTubeIframeAPIReady;
+ window.onYouTubeIframeAPIReady = () => {
+ if (previous) previous();
+ resolve();
+ };
+
+ const protocol = window.location.protocol === 'http:' ? 'http:' : 'https:';
+ loadScript(`${protocol}//www.youtube.com/iframe_api`).catch(reject);
+ });
+}
+
+function getYouTubeApi() {
+ if (window.YT && window.YT.Player && window.YT.Player instanceof Function) {
+ return window.YT;
+ }
+ return null;
+}
+
+/*
+
+Available options that you can pass to the YouTube Iframe API are
+
+- videoId updated by Player#cueVideoById
+
+- width updated by Player#setSize
+- height updated by Player#setSize
+
+- playerVars
+ - autoplay Player#loadVideoById/Playlist
+ - cc_lang_pref [static]
+ - cc_load_policy [static]
+ - color [static]
+ - controls [static]
+ - disablekb [static]
+ - enablejsapi [static]
+ - end Player#cue/load* should set endSeconds
+ - fs [static]
+ - hl [static]
+ - iv_load_policy [static]
+ - list [static]
+ - listType [static]
+ - loop updated by Player#setLoop
+ - modestbranding [static]
+ - origin [static]
+ - playlist updated by Player#cue/loadPlaylist
+ - playsinline [static]
+ - rel [static]
+ - start Player#cue/load* should set startSeconds
+ - widget_referrer [static]
+
+- events [note]
+ - onReady
+ - onStateChange
+ - onPlaybackQualityChange
+ - onPlaybackRateChange
+ - onError
+ - onApiChange
+
+[note] youtube-player fixes the very strange Player#addEventListener behaviour
+but does this by overwriting the events property so we can't set these immediately.
+
+*/
+
+/*
+
+type Config = {
+ videoId: string,
+
+ autoplay: boolean,
+ startSeconds: number,
+ endSeconds: number,
+
+ width: number,
+ height: number,
+
+ onReady: (event: any) => void,
+ onStateChange: (event: any) => void,
+ onPlaybackQualityChange: (event: any) => void,
+ onPlaybackRateChange: (event: any) => void,
+ onError: (event: any) => void,
+ onApiChange: (event: any) => void,
+};
+
+*/
+
+export default function useYouTube(config, playerVars) {
+ const [YouTubeApi, setYouTubeApi] = useState(getYouTubeApi);
+
+ const [target, setTarget] = useState(null);
+ const [player, setPlayer] = useState(null);
+ const configRef = useRef(config);
+
+ useEffect(() => {
+ configRef.current = config;
+ }, [config]);
+
+ useEffect(() => {
+ if (target === null) return undefined;
+
+ const element = target.appendChild(document.createElement('div'));
+
+ // TODO: use suspense
+ if (YouTubeApi === null) {
+ loadYouTubeIframeApi()
+ .then(() => setYouTubeApi(getYouTubeApi))
+ .catch((error) => {
+ console.error(error);
+ // TODO: throw so it can be handled by an error boundary
+ });
+ return undefined;
+ }
+
+ // NOTE: The YouTube player replaces `element`.
+ // trying to access it after this point results in unexpected behaviour
+ const instance = new YouTubeApi.Player(element, {
+ videoId: configRef.current.videoId,
+ width: configRef.current.width,
+ height: configRef.current.height,
+ playerVars,
+ events: {
+ onReady(event) {
+ setPlayer(instance);
+
+ if (typeof configRef.current.onReady === 'function') {
+ configRef.current.onReady(event);
+ }
+ },
+ onStateChange(event) {
+ if (typeof configRef.current.onStateChange === 'function') {
+ configRef.current.onStateChange(event);
+ }
+ },
+ onPlaybackQualityChange(event) {
+ if (typeof configRef.current.onPlaybackQualityChange === 'function') {
+ configRef.current.onPlaybackQualityChange(event);
+ }
+ },
+ onPlaybackRateChange(event) {
+ if (typeof configRef.current.onPlaybackRateChange === 'function') {
+ configRef.current.onPlaybackRateChange(event);
+ }
+ },
+ onError(event) {
+ if (typeof configRef.current.onError === 'function') {
+ configRef.current.onError(event);
+ }
+ },
+ onApiChange(event) {
+ if (typeof configRef.current.onApiChange === 'function') {
+ configRef.current.onApiChange(event);
+ }
+ },
+ },
+ });
+
+ return () => {
+ instance.getIframe().remove();
+ // TODO: figure out why calling instance.destroy() causes cross origin errors
+ setPlayer(null);
+ };
+ }, [YouTubeApi, target, playerVars]);
+
+ // videoId, autoplay, startSeconds, endSeconds
+ useEffect(() => {
+ if (player === null) return;
+
+ if (!config.videoId) {
+ player.stopVideo();
+ return;
+ }
+
+ if (configRef.current.autoplay) {
+ player.loadVideoById({
+ videoId: config.videoId,
+ startSeconds: configRef.current.startSeconds,
+ endSeconds: configRef.current.endSeconds,
+ });
+ return;
+ }
+
+ player.cueVideoById({
+ videoId: config.videoId,
+ startSeconds: configRef.current.startSeconds,
+ endSeconds: configRef.current.endSeconds,
+ });
+ }, [player, config.videoId]);
+
+ // width, height
+ useEffect(() => {
+ if (player === null) return;
+
+ if (config.width !== undefined && config.height !== undefined) {
+ // calling setSize with width and height set to undefined
+ // makes the player smaller than the default
+ player.setSize(config.width, config.height);
+ }
+ }, [player, config.width, config.height]);
+
+ return {
+ player,
+ targetRef: setTarget,
+ };
+}
diff --git a/src/Youtube.test.js b/tests/Youtube.test.js
similarity index 99%
rename from src/Youtube.test.js
rename to tests/Youtube.test.js
index 2b7969b..d51de8c 100644
--- a/src/Youtube.test.js
+++ b/tests/Youtube.test.js
@@ -1,7 +1,7 @@
import '@testing-library/jest-dom';
import React from 'react';
import { render, queryByAttribute } from '@testing-library/react';
-import YouTube from './YouTube';
+import YouTube from '../src/YouTube';
import Player, { playerMock } from './__mocks__/youtube-player';
diff --git a/src/__mocks__/youtube-player.js b/tests/__mocks__/youtube-player.js
similarity index 100%
rename from src/__mocks__/youtube-player.js
rename to tests/__mocks__/youtube-player.js
diff --git a/yarn.lock b/yarn.lock
index be61878..6812c68 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -66,6 +66,16 @@
lodash "^4.17.13"
source-map "^0.5.0"
+"@babel/generator@^7.9.5":
+ version "7.9.5"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9"
+ integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==
+ dependencies:
+ "@babel/types" "^7.9.5"
+ jsesc "^2.5.1"
+ lodash "^4.17.13"
+ source-map "^0.5.0"
+
"@babel/helper-annotate-as-pure@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee"
@@ -156,6 +166,15 @@
"@babel/template" "^7.8.3"
"@babel/types" "^7.8.3"
+"@babel/helper-function-name@^7.9.5":
+ version "7.9.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c"
+ integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==
+ dependencies:
+ "@babel/helper-get-function-arity" "^7.8.3"
+ "@babel/template" "^7.8.3"
+ "@babel/types" "^7.9.5"
+
"@babel/helper-get-function-arity@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
@@ -257,6 +276,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed"
integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==
+"@babel/helper-validator-identifier@^7.9.5":
+ version "7.9.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80"
+ integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==
+
"@babel/helper-wrap-function@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610"
@@ -862,7 +886,7 @@
"@babel/parser" "^7.8.6"
"@babel/types" "^7.8.6"
-"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0":
+"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0":
version "7.9.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892"
integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w==
@@ -877,7 +901,22 @@
globals "^11.1.0"
lodash "^4.17.13"
-"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0":
+"@babel/traverse@^7.7.0":
+ version "7.9.5"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2"
+ integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==
+ dependencies:
+ "@babel/code-frame" "^7.8.3"
+ "@babel/generator" "^7.9.5"
+ "@babel/helper-function-name" "^7.9.5"
+ "@babel/helper-split-export-declaration" "^7.8.3"
+ "@babel/parser" "^7.9.0"
+ "@babel/types" "^7.9.5"
+ debug "^4.1.0"
+ globals "^11.1.0"
+ lodash "^4.17.13"
+
+"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0":
version "7.9.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5"
integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng==
@@ -886,6 +925,15 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
+"@babel/types@^7.7.0", "@babel/types@^7.9.5":
+ version "7.9.5"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444"
+ integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.9.5"
+ lodash "^4.17.13"
+ to-fast-properties "^2.0.0"
+
"@bcoe/v8-coverage@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@@ -1572,6 +1620,11 @@
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
+"@types/eslint-visitor-keys@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
+ integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
+
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@@ -1600,6 +1653,11 @@
jest-diff "^25.1.0"
pretty-format "^25.1.0"
+"@types/json-schema@^7.0.3":
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
+ integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==
+
"@types/node@>= 8":
version "12.12.31"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.31.tgz#d6b4f9645fee17f11319b508fb1001797425da51"
@@ -1695,6 +1753,49 @@
resolved "https://registry.yarnpkg.com/@types/youtube/-/youtube-0.0.38.tgz#04aa5efa61f4d52e9cf682575a9dfed58f31e8c1"
integrity sha512-rS0nLlnnZIvOfBNT4957rkKRMHjHxutoVhSEzowocYgNiTMVBmN+Hbkf/L3TeGMMtts9uKZ9gw7O2JLHREVnIw==
+"@typescript-eslint/eslint-plugin@2.28.0":
+ version "2.28.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.28.0.tgz#4431bc6d3af41903e5255770703d4e55a0ccbdec"
+ integrity sha512-w0Ugcq2iatloEabQP56BRWJowliXUP5Wv6f9fKzjJmDW81hOTBxRoJ4LoEOxRpz9gcY51Libytd2ba3yLmSOfg==
+ dependencies:
+ "@typescript-eslint/experimental-utils" "2.28.0"
+ functional-red-black-tree "^1.0.1"
+ regexpp "^3.0.0"
+ tsutils "^3.17.1"
+
+"@typescript-eslint/experimental-utils@2.28.0":
+ version "2.28.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.28.0.tgz#1fd0961cd8ef6522687b4c562647da6e71f8833d"
+ integrity sha512-4SL9OWjvFbHumM/Zh/ZeEjUFxrYKtdCi7At4GyKTbQlrj1HcphIDXlje4Uu4cY+qzszR5NdVin4CCm6AXCjd6w==
+ dependencies:
+ "@types/json-schema" "^7.0.3"
+ "@typescript-eslint/typescript-estree" "2.28.0"
+ eslint-scope "^5.0.0"
+ eslint-utils "^2.0.0"
+
+"@typescript-eslint/parser@2.28.0":
+ version "2.28.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.28.0.tgz#bb761286efd2b0714761cab9d0ee5847cf080385"
+ integrity sha512-RqPybRDquui9d+K86lL7iPqH6Dfp9461oyqvlXMNtap+PyqYbkY5dB7LawQjDzot99fqzvS0ZLZdfe+1Bt3Jgw==
+ dependencies:
+ "@types/eslint-visitor-keys" "^1.0.0"
+ "@typescript-eslint/experimental-utils" "2.28.0"
+ "@typescript-eslint/typescript-estree" "2.28.0"
+ eslint-visitor-keys "^1.1.0"
+
+"@typescript-eslint/typescript-estree@2.28.0":
+ version "2.28.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.28.0.tgz#d34949099ff81092c36dc275b6a1ea580729ba00"
+ integrity sha512-HDr8MP9wfwkiuqzRVkuM3BeDrOC4cKbO5a6BymZBHUt5y/2pL0BXD6I/C/ceq2IZoHWhcASk+5/zo+dwgu9V8Q==
+ dependencies:
+ debug "^4.1.1"
+ eslint-visitor-keys "^1.1.0"
+ glob "^7.1.6"
+ is-glob "^4.0.1"
+ lodash "^4.17.15"
+ semver "^6.3.0"
+ tsutils "^3.17.1"
+
JSONStream@^1.0.4, JSONStream@^1.3.4, JSONStream@^1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
@@ -2207,6 +2308,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+base64-js@^1.0.2:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
+ integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
+
base@^0.11.1:
version "0.11.2"
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
@@ -2352,7 +2458,7 @@ browser-resolve@^1.11.3:
dependencies:
resolve "1.1.7"
-browserify-aes@^1.0.0:
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
version "1.2.0"
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
@@ -2373,6 +2479,16 @@ browserify-cipher@^1.0.0:
browserify-des "^1.0.0"
evp_bytestokey "^1.0.0"
+browserify-des@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
+ integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==
+ dependencies:
+ cipher-base "^1.0.1"
+ des.js "^1.0.0"
+ inherits "^2.0.1"
+ safe-buffer "^5.1.2"
+
browserify-rsa@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
@@ -3441,7 +3557,7 @@ csso@^4.0.2:
dependencies:
css-tree "1.0.0-alpha.39"
-cssom@^0.3.4, cssom@~0.3.6:
+cssom@0.3.x, cssom@^0.3.4, cssom@~0.3.6:
version "0.3.8"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
@@ -3684,6 +3800,14 @@ deprecation@^2.0.0, deprecation@^2.3.1:
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
+des.js@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
+ integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==
+ dependencies:
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
@@ -4072,24 +4196,6 @@ escodegen@~1.9.0:
optionalDependencies:
source-map "~0.6.1"
-eslint-config-airbnb-base@^14.1.0:
- version "14.1.0"
- resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.1.0.tgz#2ba4592dd6843258221d9bff2b6831bd77c874e4"
- integrity sha512-+XCcfGyCnbzOnktDVhwsCAx+9DmrzEmuwxyHUJpw+kqBVT744OUBrB09khgFKlK1lshVww6qXGsYPZpavoNjJw==
- dependencies:
- confusing-browser-globals "^1.0.9"
- object.assign "^4.1.0"
- object.entries "^1.1.1"
-
-eslint-config-airbnb@18.1.0:
- version "18.1.0"
- resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.1.0.tgz#724d7e93dadd2169492ff5363c5aaa779e01257d"
- integrity sha512-kZFuQC/MPnH7KJp6v95xsLBf63G/w7YqdPfQ0MUanxQ7zcKUNG8j+sSY860g3NwCBOa62apw16J6pRN+AOgXzw==
- dependencies:
- eslint-config-airbnb-base "^14.1.0"
- object.assign "^4.1.0"
- object.entries "^1.1.1"
-
eslint-config-prettier@6.10.1:
version "6.10.1"
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.10.1.tgz#129ef9ec575d5ddc0e269667bf09defcd898642a"
@@ -4097,6 +4203,13 @@ eslint-config-prettier@6.10.1:
dependencies:
get-stdin "^6.0.0"
+eslint-config-react-app@5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz#698bf7aeee27f0cea0139eaef261c7bf7dd623df"
+ integrity sha512-pGIZ8t0mFLcV+6ZirRgYK6RVqUIKRIi9MmgzUEmrIknsn3AdO0I32asO86dJgloHq+9ZPl8UIg8mYrvgP5u2wQ==
+ dependencies:
+ confusing-browser-globals "^1.0.9"
+
eslint-import-resolver-node@^0.3.2:
version "0.3.3"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404"
@@ -4113,6 +4226,13 @@ eslint-module-utils@^2.4.1:
debug "^2.6.9"
pkg-dir "^2.0.0"
+eslint-plugin-flowtype@4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.7.0.tgz#903a6ea3eb5cbf4c7ba7fa73cc43fc39ab7e4a70"
+ integrity sha512-M+hxhSCk5QBEValO5/UqrS4UunT+MgplIJK5wA1sCtXjzBcZkpTGRwxmLHhGpbHcrmQecgt6ZL/KDdXWqGB7VA==
+ dependencies:
+ lodash "^4.17.15"
+
eslint-plugin-import@2.20.2:
version "2.20.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz#91fc3807ce08be4837141272c8b99073906e588d"
@@ -4191,6 +4311,13 @@ eslint-utils@^1.4.3:
dependencies:
eslint-visitor-keys "^1.1.0"
+eslint-utils@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd"
+ integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==
+ dependencies:
+ eslint-visitor-keys "^1.1.0"
+
eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
@@ -5373,6 +5500,11 @@ icss-replace-symbols@1.1.0, icss-replace-symbols@^1.1.0:
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
+ieee754@^1.1.4:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+ integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+
iferr@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
@@ -9595,6 +9727,11 @@ regexpp@^2.0.1:
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
+regexpp@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
+ integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
+
regexpu-core@^4.6.0, regexpu-core@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938"
@@ -10378,6 +10515,11 @@ split@^1.0.0:
dependencies:
through "2"
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
@@ -11019,11 +11161,18 @@ trim-off-newlines@^1.0.0:
resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3"
integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM=
-tslib@^1.9.0:
+tslib@^1.8.1, tslib@^1.9.0:
version "1.11.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==
+tsutils@^3.17.1:
+ version "3.17.1"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
+ integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
+ dependencies:
+ tslib "^1.8.1"
+
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@@ -11036,7 +11185,7 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
-tweetnacl@~0.14.0:
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=