aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vnext/package.json1
-rw-r--r--vnext/src/App.js115
-rw-r--r--vnext/src/index.css4
-rw-r--r--vnext/src/ui/Feeds.js137
-rw-r--r--vnext/src/ui/Header.js134
-rw-r--r--vnext/yarn.lock207
6 files changed, 404 insertions, 194 deletions
diff --git a/vnext/package.json b/vnext/package.json
index 3f77fdf8..695ec898 100644
--- a/vnext/package.json
+++ b/vnext/package.json
@@ -86,6 +86,7 @@
"react-cookies": "^0.1.1",
"react-dom": "16.11.0",
"react-router-dom": "^5.1.2",
+ "react-use": "^12.9.1",
"react-use-form-state": "^0.11.0",
"regenerator-runtime": "^0.13.3",
"svg4everybody": "^2.1.9",
diff --git a/vnext/src/App.js b/vnext/src/App.js
index f39875c1..011e5cbd 100644
--- a/vnext/src/App.js
+++ b/vnext/src/App.js
@@ -1,5 +1,6 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useRef } from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
+import { useScroll, useRafState } from 'react-use';
import qs from 'qs';
import svg4everybody from 'svg4everybody';
@@ -10,18 +11,23 @@ import { Friends, Readers } from './ui/Users';
import Settings from './ui/Settings';
import Contacts from './ui/Contacts';
import Chat from './ui/Chat';
+import Header from './ui/Header';
import Post from './ui/Post';
import Thread from './ui/Thread';
import Login from './ui/Login';
-import { UserLink } from './ui/UserInfo';
-import SearchBox from './ui/SearchBox';
import cookie from 'react-cookies';
import { me } from './api';
+const elClassHidden = 'header--hidden';
+
+const elClassFull = 'content--full';
+
export default function App() {
+ let contentRef = useRef(null);
+
useEffect(() => {
svg4everybody();
}, []);
@@ -49,6 +55,48 @@ export default function App() {
});
};
+ const [scrollState, setScrollState] = useRafState({
+ hidden: false,
+ bottom: false,
+ prevScroll: 0
+ });
+
+ let { x, y } = useScroll(contentRef);
+
+ useEffect(() => {
+ let dHeight = contentRef.current.scrollHeight;
+ let wHeight = contentRef.current.clientHeight;
+ setScrollState((scrollState) => {
+ let wScrollDiff = scrollState.prevScroll - y;
+ let hidden = scrollState.hidden;
+ let bottom = scrollState.bottom;
+ if (y <= 0) {
+ // scrolled to the very top; element sticks to the top
+ hidden = false;
+ bottom = false;
+ } else if ((wScrollDiff > 0) && hidden) {
+ // scrolled up; element slides in
+ hidden = false;
+ bottom = false;
+ } else if (wScrollDiff < 0) {
+ // scrolled down
+ if ((y + wHeight) >= dHeight && hidden) {
+ // scrolled to the very bottom; element slides in
+ hidden = false;
+ bottom = true;
+ } else {
+ // scrolled down; element slides out
+ hidden = true;
+ bottom = false;
+ }
+ }
+ return {
+ hidden: hidden,
+ bottom: bottom,
+ prevScroll: y
+ };
+ });
+ }, [x, y, setScrollState]);
const [hash, setHash] = useState(cookie.load('hash'));
const [eventSource, setEventSource] = useState({});
@@ -111,66 +159,9 @@ export default function App() {
return (
<Router>
<>
- <div id="header">
- <div id="header_wrapper">
- {
- visitor.uid < 0 ?
- <>
- <div id="logo"><a href="/" /></div>
- <nav id="global">
- <a href="/">Loading...</a>
- </nav>
- </>
- : visitor.uid > 0 ?
- <UserLink user={visitor} />
- : <div id="logo">
- <Link to="/">Juick</Link>
- </div>
- }
- {
- visitor.uid >= 0 &&
- <>
- <div id="search" className="desktop">
- <SearchBox pathname="/discover" onSearch={search} />
- </div>
- <nav id="global">
- {visitor.uid > 0 ?
- <Link to={{ pathname: '/' }}>
- <Icon name="ei-bell" size="s" /><span className="desktop">Discuss</span>
- {
- visitor.unreadCount &&
- <span className="badge">{visitor.unreadCount}</span>
- }
- </Link>
- :
- <Link to='/?media=1' rel="nofollow">
- <Icon name="ei-camera" size="s" />
- <span className="desktop">Photos</span>
- </Link>
- }
- <Link to={{ pathname: '/discover' }} rel="nofollow">
- <Icon name="ei-search" size="s" />
- <span className="desktop">Discover</span>
- </Link>
-
- {visitor.uid > 0 ?
- <Link to={{ pathname: '/post' }}>
- <Icon name="ei-pencil" size="s" />
- <span className="desktop">Post</span>
- </Link>
- :
- <Link to={{ pathname: '/login', state: { retpath: window.location.pathname } }}>
- <Icon name="ei-user" size="s" />
- <span className="desktop">Login</span>
- </Link>
- }
- </nav>
- </>
- }
- </div>
- </div>
+ <Header visitor={visitor} className={scrollState.hidden ? elClassHidden : ''} />
<div id="wrapper">
- <section id="content">
+ <section id="content" ref={contentRef} className={scrollState.hidden || scrollState.bottom ? elClassFull : ''}>
<Switch>
<Route exact path="/" render={(props) => <Discussions visitor={visitor} {...props} />} />
<Route exact path="/home" render={(props) => <Home visitor={visitor} {...props} />} />
diff --git a/vnext/src/index.css b/vnext/src/index.css
index a371ae55..109eb678 100644
--- a/vnext/src/index.css
+++ b/vnext/src/index.css
@@ -167,6 +167,10 @@ hr {
overflow: auto;
}
+.content--full {
+ margin-top: 0 !important;
+}
+
#footer {
display: none;
background: var(--background-color);
diff --git a/vnext/src/ui/Feeds.js b/vnext/src/ui/Feeds.js
index 8c79f779..e687f1e2 100644
--- a/vnext/src/ui/Feeds.js
+++ b/vnext/src/ui/Feeds.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import qs from 'qs';
@@ -23,9 +23,9 @@ import { getMessages } from '../api';
* @property {import('history').History} history
* @property {import('history').Location} location
* @property {import('react-router').match} match
- * @property {string} search
+ * @property {string=} search
* @property {import('../api').SecureUser} visitor
- * @property {import('../api').Message[]} msgs
+ * @property {import('../api').Message[]=} msgs
*/
/**
@@ -101,84 +101,95 @@ export function Home(props) {
}
/**
- * @param {{
- authRequired?: boolean,
- visitor: import('../api').SecureUser,
- history: import('history').History,
- location: import('history').Location,
- msgs: import('../api').Message[],
- query: Query
-}} props
+ * @typedef {Object} FeedState
+ * @property authRequired?: boolean
+ * @property visitor: import('../api').SecureUser
+ * @property history: import('history').History
+ * @property location: import('history').Location
+ * @property msgs: import('../api').Message[]
+ * @property query: Query
+ */
+
+/**
+ * @param {FeedState} props
*/
function Feed(props) {
- const [msgs, setMsgs] = useState([]);
- const [loading, setLoading] = useState(true);
- const [nextpage, setNextpage] = useState(null);
- const [error, setError] = useState(false);
+ const [state, setState] = useState({
+ history: props.history,
+ authRequired: props.authRequired,
+ query: props.query,
+ hash: props.visitor.hash,
+ filter: props.location.search.substring(1),
+ msgs: [],
+ loading: true,
+ nextpage: null,
+ error: false,
+ tag: ''
+ });
+
+ const stateRef = useRef(state);
useEffect(() => {
- let loadMessages = (hash = '', filter = '') => {
- document.body.scrollTop = 0;
- document.documentElement.scrollTop = 0;
- setMsgs([]);
- setLoading(true);
- const filterParams = qs.parse(filter);
- let params = Object.assign({}, filterParams || {}, props.query.search || {});
- let url = props.query.baseUrl;
- if (hash) {
- params.hash = hash;
- }
- if (!params.hash && props.authRequired) {
- props.history.push('/');
- }
- getMessages(url, params)
- .then(response => {
- const { data } = response;
- const { pageParam } = props.query;
- const lastMessage = data.slice(-1)[0] || {};
- const nextpage = getPageParam(pageParam, lastMessage, filterParams);
- setMsgs(data);
- setLoading(false);
- setNextpage(nextpage);
- }).catch(ex => {
- setError(true);
- });
+ let getPageParam = (pageParam, lastMessage, filterParams) => {
+ const pageValue = pageParam === 'before_mid' ? lastMessage.mid : pageParam === 'page' ? (Number(filterParams.page) || 0) + 1 : moment.utc(lastMessage.updated).valueOf();
+ let newFilter = { ...filterParams };
+ newFilter[pageParam] = pageValue;
+ return `?${qs.stringify(newFilter)}`;
};
- loadMessages(props.visitor.hash, props.location.search.substring(1));
- }, [props]);
-
- let getPageParam = (pageParam, lastMessage, filterParams) => {
- const pageValue = pageParam === 'before_mid' ? lastMessage.mid : pageParam === 'page' ? (Number(filterParams.page) || 0) + 1 : moment.utc(lastMessage.updated).valueOf();
- let newFilter = { ...filterParams };
- newFilter[pageParam] = pageValue;
- return `?${qs.stringify(newFilter)}`;
- };
- const { tag } = qs.parse(location.search.substring(1)) || {};
- const nodes = (
- <>
+ document.body.scrollTop = 0;
+ document.documentElement.scrollTop = 0;
+ const filterParams = qs.parse(stateRef.current.filter);
+ let params = Object.assign({}, filterParams || {}, stateRef.current.query.search || {});
+ let url = stateRef.current.query.baseUrl;
+ if (stateRef.current.hash) {
+ params.hash = stateRef.current.hash;
+ }
+ if (!params.hash && stateRef.current.authRequired) {
+ stateRef.current.history.push('/');
+ }
+ getMessages(url, params)
+ .then(response => {
+ const { data } = response;
+ const { pageParam } = stateRef.current.query;
+ const lastMessage = data.slice(-1)[0] || {};
+ const nextpage = getPageParam(pageParam, lastMessage, filterParams);
+ setState({
+ ...stateRef.current,
+ msgs: data,
+ loading: false,
+ nextpage: nextpage,
+ tag: qs.parse(location.search.substring(1))['tag'] || ''
+ });
+ }).catch(ex => {
+ setState({
+ ...stateRef.current,
+ error: true
+ });
+ });
+ }, []);
+ return (state.msgs.length > 0 ? (
+ <div className="msgs">
{
- tag && (
+ state.tag && (
<p className="page">
- <Link to={{ pathname: `/tag/${tag}` }}>
- <span>← All posts with tag&nbsp;</span><b>{tag}</b>
+ <Link to={{ pathname: `/tag/${state.tag}` }}>
+ <span>← All posts with tag&nbsp;</span><b>{state.tag}</b>
</Link>
</p>
)
}
{
- msgs.map(msg =>
+ state.msgs.map(msg =>
<Message key={msg.mid} data={msg} visitor={props.visitor} />)
}
{
- msgs.length >= 20 && (
+ state.msgs.length >= 20 && (
<p className="page">
- <Link to={{ pathname: props.location.pathname, search: nextpage }} rel="prev">Next →</Link>
+ <Link to={{ pathname: props.location.pathname, search: state.nextpage }} rel="prev">Next →</Link>
</p>
)
}
- </>
+ </div>
+ ) : state.error ? <div>error</div> : state.loading ? <div className="msgs"><Spinner /><Spinner /><Spinner /><Spinner /></div> : <div>No more messages</div>
);
- return msgs.length > 0 ? (
- <div className="msgs">{nodes}</div>
- ) : error ? <div>error</div> : loading ? <div className="msgs"><Spinner /><Spinner /><Spinner /><Spinner /></div> : <div>No more messages</div>;
}
diff --git a/vnext/src/ui/Header.js b/vnext/src/ui/Header.js
index 2d042bfe..a7663dd3 100644
--- a/vnext/src/ui/Header.js
+++ b/vnext/src/ui/Header.js
@@ -1,73 +1,71 @@
-import React, { useEffect, useCallback, useRef } from 'react';
-import ReactDOM from 'react-dom';
-import PropTypes from 'prop-types';
+import React, { memo } from 'react';
+import { Link, withRouter } from 'react-router-dom';
-const elClassHidden = 'header--hidden';
+import Icon from './Icon';
+import { UserLink } from './UserInfo';
+import SearchBox from './SearchBox';
-const header = document.getElementById('header');
+function Header({ visitor, search, className }) {
+ return (
+ <div id="header" className={className}>
+ <div id="header_wrapper">
+ {
+ visitor.uid < 0 ?
+ <>
+ <div id="logo"><a href="/" /></div>
+ <nav id="global">
+ <a href="/">Loading...</a>
+ </nav>
+ </>
+ : visitor.uid > 0 ?
+ <UserLink user={visitor} />
+ : <div id="logo">
+ <Link to="/">Juick</Link>
+ </div>
+ }
+ {
+ visitor.uid >= 0 &&
+ <>
+ <div id="search" className="desktop">
+ <SearchBox pathname="/discover" onSearch={search} />
+ </div>
+ <nav id="global">
+ {visitor.uid > 0 ?
+ <Link to={{ pathname: '/' }}>
+ <Icon name="ei-bell" size="s" /><span className="desktop">Discuss</span>
+ {
+ visitor.unreadCount &&
+ <span className="badge">{visitor.unreadCount}</span>
+ }
+ </Link>
+ :
+ <Link to='/?media=1' rel="nofollow">
+ <Icon name="ei-camera" size="s" />
+ <span className="desktop">Photos</span>
+ </Link>
+ }
+ <Link to={{ pathname: '/discover' }} rel="nofollow">
+ <Icon name="ei-search" size="s" />
+ <span className="desktop">Discover</span>
+ </Link>
-export default function Header({ children }) {
- let dHeight = useRef(0);
- let wHeight = useRef(0);
- let wScrollCurrent = useRef(0);
- let wScrollBefore = useRef(0);
- let wScrollDiff = useRef(0);
-
- /**
- * @param {number} delay
- * @param {{ (): void; apply?: any; }} fn
- */
- let throttle = (delay, fn) => {
- var last, deferTimer;
- return function () {
- var context = this, args = arguments, now = +new Date;
- if (last && now < last + delay) {
- clearTimeout(deferTimer);
- deferTimer = setTimeout(
- function () {
- last = now;
- fn.apply(context, args);
- },
- delay);
- } else {
- last = now;
- fn.apply(context, args);
- }
- };
- };
- let updateHeader = useCallback(() => {
- dHeight.current = document.body.offsetHeight;
- wHeight.current = window.innerHeight;
- wScrollCurrent.current = window.pageYOffset;
- wScrollDiff.current = wScrollBefore.current - wScrollCurrent.current;
-
- if (wScrollCurrent.current <= 0) {
- // scrolled to the very top; element sticks to the top
- header.classList.remove(elClassHidden);
- } else if (wScrollDiff.current > 0 && header.classList.contains(elClassHidden)) {
- // scrolled up; element slides in
- header.classList.remove(elClassHidden);
- } else if (wScrollDiff.current < 0) {
- // scrolled down
- if (wScrollCurrent.current + wHeight.current >= dHeight.current && header.classList.contains(elClassHidden)) {
- // scrolled to the very bottom; element slides in
- header.classList.remove(elClassHidden);
- } else {
- // scrolled down; element slides out
- header.classList.add(elClassHidden);
- }
- }
- wScrollBefore.current = wScrollCurrent.current;
- }, []);
-
- useEffect(() => {
- window.addEventListener('scroll', () => (!window.requestAnimationFrame)
- ? throttle(250, updateHeader)
- : window.requestAnimationFrame(updateHeader), false);
- }, [updateHeader]);
- return ReactDOM.createPortal(children, header);
+ {visitor.uid > 0 ?
+ <Link to={{ pathname: '/post' }}>
+ <Icon name="ei-pencil" size="s" />
+ <span className="desktop">Post</span>
+ </Link>
+ :
+ <Link to={{ pathname: '/login', state: { retpath: window.location.pathname } }}>
+ <Icon name="ei-user" size="s" />
+ <span className="desktop">Login</span>
+ </Link>
+ }
+ </nav>
+ </>
+ }
+ </div>
+ </div>
+ );
}
-Header.propTypes = {
- children: PropTypes.node
-};
+export default memo(withRouter(Header));
diff --git a/vnext/yarn.lock b/vnext/yarn.lock
index 4146d201..1f7d460d 100644
--- a/vnext/yarn.lock
+++ b/vnext/yarn.lock
@@ -1135,11 +1135,31 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.2.tgz#a5ccec6abb6060d5f20d256fb03ed743e9774999"
integrity sha512-gojym4tX0FWeV2gsW4Xmzo5wxGjXGm550oVUII7f7G5o4BV6c7DBdiG1RRQd+y1bvqRyYtPfMK85UM95vsapqQ==
+"@types/prop-types@*":
+ version "15.7.3"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
+ integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
+
"@types/q@^1.5.1":
version "1.5.2"
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
+"@types/react-wait@^0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@types/react-wait/-/react-wait-0.3.0.tgz#6f7ef17571a17e72c7864ede8cf7d3aa525a005e"
+ integrity sha512-5jIfDcHRjqeE7QfZG7kCqOpfrPSvOM1E3/nlKuJ/NZrG/WrhLo/AFr0i72jhTWzyNRo4ex0pshBaiCHksZXH3A==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react@*":
+ version "16.9.11"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.11.tgz#70e0b7ad79058a7842f25ccf2999807076ada120"
+ integrity sha512-UBT4GZ3PokTXSWmdgC/GeCGEJXE5ofWyibCcecRLUVN2ZBpXQGVgQGtG2foS7CrTKFKlQVVswLvf7Js6XA/CVQ==
+ dependencies:
+ "@types/prop-types" "*"
+ csstype "^2.2.0"
+
"@types/stack-utils@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
@@ -1873,6 +1893,11 @@ boolbase@^1.0.0, boolbase@~1.0.0:
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
+bowser@^1.7.3:
+ version "1.9.4"
+ resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a"
+ integrity sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==
+
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -2540,6 +2565,13 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+copy-to-clipboard@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.2.0.tgz#d2724a3ccbfed89706fac8a894872c979ac74467"
+ integrity sha512-eOZERzvCmxS8HWzugj4Uxl8OJxa7T2k1Gi0X5qavwydHIfuSHq2dTD09LOg/XyGq4Zpb5IsR/2OJ5lbOegz78w==
+ dependencies:
+ toggle-selection "^1.0.6"
+
core-js-compat@^3.1.1:
version "3.1.4"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.1.4.tgz#e4d0c40fbd01e65b1d457980fe4112d4358a7408"
@@ -2661,6 +2693,14 @@ css-has-pseudo@^0.10.0:
postcss "^7.0.6"
postcss-selector-parser "^5.0.0-rc.4"
+css-in-js-utils@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz#3b472b398787291b47cfe3e44fecfdd9e914ba99"
+ integrity sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==
+ dependencies:
+ hyphenate-style-name "^1.0.2"
+ isobject "^3.0.1"
+
css-loader@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.2.0.tgz#bb570d89c194f763627fcf1f80059c6832d009b2"
@@ -2727,6 +2767,14 @@ css-tree@1.0.0-alpha.29:
mdn-data "~1.1.0"
source-map "^0.5.3"
+css-tree@^1.0.0-alpha.28:
+ version "1.0.0-alpha.37"
+ resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
+ integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==
+ dependencies:
+ mdn-data "2.0.4"
+ source-map "^0.6.1"
+
css-unit-converter@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996"
@@ -2844,6 +2892,11 @@ cssstyle@^1.0.0:
dependencies:
cssom "~0.3.6"
+csstype@^2.2.0, csstype@^2.5.5:
+ version "2.6.7"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.7.tgz#20b0024c20b6718f4eda3853a1f5a1cce7f5e4a5"
+ integrity sha512-9Mcn9sFbGBAdmimWb2gLVDtFJzeKtDGIr76TUqmjZrw9LFXBMSU70lcs+C0/7fyCd6iBDqmksUcCOUIkisPHsQ==
+
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -3285,6 +3338,13 @@ error-overlay-webpack-plugin@^0.4.1:
sockjs-client "^1.4.0"
url "^0.11.0"
+error-stack-parser@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.4.tgz#a757397dc5d9de973ac9a5d7d4e8ade7cfae9101"
+ integrity sha512-fZ0KkoxSjLFmhW5lHbUT3tLwy3nX1qEzMYo8koY1vrsAco53CMT1djnBSeC/wUjTEZRhZl9iRw7PaMaxfJ4wzQ==
+ dependencies:
+ stackframe "^1.1.0"
+
es-abstract@^1.11.0, es-abstract@^1.12.0, es-abstract@^1.5.1, es-abstract@^1.7.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9"
@@ -3725,6 +3785,11 @@ fast-levenshtein@~2.0.4:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+fastest-stable-stringify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-1.0.1.tgz#9122d406d4c9d98bea644a6b6853d5874b87b028"
+ integrity sha1-kSLUBtTJ2YvqZEpraFPVh0uHsCg=
+
fastparse@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
@@ -4531,6 +4596,11 @@ https-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
+hyphenate-style-name@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz#097bb7fa0b8f1a9cf0bd5c734cf95899981a9b48"
+ integrity sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==
+
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -4673,6 +4743,14 @@ ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+inline-style-prefixer@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-4.0.2.tgz#d390957d26f281255fe101da863158ac6eb60911"
+ integrity sha512-N8nVhwfYga9MiV9jWlwfdj1UDIaZlBFu4cJSJkIr7tZX7sHpHhGR5su1qdpW+7KPL8ISTvCIkcaFi/JdBknvPg==
+ dependencies:
+ bowser "^1.7.3"
+ css-in-js-utils "^2.0.0"
+
inquirer@6.5.0, inquirer@^6.4.1:
version "6.5.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42"
@@ -5953,6 +6031,11 @@ mdast-util-compact@^1.0.0:
dependencies:
unist-util-visit "^1.1.0"
+mdn-data@2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"
+ integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==
+
mdn-data@~1.1.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01"
@@ -6259,6 +6342,20 @@ nan@^2.12.1:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+nano-css@^5.1.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.2.0.tgz#1d794db644139665e68ffaeba1ec6d7c66fc620e"
+ integrity sha512-DrkBUciWkEvrWZUIyhjQkyqiF1x2bnB4FWZZ9FCYSz1Okcq5fUs6P2e46UaHYcdljaUkQbK0aS0h1I2zObCTBg==
+ dependencies:
+ css-tree "^1.0.0-alpha.28"
+ csstype "^2.5.5"
+ fastest-stable-stringify "^1.0.1"
+ inline-style-prefixer "^4.0.0"
+ rtl-css-js "^1.9.0"
+ sourcemap-codec "^1.4.1"
+ stacktrace-js "^2.0.0"
+ stylis "3.5.0"
+
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@@ -8002,6 +8099,11 @@ react-error-overlay@^6.0.1:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.1.tgz#b8d3cf9bb991c02883225c48044cb3ee20413e0f"
integrity sha512-V9yoTr6MeZXPPd4nV/05eCBvGH9cGzc52FN8fs0O0TVQ3HYYf1n7EgZVtHbldRq5xU9zEzoXIITjYNIfxDDdUw==
+react-fast-compare@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
+ integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
+
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
@@ -8056,6 +8158,28 @@ react-use-form-state@^0.11.0:
resolved "https://registry.yarnpkg.com/react-use-form-state/-/react-use-form-state-0.11.0.tgz#dbc6ec89fc868a74c6ab1954f9f0132c3294f9ac"
integrity sha512-EEqZh03ffCGN8p0Edda9SW+TYyG4foxbd3ZFhBZ/f67Lhnezd/Q0Gc0ROM6/3CTUPxC5EtBOzn/HiU29mhbV9A==
+react-use@^12.9.1:
+ version "12.9.1"
+ resolved "https://registry.yarnpkg.com/react-use/-/react-use-12.9.1.tgz#56b745a72ecec816d13f6c44c0d8c3038ec4525d"
+ integrity sha512-BTOifl9wUMKtCdWRe5IKQP7kIwj7XXWLRqpmG03GPK+lG86vTLYehMVeL/F+NJ/XoxwI229jJhCwKbFSot1hNQ==
+ dependencies:
+ "@types/react-wait" "^0.3.0"
+ copy-to-clipboard "^3.1.0"
+ nano-css "^5.1.0"
+ react-fast-compare "^2.0.4"
+ react-wait "^0.3.0"
+ resize-observer-polyfill "^1.5.1"
+ screenfull "^5.0.0"
+ set-harmonic-interval "^1.0.1"
+ throttle-debounce "^2.0.1"
+ ts-easing "^0.2.0"
+ tslib "^1.10.0"
+
+react-wait@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/react-wait/-/react-wait-0.3.0.tgz#0cdd4d919012451a5bc3ab0a16d00c6fd9a8c10b"
+ integrity sha512-kB5x/kMKWcn0uVr9gBdNz21/oGbQwEQnF3P9p6E9yLfJ9DRcKS0fagbgYMFI0YFOoyKDj+2q6Rwax0kTYJF37g==
+
react@16.11.0:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.11.0.tgz#d294545fe62299ccee83363599bf904e4a07fdbb"
@@ -8372,6 +8496,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+resize-observer-polyfill@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
+ integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
+
resolve-cwd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
@@ -8479,6 +8608,13 @@ rsvp@^4.8.4:
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
+rtl-css-js@^1.9.0:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.13.1.tgz#80deabf6e8f36d6767d495cd3eb60fecb20c67e1"
+ integrity sha512-jgkIDj6Xi25kAEm5oYM3ZMFiOQhpLEcXi2LY/6bVr91cVz73hciHKneL5AMVPxOcks/JuizSaaNsvNRkeAWe3w==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+
run-async@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
@@ -8583,6 +8719,11 @@ schema-utils@^2.2.0:
ajv "^6.10.2"
ajv-keywords "^3.4.1"
+screenfull@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.0.tgz#5c2010c0e84fd4157bf852877698f90b8cbe96f6"
+ integrity sha512-yShzhaIoE9OtOhWVyBBffA6V98CDCoyHTsp8228blmqYy1Z5bddzE/4FPiJKlr8DVR4VBiiUyfPzIQPIYDkeMA==
+
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -8667,6 +8808,11 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+set-harmonic-interval@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249"
+ integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==
+
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -8866,6 +9012,11 @@ source-map-url@^0.4.0:
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+source-map@0.5.6:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+ integrity sha1-dc449SvwczxafwwRjYEzSiu19BI=
+
source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@@ -8876,6 +9027,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+sourcemap-codec@^1.4.1:
+ version "1.4.6"
+ resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9"
+ integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==
+
spdx-correct@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
@@ -8969,11 +9125,40 @@ stable@^0.1.8:
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+stack-generator@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.4.tgz#027513eab2b195bbb43b9c8360ba2dd0ab54de09"
+ integrity sha512-ha1gosTNcgxwzo9uKTQ8zZ49aUp5FIUW58YHFxCqaAHtE0XqBg0chGFYA1MfmW//x1KWq3F4G7Ug7bJh4RiRtg==
+ dependencies:
+ stackframe "^1.1.0"
+
stack-utils@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8"
integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==
+stackframe@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.1.0.tgz#e3fc2eb912259479c9822f7d1f1ff365bd5cbc83"
+ integrity sha512-Vx6W1Yvy+AM1R/ckVwcHQHV147pTPBKWCRLrXMuPrFVfvBUc3os7PR1QLIWCMhPpRg5eX9ojzbQIMLGBwyLjqg==
+
+stacktrace-gps@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.3.tgz#b89f84cc13bb925b96607e737b617c8715facf57"
+ integrity sha512-51Rr7dXkyFUKNmhY/vqZWK+EvdsfFSRiQVtgHTFlAdNIYaDD7bVh21yBHXaNWAvTD+w+QSjxHg7/v6Tz4veExA==
+ dependencies:
+ source-map "0.5.6"
+ stackframe "^1.1.0"
+
+stacktrace-js@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.1.tgz#ebdb0e9a16e6f171f96ca7878404e7f15c3d42ba"
+ integrity sha512-13oDNgBSeWtdGa4/2BycNyKqe+VktCoJ8VLx4pDoJkwGGJVtiHdfMOAj3aW9xTi8oR2v34z9IcvfCvT6XNdNAw==
+ dependencies:
+ error-stack-parser "^2.0.4"
+ stack-generator "^2.0.4"
+ stacktrace-gps "^3.0.3"
+
state-toggle@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.2.tgz#75e93a61944116b4959d665c8db2d243631d6ddc"
@@ -9235,6 +9420,11 @@ stylelint@^11.1.1:
table "^5.2.3"
v8-compile-cache "^2.1.0"
+stylis@3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.0.tgz#016fa239663d77f868fef5b67cf201c4b7c701e1"
+ integrity sha512-pP7yXN6dwMzAR29Q0mBrabPCe0/mNO1MSr93bhay+hcZondvMMTpeGyd8nbhYJdyperNT2DRxONQuUGcJr5iPw==
+
sugarss@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d"
@@ -9368,6 +9558,11 @@ throat@^4.0.0:
resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=
+throttle-debounce@^2.0.1:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.1.0.tgz#257e648f0a56bd9e54fe0f132c4ab8611df4e1d5"
+ integrity sha512-AOvyNahXQuU7NN+VVvOOX+uW6FPaWdAOdRP5HfwYxAfCzXTFKRMoIMk+n+po318+ktcChx+F1Dd91G3YHeMKyg==
+
through2@^2.0.0:
version "2.0.5"
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
@@ -9462,6 +9657,11 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"
+toggle-selection@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32"
+ integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI=
+
toidentifier@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
@@ -9520,7 +9720,12 @@ trough@^1.0.0:
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.4.tgz#3b52b1f13924f460c3fbfd0df69b587dbcbc762e"
integrity sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==
-tslib@^1.9.0:
+ts-easing@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec"
+ integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==
+
+tslib@^1.10.0, tslib@^1.9.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==