diff options
author | Vitaly Takmazov | 2019-10-29 17:11:07 +0300 |
---|---|---|
committer | Vitaly Takmazov | 2023-01-13 10:37:55 +0300 |
commit | 522a1cdbaf0f478fb23a9f770b9caf732ea13803 (patch) | |
tree | 2baf7497f4c4717ee423c227e2ba24a22b44c27c | |
parent | 713566a435fea6c00cbd2e37d7c8c2a54ef2895d (diff) |
Hide header on scroll (mobile only)
-rw-r--r-- | vnext/package.json | 1 | ||||
-rw-r--r-- | vnext/src/App.js | 115 | ||||
-rw-r--r-- | vnext/src/index.css | 4 | ||||
-rw-r--r-- | vnext/src/ui/Feeds.js | 137 | ||||
-rw-r--r-- | vnext/src/ui/Header.js | 134 | ||||
-rw-r--r-- | vnext/yarn.lock | 207 |
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 </span><b>{tag}</b> + <Link to={{ pathname: `/tag/${state.tag}` }}> + <span>← All posts with tag </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== |