From e871ff39f1eebdb36e1da940f20908e7b834b824 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Wed, 2 Oct 2019 15:57:53 +0300 Subject: [PATCH 001/442] New ModalDialog component --- src/common/ModalDialog/ModalDialog.js | 36 +++++++++++++ src/common/ModalDialog/index.js | 3 ++ src/common/ModalDialog/styles.less | 57 ++++++++++++++++++++ src/common/index.js | 2 + storybook/stories/ModalDialog/ModalDialog.js | 56 +++++++++++++++++++ storybook/stories/ModalDialog/index.js | 2 + storybook/stories/ModalDialog/styles.less | 40 ++++++++++++++ storybook/stories/index.js | 1 + 8 files changed, 197 insertions(+) create mode 100644 src/common/ModalDialog/ModalDialog.js create mode 100644 src/common/ModalDialog/index.js create mode 100644 src/common/ModalDialog/styles.less create mode 100644 storybook/stories/ModalDialog/ModalDialog.js create mode 100644 storybook/stories/ModalDialog/index.js create mode 100644 storybook/stories/ModalDialog/styles.less diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js new file mode 100644 index 000000000..386cc505f --- /dev/null +++ b/src/common/ModalDialog/ModalDialog.js @@ -0,0 +1,36 @@ +const React = require('react'); +const PropTypes = require('prop-types'); +const classnames = require('classnames'); +const Button = require('stremio/common/Button'); +const Icon = require('stremio-icons/dom'); +const styles = require('./styles'); + +const ModalDialog = ({className, children, title, buttons, onClose}) => { + return ( +
+ +

{title}

+
+ {children} +
+
+ {buttons ? buttons.map((button, key) => ( + + )) : null} +
+
+ ) +}; + +module.exports = ModalDialog; \ No newline at end of file diff --git a/src/common/ModalDialog/index.js b/src/common/ModalDialog/index.js new file mode 100644 index 000000000..7dadbbd9e --- /dev/null +++ b/src/common/ModalDialog/index.js @@ -0,0 +1,3 @@ +const ModalDialog = require('./ModalDialog'); + +module.exports = ModalDialog; \ No newline at end of file diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less new file mode 100644 index 000000000..7c1b9e4de --- /dev/null +++ b/src/common/ModalDialog/styles.less @@ -0,0 +1,57 @@ +.modal-dialog-container { + position: relative; + padding: 1rem; + background-color: var(--color-surfacelighter); + margin: auto; + + * { + overflow: visible; + } + + .x-icon { + position: absolute; + top: 1rem; + right: 1rem; + width: 1rem; + height: 1rem; + fill: var(--color-surfacedark); + } + + h1 { + font-size: 1.2rem; + } + + .modal-dialog-content { + margin: 1rem auto 0 auto; + } + + .modal-dialog-buttons { + margin: -.5rem; + margin-top: 1rem; + display: flex; + flex-flow: row; + } + + .button { + display: flex; + align-items: center; + justify-content: center; + flex: 1 0 0; + text-align: center; + color: var(--color-surfacelighter); + background-color: var(--color-signal5); + padding: 1rem; + margin: .5rem; + + &:hover { + background-color: var(--color-signal580); + } + + .icon { + fill: var(--color-surfacelighter); + width: 1rem; + height: 1rem; + margin-right: .5rem; + } + } +} \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index 5771413e0..944e565e1 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -9,6 +9,7 @@ const MetaPreview = require('./MetaPreview'); const MetaPreviewPlaceholder = require('./MetaPreviewPlaceholder'); const MetaRow = require('./MetaRow'); const MetaRowPlaceholder = require('./MetaRowPlaceholder'); +const ModalDialog = require('./ModalDialog'); const NavBar = require('./NavBar'); const PlayIconCircleCentered = require('./PlayIconCircleCentered'); const Popup = require('./Popup'); @@ -34,6 +35,7 @@ module.exports = { MetaPreviewPlaceholder, MetaRow, MetaRowPlaceholder, + ModalDialog, NavBar, PlayIconCircleCentered, Popup, diff --git a/storybook/stories/ModalDialog/ModalDialog.js b/storybook/stories/ModalDialog/ModalDialog.js new file mode 100644 index 000000000..9cef96c61 --- /dev/null +++ b/storybook/stories/ModalDialog/ModalDialog.js @@ -0,0 +1,56 @@ + +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { ModalDialog } = require('stremio/common'); +const Icon = require('stremio-icons/dom'); +const ColorPicker = require('stremio/common/ColorPicker'); +const styles = require('./styles'); + +storiesOf('ModalDialog', module).add('ModalDialog', () => { + const oneButton = [ + { + label: 'Show many buttons', icon: 'ic_ellipsis', props: { + onClick: React.useCallback(()=>setButtons(manyButtons)) + } + }, + ] + const manyButtons = [ + { + label: 'One', icon: 'ic_back_ios', props: { + onClick: React.useCallback(()=>setButtons(oneButton)) + } + }, + { + label: 'A button with a long name', props: { + onClick: action('A button with a long name clicked.') + } + }, + { + label: ( + + + {'A button with a long name, icon and custom class'} + + ), props: { + className: styles['custom-button'], + onClick: action('A button with a long name and icon clicked') + } + }, + {} + ]; + const [buttons, setButtons] = React.useState(oneButton); + return ( + +
+
+ +
+
+

Some text here

+

Lorem ipsum dolor sit amet

+
+
+
+ ); +}); \ No newline at end of file diff --git a/storybook/stories/ModalDialog/index.js b/storybook/stories/ModalDialog/index.js new file mode 100644 index 000000000..0e5c21118 --- /dev/null +++ b/storybook/stories/ModalDialog/index.js @@ -0,0 +1,2 @@ + +require('./ModalDialog'); \ No newline at end of file diff --git a/storybook/stories/ModalDialog/styles.less b/storybook/stories/ModalDialog/styles.less new file mode 100644 index 000000000..fcb6d41cb --- /dev/null +++ b/storybook/stories/ModalDialog/styles.less @@ -0,0 +1,40 @@ +.modal-dialog { + width: 45rem; + .content-container { + display: flex; + flex-flow: row; + margin: 0 -0.5rem; + + .content-column { + flex: 1 0 0; + padding: 0 0.5rem; + } + } + + .custom-button { + display: flex; + align-items: center; + justify-content: center; + flex: 1 0 0; + text-align: center; + color: var(--color-surfacelighter); + background-color: var(--color-signal3); + padding: 1rem; + margin: 0.5rem; + + &:hover { + background-color: var(--color-signal380); + color: var(--color-backgrounddarker); + + .icon { + fill: var(--color-backgrounddarker); + } + } + + .icon { + fill: var(--color-surfacelighter); + width: 1rem; + height: 1rem; + } + } +} diff --git a/storybook/stories/index.js b/storybook/stories/index.js index a15267d5f..8660eb557 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -1,3 +1,4 @@ require('./Addon'); require('./MetaItem'); require('./ColorPicker'); +require('./ModalDialog'); From c35394289c4c26840eaabb0be93baa64ecfb0779 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Wed, 2 Oct 2019 15:59:40 +0300 Subject: [PATCH 002/442] Custom icon style --- storybook/stories/ModalDialog/styles.less | 1 + 1 file changed, 1 insertion(+) diff --git a/storybook/stories/ModalDialog/styles.less b/storybook/stories/ModalDialog/styles.less index fcb6d41cb..c4a429370 100644 --- a/storybook/stories/ModalDialog/styles.less +++ b/storybook/stories/ModalDialog/styles.less @@ -35,6 +35,7 @@ fill: var(--color-surfacelighter); width: 1rem; height: 1rem; + margin-right: 0.5rem; } } } From 2b83812327cca0e6b376c6402188b4a35bdec8b4 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Wed, 2 Oct 2019 16:13:36 +0300 Subject: [PATCH 003/442] callback dependencies --- storybook/stories/ModalDialog/ModalDialog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storybook/stories/ModalDialog/ModalDialog.js b/storybook/stories/ModalDialog/ModalDialog.js index 9cef96c61..e3440b6c1 100644 --- a/storybook/stories/ModalDialog/ModalDialog.js +++ b/storybook/stories/ModalDialog/ModalDialog.js @@ -11,14 +11,14 @@ storiesOf('ModalDialog', module).add('ModalDialog', () => { const oneButton = [ { label: 'Show many buttons', icon: 'ic_ellipsis', props: { - onClick: React.useCallback(()=>setButtons(manyButtons)) + onClick: React.useCallback(()=>setButtons(manyButtons), []) } }, ] const manyButtons = [ { label: 'One', icon: 'ic_back_ios', props: { - onClick: React.useCallback(()=>setButtons(oneButton)) + onClick: React.useCallback(()=>setButtons(oneButton), []) } }, { From 6167e86bea07f9dd0b243578a8f5eccb32cda67b Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Wed, 2 Oct 2019 16:13:48 +0300 Subject: [PATCH 004/442] PropTypes --- src/common/ModalDialog/ModalDialog.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 386cc505f..f91279827 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -16,7 +16,7 @@ const ModalDialog = ({className, children, title, buttons, onClose}) => { {children}
- {buttons ? buttons.map((button, key) => ( + {Array.isArray(buttons) && buttons.length ? buttons.map((button, key) => (
); + } else if (input.type === 'info') { + return ( +
+
{input.header} {preferences[input.id]}
+
+ ); } })} From 0a41977641fc58d30e34c79dd47ef803d0d214a2 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Fri, 4 Oct 2019 18:16:49 +0300 Subject: [PATCH 011/442] Load/store data from state container --- src/routes/Settings/useSettings.js | 82 ++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/src/routes/Settings/useSettings.js b/src/routes/Settings/useSettings.js index bca76cb46..847f99a6c 100644 --- a/src/routes/Settings/useSettings.js +++ b/src/routes/Settings/useSettings.js @@ -1,22 +1,64 @@ const React = require('react'); +const { useServices } = require('stremio/services'); + +module.exports = (devTestWithUser) => { + const { core } = useServices(); + // TODO: move these values in the state container + const [settings, setSettings] = React.useState({}); + /* + { + 'user': devTestWithUser ? { + '_id': 'neo', + 'email': 'neo@example.com', + 'avatar': 'https://www.thenational.ae/image/policy:1.891803:1566372420/AC17-Matrix-20-04.jpg', + } : null, + 'ui_language': "eng", + 'subtitles_language': 'bul', + 'subtitles_size': '100%', + 'subtitles_background': '', + 'subtitles_color': '#ffffff', + 'subtitles_outline_color': '#000', + 'auto-play_next_episode': 'true', + 'pause_playback_when_minimized': 'false', + 'hardware-accelerated_decoding': 'true', + 'launch_player_in_a_separate_window_(advanced)': 'true', + 'caching': '2048', + 'torrent_profile': 'profile-default', + 'streaming_server_is_available.': 'true', + }); + */ + + React.useEffect(() => { + const onNewState = () => { + const state = core.getState(); + try { + setSettings({ ...settings, ...state.ctx.content.settings }); + } catch (e) { } + }; + window.top.core = core; + core.on('NewModel', onNewState); + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogGrouped', + args: { extra: [] } + } + }); + return () => { + // Destructor function + core.off('NewModel', onNewState); + }; + }, []); + + const setTheSettings = React.useCallback(newSettings => { + const { user, ...args } = { ...newSettings }; + console.log('Save', args); + if(args.language === "bul") throw new Error('why') + Object.keys(args).forEach(key=> args[key] = args[key].toString()) + setSettings(newSettings); + core.dispatch({ action: 'Settings', args: { settings: 'Store', args } }); + }, [settings]) + + return [settings, setTheSettings]; +}; -module.exports = (devTestWithUser) => React.useState({ - "user": devTestWithUser ? { - "_id": "neo", - "email": "neo@example.com", - "avatar": "https://www.thenational.ae/image/policy:1.891803:1566372420/AC17-Matrix-20-04.jpg?f=16x9&w=1200&$p$f$w=5867e40", - } : null, - "ui_language": "eng", - "default_subtitles_language": "bul", - "default_subtitles_size": "100%", - "subtitles_background": "", - "subtitles_color": "#ffffff", - "subtitles_outline_color": "#000", - "auto-play_next_episode": true, - "pause_playback_when_minimized": false, - "hardware-accelerated_decoding": true, - "launch_player_in_a_separate_window_(advanced)": true, - "caching": "2048", - "torrent_profile": "profile-default", - "streaming_server_is_available.": true, -}); \ No newline at end of file From 19dcbc648004584c6327786183e6d697cb977115 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Mon, 7 Oct 2019 12:39:45 +0300 Subject: [PATCH 012/442] Handle properly the state container --- src/routes/Settings/useSettings.js | 73 ++++++++++++++---------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/src/routes/Settings/useSettings.js b/src/routes/Settings/useSettings.js index 847f99a6c..c8346039a 100644 --- a/src/routes/Settings/useSettings.js +++ b/src/routes/Settings/useSettings.js @@ -2,48 +2,41 @@ const React = require('react'); const { useServices } = require('stremio/services'); module.exports = (devTestWithUser) => { + const IGNORED_SETTINGS = Object.freeze(['user']); + const { core } = useServices(); - // TODO: move these values in the state container const [settings, setSettings] = React.useState({}); - /* - { - 'user': devTestWithUser ? { - '_id': 'neo', - 'email': 'neo@example.com', - 'avatar': 'https://www.thenational.ae/image/policy:1.891803:1566372420/AC17-Matrix-20-04.jpg', - } : null, - 'ui_language': "eng", - 'subtitles_language': 'bul', - 'subtitles_size': '100%', - 'subtitles_background': '', - 'subtitles_color': '#ffffff', - 'subtitles_outline_color': '#000', - 'auto-play_next_episode': 'true', - 'pause_playback_when_minimized': 'false', - 'hardware-accelerated_decoding': 'true', - 'launch_player_in_a_separate_window_(advanced)': 'true', - 'caching': '2048', - 'torrent_profile': 'profile-default', - 'streaming_server_is_available.': 'true', - }); - */ React.useEffect(() => { - const onNewState = () => { - const state = core.getState(); + const updateState = (state) => { try { - setSettings({ ...settings, ...state.ctx.content.settings }); - } catch (e) { } - }; - window.top.core = core; - core.on('NewModel', onNewState); - core.dispatch({ - action: 'Load', - args: { - load: 'CatalogGrouped', - args: { extra: [] } + setSettings({ + ...settings, ...state.ctx.content.settings, user: devTestWithUser ? { + '_id': 'neo', + 'email': 'neo@example.com', + 'avatar': 'https://www.thenational.ae/image/policy:1.891803:1566372420/AC17-Matrix-20-04.jpg', + } : state.ctx.content.auth && state.ctx.content.auth.user + }); + } catch (e) { + console.log('Cannot update settings state', e); } - }); + } + + const state = core.getState(); + try { + if (state.ctx.is_loaded) { + updateState(state); + return; + } + } catch (e) { + console.log('Cannot find state context', e); + } + + const onNewState = () => { + updateState(core.getState()); + }; + core.on('NewModel', onNewState); + core.dispatch({ action: 'LoadCtx' }); return () => { // Destructor function core.off('NewModel', onNewState); @@ -51,10 +44,10 @@ module.exports = (devTestWithUser) => { }, []); const setTheSettings = React.useCallback(newSettings => { - const { user, ...args } = { ...newSettings }; - console.log('Save', args); - if(args.language === "bul") throw new Error('why') - Object.keys(args).forEach(key=> args[key] = args[key].toString()) + const args = {}; + Object.keys(newSettings) + .filter(prop => !IGNORED_SETTINGS.includes(prop)) + .forEach(key => args[key] = newSettings[key].toString()) setSettings(newSettings); core.dispatch({ action: 'Settings', args: { settings: 'Store', args } }); }, [settings]) From d16c9adcf6b571107b523513b1272e2717d25063 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Mon, 7 Oct 2019 12:40:10 +0300 Subject: [PATCH 013/442] Use the user from the state container if available --- src/routes/Settings/Settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 4884722dd..f805076b5 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -6,7 +6,7 @@ const SectionsList = require('./SectionsList'); const { settingsSections } = require('./constants'); const useSettings = require('./useSettings'); -const devTestWithUser = true; +const devTestWithUser = false; const Settings = () => { const [preferences, setPreferences] = useSettings(devTestWithUser); From 61598f0e8fcd5d1193f362a1d4d2c56a1c2f970f Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Mon, 7 Oct 2019 16:16:55 +0300 Subject: [PATCH 014/442] Fetch settings options from the streaming server --- src/routes/Settings/Settings.js | 51 ++++++++++++++++++++++++++++++-- src/routes/Settings/constants.js | 5 +--- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index f805076b5..a9d2cbb5b 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -10,15 +10,60 @@ const devTestWithUser = false; const Settings = () => { const [preferences, setPreferences] = useSettings(devTestWithUser); - const sections = React.useMemo(()=>Object.keys(settingsSections) + const [dynamicSections, setDynamicSections] = React.useState(settingsSections); + // TODO: The Streaming section should be handled separately + const sections = React.useMemo(()=>Object.keys(dynamicSections) .map((section) => ({ id: section, - inputs: settingsSections[section], + inputs: dynamicSections[section], ref: React.createRef() - })), []); + })), [dynamicSections]); + const [selectedSectionId, setSelectedSectionId] = React.useState(sections[0].id); const scrollContainerRef = React.useRef(null); + React.useEffect(() => { + const shouldFetch = preferences.server_url && preferences.server_url.length > 0 + ? + Promise.resolve(preferences.server_url + 'settings') + : + Promise.reject(); + + shouldFetch + .then(fetch) + .then(response => response.json()) + .then(serverPrefs => serverPrefs.options + .map(opt => ({ + id: opt.id, + label: opt.label, + header: opt.label, + type: opt.type, + options: opt.selections.map(sel => ({ label: sel.name, value: JSON.stringify(sel.val) })) + })) + .concat({ + id: 'torrent_profile', + label: 'Torrent Profile', + header: 'Torrent Profile', + type: 'select', + options: [{ 'label': 'Default', 'value': 'profile-default' }, { 'label': 'Soft', 'value': 'profile-soft' }, { 'label': 'Fast', 'value': 'profile-fast' }], + }) + ) + .catch(() => []).then(serverInputs => { + const additionalServerSettings = [ + { 'id': 'server_url', 'header': 'Streaming server URL:', 'type': 'info' }, + { 'id': 'streaming_server_is_available.', 'label': 'Streaming server is ' + (serverInputs.length !== 0 ? '' : 'not ') + 'available.', 'type': 'static-text', 'icon': serverInputs.length !== 0 ? 'ic_check' : 'ic_x' } + ]; + setDynamicSections({ + ...dynamicSections, + Streaming: [ + ...dynamicSections.Streaming, + ...serverInputs, + ...additionalServerSettings + ] + }); + }); + }, [preferences.server_url]); + ///////////////// const updatePreference = (option, value) => { diff --git a/src/routes/Settings/constants.js b/src/routes/Settings/constants.js index e94d481cf..e709b5dbf 100644 --- a/src/routes/Settings/constants.js +++ b/src/routes/Settings/constants.js @@ -2,6 +2,7 @@ const settingsSections = { 'General': [ { 'id': 'user', 'type': 'user' }, { 'id': 'language', 'header': 'UI Language', 'label': 'UI Language', 'type': 'select', 'options': [{ 'label': 'Български език', 'value': 'bul' }, { 'label': 'English', 'value': 'eng' }, { 'label': 'Deutsch', 'value': 'ger' }, { 'label': 'Español', 'value': 'esp' }, { 'label': 'Italiano', 'value': 'ita' }] }, + { 'id': 'show_vid_overview', 'label': 'Show videos overview', 'type': 'checkbox' }, ], 'Player': [ { 'id': 'add-ons', 'label': 'ADD-ONS', 'type': 'button', 'icon': 'ic_addons', 'href': '#/addons' }, @@ -16,10 +17,6 @@ const settingsSections = { { 'id': 'use_external_player', 'label': 'Launch player in a separate window (advanced)', 'type': 'checkbox' }, ], 'Streaming': [ - { 'id': 'caching', 'header': 'Caching', 'label': 'Caching', 'type': 'select', 'options': [{ 'label': 'No Caching', 'value': '' }, { 'label': '2GB', 'value': '2048' }, { 'label': '5GB', 'value': '5120' }, { 'label': '10GB', 'value': '10240' }] }, - { 'header': 'Torrent Profile', 'label': 'Torrent Profile', 'type': 'select', 'options': [{ 'label': 'Default', 'value': 'profile-default' }, { 'label': 'Soft', 'value': 'profile-soft' }, { 'label': 'Fast', 'value': 'profile-fast' }], 'id': 'torrent_profile' }, - { 'id': 'server_url', 'header': 'Streaming server URL:', 'type': 'info' }, - { 'id': 'streaming_server_is_available.', 'label': 'Streaming server is available.', 'type': 'static-text', 'icon': 'ic_check' } ] }; From 05bbf3e721a9cb841e06f2d137e726f65b7a08ce Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Mon, 7 Oct 2019 16:44:56 +0300 Subject: [PATCH 015/442] Formatting --- src/routes/Settings/Settings.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index a9d2cbb5b..480bb8157 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -45,13 +45,17 @@ const Settings = () => { label: 'Torrent Profile', header: 'Torrent Profile', type: 'select', - options: [{ 'label': 'Default', 'value': 'profile-default' }, { 'label': 'Soft', 'value': 'profile-soft' }, { 'label': 'Fast', 'value': 'profile-fast' }], + options: [ + { label: 'Default', value: 'profile-default' }, + { label: 'Soft', value: 'profile-soft' }, + { label: 'Fast', value: 'profile-fast' } + ], }) ) .catch(() => []).then(serverInputs => { const additionalServerSettings = [ - { 'id': 'server_url', 'header': 'Streaming server URL:', 'type': 'info' }, - { 'id': 'streaming_server_is_available.', 'label': 'Streaming server is ' + (serverInputs.length !== 0 ? '' : 'not ') + 'available.', 'type': 'static-text', 'icon': serverInputs.length !== 0 ? 'ic_check' : 'ic_x' } + { id: 'server_url', header: 'Streaming server URL:', type: 'info' }, + { id: 'streaming_server_is_available.', label: 'Streaming server is ' + (serverInputs.length !== 0 ? '' : 'not ') + 'available.', type: 'static-text', icon: serverInputs.length !== 0 ? 'ic_check' : 'ic_x' } ]; setDynamicSections({ ...dynamicSections, From c1c7bb50dec55edbfecd58e6991d803ac205458d Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Wed, 9 Oct 2019 13:10:39 +0300 Subject: [PATCH 016/442] Drop dynamic streaming server settings --- src/routes/Settings/Settings.js | 27 ++------------------------- src/routes/Settings/constants.js | 2 ++ 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 480bb8157..bfb5cdfe8 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -6,10 +6,8 @@ const SectionsList = require('./SectionsList'); const { settingsSections } = require('./constants'); const useSettings = require('./useSettings'); -const devTestWithUser = false; - const Settings = () => { - const [preferences, setPreferences] = useSettings(devTestWithUser); + const [preferences, setPreferences] = useSettings(); const [dynamicSections, setDynamicSections] = React.useState(settingsSections); // TODO: The Streaming section should be handled separately const sections = React.useMemo(()=>Object.keys(dynamicSections) @@ -31,27 +29,7 @@ const Settings = () => { shouldFetch .then(fetch) - .then(response => response.json()) - .then(serverPrefs => serverPrefs.options - .map(opt => ({ - id: opt.id, - label: opt.label, - header: opt.label, - type: opt.type, - options: opt.selections.map(sel => ({ label: sel.name, value: JSON.stringify(sel.val) })) - })) - .concat({ - id: 'torrent_profile', - label: 'Torrent Profile', - header: 'Torrent Profile', - type: 'select', - options: [ - { label: 'Default', value: 'profile-default' }, - { label: 'Soft', value: 'profile-soft' }, - { label: 'Fast', value: 'profile-fast' } - ], - }) - ) + .then(() => ['OK']) .catch(() => []).then(serverInputs => { const additionalServerSettings = [ { id: 'server_url', header: 'Streaming server URL:', type: 'info' }, @@ -61,7 +39,6 @@ const Settings = () => { ...dynamicSections, Streaming: [ ...dynamicSections.Streaming, - ...serverInputs, ...additionalServerSettings ] }); diff --git a/src/routes/Settings/constants.js b/src/routes/Settings/constants.js index e709b5dbf..493f51e17 100644 --- a/src/routes/Settings/constants.js +++ b/src/routes/Settings/constants.js @@ -17,6 +17,8 @@ const settingsSections = { { 'id': 'use_external_player', 'label': 'Launch player in a separate window (advanced)', 'type': 'checkbox' }, ], 'Streaming': [ + { "id": "cacheSize", "label": "Caching", "header": "Caching", "type": "select", "options": [{ "label": "no caching", "value": "0" }, { "label": "2GB", "value": "2147483648" }, { "label": "5GB", "value": "5368709120" }, { "label": "10GB", "value": "10737418240" }, { "label": "∞", "value": "null" }] }, + { "id": "torrent_profile", "label": "Torrent Profile", "header": "Torrent Profile", "type": "select", "options": [{ "label": "Default", "value": "profile-default" }, { "label": "Soft", "value": "profile-soft" }, { "label": "Fast", "value": "profile-fast" }] } ] }; From d31a07c4990f94dbdc9e58d52f254e307f208d88 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Wed, 9 Oct 2019 13:11:42 +0300 Subject: [PATCH 017/442] Load core context on boot; Drop development test user data --- src/App/App.js | 3 +++ src/routes/Settings/useSettings.js | 39 +++++++++--------------------- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/App/App.js b/src/App/App.js index ffb33d4af..81778d1e7 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -22,6 +22,9 @@ const App = () => { }; const onCoreStateChanged = () => { setCoreInitialized(services.core.active || services.core.error instanceof Error); + if (services.core.active) { + services.core.dispatch({ action: 'LoadCtx' }); + } }; services.shell.on('stateChanged', onShellStateChanged); services.core.on('stateChanged', onCoreStateChanged); diff --git a/src/routes/Settings/useSettings.js b/src/routes/Settings/useSettings.js index c8346039a..25c5347f2 100644 --- a/src/routes/Settings/useSettings.js +++ b/src/routes/Settings/useSettings.js @@ -1,45 +1,31 @@ const React = require('react'); const { useServices } = require('stremio/services'); -module.exports = (devTestWithUser) => { +module.exports = () => { const IGNORED_SETTINGS = Object.freeze(['user']); const { core } = useServices(); const [settings, setSettings] = React.useState({}); React.useEffect(() => { - const updateState = (state) => { - try { + const updateState = () => { + const state = core.getState(); + if (state.ctx && state.ctx.is_loaded && state.ctx.content && state.ctx.content.settings) { setSettings({ - ...settings, ...state.ctx.content.settings, user: devTestWithUser ? { - '_id': 'neo', - 'email': 'neo@example.com', - 'avatar': 'https://www.thenational.ae/image/policy:1.891803:1566372420/AC17-Matrix-20-04.jpg', - } : state.ctx.content.auth && state.ctx.content.auth.user + ...settings, + ...state.ctx.content.settings, + user: state.ctx.content.auth ? state.ctx.content.auth.user : null }); - } catch (e) { - console.log('Cannot update settings state', e); } } - const state = core.getState(); - try { - if (state.ctx.is_loaded) { - updateState(state); - return; - } - } catch (e) { - console.log('Cannot find state context', e); - } + core.on('NewModel', updateState); + + updateState(); - const onNewState = () => { - updateState(core.getState()); - }; - core.on('NewModel', onNewState); - core.dispatch({ action: 'LoadCtx' }); return () => { // Destructor function - core.off('NewModel', onNewState); + core.off('NewModel', updateState); }; }, []); @@ -48,9 +34,8 @@ module.exports = (devTestWithUser) => { Object.keys(newSettings) .filter(prop => !IGNORED_SETTINGS.includes(prop)) .forEach(key => args[key] = newSettings[key].toString()) - setSettings(newSettings); core.dispatch({ action: 'Settings', args: { settings: 'Store', args } }); - }, [settings]) + }, []) return [settings, setTheSettings]; }; From bec623f3e3933bd6587cad0f3990d6552d53f1ca Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Tue, 15 Oct 2019 10:22:03 +0300 Subject: [PATCH 018/442] Bigger close button and hover styles --- src/common/ModalDialog/ModalDialog.js | 2 +- src/common/ModalDialog/styles.less | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 12ab87e26..c195d0c94 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -8,7 +8,7 @@ const styles = require('./styles'); const ModalDialog = ({className, children, title, buttons, onClose}) => { return (
-

{title}

diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index e050f5562..1f1032e0b 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -8,6 +8,20 @@ overflow: visible; } + .close-button { + position: absolute; + top: 0; + right: 0; + width: 3rem; + height: 3rem; + &:hover { + background-color: var(--color-surfacelight); + .x-icon { + fill: var(--color-signal2); + } + } + } + .x-icon { position: absolute; top: 1rem; From e7d95a53321405e6008f3786b3936b7317215f69 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 16 Oct 2019 11:47:05 +0300 Subject: [PATCH 019/442] useUser hook implemented --- src/common/index.js | 4 +++- src/common/useUser.js | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/common/useUser.js diff --git a/src/common/index.js b/src/common/index.js index c363328db..3d15f6636 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -22,6 +22,7 @@ const useLiveRef = require('./useLiveRef'); const useLocationHash = require('./useLocationHash'); const useRouteActive = require('./useRouteActive'); const useSpreadState = require('./useSpreadState'); +const useUser = require('./useUser'); module.exports = { Button, @@ -47,5 +48,6 @@ module.exports = { useLiveRef, useLocationHash, useRouteActive, - useSpreadState + useSpreadState, + useUser }; diff --git a/src/common/useUser.js b/src/common/useUser.js new file mode 100644 index 000000000..ef1d49852 --- /dev/null +++ b/src/common/useUser.js @@ -0,0 +1,24 @@ +const React = require('react'); +const { useServices } = require('stremio/services'); + +const useUser = () => { + const { core } = useServices(); + const getUserFromState = React.useCallback((state) => { + return state.ctx && state.ctx.auth && state.ctx.auth.user; + }, []); + const [user, setUser] = React.useState(() => { + return getUserFromState(core.getState()); + }); + React.useEffect(() => { + const onNewModel = () => { + setUser(getUserFromState(core.getState())); + }; + core.on('NewModel', onNewModel); + return () => { + core.off('NewModel', onNewModel); + }; + }, [core]); + return user; +}; + +module.exports = useUser; From e8659cce32660d6ec7b8e6a5ff612c60d302461e Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 17 Oct 2019 17:29:43 +0300 Subject: [PATCH 020/442] useAddons hook demo items replaced with data from the state container --- src/routes/Addons/useAddons.js | 47 +++++++++++++++------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index 3435c0dae..1c37b52f6 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -1,4 +1,5 @@ const React = require('react'); +const { useServices } = require('stremio/services'); const CATEGORIES = ['official', 'community', 'my']; const DEFAULT_CATEGORY = 'community'; @@ -7,33 +8,25 @@ const DEFAULT_TYPE = 'all'; const useAddons = (category, type) => { category = CATEGORIES.includes(category) ? category : DEFAULT_CATEGORY; type = typeof type === 'string' && type.length > 0 ? type : DEFAULT_TYPE; - const addons = React.useMemo(() => { - return [ - { - id: 'com.linvo.cinemeta', - name: 'Cinemeta', - description: 'The official add-on for movie and series catalogs', - types: ['movie', 'series'], - version: '2.12.1', - transportUrl: 'https://v3-cinemeta.strem.io/manifest.json', - installed: true, - official: true - }, - { - id: 'com.linvo.cinemeta2', - name: 'Cinemeta2', - logo: '/images/intro_background.jpg', - description: 'The official add-on for movie and series catalogs', - types: ['movie', 'series'], - version: '2.12.2', - transportUrl: 'https://v2-cinemeta.strem.io/manifest.json', - installed: false, - official: false - } - ]; + const [addons, setAddons] = React.useState([]); + const { core } = useServices(); + React.useEffect(() => { + const onNewState = () => { + const state = core.getState(); + setAddons(state.ctx.content.addons); + }; + core.on('NewModel', onNewState); + core.dispatch({ + action: 'LoadCtx' + }); + onNewState(); + return () => { + core.off('NewModel', onNewState); + }; }, []); const onSelect = React.useCallback((event) => { - const { name, value } = event.currentTarget.dataset; + const { value } = event.reactEvent.currentTarget.dataset; + const name = event.dataset.name; if (name === 'category') { const nextCategory = CATEGORIES.includes(value) ? value : ''; window.location.replace(`#/addons/${nextCategory}/${type}`); @@ -47,7 +40,7 @@ const useAddons = (category, type) => { const options = CATEGORIES .map((category) => ({ label: category, value: category })); return { - name: 'category', + 'data-name': 'category', selected, options, onSelect @@ -60,7 +53,7 @@ const useAddons = (category, type) => { .filter((type, index, types) => types.indexOf(type) === index) .map((type) => ({ label: type, value: type })); return { - name: 'type', + 'data-name': 'type', selected, options, onSelect From 388412f394297eabe2d46ff999389be4128b8f22 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Thu, 17 Oct 2019 17:32:36 +0300 Subject: [PATCH 021/442] Do not fetch the streaming server --- src/routes/Settings/Settings.js | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index bfb5cdfe8..970236064 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -20,33 +20,6 @@ const Settings = () => { const [selectedSectionId, setSelectedSectionId] = React.useState(sections[0].id); const scrollContainerRef = React.useRef(null); - React.useEffect(() => { - const shouldFetch = preferences.server_url && preferences.server_url.length > 0 - ? - Promise.resolve(preferences.server_url + 'settings') - : - Promise.reject(); - - shouldFetch - .then(fetch) - .then(() => ['OK']) - .catch(() => []).then(serverInputs => { - const additionalServerSettings = [ - { id: 'server_url', header: 'Streaming server URL:', type: 'info' }, - { id: 'streaming_server_is_available.', label: 'Streaming server is ' + (serverInputs.length !== 0 ? '' : 'not ') + 'available.', type: 'static-text', icon: serverInputs.length !== 0 ? 'ic_check' : 'ic_x' } - ]; - setDynamicSections({ - ...dynamicSections, - Streaming: [ - ...dynamicSections.Streaming, - ...additionalServerSettings - ] - }); - }); - }, [preferences.server_url]); - - ///////////////// - const updatePreference = (option, value) => { setPreferences({ ...preferences, [option]: value }); } From 0e52f2dd370e304a8e1dc294600b1d5a248d5ff7 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Thu, 17 Oct 2019 17:36:57 +0300 Subject: [PATCH 022/442] Streaming server settings from stremio-core --- src/routes/Settings/useSettings.js | 34 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/routes/Settings/useSettings.js b/src/routes/Settings/useSettings.js index c8346039a..ee7ed3642 100644 --- a/src/routes/Settings/useSettings.js +++ b/src/routes/Settings/useSettings.js @@ -1,21 +1,20 @@ const React = require('react'); const { useServices } = require('stremio/services'); -module.exports = (devTestWithUser) => { - const IGNORED_SETTINGS = Object.freeze(['user']); +module.exports = () => { + const IGNORED_SETTINGS = Object.freeze(['user', 'streaming']); const { core } = useServices(); - const [settings, setSettings] = React.useState({}); + const [settings, setSettings] = React.useState({ streaming: {} }); React.useEffect(() => { const updateState = (state) => { + console.log(state) try { setSettings({ - ...settings, ...state.ctx.content.settings, user: devTestWithUser ? { - '_id': 'neo', - 'email': 'neo@example.com', - 'avatar': 'https://www.thenational.ae/image/policy:1.891803:1566372420/AC17-Matrix-20-04.jpg', - } : state.ctx.content.auth && state.ctx.content.auth.user + ...settings, ...state.ctx.content.settings, + user: state.ctx.content.auth && state.ctx.content.auth.user, + streaming: state.streaming_server_settings || {}, }); } catch (e) { console.log('Cannot update settings state', e); @@ -44,12 +43,19 @@ module.exports = (devTestWithUser) => { }, []); const setTheSettings = React.useCallback(newSettings => { - const args = {}; - Object.keys(newSettings) - .filter(prop => !IGNORED_SETTINGS.includes(prop)) - .forEach(key => args[key] = newSettings[key].toString()) - setSettings(newSettings); - core.dispatch({ action: 'Settings', args: { settings: 'Store', args } }); + const event = { action: 'Settings', args: { args: {} } }; + // This can be done with React.useEffect and newSettings.streaming as dependency + const streamingServerSettingChanged = Object.keys(newSettings.streaming) + .some(prop => settings.streaming[prop] !== newSettings.streaming[prop]); + if (streamingServerSettingChanged) { + event.args = { settings: 'StoreStreamingServer', args: newSettings.streaming }; + } else { + event.args.settings = 'Store'; + Object.keys(newSettings) + .filter(prop => !IGNORED_SETTINGS.includes(prop)) + .forEach(key => event.args.args[key] = newSettings[key].toString()); + } + core.dispatch(event); }, [settings]) return [settings, setTheSettings]; From 4a43bf51549d94d3e3579c2ba45b162f9a90947e Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Thu, 17 Oct 2019 17:38:36 +0300 Subject: [PATCH 023/442] Hardcoded streaming server settings --- .../Settings/SectionsList/SectionsList.js | 47 ++++++++++++++++++- src/routes/Settings/constants.js | 3 +- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/routes/Settings/SectionsList/SectionsList.js b/src/routes/Settings/SectionsList/SectionsList.js index 4dc4aed53..49e9f950f 100644 --- a/src/routes/Settings/SectionsList/SectionsList.js +++ b/src/routes/Settings/SectionsList/SectionsList.js @@ -17,12 +17,18 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre }, [onPreferenceChanged]); const updateDropdown = React.useCallback((event) => { - var data = event.currentTarget.dataset; + const data = event.currentTarget.dataset; onPreferenceChanged(data.name, data.value); }, [onPreferenceChanged]); + const updateStreamingDropdown = React.useCallback((event) => { + const data = event.currentTarget.dataset; + const newPrefs = { ...preferences.streaming, [data.name]: data.value }; + onPreferenceChanged('streaming', newPrefs); + }, [onPreferenceChanged]); + const checkUser = React.useCallback((event) => { - if(! preferences.user) { + if (!preferences.user) { // Here in Stremio 4 we show a toast with a message, asking the anonymous user to log in/register console.log('No user found'); event.preventDefault(); @@ -37,6 +43,10 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre const changePasswordUrl = preferences.user && 'https://www.strem.io/reset-password/' + preferences.user.email; const webCalUrl = preferences.user && 'webcal://www.strem.io/calendar/' + preferences.user._id + '.ics'; + // TODO: move these out of here + const cachingOptions = [{ "label": "no caching", "value": "0" }, { "label": "2GB", "value": "2147483648" }, { "label": "5GB", "value": "5368709120" }, { "label": "10GB", "value": "10737418240" }, { "label": "∞", "value": "null" }]; + const streamingProfiles = [{ "label": "Default", "value": "default" }, { "label": "Soft", "value": "soft" }, { "label": "Fast", "value": "fast" }]; + const sectionsElements = sections.map((section) =>
{section.id}
@@ -104,6 +114,39 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre
); + } else if (input.type === 'streaming') { + return ( + + + { + // The streaming server settings are shown only if server is available + preferences.streaming.isLoaded + ? + +
+
Caching
+ +
+
+
Torrent Profile
+ +
+
+ : + null + } + {/* From here there is only presentation */} +
+
Streaming server URL: {preferences.server_url}
+
+
+
+ +
{'Streaming server is ' + (preferences.streaming.isLoaded ? '' : 'not ') + 'available.'}
+
+
+
+ ); } else if (input.type === 'select') { return (
diff --git a/src/routes/Settings/constants.js b/src/routes/Settings/constants.js index 493f51e17..f1e154d9c 100644 --- a/src/routes/Settings/constants.js +++ b/src/routes/Settings/constants.js @@ -17,8 +17,7 @@ const settingsSections = { { 'id': 'use_external_player', 'label': 'Launch player in a separate window (advanced)', 'type': 'checkbox' }, ], 'Streaming': [ - { "id": "cacheSize", "label": "Caching", "header": "Caching", "type": "select", "options": [{ "label": "no caching", "value": "0" }, { "label": "2GB", "value": "2147483648" }, { "label": "5GB", "value": "5368709120" }, { "label": "10GB", "value": "10737418240" }, { "label": "∞", "value": "null" }] }, - { "id": "torrent_profile", "label": "Torrent Profile", "header": "Torrent Profile", "type": "select", "options": [{ "label": "Default", "value": "profile-default" }, { "label": "Soft", "value": "profile-soft" }, { "label": "Fast", "value": "profile-fast" }] } + { 'id': 'streaming', 'type': 'streaming' }, ] }; From 2da642c90a2254b496602d452ef2c107751d5ffd Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 17 Oct 2019 17:42:37 +0300 Subject: [PATCH 024/442] sample discover picker linked with stremio core --- src/routes/Discover/Discover.js | 9 +- src/routes/Discover/styles.less | 4 +- src/routes/Discover/useCatalog.js | 189 +++++++++++++++--------------- 3 files changed, 102 insertions(+), 100 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index e060cb12f..6954cbed0 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -1,14 +1,15 @@ const React = require('react'); const classnames = require('classnames'); -const { Dropdown, MainNavBar, MetaItem, MetaPreview } = require('stremio/common'); +const { MainNavBar, MetaItem, MetaPreview, Multiselect } = require('stremio/common'); const useCatalog = require('./useCatalog'); const styles = require('./styles'); +// TODO render only 4 pickers and a more button that opens a modal with all pickers const Discover = ({ urlParams, queryParams }) => { const [dropdowns, metaItems] = useCatalog(urlParams, queryParams); const [selectedItem, setSelectedItem] = React.useState(null); const metaItemsOnMouseDown = React.useCallback((event) => { - event.nativeEvent.blurPrevented = true; + event.nativeEvent.buttonBlurPrevented = true; }, []); const metaItemsOnFocus = React.useCallback((event) => { const metaItem = metaItems.find(({ id }) => { @@ -27,8 +28,8 @@ const Discover = ({ urlParams, queryParams }) => {
- {dropdowns.map((dropdown) => ( - + {dropdowns.map((dropdown, index) => ( + ))}
diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 0f8251548..8f972da85 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -17,7 +17,7 @@ align-self: stretch; display: grid; grid-template-columns: 1fr 26rem; - grid-template-rows: fit-content(15rem) 1fr; + grid-template-rows: 7rem 1fr; grid-template-areas: "dropdowns-area meta-preview-area" "meta-items-area meta-preview-area"; @@ -29,7 +29,7 @@ grid-gap: 1rem; margin: 2rem 0; padding: 0 2rem; - overflow-y: auto; + overflow: visible; .dropdown { height: 3rem; diff --git a/src/routes/Discover/useCatalog.js b/src/routes/Discover/useCatalog.js index 77dc11da4..bb81dbf13 100644 --- a/src/routes/Discover/useCatalog.js +++ b/src/routes/Discover/useCatalog.js @@ -1,104 +1,105 @@ const React = require('react'); +const { useServices } = require('stremio/services'); + +const DEFAULT_TYPE = 'movie'; +const DEFAULT_ADDON_ID = 'com.linvo.cinemeta'; +const DEFAULT_CATALOG_ID = 'top'; const useCatalog = (urlParams, queryParams) => { - const queryString = new URLSearchParams(queryParams).toString(); - const [addon, catalog] = React.useMemo(() => { - // TODO impl this logic to stremio-core for code-reuse: - // TODO use type if it is part of user's addons - // TODO fallback to first type from user's addons - // TODO find catalog for addonId, catalogId and type - // TODO fallback to first catalog for the type from user's catalogs - const addon = { - id: 'com.linvo.cinemeta', - version: '2.11.0', - name: 'Cinemeta' - }; - const catalog = { - id: 'top', - type: 'movie', - name: 'Top', - extra: [ - { - name: 'genre', - isRequired: false, - options: ['Action', 'Drama', 'Boring'] - }, - { - name: 'year', - isRequired: false, - options: ['2017', '2016', '2015'] + const { core } = useServices(); + const [selectInputs, setSelectInputs] = React.useState([]); + React.useEffect(() => { + const onNewModel = () => { + const state = core.getState(); + const typeSelectInput = { + options: [{ value: urlParams.type, label: urlParams.type }].concat(state.discover.types.map(({ type_name }) => ({ + value: type_name, + label: type_name + }))).filter((item, index, array) => { + // TODO findIndexRight + return array.findIndex(({ value }) => value === item.value) === index; + }), + selected: [urlParams.type].concat(state.discover.types.filter(({ is_selected }) => is_selected) + .map(({ type_name }) => type_name)) + .filter((item, index, array) => { + return array.indexOf(item) === index; + }), + onSelect: (event) => { + const value = event.reactEvent.currentTarget.dataset.value; + // TODO queryparams + window.location = `#/discover/${value}/${typeof urlParams.catalog === 'string' ? urlParams.catalog : ''}`; } - ] + }; + console.log(typeSelectInput); + setSelectInputs([typeSelectInput]); }; - return [addon, catalog]; - }, [urlParams.type, urlParams.catalog]); - const dropdowns = React.useMemo(() => { - const onTypeChange = (event) => { - const { value } = event.currentTarget.dataset; - const query = new URLSearchParams(queryParams); - window.location = `#/discover/${value}/${addon.id}:${catalog.id}?${query}`; + core.on('NewModel', onNewModel); + return () => { + core.off('NewModel', onNewModel); }; - const onCatalogChange = (event) => { - const { value } = event.currentTarget.dataset; - const query = new URLSearchParams(queryParams); - window.location = `#/discover/${catalog.type}/${value}?${query}`; - }; - const onQueryParamChange = (event) => { - const { name, value } = event.currentTarget.dataset; - const query = new URLSearchParams({ ...queryParams, [name]: value }); - window.location = `#/discover/${catalog.type}/${addon.id}:${catalog.id}?${query}`; - }; - const requiredDropdowns = [ - { - name: 'type', - selected: [catalog.type], - options: [ - { value: 'movie', label: 'movie' }, - { value: 'series', label: 'series' }, - { value: 'channels', label: 'channels' }, - { value: 'games', label: 'games' } - ], - onSelect: onTypeChange - }, - { - name: 'catalog', - selected: [`${addon.id}:${catalog.id}`], - options: [ - { value: 'com.linvo.cinemeta:top', label: 'Top' }, - { value: 'com.linvo.cinemeta:year', label: 'By year' } - ], - onSelect: onCatalogChange + }, [urlParams, queryParams]); + React.useEffect(() => { + const state = core.getState(); + let type = DEFAULT_TYPE; + let addonId = DEFAULT_ADDON_ID; + let catalogId = DEFAULT_CATALOG_ID; + if (typeof urlParams.type === 'string' && urlParams.type.length > 0) { + type = urlParams.type; + addonId = null; + catalogId = null; + if (typeof urlParams.catalog === 'string' && urlParams.catalog.includes(':')) { + [addonId = '', catalogId = ''] = urlParams.catalog.split(':'); } - ]; - const extraDropdowns = catalog.extra - .filter((extra) => { - return extra.name !== 'skip' && extra.name !== 'search'; - }) - .map((extra) => ({ - ...extra, - onSelect: onQueryParamChange, - options: extra.options.map((option) => ({ value: option, label: option })), - selected: extra.options.includes(queryParams[extra.name]) ? - [queryParams[extra.name]] - : - extra.isRequired ? - [extra.options[0]] - : - [] - })); - return requiredDropdowns.concat(extraDropdowns); - }, [addon, catalog, queryString]); - const items = React.useMemo(() => { - return Array(100).fill(null).map((_, index) => ({ - id: `tt${index}`, - type: 'movie', - name: `Stremio demo item ${index}`, - poster: `https://www.stremio.com/website/technology-hero.jpg`, - logo: `https://www.stremio.com/website/stremio-logo-small.png`, - posterShape: 'poster' - })); - }, []); - return [dropdowns, items]; + } + + const [addon, catalog] = state.ctx.content.addons.reduceRight((result, addon) => { + if (typeof addonId !== 'string' || addonId === addon.manifest.id) { + const catalog = addon.manifest.catalogs.find((catalog) => { + return (typeof catalogId !== 'string' || catalogId === catalog.id) && + catalog.type === type; // TODO && extraRequired.every(...); + }); + if (catalog) { + return [addon, catalog]; + } + } + + return result; + }, []); + if (catalog) { + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogFiltered', + args: { + base: addon.transportUrl, + path: { + resource: 'catalog', + type_name: type, + id: catalog.id, + extra: [] // TODO + } + } + } + }); + } else { + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogFiltered', + args: { + base: '', + path: { + resource: 'catalog', + type_name: type, + id: '', + extra: [] // TODO + } + } + } + }); + } + }, [urlParams, queryParams]); + return [selectInputs, []]; }; module.exports = useCatalog; From 830ae9faf6b86c1b12b62ca5deb50dd140f41bfc Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Thu, 17 Oct 2019 18:05:02 +0300 Subject: [PATCH 025/442] Fixed icon style for offline streaming server --- src/routes/Settings/SectionsList/SectionsList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Settings/SectionsList/SectionsList.js b/src/routes/Settings/SectionsList/SectionsList.js index 49e9f950f..c1ce5aa4e 100644 --- a/src/routes/Settings/SectionsList/SectionsList.js +++ b/src/routes/Settings/SectionsList/SectionsList.js @@ -141,7 +141,7 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre
- +
{'Streaming server is ' + (preferences.streaming.isLoaded ? '' : 'not ') + 'available.'}
From e8d5356fcdc4cd81df9e3f3cd4154a34a98e561b Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Fri, 18 Oct 2019 10:50:33 +0300 Subject: [PATCH 026/442] Improved styles --- .../Settings/SectionsList/SectionsList.js | 2 +- src/routes/Settings/SectionsList/styles.less | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/routes/Settings/SectionsList/SectionsList.js b/src/routes/Settings/SectionsList/SectionsList.js index c1ce5aa4e..b51834314 100644 --- a/src/routes/Settings/SectionsList/SectionsList.js +++ b/src/routes/Settings/SectionsList/SectionsList.js @@ -136,7 +136,7 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre null } {/* From here there is only presentation */} -
+
Streaming server URL: {preferences.server_url}
diff --git a/src/routes/Settings/SectionsList/styles.less b/src/routes/Settings/SectionsList/styles.less index d7b647535..0bc15dab1 100644 --- a/src/routes/Settings/SectionsList/styles.less +++ b/src/routes/Settings/SectionsList/styles.less @@ -3,16 +3,18 @@ } .section { - padding: 4rem 2rem; + padding: 4rem 0; + margin: 0 2rem; + width: var(--input-width); .section-header { - margin: 0 1.5rem 1.5rem 1.5rem; + margin: 1.5rem 0; font-size: 2rem; color: var(--color-surfacelighter); } .input-container { - margin: 1.5rem; + margin: 2rem 0; display: flex; flex-direction: column; @@ -51,14 +53,14 @@ &.select-container { .dropdown { height: 3rem; - width: var(--input-width); + // width: var(--input-width); } } &.link-container { - margin: 1rem 1.5rem; - + margin: 0; .link { + padding: .75rem 0; display: block; color: var(--color-secondarylight); @@ -75,7 +77,6 @@ &.button-container { .button { padding: 0.7rem; - width: var(--input-width); min-height: calc(var(--input-width) * 0.09); display: flex; align-items: center; @@ -132,10 +133,12 @@ } &.text-container { + margin: 0; .text { display: flex; flex-direction: row; align-items: center; + padding: .75rem 0; .icon { margin-right: 0.5rem; @@ -160,7 +163,7 @@ &.color-container { .color-picker { - width: var(--input-width); + box-shadow: inset 0px 0px .2rem 0px var(--color-surfacelighter20); height: calc(var(--input-width) * 0.08); cursor: pointer; From b12a8a3c9d264aeb55c089c71de952458be63384 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 18 Oct 2019 11:19:32 +0300 Subject: [PATCH 027/442] attach core service to window --- src/App/App.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/App/App.js b/src/App/App.js index 81778d1e7..0a560f919 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -24,6 +24,7 @@ const App = () => { setCoreInitialized(services.core.active || services.core.error instanceof Error); if (services.core.active) { services.core.dispatch({ action: 'LoadCtx' }); + window.core = services.core; } }; services.shell.on('stateChanged', onShellStateChanged); From 9923970a54146d9d0bba94bb823828e4e5a36680 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 18 Oct 2019 11:21:21 +0300 Subject: [PATCH 028/442] useCatalogs fixed --- src/routes/Board/useCatalogs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Board/useCatalogs.js b/src/routes/Board/useCatalogs.js index b31b19ddb..d2470ff9e 100644 --- a/src/routes/Board/useCatalogs.js +++ b/src/routes/Board/useCatalogs.js @@ -7,7 +7,7 @@ const useCatalogs = () => { React.useEffect(() => { const onNewState = () => { const state = core.getState(); - setCatalogs(state.catalogs.groups); + setCatalogs(state.board.groups); }; core.on('NewModel', onNewState); core.dispatch({ From fc89a083eadbf1d4bc54e3baf27f8e3185a48d16 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 18 Oct 2019 11:40:40 +0300 Subject: [PATCH 029/442] Addons adapted to useAddons hook changes --- src/routes/Addons/Addons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 5146bc713..602aac2e1 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -48,9 +48,9 @@ const Addons = ({ urlParams, queryParams }) => {
{ - addons.filter(({ name }) => query.length === 0 || (typeof name === 'string' && name.includes(query))) + addons.filter((addon) => query.length === 0 || (typeof addon.manifest.name === 'string' && addon.manifest.name.includes(query))) .map((addon) => ( - + )) }
From 4f37dc09f90cadfd6c91fcc89bca9cf576068eed Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 18 Oct 2019 13:31:46 +0300 Subject: [PATCH 030/442] Multiselect instead of Dropdown used --- src/routes/Addons/Addons.js | 6 +++--- src/routes/Addons/styles.less | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 602aac2e1..93e0ccef8 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -1,7 +1,7 @@ const React = require('react'); const Icon = require('stremio-icons/dom'); const { Modal } = require('stremio-router'); -const { Button, Dropdown, NavBar, TextInput } = require('stremio/common'); +const { Button, Multiselect, NavBar, TextInput } = require('stremio/common'); const Addon = require('./Addon'); const AddonPrompt = require('./AddonPrompt'); const useAddons = require('./useAddons'); @@ -32,8 +32,8 @@ const Addons = ({ urlParams, queryParams }) => {
Add addon
- {dropdowns.map((dropdown) => ( - + {dropdowns.map((dropdown, index) => ( + ))}
-
+
{ - addons.filter((addon) => query.length === 0 || (typeof addon.manifest.name === 'string' && addon.manifest.name.includes(query))) + addons.filter((addon) => query.length === 0 || + ((typeof addon.manifest.name === 'string' && addon.manifest.name.toLowerCase().includes(query.toLowerCase())) || + (typeof addon.manifest.description === 'string' && addon.manifest.description.toLowerCase().includes(query.toLowerCase())) + )) .map((addon) => ( )) From a09b9b42d27824ecb225917422be07163e680320 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 18 Oct 2019 14:51:18 +0300 Subject: [PATCH 032/442] no options label rendered when there are no options --- src/common/Multiselect/Multiselect.js | 19 +++++++++++++------ src/common/Multiselect/styles.less | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/common/Multiselect/Multiselect.js b/src/common/Multiselect/Multiselect.js index 9f03f33e5..f61b69305 100644 --- a/src/common/Multiselect/Multiselect.js +++ b/src/common/Multiselect/Multiselect.js @@ -92,12 +92,19 @@ const Multiselect = ({ className, direction, title, renderLabelContent, options, )} renderMenu={() => (
- {options.map(({ label, value }) => ( - - ))} + { + options.length > 0 ? + options.map(({ label, value }) => ( + + )) + : +
+
No options available
+
+ }
)} /> diff --git a/src/common/Multiselect/styles.less b/src/common/Multiselect/styles.less index c88dae55f..090d39bb1 100644 --- a/src/common/Multiselect/styles.less +++ b/src/common/Multiselect/styles.less @@ -73,6 +73,24 @@ fill: var(--color-surfacelighter); } } + + .no-options-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding: 1rem; + background-color: var(--color-backgroundlighter); + + .label { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + font-size: 1.2rem; + text-align: center; + color: var(--color-surfacelighter); + } + } } } } \ No newline at end of file From c430f09376a5651b27d63a9be4ff6a52593eca45 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 18 Oct 2019 14:55:00 +0300 Subject: [PATCH 033/442] discover url restrictions changed --- src/common/routesRegexp.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index 7d66a0566..5e8eae4d1 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -8,8 +8,8 @@ const routesRegexp = { urlParamsNames: [] }, discover: { - regexp: /^\/discover(?:\/([^\/]*?))?(?:\/([^\/]*?))?\/?$/i, - urlParamsNames: ['type', 'catalog'] + regexp: /^\/discover(?:\/([^\/]+?)\/([^\/]+?)\/([^\/]+?))?\/?$/i, + urlParamsNames: ['addonTransportUrl', 'catalogId', 'type'] }, library: { regexp: /^\/library(?:\/([^\/]*?))?\/?$/i, From 4941d6755cbb76b5cab8d432cb9e346b07b005d4 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 18 Oct 2019 14:59:50 +0300 Subject: [PATCH 034/442] Router decode url params --- src/router/Router/Router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index 7fbaa26c3..16fbc5740 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -64,7 +64,7 @@ const Router = ({ className, onPathNotMatch, ...props }) => { const matches = pathname.match(routeConfig.regexp); const urlParams = routeConfig.urlParamsNames.reduce((urlParams, name, index) => { if (Array.isArray(matches) && typeof matches[index + 1] === 'string') { - urlParams[name] = matches[index + 1]; + urlParams[name] = decodeURIComponent(matches[index + 1]); } else { urlParams[name] = null; } From 2ee323f720ffb177469a870235af7cf33dc87304 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 18 Oct 2019 16:20:33 +0300 Subject: [PATCH 035/442] discover linked with stremio-core --- src/routes/Discover/Discover.js | 34 +++++----- src/routes/Discover/styles.less | 14 ++-- src/routes/Discover/useCatalog.js | 105 ----------------------------- src/routes/Discover/useDiscover.js | 79 ++++++++++++++++++++++ 4 files changed, 103 insertions(+), 129 deletions(-) delete mode 100644 src/routes/Discover/useCatalog.js create mode 100644 src/routes/Discover/useDiscover.js diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 6954cbed0..71ea541f8 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -1,50 +1,50 @@ const React = require('react'); const classnames = require('classnames'); const { MainNavBar, MetaItem, MetaPreview, Multiselect } = require('stremio/common'); -const useCatalog = require('./useCatalog'); +const useDiscover = require('./useDiscover'); const styles = require('./styles'); // TODO render only 4 pickers and a more button that opens a modal with all pickers const Discover = ({ urlParams, queryParams }) => { - const [dropdowns, metaItems] = useCatalog(urlParams, queryParams); - const [selectedItem, setSelectedItem] = React.useState(null); - const metaItemsOnMouseDown = React.useCallback((event) => { + const [selectInputs, metaItems, error] = useDiscover(urlParams, queryParams); + const [selectedMetaItem, setSelectedMetaItem] = React.useState(null); + const metaItemsOnMouseDownCapture = React.useCallback((event) => { event.nativeEvent.buttonBlurPrevented = true; }, []); - const metaItemsOnFocus = React.useCallback((event) => { + const metaItemsOnFocusCapture = React.useCallback((event) => { const metaItem = metaItems.find(({ id }) => { return id === event.target.dataset.id; }); if (metaItem) { - setSelectedItem(metaItem); + setSelectedMetaItem(metaItem); } - }, []); + }, [metaItems]); React.useEffect(() => { const metaItem = metaItems.length > 0 ? metaItems[0] : null; - setSelectedItem(metaItem); + setSelectedMetaItem(metaItem); }, [metaItems]); return (
-
- {dropdowns.map((dropdown, index) => ( - +
+ {selectInputs.map((selectInput, index) => ( + ))}
-
- {metaItems.map((metaItem) => ( +
+ {metaItems.map((metaItem, index) => ( ))}
{ - selectedItem !== null ? + selectedMetaItem !== null ? diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 8f972da85..c541497fe 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -19,11 +19,11 @@ grid-template-columns: 1fr 26rem; grid-template-rows: 7rem 1fr; grid-template-areas: - "dropdowns-area meta-preview-area" + "multiselects-area meta-preview-area" "meta-items-area meta-preview-area"; - .dropdowns-container { - grid-area: dropdowns-area; + .multiselects-container { + grid-area: multiselects-area; display: grid; grid-template-columns: repeat(auto-fill, 15rem); grid-gap: 1rem; @@ -31,7 +31,7 @@ padding: 0 2rem; overflow: visible; - .dropdown { + .multiselect { height: 3rem; } } @@ -46,7 +46,7 @@ overflow-y: auto; .meta-item { - &.selected { + &:global(.selected) { outline: calc(1.5 * var(--focus-outline-size)) solid var(--color-surfacelighter); outline-offset: calc(-1.5 * var(--focus-outline-size)); } @@ -116,10 +116,10 @@ grid-template-columns: 1fr; grid-template-rows: fit-content(19rem) 1fr; grid-template-areas: - "dropdowns-area" + "multiselects-area" "meta-items-area"; - .dropdowns-container { + .multiselects-container { grid-template-columns: repeat(4, 1fr); } diff --git a/src/routes/Discover/useCatalog.js b/src/routes/Discover/useCatalog.js deleted file mode 100644 index bb81dbf13..000000000 --- a/src/routes/Discover/useCatalog.js +++ /dev/null @@ -1,105 +0,0 @@ -const React = require('react'); -const { useServices } = require('stremio/services'); - -const DEFAULT_TYPE = 'movie'; -const DEFAULT_ADDON_ID = 'com.linvo.cinemeta'; -const DEFAULT_CATALOG_ID = 'top'; - -const useCatalog = (urlParams, queryParams) => { - const { core } = useServices(); - const [selectInputs, setSelectInputs] = React.useState([]); - React.useEffect(() => { - const onNewModel = () => { - const state = core.getState(); - const typeSelectInput = { - options: [{ value: urlParams.type, label: urlParams.type }].concat(state.discover.types.map(({ type_name }) => ({ - value: type_name, - label: type_name - }))).filter((item, index, array) => { - // TODO findIndexRight - return array.findIndex(({ value }) => value === item.value) === index; - }), - selected: [urlParams.type].concat(state.discover.types.filter(({ is_selected }) => is_selected) - .map(({ type_name }) => type_name)) - .filter((item, index, array) => { - return array.indexOf(item) === index; - }), - onSelect: (event) => { - const value = event.reactEvent.currentTarget.dataset.value; - // TODO queryparams - window.location = `#/discover/${value}/${typeof urlParams.catalog === 'string' ? urlParams.catalog : ''}`; - } - }; - console.log(typeSelectInput); - setSelectInputs([typeSelectInput]); - }; - core.on('NewModel', onNewModel); - return () => { - core.off('NewModel', onNewModel); - }; - }, [urlParams, queryParams]); - React.useEffect(() => { - const state = core.getState(); - let type = DEFAULT_TYPE; - let addonId = DEFAULT_ADDON_ID; - let catalogId = DEFAULT_CATALOG_ID; - if (typeof urlParams.type === 'string' && urlParams.type.length > 0) { - type = urlParams.type; - addonId = null; - catalogId = null; - if (typeof urlParams.catalog === 'string' && urlParams.catalog.includes(':')) { - [addonId = '', catalogId = ''] = urlParams.catalog.split(':'); - } - } - - const [addon, catalog] = state.ctx.content.addons.reduceRight((result, addon) => { - if (typeof addonId !== 'string' || addonId === addon.manifest.id) { - const catalog = addon.manifest.catalogs.find((catalog) => { - return (typeof catalogId !== 'string' || catalogId === catalog.id) && - catalog.type === type; // TODO && extraRequired.every(...); - }); - if (catalog) { - return [addon, catalog]; - } - } - - return result; - }, []); - if (catalog) { - core.dispatch({ - action: 'Load', - args: { - load: 'CatalogFiltered', - args: { - base: addon.transportUrl, - path: { - resource: 'catalog', - type_name: type, - id: catalog.id, - extra: [] // TODO - } - } - } - }); - } else { - core.dispatch({ - action: 'Load', - args: { - load: 'CatalogFiltered', - args: { - base: '', - path: { - resource: 'catalog', - type_name: type, - id: '', - extra: [] // TODO - } - } - } - }); - } - }, [urlParams, queryParams]); - return [selectInputs, []]; -}; - -module.exports = useCatalog; diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js new file mode 100644 index 000000000..5af83eabc --- /dev/null +++ b/src/routes/Discover/useDiscover.js @@ -0,0 +1,79 @@ +const React = require('react'); +const { useServices } = require('stremio/services'); + +const DEFAULT_ADDON_TRANSPORT_URL = 'https://v3-cinemeta.strem.io/manifest.json'; +const DEFAULT_CATALOG_ID = 'top'; +const DEFAULT_TYPE = 'movie'; + +const useCatalog = (urlParams, queryParams) => { + const { core } = useServices(); + const [discover, setDiscover] = React.useState([[], [], null]); + React.useEffect(() => { + const addonTransportUrl = typeof urlParams.addonTransportUrl === 'string' ? urlParams.addonTransportUrl : DEFAULT_ADDON_TRANSPORT_URL; + const catalogId = typeof urlParams.catalogId === 'string' ? urlParams.catalogId : DEFAULT_CATALOG_ID; + const type = typeof urlParams.type === 'string' ? urlParams.type : DEFAULT_TYPE; + const onNewModel = () => { + const state = core.getState(); + const selectInputs = [ + { + title: 'Select type', + options: state.discover.types + .map(({ type_name, load }) => ({ + value: JSON.stringify(load), + label: type_name + })), + selected: state.discover.types + .filter(({ is_selected }) => is_selected) + .map(({ load }) => JSON.stringify(load)), + onSelect: (event) => { + const load = JSON.parse(event.reactEvent.currentTarget.dataset.value); + window.location = `#/discover/${encodeURIComponent(load.base)}/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; + } + }, + { + title: 'Select catalog', + options: state.discover.catalogs + .filter(({ load: { path: { type_name } } }) => { + return type_name === type; + }) + .map(({ name, load }) => ({ + value: JSON.stringify(load), + label: name + })), + selected: state.discover.catalogs + .filter(({ is_selected }) => is_selected) + .map(({ load }) => JSON.stringify(load)), + onSelect: (event) => { + const load = JSON.parse(event.reactEvent.currentTarget.dataset.value); + window.location = `#/discover/${encodeURIComponent(load.base)}/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; + } + } + ]; + const items = state.discover.content.type === 'Ready' ? state.discover.content.content : []; + const error = state.discover.content.type === 'Err' ? JSON.stringify(state.discover.content.content) : null; + setDiscover([selectInputs, items, error]); + }; + core.on('NewModel', onNewModel); + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogFiltered', + args: { + base: addonTransportUrl, + path: { + resource: 'catalog', + type_name: type, + id: catalogId, + extra: [] // TODO + } + } + } + }); + return () => { + core.off('NewModel', onNewModel); + }; + }, [urlParams, queryParams]); + return discover; +}; + +module.exports = useCatalog; From e67d026f39a0b457f9ad42d498c76730328b787a Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 18 Oct 2019 16:24:04 +0300 Subject: [PATCH 036/442] spread props in metaItem --- src/common/MetaItem/MetaItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/MetaItem/MetaItem.js b/src/common/MetaItem/MetaItem.js index 60180cd32..f092facf9 100644 --- a/src/common/MetaItem/MetaItem.js +++ b/src/common/MetaItem/MetaItem.js @@ -45,7 +45,7 @@ const MetaItem = React.memo(({ className, type, name, poster, posterShape, playI } }, [menuOptionOnSelect, dataset]); return ( - @@ -104,7 +104,7 @@ const AddonPrompt = ({ className, id, name, logo, description, types, catalogs, }
-
{ selectedAddon !== null ? -
- +
+
: diff --git a/src/routes/Addons/useSelectedAddon.js b/src/routes/Addons/useSelectedAddon.js index e770cc5b8..c0937277d 100644 --- a/src/routes/Addons/useSelectedAddon.js +++ b/src/routes/Addons/useSelectedAddon.js @@ -30,7 +30,7 @@ const useSelectedAddon = (transportUrl) => { setAddon(null); } }, [active, locationHash]); - return [addon, clear]; + return [addon, clear, setAddon]; }; module.exports = useSelectedAddon; From 739c06b998dea35ff13c47c2c1c72e2b6a7c756e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 25 Oct 2019 15:30:27 +0300 Subject: [PATCH 081/442] disabled prop added to Multiselect --- src/common/Multiselect/Multiselect.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/Multiselect/Multiselect.js b/src/common/Multiselect/Multiselect.js index 0faf8171c..7a251849b 100644 --- a/src/common/Multiselect/Multiselect.js +++ b/src/common/Multiselect/Multiselect.js @@ -8,7 +8,7 @@ const useBinaryState = require('stremio/common/useBinaryState'); const useDataset = require('stremio/common/useDataset'); const styles = require('./styles'); -const Multiselect = ({ className, direction, title, renderLabelContent, renderLabelText, options, selected, onOpen, onClose, onSelect, ...props }) => { +const Multiselect = ({ className, direction, title, renderLabelContent, renderLabelText, options, selected, disabled, onOpen, onClose, onSelect, ...props }) => { options = Array.isArray(options) ? options.filter(option => option && typeof option.value === 'string') : @@ -65,7 +65,7 @@ const Multiselect = ({ className, direction, title, renderLabelContent, renderLa direction={direction} onCloseRequest={closeMenu} renderLabel={({ ref, className: popupLabelClassName, children }) => ( - + ( +
{selectedLabelText}
+ )} + options={ + Array.isArray(options) ? + options.map(({ value, label }) => ({ + value: String(value), + label + })) + : + null + } + disabled={!Array.isArray(options) || options.length === 0} + onSelect={optionOnSelect} + /> + +
+ ); +}; + +PaginateInput.propTypes = { + className: PropTypes.string, + options: PropTypes.arrayOf(PropTypes.shape({ + value: PropTypes.number.isRequired, + label: PropTypes.string + })), + selected: PropTypes.number.isRequired, + onSelect: PropTypes.func +}; + +module.exports = PaginateInput; diff --git a/src/common/PaginateInput/index.js b/src/common/PaginateInput/index.js new file mode 100644 index 000000000..60b8c3e91 --- /dev/null +++ b/src/common/PaginateInput/index.js @@ -0,0 +1,3 @@ +const PaginateInput = require('./PaginateInput'); + +module.exports = PaginateInput; \ No newline at end of file diff --git a/src/common/PaginateInput/styles.less b/src/common/PaginateInput/styles.less new file mode 100644 index 000000000..e370414f8 --- /dev/null +++ b/src/common/PaginateInput/styles.less @@ -0,0 +1,32 @@ +.paginate-input-container { + display: flex; + flex-direction: row; + overflow: visible; + + .prev-button-container, .next-button-container { + flex: none; + display: flex; + align-items: center; + justify-content: center; + + .icon { + display: block; + width: 40%; + height: 40%; + fill: var(--color-surfacelighter); + } + } + + .multiselect-label-container { + flex: 1; + align-self: stretch; + display: flex; + align-items: center; + justify-content: center; + + .multiselect-label { + flex: none; + color: var(--color-surfacelighter); + } + } +} \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index 3d15f6636..5e0336ad4 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -8,6 +8,7 @@ const MetaPreview = require('./MetaPreview'); const MetaRow = require('./MetaRow'); const Multiselect = require('./Multiselect'); const NavBar = require('./NavBar'); +const PaginateInput = require('./PaginateInput'); const PlayIconCircleCentered = require('./PlayIconCircleCentered'); const Popup = require('./Popup'); const SharePrompt = require('./SharePrompt'); @@ -35,6 +36,7 @@ module.exports = { MetaRow, Multiselect, NavBar, + PaginateInput, PlayIconCircleCentered, Popup, SharePrompt, From 13e3c1a85d8aec8dce05e1409c68d3adec4691fa Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 28 Oct 2019 11:27:43 +0200 Subject: [PATCH 084/442] paginateInput added in useDiscover hook --- src/routes/Discover/useDiscover.js | 67 +++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 0903b3f15..4c24804e3 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -5,6 +5,7 @@ const DEFAULT_ADDON_TRANSPORT_URL = 'https://v3-cinemeta.strem.io/manifest.json' const DEFAULT_CATALOG_ID = 'top'; const DEFAULT_TYPE = 'movie'; const NONE_EXTRA_VALUE = 'None'; +const PAGE_SIZE = 100; const useCatalog = (urlParams, queryParams) => { const { core } = useServices(); @@ -122,9 +123,73 @@ const useCatalog = (urlParams, queryParams) => { return { title, options, selected, renderLabelText, onSelect }; }) ]; + const paginateInput = state.discover.load_next !== null || state.discover.load_prev !== null ? + { + selected: state.discover.load_next !== null ? + state.discover.load_next.path.extra.reduce((page, [name, value]) => { + if (name === 'skip') { + const parsedValue = parseInt(value); + if (!isNaN(parsedValue)) { + return Math.floor(parsedValue / 100); + } + } + + return page; + }, 1) + : + state.discover.load_prev !== null ? + state.discover.load_prev.path.extra.reduce((page, [name, value]) => { + if (name === 'skip') { + const parsedValue = parseInt(value); + if (!isNaN(parsedValue)) { + return Math.floor(parsedValue / 100) + 2; + } + } + + return page; + }, 1) + : + 1, + onSelect: (event) => { + if (event.value < 1) { + return; + } + + navigateWithLoad({ + base: addonTransportUrl, + path: { + resource: 'catalog', + type_name: type, + id: catalogId, + extra: Array.from(queryParams.entries()) + .concat([['skip', String((event.value - 1) * PAGE_SIZE)]]) + .reduceRight((result, [name, value]) => { + if (name === 'skip') { + const optionsCount = result.reduce((optionsCount, [name]) => { + if (name === 'skip') { + optionsCount++; + } + + return optionsCount; + }, 0); + if (optionsCount === 0) { + result.unshift([name, value]); + } + } else { + result.unshift([name, value]); + } + + return result; + }, []) + } + }); + } + } + : + null; const items = state.discover.content.type === 'Ready' ? state.discover.content.content : null; const error = state.discover.content.type === 'Err' ? JSON.stringify(state.discover.content.content) : null; - setDiscover([selectInputs, items, error]); + setDiscover([selectInputs, paginateInput, items, error]); }; core.on('NewModel', onNewModel); core.dispatch({ From 12c5ab900da1845f362a850ed0e0fe35bcd162fe Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Mon, 28 Oct 2019 11:29:17 +0200 Subject: [PATCH 085/442] Handle notLoaded state in the streaming server settings --- .../Settings/SectionsList/SectionsList.js | 69 ++++++++++--------- src/routes/Settings/useSettings.js | 6 +- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/routes/Settings/SectionsList/SectionsList.js b/src/routes/Settings/SectionsList/SectionsList.js index 66fc632cc..509c0a498 100644 --- a/src/routes/Settings/SectionsList/SectionsList.js +++ b/src/routes/Settings/SectionsList/SectionsList.js @@ -50,14 +50,14 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre if (inBytes === 'Infinity') return '∞'; const bytes = parseInt(inBytes, 10); - + const kilo = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - + const power = Math.floor(Math.log(bytes) / Math.log(kilo)); // More than 1024 yotta bytes - if(power >= sizes.length) { + if (power >= sizes.length) { power = sizes.length - 1; } return parseFloat((bytes / Math.pow(kilo, power)).toFixed(2)) + ' ' + sizes[power]; @@ -75,7 +75,7 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre const [cachingOptions, setCachingOptions] = React.useState(mkProfiles(supportedProfiles)); const [streamingProfiles, setStreamingProfiles] = React.useState(mkProfiles(supportedProfiles)); React.useEffect(() => { - if(!preferences.streaming || typeof preferences.streaming.cacheSize === 'undefined') return; + if (!preferences.streaming || typeof preferences.streaming.cacheSize === 'undefined') return; setCachingOptions(mkCacheSizeOptions([...new Set(cacheSizes.concat(preferences.streaming.cacheSize))])); }, [preferences.streaming && preferences.streaming.cacheSize]); React.useEffect(() => { @@ -153,36 +153,41 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre ); } else if (input.type === 'streaming') { return ( - - - { - // The streaming server settings are shown only if server is available - preferences.streaming_error - ? - null - : - -
-
Caching
- -
-
-
Torrent Profile
- -
-
- } - {/* From here there is only presentation */} -
-
Streaming server URL: {preferences.server_url}
-
-
-
- -
{'Streaming server is ' + (preferences.streaming_error ? 'not ' : '') + 'available. Reason: '+preferences.streaming_error}
+ preferences.streaming_loaded + ? + + { + // The streaming server settings are shown only if server is available + preferences.streaming_error + ? + null + : + +
+
Caching
+ +
+
+
Torrent Profile
+ +
+
+ } + {/* From here there is only presentation */} +
+
Streaming server URL: {preferences.server_url}
+
+
+ +
{'Streaming server is ' + (preferences.streaming_error ? 'not ' : '') + 'available. Reason: ' + preferences.streaming_error}
+
+
+
+ : +
+
Loading streaming settgins...
- ); } else if (input.type === 'select') { return ( diff --git a/src/routes/Settings/useSettings.js b/src/routes/Settings/useSettings.js index 2780ee37f..9af135cd4 100644 --- a/src/routes/Settings/useSettings.js +++ b/src/routes/Settings/useSettings.js @@ -11,13 +11,15 @@ module.exports = () => { const onNewState = () => { const state = core.getState() try { - setSettings({ + const newSettings = { ...settings, ...state.ctx.content.settings, user: state.ctx.content.auth ? state.ctx.content.auth.user : null, streaming: state.streaming_server_settings && state.streaming_server_settings.ready || {}, + streaming_loaded: state.streaming_server_settings && (state.streaming_server_settings.error || state.streaming_server_settings.ready), streaming_error: state.streaming_server_settings && state.streaming_server_settings.error || "", - }); + }; + setSettings(newSettings); } catch (e) { console.log('Cannot update settings state', e); } From 01303a742a626234a81fd07d110af9a6c53a1e60 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 28 Oct 2019 12:01:40 +0200 Subject: [PATCH 086/442] install/uninstall addon works --- src/routes/Addons/AddonPrompt/AddonPrompt.js | 8 +++++--- src/routes/Addons/Addons.js | 10 +++++++--- src/routes/Addons/useAddons.js | 21 +++++++++++++++++++- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/routes/Addons/AddonPrompt/AddonPrompt.js b/src/routes/Addons/AddonPrompt/AddonPrompt.js index 34938be38..4f3b6dfaf 100644 --- a/src/routes/Addons/AddonPrompt/AddonPrompt.js +++ b/src/routes/Addons/AddonPrompt/AddonPrompt.js @@ -6,7 +6,7 @@ const { useRouteFocused } = require('stremio-router'); const { Button } = require('stremio/common'); const styles = require('./styles'); -const AddonPrompt = ({ className, id, name, logo, description, types, catalogs, version, transportUrl, installed, official, cancel, onClick }) => { +const AddonPrompt = ({ className, id, name, logo, description, types, catalogs, version, transportUrl, installed, official, cancel, onClick, toggle }) => { const focusable = useRouteFocused(); React.useEffect(() => { const onKeyUp = (event) => { @@ -107,7 +107,7 @@ const AddonPrompt = ({ className, id, name, logo, description, types, catalogs, -
@@ -129,7 +129,9 @@ AddonPrompt.propTypes = { transportUrl: PropTypes.string, installed: PropTypes.bool, official: PropTypes.bool, - cancel: PropTypes.func + cancel: PropTypes.func, + onClick: PropTypes.func, + toggle: PropTypes.func }; module.exports = AddonPrompt; diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 576147ea0..206e8cba1 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -13,7 +13,7 @@ const Addons = ({ urlParams, queryParams }) => { const queryOnChange = React.useCallback((event) => { setQuery(event.currentTarget.value); }, []); - const [addons, dropdowns] = useAddons(urlParams, queryParams); + const [addons, dropdowns, installSelectedAddon, uninstallSelectedAddon, installedAddons] = useAddons(urlParams, queryParams); const [selectedAddon, clearSelectedAddon, setSelectedAddon] = useSelectedAddon(queryParams.get('addon')); const addonPromptModalBackgroundOnClick = React.useCallback((event) => { if (!event.nativeEvent.clearSelectedAddonPrevented) { @@ -23,6 +23,10 @@ const Addons = ({ urlParams, queryParams }) => { const addonPromptOnClick = React.useCallback((event) => { event.nativeEvent.clearSelectedAddonPrevented = true; }, []); + const setInstalledAddon = React.useCallback((currentAddon) => { + return installedAddons.some((installedAddon) => installedAddon.manifest.id === currentAddon.manifest.id && + installedAddon.transportUrl === currentAddon.transportUrl); + }, [installedAddons]); return (
@@ -53,7 +57,7 @@ const Addons = ({ urlParams, queryParams }) => { (typeof addon.manifest.description === 'string' && addon.manifest.description.toLowerCase().includes(query.toLowerCase())) )) .map((addon, index) => ( - setSelectedAddon(addon)} /> + setSelectedAddon(addon)} /> )) }
@@ -61,7 +65,7 @@ const Addons = ({ urlParams, queryParams }) => { selectedAddon !== null ?
- + setInstalledAddon(selectedAddon) ? uninstallSelectedAddon(selectedAddon) : installSelectedAddon(selectedAddon)} />
: diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index fc1e3764e..b8a19066e 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -7,6 +7,24 @@ const DEFAULT_CATEGORY = 'thirdparty'; const useAddons = (urlParams, queryParams) => { const { core } = useServices(); const [addons, setAddons] = React.useState([[], []]); + const installAddon = React.useCallback(descriptor => + core.dispatch({ + action: 'AddonOp', + args: { + addonOp: 'Install', + args: descriptor + } + }), []); + const uninstallAddon = React.useCallback(descriptor => + core.dispatch({ + action: 'AddonOp', + args: { + addonOp: 'Remove', + args: { + transport_url: descriptor.transportUrl + } + } + }), []); React.useEffect(() => { const type = typeof urlParams.type === 'string' && urlParams.type.length > 0 ? urlParams.type : DEFAULT_TYPE; const category = typeof urlParams.category === 'string' && urlParams.category.length > 0 ? urlParams.category : DEFAULT_CATEGORY; @@ -48,7 +66,8 @@ const useAddons = (urlParams, queryParams) => { } ]; const addonsItems = state.addons.content.type === 'Ready' ? state.addons.content.content : []; - setAddons([addonsItems, selectInputs]); + const installedAddons = state.ctx.is_loaded ? state.ctx.content.addons : []; + setAddons([addonsItems, selectInputs, installAddon, uninstallAddon, installedAddons]); }; core.on('NewModel', onNewState); core.dispatch({ From 7ba0e35657b3b8c4840dbfb6f0c2fdc46a50e9cd Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 28 Oct 2019 12:04:26 +0200 Subject: [PATCH 087/442] floor the skip query param --- src/routes/Discover/useDiscover.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 4c24804e3..6966c8630 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -14,6 +14,13 @@ const useCatalog = (urlParams, queryParams) => { const addonTransportUrl = typeof urlParams.addonTransportUrl === 'string' ? urlParams.addonTransportUrl : DEFAULT_ADDON_TRANSPORT_URL; const catalogId = typeof urlParams.catalogId === 'string' ? urlParams.catalogId : DEFAULT_CATALOG_ID; const type = typeof urlParams.type === 'string' ? urlParams.type : DEFAULT_TYPE; + queryParams = new URLSearchParams(queryParams); + if (queryParams.has('skip')) { + const skip = parseInt(queryParams.get('skip')); + if (!isNaN(skip)) { + queryParams.set('skip', Math.floor(skip / PAGE_SIZE) * PAGE_SIZE); + } + } const onNewModel = () => { const state = core.getState(); const navigateWithLoad = (load) => { From 3f7a5b258bdfbf70662d3c8cdf69afa0252fe4ca Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 28 Oct 2019 12:53:19 +0200 Subject: [PATCH 088/442] title added to PaginateInput --- src/common/PaginateInput/PaginateInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/PaginateInput/PaginateInput.js b/src/common/PaginateInput/PaginateInput.js index be7ef97fe..5aa09c7cd 100644 --- a/src/common/PaginateInput/PaginateInput.js +++ b/src/common/PaginateInput/PaginateInput.js @@ -88,7 +88,7 @@ const PaginateInput = ({ className, options, selected, onSelect, ...props }) => } }, [onSelect]); return ( -
+
From 1f5ac16275337e71a46a9af3cc476f87a087a809 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 28 Oct 2019 12:57:23 +0200 Subject: [PATCH 089/442] filter and paginate buttons added to discover layout --- src/routes/Discover/Discover.js | 18 +++++++++-- src/routes/Discover/styles.less | 55 ++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 5e33b27aa..4d1b9c992 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -1,12 +1,13 @@ const React = require('react'); const classnames = require('classnames'); -const { MainNavBar, MetaItem, MetaPreview, Multiselect } = require('stremio/common'); +const Icon = require('stremio-icons/dom'); +const { Button, MainNavBar, MetaItem, MetaPreview, Multiselect, PaginateInput } = require('stremio/common'); const useDiscover = require('./useDiscover'); const styles = require('./styles'); // TODO render only 4 pickers and a more button that opens a modal with all pickers const Discover = ({ urlParams, queryParams }) => { - const [selectInputs, metaItems, error] = useDiscover(urlParams, queryParams); + const [selectInputs, paginateInput, metaItems, error] = useDiscover(urlParams, queryParams); const [selectedMetaItem, setSelectedMetaItem] = React.useState(null); const metaItemsOnMouseDownCapture = React.useCallback((event) => { event.nativeEvent.buttonBlurPrevented = true; @@ -35,6 +36,19 @@ const Discover = ({ urlParams, queryParams }) => { className={styles['select-input-container']} /> ))} + +
+ { + paginateInput !== null ? + + : + null + }
{ diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index c748337ed..24564e40a 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -4,6 +4,12 @@ multiselect-menu-container: menu-container; } +:import('~stremio/common/PaginateInput/styles.less') { + paginate-prev-button-container: prev-button-container; + paginate-next-button-container: next-button-container; + paginate-multiselect-label: multiselect-label; +} + .discover-container { display: flex; flex-direction: column; @@ -28,21 +34,60 @@ .controls-container { grid-area: controls-area; - display: grid; - grid-template-columns: repeat(auto-fill, 15rem); - grid-gap: 1rem; + display: flex; + flex-direction: row; margin: 2rem 0; padding: 0 2rem; overflow: visible; .select-input-container { + flex-grow: 0; + flex-shrink: 1; + flex-basis: 15rem; height: 3rem; + margin-right: 1rem; .multiselect-menu-container { max-height: calc(3.2rem * 7); overflow: auto; } } + + .filter-container { + flex: none; + width: 3rem; + height: 3rem; + background-color: var(--color-backgroundlighter); + + .filter-icon { + display: block; + width: 1.2rem; + height: 1.2rem; + margin: 0.9rem; + fill: var(--color-surfacelighter); + } + } + + .spacing { + flex: 1; + } + + .paginate-input-container { + flex: none; + margin-right: 1rem; + background-color: var(--color-backgroundlighter); + + .paginate-prev-button-container, .paginate-next-button-container { + width: 3rem; + height: 3rem; + } + + .paginate-multiselect-label { + max-width: 3rem; + white-space: nowrap; + text-overflow: ellipsis; + } + } } .catalog-content-container { @@ -150,10 +195,6 @@ "controls-area" "catalog-content-area"; - .controls-container { - grid-template-columns: repeat(4, 1fr); - } - .catalog-content-container { .meta-items-container { grid-template-columns: repeat(5, 1fr); From d2b81d199ef509ce8ad5ea8b43ed995dc5db5bb9 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 28 Oct 2019 16:32:06 +0200 Subject: [PATCH 090/442] controls in control bar of discover properly aligned --- src/routes/Discover/styles.less | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 24564e40a..ce269b306 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -47,6 +47,14 @@ height: 3rem; margin-right: 1rem; + &:nth-child(n+4) { + display: none; + + &~.filter-container { + display: block; + } + } + .multiselect-menu-container { max-height: calc(3.2rem * 7); overflow: auto; @@ -54,11 +62,16 @@ } .filter-container { + display: none; flex: none; width: 3rem; height: 3rem; background-color: var(--color-backgroundlighter); + &:not(:nth-last-child(2)) { + margin-right: 1rem; + } + .filter-icon { display: block; width: 1.2rem; @@ -74,7 +87,6 @@ .paginate-input-container { flex: none; - margin-right: 1rem; background-color: var(--color-backgroundlighter); .paginate-prev-button-container, .paginate-next-button-container { From 0aa6b1a6a71034d131e6c7a9d5734391af895a56 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 28 Oct 2019 16:32:33 +0200 Subject: [PATCH 091/442] filter button disabled for now --- src/routes/Discover/Discover.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 4d1b9c992..f2635b837 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -36,9 +36,9 @@ const Discover = ({ urlParams, queryParams }) => { className={styles['select-input-container']} /> ))} - + */}
{ paginateInput !== null ? From 307d0c571416a73d914904602416d64692f747e0 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 28 Oct 2019 17:13:31 +0200 Subject: [PATCH 092/442] 'my' category added --- src/routes/Addons/useAddons.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index b8a19066e..f45267c4c 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -30,6 +30,25 @@ const useAddons = (urlParams, queryParams) => { const category = typeof urlParams.category === 'string' && urlParams.category.length > 0 ? urlParams.category : DEFAULT_CATEGORY; const onNewState = () => { const state = core.getState(); + const myAddons = [...new Set( + [].concat(...state.ctx.content.addons.map(addon => addon.manifest.types)) + )] + .map((type) => ( + { + is_selected: urlParams.category === 'my', + name: 'my', + load: { + base: 'https://v3-cinemeta.strem.io/manifest.json', + path: { + resource: 'addon_catalog', + type_name: type, + id: 'my', + extra: [] + } + } + }) + ); + myAddons.forEach(addon => state.addons.catalogs.push(addon)); const selectInputs = [ { 'data-name': 'type', @@ -65,8 +84,11 @@ const useAddons = (urlParams, queryParams) => { } } ]; - const addonsItems = state.addons.content.type === 'Ready' ? state.addons.content.content : []; const installedAddons = state.ctx.is_loaded ? state.ctx.content.addons : []; + const addonsItems = urlParams.category === 'my' && state.ctx.is_loaded ? + installedAddons.filter(addon => addon.manifest.types.includes(urlParams.type)) + : + (state.addons.content.type === 'Ready' ? state.addons.content.content : []); setAddons([addonsItems, selectInputs, installAddon, uninstallAddon, installedAddons]); }; core.on('NewModel', onNewState); From f30c463486431d139fbdefe2286dfee21383b970 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 29 Oct 2019 14:04:48 +0200 Subject: [PATCH 093/442] addons selectInputs swapped --- src/common/routesRegexp.js | 2 +- src/routes/Addons/useAddons.js | 37 +++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index c91fd7f31..7d66a0566 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -25,7 +25,7 @@ const routesRegexp = { }, addons: { regexp: /^\/addons(?:\/([^\/]*?))?(?:\/([^\/]*?))?\/?$/i, - urlParamsNames: ['type', 'category'] + urlParamsNames: ['category', 'type'] }, settings: { regexp: /^\/settings\/?$/i, diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index f45267c4c..4931cfbb3 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -35,7 +35,7 @@ const useAddons = (urlParams, queryParams) => { )] .map((type) => ( { - is_selected: urlParams.category === 'my', + is_selected: urlParams.type === type && urlParams.category === 'my', name: 'my', load: { base: 'https://v3-cinemeta.strem.io/manifest.json', @@ -51,36 +51,41 @@ const useAddons = (urlParams, queryParams) => { myAddons.forEach(addon => state.addons.catalogs.push(addon)); const selectInputs = [ { - 'data-name': 'type', - selected: state.addons.types + 'data-name': 'category', + selected: state.addons.catalogs .filter(({ is_selected }) => is_selected) - .map(({ load }) => JSON.stringify(load)), - options: state.addons.types - .map(({ type_name, load }) => ({ - value: JSON.stringify(load), - label: type_name + .map(({ load }) => load.path.id), + options: state.addons.catalogs + .filter((catalog, index, catalogs) => { + return catalogs.map(ctg => ctg.name).indexOf(catalog.name) === index; + }) + .map(({ name, load }) => ({ + value: load.path.id, + label: name })), onSelect: (event) => { - const load = JSON.parse(event.reactEvent.currentTarget.dataset.value); - window.location = `#/addons/${encodeURIComponent(load.path.type_name)}/${encodeURIComponent(load.path.id)}`; + const load = (state.addons.catalogs.find(({ load: { path: { id } } }) => { + return id === event.reactEvent.currentTarget.dataset.value; + }) || {}).load; + window.location = `#/addons/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; } }, { - 'data-name': 'category', + 'data-name': 'type', selected: state.addons.catalogs .filter(({ is_selected }) => is_selected) .map(({ load }) => JSON.stringify(load)), options: state.addons.catalogs - .filter(({ load: { path: { type_name } } }) => { - return type_name === type; + .filter(({ load: { path: { id } } }) => { + return id === category; }) - .map(({ name, load }) => ({ + .map(({ load }) => ({ value: JSON.stringify(load), - label: name + label: load.path.type_name })), onSelect: (event) => { const load = JSON.parse(event.reactEvent.currentTarget.dataset.value); - window.location = `#/addons/${encodeURIComponent(load.path.type_name)}/${encodeURIComponent(load.path.id)}` + window.location = `#/addons/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; } } ]; From 53e99910691987259cc0781d4320f15a07276936 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 29 Oct 2019 14:32:06 +0200 Subject: [PATCH 094/442] 'all' type added --- src/routes/Addons/useAddons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index 4931cfbb3..e218f0afa 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -31,7 +31,7 @@ const useAddons = (urlParams, queryParams) => { const onNewState = () => { const state = core.getState(); const myAddons = [...new Set( - [].concat(...state.ctx.content.addons.map(addon => addon.manifest.types)) + ['all'].concat(...state.ctx.content.addons.map(addon => addon.manifest.types)) )] .map((type) => ( { @@ -91,7 +91,7 @@ const useAddons = (urlParams, queryParams) => { ]; const installedAddons = state.ctx.is_loaded ? state.ctx.content.addons : []; const addonsItems = urlParams.category === 'my' && state.ctx.is_loaded ? - installedAddons.filter(addon => addon.manifest.types.includes(urlParams.type)) + installedAddons.filter(addon => urlParams.type === 'all' || addon.manifest.types.includes(urlParams.type)) : (state.addons.content.type === 'Ready' ? state.addons.content.content : []); setAddons([addonsItems, selectInputs, installAddon, uninstallAddon, installedAddons]); From 188e64dff6969587553abdd8510ff5ab75aea9fc Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Tue, 29 Oct 2019 14:49:46 +0200 Subject: [PATCH 095/442] Removed useless option --- src/routes/Settings/constants.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/Settings/constants.js b/src/routes/Settings/constants.js index 0d3439446..9a3a95b9d 100644 --- a/src/routes/Settings/constants.js +++ b/src/routes/Settings/constants.js @@ -15,7 +15,6 @@ const settingsSections = { { 'id': 'subtitles_outline_color', 'header': 'Subtitles outline color', 'label': 'Subtitles outline color', 'type': 'color' }, { 'id': 'autoplay_next_vid', 'label': 'Auto-play next episode', 'type': 'checkbox' }, { 'id': 'pause_on_lost_focus', 'label': 'Pause playback when not in focus', 'type': 'checkbox' }, - { 'id': 'hardware-accelerated_decoding', 'label': 'Hardware-accelerated decoding', 'type': 'checkbox' }, { 'id': 'use_external_player', 'label': 'Launch player in a separate window (advanced)', 'type': 'checkbox' }, ], 'Streaming': [ From 0c62d79312b50b7854997da894e27c737d1d788a Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Tue, 29 Oct 2019 14:50:35 +0200 Subject: [PATCH 096/442] New type of core messages. Better events --- src/services/Core/Core.js | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/services/Core/Core.js b/src/services/Core/Core.js index 1489be668..0999b75f0 100644 --- a/src/services/Core/Core.js +++ b/src/services/Core/Core.js @@ -1,6 +1,34 @@ -const EventEmitter = require('events'); +// const EventEmitter = require('events'); const { default: init, ContainerService } = require('stremio-core-web'); +// Slightly better event handling +class EventEmitter { + constructor() { + this._handlers = {}; + } + _handlersFor(event) { + return this._handlers[event] || []; + } + on(event, handler) { + this._handlers[event] = this._handlersFor(event).concat(handler); + } + off(event, handler) { + console.log('Before off', this._handlersFor(event)) + this._handlers[event] = this._handlersFor(event).filter(event => event !== handler); + console.log('After off', this._handlersFor(event)) + } + emit(event, args) { + this._handlersFor(event).forEach(handler => { + try { + handler(args); + } + catch (e) { + console.log('Event error', event, args, e); + } + }); + } +} + function Core() { let active = false; let error = null; @@ -52,12 +80,12 @@ function Core() { function off(name, listener) { events.off(name, listener); } - function dispatch({ action, args } = {}) { + function dispatch(args, model = 'All') { if (!active) { return; } - containerService.dispatch({ action, args }); + containerService.dispatch({ model, args }); } function getState() { if (!active) { From b1f917e3a93d92c867c2daadf4e6b6faad1eb514 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Tue, 29 Oct 2019 14:51:03 +0200 Subject: [PATCH 097/442] New loaded state --- .../Settings/SectionsList/SectionsList.js | 2 +- src/routes/Settings/useSettings.js | 26 ++++++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/routes/Settings/SectionsList/SectionsList.js b/src/routes/Settings/SectionsList/SectionsList.js index 509c0a498..d56de298a 100644 --- a/src/routes/Settings/SectionsList/SectionsList.js +++ b/src/routes/Settings/SectionsList/SectionsList.js @@ -180,7 +180,7 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre
-
{'Streaming server is ' + (preferences.streaming_error ? 'not ' : '') + 'available. Reason: ' + preferences.streaming_error}
+
{'Streaming server is ' + (preferences.streaming_error ? 'not ' : '') + 'available.'}{preferences.streaming_error && ' Reason: ' + preferences.streaming_error}
diff --git a/src/routes/Settings/useSettings.js b/src/routes/Settings/useSettings.js index 9af135cd4..4f71eba0e 100644 --- a/src/routes/Settings/useSettings.js +++ b/src/routes/Settings/useSettings.js @@ -1,29 +1,35 @@ const React = require('react'); const { useServices } = require('stremio/services'); -module.exports = () => { - const IGNORED_SETTINGS = Object.freeze(['user', 'streaming']); +const IGNORED_SETTINGS = Object.freeze(['user', 'streaming']); +module.exports = () => { const { core } = useServices(); - const [settings, setSettings] = React.useState({ streaming: {} }); + + const [settings, setSettings] = React.useState({ + user: null, + streaming: {}, + streaming_loaded: false, + streaming_error: "" + }); React.useEffect(() => { const onNewState = () => { - const state = core.getState() + const { ctx, streaming_server_settings } = core.getState() try { const newSettings = { ...settings, - ...state.ctx.content.settings, - user: state.ctx.content.auth ? state.ctx.content.auth.user : null, - streaming: state.streaming_server_settings && state.streaming_server_settings.ready || {}, - streaming_loaded: state.streaming_server_settings && (state.streaming_server_settings.error || state.streaming_server_settings.ready), - streaming_error: state.streaming_server_settings && state.streaming_server_settings.error || "", + ...ctx.content.settings, + user: ctx.content.auth ? ctx.content.auth.user : null, + streaming: streaming_server_settings && streaming_server_settings.ready || {}, + streaming_loaded: streaming_server_settings && !!(streaming_server_settings.error || streaming_server_settings.ready), + streaming_error: streaming_server_settings && streaming_server_settings.error || "", }; setSettings(newSettings); } catch (e) { console.log('Cannot update settings state', e); } - } + }; const onStoreError = ({ event, args }) => { if (event !== "SettingsStoreError") return; // TODO: Notify with maybe a toast? From eb19a3b38886917b0861d1b59f681f55c554a786 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 29 Oct 2019 16:37:45 +0200 Subject: [PATCH 098/442] check for protected addon --- src/routes/Addons/Addons.js | 2 +- src/routes/Addons/useSelectedAddon.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 206e8cba1..a69ad3cb2 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -62,7 +62,7 @@ const Addons = ({ urlParams, queryParams }) => { }
{ - selectedAddon !== null ? + selectedAddon !== null && !selectedAddon.flags.protected ?
setInstalledAddon(selectedAddon) ? uninstallSelectedAddon(selectedAddon) : installSelectedAddon(selectedAddon)} /> diff --git a/src/routes/Addons/useSelectedAddon.js b/src/routes/Addons/useSelectedAddon.js index c0937277d..ce4f49ec5 100644 --- a/src/routes/Addons/useSelectedAddon.js +++ b/src/routes/Addons/useSelectedAddon.js @@ -12,7 +12,7 @@ const useSelectedAddon = (transportUrl) => { return; } - fetch(transportUrl) + fetch(transportUrl) // todo .then((resp) => resp.json()) .then((manifest) => setAddon({ manifest, transportUrl, flags: {} })); }, [transportUrl]); From 67fd80a63ecea3600c86a280d4b69e60e3d8a4b8 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 29 Oct 2019 17:20:09 +0200 Subject: [PATCH 099/442] isProtected property added --- src/routes/Addons/Addon/Addon.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/routes/Addons/Addon/Addon.js b/src/routes/Addons/Addon/Addon.js index 496a27168..2866a4881 100644 --- a/src/routes/Addons/Addon/Addon.js +++ b/src/routes/Addons/Addon/Addon.js @@ -5,7 +5,7 @@ const Icon = require('stremio-icons/dom'); const { Button } = require('stremio/common'); const styles = require('./styles'); -const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, toggle }) => { +const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, isProtected, toggle }) => { const onKeyUp = React.useCallback((event) => { if (event.key === 'Enter' && typeof toggle === 'function') { toggle(event); @@ -52,7 +52,7 @@ const Addon = ({ className, id, name, logo, description, types, version, transpo }
-
{ - selectedAddon !== null && !selectedAddon.flags.protected ? + selectedAddon !== null ?
setInstalledAddon(selectedAddon) ? uninstallSelectedAddon(selectedAddon) : installSelectedAddon(selectedAddon)} /> diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index e218f0afa..a40f9a413 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -7,15 +7,16 @@ const DEFAULT_CATEGORY = 'thirdparty'; const useAddons = (urlParams, queryParams) => { const { core } = useServices(); const [addons, setAddons] = React.useState([[], []]); - const installAddon = React.useCallback(descriptor => + const installAddon = React.useCallback(descriptor => { core.dispatch({ action: 'AddonOp', args: { addonOp: 'Install', args: descriptor } - }), []); - const uninstallAddon = React.useCallback(descriptor => + }) + }, []); + const uninstallAddon = React.useCallback(descriptor => { core.dispatch({ action: 'AddonOp', args: { @@ -24,7 +25,8 @@ const useAddons = (urlParams, queryParams) => { transport_url: descriptor.transportUrl } } - }), []); + }) + }, []); React.useEffect(() => { const type = typeof urlParams.type === 'string' && urlParams.type.length > 0 ? urlParams.type : DEFAULT_TYPE; const category = typeof urlParams.category === 'string' && urlParams.category.length > 0 ? urlParams.category : DEFAULT_CATEGORY; @@ -49,6 +51,9 @@ const useAddons = (urlParams, queryParams) => { }) ); myAddons.forEach(addon => state.addons.catalogs.push(addon)); + const selectAddon = (transportUrl) => { + window.location = `#/addons/${category}/${type}?addon=${transportUrl}`; + } const selectInputs = [ { 'data-name': 'category', @@ -64,9 +69,9 @@ const useAddons = (urlParams, queryParams) => { label: name })), onSelect: (event) => { - const load = (state.addons.catalogs.find(({ load: { path: { id } } }) => { + const load = state.addons.catalogs.find(({ load: { path: { id } } }) => { return id === event.reactEvent.currentTarget.dataset.value; - }) || {}).load; + }).load; window.location = `#/addons/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; } }, @@ -94,7 +99,7 @@ const useAddons = (urlParams, queryParams) => { installedAddons.filter(addon => urlParams.type === 'all' || addon.manifest.types.includes(urlParams.type)) : (state.addons.content.type === 'Ready' ? state.addons.content.content : []); - setAddons([addonsItems, selectInputs, installAddon, uninstallAddon, installedAddons]); + setAddons([addonsItems, selectInputs, selectAddon, installAddon, uninstallAddon, installedAddons]); }; core.on('NewModel', onNewState); core.dispatch({ From bb1a4886c3f9e9e2e58fb77fb9a34010f1ca2e06 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Wed, 30 Oct 2019 15:29:03 +0200 Subject: [PATCH 101/442] open/close SharePrompt works --- src/common/SharePrompt/SharePrompt.js | 15 ++++---- src/routes/Addons/Addon/Addon.js | 7 ++-- src/routes/Addons/Addons.js | 50 +++++++++++++++++++++++---- src/routes/Addons/styles.less | 15 +++++--- src/routes/Addons/useSelectedAddon.js | 2 +- 5 files changed, 67 insertions(+), 22 deletions(-) diff --git a/src/common/SharePrompt/SharePrompt.js b/src/common/SharePrompt/SharePrompt.js index 4a1abc80b..eb0ade0f1 100644 --- a/src/common/SharePrompt/SharePrompt.js +++ b/src/common/SharePrompt/SharePrompt.js @@ -2,14 +2,14 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); -const { useFocusable } = require('stremio-router'); +const { useRouteFocused } = require('stremio-router'); const Button = require('stremio/common/Button'); const TextInput = require('stremio/common/TextInput'); const styles = require('./styles'); -const SharePrompt = ({ className, label, url, close }) => { +const SharePrompt = ({ className, label, url, close, onClick }) => { const inputRef = React.useRef(null); - const focusable = useFocusable(); + const focusable = useRouteFocused(); const copyToClipboard = React.useCallback(() => { inputRef.current.select(); document.execCommand('copy'); @@ -28,9 +28,9 @@ const SharePrompt = ({ className, label, url, close }) => { }; }, [close, focusable]); return ( -
-
{label}
@@ -60,7 +60,8 @@ SharePrompt.propTypes = { className: PropTypes.string, label: PropTypes.string.isRequired, url: PropTypes.string.isRequired, - close: PropTypes.func + close: PropTypes.func, + onClick: PropTypes.func }; module.exports = SharePrompt; diff --git a/src/routes/Addons/Addon/Addon.js b/src/routes/Addons/Addon/Addon.js index 2866a4881..765449bb8 100644 --- a/src/routes/Addons/Addon/Addon.js +++ b/src/routes/Addons/Addon/Addon.js @@ -5,7 +5,7 @@ const Icon = require('stremio-icons/dom'); const { Button } = require('stremio/common'); const styles = require('./styles'); -const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, isProtected, toggle }) => { +const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, isProtected, toggle, onShareButtonClicked }) => { const onKeyUp = React.useCallback((event) => { if (event.key === 'Enter' && typeof toggle === 'function') { toggle(event); @@ -55,7 +55,7 @@ const Addon = ({ className, id, name, logo, description, types, version, transpo - @@ -75,7 +75,8 @@ Addon.propTypes = { transportUrl: PropTypes.string, installed: PropTypes.bool, isProtected: PropTypes.bool, - toggle: PropTypes.func + toggle: PropTypes.func, + onShareButtonClicked: PropTypes.func }; module.exports = Addon; diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 4d8657b59..68e534245 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -1,7 +1,8 @@ const React = require('react'); +const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { Modal } = require('stremio-router'); -const { Button, Multiselect, NavBar, TextInput } = require('stremio/common'); +const { Button, Multiselect, NavBar, TextInput, SharePrompt } = require('stremio/common'); const Addon = require('./Addon'); const AddonPrompt = require('./AddonPrompt'); const useAddons = require('./useAddons'); @@ -15,12 +16,14 @@ const Addons = ({ urlParams, queryParams }) => { }, []); const [addons, dropdowns, setSelectedAddon, installSelectedAddon, uninstallSelectedAddon, installedAddons] = useAddons(urlParams, queryParams); const [selectedAddon, clearSelectedAddon] = useSelectedAddon(queryParams.get('addon')); - const addonPromptModalBackgroundOnClick = React.useCallback((event) => { + const [sharedAddon, setSharedAddon] = React.useState(null); + const promptModalBackgroundOnClick = React.useCallback((event) => { if (!event.nativeEvent.clearSelectedAddonPrevented) { clearSelectedAddon(); + setSharedAddon(null); } }, []); - const addonPromptOnClick = React.useCallback((event) => { + const promptOnClick = React.useCallback((event) => { event.nativeEvent.clearSelectedAddonPrevented = true; }, []); const setInstalledAddon = React.useCallback((currentAddon) => { @@ -57,15 +60,48 @@ const Addons = ({ urlParams, queryParams }) => { (typeof addon.manifest.description === 'string' && addon.manifest.description.toLowerCase().includes(query.toLowerCase())) )) .map((addon, index) => ( - setSelectedAddon(addon.transportUrl)} /> + setSelectedAddon(addon.transportUrl)} + onShareButtonClicked={() => setSharedAddon(addon)} + /> )) }
{ selectedAddon !== null ? - -
- setInstalledAddon(selectedAddon) ? uninstallSelectedAddon(selectedAddon) : installSelectedAddon(selectedAddon)} /> + +
+ setInstalledAddon(selectedAddon) ? uninstallSelectedAddon(selectedAddon) : installSelectedAddon(selectedAddon)} + /> +
+
+ : + null + } + { + sharedAddon !== null ? + +
+ setSharedAddon(null)} + onClick={promptOnClick} + />
: diff --git a/src/routes/Addons/styles.less b/src/routes/Addons/styles.less index 8e32b6f70..2fbd3e928 100644 --- a/src/routes/Addons/styles.less +++ b/src/routes/Addons/styles.less @@ -117,25 +117,32 @@ } } -.addon-prompt-modal-container { +.prompt-modal-container { display: flex; align-items: center; justify-content: center; background-color: var(--color-background60); - .addon-prompt-container { + .prompt-container { flex: none; display: flex; flex-direction: column; justify-content: center; - width: 50rem; height: 80%; - .addon-prompt { + .prompt { flex-grow: 0; flex-shrink: 1; flex-basis: auto; align-self: stretch; } } + + .addon-prompt-container { + width: 50rem; + } + + .share-prompt-container { + width: 30rem; + } } \ No newline at end of file diff --git a/src/routes/Addons/useSelectedAddon.js b/src/routes/Addons/useSelectedAddon.js index ce4f49ec5..4d47137f5 100644 --- a/src/routes/Addons/useSelectedAddon.js +++ b/src/routes/Addons/useSelectedAddon.js @@ -21,7 +21,7 @@ const useSelectedAddon = (transportUrl) => { const { pathname, search } = UrlUtils.parse(locationHash.slice(1)); const queryParams = new URLSearchParams(search); queryParams.delete('addon'); - if (search && queryParams) { + if (!queryParams.values().next().done) { window.location.replace(`#${pathname}?${queryParams.toString()}`); } else { From 7b2ed24c37d38eae8f798d87e0c59904017dff2b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 30 Oct 2019 15:39:51 +0200 Subject: [PATCH 102/442] map dates to date object --- src/routes/Discover/useDiscover.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 6966c8630..fcb22ac33 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -194,7 +194,13 @@ const useCatalog = (urlParams, queryParams) => { } : null; - const items = state.discover.content.type === 'Ready' ? state.discover.content.content : null; + const items = state.discover.content.type === 'Ready' ? + state.discover.content.content.map((metaItem) => ({ + ...metaItem, + released: new Date(metaItem.released) + })) + : + null; const error = state.discover.content.type === 'Err' ? JSON.stringify(state.discover.content.content) : null; setDiscover([selectInputs, paginateInput, items, error]); }; From f65f30928ed978ce743f45d94d473af5e8fd1cd8 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 30 Oct 2019 15:51:55 +0200 Subject: [PATCH 103/442] avoid spread props on MetaItem --- src/routes/Discover/Discover.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index f2635b837..257b92cec 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -60,12 +60,15 @@ const Discover = ({ urlParams, queryParams }) => { Array.isArray(metaItems) ? metaItems.length > 0 ?
- {metaItems.map((metaItem, index) => ( + {metaItems.map(({ id, type, name, poster, posterShape }, index) => ( ))}
From 5dedcb40f9f3144afb9cc77f0ec325c70ae752fc Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 30 Oct 2019 20:19:07 +0200 Subject: [PATCH 104/442] pagination ux improved --- src/routes/Discover/useDiscover.js | 33 ++++++++---------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index fcb22ac33..47f437708 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -130,33 +130,18 @@ const useCatalog = (urlParams, queryParams) => { return { title, options, selected, renderLabelText, onSelect }; }) ]; - const paginateInput = state.discover.load_next !== null || state.discover.load_prev !== null ? + const paginateInput = state.discover.load_next !== null || state.discover.load_prev !== null || state.discover.selected.some(({ name }) => name === 'skip') ? { - selected: state.discover.load_next !== null ? - state.discover.load_next.path.extra.reduce((page, [name, value]) => { - if (name === 'skip') { - const parsedValue = parseInt(value); - if (!isNaN(parsedValue)) { - return Math.floor(parsedValue / 100); - } + selected: state.discover.selected.path.extra.reduce((page, [name, value]) => { + if (name === 'skip') { + const parsedValue = parseInt(value); + if (!isNaN(parsedValue)) { + return Math.floor(parsedValue / 100) + 1; } + } - return page; - }, 1) - : - state.discover.load_prev !== null ? - state.discover.load_prev.path.extra.reduce((page, [name, value]) => { - if (name === 'skip') { - const parsedValue = parseInt(value); - if (!isNaN(parsedValue)) { - return Math.floor(parsedValue / 100) + 2; - } - } - - return page; - }, 1) - : - 1, + return page; + }, 1), onSelect: (event) => { if (event.value < 1) { return; From b3e993dad011d77a638c915b47c6e64ee66f5930 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 30 Oct 2019 20:48:26 +0200 Subject: [PATCH 105/442] MainNavBar wrapped in memo --- src/common/MainNavBar/MainNavBar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/MainNavBar/MainNavBar.js b/src/common/MainNavBar/MainNavBar.js index 9f2db6a02..c6920ce42 100644 --- a/src/common/MainNavBar/MainNavBar.js +++ b/src/common/MainNavBar/MainNavBar.js @@ -8,7 +8,7 @@ const TABS = [ { label: 'Library', icon: 'ic_library', href: '#/library' } ]; -const MainNavBar = ({ className }) => { +const MainNavBar = React.memo(({ className }) => { return ( { navMenu={true} /> ); -}; +}); MainNavBar.propTypes = { className: PropTypes.string From 680815197db97ca6bcf7e7fcdec1752988862ebb Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 31 Oct 2019 11:12:25 +0200 Subject: [PATCH 106/442] paginate input fixed in discover --- src/routes/Discover/useDiscover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 47f437708..4abe864f9 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -130,7 +130,7 @@ const useCatalog = (urlParams, queryParams) => { return { title, options, selected, renderLabelText, onSelect }; }) ]; - const paginateInput = state.discover.load_next !== null || state.discover.load_prev !== null || state.discover.selected.some(({ name }) => name === 'skip') ? + const paginateInput = state.discover.load_next !== null || state.discover.load_prev !== null || state.discover.selected.path.extra.some(([name]) => name === 'skip') ? { selected: state.discover.selected.path.extra.reduce((page, [name, value]) => { if (name === 'skip') { From e9745ea905bfac6c7e49721e3e5c88d325f669e4 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 31 Oct 2019 13:06:11 +0200 Subject: [PATCH 107/442] add addon prompt implemented --- src/common/NavBar/NavMenu/NavMenu.js | 2 +- src/routes/Addons/Addons.js | 60 +++++++++- src/routes/Addons/styles.less | 113 +++++++++++++++++++ src/routes/Addons/useSelectedAddon.js | 3 +- src/routes/Detail/StreamsList/StreamsList.js | 2 +- 5 files changed, 172 insertions(+), 8 deletions(-) diff --git a/src/common/NavBar/NavMenu/NavMenu.js b/src/common/NavBar/NavMenu/NavMenu.js index b8126116a..fa7f5db20 100644 --- a/src/common/NavBar/NavMenu/NavMenu.js +++ b/src/common/NavBar/NavMenu/NavMenu.js @@ -64,7 +64,7 @@ const NavMenu = ({ className }) => { {dropdowns.map((dropdown, index) => ( @@ -47,7 +71,7 @@ const Addons = ({ urlParams, queryParams }) => { @@ -72,6 +96,32 @@ const Addons = ({ urlParams, queryParams }) => { )) }
+ { + addedAddon ? + +
+
+ +
+
Add add-on
+ +
+ + +
+
+
+
+
+ : + null + } { selectedAddon !== null ? diff --git a/src/routes/Addons/styles.less b/src/routes/Addons/styles.less index 2fbd3e928..876e88301 100644 --- a/src/routes/Addons/styles.less +++ b/src/routes/Addons/styles.less @@ -138,6 +138,119 @@ } } + .add-addon-prompt-container { + width: 30rem; + + .add-addon-prompt { + position: relative; + z-index: 0; + display: flex; + flex-direction: column; + padding: 2.4rem 0; + background-color: var(--color-surfacelighter); + + .close-button-container { + position: absolute; + top: 0.4rem; + right: 0.4rem; + z-index: 1; + width: 2rem; + height: 2rem; + padding: 0.4rem; + + &:hover { + background-color: var(--color-surfacelight); + } + + .icon { + display: block; + width: 100%; + height: 100%; + fill: var(--color-backgrounddarker); + } + } + + .add-addon-prompt-content { + padding: 0 2.4rem; + + .add-addon-prompt-label { + margin-bottom: 1.4rem; + font-size: 1.3rem; + color: var(--color-backgrounddarker); + } + + .url-content { + flex: 1; + width: 100%; + padding: 0.5rem; + font-size: 0.9rem; + color: var(--color-surfacedark); + border: thin solid var(--color-surface); + } + + .buttons-container { + flex: none; + align-self: stretch; + display: flex; + flex-direction: row; + margin-top: 2rem; + + .button-container { + flex: 1; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + height: 3rem; + padding: 0 1rem; + + &:first-child { + margin-right: 2rem; + } + + .label { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + max-height: 2.4em; + font-size: 1.2rem; + text-align: center; + } + } + + .cancel-button { + outline-color: var(--color-surfacedark); + outline-style: solid; + + &:hover, &:focus { + background-color: var(--color-surfacelight); + } + + .label { + color: var(--color-backgrounddarker); + } + } + + .add-button { + background-color: var(--color-signal5); + + &:hover, &:focus { + filter: brightness(1.2); + } + + &:focus { + outline-color: var(--color-surfacedarker); + } + + .label { + color: var(--color-surfacelighter); + } + } + } + } + } + } + .addon-prompt-container { width: 50rem; } diff --git a/src/routes/Addons/useSelectedAddon.js b/src/routes/Addons/useSelectedAddon.js index 4d47137f5..edf12cbc9 100644 --- a/src/routes/Addons/useSelectedAddon.js +++ b/src/routes/Addons/useSelectedAddon.js @@ -21,7 +21,8 @@ const useSelectedAddon = (transportUrl) => { const { pathname, search } = UrlUtils.parse(locationHash.slice(1)); const queryParams = new URLSearchParams(search); queryParams.delete('addon'); - if (!queryParams.values().next().done) { + queryParams.delete('null'); + if ([...queryParams].length !== 0) { window.location.replace(`#${pathname}?${queryParams.toString()}`); } else { diff --git a/src/routes/Detail/StreamsList/StreamsList.js b/src/routes/Detail/StreamsList/StreamsList.js index 4d0102d91..6b6ee8a26 100644 --- a/src/routes/Detail/StreamsList/StreamsList.js +++ b/src/routes/Detail/StreamsList/StreamsList.js @@ -31,7 +31,7 @@ const StreamsList = ({ className, metaItem }) => {
); From d96573b8d9727e98df11a1dc018138545fe2115f Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 31 Oct 2019 13:16:05 +0200 Subject: [PATCH 108/442] check the length of url --- src/routes/Addons/Addons.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index f5aa2c39c..7d435cca9 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -24,8 +24,12 @@ const Addons = ({ urlParams, queryParams }) => { setAddedAddon(true); }, []); const onAddButtonClicked = React.useCallback(() => { - setSelectedAddon(inputRef.current.value); - setAddedAddon(false); + if (inputRef.current.value.length > 0) { + setSelectedAddon(inputRef.current.value); + setAddedAddon(false); + } else { + alert('TODO: Error message'); + } }, [setSelectedAddon]); React.useEffect(() => { const onKeyUp = (event) => { From f84fc463e60361be7b7879c835aac88ae02a0307 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 31 Oct 2019 13:36:44 +0200 Subject: [PATCH 109/442] discover initial state fixed --- src/routes/Discover/useDiscover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 4abe864f9..19b40590b 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -9,7 +9,7 @@ const PAGE_SIZE = 100; const useCatalog = (urlParams, queryParams) => { const { core } = useServices(); - const [discover, setDiscover] = React.useState([[], null, null]); + const [discover, setDiscover] = React.useState([[], null, null, null]); React.useEffect(() => { const addonTransportUrl = typeof urlParams.addonTransportUrl === 'string' ? urlParams.addonTransportUrl : DEFAULT_ADDON_TRANSPORT_URL; const catalogId = typeof urlParams.catalogId === 'string' ? urlParams.catalogId : DEFAULT_CATALOG_ID; From 8dc98ec1d2538c2341333361852602818c118c32 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 31 Oct 2019 13:39:51 +0200 Subject: [PATCH 110/442] empty catalog handled by core --- src/routes/Discover/Discover.js | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 257b92cec..88037cdb3 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -58,24 +58,19 @@ const Discover = ({ urlParams, queryParams }) => {
: Array.isArray(metaItems) ? - metaItems.length > 0 ? -
- {metaItems.map(({ id, type, name, poster, posterShape }, index) => ( - - ))} -
- : -
- Empty catalog -
+
+ {metaItems.map(({ id, type, name, poster, posterShape }, index) => ( + + ))} +
:
Loading From e204b2f7f01305d71df9f74309f3a9e02e4c2e75 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 31 Oct 2019 13:45:21 +0200 Subject: [PATCH 111/442] queryParams fixed --- src/routes/Addons/useSelectedAddon.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/routes/Addons/useSelectedAddon.js b/src/routes/Addons/useSelectedAddon.js index edf12cbc9..b0e6e6dc5 100644 --- a/src/routes/Addons/useSelectedAddon.js +++ b/src/routes/Addons/useSelectedAddon.js @@ -12,16 +12,15 @@ const useSelectedAddon = (transportUrl) => { return; } - fetch(transportUrl) // todo + fetch(transportUrl) // TODO .then((resp) => resp.json()) .then((manifest) => setAddon({ manifest, transportUrl, flags: {} })); }, [transportUrl]); const clear = React.useCallback(() => { if (active) { const { pathname, search } = UrlUtils.parse(locationHash.slice(1)); - const queryParams = new URLSearchParams(search); + const queryParams = new URLSearchParams(search || ''); queryParams.delete('addon'); - queryParams.delete('null'); if ([...queryParams].length !== 0) { window.location.replace(`#${pathname}?${queryParams.toString()}`); } From 5620ada5450053566ae15310e9486bde2eb62fe9 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 31 Oct 2019 14:04:38 +0200 Subject: [PATCH 112/442] error message formatted --- src/routes/Discover/Discover.js | 4 ++-- src/routes/Discover/useDiscover.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 88037cdb3..79654f2ab 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -52,9 +52,9 @@ const Discover = ({ urlParams, queryParams }) => {
{ - error ? + error !== null ?
- {error} + {error.type}{error.type === 'Other' ? ` - ${error.content}` : null}
: Array.isArray(metaItems) ? diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 19b40590b..b382d507c 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -186,7 +186,7 @@ const useCatalog = (urlParams, queryParams) => { })) : null; - const error = state.discover.content.type === 'Err' ? JSON.stringify(state.discover.content.content) : null; + const error = state.discover.content.type === 'Err' ? state.discover.content.content : null; setDiscover([selectInputs, paginateInput, items, error]); }; core.on('NewModel', onNewModel); From 1a01242fef7e6336eab24c531706f4c75eb4fccf Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 31 Oct 2019 14:45:13 +0200 Subject: [PATCH 113/442] isProtected property dropped --- src/routes/Addons/Addon/Addon.js | 5 ++--- src/routes/Addons/Addons.js | 6 +----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/routes/Addons/Addon/Addon.js b/src/routes/Addons/Addon/Addon.js index 765449bb8..023c17732 100644 --- a/src/routes/Addons/Addon/Addon.js +++ b/src/routes/Addons/Addon/Addon.js @@ -5,7 +5,7 @@ const Icon = require('stremio-icons/dom'); const { Button } = require('stremio/common'); const styles = require('./styles'); -const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, isProtected, toggle, onShareButtonClicked }) => { +const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, toggle, onShareButtonClicked }) => { const onKeyUp = React.useCallback((event) => { if (event.key === 'Enter' && typeof toggle === 'function') { toggle(event); @@ -52,7 +52,7 @@ const Addon = ({ className, id, name, logo, description, types, version, transpo }
- */} +
{ paginateInput !== null ? @@ -88,6 +92,14 @@ const Discover = ({ urlParams, queryParams }) => {
}
+ { + filtersModalOpen ? + + {/* TODO */} + + : + null + }
); }; From 4f944c2a68ca47f0d649a2d0145e6339b2d196c3 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Thu, 31 Oct 2019 16:34:30 +0200 Subject: [PATCH 116/442] Easier button styles; Keyboard handling; Better demo --- src/common/ModalDialog/ModalDialog.js | 25 ++++-- src/common/ModalDialog/styles.less | 94 +++++++++++--------- storybook/stories/ModalDialog/ModalDialog.js | 68 +++++++++----- storybook/stories/ModalDialog/styles.less | 57 ++++++------ 4 files changed, 146 insertions(+), 98 deletions(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index c12442c37..32f76a468 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -6,14 +6,27 @@ const Icon = require('stremio-icons/dom'); const { Modal } = require('stremio-router'); const styles = require('./styles'); -const ModalDialog = ({ className, children, title, buttons, visible, onClose }) => { +const ModalDialog = ({ className, children, title, buttons, onClose }) => { + // Close with the Escape key + // TODO: Maybe we should consider a global actions mapping so the 'close' key can be globbaly changed + React.useEffect(() => { + const onKeyUp = (event) => { + if (event.key === 'Escape' && typeof onClose === 'function') { + onClose(); + } + }; + window.addEventListener('keyup', onKeyUp); + return () => { + window.removeEventListener('keyup', onKeyUp); + }; + }, [onClose]); const onModalContainerClick = React.useCallback(event => { - if(event.target === event.currentTarget) { + if (event.target === event.currentTarget && typeof onClose === 'function') { onClose(event); } - }); + }, [onClose]); return ( - +
{Array.isArray(buttons) && buttons.length ? buttons.map((button, key) => ( - +
+ + { + modalVisible + ? + + {modalDummyContents} + + : + null + } - - - - {modalDummyContents} - - - {modalDummyContents} - - + + { + modalBVisible + ? + + {modalDummyContents} + + : + null + } +
); }); \ No newline at end of file diff --git a/storybook/stories/ModalDialog/styles.less b/storybook/stories/ModalDialog/styles.less index d6ae29b64..91e9557e6 100644 --- a/storybook/stories/ModalDialog/styles.less +++ b/storybook/stories/ModalDialog/styles.less @@ -1,39 +1,8 @@ -.button { - display: inline-block; - background-color: var(--color-signal3); - width: 15rem; - text-align: center; - padding: 1rem; - margin: .5rem; -} - .modal-dialog { width: 45rem; - .content-container { - display: flex; - flex-flow: row; - margin: 0 -0.5rem; - - .content-column { - flex: 1 0 0; - padding: 0 0.5rem; - - p { - text-align: justify; - } - } - } .custom-button { - display: flex; - align-items: center; - justify-content: center; - flex: 1 0 0; - text-align: center; - color: var(--color-surfacelighter); background-color: var(--color-signal3); - padding: 1rem; - margin: 0.5rem; &:hover { background-color: var(--color-signal380); @@ -51,4 +20,30 @@ margin-right: 0.5rem; } } + + // This is only for the content. Not relevant for the demo + .content-container { + display: flex; + flex-flow: row; + margin: 0 -0.5rem; + + .content-column { + flex: 1 0 0; + padding: 0 0.5rem; + + p { + text-align: justify; + } + } + } } + +// This is only for the buttons that show the modals. Not relevant for the demo +.show-modal-button { + display: inline-block; + background-color: var(--color-signal4); + width: 15rem; + text-align: center; + padding: 1rem; + margin: .5rem; +} \ No newline at end of file From 80070aa5ec76192bbc734aee080d94593cdb44b0 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 31 Oct 2019 16:38:05 +0200 Subject: [PATCH 117/442] formatting --- src/common/routesRegexp.js | 2 +- src/routes/Addons/Addons.js | 2 +- src/routes/Addons/useAddons.js | 30 ++++++++++++++------------- src/routes/Addons/useSelectedAddon.js | 3 +-- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index 7d66a0566..8896ca081 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -24,7 +24,7 @@ const routesRegexp = { urlParamsNames: ['type', 'id', 'videoId'] }, addons: { - regexp: /^\/addons(?:\/([^\/]*?))?(?:\/([^\/]*?))?\/?$/i, + regexp: /^\/addons(?:\/([^\/]*?))?(?:\/([^\/]*?))?\/?$/i, // TODO both are required or none urlParamsNames: ['category', 'type'] }, settings: { diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 5bc51e4fc..dcc1c9a1d 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -16,7 +16,7 @@ const Addons = ({ urlParams, queryParams }) => { const queryOnChange = React.useCallback((event) => { setQuery(event.currentTarget.value); }, []); - const [addons, dropdowns, setSelectedAddon, installSelectedAddon, uninstallSelectedAddon, installedAddons] = useAddons(urlParams, queryParams); + const [[addons, dropdowns, setSelectedAddon, installedAddons], installSelectedAddon, uninstallSelectedAddon] = useAddons(urlParams, queryParams); const [addedAddon, setAddedAddon] = React.useState(false); const [selectedAddon, clearSelectedAddon] = useSelectedAddon(queryParams.get('addon')); const [sharedAddon, setSharedAddon] = React.useState(null); diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index a40f9a413..659dbb612 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -6,7 +6,7 @@ const DEFAULT_CATEGORY = 'thirdparty'; const useAddons = (urlParams, queryParams) => { const { core } = useServices(); - const [addons, setAddons] = React.useState([[], []]); + const [addons, setAddons] = React.useState([[], [], [], []]); const installAddon = React.useCallback(descriptor => { core.dispatch({ action: 'AddonOp', @@ -14,7 +14,7 @@ const useAddons = (urlParams, queryParams) => { addonOp: 'Install', args: descriptor } - }) + }); }, []); const uninstallAddon = React.useCallback(descriptor => { core.dispatch({ @@ -25,14 +25,14 @@ const useAddons = (urlParams, queryParams) => { transport_url: descriptor.transportUrl } } - }) + }); }, []); React.useEffect(() => { const type = typeof urlParams.type === 'string' && urlParams.type.length > 0 ? urlParams.type : DEFAULT_TYPE; const category = typeof urlParams.category === 'string' && urlParams.category.length > 0 ? urlParams.category : DEFAULT_CATEGORY; const onNewState = () => { const state = core.getState(); - const myAddons = [...new Set( + [...new Set( ['all'].concat(...state.ctx.content.addons.map(addon => addon.manifest.types)) )] .map((type) => ( @@ -49,14 +49,13 @@ const useAddons = (urlParams, queryParams) => { } } }) - ); - myAddons.forEach(addon => state.addons.catalogs.push(addon)); + ) + .forEach(addon => state.addons.catalogs.push(addon)); const selectAddon = (transportUrl) => { window.location = `#/addons/${category}/${type}?addon=${transportUrl}`; - } + }; const selectInputs = [ { - 'data-name': 'category', selected: state.addons.catalogs .filter(({ is_selected }) => is_selected) .map(({ load }) => load.path.id), @@ -69,6 +68,7 @@ const useAddons = (urlParams, queryParams) => { label: name })), onSelect: (event) => { + // TODO event.value const load = state.addons.catalogs.find(({ load: { path: { id } } }) => { return id === event.reactEvent.currentTarget.dataset.value; }).load; @@ -76,7 +76,6 @@ const useAddons = (urlParams, queryParams) => { } }, { - 'data-name': 'type', selected: state.addons.catalogs .filter(({ is_selected }) => is_selected) .map(({ load }) => JSON.stringify(load)), @@ -95,11 +94,14 @@ const useAddons = (urlParams, queryParams) => { } ]; const installedAddons = state.ctx.is_loaded ? state.ctx.content.addons : []; - const addonsItems = urlParams.category === 'my' && state.ctx.is_loaded ? + const addonsItems = urlParams.category === 'my' ? installedAddons.filter(addon => urlParams.type === 'all' || addon.manifest.types.includes(urlParams.type)) : - (state.addons.content.type === 'Ready' ? state.addons.content.content : []); - setAddons([addonsItems, selectInputs, selectAddon, installAddon, uninstallAddon, installedAddons]); + state.addons.content.type === 'Ready' ? + state.addons.content.content + : + []; + setAddons([addonsItems, selectInputs, selectAddon, installedAddons]); }; core.on('NewModel', onNewState); core.dispatch({ @@ -112,7 +114,7 @@ const useAddons = (urlParams, queryParams) => { resource: 'addon_catalog', type_name: type, id: category, - extra: [] // TODO + extra: [] } } } @@ -121,7 +123,7 @@ const useAddons = (urlParams, queryParams) => { core.off('NewModel', onNewState); }; }, [urlParams, queryParams]); - return addons; + return [addons, installAddon, uninstallAddon]; }; module.exports = useAddons; diff --git a/src/routes/Addons/useSelectedAddon.js b/src/routes/Addons/useSelectedAddon.js index b0e6e6dc5..5bffaec37 100644 --- a/src/routes/Addons/useSelectedAddon.js +++ b/src/routes/Addons/useSelectedAddon.js @@ -23,8 +23,7 @@ const useSelectedAddon = (transportUrl) => { queryParams.delete('addon'); if ([...queryParams].length !== 0) { window.location.replace(`#${pathname}?${queryParams.toString()}`); - } - else { + } else { window.location.replace(`#${pathname}`); } setAddon(null); From 3f68cacab8eca67937ea56a6e708436dd96d8539 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 31 Oct 2019 16:41:26 +0200 Subject: [PATCH 118/442] add space between metapreview and scroll in discover --- src/routes/Discover/styles.less | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index ce269b306..74433b0d3 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -26,7 +26,7 @@ flex: 1; align-self: stretch; display: grid; - grid-template-columns: 1fr 26rem; + grid-template-columns: 1fr 28rem; grid-template-rows: 7rem 1fr; grid-template-areas: "controls-area meta-preview-area" @@ -104,6 +104,7 @@ .catalog-content-container { grid-area: catalog-content-area; + margin-right: 2rem; .meta-items-container { display: grid; @@ -208,6 +209,8 @@ "catalog-content-area"; .catalog-content-container { + margin-right: 0; + .meta-items-container { grid-template-columns: repeat(5, 1fr); } From e87c6d836c3d96da7b3f7378cdffc8624659bdcf Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 31 Oct 2019 16:41:37 +0200 Subject: [PATCH 119/442] override metapreview background --- src/routes/Discover/Discover.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 19b62d204..e62223248 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -87,6 +87,7 @@ const Discover = ({ urlParams, queryParams }) => { {...selectedMetaItem} className={styles['meta-preview-container']} compact={true} + background={selectedMetaItem.poster} /> :
From da26b20c18fcbfadc6ed44d677b50f600fc85e4a Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 31 Oct 2019 16:43:42 +0200 Subject: [PATCH 120/442] addedAddon renamed to addAddonModalOpened --- src/routes/Addons/Addons.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index dcc1c9a1d..fb283a07b 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -17,22 +17,22 @@ const Addons = ({ urlParams, queryParams }) => { setQuery(event.currentTarget.value); }, []); const [[addons, dropdowns, setSelectedAddon, installedAddons], installSelectedAddon, uninstallSelectedAddon] = useAddons(urlParams, queryParams); - const [addedAddon, setAddedAddon] = React.useState(false); + const [addAddonModalOpened, setAddAddonModalOpened] = React.useState(false); const [selectedAddon, clearSelectedAddon] = useSelectedAddon(queryParams.get('addon')); const [sharedAddon, setSharedAddon] = React.useState(null); const onAddAddonButtonClicked = React.useCallback(() => { - setAddedAddon(true); + setAddAddonModalOpened(true); }, []); const onAddButtonClicked = React.useCallback(() => { if (inputRef.current.value.length > 0) { setSelectedAddon(inputRef.current.value); - setAddedAddon(false); + setAddAddonModalOpened(false); } }, [setSelectedAddon]); React.useEffect(() => { const onKeyUp = (event) => { if (event.key === 'Escape' && typeof close === 'function') { - setAddedAddon(false); + setAddAddonModalOpened(false); } }; if (focusable) { @@ -45,7 +45,7 @@ const Addons = ({ urlParams, queryParams }) => { const promptModalBackgroundOnClick = React.useCallback((event) => { if (!event.nativeEvent.clearSelectedAddonPrevented) { clearSelectedAddon(); - setAddedAddon(false); + setAddAddonModalOpened(false); setSharedAddon(null); } }, [clearSelectedAddon]); @@ -97,18 +97,18 @@ const Addons = ({ urlParams, queryParams }) => { }
{ - addedAddon ? + addAddonModalOpened ?
-
Add add-on
-

{title}

{children}
- {Array.isArray(buttons) && buttons.length ? buttons.map((button, key) => ( - - )) : null} + { + Array.isArray(buttons) && buttons.length > 0 ? + buttons.map((button, key) => ( + + )) + : + null + }
@@ -66,4 +76,4 @@ ModalDialog.propTypes = { onClose: PropTypes.func }; -module.exports = ModalDialog; \ No newline at end of file +module.exports = ModalDialog; diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index 5afbd41ed..6de3bb7e7 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -13,33 +13,35 @@ overflow: visible; } - .close-button { + .close-button-container { display: flex; flex-direction: row; align-items: center; + justify-content: center; position: absolute; top: .2rem; right: .2rem; width: 2rem; height: 2rem; + padding: 0.5rem; - .x-icon { - flex: 1 0 0; - width: 1rem; - height: 1rem; + .icon { + display: block; + width: 100%; + height: 100%; fill: var(--color-surfacedark); } &:hover { background-color: var(--color-surfacelight); - .x-icon { + .icon { fill: var(--color-signal2); } } &:focus { - .x-icon { + .icon { fill: var(--color-signal2); } } @@ -81,7 +83,6 @@ &:focus { outline: 3px solid var(--color-surfacelighter); outline-offset: -4px; - } &:global(.disabled) { diff --git a/storybook/stories/ModalDialog/ModalDialog.js b/storybook/stories/ModalDialog/ModalDialog.js index 6bc3125fd..c32f7a7e3 100644 --- a/storybook/stories/ModalDialog/ModalDialog.js +++ b/storybook/stories/ModalDialog/ModalDialog.js @@ -59,12 +59,7 @@ storiesOf('ModalDialog', module).add('ModalDialog', () => { } }, { - label: ( - - - {'A button with a long name, icon and custom class'} - - ), + label: 'A button with a long name, icon and custom class', className: styles['custom-button'], props: { onClick: action('A button with a long name and icon clicked') From c8e0a5112819dc4b0689910d9f028096e15c7db0 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 1 Nov 2019 17:19:39 +0200 Subject: [PATCH 131/442] log errors from Core events --- src/services/Core/Core.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/services/Core/Core.js b/src/services/Core/Core.js index ab49fc245..547faad49 100644 --- a/src/services/Core/Core.js +++ b/src/services/Core/Core.js @@ -23,7 +23,11 @@ function Core() { if (starting) { containerService = new ContainerService(({ name, args } = {}) => { if (active) { - events.emit(name, args); + try { + events.emit(name, args); + } catch (e) { + console.error(e); + } } }); active = true; From 727d2fac13dac7ca6da26e92d546700e3a3822d1 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Fri, 1 Nov 2019 17:23:52 +0200 Subject: [PATCH 132/442] Button label must be a string --- src/common/ModalDialog/ModalDialog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 6aed44168..9938db8cf 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -48,7 +48,7 @@ const ModalDialog = ({ className, children, title, buttons, onClose }) => { null } { - ReactIs.isValidElementType(button.label) ? + typeof button.label === 'string' && button.label.length > 0 ? button.label : null @@ -68,7 +68,7 @@ ModalDialog.propTypes = { className: PropTypes.string, title: PropTypes.string, buttons: PropTypes.arrayOf(PropTypes.shape({ - label: PropTypes.node, + label: PropTypes.string, icon: PropTypes.string, className: PropTypes.string, props: PropTypes.object // Button.propTypes unfortunately these are not defined From 3d19a4d1faf015bf74a79b48d0f5139d6d810197 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 1 Nov 2019 17:51:05 +0200 Subject: [PATCH 133/442] useDiscover name fixed --- src/routes/Discover/useDiscover.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index b34fd09dd..7421e85e8 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -7,7 +7,7 @@ const DEFAULT_TYPE = 'movie'; const NONE_EXTRA_VALUE = 'None'; const PAGE_SIZE = 100; -const useCatalog = (urlParams, queryParams) => { +const useDiscover = (urlParams, queryParams) => { const { core } = useServices(); const [discover, setDiscover] = React.useState([[], null, null, null]); React.useEffect(() => { @@ -212,4 +212,4 @@ const useCatalog = (urlParams, queryParams) => { return discover; }; -module.exports = useCatalog; +module.exports = useDiscover; From e70c5508c7277a87f6c113e84ac426ef9fcee922 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 4 Nov 2019 10:00:42 +0200 Subject: [PATCH 134/442] not needed react-is removed --- src/common/ModalDialog/ModalDialog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 9938db8cf..ddfd890cf 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -1,5 +1,4 @@ const React = require('react'); -const ReactIs = require('react-is'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Button = require('stremio/common/Button'); From 639be32f6760d7455804eb352a5119cbb2224c1e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 4 Nov 2019 11:25:52 +0200 Subject: [PATCH 135/442] PaginateInput refactored for code reuse --- src/common/PaginateInput/PaginateInput.js | 51 +++++++---------------- src/routes/Discover/useDiscover.js | 4 -- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/src/common/PaginateInput/PaginateInput.js b/src/common/PaginateInput/PaginateInput.js index 5aa09c7cd..9c75643ae 100644 --- a/src/common/PaginateInput/PaginateInput.js +++ b/src/common/PaginateInput/PaginateInput.js @@ -21,53 +21,32 @@ const PaginateInput = ({ className, options, selected, onSelect, ...props }) => return selected; }, [options, selected]); - const prevButtonOnClick = React.useCallback((event) => { + const prevNextButtonOnClick = React.useCallback((event) => { if (typeof onSelect === 'function') { if (Array.isArray(options) && options.length > 0) { - const selectedIndex = options.findIndex(({ value }) => { + const selectedValueIndex = options.findIndex(({ value }) => { return selected === value; }); - const prevIndex = Math.max(selectedIndex - 1, 0); - const prevValue = options[prevIndex]; + const nextSelectedIndex = event.currentTarget.dataset.button === 'next' ? + Math.min(selectedValueIndex + 1, options.length - 1) + : + Math.max(selectedValueIndex - 1, 0); + const nextSelectedValue = options[nextSelectedIndex].value; onSelect({ type: 'select', - value: prevValue, + value: nextSelectedValue, dataset: dataset, reactEvent: event, nativeEvent: event.nativeEvent }); } else { - const prevValue = Math.max(selected - 1, 0); + const nextSelectedValue = event.currentTarget.dataset.button === 'next' ? + selected + 1 + : + Math.max(selected - 1, 1); onSelect({ type: 'select', - value: prevValue, - dataset: dataset, - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } - } - }, [dataset, options, selected, onSelect]); - const nextButtonOnClick = React.useCallback((event) => { - if (typeof onSelect === 'function') { - if (Array.isArray(options) && options.length > 0) { - const selectedIndex = options.findIndex(({ value }) => { - return selected === value; - }); - const nextIndex = Math.max(selectedIndex + 1, options.length - 1); - const nextValue = options[nextIndex]; - onSelect({ - type: 'select', - value: nextValue, - dataset: dataset, - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } else { - const nextValue = selected + 1; - onSelect({ - type: 'select', - value: nextValue, + value: nextSelectedValue, dataset: dataset, reactEvent: event, nativeEvent: event.nativeEvent @@ -89,7 +68,7 @@ const PaginateInput = ({ className, options, selected, onSelect, ...props }) => }, [onSelect]); return (
- disabled={!Array.isArray(options) || options.length === 0} onSelect={optionOnSelect} /> -
diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 7421e85e8..aeb29edd6 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -143,10 +143,6 @@ const useDiscover = (urlParams, queryParams) => { return page; }, 1), onSelect: (event) => { - if (event.value < 1) { - return; - } - navigateWithLoad({ base: addonTransportUrl, path: { From 97115d45817015b5d481d10a902c4999e5a05a49 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 4 Nov 2019 11:47:19 +0200 Subject: [PATCH 136/442] drop getUserFromState callback from useUser hook --- src/common/useUser.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/common/useUser.js b/src/common/useUser.js index 3dedd9aac..0c5391b26 100644 --- a/src/common/useUser.js +++ b/src/common/useUser.js @@ -3,15 +3,10 @@ const { useServices } = require('stremio/services'); const useUser = () => { const { core } = useServices(); - const getUserFromState = React.useCallback((state) => { - return state.ctx && state.ctx.auth && state.ctx.auth.user; - }, []); - const [user, setUser] = React.useState(() => { - return getUserFromState(core.getState()); - }); + const [user, setUser] = React.useState(state.ctx.auth ? state.ctx.auth.user : null); React.useEffect(() => { const onNewModel = () => { - setUser(getUserFromState(core.getState())); + setUser(state.ctx.auth ? state.ctx.auth.user : null); }; core.on('NewModel', onNewModel); return () => { From 1356e87bf91690406f42969c929d14b537ff0af4 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 4 Nov 2019 11:48:37 +0200 Subject: [PATCH 137/442] ModalDialog styles improved --- src/common/ModalDialog/ModalDialog.js | 48 ++++++++++++----------- src/common/ModalDialog/styles.less | 30 +++++++------- storybook/stories/ModalDialog/styles.less | 2 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index ddfd890cf..2bd120acd 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -35,29 +35,31 @@ const ModalDialog = ({ className, children, title, buttons, onClose }) => {
{children}
-
- { - Array.isArray(buttons) && buttons.length > 0 ? - buttons.map((button, key) => ( - - )) - : - null - } -
+ { + Array.isArray(buttons) && buttons.length > 0 ? +
+ { + buttons.map((button, key) => ( + + )) + } +
+ : + null + }
) diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index 6de3bb7e7..39e05d5ff 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -1,17 +1,13 @@ .modal-container { display: flex; - flex-flow: column; + flex-direction: column; background-color: var(--color-backgrounddark40); .modal-dialog-container { position: relative; + margin: auto; padding: 1rem; background-color: var(--color-surfacelighter); - margin: auto; - - * { - overflow: visible; - } .close-button-container { display: flex; @@ -52,37 +48,35 @@ } .modal-dialog-content { - margin: 1rem auto 0 auto; + margin-top: 1rem; } .modal-dialog-buttons { - margin: -.5rem; margin-top: 1rem; display: flex; - flex-flow: row; + flex-direction: row; } - } } .action-button { display: flex; + flex-direction: row; align-items: center; justify-content: center; flex: 1 0 0; + padding: 1rem; text-align: center; color: var(--color-surfacelighter); background-color: var(--color-signal5); - padding: 1rem; - margin: .5rem; &:hover { - background-color: var(--color-signal580); + filter: brightness(1.2); } &:focus { - outline: 3px solid var(--color-surfacelighter); - outline-offset: -4px; + outline: calc(1.5 * var(--focus-outline-size)) solid var(--color-surfacelighter); + outline-offset: calc(-2 * var(--focus-outline-size)); } &:global(.disabled) { @@ -91,9 +85,13 @@ } .icon { - fill: var(--color-surfacelighter); width: 1rem; height: 1rem; margin-right: .5rem; + fill: var(--color-surfacelighter); + } + + &:not(:last-child) { + margin-right: 1rem; } } \ No newline at end of file diff --git a/storybook/stories/ModalDialog/styles.less b/storybook/stories/ModalDialog/styles.less index 91e9557e6..d6a3e426f 100644 --- a/storybook/stories/ModalDialog/styles.less +++ b/storybook/stories/ModalDialog/styles.less @@ -24,7 +24,7 @@ // This is only for the content. Not relevant for the demo .content-container { display: flex; - flex-flow: row; + flex-direction: row; margin: 0 -0.5rem; .content-column { From 9a601b605f312809e670fa456bf385b0b7efee8c Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 4 Nov 2019 13:58:08 +0200 Subject: [PATCH 138/442] ModalDialog refactored --- src/common/ModalDialog/ModalDialog.js | 46 ++++++++++++-------- src/common/ModalDialog/styles.less | 2 + storybook/stories/ModalDialog/ModalDialog.js | 9 ++-- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 2bd120acd..81fd375af 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -6,29 +6,37 @@ const Icon = require('stremio-icons/dom'); const { Modal } = require('stremio-router'); const styles = require('./styles'); -const ModalDialog = ({ className, children, title, buttons, onClose }) => { - // Close with the Escape key - // TODO: Maybe we should consider a global actions mapping so the 'close' key can be globbaly changed +const ModalDialog = ({ className, children, title, buttons, onCloseRequest }) => { + const dispatchCloseRequestEvent = React.useCallback(event => { + if (typeof onCloseRequest === 'function') { + onCloseRequest({ + type: 'closeRequest', + dataset: [], + reactEvent: event, + nativeEvent: event.nativeEvent + }); + } + }, [onCloseRequest]); React.useEffect(() => { - const onKeyUp = (event) => { - if (event.key === 'Escape' && typeof onClose === 'function') { - onClose(); + const onKeyDown = (event) => { + if (event.key === 'Escape') { + dispatchCloseRequestEvent(event); } }; - window.addEventListener('keyup', onKeyUp); + window.addEventListener('keydown', onKeyDown); return () => { - window.removeEventListener('keyup', onKeyUp); + window.removeEventListener('keydown', onKeyDown); }; - }, [onClose]); - const onModalContainerClick = React.useCallback(event => { - if (event.target === event.currentTarget && typeof onClose === 'function') { - onClose(event); + }, [dispatchCloseRequestEvent]); + const onModalContainerMouseDown = React.useCallback(event => { + if (event.target === event.currentTarget) { + dispatchCloseRequestEvent(event); } - }, [onClose]); + }, [dispatchCloseRequestEvent]); return ( - +
-

{title}

@@ -40,7 +48,7 @@ const ModalDialog = ({ className, children, title, buttons, onClose }) => {
{ buttons.map((button, key) => ( -
- ) + ); }; ModalDialog.propTypes = { @@ -72,9 +80,9 @@ ModalDialog.propTypes = { label: PropTypes.string, icon: PropTypes.string, className: PropTypes.string, - props: PropTypes.object // Button.propTypes unfortunately these are not defined + props: PropTypes.object })), - onClose: PropTypes.func + onCloseRequest: PropTypes.func }; module.exports = ModalDialog; diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index 39e05d5ff..09196210b 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -22,6 +22,7 @@ padding: 0.5rem; .icon { + flex: none; display: block; width: 100%; height: 100%; @@ -85,6 +86,7 @@ } .icon { + flex: none; width: 1rem; height: 1rem; margin-right: .5rem; diff --git a/storybook/stories/ModalDialog/ModalDialog.js b/storybook/stories/ModalDialog/ModalDialog.js index c32f7a7e3..31f8d3e33 100644 --- a/storybook/stories/ModalDialog/ModalDialog.js +++ b/storybook/stories/ModalDialog/ModalDialog.js @@ -2,7 +2,6 @@ const React = require('react'); const { storiesOf } = require('@storybook/react'); const { action } = require('@storybook/addon-actions'); -const Icon = require('stremio-icons/dom'); const { ModalDialog } = require('stremio/common'); const styles = require('./styles'); const useBinaryState = require('stremio/common/useBinaryState'); @@ -30,8 +29,8 @@ storiesOf('ModalDialog', module).add('ModalDialog', () => { label (String/React component) - the contents of the button. icon (String) - icon class name. It will be shown to the left of the button's text - className (String) - Custom className applied along side the default one. Used for custom styles - props (Object) - the properties applied to the button itself. If a className is supplied here it will override all other class names for this Button + className (String) - Custom className applied along side the default one. Used for custom styles + props (Object) - the properties applied to the button itself. If a className is supplied here it will override all other class names for this Button */ @@ -75,7 +74,7 @@ storiesOf('ModalDialog', module).add('ModalDialog', () => { { modalVisible ? - + {modalDummyContents} : @@ -86,7 +85,7 @@ storiesOf('ModalDialog', module).add('ModalDialog', () => { { modalBVisible ? - + {modalDummyContents} : From 1a719bbc2051063fb9ace155782005077e639817 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 4 Nov 2019 14:04:36 +0200 Subject: [PATCH 139/442] dataset dropped --- src/common/ModalDialog/ModalDialog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 81fd375af..20128aa25 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -11,7 +11,6 @@ const ModalDialog = ({ className, children, title, buttons, onCloseRequest }) => if (typeof onCloseRequest === 'function') { onCloseRequest({ type: 'closeRequest', - dataset: [], reactEvent: event, nativeEvent: event.nativeEvent }); From 17ecf8fb32e7d76977bc5ceb5d479a7e993dc60c Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 4 Nov 2019 14:35:34 +0200 Subject: [PATCH 140/442] change url/query params ref only if their value changed --- src/router/Router/Router.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index 16fbc5740..f8e59f2f6 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -3,6 +3,7 @@ const ReactIs = require('react-is'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const UrlUtils = require('url'); +const deepEqual = require('deep-equal'); const { RouteFocusedProvider } = require('../RouteFocusedContext'); const Route = require('../Route'); @@ -81,8 +82,14 @@ const Router = ({ className, onPathNotMatch, ...props }) => { return { key: `${routeViewIndex}${routeIndex}`, component: routeConfig.component, - urlParams, - queryParams + urlParams: view !== null && deepEqual(view.urlParams, urlParams) ? + view.urlParams + : + urlParams, + queryParams: view !== null && deepEqual(Array.from(view.queryParams.entries()), Array.from(queryParams.entries())) ? + view.queryParams + : + queryParams }; } else { return null; From 2093f8118eec052d686322ce432d795c53ea5978 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Mon, 4 Nov 2019 14:44:35 +0200 Subject: [PATCH 141/442] Make use of the modal dialog --- src/common/ColorInput/ColorInput.js | 44 +++++----------- src/common/ColorInput/styles.less | 81 ----------------------------- 2 files changed, 12 insertions(+), 113 deletions(-) delete mode 100644 src/common/ColorInput/styles.less diff --git a/src/common/ColorInput/ColorInput.js b/src/common/ColorInput/ColorInput.js index eefcc2c18..ab43c3050 100644 --- a/src/common/ColorInput/ColorInput.js +++ b/src/common/ColorInput/ColorInput.js @@ -1,41 +1,32 @@ const React = require('react'); const PropTypes = require('prop-types'); const AColorPicker = require('a-color-picker'); -const Icon = require('stremio-icons/dom'); -const { Modal } = require('stremio-router'); const Button = require('stremio/common/Button'); const useBinaryState = require('stremio/common/useBinaryState'); +const ModalDialog = require('stremio/common/ModalDialog'); const useDataset = require('stremio/common/useDataset'); const ColorPicker = require('./ColorPicker'); -const styles = require('./styles'); const COLOR_FORMAT = 'hexcss4'; const ColorInput = ({ className, value, onChange, ...props }) => { value = AColorPicker.parseColor(value, COLOR_FORMAT); const dataset = useDataset(props); - const [modalOpen, openModal, closeModal] = useBinaryState(false); + const [modalOpen, setModalOpen, setModalClsoed] = useBinaryState(false); const [tempValue, setTempValue] = React.useState(value); + const closeModal = (event) => { + event.nativeEvent.openModalPrevented = true; + setModalClsoed(); + }; const pickerLabelOnClick = React.useCallback((event) => { if (typeof props.onClick === 'function') { props.onClick(event); } if (!event.nativeEvent.openModalPrevented) { - openModal(); + setModalOpen(); } }, [props.onClick]); - const modalContainerOnClick = React.useCallback((event) => { - event.nativeEvent.openModalPrevented = true; - }, []); - const modalContainerOnMouseDown = React.useCallback((event) => { - if (!event.nativeEvent.closeModalPrevented) { - closeModal(); - } - }, []); - const modalContentOnMouseDown = React.useCallback((event) => { - event.nativeEvent.closeModalPrevented = true; - }, []); const colorPickerOnInput = React.useCallback((event) => { setTempValue(event.value); }, []); @@ -50,8 +41,8 @@ const ColorInput = ({ className, value, onChange, ...props }) => { }); } - closeModal(); - }, [onChange, tempValue, dataset]); + closeModal(event); + }, [onChange, tempValue, dataset, closeModal]); React.useEffect(() => { setTempValue(value); }, [value, modalOpen]); @@ -59,20 +50,9 @@ const ColorInput = ({ className, value, onChange, ...props }) => { -
- - -
- + + + : null } diff --git a/src/common/ColorInput/styles.less b/src/common/ColorInput/styles.less deleted file mode 100644 index 8242c6e67..000000000 --- a/src/common/ColorInput/styles.less +++ /dev/null @@ -1,81 +0,0 @@ -.color-input-modal-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - pointer-events: auto; - background-color: var(--color-backgrounddarker40); - - .color-input-container { - flex: none; - display: flex; - flex-direction: column; - align-items: center; - max-width: 25rem; - padding: 1rem; - background-color: var(--color-surfacelighter); - - .header-container { - flex: none; - align-self: stretch; - display: flex; - flex-direction: row; - align-items: flex-start; - - .title { - flex: 1; - margin-right: 1rem; - font-size: 1.2rem; - max-height: 2.4em; - } - - .close-button-container { - flex: none; - width: 1.5rem; - height: 1.5rem; - padding: 0.25rem; - - &:hover, &:focus { - background-color: var(--color-surfacedark20); - } - - &:focus { - outline-color: var(--color-surfacedarker); - } - - .icon { - display: block; - width: 100%; - height: 100%; - fill: var(--color-surfacedarker); - } - } - } - - .color-picker { - flex: none; - margin: 1rem; - } - - .submit-button-container { - flex: none; - align-self: stretch; - padding: 1rem; - background-color: var(--color-signal5); - - &:hover, &:focus { - filter: brightness(1.2); - } - - &:focus { - outline-color: var(--color-surfacedarker); - } - - .label { - max-height: 2.4em; - text-align: center; - color: var(--color-surfacelighter); - } - } - } -} \ No newline at end of file From b4c9b527d0d75b870df8111319ad6a7b0ed26c1d Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Mon, 4 Nov 2019 15:32:06 +0200 Subject: [PATCH 142/442] Fixed a typo --- src/common/ColorInput/ColorInput.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/ColorInput/ColorInput.js b/src/common/ColorInput/ColorInput.js index ab43c3050..661dae50c 100644 --- a/src/common/ColorInput/ColorInput.js +++ b/src/common/ColorInput/ColorInput.js @@ -12,11 +12,11 @@ const COLOR_FORMAT = 'hexcss4'; const ColorInput = ({ className, value, onChange, ...props }) => { value = AColorPicker.parseColor(value, COLOR_FORMAT); const dataset = useDataset(props); - const [modalOpen, setModalOpen, setModalClsoed] = useBinaryState(false); + const [modalOpen, setModalOpen, setModalClosed] = useBinaryState(false); const [tempValue, setTempValue] = React.useState(value); const closeModal = (event) => { event.nativeEvent.openModalPrevented = true; - setModalClsoed(); + setModalClosed(); }; const pickerLabelOnClick = React.useCallback((event) => { if (typeof props.onClick === 'function') { From cdc6ca4049616c717f7af56ad7be5211f09b018b Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 5 Nov 2019 12:05:20 +0200 Subject: [PATCH 143/442] check title value --- src/common/ModalDialog/ModalDialog.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 20128aa25..7d12c9ec0 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -38,7 +38,12 @@ const ModalDialog = ({ className, children, title, buttons, onCloseRequest }) => -

{title}

+ { + typeof title === 'string' && title.length > 0 ? +

{title}

+ : + null + }
{children}
From 86c7b746e3c8cedab70b8f8937b11717cdfd30aa Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 5 Nov 2019 14:47:00 +0200 Subject: [PATCH 144/442] addon prompt, share prompt and addons adapted to the new modal dialog --- src/common/ModalDialog/styles.less | 11 +- src/common/SharePrompt/SharePrompt.js | 62 ++---- src/common/SharePrompt/styles.less | 208 ++++++++----------- src/routes/Addons/AddonPrompt/AddonPrompt.js | 170 ++++++--------- src/routes/Addons/AddonPrompt/styles.less | 177 ++++------------ src/routes/Addons/Addons.js | 139 ++++++------- src/routes/Addons/styles.less | 154 ++------------ 7 files changed, 311 insertions(+), 610 deletions(-) diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index 09196210b..9eb93b01f 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -45,15 +45,20 @@ } h1 { + margin-bottom: 1rem; font-size: 1.2rem; } .modal-dialog-content { - margin-top: 1rem; + padding: 1rem; + + >:not(:first-child) { + margin-top: 1rem; + } } .modal-dialog-buttons { - margin-top: 1rem; + margin: 1rem; display: flex; flex-direction: row; } @@ -94,6 +99,6 @@ } &:not(:last-child) { - margin-right: 1rem; + margin-right: 2rem; } } \ No newline at end of file diff --git a/src/common/SharePrompt/SharePrompt.js b/src/common/SharePrompt/SharePrompt.js index 292a33d2a..8a8dbefef 100644 --- a/src/common/SharePrompt/SharePrompt.js +++ b/src/common/SharePrompt/SharePrompt.js @@ -2,55 +2,34 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); -const { useRouteFocused } = require('stremio-router'); const Button = require('stremio/common/Button'); const TextInput = require('stremio/common/TextInput'); const styles = require('./styles'); -const SharePrompt = ({ className, label, url, close, onClick }) => { +const SharePrompt = ({ className, url }) => { const inputRef = React.useRef(null); - const focusRoute = useRouteFocused(); const copyToClipboard = React.useCallback(() => { inputRef.current.select(); document.execCommand('copy'); }, []); - React.useEffect(() => { - const onKeyUp = (event) => { - if (event.key === 'Escape' && typeof close === 'function') { - close(); - } - }; - if (focusRoute) { - window.addEventListener('keyup', onKeyUp); - } - return () => { - window.removeEventListener('keyup', onKeyUp); - }; - }, [close, focusRoute]); return ( -
- -
-
{label}
-
- - -
-
- - -
+
+
+ + +
+
+ +
); @@ -58,10 +37,7 @@ const SharePrompt = ({ className, label, url, close, onClick }) => { SharePrompt.propTypes = { className: PropTypes.string, - label: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, - close: PropTypes.func, - onClick: PropTypes.func + url: PropTypes.string.isRequired }; module.exports = SharePrompt; diff --git a/src/common/SharePrompt/styles.less b/src/common/SharePrompt/styles.less index 36c97ce7f..712f9d7cf 100644 --- a/src/common/SharePrompt/styles.less +++ b/src/common/SharePrompt/styles.less @@ -1,133 +1,107 @@ .share-prompt-container { - position: relative; - z-index: 0; - display: flex; - flex-direction: column; - padding: 2.4rem 0; - background-color: var(--color-surfacelighter); + .buttons-container { + flex: none; + align-self: stretch; + display: flex; + flex-direction: row; - .close-button-container { - position: absolute; - top: 0.4rem; - right: 0.4rem; - z-index: 1; - width: 2rem; - height: 2rem; - padding: 0.4rem; - - &:hover { - background-color: var(--color-surfacelight); - } - - .icon { - display: block; - width: 100%; - height: 100%; - fill: var(--color-backgrounddarker); - } - } - - .share-prompt-content { - padding: 0 2.4rem; - - .share-prompt-label { - font-size: 1.3rem; - color: var(--color-backgrounddarker); - } - - .buttons-container { - flex: none; - align-self: stretch; + .button-container { + flex-grow: 0; + flex-shrink: 1; + flex-basis: 14rem; display: flex; flex-direction: row; - margin: 1.4rem 0; + align-items: center; + justify-content: center; + padding: 0.6rem 1rem; - .button-container { - flex-grow: 0; - flex-shrink: 1; - flex-basis: 14rem; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - padding: 0.6rem 1rem; - - .icon { - flex: none; - width: 1.4rem; - height: 1.4rem; - margin-right: 0.6rem; - fill: var(--color-surfacelighter); - } - - .label { - flex-grow: 0; - flex-shrink: 1; - flex-basis: auto; - font-size: 0.8rem; - font-weight: 500; - color: var(--color-surfacelighter); - text-align: center; - } - - &:hover, &:focus { - filter: brightness(1.2); - } - - &:not(:last-child) { - margin-right: 2rem; - } + .icon { + flex: none; + width: 1.4rem; + height: 1.4rem; + margin-right: 0.6rem; + fill: var(--color-surfacelighter); } - .facebook-button { - background-color: var(--color-facebook); - } - - .twitter-button { - background-color: var(--color-twitter); - } - } - - .url-container { - display: flex; - flex-direction: row; - border: thin solid var(--color-surface); - - .url-content { - flex: 1; - min-width: 12rem; - padding: 0.6rem 1rem; - font-size: 0.9rem; - color: var(--color-surfacedark); - text-align: center; - } - - .copy-button { + .label { flex-grow: 0; flex-shrink: 1; flex-basis: auto; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - padding: 0.6rem 1rem; - background-color: var(--color-surface); + font-size: 0.8rem; + font-weight: 500; + color: var(--color-surfacelighter); + text-align: center; + } - .icon { - flex: none; - width: 1.4rem; - height: 1.4rem; - margin-right: 0.6rem; - fill: var(--color-surfacedarker); - } + &:hover { + filter: brightness(1.2); + } - .label { - color: var(--color-surfacedarker); - } + &:focus { + outline: calc(1.5 * var(--focus-outline-size)) solid var(--color-surfacelighter); + outline-offset: calc(-2 * var(--focus-outline-size)); + } - &:hover, &:focus { - filter: brightness(1.2); - } + &:not(:last-child) { + margin-right: 2rem; + } + } + + .facebook-button { + background-color: var(--color-facebook); + } + + .twitter-button { + background-color: var(--color-twitter); + } + } + + .url-container { + display: flex; + flex-direction: row; + margin-top: 2rem; + border: thin solid var(--color-surface); + + .url-content { + flex: 1; + min-width: 12rem; + padding: 0.6rem 1rem; + font-size: 0.9rem; + color: var(--color-surfacedark); + text-align: center; + border-right: thin solid var(--color-surface); + } + + .copy-button { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding: 0.6rem 1rem; + background-color: var(--color-surface); + + .icon { + flex: none; + width: 1.4rem; + height: 1.4rem; + margin-right: 0.6rem; + fill: var(--color-surfacedarker); + } + + .label { + color: var(--color-surfacedarker); + } + + &:hover { + filter: brightness(1.2); + } + + &:focus { + outline: calc(1.5 * var(--focus-outline-size)) solid var(--color-surfacelighter); + outline-offset: calc(-1.5 * var(--focus-outline-size)); } } } diff --git a/src/routes/Addons/AddonPrompt/AddonPrompt.js b/src/routes/Addons/AddonPrompt/AddonPrompt.js index 54b056a47..4d6f9ffc8 100644 --- a/src/routes/Addons/AddonPrompt/AddonPrompt.js +++ b/src/routes/Addons/AddonPrompt/AddonPrompt.js @@ -1,116 +1,86 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const Icon = require('stremio-icons/dom'); -const { useRouteFocused } = require('stremio-router'); -const { Button } = require('stremio/common'); const styles = require('./styles'); -const AddonPrompt = ({ className, id, name, logo, description, types, catalogs, version, transportUrl, installed, official, cancel, onClick, toggle }) => { - const focusRoute = useRouteFocused(); - React.useEffect(() => { - const onKeyUp = (event) => { - if (event.key === 'Escape') { - cancel(); - } - }; - if (focusRoute) { - window.addEventListener('keyup', onKeyUp); - } - return () => { - window.removeEventListener('keyup', onKeyUp); - }; - }, [cancel, focusRoute]); +const AddonPrompt = ({ className, id, name, logo, description, types, catalogs, version, transportUrl, official }) => { return ( -
- -
-
0 })}> - { - typeof logo === 'string' && logo.length > 0 ? -
- {' -
- : - null - } - {typeof name === 'string' && name.length > 0 ? name : id} - {' '} - { - typeof version === 'string' && version.length > 0 ? - v.{version} - : - null - } -
+
+
0 })}> { - typeof description === 'string' && description.length > 0 ? -
- {description} + typeof logo === 'string' && logo.length > 0 ? +
+ {'
: null } + {typeof name === 'string' && name.length > 0 ? name : id} + {' '} { - typeof transportUrl === 'string' && transportUrl.length > 0 ? -
- URL: - {transportUrl} -
- : - null - } - { - Array.isArray(types) && types.length > 0 ? -
- Supported types: - - { - types.length === 1 ? - types[0] - : - types.slice(0, -1).join(', ') + ' & ' + types[types.length - 1] - } - -
- : - null - } - { - Array.isArray(catalogs) && catalogs.length > 0 ? -
- Supported catalogs: - - { - catalogs.length === 1 ? - catalogs[0].name - : - catalogs.slice(0, -1).map(({ name }) => name).join(', ') + ' & ' + catalogs[catalogs.length - 1].name - } - -
- : - null - } - { - !official ? -
-
Using third-party add-ons will always be subject to your responsibility and the governing law of the jurisdiction you are located.
-
+ typeof version === 'string' && version.length > 0 ? + v.{version} : null }
-
- - -
+ { + typeof description === 'string' && description.length > 0 ? +
+ {description} +
+ : + null + } + { + typeof transportUrl === 'string' && transportUrl.length > 0 ? +
+ URL: + {transportUrl} +
+ : + null + } + { + Array.isArray(types) && types.length > 0 ? +
+ Supported types: + + { + types.length === 1 ? + types[0] + : + types.slice(0, -1).join(', ') + ' & ' + types[types.length - 1] + } + +
+ : + null + } + { + Array.isArray(catalogs) && catalogs.length > 0 ? +
+ Supported catalogs: + + { + catalogs.length === 1 ? + catalogs[0].name + : + catalogs.slice(0, -1).map(({ name }) => name).join(', ') + ' & ' + catalogs[catalogs.length - 1].name + } + +
+ : + null + } + { + !official ? +
+
Using third-party add-ons will always be subject to your responsibility and the governing law of the jurisdiction you are located.
+
+ : + null + }
); }; @@ -127,11 +97,7 @@ AddonPrompt.propTypes = { })), version: PropTypes.string, transportUrl: PropTypes.string, - installed: PropTypes.bool, - official: PropTypes.bool, - cancel: PropTypes.func, - onClick: PropTypes.func, - toggle: PropTypes.func + official: PropTypes.bool }; module.exports = AddonPrompt; diff --git a/src/routes/Addons/AddonPrompt/styles.less b/src/routes/Addons/AddonPrompt/styles.less index 11249348a..b58aafceb 100644 --- a/src/routes/Addons/AddonPrompt/styles.less +++ b/src/routes/Addons/AddonPrompt/styles.less @@ -1,153 +1,54 @@ .addon-prompt-container { - position: relative; - z-index: 0; - display: flex; - flex-direction: column; - padding: 3rem 0; - background-color: var(--color-surfacelighter); + .title-container { + font-size: 3rem; + font-weight: 300; + word-break: break-all; - .close-button-container { - position: absolute; - top: 0.5rem; - right: 0.5rem; - z-index: 1; - width: 2.5rem; - height: 2.5rem; - padding: 0.5rem; - - &:hover { - background-color: var(--color-surfacelight); + &.title-with-logo-container { + &::first-line { + line-height: 5rem; + } } - .icon { - display: block; - width: 100%; - height: 100%; - fill: var(--color-backgrounddarker); + .logo-container { + width: 5rem; + height: 5rem; + margin-right: 0.5rem; + background-color: var(--color-surfacelight20); + float: left; + + .logo { + display: block; + width: 100%; + height: 100%; + object-fit: contain; + object-position: center; + } + } + + .version-container { + font-size: 1.5rem; + font-weight: 400; } } - .addon-prompt-content { - flex-grow: 0; - flex-shrink: 1; - flex-basis: auto; - align-self: stretch; - padding: 0 3rem; - overflow-y: auto; + .section-container { + margin-top: 1rem; - .title-container { - font-size: 3rem; + .section-header { + font-size: 1.2rem; + } + + .section-label { + font-size: 1.2rem; font-weight: 300; - word-break: break-all; - &.title-with-logo-container { - &::first-line { - line-height: 5rem; - } + &.transport-url-label { + user-select: text; } - .logo-container { - width: 5rem; - height: 5rem; - margin-right: 0.5rem; - background-color: var(--color-surfacelight20); - float: left; - - .logo { - display: block; - width: 100%; - height: 100%; - object-fit: contain; - object-position: center; - } - } - - .version-container { - font-size: 1.5rem; - font-weight: 400; - } - } - - .section-container { - margin-top: 1rem; - - .section-header { - font-size: 1.2rem; - } - - .section-label { - font-size: 1.2rem; - font-weight: 300; - - &.transport-url-label { - user-select: text; - } - - &.disclaimer-label { - font-style: italic; - } - } - } - } - - .buttons-container { - flex: none; - align-self: stretch; - display: flex; - flex-direction: row; - margin-top: 2rem; - padding: 0 3rem; - - .button-container { - flex: 1; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - height: 4rem; - padding: 0 1rem; - - &:first-child { - margin-right: 2rem; - } - - .label { - flex-grow: 0; - flex-shrink: 1; - flex-basis: auto; - max-height: 2.4em; - font-size: 1.3rem; - font-weight: 500; - text-align: center; - } - } - - .cancel-button, .uninstall-button { - outline-color: var(--color-surfacedark); - outline-style: solid; - - &:hover, &:focus { - background-color: var(--color-surfacelight); - } - - .label { - color: var(--color-backgrounddarker); - } - } - - .install-button { - background-color: var(--color-signal5); - - &:hover, &:focus { - filter: brightness(1.2); - } - - &:focus { - outline-color: var(--color-surfacedarker); - } - - .label { - color: var(--color-surfacelighter); + &.disclaimer-label { + font-style: italic; } } } diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index ab5100085..e50f98116 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -1,8 +1,6 @@ const React = require('react'); -const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); -const { Modal, useRouteFocused } = require('stremio-router'); -const { Button, Multiselect, NavBar, TextInput, SharePrompt } = require('stremio/common'); +const { Button, Multiselect, NavBar, TextInput, SharePrompt, ModalDialog } = require('stremio/common'); const Addon = require('./Addon'); const AddonPrompt = require('./AddonPrompt'); const useAddons = require('./useAddons'); @@ -11,7 +9,6 @@ const styles = require('./styles'); const Addons = ({ urlParams, queryParams }) => { const inputRef = React.useRef(null); - const focusRoute = useRouteFocused(); const [query, setQuery] = React.useState(''); const queryOnChange = React.useCallback((event) => { setQuery(event.currentTarget.value); @@ -29,32 +26,13 @@ const Addons = ({ urlParams, queryParams }) => { setAddAddonModalOpened(false); } }, [setSelectedAddon]); - React.useEffect(() => { - const onKeyUp = (event) => { - if (event.key === 'Escape' && typeof close === 'function') { - setAddAddonModalOpened(false); - } - }; - if (focusRoute) { - window.addEventListener('keyup', onKeyUp); - } - return () => { - window.removeEventListener('keyup', onKeyUp); - }; - }, [close, focusRoute]); - const promptModalBackgroundOnClick = React.useCallback((event) => { - if (!event.nativeEvent.clearSelectedAddonPrevented) { - clearSelectedAddon(); - setAddAddonModalOpened(false); - setSharedAddon(null); - } - }, [clearSelectedAddon]); - const promptOnClick = React.useCallback((event) => { - event.nativeEvent.clearSelectedAddonPrevented = true; - }, []); const setInstalledAddon = React.useCallback((currentAddon) => { return installedAddons.some((installedAddon) => installedAddon.transportUrl === currentAddon.transportUrl); }, [installedAddons]); + const toggleAddon = React.useCallback(() => { + setInstalledAddon(selectedAddon) ? uninstallSelectedAddon(selectedAddon) : installSelectedAddon(selectedAddon); + clearSelectedAddon(); + }); return (
@@ -108,62 +86,77 @@ const Addons = ({ urlParams, queryParams }) => {
{ addAddonModalOpened ? - -
-
- -
-
Add add-on
- -
- - -
-
-
-
-
+ setAddAddonModalOpened(false) + } + }, + { + label: 'Add', + props: { + title: 'Add', + onClick: onAddButtonClicked + } + } + ]} + onCloseRequest={() => setAddAddonModalOpened(false)} + > + + : null } { selectedAddon !== null ? - -
- setInstalledAddon(selectedAddon) ? uninstallSelectedAddon(selectedAddon) : installSelectedAddon(selectedAddon)} - /> -
-
+ + + : null } { sharedAddon !== null ? - -
- setSharedAddon(null)} - onClick={promptOnClick} - /> -
-
+ setSharedAddon(null)}> + setSharedAddon(null)} + /> + : null } diff --git a/src/routes/Addons/styles.less b/src/routes/Addons/styles.less index 5a87e221d..d97a130ea 100644 --- a/src/routes/Addons/styles.less +++ b/src/routes/Addons/styles.less @@ -123,145 +123,31 @@ } } -.prompt-modal-container { - display: flex; - align-items: center; - justify-content: center; - background-color: var(--color-background60); +.add-addon-prompt-container { + width: 30rem; - .prompt-container { - flex: none; - display: flex; - flex-direction: column; - justify-content: center; - height: 80%; - - .prompt { - flex-grow: 0; - flex-shrink: 1; - flex-basis: auto; - align-self: stretch; - } + .url-content { + flex: 1; + width: 100%; + padding: 0.5rem; + font-size: 0.9rem; + color: var(--color-surfacedark); + border: thin solid var(--color-surface); } - .add-addon-prompt-container { - width: 30rem; - - .add-addon-prompt { - position: relative; - z-index: 0; - display: flex; - flex-direction: column; - padding: 2.4rem 0; - background-color: var(--color-surfacelighter); - - .close-button-container { - position: absolute; - top: 0.4rem; - right: 0.4rem; - z-index: 1; - width: 2rem; - height: 2rem; - padding: 0.4rem; - - &:hover { - background-color: var(--color-surfacelight); - } - - .icon { - display: block; - width: 100%; - height: 100%; - fill: var(--color-backgrounddarker); - } - } - - .add-addon-prompt-content { - padding: 0 2.4rem; - - .add-addon-prompt-label { - margin-bottom: 1.4rem; - font-size: 1.3rem; - color: var(--color-backgrounddarker); - } - - .url-content { - flex: 1; - width: 100%; - padding: 0.5rem; - font-size: 0.9rem; - color: var(--color-surfacedark); - border: thin solid var(--color-surface); - } - - .buttons-container { - flex: none; - align-self: stretch; - display: flex; - flex-direction: row; - margin-top: 2rem; - - .button-container { - flex: 1; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - height: 3rem; - padding: 0 1rem; - - &:first-child { - margin-right: 2rem; - } - - .label { - flex-grow: 0; - flex-shrink: 1; - flex-basis: auto; - max-height: 2.4em; - font-size: 1.2rem; - text-align: center; - } - } - - .cancel-button { - outline-color: var(--color-surfacedark); - outline-style: solid; - - &:hover, &:focus { - background-color: var(--color-surfacelight); - } - - .label { - color: var(--color-backgrounddarker); - } - } - - .add-button { - background-color: var(--color-signal5); - - &:hover, &:focus { - filter: brightness(1.2); - } - - &:focus { - outline-color: var(--color-surfacedarker); - } - - .label { - color: var(--color-surfacelighter); - } - } - } - } - } + .cancel-button { + background-color: var(--color-surfacedark); } +} - .addon-prompt-container { - width: 50rem; - } +.addon-prompt-container { + width: 50rem; - .share-prompt-container { - width: 30rem; + .cancel-button { + background-color: var(--color-surfacedark); } +} + +.share-prompt-container { + width: 30rem; } \ No newline at end of file From 9f97f96e9eded57010e6cdd63e16fff8ee54c383 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 5 Nov 2019 15:06:42 +0200 Subject: [PATCH 145/442] incorrect usage of dispatchCloseRequestEvent func removed --- src/common/ModalDialog/ModalDialog.js | 37 +++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 7d12c9ec0..89e36e209 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -7,39 +7,44 @@ const { Modal } = require('stremio-router'); const styles = require('./styles'); const ModalDialog = ({ className, children, title, buttons, onCloseRequest }) => { - const dispatchCloseRequestEvent = React.useCallback(event => { - if (typeof onCloseRequest === 'function') { - onCloseRequest({ - type: 'closeRequest', - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } - }, [onCloseRequest]); React.useEffect(() => { const onKeyDown = (event) => { if (event.key === 'Escape') { - dispatchCloseRequestEvent(event); + onCloseRequest({ + type: 'close', + nativeEvent: event + }); } }; window.addEventListener('keydown', onKeyDown); return () => { window.removeEventListener('keydown', onKeyDown); }; - }, [dispatchCloseRequestEvent]); - const onModalContainerMouseDown = React.useCallback(event => { + }, [onCloseRequest]); + const closeButtonOnClick = React.useCallback((event) => { + onCloseRequest({ + type: 'close', + reactEvent: event, + nativeEvent: event.nativeEvent + }); + }, [onCloseRequest]) + const onModalContainerMouseDown = React.useCallback((event) => { if (event.target === event.currentTarget) { - dispatchCloseRequestEvent(event); + onCloseRequest({ + type: 'close', + reactEvent: event, + nativeEvent: event.nativeEvent + }); } - }, [dispatchCloseRequestEvent]); + }, [onCloseRequest]); return (
- { - typeof title === 'string' && title.length > 0 ? + typeof title === 'string' && title.length > 0 ?

{title}

: null From 84b8c543177e3573e7906d85c7c8e2eed44d3d7e Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 5 Nov 2019 15:07:51 +0200 Subject: [PATCH 146/442] semicolon added --- src/common/ModalDialog/ModalDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 89e36e209..bb632fc6b 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -27,7 +27,7 @@ const ModalDialog = ({ className, children, title, buttons, onCloseRequest }) => reactEvent: event, nativeEvent: event.nativeEvent }); - }, [onCloseRequest]) + }, [onCloseRequest]); const onModalContainerMouseDown = React.useCallback((event) => { if (event.target === event.currentTarget) { onCloseRequest({ From f27624a8a0a7b134e04f7be6f466cb2fb9a98f02 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 5 Nov 2019 15:25:04 +0200 Subject: [PATCH 147/442] setInstalledAddon func renamed to installedAddon --- src/common/NavBar/NavMenu/NavMenu.js | 2 +- src/routes/Addons/Addons.js | 26 ++++++++++---------- src/routes/Detail/StreamsList/StreamsList.js | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/common/NavBar/NavMenu/NavMenu.js b/src/common/NavBar/NavMenu/NavMenu.js index fa7f5db20..b8126116a 100644 --- a/src/common/NavBar/NavMenu/NavMenu.js +++ b/src/common/NavBar/NavMenu/NavMenu.js @@ -64,7 +64,7 @@ const NavMenu = ({ className }) => { {dropdowns.map((dropdown, index) => ( @@ -50,7 +50,7 @@ const Addons = ({ urlParams, queryParams }) => { @@ -72,7 +72,7 @@ const Addons = ({ urlParams, queryParams }) => { setSelectedAddon(addon.transportUrl)} onShareButtonClicked={() => setSharedAddon(addon)} @@ -88,7 +88,7 @@ const Addons = ({ urlParams, queryParams }) => { addAddonModalOpened ? { } }, { - label: setInstalledAddon(selectedAddon) ? 'Uninstall' : 'Install', + label: installedAddon(selectedAddon) ? 'Uninstall' : 'Install', props: { - title: setInstalledAddon(selectedAddon) ? 'Uninstall' : 'Install', + title: installedAddon(selectedAddon) ? 'Uninstall' : 'Install', onClick: toggleAddon } } @@ -139,7 +139,7 @@ const Addons = ({ urlParams, queryParams }) => { { } { sharedAddon !== null ? - setSharedAddon(null)}> + setSharedAddon(null)}> {
); From 36eef2b050e568262d40a67a149398b0a3b18620 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 5 Nov 2019 15:29:05 +0200 Subject: [PATCH 148/442] use event.value --- src/routes/Addons/useAddons.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index ab58885ff..eb6ffb746 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -68,9 +68,8 @@ const useAddons = (urlParams, queryParams) => { label: name })), onSelect: (event) => { - // TODO event.value const load = state.addons.catalogs.find(({ load: { path: { id } } }) => { - return id === event.reactEvent.currentTarget.dataset.value; + return id === event.value; }).load; window.location = `#/addons/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; } From f4d3b30983ad38c9f15e1a9b7c5b7c2a948419ac Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 5 Nov 2019 16:08:25 +0200 Subject: [PATCH 149/442] error case fixed --- src/routes/Addons/useAddons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index eb6ffb746..154af9940 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -87,7 +87,7 @@ const useAddons = (urlParams, queryParams) => { label: load.path.type_name })), onSelect: (event) => { - const load = JSON.parse(event.reactEvent.currentTarget.dataset.value); + const load = JSON.parse(event.value); window.location = `#/addons/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; } } @@ -100,7 +100,7 @@ const useAddons = (urlParams, queryParams) => { state.addons.content.content : []; - const error = state.addons.content.type === 'Err' ? state.addons.content.content : null; + const error = state.addons.content.type === 'Err' && !state.ctx.is_loaded ? state.addons.content.content : null; setAddons([addonsItems, selectInputs, selectAddon, installedAddons, error]); }; core.on('NewModel', onNewState); From 07cfad8cd841272fc8a625d1cfe76967a486d0d4 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Tue, 5 Nov 2019 16:13:25 +0200 Subject: [PATCH 150/442] Multiselect autofocus first selected item --- src/common/Multiselect/Multiselect.js | 16 ++++++++++------ src/common/Popup/Popup.js | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/common/Multiselect/Multiselect.js b/src/common/Multiselect/Multiselect.js index 7a251849b..f5b81f751 100644 --- a/src/common/Multiselect/Multiselect.js +++ b/src/common/Multiselect/Multiselect.js @@ -98,12 +98,16 @@ const Multiselect = ({ className, direction, title, renderLabelContent, renderLa
{ options.length > 0 ? - options.map(({ label, value }) => ( - - )) + options.map(({ label, value }) => { + const isSelected = selected.includes(value); + const title = typeof label === 'string' ? label : value; + return ( + + ) + }) :
No options available
diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index dc5c9bc16..5b957392d 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -68,7 +68,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, onCloseRequest, ...pr ref: labelRef, className: styles['label-container'], children: open ? - + {renderMenu()} : From e6163085b5b25980d2cb5c5d7fc955975ab20745 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Tue, 5 Nov 2019 17:46:44 +0200 Subject: [PATCH 151/442] Simplified ColorInput --- src/common/ColorInput/ColorInput.js | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/common/ColorInput/ColorInput.js b/src/common/ColorInput/ColorInput.js index 661dae50c..f9a682eb9 100644 --- a/src/common/ColorInput/ColorInput.js +++ b/src/common/ColorInput/ColorInput.js @@ -14,19 +14,6 @@ const ColorInput = ({ className, value, onChange, ...props }) => { const dataset = useDataset(props); const [modalOpen, setModalOpen, setModalClosed] = useBinaryState(false); const [tempValue, setTempValue] = React.useState(value); - const closeModal = (event) => { - event.nativeEvent.openModalPrevented = true; - setModalClosed(); - }; - const pickerLabelOnClick = React.useCallback((event) => { - if (typeof props.onClick === 'function') { - props.onClick(event); - } - - if (!event.nativeEvent.openModalPrevented) { - setModalOpen(); - } - }, [props.onClick]); const colorPickerOnInput = React.useCallback((event) => { setTempValue(event.value); }, []); @@ -40,23 +27,23 @@ const ColorInput = ({ className, value, onChange, ...props }) => { nativeEvent: event.nativeEvent }); } - - closeModal(event); - }, [onChange, tempValue, dataset, closeModal]); + setModalClosed(); + }, [onChange, tempValue, dataset]); React.useEffect(() => { setTempValue(value); }, [value, modalOpen]); return ( - + ); }; From 3aa7cf6ad5e64effe4efc568d4cd51fd397fd668 Mon Sep 17 00:00:00 2001 From: Vladimir Borisov Date: Wed, 6 Nov 2019 13:23:45 +0200 Subject: [PATCH 152/442] Do not force auto focus --- src/common/Popup/Popup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index 5b957392d..dc5c9bc16 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -68,7 +68,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, onCloseRequest, ...pr ref: labelRef, className: styles['label-container'], children: open ? - + {renderMenu()} : From 807cf9f0573865aebe25d81e7a49851128f1e205 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 7 Nov 2019 16:19:53 +0200 Subject: [PATCH 153/442] intro linked with stremio-core (login, logout, register) --- src/common/NavBar/NavMenu/NavMenu.js | 20 ++++++-- src/common/useUser.js | 12 +++-- src/routes/Intro/Intro.js | 75 +++++++++++++++++++++++++--- 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/common/NavBar/NavMenu/NavMenu.js b/src/common/NavBar/NavMenu/NavMenu.js index b8126116a..329e93dfb 100644 --- a/src/common/NavBar/NavMenu/NavMenu.js +++ b/src/common/NavBar/NavMenu/NavMenu.js @@ -2,14 +2,16 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); +const { useServices } = require('stremio/services'); const Button = require('stremio/common/Button'); const Popup = require('stremio/common/Popup'); const useBinaryState = require('stremio/common/useBinaryState'); const useFullscreen = require('stremio/common/useFullscreen'); -const useUser = require('./useUser'); +const useUser = require('stremio/common/useUser'); const styles = require('./styles'); const NavMenu = ({ className }) => { + const { core } = useServices(); const [menuOpen, openMenu, closeMenu, toggleMenu] = useBinaryState(false); const [fullscreen, requestFullscreen, exitFullscreen] = useFullscreen(); const user = useUser(); @@ -21,6 +23,14 @@ const NavMenu = ({ className }) => { const popupMenuOnClick = React.useCallback((event) => { event.nativeEvent.togglePopupPrevented = true; }, []); + const logoutButtonOnClick = React.useCallback(() => { + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Logout' + } + }); + }, []); return ( {
-
{user.anonymous ? 'Anonymous user' : user.email}
+
{!user ? 'Anonymous user' : user.email}
-
diff --git a/src/common/useUser.js b/src/common/useUser.js index 0c5391b26..fe685894f 100644 --- a/src/common/useUser.js +++ b/src/common/useUser.js @@ -3,14 +3,16 @@ const { useServices } = require('stremio/services'); const useUser = () => { const { core } = useServices(); - const [user, setUser] = React.useState(state.ctx.auth ? state.ctx.auth.user : null); + const state = core.getState(); + const [user, setUser] = React.useState(state.ctx.content.auth ? state.ctx.content.auth.user : null); React.useEffect(() => { - const onNewModel = () => { - setUser(state.ctx.auth ? state.ctx.auth.user : null); + const onNewState = () => { + setUser(state.ctx.content.auth ? state.ctx.content.auth.user : null); }; - core.on('NewModel', onNewModel); + core.on('NewModel', onNewState); + onNewState(); return () => { - core.off('NewModel', onNewModel); + core.off('NewModel', onNewState); }; }, []); return user; diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 9f1ad474f..396c6cee1 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -3,14 +3,16 @@ const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { useRouteFocused } = require('stremio-router'); const { Button } = require('stremio/common'); +const { useServices } = require('stremio/services'); const CredentialsTextInput = require('./CredentialsTextInput'); const ConsentCheckbox = require('./ConsentCheckbox'); const styles = require('./styles'); const LOGIN_FORM = 'LOGIN_FORM'; const SIGNUP_FORM = 'SIGNUP_FORM'; - +// TODO queryparams for signup and login const Intro = () => { + const { core } = useServices(); const routeFocused = useRouteFocused(); const emailRef = React.useRef(); const passwordRef = React.useRef(); @@ -65,6 +67,23 @@ const Intro = () => { error: '' } ); + React.useEffect(() => { + const onEvent = ({ event, args }) => { + if (event === 'CtxActionErr') { + dispatch({ type: 'error', error: args[1].args.message }); + } + if (event === 'CtxChanged') { + const state = core.getState(); + if (state.ctx.content.auth !== null) { + window.location.replace('/'); + } + } + }; + core.on('Event', onEvent); + return () => { + core.off('Event', onEvent); + }; + }, []); const loginWithFacebook = React.useCallback(() => { alert('TODO: Facebook login'); }, []); @@ -73,19 +92,61 @@ const Intro = () => { dispatch({ type: 'error', error: 'Invalid email' }); return; } - - alert('TODO: Login'); + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Login', + args: { + email: state.email, + password: state.password + } + } + }); }, [state.email, state.password]); const loginAsGuest = React.useCallback(() => { if (!state.termsAccepted) { dispatch({ type: 'error', error: 'You must accept the Terms of Service' }); return; + } else { + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Logout' + } + }); + location = '#/'; } - - alert('TODO: Guest login'); - }, [state.termsAccepted, state.privacyPolicyAccepted, state.marketingAccepted]); + }, [state.termsAccepted]); const signup = React.useCallback(() => { - alert('TODO: Signup'); + if (!state.termsAccepted) { + dispatch({ type: 'error', error: 'You must accept the Terms of Service' }); + return; + } + if (!state.privacyPolicyAccepted) { + dispatch({ type: 'error', error: 'You must accept the Privacy Policy' }); + return; + } + if (state.password !== state.confirmPassword) { + dispatch({ type: 'error', error: 'Passwords do not match' }); + return; + } + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Register', + args: { + email: state.email, + password: state.password, + gdpr_consent: { + tos: state.termsAccepted, + privacy: state.privacyPolicyAccepted, + marketing: state.marketingAccepted, + time: new Date(), + from: 'web' + } + } + } + }); }, [state.email, state.password, state.confirmPassword, state.termsAccepted, state.privacyPolicyAccepted, state.marketingAccepted]); const emailOnChange = React.useCallback((event) => { dispatch({ From 178de4012a84d1f2388b256939c067b257a33641 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 7 Nov 2019 16:25:27 +0200 Subject: [PATCH 154/442] detail page use core to pull data --- src/routes/Detail/Detail.js | 16 ++++----- src/routes/Detail/useMetaDetails.js | 51 +++++++++++++++++++++++++++++ src/routes/Detail/useMetaItem.js | 46 -------------------------- 3 files changed, 59 insertions(+), 54 deletions(-) create mode 100644 src/routes/Detail/useMetaDetails.js delete mode 100644 src/routes/Detail/useMetaItem.js diff --git a/src/routes/Detail/Detail.js b/src/routes/Detail/Detail.js index 4aa79feb8..8d65a25af 100644 --- a/src/routes/Detail/Detail.js +++ b/src/routes/Detail/Detail.js @@ -2,29 +2,29 @@ const React = require('react'); const { NavBar, MetaPreview } = require('stremio/common'); const VideosList = require('./VideosList'); const StreamsList = require('./StreamsList'); -const useMetaItem = require('./useMetaItem'); +const useMetaDetails = require('./useMetaDetails'); const useInLibrary = require('./useInLibrary'); const styles = require('./styles'); const Detail = ({ urlParams }) => { - const metaItem = useMetaItem(urlParams.type, urlParams.id, urlParams.videoId); + const [meta, streams] = useMetaDetails(urlParams); const [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary] = useInLibrary(urlParams.id); return (
{ - metaItem !== null ? + meta !== null && meta.content.type === 'Ready' ?
- {' + {'
{ } { typeof urlParams.videoId === 'string' && urlParams.videoId.length > 0 ? - + : - + }
diff --git a/src/routes/Detail/useMetaDetails.js b/src/routes/Detail/useMetaDetails.js new file mode 100644 index 000000000..b5afe283a --- /dev/null +++ b/src/routes/Detail/useMetaDetails.js @@ -0,0 +1,51 @@ +const React = require('react'); +const { useServices } = require('stremio/services'); + +const useMetaDetails = (urlParams) => { + const { core } = useServices(); + const [metaDetails, setMetaDetails] = React.useState([null, []]); + React.useEffect(() => { + const onNewModel = () => { + const state = core.getState(); + const selectedMeta = state.meta_details.metas.reduce((selectedMeta, meta) => { + if (selectedMeta === null && meta.content.type === 'Ready') { + selectedMeta = { + ...meta, + content: { + ...meta.content, + content: { + ...meta.content.content, + released: new Date(meta.content.content.released), + videos: meta.content.content.videos.map((video) => ({ + ...video, + released: new Date(video.released) + })) + } + } + }; + } + + return selectedMeta; + }, null); + setMetaDetails([selectedMeta, state.meta_details.streams]); + }; + core.on('NewModel', onNewModel); + core.dispatch({ + action: 'Load', + args: { + load: 'MetaDetails', + args: { + id: urlParams.id, + type_name: urlParams.type, + video_id: urlParams.videoId + } + } + }); + return () => { + core.off('NewModel', onNewModel); + }; + }, [urlParams]); + return metaDetails; +}; + +module.exports = useMetaDetails; diff --git a/src/routes/Detail/useMetaItem.js b/src/routes/Detail/useMetaItem.js deleted file mode 100644 index dd5d370ba..000000000 --- a/src/routes/Detail/useMetaItem.js +++ /dev/null @@ -1,46 +0,0 @@ -const React = require('react'); - -const useMetaItem = (type = '', id = '', videoId = '') => { - const [metaItem] = React.useState(() => ({ - id, - type, - name: 'Underworld', - logo: 'https://images.metahub.space/logo/medium/tt0320691/img', - background: 'https://images.metahub.space/background/medium/tt0320691/img', - duration: '121 min', - releaseInfo: '2003', - released: new Date('2003-09-19T00:00:00.000Z'), - description: 'Selene, a vampire warrior, is entrenched in a conflict between vampires and werewolves, while falling in love with Michael, a human who is sought by werewolves for unknown reasons.', - genres: ['Action', 'Fantasy', 'Thriller'], - writers: ['Kevin Grevioux', 'Len Wiseman', 'Danny McBride', 'Danny McBride'], - directors: ['Len Wiseman'], - cast: ['Kate Beckinsale', 'Scott Speedman', 'Michael Sheen', 'Shane Brolly'], - imdbRating: '7.0', - trailer: 'mn4O3iQ8B_s', - imdbId: 'tt0320691', - share: 'movie/underworld-0320691', - videos: [ - { - id: '1', - name: 'How to create a Stremio add-on with Node.js', - description: 'This is a step-by-step tutorial on how to create your own add-on using Node.js.', - released: new Date('Mon Jul 01 2019 00:00:00 GMT+0300 (Eastern European Summer Time)'), - poster: 'https://theme.zdassets.com/theme_assets/2160011/77a6ad5aee11a07eb9b87281070f1aadf946f2b3.png', - season: 1, - episode: 1 - }, - { - id: '2', - name: 'How to create a Stremio add-on with Node.js', - description: 'This is a step-by-step tutorial on how to create your own add-on using Node.js.', - released: new Date('Mon Jul 02 2019 00:00:00 GMT+0300 (Eastern European Summer Time)'), - poster: 'https://theme.zdassets.com/theme_assets/2160011/77a6ad5aee11a07eb9b87281070f1aadf946f2b3.png', - season: 2, - episode: 1 - } - ] - })); - return metaItem; -}; - -module.exports = useMetaItem; From 62e6ddde968ca81cc45a2aa29a2e8bb5fbe9b942 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 7 Nov 2019 16:30:38 +0200 Subject: [PATCH 155/442] query params for signup and login used --- src/routes/Intro/Intro.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 396c6cee1..1989cf6ea 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -8,10 +8,9 @@ const CredentialsTextInput = require('./CredentialsTextInput'); const ConsentCheckbox = require('./ConsentCheckbox'); const styles = require('./styles'); -const LOGIN_FORM = 'LOGIN_FORM'; -const SIGNUP_FORM = 'SIGNUP_FORM'; -// TODO queryparams for signup and login -const Intro = () => { +const SIGNUP_FORM = 'signup'; + +const Intro = ({ queryParams }) => { const { core } = useServices(); const routeFocused = useRouteFocused(); const emailRef = React.useRef(); @@ -21,12 +20,12 @@ const Intro = () => { const privacyPolicyRef = React.useRef(); const marketingRef = React.useRef(); const errorRef = React.useRef(); + const [selectedForm, setSelectedForm] = React.useState(queryParams.get('form')); const [state, dispatch] = React.useReducer( (state, action) => { switch (action.type) { - case 'switch-form': + case 'reset-form': return { - form: state.form === SIGNUP_FORM ? LOGIN_FORM : SIGNUP_FORM, email: '', password: '', confirmPassword: '', @@ -57,7 +56,6 @@ const Intro = () => { } }, { - form: SIGNUP_FORM, email: '', password: '', confirmPassword: '', @@ -166,12 +164,12 @@ const Intro = () => { }); }, []); const passwordOnSubmit = React.useCallback(() => { - if (state.form === SIGNUP_FORM) { + if (selectedForm === SIGNUP_FORM) { confirmPasswordRef.current.focus(); } else { loginWithEmail(); } - }, [state.form, loginWithEmail]); + }, [selectedForm, loginWithEmail]); const confirmPasswordOnChange = React.useCallback((event) => { dispatch({ type: 'change-credentials', @@ -191,9 +189,10 @@ const Intro = () => { const toggleMarketingAccepted = React.useCallback(() => { dispatch({ type: 'toggle-checkbox', name: 'marketingAccepted' }); }, []); - const switchForm = React.useCallback(() => { - dispatch({ type: 'switch-form' }); - }, []); + React.useEffect(() => { + dispatch({ type: 'reset-form' }); + setSelectedForm(queryParams.get('form')); + }, [queryParams]); React.useEffect(() => { if (typeof state.error === 'string' && state.error.length > 0) { errorRef.current.scrollIntoView(); @@ -203,7 +202,7 @@ const Intro = () => { if (routeFocused) { emailRef.current.focus(); } - }, [state.form, routeFocused]); + }, [selectedForm, routeFocused]); return (
@@ -231,7 +230,7 @@ const Intro = () => { onSubmit={passwordOnSubmit} /> { - state.form === SIGNUP_FORM ? + selectedForm === SIGNUP_FORM ? { : null } - { - state.form === SIGNUP_FORM ? + selectedForm === SIGNUP_FORM ? : null } -
From fbf0779c4c87398b3add6f54b2ef8c810e3de034 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 7 Nov 2019 17:08:41 +0200 Subject: [PATCH 156/442] emit empty meta on error --- src/routes/Detail/useMetaDetails.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/routes/Detail/useMetaDetails.js b/src/routes/Detail/useMetaDetails.js index b5afe283a..d9dd82fd4 100644 --- a/src/routes/Detail/useMetaDetails.js +++ b/src/routes/Detail/useMetaDetails.js @@ -7,26 +7,26 @@ const useMetaDetails = (urlParams) => { React.useEffect(() => { const onNewModel = () => { const state = core.getState(); - const selectedMeta = state.meta_details.metas.reduce((selectedMeta, meta) => { - if (selectedMeta === null && meta.content.type === 'Ready') { + let selectedMeta = state.meta_details.metas.find((meta) => meta.content.type === 'Ready'); + if (!selectedMeta) { + if (state.meta_details.metas.every((meta) => meta.content.type === 'Err')) { selectedMeta = { - ...meta, content: { - ...meta.content, - content: { - ...meta.content.content, - released: new Date(meta.content.content.released), - videos: meta.content.content.videos.map((video) => ({ - ...video, - released: new Date(video.released) - })) - } + type: 'Ready', + content: {} } }; + } else { + selectedMeta = null; } + } else { + selectedMeta.content.content.released = new Date(selectedMeta.content.content.released); + selectedMeta.content.content.videos = selectedMeta.content.content.videos.map((video) => ({ + ...video, + released: new Date(video.released) + })); + } - return selectedMeta; - }, null); setMetaDetails([selectedMeta, state.meta_details.streams]); }; core.on('NewModel', onNewModel); From 9e7fd2c4681bb4cb2673c6407d861a8d6bec270b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 8 Nov 2019 09:42:04 +0200 Subject: [PATCH 157/442] streams rendered properly --- src/routes/Detail/StreamsList/StreamsList.js | 23 +++++++++++------- src/routes/Detail/StreamsList/styles.less | 7 ++++++ src/routes/Detail/StreamsList/useStreams.js | 25 -------------------- 3 files changed, 21 insertions(+), 34 deletions(-) delete mode 100644 src/routes/Detail/StreamsList/useStreams.js diff --git a/src/routes/Detail/StreamsList/StreamsList.js b/src/routes/Detail/StreamsList/StreamsList.js index 4d0102d91..664520111 100644 --- a/src/routes/Detail/StreamsList/StreamsList.js +++ b/src/routes/Detail/StreamsList/StreamsList.js @@ -5,20 +5,18 @@ const Icon = require('stremio-icons/dom'); const { Button } = require('stremio/common'); const Stream = require('./Stream'); const StreamPlaceholder = require('./StreamPlaceholder'); -const useStreams = require('./useStreams'); const styles = require('./styles'); -const StreamsList = ({ className, metaItem }) => { - const streams = useStreams(metaItem); +const StreamsList = ({ className, streams }) => { + const readyStreams = streams + .filter(stream => stream.content.type === 'Ready') + .map(stream => stream.content.content) + .flat(); return (
{ - streams.length > 0 ? - streams.map((stream) => ( - - )) - : + streams.length === 0 || streams.every(stream => stream.content.type === 'Loading') ? @@ -27,6 +25,13 @@ const StreamsList = ({ className, metaItem }) => { + : + readyStreams.length === 0 ? +
No streams were found
+ : + readyStreams.map((stream) => ( + + )) }
{ - selectedForm === SIGNUP_FORM ? + state.form === SIGNUP_FORM ? : null } -
From eae70a7fbb3a98b15cbb4867d7316b923c96b8c7 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 11 Nov 2019 11:51:39 +0200 Subject: [PATCH 166/442] useMetaDetails refactored to handle error cases --- src/routes/Detail/useMetaDetails.js | 40 +++++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/routes/Detail/useMetaDetails.js b/src/routes/Detail/useMetaDetails.js index d9dd82fd4..3808cb3ff 100644 --- a/src/routes/Detail/useMetaDetails.js +++ b/src/routes/Detail/useMetaDetails.js @@ -7,27 +7,39 @@ const useMetaDetails = (urlParams) => { React.useEffect(() => { const onNewModel = () => { const state = core.getState(); - let selectedMeta = state.meta_details.metas.find((meta) => meta.content.type === 'Ready'); - if (!selectedMeta) { - if (state.meta_details.metas.every((meta) => meta.content.type === 'Err')) { - selectedMeta = { + const [metaRequest] = state.meta_details.selected; + const readyMeta = state.meta_details.metas + .filter((meta) => meta.content.type === 'Ready') + .map((meta) => { + meta.content.content.released = new Date(meta.content.content.released); + meta.content.content.videos = meta.content.content.videos.map((video) => ({ + ...video, + released: new Date(video.released) + })); + return meta; + }) + .shift(); + if (metaRequest) { + if (readyMeta) { + setMetaDetails([readyMeta, state.meta_details.streams]); + } else if (state.meta_details.metas.length === 0) { + const errMeta = { content: { - type: 'Ready', - content: {} + type: 'Err', + content: { + type: 'EmptyContent' + } } }; + setMetaDetails([errMeta, state.meta_details.streams]); + } else if (state.meta_details.metas.every((meta) => meta.content.type === 'Err')) { + setMetaDetails([state.meta_details.metas[0], state.meta_details.streams]); } else { - selectedMeta = null; + setMetaDetails([null, state.meta_details.streams]); } } else { - selectedMeta.content.content.released = new Date(selectedMeta.content.content.released); - selectedMeta.content.content.videos = selectedMeta.content.content.videos.map((video) => ({ - ...video, - released: new Date(video.released) - })); + setMetaDetails([null, state.meta_details.streams]); } - - setMetaDetails([selectedMeta, state.meta_details.streams]); }; core.on('NewModel', onNewModel); core.dispatch({ From 187faba125e5dfd7c82c9f61233891ed6f7add15 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 11 Nov 2019 11:52:08 +0200 Subject: [PATCH 167/442] use mete group as a prop of videoslist --- src/routes/Detail/Detail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Detail/Detail.js b/src/routes/Detail/Detail.js index 8d65a25af..352cea612 100644 --- a/src/routes/Detail/Detail.js +++ b/src/routes/Detail/Detail.js @@ -38,7 +38,7 @@ const Detail = ({ urlParams }) => { typeof urlParams.videoId === 'string' && urlParams.videoId.length > 0 ? : - + }
From 204f7ead5272ec1435b4764ceba28fbc60857955 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 11 Nov 2019 12:40:21 +0200 Subject: [PATCH 168/442] inline baseUrl --- src/common/useUser.js | 1 - src/routes/Intro/Intro.js | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/common/useUser.js b/src/common/useUser.js index dd7f97482..cb92a36b6 100644 --- a/src/common/useUser.js +++ b/src/common/useUser.js @@ -13,7 +13,6 @@ const useUser = () => { setUser(state.ctx.content.auth ? state.ctx.content.auth.user : null); }; core.on('NewModel', onNewState); - onNewState(); return () => { core.off('NewModel', onNewState); }; diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 8b7e8983d..beb35e26d 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -9,7 +9,6 @@ const ConsentCheckbox = require('./ConsentCheckbox'); const styles = require('./styles'); const SIGNUP_FORM = 'signup'; -const baseUrl = 'https://www.strem.io'; const Intro = ({ queryParams }) => { const { core } = useServices(); @@ -90,7 +89,7 @@ const Intro = ({ queryParams }) => { const loginWithFacebook = React.useCallback(() => { FB.login((response) => { if (response.status === 'connected') { - fetch(baseUrl + "/fb-login-with-token/" + encodeURIComponent(response.authResponse.accessToken), { timeout: 10 * 1000 }) + fetch('https://www.strem.io/fb-login-with-token/' + encodeURIComponent(response.authResponse.accessToken), { timeout: 10 * 1000 }) .then((resp) => { if (resp.status < 200 || resp.status >= 300) { throw new Error('Login failed at getting token from Stremio with status ' + resp.status); From 40660a01d70767eb81036e24f1da972f0f92df49 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 11 Nov 2019 13:32:03 +0200 Subject: [PATCH 169/442] error and loading cases handled in videos list --- src/routes/Detail/VideosList/VideosList.js | 78 +++++++++++++--------- src/routes/Detail/VideosList/styles.less | 8 ++- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/routes/Detail/VideosList/VideosList.js b/src/routes/Detail/VideosList/VideosList.js index 0be73e3bf..fe87e6d46 100644 --- a/src/routes/Detail/VideosList/VideosList.js +++ b/src/routes/Detail/VideosList/VideosList.js @@ -8,39 +8,20 @@ const VideoPlaceholder = require('./VideoPlaceholder'); const useSeasons = require('./useSeasons'); const styles = require('./styles'); -const VideosList = ({ className, metaItem }) => { - const [season, seasons, setSeason] = useSeasons(metaItem); +const VideosList = ({ className, meta }) => { + const [season, seasons, setSeason] = useSeasons(meta !== null && meta.content.type === 'Ready' ? meta.content.content : null); + const videos = React.useMemo(() => { + return meta !== null && meta.content.type === 'Ready' ? + meta.content.content.videos.filter((video) => { + return isNaN(season) || video.season === season; + }) + : + []; + }, [meta, season]); return (
{ - metaItem !== null ? - - { - seasons.length > 1 ? - - : - null - } -
- { - metaItem.videos - .filter((video) => isNaN(season) || video.season === season) - .map((video) => ( -
-
- : + meta === null ?
@@ -54,6 +35,41 @@ const VideosList = ({ className, metaItem }) => {
+ : + meta.content.type === 'Ready' ? + + { + seasons.length > 1 ? + + : + null + } + { + videos.length > 0 ? +
+ {videos.map((video, index) => ( +
+ : +
+ No videos +
+ } +
+ : +
+ No videos +
}
); @@ -61,7 +77,7 @@ const VideosList = ({ className, metaItem }) => { VideosList.propTypes = { className: PropTypes.string, - metaItem: PropTypes.object + meta: PropTypes.object }; module.exports = VideosList; diff --git a/src/routes/Detail/VideosList/styles.less b/src/routes/Detail/VideosList/styles.less index 2370a2899..a061fc31d 100644 --- a/src/routes/Detail/VideosList/styles.less +++ b/src/routes/Detail/VideosList/styles.less @@ -3,12 +3,18 @@ flex-direction: column; background: var(--color-backgrounddark80); - .seasons-bar { + .seasons-bar, .message-label { flex: none; width: var(--item-size); margin: 2rem 2rem 1rem 2rem; } + .message-label { + font-size: 2rem; + text-align: center; + color: var(--color-surfacelighter); + } + .videos-scroll-container { flex: 1; align-self: stretch; From dad73516298226e8ba3744c43ab141ed49caeb92 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 11 Nov 2019 15:06:51 +0200 Subject: [PATCH 170/442] Video component adapted to the video model --- src/routes/Detail/VideosList/Video/Video.js | 36 +++++++++++-------- .../Detail/VideosList/Video/styles.less | 13 +++++-- src/routes/Detail/useMetaDetails.js | 13 ++++--- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/routes/Detail/VideosList/Video/Video.js b/src/routes/Detail/VideosList/Video/Video.js index 7a37fafc4..d9ca1fbee 100644 --- a/src/routes/Detail/VideosList/Video/Video.js +++ b/src/routes/Detail/VideosList/Video/Video.js @@ -1,25 +1,35 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const { Button } = require('stremio/common'); +const { Button, Image } = require('stremio/common'); const Icon = require('stremio-icons/dom'); const styles = require('./styles'); -const Video = ({ className, id, name, poster, episode, released, watched, upcoming, progress, onClick }) => { +const Video = ({ className, title, thumbnail, episode, released, upcoming, watched, progress, ...props }) => { return ( - )} renderMenu={() => ( -
+
{ options.length > 0 ? options.map(({ label, value }) => ( @@ -119,14 +120,15 @@ Multiselect.propTypes = { className: PropTypes.string, direction: PropTypes.any, title: PropTypes.string, - renderLabelContent: PropTypes.func, - renderLabelText: PropTypes.func, options: PropTypes.arrayOf(PropTypes.shape({ value: PropTypes.string.isRequired, label: PropTypes.string })), selected: PropTypes.arrayOf(PropTypes.string), disabled: PropTypes.bool, + dataset: PropTypes.objectOf(String), + renderLabelContent: PropTypes.func, + renderLabelText: PropTypes.func, onOpen: PropTypes.func, onClose: PropTypes.func, onSelect: PropTypes.func diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index 83f27dc8c..d7830965e 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -10,9 +10,6 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque const menuOnMouseDown = React.useCallback((event) => { event.nativeEvent.closePopupPrevented = true; }, []); - const menuOnKeyUp = React.useCallback((event) => { - event.nativeEvent.buttonClickPrevented = true; - }, []); React.useEffect(() => { const onCloseEvent = (event) => { if (!event.closePopupPrevented && typeof onCloseRequest === 'function') { @@ -65,7 +62,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque ref: labelRef, className: styles['label-container'], children: open ? - + {renderMenu()} : From da33bfa168578a973a1ecf915417003fcadeab92 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 13 Nov 2019 23:26:06 +0200 Subject: [PATCH 194/442] enable spat nav in storybook --- storybook/config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/storybook/config.js b/storybook/config.js index fd756c0a6..64a3e6bd7 100644 --- a/storybook/config.js +++ b/storybook/config.js @@ -3,6 +3,7 @@ const { withConsole } = require('@storybook/addon-console'); const { addDecorator, addParameters, configure } = require('@storybook/react'); const { jsxDecorator } = require('storybook-addon-jsx'); const RouterDecorator = require('./RouterDecorator'); +require('spatial-navigation-polyfill'); require('./styles'); addParameters({ From 7954e4f26154931356e35686fa354976eff0ffac Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 13 Nov 2019 23:32:06 +0200 Subject: [PATCH 195/442] Multiselect stories added to storybook --- .../MultiselectMultipleValues.js | 37 ++++++++++++++++++ .../MultiselectMultipleValues/index.js | 1 + .../MultiselectMultipleValues/styles.less | 6 +++ .../MultiselectNotAutoClosing.js | 39 +++++++++++++++++++ .../MultiselectNotAutoClosing/index.js | 1 + .../MultiselectNotAutoClosing/styles.less | 6 +++ .../MultiselectSingleValue.js | 33 ++++++++++++++++ .../MultiselectSingleValue/index.js | 1 + .../MultiselectSingleValue/styles.less | 6 +++ storybook/stories/Multiselect/index.js | 3 ++ storybook/stories/index.js | 7 ++-- 11 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 storybook/stories/Multiselect/MultiselectMultipleValues/MultiselectMultipleValues.js create mode 100644 storybook/stories/Multiselect/MultiselectMultipleValues/index.js create mode 100644 storybook/stories/Multiselect/MultiselectMultipleValues/styles.less create mode 100644 storybook/stories/Multiselect/MultiselectNotAutoClosing/MultiselectNotAutoClosing.js create mode 100644 storybook/stories/Multiselect/MultiselectNotAutoClosing/index.js create mode 100644 storybook/stories/Multiselect/MultiselectNotAutoClosing/styles.less create mode 100644 storybook/stories/Multiselect/MultiselectSingleValue/MultiselectSingleValue.js create mode 100644 storybook/stories/Multiselect/MultiselectSingleValue/index.js create mode 100644 storybook/stories/Multiselect/MultiselectSingleValue/styles.less create mode 100644 storybook/stories/Multiselect/index.js diff --git a/storybook/stories/Multiselect/MultiselectMultipleValues/MultiselectMultipleValues.js b/storybook/stories/Multiselect/MultiselectMultipleValues/MultiselectMultipleValues.js new file mode 100644 index 000000000..af613c04b --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectMultipleValues/MultiselectMultipleValues.js @@ -0,0 +1,37 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { Multiselect } = require('stremio/common'); +const styles = require('./styles'); + +storiesOf('Multiselect', module).add('MultiselectMultipleValues', () => { + const [selected, setSelected] = React.useState(['a']); + const onSelect = React.useCallback((event) => { + action('onSelect')(event); + if (selected.includes(event.value)) { + setSelected(selected.filter((value) => value !== event.value)); + } else { + setSelected([...selected, event.value]); + } + }, [selected]); + return ( + + ); +}); \ No newline at end of file diff --git a/storybook/stories/Multiselect/MultiselectMultipleValues/index.js b/storybook/stories/Multiselect/MultiselectMultipleValues/index.js new file mode 100644 index 000000000..f7c2216f8 --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectMultipleValues/index.js @@ -0,0 +1 @@ +require('./MultiselectMultipleValues'); diff --git a/storybook/stories/Multiselect/MultiselectMultipleValues/styles.less b/storybook/stories/Multiselect/MultiselectMultipleValues/styles.less new file mode 100644 index 000000000..83da3846f --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectMultipleValues/styles.less @@ -0,0 +1,6 @@ +.label-container { + flex: none; + width: 17rem; + height: 3.6rem; + margin: 2rem; +} \ No newline at end of file diff --git a/storybook/stories/Multiselect/MultiselectNotAutoClosing/MultiselectNotAutoClosing.js b/storybook/stories/Multiselect/MultiselectNotAutoClosing/MultiselectNotAutoClosing.js new file mode 100644 index 000000000..5074694dc --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectNotAutoClosing/MultiselectNotAutoClosing.js @@ -0,0 +1,39 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { Multiselect } = require('stremio/common'); +const styles = require('./styles'); + +storiesOf('Multiselect', module).add('MultiselectNotAutoClosing', () => { + const [selected, setSelected] = React.useState(['a']); + const onSelect = React.useCallback((event) => { + action('onSelect')(event); + if (selected.includes(event.value)) { + setSelected(selected.filter((value) => value !== event.value)); + } else { + setSelected([...selected, event.value]); + } + + event.nativeEvent.closeMenuPrevented = true; + }, [selected]); + return ( + + ); +}); \ No newline at end of file diff --git a/storybook/stories/Multiselect/MultiselectNotAutoClosing/index.js b/storybook/stories/Multiselect/MultiselectNotAutoClosing/index.js new file mode 100644 index 000000000..666210910 --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectNotAutoClosing/index.js @@ -0,0 +1 @@ +require('./MultiselectNotAutoClosing'); diff --git a/storybook/stories/Multiselect/MultiselectNotAutoClosing/styles.less b/storybook/stories/Multiselect/MultiselectNotAutoClosing/styles.less new file mode 100644 index 000000000..83da3846f --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectNotAutoClosing/styles.less @@ -0,0 +1,6 @@ +.label-container { + flex: none; + width: 17rem; + height: 3.6rem; + margin: 2rem; +} \ No newline at end of file diff --git a/storybook/stories/Multiselect/MultiselectSingleValue/MultiselectSingleValue.js b/storybook/stories/Multiselect/MultiselectSingleValue/MultiselectSingleValue.js new file mode 100644 index 000000000..f143e5f8b --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectSingleValue/MultiselectSingleValue.js @@ -0,0 +1,33 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { Multiselect } = require('stremio/common'); +const styles = require('./styles'); + +storiesOf('Multiselect', module).add('MultiselectSingleValue', () => { + const [selected, setSelected] = React.useState(['a']); + const onSelect = React.useCallback((event) => { + action('onSelect')(event); + setSelected([event.value]); + }, []); + return ( + + ); +}); \ No newline at end of file diff --git a/storybook/stories/Multiselect/MultiselectSingleValue/index.js b/storybook/stories/Multiselect/MultiselectSingleValue/index.js new file mode 100644 index 000000000..3d9f8a316 --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectSingleValue/index.js @@ -0,0 +1 @@ +require('./MultiselectSingleValue'); diff --git a/storybook/stories/Multiselect/MultiselectSingleValue/styles.less b/storybook/stories/Multiselect/MultiselectSingleValue/styles.less new file mode 100644 index 000000000..83da3846f --- /dev/null +++ b/storybook/stories/Multiselect/MultiselectSingleValue/styles.less @@ -0,0 +1,6 @@ +.label-container { + flex: none; + width: 17rem; + height: 3.6rem; + margin: 2rem; +} \ No newline at end of file diff --git a/storybook/stories/Multiselect/index.js b/storybook/stories/Multiselect/index.js new file mode 100644 index 000000000..b9003647a --- /dev/null +++ b/storybook/stories/Multiselect/index.js @@ -0,0 +1,3 @@ +require('./MultiselectMultipleValues'); +require('./MultiselectNotAutoClosing'); +require('./MultiselectSingleValue'); diff --git a/storybook/stories/index.js b/storybook/stories/index.js index a3b450370..cf5c2b933 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -1,6 +1,7 @@ require('./Addon'); -require('./MetaItem'); require('./ColorPicker'); -require('./SharePrompt'); -require('./Notification'); +require('./MetaItem'); require('./ModalDialog'); +require('./Multiselect'); +require('./Notification'); +require('./SharePrompt'); From 82abac01e55127f1db9058c1704967e53fd91672 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 13 Nov 2019 23:32:26 +0200 Subject: [PATCH 196/442] spat nav fixed in storybook --- storybook/config.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storybook/config.js b/storybook/config.js index 64a3e6bd7..29f6de218 100644 --- a/storybook/config.js +++ b/storybook/config.js @@ -6,6 +6,10 @@ const RouterDecorator = require('./RouterDecorator'); require('spatial-navigation-polyfill'); require('./styles'); +window.top.__spatialNavigation__ = { + keyMode: 'ARROW' +}; + addParameters({ jsx: { indent_size: 4, From cf9423cd7a139f8c6e25f13e8ac5a2b70ddc2a17 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 13 Nov 2019 23:50:23 +0200 Subject: [PATCH 197/442] Popup story added to storybook --- storybook/stories/Popup/Popup.js | 46 +++++++++++++++++++++++++++++ storybook/stories/Popup/index.js | 1 + storybook/stories/Popup/styles.less | 40 +++++++++++++++++++++++++ storybook/stories/index.js | 1 + 4 files changed, 88 insertions(+) create mode 100644 storybook/stories/Popup/Popup.js create mode 100644 storybook/stories/Popup/index.js create mode 100644 storybook/stories/Popup/styles.less diff --git a/storybook/stories/Popup/Popup.js b/storybook/stories/Popup/Popup.js new file mode 100644 index 000000000..8e1f99515 --- /dev/null +++ b/storybook/stories/Popup/Popup.js @@ -0,0 +1,46 @@ +const React = require('react'); +const classnames = require('classnames'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { Button, Popup, useBinaryState } = require('stremio/common'); +const styles = require('./styles'); + +storiesOf('Popup', module).add('Popup', () => { + const [menuOpen, openMenu, closeMenu, toggleMenu] = useBinaryState(false); + const popupLabelOnClick = React.useCallback((event) => { + if (!event.nativeEvent.togglePopupPrevented) { + toggleMenu(); + } + }, [toggleMenu]); + const popupMenuOnClick = React.useCallback((event) => { + event.nativeEvent.togglePopupPrevented = true; + }, []); + const popupMenuOnKeyDown = React.useCallback((event) => { + event.nativeEvent.buttonClickPrevented = true; + }, []); + const onCloseRequest = React.useCallback((event) => { + action('onCloseRequest')(event); + closeMenu(); + }, []); + return ( + ( + + )} + renderMenu={() => ( +
+ {Array(10).fill(null).map((_, index) => ( + + ))} +
+ )} + dataset={{ prop: 'value' }} + onCloseRequest={onCloseRequest} + /> + ); +}); diff --git a/storybook/stories/Popup/index.js b/storybook/stories/Popup/index.js new file mode 100644 index 000000000..d3d099b48 --- /dev/null +++ b/storybook/stories/Popup/index.js @@ -0,0 +1 @@ +require('./Popup'); diff --git a/storybook/stories/Popup/styles.less b/storybook/stories/Popup/styles.less new file mode 100644 index 000000000..82d1d09e2 --- /dev/null +++ b/storybook/stories/Popup/styles.less @@ -0,0 +1,40 @@ +:import('~stremio/common/Popup/styles.less') { + popup-menu-container: menu-container; +} + +.popup-label-container { + flex: none; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + width: 10rem; + height: 3rem; + margin: 2rem; + padding: 0 1.2rem; + color: var(--color-surfacelighter); + background: var(--color-backgroundlight); + + .popup-menu-container { + right: initial; + left: 0; + + .menu-container { + width: 20rem; + height: 20rem; + padding: 2rem; + background: var(--color-surface); + overflow-y: auto; + + .random-button { + padding: 0.8rem; + background: var(--color-primary); + text-align: center; + + &:hover, &:focus { + background: var(--color-primarylight); + } + } + } + } +} \ No newline at end of file diff --git a/storybook/stories/index.js b/storybook/stories/index.js index cf5c2b933..e40aee097 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -4,4 +4,5 @@ require('./MetaItem'); require('./ModalDialog'); require('./Multiselect'); require('./Notification'); +require('./Popup'); require('./SharePrompt'); From 6f86c105e5739fe90916960e74eb7d6a708b7e6b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 08:05:51 +0200 Subject: [PATCH 198/442] Seasons bar uses multiselect instead of Popup --- .../VideosList/SeasonsBar/SeasonsBar.js | 121 +++++++++--------- .../Detail/VideosList/SeasonsBar/styles.less | 48 ++++--- 2 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js index 705e23988..26160461a 100644 --- a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js @@ -2,77 +2,72 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); -const { Button, Popup, useBinaryState } = require('stremio/common'); +const { Button, Multiselect } = require('stremio/common'); const styles = require('./styles'); -const SeasonsBar = ({ className, season, seasons, onSeasonChange }) => { - const [menuOpen, openMenu, closeMenu, toggleMenu] = useBinaryState(false); - const setPrevSeason = React.useCallback(() => { - if (Array.isArray(seasons) && typeof onSeasonChange === 'function') { +const SeasonsBar = ({ className, season, seasons, onSelect }) => { + const options = React.useMemo(() => { + return Array.isArray(seasons) ? + seasons.map((season) => ({ + value: String(season), + label: `Season ${season}` + })) + : + []; + }, [seasons]); + const selected = React.useMemo(() => { + return [String(season)]; + }, [season]); + const renderMultiselectLabelText = React.useMemo(() => { + return () => `Season ${season}`; + }, [season]); + const prevNextButtonOnClick = React.useCallback((event) => { + if (Array.isArray(seasons) && typeof onSelect === 'function') { const seasonIndex = seasons.indexOf(season); - if (seasonIndex > 0) { - onSeasonChange(seasons[seasonIndex - 1]); - } + const valueIndex = event.currentTarget.dataset.action === 'next' ? + seasonIndex + 1 + : + seasonIndex - 1; + const value = valueIndex >= 0 && valueIndex < seasons.length ? + seasons[valueIndex] + : + seasons[0]; + onSelect({ + type: 'select', + value: value, + reactEvent: event, + nativeEvent: event.nativeEvent + }); } - }, [season, seasons, onSeasonChange]); - const setNextSeason = React.useCallback(() => { - if (Array.isArray(seasons) && typeof onSeasonChange === 'function') { - const seasonIndex = seasons.indexOf(season); - if (seasonIndex < seasons.length - 1) { - onSeasonChange(seasons[seasonIndex + 1]); - } + }, [season, seasons, onSelect]); + const seasonOnSelect = React.useCallback((event) => { + const value = parseInt(event.value); + if (!isNaN(value) && typeof onSelect === 'function') { + onSelect({ + type: 'select', + value: value, + reactEvent: event.reactEvent, + nativeEvent: event.nativeEvent + }); } - }, [season, seasons, onSeasonChange]); - const seasonOnClick = React.useCallback((event) => { - closeMenu(); - const season = parseInt(event.currentTarget.dataset.season); - if (!isNaN(season) && typeof onSeasonChange === 'function') { - onSeasonChange(season); - } - }, [onSeasonChange]); + }, [onSelect]); return (
- - ( - - )} - renderMenu={() => ( -
- { - Array.isArray(seasons) ? - seasons.map((season) => ( - - )) - : - null - } -
- )} + -
); @@ -80,9 +75,9 @@ const SeasonsBar = ({ className, season, seasons, onSeasonChange }) => { SeasonsBar.propTypes = { className: PropTypes.string, - season: PropTypes.number, + selected: PropTypes.number, seasons: PropTypes.arrayOf(PropTypes.number), - onSeasonChange: PropTypes.func + onSelect: PropTypes.func }; module.exports = SeasonsBar; diff --git a/src/routes/Detail/VideosList/SeasonsBar/styles.less b/src/routes/Detail/VideosList/SeasonsBar/styles.less index a1ef9706d..4951755d6 100644 --- a/src/routes/Detail/VideosList/SeasonsBar/styles.less +++ b/src/routes/Detail/VideosList/SeasonsBar/styles.less @@ -1,6 +1,7 @@ .seasons-bar-container { display: flex; flex-direction: row; + overflow: visible; .prev-season-button, .next-season-button { flex: none; @@ -27,6 +28,7 @@ justify-content: center; margin: 0 1rem; background-color: var(--color-surfacedarker60); + overflow: visible; &:hover, &:focus, &:global(.active) { background-color: var(--color-surfacedarker); @@ -37,33 +39,37 @@ max-width: 50%; max-height: 3.6em; padding: 0 0.2rem; - font-size: 1.2rem; + font-size: 1.1rem; color: var(--color-surfacelighter); } - } -} -.seasons-menu-container { - background-color: var(--color-surfacelighter); + .popup-menu-container { + width: 100%; - .season-option-container { - display: flex; - align-items: center; - justify-content: center; - height: 4rem; + .seasons-menu-container { + background-color: var(--color-surfacelighter); - &:hover, &:focus { - outline: none; - background-color: var(--color-surfacelight); - } + .season-option-container { + display: flex; + align-items: center; + justify-content: center; + height: 4rem; - .season-label, .number-label { - flex: none; - max-width: 50%; - max-height: 3.6em; - padding: 0 0.2rem; - font-size: 1.2rem; - color: var(--color-backgrounddarker); + &:hover, &:focus { + outline: none; + background-color: var(--color-surfacelight); + } + + .season-label, .number-label { + flex: none; + max-width: 50%; + max-height: 3.6em; + padding: 0 0.2rem; + font-size: 1.2rem; + color: var(--color-backgrounddarker); + } + } + } } } } \ No newline at end of file From ae3db87fe513bb0d8d734dc0b753d1adb2ab3686 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 14 Nov 2019 11:23:48 +0200 Subject: [PATCH 199/442] library linked with stremio-core --- src/routes/Library/Library.js | 21 +++-- src/routes/Library/styles.less | 1 + src/routes/Library/useLibrary.js | 152 +++++++++++++------------------ 3 files changed, 73 insertions(+), 101 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 5b75fcfaf..95ed7eb93 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -1,26 +1,27 @@ const React = require('react'); -const { Dropdown, MainNavBar, MetaItem } = require('stremio/common'); +const { Multiselect, MainNavBar, MetaItem } = require('stremio/common'); const useLibrary = require('./useLibrary'); const styles = require('./styles'); const Library = ({ urlParams, queryParams }) => { - const [metaItems, dropdowns] = useLibrary(urlParams.type, queryParams.get('sort')); + const [metaItems, dropdowns] = useLibrary(urlParams, queryParams); return (
- {dropdowns.map((dropdown) => ( - + {dropdowns.map((dropdown, index) => ( + ))}
- {metaItems.map((metaItem) => ( - - ))} + {metaItems + .map((metaItem, index) => ( + + ))}
diff --git a/src/routes/Library/styles.less b/src/routes/Library/styles.less index 156166891..31a302c9e 100644 --- a/src/routes/Library/styles.less +++ b/src/routes/Library/styles.less @@ -27,6 +27,7 @@ display: flex; flex-direction: row; margin: 2rem; + overflow: visible; .dropdown { flex-grow: 0; diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 452f63bd9..73291f847 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -1,99 +1,69 @@ const React = require('react'); +const { useServices } = require('stremio/services'); const DEFAULT_TYPE = 'movie'; -const libraryItems = [ - { - id: '1', - type: 'movie', - name: 'Stremio demo item movie 1', - poster: '/images/intro_background.jpg', - logo: '/images/default_avatar.png', - posterShape: 'poster' - }, - { - id: '2', - type: 'movie', - name: 'Stremio demo item movie 2', - poster: '/images/intro_background.jpg', - logo: '/images/default_avatar.png', - posterShape: 'poster' - }, - { - id: '3', - type: 'series', - name: 'Stremio demo item series 1', - poster: '/images/default_avatar.png', - logo: '/images/default_avatar.png', - posterShape: 'poster' - }, - { - id: '4', - type: 'series', - name: 'Stremio demo item series 2', - poster: '/images/default_avatar.png', - logo: '/images/default_avatar.png', - posterShape: 'poster' - }, - { - id: '5', - type: 'channel', - name: 'Stremio demo item channel 1', - poster: '/images/anonymous.png', - logo: '/images/default_avatar.png', - posterShape: 'square' - }, - { - id: '6', - type: 'channel', - name: 'Stremio demo item channel 2', - poster: '/images/anonymous.png', - logo: '/images/default_avatar.png', - posterShape: 'square' - } -]; +const DEFAULT_SORT = 'recent'; -const useLibrary = (type, sort) => { - type = typeof type === 'string' && type.length > 0 ? type : DEFAULT_TYPE; - const items = React.useMemo(() => { - return libraryItems.filter(item => item.type === type); - }, [type, sort]); - const onSelect = React.useCallback((event) => { - const { name, value } = event.currentTarget.dataset; - if (name === 'type') { - const nextQuery = new URLSearchParams({ sort: typeof sort === 'string' ? sort : '' }); - const nextType = typeof value === 'string' ? value : ''; - window.location.replace(`#/library/${nextType}?${nextQuery}`); - } else if (name === 'sort') { - const nextQuery = new URLSearchParams({ sort: typeof value === 'string' ? value : '' }); - const nextType = typeof type === 'string' ? type : ''; - window.location.replace(`#/library/${nextType}?${nextQuery}`); +const useLibrary = (urlParams, queryParams) => { + const { core } = useServices(); + const [library, setLibrary] = React.useState([[], []]); + + React.useEffect(() => { + const type = typeof urlParams.type === 'string' && urlParams.type.length > 0 ? urlParams.type : DEFAULT_TYPE; + const sort = typeof queryParams.get('sort') === 'string' && queryParams.get('sort').length > 0 ? queryParams.get('sort') : DEFAULT_SORT; + const onNewState = () => { + const state = core.getState(); + const sortItems = (items, prop) => { + return items + .filter(item => !item.removed) + .sort((a, b) => { + if (a[prop] < b[prop]) return -1; + if (a[prop] > b[prop]) return 1; + return 0; + }); + } + const selectInputs = [ + { + selected: [type], + options: state.library.types + .map((type) => ({ + label: type, + value: type + })), + onSelect: (event) => { + const value = event.value; + const nextQuery = new URLSearchParams({ sort: typeof sort === 'string' ? sort : '' }); + const nextType = typeof value === 'string' ? value : ''; + window.location.replace(`#/library/${nextType}?${nextQuery}`); + } + }, + { + selected: [sort], + options: [{ label: 'A-Z', value: 'a-z' }, { label: 'Recent', value: 'recent' }], + onSelect: (event) => { + const value = event.value; + const nextQuery = new URLSearchParams({ sort: typeof value === 'string' ? value : '' }); + const nextType = typeof type === 'string' ? type : ''; + window.location.replace(`#/library/${nextType}?${nextQuery}`); + } + } + ]; + const items = sort === 'recent' ? sortItems(state.library.items, '_ctime') : sortItems(state.library.items, 'name'); + setLibrary([items, selectInputs]); } - }, [type, sort]); - const typeDropdown = React.useMemo(() => { - const selected = typeof type === 'string' && type.length > 0 ? [type] : []; - const options = libraryItems - .map(({ type }) => type) - .concat(selected) - .filter((type, index, types) => types.indexOf(type) === index) - .map((type) => ({ label: type, value: type })); - return { - name: 'type', - selected, - options, - onSelect + core.on('NewModel', onNewState); + core.dispatch({ + action: 'Load', + args: { + load: 'LibItemsByType', + args: type + } + }); + return () => { + core.off('NewModel', onNewState); }; - }, [type, onSelect]); - const sortDropdown = React.useMemo(() => { - const selected = typeof sort === 'string' && sort.length > 0 ? [sort] : []; - const options = [{ label: 'A-Z', value: 'a-z' }, { label: 'Recent', value: 'recent' }]; - return { - name: 'sort', - selected, - options, - onSelect - }; - }, [sort, onSelect]); - return [items, [typeDropdown, sortDropdown]]; -}; + }, [urlParams, queryParams]); + return library; +} module.exports = useLibrary; From 2a12457be33aa0cc2bdb662a3497a56c2532c0c8 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 14 Nov 2019 11:26:50 +0200 Subject: [PATCH 200/442] size media queries fixed --- src/routes/Library/styles.less | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/routes/Library/styles.less b/src/routes/Library/styles.less index 31a302c9e..44eaa213e 100644 --- a/src/routes/Library/styles.less +++ b/src/routes/Library/styles.less @@ -57,7 +57,7 @@ .library-container { .library-content { .meta-items-container { - grid-template-columns: repeat(10, auto); + grid-template-columns: repeat(10, 1fr); } } } @@ -67,7 +67,7 @@ .library-container { .library-content { .meta-items-container { - grid-template-columns: repeat(9, auto); + grid-template-columns: repeat(9, 1fr); } } } @@ -77,7 +77,7 @@ .library-container { .library-content { .meta-items-container { - grid-template-columns: repeat(8, auto); + grid-template-columns: repeat(8, 1fr); } } } @@ -87,7 +87,7 @@ .library-container { .library-content { .meta-items-container { - grid-template-columns: repeat(7, auto); + grid-template-columns: repeat(7, 1fr); } } } @@ -97,7 +97,7 @@ .library-container { .library-content { .meta-items-container { - grid-template-columns: repeat(6, auto); + grid-template-columns: repeat(6, 1fr); } } } @@ -107,7 +107,7 @@ .library-container { .library-content { .meta-items-container { - grid-template-columns: repeat(5, auto); + grid-template-columns: repeat(5, 1fr); } } } From e0ec521755472d2ccd28e208e67ce08c9499227c Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 12:32:31 +0200 Subject: [PATCH 201/442] SeasonBar reimplemented following the common styles for pickers --- .../VideosList/SeasonsBar/SeasonsBar.js | 44 +++++++++---------- .../Detail/VideosList/SeasonsBar/styles.less | 42 ++++-------------- 2 files changed, 28 insertions(+), 58 deletions(-) diff --git a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js index 26160461a..8e50ce2a3 100644 --- a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js @@ -5,33 +5,29 @@ const Icon = require('stremio-icons/dom'); const { Button, Multiselect } = require('stremio/common'); const styles = require('./styles'); -const SeasonsBar = ({ className, season, seasons, onSelect }) => { +const SeasonsBar = ({ className, seasons, season, onSelect }) => { const options = React.useMemo(() => { - return Array.isArray(seasons) ? - seasons.map((season) => ({ - value: String(season), - label: `Season ${season}` - })) - : - []; + return seasons.map((season) => ({ + value: String(season), + label: `Season ${season}` + })); }, [seasons]); const selected = React.useMemo(() => { return [String(season)]; }, [season]); - const renderMultiselectLabelText = React.useMemo(() => { - return () => `Season ${season}`; + const renderMultiselectLabelContent = React.useMemo(() => { + return () => ( +
Season {season}
+ ); }, [season]); const prevNextButtonOnClick = React.useCallback((event) => { - if (Array.isArray(seasons) && typeof onSelect === 'function') { + if (typeof onSelect === 'function') { const seasonIndex = seasons.indexOf(season); const valueIndex = event.currentTarget.dataset.action === 'next' ? - seasonIndex + 1 + seasonIndex + 1 < seasons.length ? seasonIndex + 1 : seasons.length - 1 : - seasonIndex - 1; - const value = valueIndex >= 0 && valueIndex < seasons.length ? - seasons[valueIndex] - : - seasons[0]; + seasonIndex - 1 >= 0 ? seasonIndex - 1 : 0; + const value = seasons[valueIndex]; onSelect({ type: 'select', value: value, @@ -41,8 +37,8 @@ const SeasonsBar = ({ className, season, seasons, onSelect }) => { } }, [season, seasons, onSelect]); const seasonOnSelect = React.useCallback((event) => { - const value = parseInt(event.value); - if (!isNaN(value) && typeof onSelect === 'function') { + const value = parseFloat(event.value); + if (typeof onSelect === 'function') { onSelect({ type: 'select', value: value, @@ -59,15 +55,15 @@ const SeasonsBar = ({ className, season, seasons, onSelect }) => {
); @@ -75,8 +71,8 @@ const SeasonsBar = ({ className, season, seasons, onSelect }) => { SeasonsBar.propTypes = { className: PropTypes.string, - selected: PropTypes.number, - seasons: PropTypes.arrayOf(PropTypes.number), + seasons: PropTypes.arrayOf(PropTypes.number).isRequired, + season: PropTypes.number.isRequired, onSelect: PropTypes.func }; diff --git a/src/routes/Detail/VideosList/SeasonsBar/styles.less b/src/routes/Detail/VideosList/SeasonsBar/styles.less index 4951755d6..859f68770 100644 --- a/src/routes/Detail/VideosList/SeasonsBar/styles.less +++ b/src/routes/Detail/VideosList/SeasonsBar/styles.less @@ -5,6 +5,8 @@ .prev-season-button, .next-season-button { flex: none; + width: 4rem; + height: 4rem; padding: 1rem; background-color: var(--color-surfacedarker60); @@ -14,8 +16,8 @@ .icon { display: block; - width: 2rem; - height: 2rem; + width: 100%; + height: 100%; fill: var(--color-surfacelighter); } } @@ -34,42 +36,14 @@ background-color: var(--color-surfacedarker); } - .season-label, .number-label { - flex: none; - max-width: 50%; + .season-label { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; max-height: 3.6em; padding: 0 0.2rem; font-size: 1.1rem; color: var(--color-surfacelighter); } - - .popup-menu-container { - width: 100%; - - .seasons-menu-container { - background-color: var(--color-surfacelighter); - - .season-option-container { - display: flex; - align-items: center; - justify-content: center; - height: 4rem; - - &:hover, &:focus { - outline: none; - background-color: var(--color-surfacelight); - } - - .season-label, .number-label { - flex: none; - max-width: 50%; - max-height: 3.6em; - padding: 0 0.2rem; - font-size: 1.2rem; - color: var(--color-backgrounddarker); - } - } - } - } } } \ No newline at end of file From d4836feef47ee9456e228f34bc85da440c8f57d7 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 12:33:00 +0200 Subject: [PATCH 202/442] SeasonBar story added to storybook --- storybook/stories/SeasonsBar/SeasonsBar.js | 24 ++++++++++++++++++++++ storybook/stories/SeasonsBar/index.js | 1 + storybook/stories/SeasonsBar/styles.less | 5 +++++ storybook/stories/index.js | 1 + 4 files changed, 31 insertions(+) create mode 100644 storybook/stories/SeasonsBar/SeasonsBar.js create mode 100644 storybook/stories/SeasonsBar/index.js create mode 100644 storybook/stories/SeasonsBar/styles.less diff --git a/storybook/stories/SeasonsBar/SeasonsBar.js b/storybook/stories/SeasonsBar/SeasonsBar.js new file mode 100644 index 000000000..44dc65d49 --- /dev/null +++ b/storybook/stories/SeasonsBar/SeasonsBar.js @@ -0,0 +1,24 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const SeasonsBar = require('stremio/routes/Detail/VideosList/SeasonsBar'); +const styles = require('./styles'); + +storiesOf('SeasonsBar', module).add('SeasonsBar', () => { + const [season, setSeason] = React.useState(1); + const seasons = React.useMemo(() => { + return [1, 2, 3, 4, 5, /*6,*/ 7]; + }, []); + const onSelect = React.useCallback((event) => { + action('onSelect')(event); + setSeason(event.value); + }, []); + return ( + + ); +}); diff --git a/storybook/stories/SeasonsBar/index.js b/storybook/stories/SeasonsBar/index.js new file mode 100644 index 000000000..cd28454e8 --- /dev/null +++ b/storybook/stories/SeasonsBar/index.js @@ -0,0 +1 @@ +require('./SeasonsBar'); diff --git a/storybook/stories/SeasonsBar/styles.less b/storybook/stories/SeasonsBar/styles.less new file mode 100644 index 000000000..a62a204c7 --- /dev/null +++ b/storybook/stories/SeasonsBar/styles.less @@ -0,0 +1,5 @@ +.seasons-bar { + flex: none; + width: 28rem; + margin: 2rem; +} \ No newline at end of file diff --git a/storybook/stories/index.js b/storybook/stories/index.js index e40aee097..9dcb43889 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -5,4 +5,5 @@ require('./ModalDialog'); require('./Multiselect'); require('./Notification'); require('./Popup'); +require('./SeasonsBar'); require('./SharePrompt'); From 628e496bffb8e0826f80c4ae7a651534d00c290e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 12:40:43 +0200 Subject: [PATCH 203/442] SeasonsBarPlaceholder moved inside SeasonsBar --- .../SeasonsBarPlaceholder/SeasonsBarPlaceholder.js | 0 .../VideosList/{ => SeasonsBar}/SeasonsBarPlaceholder/index.js | 0 .../{ => SeasonsBar}/SeasonsBarPlaceholder/styles.less | 0 src/routes/Detail/VideosList/VideosList.js | 3 +-- 4 files changed, 1 insertion(+), 2 deletions(-) rename src/routes/Detail/VideosList/{ => SeasonsBar}/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js (100%) rename src/routes/Detail/VideosList/{ => SeasonsBar}/SeasonsBarPlaceholder/index.js (100%) rename src/routes/Detail/VideosList/{ => SeasonsBar}/SeasonsBarPlaceholder/styles.less (100%) diff --git a/src/routes/Detail/VideosList/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js rename to src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js diff --git a/src/routes/Detail/VideosList/SeasonsBarPlaceholder/index.js b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/index.js similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBarPlaceholder/index.js rename to src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/index.js diff --git a/src/routes/Detail/VideosList/SeasonsBarPlaceholder/styles.less b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBarPlaceholder/styles.less rename to src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less diff --git a/src/routes/Detail/VideosList/VideosList.js b/src/routes/Detail/VideosList/VideosList.js index 46ea3edf1..c60935042 100644 --- a/src/routes/Detail/VideosList/VideosList.js +++ b/src/routes/Detail/VideosList/VideosList.js @@ -2,7 +2,6 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const SeasonsBar = require('./SeasonsBar'); -const SeasonsBarPlaceholder = require('./SeasonsBarPlaceholder'); const Video = require('./Video'); const VideoPlaceholder = require('./VideoPlaceholder'); const useSelectableSeasons = require('./useSelectableSeasons'); @@ -26,7 +25,7 @@ const VideosList = ({ className, metaGroup }) => { { !metaGroup || metaGroup.content.type === 'Loading' ? - +
From f0b51e0a73d2a798cc0328561e7d8b01ab1d4bae Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 12:42:13 +0200 Subject: [PATCH 204/442] SeasonsBar story moved to SampleSeasonsBar --- .../{SeasonsBar.js => SampleSeasonsBar/SampleSeasonsBar.js} | 2 +- storybook/stories/SeasonsBar/SampleSeasonsBar/index.js | 1 + storybook/stories/SeasonsBar/{ => SampleSeasonsBar}/styles.less | 0 storybook/stories/SeasonsBar/index.js | 2 +- 4 files changed, 3 insertions(+), 2 deletions(-) rename storybook/stories/SeasonsBar/{SeasonsBar.js => SampleSeasonsBar/SampleSeasonsBar.js} (91%) create mode 100644 storybook/stories/SeasonsBar/SampleSeasonsBar/index.js rename storybook/stories/SeasonsBar/{ => SampleSeasonsBar}/styles.less (100%) diff --git a/storybook/stories/SeasonsBar/SeasonsBar.js b/storybook/stories/SeasonsBar/SampleSeasonsBar/SampleSeasonsBar.js similarity index 91% rename from storybook/stories/SeasonsBar/SeasonsBar.js rename to storybook/stories/SeasonsBar/SampleSeasonsBar/SampleSeasonsBar.js index 44dc65d49..f7a25a33c 100644 --- a/storybook/stories/SeasonsBar/SeasonsBar.js +++ b/storybook/stories/SeasonsBar/SampleSeasonsBar/SampleSeasonsBar.js @@ -4,7 +4,7 @@ const { action } = require('@storybook/addon-actions'); const SeasonsBar = require('stremio/routes/Detail/VideosList/SeasonsBar'); const styles = require('./styles'); -storiesOf('SeasonsBar', module).add('SeasonsBar', () => { +storiesOf('SeasonsBar', module).add('SampleSeasonsBar', () => { const [season, setSeason] = React.useState(1); const seasons = React.useMemo(() => { return [1, 2, 3, 4, 5, /*6,*/ 7]; diff --git a/storybook/stories/SeasonsBar/SampleSeasonsBar/index.js b/storybook/stories/SeasonsBar/SampleSeasonsBar/index.js new file mode 100644 index 000000000..9b63be877 --- /dev/null +++ b/storybook/stories/SeasonsBar/SampleSeasonsBar/index.js @@ -0,0 +1 @@ +require('./SampleSeasonsBar'); \ No newline at end of file diff --git a/storybook/stories/SeasonsBar/styles.less b/storybook/stories/SeasonsBar/SampleSeasonsBar/styles.less similarity index 100% rename from storybook/stories/SeasonsBar/styles.less rename to storybook/stories/SeasonsBar/SampleSeasonsBar/styles.less diff --git a/storybook/stories/SeasonsBar/index.js b/storybook/stories/SeasonsBar/index.js index cd28454e8..c3a9531b5 100644 --- a/storybook/stories/SeasonsBar/index.js +++ b/storybook/stories/SeasonsBar/index.js @@ -1 +1 @@ -require('./SeasonsBar'); +require('./SampleSeasonsBar'); From a511a24f9b0c742e528fc429953a6bdb6f9677bd Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 12:45:05 +0200 Subject: [PATCH 205/442] SeasonsBarPlaceholder story added to storybook --- .../Detail/VideosList/SeasonsBar/SeasonsBar.js | 3 +++ .../SeasonsBarPlaceholder/SeasonsBarPlaceholder.js | 12 ++++++++++++ .../SeasonsBar/SeasonsBarPlaceholder/index.js | 1 + .../SeasonsBar/SeasonsBarPlaceholder/styles.less | 5 +++++ storybook/stories/SeasonsBar/index.js | 1 + 5 files changed, 22 insertions(+) create mode 100644 storybook/stories/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js create mode 100644 storybook/stories/SeasonsBar/SeasonsBarPlaceholder/index.js create mode 100644 storybook/stories/SeasonsBar/SeasonsBarPlaceholder/styles.less diff --git a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js index 8e50ce2a3..13f94594b 100644 --- a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js @@ -3,6 +3,7 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { Button, Multiselect } = require('stremio/common'); +const SeasonsBarPlaceholder = require('./SeasonsBarPlaceholder'); const styles = require('./styles'); const SeasonsBar = ({ className, seasons, season, onSelect }) => { @@ -69,6 +70,8 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { ); }; +SeasonsBar.Placeholder = SeasonsBarPlaceholder; + SeasonsBar.propTypes = { className: PropTypes.string, seasons: PropTypes.arrayOf(PropTypes.number).isRequired, diff --git a/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js b/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js new file mode 100644 index 000000000..e04109b34 --- /dev/null +++ b/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js @@ -0,0 +1,12 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const SeasonsBar = require('stremio/routes/Detail/VideosList/SeasonsBar'); +const styles = require('./styles'); + +storiesOf('SeasonsBar', module).add('SeasonsBarPlaceholder', () => { + return ( + + ); +}); diff --git a/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/index.js b/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/index.js new file mode 100644 index 000000000..1b073fb5d --- /dev/null +++ b/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/index.js @@ -0,0 +1 @@ +require('./SeasonsBarPlaceholder'); diff --git a/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/styles.less b/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/styles.less new file mode 100644 index 000000000..a62a204c7 --- /dev/null +++ b/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/styles.less @@ -0,0 +1,5 @@ +.seasons-bar { + flex: none; + width: 28rem; + margin: 2rem; +} \ No newline at end of file diff --git a/storybook/stories/SeasonsBar/index.js b/storybook/stories/SeasonsBar/index.js index c3a9531b5..3d7a90e9c 100644 --- a/storybook/stories/SeasonsBar/index.js +++ b/storybook/stories/SeasonsBar/index.js @@ -1 +1,2 @@ require('./SampleSeasonsBar'); +require('./SeasonsBarPlaceholder'); From 01cabe6343c2c362f953989afbd5039ffbedb0ea Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 13:00:09 +0200 Subject: [PATCH 206/442] seasonsbar placeholder styles improved --- .../SeasonsBar/SeasonsBarPlaceholder/styles.less | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less index 529d31570..ec0352240 100644 --- a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less +++ b/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less @@ -1,30 +1,34 @@ .seasons-bar-placeholder-container { display: flex; flex-direction: row; - align-items: center; .prev-season-button, .next-season-button { flex: none; + width: 4rem; + height: 4rem; padding: 1rem; background-color: var(--color-placeholder); .icon { display: block; - width: 2rem; - height: 2rem; + width: 100%; + height: 100%; fill: var(--color-placeholder); } } .seasons-popup-label-container { flex: 1; + align-self: stretch; + display: flex; + align-items: center; + justify-content: center; margin: 0 1rem; background-color: var(--color-placeholder); .seasons-popup-label { - width: 60%; - height: 1.4rem; - margin: 1.3rem 20%; + width: 50%; + height: 1.2rem; background-color: var(--color-placeholder); } } From f32173797b0d997b70bb9b7ea883191dd2f8e901 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 13:10:18 +0200 Subject: [PATCH 207/442] VideoPlaceholder moved inside video --- src/routes/Detail/VideosList/Video/Video.js | 5 ++++- .../{ => Video}/VideoPlaceholder/VideoPlaceholder.js | 0 .../VideosList/{ => Video}/VideoPlaceholder/index.js | 0 .../{ => Video}/VideoPlaceholder/styles.less | 0 src/routes/Detail/VideosList/VideosList.js | 11 +++++------ 5 files changed, 9 insertions(+), 7 deletions(-) rename src/routes/Detail/VideosList/{ => Video}/VideoPlaceholder/VideoPlaceholder.js (100%) rename src/routes/Detail/VideosList/{ => Video}/VideoPlaceholder/index.js (100%) rename src/routes/Detail/VideosList/{ => Video}/VideoPlaceholder/styles.less (100%) diff --git a/src/routes/Detail/VideosList/Video/Video.js b/src/routes/Detail/VideosList/Video/Video.js index d9ca1fbee..2bcd22f27 100644 --- a/src/routes/Detail/VideosList/Video/Video.js +++ b/src/routes/Detail/VideosList/Video/Video.js @@ -3,6 +3,7 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const { Button, Image } = require('stremio/common'); const Icon = require('stremio-icons/dom'); +const VideoPlaceholder = require('./VideoPlaceholder'); const styles = require('./styles'); const Video = ({ className, title, thumbnail, episode, released, upcoming, watched, progress, ...props }) => { @@ -69,7 +70,9 @@ const Video = ({ className, title, thumbnail, episode, released, upcoming, watch } ); -} +}; + +Video.Placeholder = VideoPlaceholder; Video.propTypes = { className: PropTypes.string, diff --git a/src/routes/Detail/VideosList/VideoPlaceholder/VideoPlaceholder.js b/src/routes/Detail/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js similarity index 100% rename from src/routes/Detail/VideosList/VideoPlaceholder/VideoPlaceholder.js rename to src/routes/Detail/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js diff --git a/src/routes/Detail/VideosList/VideoPlaceholder/index.js b/src/routes/Detail/VideosList/Video/VideoPlaceholder/index.js similarity index 100% rename from src/routes/Detail/VideosList/VideoPlaceholder/index.js rename to src/routes/Detail/VideosList/Video/VideoPlaceholder/index.js diff --git a/src/routes/Detail/VideosList/VideoPlaceholder/styles.less b/src/routes/Detail/VideosList/Video/VideoPlaceholder/styles.less similarity index 100% rename from src/routes/Detail/VideosList/VideoPlaceholder/styles.less rename to src/routes/Detail/VideosList/Video/VideoPlaceholder/styles.less diff --git a/src/routes/Detail/VideosList/VideosList.js b/src/routes/Detail/VideosList/VideosList.js index c60935042..9f2394d3e 100644 --- a/src/routes/Detail/VideosList/VideosList.js +++ b/src/routes/Detail/VideosList/VideosList.js @@ -3,7 +3,6 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const SeasonsBar = require('./SeasonsBar'); const Video = require('./Video'); -const VideoPlaceholder = require('./VideoPlaceholder'); const useSelectableSeasons = require('./useSelectableSeasons'); const styles = require('./styles'); @@ -27,11 +26,11 @@ const VideosList = ({ className, metaGroup }) => {
- - - - - + + + + +
: From efa3586f059f1f8bf06a7a800f027b35ddfd11f4 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 13:23:50 +0200 Subject: [PATCH 208/442] filter videos by season inside seasons reducer to keep state consistent --- src/routes/Detail/VideosList/VideosList.js | 7 +------ src/routes/Detail/VideosList/useSelectableSeasons.js | 11 +++++++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/routes/Detail/VideosList/VideosList.js b/src/routes/Detail/VideosList/VideosList.js index 9f2394d3e..c2ba033fe 100644 --- a/src/routes/Detail/VideosList/VideosList.js +++ b/src/routes/Detail/VideosList/VideosList.js @@ -13,12 +13,7 @@ const VideosList = ({ className, metaGroup }) => { : []; }, [metaGroup]); - const [seasons, selectedSeason, selectSeason] = useSelectableSeasons(videos); - const videosForSeason = React.useMemo(() => { - return videos.filter((video) => { - return selectedSeason === null || video.season === selectedSeason; - }); - }, [videos, selectedSeason]); + const [seasons, selectedSeason, videosForSeason, selectSeason] = useSelectableSeasons(videos); return (
{ diff --git a/src/routes/Detail/VideosList/useSelectableSeasons.js b/src/routes/Detail/VideosList/useSelectableSeasons.js index 04815b4fa..3a407836d 100644 --- a/src/routes/Detail/VideosList/useSelectableSeasons.js +++ b/src/routes/Detail/VideosList/useSelectableSeasons.js @@ -20,6 +20,7 @@ const reducer = (state, action) => { null; return { ...state, + videos: action.videos, seasons, selectedSeason }; @@ -42,6 +43,7 @@ const reducer = (state, action) => { const initializer = (videos) => { const initialState = { + videos: [], seasons: [], selectedSeason: null }; @@ -54,7 +56,7 @@ const initializer = (videos) => { }; const useSelectableSeasons = (videos) => { - const [{ seasons, selectedSeason }, dispatch] = React.useReducer( + const [state, dispatch] = React.useReducer( reducer, videos, initializer @@ -65,13 +67,18 @@ const useSelectableSeasons = (videos) => { season }); }, []); + const videosForSeason = React.useMemo(() => { + return state.videos.filter((video) => { + return video.season === state.selectedSeason; + }); + }, [state.videos, state.selectedSeason]); React.useEffect(() => { dispatch({ type: 'videos-changed', videos }); }, [videos]); - return [seasons, selectedSeason, selectSeason]; + return [state.seasons, state.selectedSeason, videosForSeason, selectSeason]; }; module.exports = useSelectableSeasons; From cc8292d3f61e30cf6b92cffd4baed696fea7d317 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 13:26:26 +0200 Subject: [PATCH 209/442] VideosList adapted to changed api of SeasonsBar --- src/routes/Detail/VideosList/VideosList.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/Detail/VideosList/VideosList.js b/src/routes/Detail/VideosList/VideosList.js index c2ba033fe..32d6efbb0 100644 --- a/src/routes/Detail/VideosList/VideosList.js +++ b/src/routes/Detail/VideosList/VideosList.js @@ -14,6 +14,9 @@ const VideosList = ({ className, metaGroup }) => { []; }, [metaGroup]); const [seasons, selectedSeason, videosForSeason, selectSeason] = useSelectableSeasons(videos); + const seasonOnSelect = React.useCallback((event) => { + selectSeason(event.value); + }, []); return (
{ @@ -41,7 +44,7 @@ const VideosList = ({ className, metaGroup }) => { className={styles['seasons-bar']} season={selectedSeason} seasons={seasons} - onSeasonChange={selectSeason} + onSelect={seasonOnSelect} /> : null From 6a20cbe885381748975fbfd43f15ce1a69bd7cc9 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 13:43:37 +0200 Subject: [PATCH 210/442] seasons popup label active styles updated --- src/routes/Detail/VideosList/SeasonsBar/styles.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/routes/Detail/VideosList/SeasonsBar/styles.less b/src/routes/Detail/VideosList/SeasonsBar/styles.less index 859f68770..b70da1d3f 100644 --- a/src/routes/Detail/VideosList/SeasonsBar/styles.less +++ b/src/routes/Detail/VideosList/SeasonsBar/styles.less @@ -32,10 +32,14 @@ background-color: var(--color-surfacedarker60); overflow: visible; - &:hover, &:focus, &:global(.active) { + &:hover, &:focus { background-color: var(--color-surfacedarker); } + &:global(.active) { + background-color: var(--color-surfacedark); + } + .season-label { flex-grow: 0; flex-shrink: 1; From e21caea72578403fa9e3530852d6ad2b8ce20802 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 13:46:57 +0200 Subject: [PATCH 211/442] videos for season fixed if season not set --- src/routes/Detail/VideosList/useSelectableSeasons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Detail/VideosList/useSelectableSeasons.js b/src/routes/Detail/VideosList/useSelectableSeasons.js index 3a407836d..4952f0d55 100644 --- a/src/routes/Detail/VideosList/useSelectableSeasons.js +++ b/src/routes/Detail/VideosList/useSelectableSeasons.js @@ -69,7 +69,7 @@ const useSelectableSeasons = (videos) => { }, []); const videosForSeason = React.useMemo(() => { return state.videos.filter((video) => { - return video.season === state.selectedSeason; + return state.selectedSeason === null || video.season === state.selectedSeason; }); }, [state.videos, state.selectedSeason]); React.useEffect(() => { From 0df8637502b5c05e48a6824f6c95813be27a2b6b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 13:59:16 +0200 Subject: [PATCH 212/442] video placeholder styles updated --- .../Detail/VideosList/Video/VideoPlaceholder/styles.less | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/routes/Detail/VideosList/Video/VideoPlaceholder/styles.less b/src/routes/Detail/VideosList/Video/VideoPlaceholder/styles.less index 687c4305d..3edf01b4b 100644 --- a/src/routes/Detail/VideosList/Video/VideoPlaceholder/styles.less +++ b/src/routes/Detail/VideosList/Video/VideoPlaceholder/styles.less @@ -24,12 +24,14 @@ .next-icon-container { flex: none; + width: 2rem; + height: 2.5rem; padding: 0.5rem; .next-icon { display: block; - width: 1rem; - height: 1.5rem; + width: 100%; + height: 100%; fill: var(--color-placeholder); } } From a67aec064912986b6a4ea9c9c9c88a13bb13d0e5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 14:07:21 +0200 Subject: [PATCH 213/442] Detail route renamed to MetaDetails --- src/App/routerViewsConfig.js | 4 ++-- src/common/routesRegexp.js | 4 ++-- src/routes/Detail/index.js | 3 --- .../{Detail/Detail.js => MetaDetails/MetaDetails.js} | 8 ++++---- .../{Detail => MetaDetails}/StreamsList/Stream/Stream.js | 0 .../{Detail => MetaDetails}/StreamsList/Stream/index.js | 0 .../StreamsList/Stream/styles.less | 0 .../StreamsList/StreamPlaceholder/StreamPlaceholder.js | 0 .../StreamsList/StreamPlaceholder/index.js | 0 .../StreamsList/StreamPlaceholder/styles.less | 0 .../{Detail => MetaDetails}/StreamsList/StreamsList.js | 0 src/routes/{Detail => MetaDetails}/StreamsList/index.js | 0 .../{Detail => MetaDetails}/StreamsList/styles.less | 0 .../VideosList/SeasonsBar/SeasonsBar.js | 0 .../SeasonsBarPlaceholder/SeasonsBarPlaceholder.js | 0 .../VideosList/SeasonsBar/SeasonsBarPlaceholder/index.js | 0 .../SeasonsBar/SeasonsBarPlaceholder/styles.less | 0 .../VideosList/SeasonsBar/index.js | 0 .../VideosList/SeasonsBar/styles.less | 0 .../{Detail => MetaDetails}/VideosList/Video/Video.js | 0 .../VideosList/Video/VideoPlaceholder/VideoPlaceholder.js | 0 .../VideosList/Video/VideoPlaceholder/index.js | 0 .../VideosList/Video/VideoPlaceholder/styles.less | 0 .../{Detail => MetaDetails}/VideosList/Video/index.js | 0 .../{Detail => MetaDetails}/VideosList/Video/styles.less | 0 .../{Detail => MetaDetails}/VideosList/VideosList.js | 0 src/routes/{Detail => MetaDetails}/VideosList/index.js | 0 src/routes/{Detail => MetaDetails}/VideosList/styles.less | 0 .../VideosList/useSelectableSeasons.js | 0 src/routes/MetaDetails/index.js | 3 +++ src/routes/{Detail => MetaDetails}/styles.less | 4 ++-- src/routes/{Detail => MetaDetails}/useInLibrary.js | 0 src/routes/{Detail => MetaDetails}/useMetaDetails.js | 0 src/routes/{Detail => MetaDetails}/useSelectableGroups.js | 0 src/routes/index.js | 4 ++-- .../SeasonsBar/SampleSeasonsBar/SampleSeasonsBar.js | 2 +- .../SeasonsBarPlaceholder/SeasonsBarPlaceholder.js | 2 +- 37 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 src/routes/Detail/index.js rename src/routes/{Detail/Detail.js => MetaDetails/MetaDetails.js} (95%) rename src/routes/{Detail => MetaDetails}/StreamsList/Stream/Stream.js (100%) rename src/routes/{Detail => MetaDetails}/StreamsList/Stream/index.js (100%) rename src/routes/{Detail => MetaDetails}/StreamsList/Stream/styles.less (100%) rename src/routes/{Detail => MetaDetails}/StreamsList/StreamPlaceholder/StreamPlaceholder.js (100%) rename src/routes/{Detail => MetaDetails}/StreamsList/StreamPlaceholder/index.js (100%) rename src/routes/{Detail => MetaDetails}/StreamsList/StreamPlaceholder/styles.less (100%) rename src/routes/{Detail => MetaDetails}/StreamsList/StreamsList.js (100%) rename src/routes/{Detail => MetaDetails}/StreamsList/index.js (100%) rename src/routes/{Detail => MetaDetails}/StreamsList/styles.less (100%) rename src/routes/{Detail => MetaDetails}/VideosList/SeasonsBar/SeasonsBar.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/SeasonsBar/SeasonsBarPlaceholder/index.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less (100%) rename src/routes/{Detail => MetaDetails}/VideosList/SeasonsBar/index.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/SeasonsBar/styles.less (100%) rename src/routes/{Detail => MetaDetails}/VideosList/Video/Video.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/Video/VideoPlaceholder/index.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/Video/VideoPlaceholder/styles.less (100%) rename src/routes/{Detail => MetaDetails}/VideosList/Video/index.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/Video/styles.less (100%) rename src/routes/{Detail => MetaDetails}/VideosList/VideosList.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/index.js (100%) rename src/routes/{Detail => MetaDetails}/VideosList/styles.less (100%) rename src/routes/{Detail => MetaDetails}/VideosList/useSelectableSeasons.js (100%) create mode 100644 src/routes/MetaDetails/index.js rename src/routes/{Detail => MetaDetails}/styles.less (95%) rename src/routes/{Detail => MetaDetails}/useInLibrary.js (100%) rename src/routes/{Detail => MetaDetails}/useMetaDetails.js (100%) rename src/routes/{Detail => MetaDetails}/useSelectableGroups.js (100%) diff --git a/src/App/routerViewsConfig.js b/src/App/routerViewsConfig.js index 29453fd26..b53ee54fb 100644 --- a/src/App/routerViewsConfig.js +++ b/src/App/routerViewsConfig.js @@ -26,8 +26,8 @@ const routerViewsConfig = [ ], [ { - ...routesRegexp.detail, - component: routes.Detail + ...routesRegexp.metadetails, + component: routes.MetaDetails }, { ...routesRegexp.addons, diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index 5e8eae4d1..e21c84f17 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -19,8 +19,8 @@ const routesRegexp = { regexp: /^\/search\/?$/i, urlParamsNames: [] }, - detail: { - regexp: /^\/detail\/(?:([^\/]+?))\/(?:([^\/]+?))(?:\/([^\/]*?))?\/?$/i, + metadetails: { + regexp: /^\/metadetails\/(?:([^\/]+?))\/(?:([^\/]+?))(?:\/([^\/]*?))?\/?$/i, urlParamsNames: ['type', 'id', 'videoId'] }, addons: { diff --git a/src/routes/Detail/index.js b/src/routes/Detail/index.js deleted file mode 100644 index 89fc1aead..000000000 --- a/src/routes/Detail/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const Detail = require('./Detail'); - -module.exports = Detail; diff --git a/src/routes/Detail/Detail.js b/src/routes/MetaDetails/MetaDetails.js similarity index 95% rename from src/routes/Detail/Detail.js rename to src/routes/MetaDetails/MetaDetails.js index 84fb46bc0..a2ef2fb3d 100644 --- a/src/routes/Detail/Detail.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -6,18 +6,18 @@ const useMetaDetails = require('./useMetaDetails'); const useSelectableGroups = require('./useSelectableGroups'); const styles = require('./styles'); -const Detail = ({ urlParams }) => { +const MetaDetails = ({ urlParams }) => { const [meta, streams] = useMetaDetails(urlParams); const [metaResourceRef, metaGroups, selectedMetaGroup] = useSelectableGroups(meta.resourceRef, meta.groups); const { resourceRef: streamsResourceRef, groups: streamsGroups } = streams; return ( -
+
-
+
{ metaResourceRef !== null ? selectedMetaGroup !== null ? @@ -80,4 +80,4 @@ const Detail = ({ urlParams }) => { ); }; -module.exports = Detail; +module.exports = MetaDetails; diff --git a/src/routes/Detail/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js similarity index 100% rename from src/routes/Detail/StreamsList/Stream/Stream.js rename to src/routes/MetaDetails/StreamsList/Stream/Stream.js diff --git a/src/routes/Detail/StreamsList/Stream/index.js b/src/routes/MetaDetails/StreamsList/Stream/index.js similarity index 100% rename from src/routes/Detail/StreamsList/Stream/index.js rename to src/routes/MetaDetails/StreamsList/Stream/index.js diff --git a/src/routes/Detail/StreamsList/Stream/styles.less b/src/routes/MetaDetails/StreamsList/Stream/styles.less similarity index 100% rename from src/routes/Detail/StreamsList/Stream/styles.less rename to src/routes/MetaDetails/StreamsList/Stream/styles.less diff --git a/src/routes/Detail/StreamsList/StreamPlaceholder/StreamPlaceholder.js b/src/routes/MetaDetails/StreamsList/StreamPlaceholder/StreamPlaceholder.js similarity index 100% rename from src/routes/Detail/StreamsList/StreamPlaceholder/StreamPlaceholder.js rename to src/routes/MetaDetails/StreamsList/StreamPlaceholder/StreamPlaceholder.js diff --git a/src/routes/Detail/StreamsList/StreamPlaceholder/index.js b/src/routes/MetaDetails/StreamsList/StreamPlaceholder/index.js similarity index 100% rename from src/routes/Detail/StreamsList/StreamPlaceholder/index.js rename to src/routes/MetaDetails/StreamsList/StreamPlaceholder/index.js diff --git a/src/routes/Detail/StreamsList/StreamPlaceholder/styles.less b/src/routes/MetaDetails/StreamsList/StreamPlaceholder/styles.less similarity index 100% rename from src/routes/Detail/StreamsList/StreamPlaceholder/styles.less rename to src/routes/MetaDetails/StreamsList/StreamPlaceholder/styles.less diff --git a/src/routes/Detail/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js similarity index 100% rename from src/routes/Detail/StreamsList/StreamsList.js rename to src/routes/MetaDetails/StreamsList/StreamsList.js diff --git a/src/routes/Detail/StreamsList/index.js b/src/routes/MetaDetails/StreamsList/index.js similarity index 100% rename from src/routes/Detail/StreamsList/index.js rename to src/routes/MetaDetails/StreamsList/index.js diff --git a/src/routes/Detail/StreamsList/styles.less b/src/routes/MetaDetails/StreamsList/styles.less similarity index 100% rename from src/routes/Detail/StreamsList/styles.less rename to src/routes/MetaDetails/StreamsList/styles.less diff --git a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBar/SeasonsBar.js rename to src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js diff --git a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js rename to src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js diff --git a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/index.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBarPlaceholder/index.js similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/index.js rename to src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBarPlaceholder/index.js diff --git a/src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less rename to src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBarPlaceholder/styles.less diff --git a/src/routes/Detail/VideosList/SeasonsBar/index.js b/src/routes/MetaDetails/VideosList/SeasonsBar/index.js similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBar/index.js rename to src/routes/MetaDetails/VideosList/SeasonsBar/index.js diff --git a/src/routes/Detail/VideosList/SeasonsBar/styles.less b/src/routes/MetaDetails/VideosList/SeasonsBar/styles.less similarity index 100% rename from src/routes/Detail/VideosList/SeasonsBar/styles.less rename to src/routes/MetaDetails/VideosList/SeasonsBar/styles.less diff --git a/src/routes/Detail/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js similarity index 100% rename from src/routes/Detail/VideosList/Video/Video.js rename to src/routes/MetaDetails/VideosList/Video/Video.js diff --git a/src/routes/Detail/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js b/src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js similarity index 100% rename from src/routes/Detail/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js rename to src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/VideoPlaceholder.js diff --git a/src/routes/Detail/VideosList/Video/VideoPlaceholder/index.js b/src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/index.js similarity index 100% rename from src/routes/Detail/VideosList/Video/VideoPlaceholder/index.js rename to src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/index.js diff --git a/src/routes/Detail/VideosList/Video/VideoPlaceholder/styles.less b/src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/styles.less similarity index 100% rename from src/routes/Detail/VideosList/Video/VideoPlaceholder/styles.less rename to src/routes/MetaDetails/VideosList/Video/VideoPlaceholder/styles.less diff --git a/src/routes/Detail/VideosList/Video/index.js b/src/routes/MetaDetails/VideosList/Video/index.js similarity index 100% rename from src/routes/Detail/VideosList/Video/index.js rename to src/routes/MetaDetails/VideosList/Video/index.js diff --git a/src/routes/Detail/VideosList/Video/styles.less b/src/routes/MetaDetails/VideosList/Video/styles.less similarity index 100% rename from src/routes/Detail/VideosList/Video/styles.less rename to src/routes/MetaDetails/VideosList/Video/styles.less diff --git a/src/routes/Detail/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js similarity index 100% rename from src/routes/Detail/VideosList/VideosList.js rename to src/routes/MetaDetails/VideosList/VideosList.js diff --git a/src/routes/Detail/VideosList/index.js b/src/routes/MetaDetails/VideosList/index.js similarity index 100% rename from src/routes/Detail/VideosList/index.js rename to src/routes/MetaDetails/VideosList/index.js diff --git a/src/routes/Detail/VideosList/styles.less b/src/routes/MetaDetails/VideosList/styles.less similarity index 100% rename from src/routes/Detail/VideosList/styles.less rename to src/routes/MetaDetails/VideosList/styles.less diff --git a/src/routes/Detail/VideosList/useSelectableSeasons.js b/src/routes/MetaDetails/VideosList/useSelectableSeasons.js similarity index 100% rename from src/routes/Detail/VideosList/useSelectableSeasons.js rename to src/routes/MetaDetails/VideosList/useSelectableSeasons.js diff --git a/src/routes/MetaDetails/index.js b/src/routes/MetaDetails/index.js new file mode 100644 index 000000000..e92f5c8cf --- /dev/null +++ b/src/routes/MetaDetails/index.js @@ -0,0 +1,3 @@ +const MetaDetails = require('./MetaDetails'); + +module.exports = MetaDetails; diff --git a/src/routes/Detail/styles.less b/src/routes/MetaDetails/styles.less similarity index 95% rename from src/routes/Detail/styles.less rename to src/routes/MetaDetails/styles.less index 4cce3adb1..4bdea39ca 100644 --- a/src/routes/Detail/styles.less +++ b/src/routes/MetaDetails/styles.less @@ -1,4 +1,4 @@ -.detail-container { +.metadetails-container { display: flex; flex-direction: column; width: 100%; @@ -10,7 +10,7 @@ align-self: stretch; } - .detail-content { + .metadetails-content { flex: 1; align-self: stretch; position: relative; diff --git a/src/routes/Detail/useInLibrary.js b/src/routes/MetaDetails/useInLibrary.js similarity index 100% rename from src/routes/Detail/useInLibrary.js rename to src/routes/MetaDetails/useInLibrary.js diff --git a/src/routes/Detail/useMetaDetails.js b/src/routes/MetaDetails/useMetaDetails.js similarity index 100% rename from src/routes/Detail/useMetaDetails.js rename to src/routes/MetaDetails/useMetaDetails.js diff --git a/src/routes/Detail/useSelectableGroups.js b/src/routes/MetaDetails/useSelectableGroups.js similarity index 100% rename from src/routes/Detail/useSelectableGroups.js rename to src/routes/MetaDetails/useSelectableGroups.js diff --git a/src/routes/index.js b/src/routes/index.js index f9f19e314..e819535bb 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -2,10 +2,10 @@ const Addons = require('./Addons'); const Board = require('./Board'); const Discover = require('./Discover'); const Library = require('./Library'); +const MetaDetails = require('./MetaDetails'); const Search = require('./Search'); const Settings = require('./Settings'); const Player = require('./Player'); -const Detail = require('./Detail'); const Intro = require('./Intro'); module.exports = { @@ -13,9 +13,9 @@ module.exports = { Board, Discover, Library, + MetaDetails, Search, Settings, Player, - Detail, Intro }; diff --git a/storybook/stories/SeasonsBar/SampleSeasonsBar/SampleSeasonsBar.js b/storybook/stories/SeasonsBar/SampleSeasonsBar/SampleSeasonsBar.js index f7a25a33c..354079577 100644 --- a/storybook/stories/SeasonsBar/SampleSeasonsBar/SampleSeasonsBar.js +++ b/storybook/stories/SeasonsBar/SampleSeasonsBar/SampleSeasonsBar.js @@ -1,7 +1,7 @@ const React = require('react'); const { storiesOf } = require('@storybook/react'); const { action } = require('@storybook/addon-actions'); -const SeasonsBar = require('stremio/routes/Detail/VideosList/SeasonsBar'); +const SeasonsBar = require('stremio/routes/MetaDetails/VideosList/SeasonsBar'); const styles = require('./styles'); storiesOf('SeasonsBar', module).add('SampleSeasonsBar', () => { diff --git a/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js b/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js index e04109b34..e8067f79f 100644 --- a/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js +++ b/storybook/stories/SeasonsBar/SeasonsBarPlaceholder/SeasonsBarPlaceholder.js @@ -1,6 +1,6 @@ const React = require('react'); const { storiesOf } = require('@storybook/react'); -const SeasonsBar = require('stremio/routes/Detail/VideosList/SeasonsBar'); +const SeasonsBar = require('stremio/routes/MetaDetails/VideosList/SeasonsBar'); const styles = require('./styles'); storiesOf('SeasonsBar', module).add('SeasonsBarPlaceholder', () => { From 5eebaeee60bb006566e9f972ee8c34f876294b61 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 14:42:03 +0200 Subject: [PATCH 214/442] href added to videos --- src/routes/MetaDetails/useMetaDetails.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/MetaDetails/useMetaDetails.js b/src/routes/MetaDetails/useMetaDetails.js index 12fa1993b..ab7809b30 100644 --- a/src/routes/MetaDetails/useMetaDetails.js +++ b/src/routes/MetaDetails/useMetaDetails.js @@ -20,6 +20,7 @@ const useMetaDetails = (urlParams) => { video.released.getTime() > Date.now() : false; + video.href = `#/metadetails/${metaGroup.content.content.type}/${metaGroup.content.content.id}/${video.id}`; // TODO add href, watched and progress return video; }); From b86cf17ea7cbf19e95fdd521964aa8f66f29a6e8 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 14:43:01 +0200 Subject: [PATCH 215/442] all cases handled in streamslist --- .../MetaDetails/StreamsList/StreamsList.js | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index 664520111..d4dc8ca5f 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -7,31 +7,32 @@ const Stream = require('./Stream'); const StreamPlaceholder = require('./StreamPlaceholder'); const styles = require('./styles'); -const StreamsList = ({ className, streams }) => { - const readyStreams = streams - .filter(stream => stream.content.type === 'Ready') - .map(stream => stream.content.content) - .flat(); +const StreamsList = ({ className, streamsGroups }) => { + const readyStreams = React.useMemo(() => { + return streamsGroups + .filter((stream) => stream.content.type === 'Ready') + .map((stream) => stream.content.content) + .flat(1); + }, [streamsGroups]); return (
{ - streams.length === 0 || streams.every(stream => stream.content.type === 'Loading') ? - - - - - - - - + readyStreams.length > 0 ? + readyStreams.map((stream, index) => ( + + )) : - readyStreams.length === 0 ? -
No streams were found
+ streamsGroups.length === 0 ? +
No addons ware requested for streams
: - readyStreams.map((stream) => ( - - )) + streamsGroups.every((group) => group.content.type === 'Err') ? +
No streams were found
+ : + + + + }
); -} +}; + +Stream.Placeholder = StreamPlaceholder; Stream.propTypes = { className: PropTypes.string, diff --git a/src/routes/MetaDetails/StreamsList/StreamPlaceholder/StreamPlaceholder.js b/src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/StreamPlaceholder.js similarity index 100% rename from src/routes/MetaDetails/StreamsList/StreamPlaceholder/StreamPlaceholder.js rename to src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/StreamPlaceholder.js diff --git a/src/routes/MetaDetails/StreamsList/StreamPlaceholder/index.js b/src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/index.js similarity index 100% rename from src/routes/MetaDetails/StreamsList/StreamPlaceholder/index.js rename to src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/index.js diff --git a/src/routes/MetaDetails/StreamsList/StreamPlaceholder/styles.less b/src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/styles.less similarity index 100% rename from src/routes/MetaDetails/StreamsList/StreamPlaceholder/styles.less rename to src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/styles.less diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index d4dc8ca5f..855615f3c 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -4,7 +4,6 @@ const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { Button } = require('stremio/common'); const Stream = require('./Stream'); -const StreamPlaceholder = require('./StreamPlaceholder'); const styles = require('./styles'); const StreamsList = ({ className, streamsGroups }) => { @@ -30,8 +29,8 @@ const StreamsList = ({ className, streamsGroups }) => {
No streams were found
: - - + + }
From 36e0b4b13f3db710cabc6cb25383801e9ec53550 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 14:51:30 +0200 Subject: [PATCH 217/442] Stream placeholder styles updated --- .../StreamsList/Stream/StreamPlaceholder/styles.less | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/styles.less b/src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/styles.less index 61129d8d8..c8f82a3df 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/styles.less +++ b/src/routes/MetaDetails/StreamsList/Stream/StreamPlaceholder/styles.less @@ -36,12 +36,14 @@ .play-icon-container { flex: none; + width: 5rem; + height: 5rem; padding: 1.5rem; .play-icon { display: block; - width: 2rem; - height: 2rem; + width: 100%; + height: 100%; fill: var(--color-placeholder); } } From 277de44458798e83e76d396845d9e8915dd906a3 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 16:06:25 +0200 Subject: [PATCH 218/442] Stream story added to storybook --- .../StreamWithThumbnail/StreamWithThumbnail.js | 14 ++++++++++++++ .../stories/Stream/StreamWithThumbnail/index.js | 1 + .../stories/Stream/StreamWithThumbnail/styles.less | 5 +++++ storybook/stories/Stream/index.js | 1 + storybook/stories/index.js | 1 + 5 files changed, 22 insertions(+) create mode 100644 storybook/stories/Stream/StreamWithThumbnail/StreamWithThumbnail.js create mode 100644 storybook/stories/Stream/StreamWithThumbnail/index.js create mode 100644 storybook/stories/Stream/StreamWithThumbnail/styles.less create mode 100644 storybook/stories/Stream/index.js diff --git a/storybook/stories/Stream/StreamWithThumbnail/StreamWithThumbnail.js b/storybook/stories/Stream/StreamWithThumbnail/StreamWithThumbnail.js new file mode 100644 index 000000000..3b9332367 --- /dev/null +++ b/storybook/stories/Stream/StreamWithThumbnail/StreamWithThumbnail.js @@ -0,0 +1,14 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const Stream = require('stremio/routes/MetaDetails/StreamsList/Stream'); +const styles = require('./styles'); + +storiesOf('Stream', module).add('StreamWithThumbnail', () => ( + +)); diff --git a/storybook/stories/Stream/StreamWithThumbnail/index.js b/storybook/stories/Stream/StreamWithThumbnail/index.js new file mode 100644 index 000000000..efb6028e4 --- /dev/null +++ b/storybook/stories/Stream/StreamWithThumbnail/index.js @@ -0,0 +1 @@ +require('./StreamWithThumbnail'); diff --git a/storybook/stories/Stream/StreamWithThumbnail/styles.less b/storybook/stories/Stream/StreamWithThumbnail/styles.less new file mode 100644 index 000000000..47840176d --- /dev/null +++ b/storybook/stories/Stream/StreamWithThumbnail/styles.less @@ -0,0 +1,5 @@ +.stream-container { + flex: none; + width: 28rem; + margin: 2rem; +} \ No newline at end of file diff --git a/storybook/stories/Stream/index.js b/storybook/stories/Stream/index.js new file mode 100644 index 000000000..efb6028e4 --- /dev/null +++ b/storybook/stories/Stream/index.js @@ -0,0 +1 @@ +require('./StreamWithThumbnail'); diff --git a/storybook/stories/index.js b/storybook/stories/index.js index 9dcb43889..3f82e3793 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -7,3 +7,4 @@ require('./Notification'); require('./Popup'); require('./SeasonsBar'); require('./SharePrompt'); +require('./Stream'); From 2cc6671b93442ab13e87820ae34913f9c3c57382 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 14 Nov 2019 17:23:27 +0200 Subject: [PATCH 219/442] Stream adapted to the new data stucture --- .../MetaDetails/StreamsList/Stream/Stream.js | 43 +++++++++++++------ .../StreamsList/Stream/styles.less | 37 +++++++++++++--- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 094fdb776..13cf4f04b 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -2,25 +2,41 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); -const { Button } = require('stremio/common'); +const { Button, Image } = require('stremio/common'); const StreamPlaceholder = require('./StreamPlaceholder'); const styles = require('./styles'); -const Stream = ({ className, id, addon, description, progress, onClick }) => { +const Stream = ({ className, addonName, title, thumbnail, progress, ...props }) => { return ( - ))} @@ -32,10 +32,10 @@ const MetaLinks = ({ className, label, links }) => { MetaLinks.propTypes = { className: PropTypes.string, - label: PropTypes.string, + category: PropTypes.string, links: PropTypes.arrayOf(PropTypes.shape({ - label: PropTypes.string.isRequired, - href: PropTypes.string.isRequired + name: PropTypes.string, + href: PropTypes.string })) }; diff --git a/src/common/MetaPreview/MetaLinks/styles.less b/src/common/MetaPreview/MetaLinks/styles.less index 1a9ded8ba..4181a2a5e 100644 --- a/src/common/MetaPreview/MetaLinks/styles.less +++ b/src/common/MetaPreview/MetaLinks/styles.less @@ -1,5 +1,5 @@ .meta-links-container { - .label-container { + .category-container { margin-bottom: 0.2rem; font-size: 1.2rem; color: var(--color-surfacelighter); From 16e4b742b74c2f395d662551b1a33f8597eb26cc Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 18 Nov 2019 11:05:37 +0200 Subject: [PATCH 231/442] useInLibrary moved to common --- src/common/index.js | 2 ++ src/{routes/MetaDetails => common}/useInLibrary.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) rename src/{routes/MetaDetails => common}/useInLibrary.js (87%) diff --git a/src/common/index.js b/src/common/index.js index 9eeca6a39..48393ed87 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -20,6 +20,7 @@ const useAnimationFrame = require('./useAnimationFrame'); const useBinaryState = require('./useBinaryState'); const useDataset = require('./useDataset'); const useFullscreen = require('./useFullscreen'); +const useInLibrary = require('./useInLibrary'); const useLiveRef = require('./useLiveRef'); const useLocationHash = require('./useLocationHash'); const useRouteActive = require('./useRouteActive'); @@ -49,6 +50,7 @@ module.exports = { useBinaryState, useDataset, useFullscreen, + useInLibrary, useLiveRef, useLocationHash, useRouteActive, diff --git a/src/routes/MetaDetails/useInLibrary.js b/src/common/useInLibrary.js similarity index 87% rename from src/routes/MetaDetails/useInLibrary.js rename to src/common/useInLibrary.js index 08ffd21fd..0c8a601cb 100644 --- a/src/routes/MetaDetails/useInLibrary.js +++ b/src/common/useInLibrary.js @@ -1,6 +1,6 @@ const { useBinaryState } = require('stremio/common'); -const useInLibrary = (id = '') => { +const useInLibrary = () => { const [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary] = useBinaryState(false); return [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary]; }; From 6a0b8e8b29d5ddabb16b01ed28701b5e372333d5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 18 Nov 2019 11:25:40 +0200 Subject: [PATCH 232/442] MetaPreview actionbuttons and metalinks adapted to the new data structure --- src/common/MetaPreview/MetaLinks/MetaLinks.js | 16 +- src/common/MetaPreview/MetaLinks/styles.less | 2 +- src/common/MetaPreview/MetaPreview.js | 226 +++++++++--------- src/common/useInLibrary.js | 10 +- src/routes/MetaDetails/MetaDetails.js | 9 +- 5 files changed, 133 insertions(+), 130 deletions(-) diff --git a/src/common/MetaPreview/MetaLinks/MetaLinks.js b/src/common/MetaPreview/MetaLinks/MetaLinks.js index dc3a00b4a..0ddb3d096 100644 --- a/src/common/MetaPreview/MetaLinks/MetaLinks.js +++ b/src/common/MetaPreview/MetaLinks/MetaLinks.js @@ -4,21 +4,21 @@ const classnames = require('classnames'); const Button = require('stremio/common/Button'); const styles = require('./styles'); -const MetaLinks = ({ className, category, links }) => { +const MetaLinks = ({ className, label, links }) => { return (
{ - typeof category === 'string' && category.length > 0 ? -
{category}:
+ typeof label === 'string' && label.length > 0 ? +
{label}:
: null } { Array.isArray(links) && links.length > 0 ?
- {links.map(({ name, href }, index) => ( - ))} @@ -32,9 +32,9 @@ const MetaLinks = ({ className, category, links }) => { MetaLinks.propTypes = { className: PropTypes.string, - category: PropTypes.string, + label: PropTypes.string, links: PropTypes.arrayOf(PropTypes.shape({ - name: PropTypes.string, + label: PropTypes.string, href: PropTypes.string })) }; diff --git a/src/common/MetaPreview/MetaLinks/styles.less b/src/common/MetaPreview/MetaLinks/styles.less index 4181a2a5e..1a9ded8ba 100644 --- a/src/common/MetaPreview/MetaLinks/styles.less +++ b/src/common/MetaPreview/MetaLinks/styles.less @@ -1,5 +1,5 @@ .meta-links-container { - .category-container { + .label-container { margin-bottom: 0.2rem; font-size: 1.2rem; color: var(--color-surfacelighter); diff --git a/src/common/MetaPreview/MetaPreview.js b/src/common/MetaPreview/MetaPreview.js index 82fbd5c82..abde7791c 100644 --- a/src/common/MetaPreview/MetaPreview.js +++ b/src/common/MetaPreview/MetaPreview.js @@ -1,65 +1,73 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const { Modal } = require('stremio-router'); +const UrlUtils = require('url'); const Icon = require('stremio-icons/dom'); const Image = require('stremio/common/Image'); +const ModalDialog = require('stremio/common/ModalDialog'); +const SharePrompt = require('stremio/common/SharePrompt'); +const routesRegexp = require('stremio/common/routesRegexp'); const useBinaryState = require('stremio/common/useBinaryState'); const ActionButton = require('./ActionButton'); const MetaLinks = require('./MetaLinks'); const MetaPreviewPlaceholder = require('./MetaPreviewPlaceholder'); const styles = require('./styles'); -const MetaPreview = ({ className, compact, id, type, name, logo, background, runtime, releaseInfo, released, description, genres, writers, directors, cast, imdbId, imdbRating, trailer, share, inLibrary, toggleInLibrary }) => { +const IMDB_LINK_CATEGORY = 'imdb'; +const SHARE_LINK_CATEGORY = 'share'; +const ALLOWED_LINK_REDIRECTS = [ + routesRegexp.search.regexp, + routesRegexp.discover.regexp, + routesRegexp.metadetails.regexp +]; + +const MetaPreview = ({ className, compact, name, logo, background, runtime, releaseInfo, released, description, links, trailer, inLibrary, toggleInLibrary }) => { const [shareModalOpen, openShareModal, closeShareModal] = useBinaryState(false); - const genresLinks = React.useMemo(() => { - return Array.isArray(genres) ? - genres.filter(genre => typeof genre === 'string') - .map((genre) => ({ - label: genre, - href: `#/discover/${type}//?genre=${genre}` - })) + const linksGroups = React.useMemo(() => { + return Array.isArray(links) ? + links + .filter((link) => { + return link && + typeof link.category === 'string' && + typeof link.url === 'string'; + }) + .reduce((linksGroups, { category, name, url }) => { + if (category === IMDB_LINK_CATEGORY) { + linksGroups[category] = { + label: name, + href: `https://www.stremio.com/warning#${encodeURIComponent(`https://www.imdb.com/title/${url}`)}` + }; + } else if (category === SHARE_LINK_CATEGORY) { + linksGroups[category] = { + label: name, + href: url + }; + } else { + const { protocol, host, path, pathname } = UrlUtils.parse(url); + if (protocol === 'stremio:') { + if (ALLOWED_LINK_REDIRECTS.some((regexp) => pathname.match(regexp))) { + linksGroups[category] = linksGroups[category] || []; + linksGroups[category].push({ + label: name, + href: `#${path}` + }); + } + } else { + if (typeof host === 'string' && host.length > 0) { + linksGroups[category] = linksGroups[category] || []; + linksGroups[category].push({ + label: name, + href: `https://www.stremio.com/warning#${encodeURIComponent(url)}` + }); + } + } + } + + return linksGroups; + }, {}) : []; - }, [type, genres]); - const writersLinks = React.useMemo(() => { - return Array.isArray(writers) ? - writers.filter(writer => typeof writer === 'string') - .map((writer) => ({ - label: writer, - href: `#/search?q=${writer}` - })) - : - []; - }, [writers]); - const directorsLinks = React.useMemo(() => { - return Array.isArray(directors) ? - directors.filter(director => typeof director === 'string') - .map((director) => ({ - label: director, - href: `#/search?q=${director}` - })) - : - []; - }, [directors]); - const castLinks = React.useMemo(() => { - return Array.isArray(cast) ? - cast.filter(name => typeof name === 'string') - .map((name) => ({ - label: name, - href: `#/search?q=${name}` - })) - : - []; - }, [cast]); - const shareModalBackgroundOnClick = React.useCallback((event) => { - if (!event.nativeEvent.closeShareModalPrevented) { - closeShareModal(); - } - }, []); - const shareModalContentOnClick = React.useCallback((event) => { - event.nativeEvent.closeShareModalPrevented = true; - }, []); + }, [links]); return (
{ @@ -78,18 +86,15 @@ const MetaPreview = ({ className, compact, id, type, name, logo, background, run { typeof logo === 'string' && logo.length > 0 ? {' ( - - ) - : - null - } + renderFallback={() => ( + + )} /> : null @@ -116,9 +121,14 @@ const MetaPreview = ({ className, compact, id, type, name, logo, background, run : null } -
- {typeof name === 'string' && name.length > 0 ? name : id} -
+ { + typeof name === 'string' && name.length > 0 ? +
+ {name} +
+ : + null + } { typeof description === 'string' && description.length > 0 ?
{description}
@@ -126,28 +136,19 @@ const MetaPreview = ({ className, compact, id, type, name, logo, background, run null } { - genresLinks.length > 0 ? - - : - null - } - { - writersLinks.length > 0 ? - - : - null - } - { - directorsLinks.length > 0 ? - - : - null - } - { - castLinks.length > 0 ? - - : - null + Object.keys(linksGroups) + .filter((category) => { + return category !== IMDB_LINK_CATEGORY && + category !== SHARE_LINK_CATEGORY; + }) + .map((category, index) => ( + + )) }
@@ -157,32 +158,30 @@ const MetaPreview = ({ className, compact, id, type, name, logo, background, run className={styles['action-button']} icon={inLibrary ? 'ic_removelib' : 'ic_addlib'} label={inLibrary ? 'Remove from Library' : 'Add to library'} - data-id={id} onClick={toggleInLibrary} - {...(!compact ? { tabIndex: -1 } : null)} - /> - : - null - } - { - typeof trailer === 'string' && trailer.length > 0 ? - : null } { - typeof imdbId === 'string' && imdbId.length > 0 ? + typeof trailer === 'object' && trailer !== null ? + : + null + } + { + linksGroups.hasOwnProperty(IMDB_LINK_CATEGORY) ? + 0 ? `${imdbRating} / 10` : null} - href={`https://imdb.com/title/${imdbId}`} target={'_blank'} {...(compact ? { tabIndex: -1 } : null)} /> @@ -190,7 +189,7 @@ const MetaPreview = ({ className, compact, id, type, name, logo, background, run null } { - !compact && typeof share === 'string' && share.length > 0 ? + !compact && linksGroups.hasOwnProperty(SHARE_LINK_CATEGORY) ? { shareModalOpen ? - -
-
-
- + + + : null } @@ -226,8 +222,6 @@ MetaPreview.Placeholder = MetaPreviewPlaceholder; MetaPreview.propTypes = { className: PropTypes.string, compact: PropTypes.bool, - id: PropTypes.string, - type: PropTypes.string, name: PropTypes.string, logo: PropTypes.string, background: PropTypes.string, @@ -235,14 +229,12 @@ MetaPreview.propTypes = { releaseInfo: PropTypes.string, released: PropTypes.instanceOf(Date), description: PropTypes.string, - genres: PropTypes.arrayOf(PropTypes.string), - writers: PropTypes.arrayOf(PropTypes.string), - directors: PropTypes.arrayOf(PropTypes.string), - cast: PropTypes.arrayOf(PropTypes.string), - imdbId: PropTypes.string, - imdbRating: PropTypes.string, - trailer: PropTypes.string, - share: PropTypes.string, + links: PropTypes.arrayOf(PropTypes.shape({ + category: PropTypes.string, + name: PropTypes.string, + url: PropTypes.string + })), + trailer: PropTypes.object, inLibrary: PropTypes.bool, toggleInLibrary: PropTypes.func }; diff --git a/src/common/useInLibrary.js b/src/common/useInLibrary.js index 0c8a601cb..2f595ed15 100644 --- a/src/common/useInLibrary.js +++ b/src/common/useInLibrary.js @@ -1,8 +1,12 @@ -const { useBinaryState } = require('stremio/common'); +const useBinaryState = require('stremio/common/useBinaryState'); -const useInLibrary = () => { +const useInLibrary = (id) => { const [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary] = useBinaryState(false); - return [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary]; + if (typeof id === 'string') { + return [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary]; + } else { + return [false, null, null, null]; + } }; module.exports = useInLibrary; diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js index a2ef2fb3d..877916cfb 100644 --- a/src/routes/MetaDetails/MetaDetails.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -1,5 +1,5 @@ const React = require('react'); -const { NavBar, MetaPreview } = require('stremio/common'); +const { NavBar, MetaPreview, useInLibrary } = require('stremio/common'); const VideosList = require('./VideosList'); const StreamsList = require('./StreamsList'); const useMetaDetails = require('./useMetaDetails'); @@ -10,6 +10,7 @@ const MetaDetails = ({ urlParams }) => { const [meta, streams] = useMetaDetails(urlParams); const [metaResourceRef, metaGroups, selectedMetaGroup] = useSelectableGroups(meta.resourceRef, meta.groups); const { resourceRef: streamsResourceRef, groups: streamsGroups } = streams; + const [inLibrary, , , toggleInLibrary] = useInLibrary(metaResourceRef ? metaResourceRef.id : null); return (
{ {...selectedMetaGroup.content.content} className={styles['meta-preview']} background={null} + inLibrary={inLibrary} + toggleInLibrary={toggleInLibrary} /> : @@ -46,12 +49,16 @@ const MetaDetails = ({ urlParams }) => { : metaGroups.every((group) => group.content.type === 'Err') ? : Date: Mon, 18 Nov 2019 12:50:59 +0200 Subject: [PATCH 233/442] close share modal fixed --- src/common/MetaPreview/MetaPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/MetaPreview/MetaPreview.js b/src/common/MetaPreview/MetaPreview.js index abde7791c..b530cf028 100644 --- a/src/common/MetaPreview/MetaPreview.js +++ b/src/common/MetaPreview/MetaPreview.js @@ -200,7 +200,7 @@ const MetaPreview = ({ className, compact, name, logo, background, runtime, rele /> { shareModalOpen ? - + From 6e65012ec75e6bbd2158b2fde98e1e3f1042e654 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 18 Nov 2019 12:58:20 +0200 Subject: [PATCH 234/442] handle error cases in library --- src/routes/Library/Library.js | 34 ++++++++++++++++++++++---------- src/routes/Library/styles.less | 32 +++++++++++++++++++----------- src/routes/Library/useLibrary.js | 5 +++-- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 8ece37d85..4e81032d3 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -5,7 +5,7 @@ const useSort = require('./useSort'); const styles = require('./styles'); const Library = ({ urlParams, queryParams }) => { - const [metaItems, selectTypeInput] = useLibrary(urlParams); + const [metaItems, selectTypeInput, error] = useLibrary(urlParams); const [selectSortInput, sortFunction] = useSort(urlParams, queryParams); return (
@@ -15,15 +15,29 @@ const Library = ({ urlParams, queryParams }) => {
-
- {metaItems - .sort(sortFunction) - .map((metaItem, index) => ( - - )) +
+ { + error !== null ? +
+ No items for type {urlParams.type !== (null && '') ? urlParams.type : '"Empty"'} +
+ : + Array.isArray(metaItems) ? +
+ { + metaItems + .sort(sortFunction) + .map(({ removed, temp, ...metaItem }, index) => ( + + ))} +
+ : +
+ Loading +
}
diff --git a/src/routes/Library/styles.less b/src/routes/Library/styles.less index 8f4417f89..42f281429 100644 --- a/src/routes/Library/styles.less +++ b/src/routes/Library/styles.less @@ -19,11 +19,11 @@ grid-template-columns: 1fr auto; grid-template-rows: auto 1fr; grid-template-areas: - "dropdowns-area switch-view-area" - "meta-items-area meta-items-area"; + "controls-area switch-view-area" + "type-content-area type-content-area"; .controls-container { - grid-area: dropdowns-area; + grid-area: controls-area; display: flex; flex-direction: row; margin: 2rem; @@ -41,14 +41,24 @@ } } - .meta-items-container { - grid-area: meta-items-area; - display: grid; - grid-auto-rows: max-content; - grid-gap: 1.5rem; - align-items: center; - padding: 0 2rem; - overflow-y: auto; + .type-content-container { + grid-area: type-content-area; + + .meta-items-container { + display: grid; + max-height: 100%; + grid-auto-rows: max-content; + grid-gap: 1.5rem; + align-items: center; + padding: 0 2rem; + overflow-y: auto; + } + + .message-container { + padding: 0 2rem; + font-size: 2rem; + color: var(--color-surfacelighter); + } } } } diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 8e8989709..85c17be64 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -4,7 +4,7 @@ const { useServices } = require('stremio/services'); const useLibrary = (urlParams) => { const { core } = useServices(); - const [library, setLibrary] = React.useState([[], null]); + const [library, setLibrary] = React.useState([[], null, null]); React.useEffect(() => { const state = core.getState(); const type = typeof urlParams.type === 'string' && urlParams.type.length > 0 ? @@ -28,7 +28,8 @@ const useLibrary = (urlParams) => { window.location.replace(`#/library/${event.value}${search !== null ? search : ''}`); } }; - setLibrary([state.library.items, selectInput]); + const error = state.library.items === 0 ? state.library.items : null; + setLibrary([state.library.items, selectInput, error]); }; core.on('NewModel', onNewState); core.dispatch({ From f0e252ed635c1d1c3c79ec1948a892611104872e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 18 Nov 2019 13:42:48 +0200 Subject: [PATCH 235/442] title added to share dialog --- src/common/MetaPreview/MetaPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/MetaPreview/MetaPreview.js b/src/common/MetaPreview/MetaPreview.js index b530cf028..a498bd250 100644 --- a/src/common/MetaPreview/MetaPreview.js +++ b/src/common/MetaPreview/MetaPreview.js @@ -200,7 +200,7 @@ const MetaPreview = ({ className, compact, name, logo, background, runtime, rele /> { shareModalOpen ? - + From 41e910e1f0fb87a28827dc2e155e6444c2751640 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 18 Nov 2019 15:47:21 +0200 Subject: [PATCH 236/442] ModalDialog overflow styles fixed --- src/common/ModalDialog/ModalDialog.js | 121 ++++++++++------- src/common/ModalDialog/styles.less | 127 ++++++++++-------- storybook/stories/ModalDialog/ModalDialog.js | 96 ------------- .../ModalDialogWithActionButtons.js | 18 +++ .../ModalDialogWithActionButtons/index.js | 1 + .../ModalDialogWithActionButtons/styles.less | 31 +++++ .../SampleModalDialog/SampleModalDialog.js | 13 ++ .../ModalDialog/SampleModalDialog/index.js | 1 + storybook/stories/ModalDialog/index.js | 4 +- 9 files changed, 205 insertions(+), 207 deletions(-) delete mode 100644 storybook/stories/ModalDialog/ModalDialog.js create mode 100644 storybook/stories/ModalDialog/ModalDialogWithActionButtons/ModalDialogWithActionButtons.js create mode 100644 storybook/stories/ModalDialog/ModalDialogWithActionButtons/index.js create mode 100644 storybook/stories/ModalDialog/ModalDialogWithActionButtons/styles.less create mode 100644 storybook/stories/ModalDialog/SampleModalDialog/SampleModalDialog.js create mode 100644 storybook/stories/ModalDialog/SampleModalDialog/index.js diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index bb632fc6b..c6e5522e4 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -6,21 +6,10 @@ const Icon = require('stremio-icons/dom'); const { Modal } = require('stremio-router'); const styles = require('./styles'); -const ModalDialog = ({ className, children, title, buttons, onCloseRequest }) => { - React.useEffect(() => { - const onKeyDown = (event) => { - if (event.key === 'Escape') { - onCloseRequest({ - type: 'close', - nativeEvent: event - }); - } - }; - window.addEventListener('keydown', onKeyDown); - return () => { - window.removeEventListener('keydown', onKeyDown); - }; - }, [onCloseRequest]); +const ModalDialog = ({ className, title, buttons, children, onCloseRequest }) => { + const onModalDialogContainerMouseDown = React.useCallback((event) => { + event.nativeEvent.closeModalDialogPrevented = true; + }, []); const closeButtonOnClick = React.useCallback((event) => { onCloseRequest({ type: 'close', @@ -28,55 +17,79 @@ const ModalDialog = ({ className, children, title, buttons, onCloseRequest }) => nativeEvent: event.nativeEvent }); }, [onCloseRequest]); - const onModalContainerMouseDown = React.useCallback((event) => { - if (event.target === event.currentTarget) { - onCloseRequest({ - type: 'close', - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } + React.useEffect(() => { + const onCloseEvent = (event) => { + if (!event.closeModalDialogPrevented && typeof onCloseRequest === 'function') { + const closeEvent = { + type: 'close', + nativeEvent: event + }; + switch (event.type) { + case 'resize': + onCloseRequest(closeEvent); + break; + case 'keydown': + if (event.key === 'Escape') { + onCloseRequest(closeEvent); + } + break; + case 'mousedown': + if (event.target !== document.documentElement) { + onCloseRequest(closeEvent); + } + break; + } + } + }; + window.addEventListener('resize', onCloseEvent); + window.addEventListener('keydown', onCloseEvent); + window.addEventListener('mousedown', onCloseEvent); + return () => { + window.removeEventListener('resize', onCloseEvent); + window.removeEventListener('keydown', onCloseEvent); + window.removeEventListener('mousedown', onCloseEvent); + }; }, [onCloseRequest]); return ( - -
- - { - typeof title === 'string' && title.length > 0 ? -

{title}

- : - null - } + +
+
+ { + typeof title === 'string' && title.length > 0 ? +
{title}
+ : + null + } + +
{children} -
- { - Array.isArray(buttons) && buttons.length > 0 ? -
- { - buttons.map((button, key) => ( - - )) - } -
- : - null - } + ))} +
+ : + null + } +
); @@ -86,11 +99,15 @@ ModalDialog.propTypes = { className: PropTypes.string, title: PropTypes.string, buttons: PropTypes.arrayOf(PropTypes.shape({ + className: PropTypes.string, label: PropTypes.string, icon: PropTypes.string, - className: PropTypes.string, props: PropTypes.object })), + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]), onCloseRequest: PropTypes.func }; diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index 9eb93b01f..4700d70fc 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -1,104 +1,117 @@ .modal-container { display: flex; - flex-direction: column; + justify-content: center; + align-items: center; background-color: var(--color-backgrounddark40); .modal-dialog-container { - position: relative; - margin: auto; - padding: 1rem; + flex: none; + display: flex; + flex-direction: column; + max-width: 80%; + max-height: 80%; background-color: var(--color-surfacelighter); - .close-button-container { + .header-container { + flex: none; + align-self: stretch; display: flex; flex-direction: row; - align-items: center; - justify-content: center; - position: absolute; - top: .2rem; - right: .2rem; - width: 2rem; - height: 2rem; - padding: 0.5rem; + justify-content: flex-end; + padding: 0.2rem 0.2rem 0; - .icon { + .title-container { + flex: 1; + align-self: center; + max-height: 2.4em; + padding: 0 0.5rem; + font-size: 1.2rem; + color: var(--color-backgrounddarker); + } + + .close-button-container { flex: none; - display: block; - width: 100%; - height: 100%; - fill: var(--color-surfacedark); - } - - &:hover { - background-color: var(--color-surfacelight); + align-self: flex-start; + width: 2rem; + height: 2rem; + padding: 0.5rem; .icon { - fill: var(--color-signal2); + display: block; + width: 100%; + height: 100%; + fill: var(--color-surfacedark); + } + + &:hover, &:focus { + background-color: var(--color-surfacelight); + + .icon { + fill: var(--color-surfacedarker); + } + } + + &:focus { + outline-color: var(--color-surfacedark); } } - - &:focus { - .icon { - fill: var(--color-signal2); - } - } - } - - h1 { - margin-bottom: 1rem; - font-size: 1.2rem; } .modal-dialog-content { - padding: 1rem; + flex: 1; + align-self: stretch; + margin: 1rem 0.5rem; + padding: 0 0.5rem; + overflow-y: auto; - >:not(:first-child) { + .buttons-container { margin-top: 1rem; + display: flex; + flex-direction: row; + flex-wrap: wrap; } } - - .modal-dialog-buttons { - margin: 1rem; - display: flex; - flex-direction: row; - } } } .action-button { + flex: 1; display: flex; flex-direction: row; align-items: center; justify-content: center; - flex: 1 0 0; padding: 1rem; - text-align: center; - color: var(--color-surfacelighter); background-color: var(--color-signal5); + &:focus { + outline-width: calc(1.5 * var(--focus-outline-size)); + outline-color: var(--color-surfacelighter); + outline-offset: calc(-2 * var(--focus-outline-size)); + } + &:hover { filter: brightness(1.2); } - &:focus { - outline: calc(1.5 * var(--focus-outline-size)) solid var(--color-surfacelighter); - outline-offset: calc(-2 * var(--focus-outline-size)); - } - - &:global(.disabled) { - color: var(--color-surfacedarker); - background-color: var(--color-surfacedark); + &:not(:last-child) { + margin-right: 1rem; } .icon { flex: none; - width: 1rem; - height: 1rem; + width: 1.2rem; + height: 1.2rem; margin-right: .5rem; fill: var(--color-surfacelighter); } - &:not(:last-child) { - margin-right: 2rem; + .label { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + max-height: 3.6em; + font-size: 1.1rem; + text-align: center; + color: var(--color-surfacelighter); } } \ No newline at end of file diff --git a/storybook/stories/ModalDialog/ModalDialog.js b/storybook/stories/ModalDialog/ModalDialog.js deleted file mode 100644 index 31f8d3e33..000000000 --- a/storybook/stories/ModalDialog/ModalDialog.js +++ /dev/null @@ -1,96 +0,0 @@ - -const React = require('react'); -const { storiesOf } = require('@storybook/react'); -const { action } = require('@storybook/addon-actions'); -const { ModalDialog } = require('stremio/common'); -const styles = require('./styles'); -const useBinaryState = require('stremio/common/useBinaryState'); - -storiesOf('ModalDialog', module).add('ModalDialog', () => { - const [modalVisible, showModal, hideModal] = useBinaryState(false); - const [modalBVisible, showModalB, hideModalB] = useBinaryState(true); - - const modalDummyContents = ( -
-
-

What is Lorem Ipsum?

-

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

-
-
-

Where does it come from?

-

Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.

-
-
- ); - - /* - - Every Button has the following properties: - - label (String/React component) - the contents of the button. - icon (String) - icon class name. It will be shown to the left of the button's text - className (String) - Custom className applied along side the default one. Used for custom styles - props (Object) - the properties applied to the button itself. If a className is supplied here it will override all other class names for this Button - - */ - - const oneButton = [ - { - label: 'Show many buttons', icon: 'ic_ellipsis', props: { - onClick: React.useCallback(() => setButtons(manyButtons), [setButtons]) - } - }, - ] - const manyButtons = [ - { - label: 'One', - icon: 'ic_back_ios', - props: { - onClick: React.useCallback(() => setButtons(oneButton), [setButtons]) - } - }, - { - label: 'A disabled button with a long name', - props: { - disabled: true, - tabIndex: -1, // We don't need keyboard focus on disabled elements - onClick: action('The onClick on disabled buttons should not be called!') - } - }, - { - label: 'A button with a long name, icon and custom class', - className: styles['custom-button'], - props: { - onClick: action('A button with a long name and icon clicked') - } - }, - {} - ]; - const [buttons, setButtons] = React.useState(oneButton); - - return ( -
- - { - modalVisible - ? - - {modalDummyContents} - - : - null - } - - - { - modalBVisible - ? - - {modalDummyContents} - - : - null - } -
- ); -}); \ No newline at end of file diff --git a/storybook/stories/ModalDialog/ModalDialogWithActionButtons/ModalDialogWithActionButtons.js b/storybook/stories/ModalDialog/ModalDialogWithActionButtons/ModalDialogWithActionButtons.js new file mode 100644 index 000000000..0b2f7cfae --- /dev/null +++ b/storybook/stories/ModalDialog/ModalDialogWithActionButtons/ModalDialogWithActionButtons.js @@ -0,0 +1,18 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { ModalDialog } = require('stremio/common'); +const styles = require('./styles'); + +storiesOf('ModalDialog', module).add('ModalDialogWithActionButtons', () => ( + +
+ 1000px height content +
+
+)); \ No newline at end of file diff --git a/storybook/stories/ModalDialog/ModalDialogWithActionButtons/index.js b/storybook/stories/ModalDialog/ModalDialogWithActionButtons/index.js new file mode 100644 index 000000000..2da4e4115 --- /dev/null +++ b/storybook/stories/ModalDialog/ModalDialogWithActionButtons/index.js @@ -0,0 +1 @@ +require('./ModalDialogWithActionButtons'); diff --git a/storybook/stories/ModalDialog/ModalDialogWithActionButtons/styles.less b/storybook/stories/ModalDialog/ModalDialogWithActionButtons/styles.less new file mode 100644 index 000000000..febf9ea6e --- /dev/null +++ b/storybook/stories/ModalDialog/ModalDialogWithActionButtons/styles.less @@ -0,0 +1,31 @@ +:import('~stremio/common/ModalDialog/styles.less') { + modal-dialog-icon: icon; + modal-dialog-label: label; +} + +.addons-button-container { + background-color: transparent; + border: 2px solid gray; + + .modal-dialog-icon { + fill: gray; + } + + .modal-dialog-label { + color: gray; + } + + &:hover, &:focus { + filter: none; + outline: none; + border-color: black; + + .modal-dialog-icon { + fill: black; + } + + .modal-dialog-label { + color: black; + } + } +} \ No newline at end of file diff --git a/storybook/stories/ModalDialog/SampleModalDialog/SampleModalDialog.js b/storybook/stories/ModalDialog/SampleModalDialog/SampleModalDialog.js new file mode 100644 index 000000000..980810b0e --- /dev/null +++ b/storybook/stories/ModalDialog/SampleModalDialog/SampleModalDialog.js @@ -0,0 +1,13 @@ + +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { ModalDialog } = require('stremio/common'); + +storiesOf('ModalDialog', module).add('SampleModalDialog', () => ( + +
+ 100px height content +
+
+)); \ No newline at end of file diff --git a/storybook/stories/ModalDialog/SampleModalDialog/index.js b/storybook/stories/ModalDialog/SampleModalDialog/index.js new file mode 100644 index 000000000..a95c16af6 --- /dev/null +++ b/storybook/stories/ModalDialog/SampleModalDialog/index.js @@ -0,0 +1 @@ +require('./SampleModalDialog'); diff --git a/storybook/stories/ModalDialog/index.js b/storybook/stories/ModalDialog/index.js index 0e5c21118..89d26593b 100644 --- a/storybook/stories/ModalDialog/index.js +++ b/storybook/stories/ModalDialog/index.js @@ -1,2 +1,2 @@ - -require('./ModalDialog'); \ No newline at end of file +require('./SampleModalDialog'); +require('./ModalDialogWithActionButtons'); From d01e51235c365649711677c5db55263d27a3caae Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 18 Nov 2019 16:39:57 +0200 Subject: [PATCH 237/442] share prompt styles updated --- src/common/SharePrompt/SharePrompt.js | 17 +++-- src/common/SharePrompt/styles.less | 90 ++++++++++++++------------- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/common/SharePrompt/SharePrompt.js b/src/common/SharePrompt/SharePrompt.js index 8a8dbefef..2ac48f060 100644 --- a/src/common/SharePrompt/SharePrompt.js +++ b/src/common/SharePrompt/SharePrompt.js @@ -9,8 +9,10 @@ const styles = require('./styles'); const SharePrompt = ({ className, url }) => { const inputRef = React.useRef(null); const copyToClipboard = React.useCallback(() => { - inputRef.current.select(); - document.execCommand('copy'); + if (inputRef.current !== null) { + inputRef.current.select(); + document.execCommand('copy'); + } }, []); return (
@@ -25,7 +27,14 @@ const SharePrompt = ({ className, url }) => {
- + -
@@ -46,7 +46,7 @@ const SharePrompt = ({ className, url }) => { onClick={selectInputContent} tabIndex={-1} /> - diff --git a/src/common/SharePrompt/styles.less b/src/common/SharePrompt/styles.less index a56740d58..7deac93f2 100644 --- a/src/common/SharePrompt/styles.less +++ b/src/common/SharePrompt/styles.less @@ -41,7 +41,6 @@ flex-shrink: 1; flex-basis: auto; max-height: 2.4em; - font-size: 0.9rem; font-weight: 500; text-align: center; color: var(--color-surfacelighter); From 21570bd6975e843dc9bea3ee3e8d34350543ce00 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 18 Nov 2019 18:50:21 +0200 Subject: [PATCH 243/442] --spatial-navigation-action usage dropped from button --- src/common/Button/styles.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/Button/styles.less b/src/common/Button/styles.less index 699eeb552..53f567ed4 100644 --- a/src/common/Button/styles.less +++ b/src/common/Button/styles.less @@ -1,5 +1,4 @@ .button-container { - --spatial-navigation-action: focus; outline-width: var(--focus-outline-size); outline-color: var(--color-surfacelighter); outline-offset: calc(-1 * var(--focus-outline-size)); From 0f535a4afcb46f95de2653f78535216a128d1256 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 18 Nov 2019 18:52:02 +0200 Subject: [PATCH 244/442] metadetails regexp updated --- src/common/routesRegexp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index b8bad8efa..67313eea0 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -20,7 +20,7 @@ const routesRegexp = { urlParamsNames: [] }, metadetails: { - regexp: /^\/metadetails\/(?:([^\/]*)\/)(?:([^\/]*)\/?)(?:([^\/]*)\/?)?$/i, + regexp: /^\/metadetails\/(?:([^\/]*))\/(?:([^\/]*))(?:\/([^\/]*)\/?)?$/i, urlParamsNames: ['type', 'id', 'videoId'] }, addons: { From 11e01f49070ad8e79f43d1942747f76a7ed3eacf Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 18 Nov 2019 20:51:42 +0200 Subject: [PATCH 245/442] ColorInput/ColorPicker stories added --- src/common/ColorInput/ColorInput.js | 37 ++++++++++++------- .../ColorInput/ColorPicker/ColorPicker.js | 12 +++--- storybook/stories/ColorInput/ColorInput.js | 20 ++++++++++ storybook/stories/ColorInput/index.js | 1 + storybook/stories/ColorInput/styles.less | 6 +++ storybook/stories/ColorPicker/ColorPicker.js | 7 +++- storybook/stories/index.js | 1 + 7 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 storybook/stories/ColorInput/ColorInput.js create mode 100644 storybook/stories/ColorInput/index.js create mode 100644 storybook/stories/ColorInput/styles.less diff --git a/src/common/ColorInput/ColorInput.js b/src/common/ColorInput/ColorInput.js index f9a682eb9..81700a015 100644 --- a/src/common/ColorInput/ColorInput.js +++ b/src/common/ColorInput/ColorInput.js @@ -4,40 +4,51 @@ const AColorPicker = require('a-color-picker'); const Button = require('stremio/common/Button'); const useBinaryState = require('stremio/common/useBinaryState'); const ModalDialog = require('stremio/common/ModalDialog'); -const useDataset = require('stremio/common/useDataset'); const ColorPicker = require('./ColorPicker'); const COLOR_FORMAT = 'hexcss4'; -const ColorInput = ({ className, value, onChange, ...props }) => { - value = AColorPicker.parseColor(value, COLOR_FORMAT); - const dataset = useDataset(props); - const [modalOpen, setModalOpen, setModalClosed] = useBinaryState(false); - const [tempValue, setTempValue] = React.useState(value); +const ColorInput = ({ className, value, onChange }) => { + const [modalOpen, openModal, closeModal] = useBinaryState(false); + const [tempValue, setTempValue] = React.useState(() => { + return AColorPicker.parseColor(value, COLOR_FORMAT); + }); const colorPickerOnInput = React.useCallback((event) => { setTempValue(event.value); }, []); - const submitButtonOnClick = React.useCallback((event) => { + const selectButtonOnClick = React.useCallback((event) => { if (typeof onChange === 'function') { onChange({ type: 'change', value: tempValue, - dataset: dataset, reactEvent: event, nativeEvent: event.nativeEvent }); } - setModalClosed(); - }, [onChange, tempValue, dataset]); + + closeModal(); + }, [tempValue, onChange]); + const buttonStyle = React.useMemo(() => ({ + backgroundColor: value + }), [value]); + const modalButtons = React.useMemo(() => ([ + { + label: 'Select', + props: { + onClick: selectButtonOnClick, + 'data-autofocus': true + } + } + ]), [selectButtonOnClick]); React.useEffect(() => { - setTempValue(value); + setTempValue(AColorPicker.parseColor(value, COLOR_FORMAT)); }, [value, modalOpen]); return ( -
{ @@ -94,9 +98,7 @@ const MetaItem = React.memo(({ className, type, name, poster, posterShape, playI
( - - )} + renderLabelContent={renderMenuOptionsLabelContent} options={menuOptions} onOpen={onMenuOpen} onClose={onMenuClose} From d9f5bec1f510ceef593d52e7384d0d057bef37e5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 19 Nov 2019 11:36:54 +0200 Subject: [PATCH 250/442] TextInput submit onKeyDown --- src/common/TextInput/TextInput.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/TextInput/TextInput.js b/src/common/TextInput/TextInput.js index 88f263348..4f7db50f1 100644 --- a/src/common/TextInput/TextInput.js +++ b/src/common/TextInput/TextInput.js @@ -3,15 +3,15 @@ const classnames = require('classnames'); const styles = require('./styles'); const TextInput = React.forwardRef((props, ref) => { - const onKeyUp = React.useCallback((event) => { - if (typeof props.onKeyUp === 'function') { - props.onKeyUp(event); + const onKeyDown = React.useCallback((event) => { + if (typeof props.onKeyDown === 'function') { + props.onKeyDown(event); } if (event.key === 'Enter' && !event.nativeEvent.submitPrevented && typeof props.onSubmit === 'function') { props.onSubmit(event); } - }, [props.onKeyUp, props.onSubmit]); + }, [props.onKeyDown, props.onSubmit]); return ( { {...props} ref={ref} className={classnames(props.className, styles['text-input'], { 'disabled': props.disabled })} - onKeyUp={onKeyUp} + onKeyDown={onKeyDown} /> ); }); From d63e73e5ecf8344aae37ae6155e907a9a8898ee4 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 19 Nov 2019 11:39:28 +0200 Subject: [PATCH 251/442] dataset prop added to ColorInput --- src/common/ColorInput/ColorInput.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/common/ColorInput/ColorInput.js b/src/common/ColorInput/ColorInput.js index 81700a015..d90651573 100644 --- a/src/common/ColorInput/ColorInput.js +++ b/src/common/ColorInput/ColorInput.js @@ -8,7 +8,7 @@ const ColorPicker = require('./ColorPicker'); const COLOR_FORMAT = 'hexcss4'; -const ColorInput = ({ className, value, onChange }) => { +const ColorInput = ({ className, value, dataset, onChange }) => { const [modalOpen, openModal, closeModal] = useBinaryState(false); const [tempValue, setTempValue] = React.useState(() => { return AColorPicker.parseColor(value, COLOR_FORMAT); @@ -21,13 +21,14 @@ const ColorInput = ({ className, value, onChange }) => { onChange({ type: 'change', value: tempValue, + dataset: dataset, reactEvent: event, nativeEvent: event.nativeEvent }); } closeModal(); - }, [tempValue, onChange]); + }, [tempValue, dataset, onChange]); const buttonStyle = React.useMemo(() => ({ backgroundColor: value }), [value]); @@ -61,6 +62,7 @@ const ColorInput = ({ className, value, onChange }) => { ColorInput.propTypes = { className: PropTypes.string, value: PropTypes.string, + dataset: PropTypes.objectOf(String), onChange: PropTypes.func }; From b2fdfc51ae4a545094455f01a830741e902c541c Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 19 Nov 2019 14:19:42 +0200 Subject: [PATCH 252/442] library regexp changed --- src/common/routesRegexp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index 62f1f2887..a44480d3c 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -12,7 +12,7 @@ const routesRegexp = { urlParamsNames: ['addonTransportUrl', 'catalogId', 'type'] }, library: { - regexp: /^\/library(?:\/([^\/]*?))?\/?$/i, + regexp: /^\/library(?:\/([^\/]*)\/?)?$/i, urlParamsNames: ['type'] }, search: { From 0cc698c509ceb44852fad4e22b0afc0d61b300a3 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 19 Nov 2019 14:30:26 +0200 Subject: [PATCH 253/442] dispatch load action when receive types --- src/routes/Library/useLibrary.js | 38 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 85c17be64..45f75b535 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -5,16 +5,22 @@ const { useServices } = require('stremio/services'); const useLibrary = (urlParams) => { const { core } = useServices(); const [library, setLibrary] = React.useState([[], null, null]); + const [type, setType] = React.useState(null); React.useEffect(() => { - const state = core.getState(); - const type = typeof urlParams.type === 'string' && urlParams.type.length > 0 ? - urlParams.type - : - state.library.types.length > 0 ? - state.library.types[0] + const updateType = () => { + const state = core.getState(); + setType(typeof urlParams.type === 'string' ? + urlParams.type : - ''; + state.library.types.length > 0 ? + state.library.types[0] + : + '' + ); + }; + updateType(); const onNewState = () => { + updateType(); const state = core.getState(); const selectInput = { selected: [state.library.selected], @@ -32,17 +38,21 @@ const useLibrary = (urlParams) => { setLibrary([state.library.items, selectInput, error]); }; core.on('NewModel', onNewState); - core.dispatch({ - action: 'Load', - args: { - load: 'LibItemsByType', - args: type - } - }); return () => { core.off('NewModel', onNewState); }; }, [urlParams]); + React.useEffect(() => { + if (typeof type === 'string') { + core.dispatch({ + action: 'Load', + args: { + load: 'LibItemsByType', + args: type + } + }); + } + }, [type]); return library; } From db185dcf3eac878d25e58eeddc9204f6c93f424a Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 19 Nov 2019 14:31:08 +0200 Subject: [PATCH 254/442] check for user in library --- src/routes/Library/Library.js | 42 ++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 4e81032d3..69b2f744b 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -1,10 +1,12 @@ const React = require('react'); const { Multiselect, MainNavBar, MetaItem } = require('stremio/common'); +const useUser = require('stremio/common/useUser'); const useLibrary = require('./useLibrary'); const useSort = require('./useSort'); const styles = require('./styles'); const Library = ({ urlParams, queryParams }) => { + const user = useUser(); const [metaItems, selectTypeInput, error] = useLibrary(urlParams); const [selectSortInput, sortFunction] = useSort(urlParams, queryParams); return ( @@ -17,27 +19,35 @@ const Library = ({ urlParams, queryParams }) => {
{ - error !== null ? + !user ?
- No items for type {urlParams.type !== (null && '') ? urlParams.type : '"Empty"'} + Please log into this app + { + window.location.replace('#/intro') + }
: - Array.isArray(metaItems) ? -
- { - metaItems - .sort(sortFunction) - .map(({ removed, temp, ...metaItem }, index) => ( - - ))} + error !== null ? +
+ No items for type {urlParams.type !== (null && '') ? urlParams.type : '"Empty"'}
: -
- Loading -
+ Array.isArray(metaItems) ? +
+ { + metaItems + .sort(sortFunction) + .map(({ removed, temp, ...metaItem }, index) => ( + + ))} +
+ : +
+ Loading +
}
From a95661802a5e66b36ce4466395d891bd43fc7424 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 19 Nov 2019 14:46:10 +0200 Subject: [PATCH 255/442] intro: window location fixed --- src/routes/Intro/Intro.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index beb35e26d..e71730c30 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -77,7 +77,7 @@ const Intro = ({ queryParams }) => { if (event === 'CtxChanged') { const state = core.getState(); if (state.ctx.content.auth !== null) { - window.location.replace('/'); + window.location.replace('#/'); } } }; From 7c421d2d6efa1261699e2f8316b0ee63a25f7412 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 19 Nov 2019 14:49:04 +0200 Subject: [PATCH 256/442] into: location replace in loginAsGuest --- src/routes/Intro/Intro.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index e71730c30..66b4b5fe6 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -146,7 +146,7 @@ const Intro = ({ queryParams }) => { userOp: 'Logout' } }); - location = '#/'; + window.location.replace('#/'); }, [state.termsAccepted]); const signup = React.useCallback(() => { if (!state.termsAccepted) { From 54793eb60cbe8e29878e71b971d458e67c825602 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 19 Nov 2019 14:56:19 +0200 Subject: [PATCH 257/442] useDataset removed --- src/common/PaginateInput/PaginateInput.js | 8 +++----- src/common/index.js | 2 -- src/common/useDataset.js | 20 -------------------- 3 files changed, 3 insertions(+), 27 deletions(-) delete mode 100644 src/common/useDataset.js diff --git a/src/common/PaginateInput/PaginateInput.js b/src/common/PaginateInput/PaginateInput.js index 9c75643ae..e0f207a31 100644 --- a/src/common/PaginateInput/PaginateInput.js +++ b/src/common/PaginateInput/PaginateInput.js @@ -4,11 +4,9 @@ const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const Button = require('stremio/common/Button'); const Multiselect = require('stremio/common/Multiselect'); -const useDataset = require('stremio/common/useDataset'); const styles = require('./styles'); -const PaginateInput = ({ className, options, selected, onSelect, ...props }) => { - const dataset = useDataset(props); +const PaginateInput = ({ className, options, selected, dataset, onSelect }) => { const selectedLabelText = React.useMemo(() => { if (Array.isArray(options)) { const selectedOption = options.find(({ value }) => { @@ -53,7 +51,7 @@ const PaginateInput = ({ className, options, selected, onSelect, ...props }) => }); } } - }, [dataset, options, selected, onSelect]); + }, [options, selected, dataset, onSelect]); const optionOnSelect = React.useCallback((event) => { const page = parseInt(event.value); if (!isNaN(page) && typeof onSelect === 'function') { @@ -65,7 +63,7 @@ const PaginateInput = ({ className, options, selected, onSelect, ...props }) => nativeEvent: event.nativeEvent }); } - }, [onSelect]); + }, [dataset, onSelect]); return (
: error !== null ? diff --git a/src/routes/Library/styles.less b/src/routes/Library/styles.less index 42f281429..a09fb601e 100644 --- a/src/routes/Library/styles.less +++ b/src/routes/Library/styles.less @@ -59,6 +59,45 @@ font-size: 2rem; color: var(--color-surfacelighter); } + + .anonymous-user-message-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + + .login-button { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 20rem; + min-height: 4rem; + margin-top: 2rem; + padding: 0.5rem 1rem; + background-color: var(--color-primarydark); + + .label { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + font-size: 1.1rem; + font-weight: 700; + color: var(--color-surfacelighter); + text-align: center; + } + + &:hover { + background-color: var(--color-primary); + } + + .label { + font-size: 1.2rem; + } + } + } } } } From 6ffaf178362b3e14591099a6678df637eecf22da Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 20 Nov 2019 16:28:32 +0200 Subject: [PATCH 259/442] MetaDetails screen adapted to changes in core --- src/routes/MetaDetails/useMetaDetails.js | 26 ++++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/routes/MetaDetails/useMetaDetails.js b/src/routes/MetaDetails/useMetaDetails.js index ab7809b30..01029a80e 100644 --- a/src/routes/MetaDetails/useMetaDetails.js +++ b/src/routes/MetaDetails/useMetaDetails.js @@ -10,28 +10,32 @@ const useMetaDetails = (urlParams) => { React.useEffect(() => { const onNewModel = () => { const state = core.getState(); - const [metaResourceRef, streamsResourceRef] = state.meta_details.selected; - const metaGroups = state.meta_details.metas.map((metaGroup) => { - if (metaGroup.content.type === 'Ready') { - metaGroup.content.content.released = new Date(metaGroup.content.content.released); - metaGroup.content.content.videos = metaGroup.content.content.videos.map((video) => { + console.log(state); + const { meta_resource_ref = null, streams_resource_ref = null } = state.meta_details.selected !== null ? + state.meta_details.selected + : + {}; + const meta_groups = state.meta_details.meta_groups.map((meta_group) => { + if (meta_group.content.type === 'Ready') { + meta_group.content.content.released = new Date(meta_group.content.content.released); + meta_group.content.content.videos = meta_group.content.content.videos.map((video) => { video.released = new Date(video.released); video.upcoming = !isNaN(video.released.getTime()) ? video.released.getTime() > Date.now() : false; - video.href = `#/metadetails/${metaGroup.content.content.type}/${metaGroup.content.content.id}/${video.id}`; - // TODO add href, watched and progress + video.href = `#/metadetails/${meta_group.content.content.type}/${meta_group.content.content.id}/${video.id}`; + // TODO add watched and progress return video; }); } - return metaGroup; + return meta_group; }); - const streamsGroups = state.meta_details.streams; + const streams_groups = state.meta_details.streams_groups; setMetaDetails([ - { resourceRef: metaResourceRef, groups: metaGroups }, - { resourceRef: streamsResourceRef, groups: streamsGroups } + { resourceRef: meta_resource_ref, groups: meta_groups }, + { resourceRef: streams_resource_ref, groups: streams_groups } ]); }; core.on('NewModel', onNewModel); From f70ca3d293fc83ae3ee7feca601e0f55a2df2af3 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Wed, 20 Nov 2019 16:48:29 +0200 Subject: [PATCH 260/442] type checks for dispatch fixed --- src/routes/Library/useLibrary.js | 47 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 45f75b535..240646745 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -5,23 +5,19 @@ const { useServices } = require('stremio/services'); const useLibrary = (urlParams) => { const { core } = useServices(); const [library, setLibrary] = React.useState([[], null, null]); - const [type, setType] = React.useState(null); React.useEffect(() => { - const updateType = () => { - const state = core.getState(); - setType(typeof urlParams.type === 'string' ? - urlParams.type - : - state.library.types.length > 0 ? - state.library.types[0] - : - '' - ); - }; - updateType(); const onNewState = () => { - updateType(); const state = core.getState(); + if (state.library.selected === null && state.library.types.length > 0) { + core.dispatch({ + action: 'Load', + args: { + load: 'LibItemsByType', + args: state.library.types[0] + } + }); + return; + } const selectInput = { selected: [state.library.selected], options: state.library.types @@ -38,21 +34,28 @@ const useLibrary = (urlParams) => { setLibrary([state.library.items, selectInput, error]); }; core.on('NewModel', onNewState); - return () => { - core.off('NewModel', onNewState); - }; - }, [urlParams]); - React.useEffect(() => { - if (typeof type === 'string') { + const state = core.getState(); + if (typeof urlParams.type === 'string') { core.dispatch({ action: 'Load', args: { load: 'LibItemsByType', - args: type + args: urlParams.type + } + }); + } else if (state.library.types.length > 0) { + core.dispatch({ + action: 'Load', + args: { + load: 'LibItemsByType', + args: state.library.types[0] } }); } - }, [type]); + return () => { + core.off('NewModel', onNewState); + }; + }, [urlParams]); return library; } From ce0c2c387a42b72008c8db971ff8ea4013fff9ee Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 20 Nov 2019 20:42:43 +0200 Subject: [PATCH 261/442] logs removed --- src/routes/MetaDetails/useMetaDetails.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/MetaDetails/useMetaDetails.js b/src/routes/MetaDetails/useMetaDetails.js index 01029a80e..c3054a845 100644 --- a/src/routes/MetaDetails/useMetaDetails.js +++ b/src/routes/MetaDetails/useMetaDetails.js @@ -10,7 +10,6 @@ const useMetaDetails = (urlParams) => { React.useEffect(() => { const onNewModel = () => { const state = core.getState(); - console.log(state); const { meta_resource_ref = null, streams_resource_ref = null } = state.meta_details.selected !== null ? state.meta_details.selected : From 9ded05962038a5b7e7da836c20ab09b02bbdfc37 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 21 Nov 2019 10:52:27 +0200 Subject: [PATCH 262/442] useMetaDetails expose raw meta_details model props --- src/routes/MetaDetails/MetaDetails.js | 7 ++++--- src/routes/MetaDetails/useMetaDetails.js | 24 ++++++++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js index 877916cfb..925ecea2e 100644 --- a/src/routes/MetaDetails/MetaDetails.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -7,9 +7,10 @@ const useSelectableGroups = require('./useSelectableGroups'); const styles = require('./styles'); const MetaDetails = ({ urlParams }) => { - const [meta, streams] = useMetaDetails(urlParams); - const [metaResourceRef, metaGroups, selectedMetaGroup] = useSelectableGroups(meta.resourceRef, meta.groups); - const { resourceRef: streamsResourceRef, groups: streamsGroups } = streams; + const metaDetails = useMetaDetails(urlParams); + const [metaResourceRef, metaGroups, selectedMetaGroup] = useSelectableGroups(metaDetails.selected.meta_resource_ref, metaDetails.meta_groups); + const streamsResourceRef = metaDetails.selected.streams_resource_ref; + const streamsGroups = metaDetails.streams_groups; const [inLibrary, , , toggleInLibrary] = useInLibrary(metaResourceRef ? metaResourceRef.id : null); return (
diff --git a/src/routes/MetaDetails/useMetaDetails.js b/src/routes/MetaDetails/useMetaDetails.js index c3054a845..f4d5c0e27 100644 --- a/src/routes/MetaDetails/useMetaDetails.js +++ b/src/routes/MetaDetails/useMetaDetails.js @@ -3,10 +3,14 @@ const { useServices } = require('stremio/services'); const useMetaDetails = (urlParams) => { const { core } = useServices(); - const [metaDetails, setMetaDetails] = React.useState([ - { resourceRef: null, groups: [] }, - { resourceRef: null, groups: [] } - ]); + const [metaDetails, setMetaDetails] = React.useState({ + selected: { + meta_resource_ref: null, + streams_resource_ref: null + }, + meta_groups: [], + streams_groups: [] + }); React.useEffect(() => { const onNewModel = () => { const state = core.getState(); @@ -32,10 +36,14 @@ const useMetaDetails = (urlParams) => { return meta_group; }); const streams_groups = state.meta_details.streams_groups; - setMetaDetails([ - { resourceRef: meta_resource_ref, groups: meta_groups }, - { resourceRef: streams_resource_ref, groups: streams_groups } - ]); + setMetaDetails({ + selected: { + meta_resource_ref, + streams_resource_ref + }, + meta_groups, + streams_groups + }); }; core.on('NewModel', onNewModel); core.dispatch({ From 6aced6fc0e8f982aeffb316cd3875554bcf4e563 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 21 Nov 2019 12:54:16 +0200 Subject: [PATCH 263/442] check if library is loaded --- src/routes/Library/Library.js | 2 +- src/routes/Library/useLibrary.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 1b10dc87b..9ea48e5ff 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -38,7 +38,7 @@ const Library = ({ urlParams, queryParams }) => { : error !== null ?
- No items for type {urlParams.type !== (null && '') ? urlParams.type : '"Empty"'} + {error}
: Array.isArray(metaItems) ? diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 240646745..9a3a07895 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -30,7 +30,7 @@ const useLibrary = (urlParams) => { window.location.replace(`#/library/${event.value}${search !== null ? search : ''}`); } }; - const error = state.library.items === 0 ? state.library.items : null; + const error = state.ctx.library.Ready.type !== 'Ready' ? state.ctx.library.Ready.type : null; setLibrary([state.library.items, selectInput, error]); }; core.on('NewModel', onNewState); From 5de793c189dc788a35e7ca1e2364688f072a5109 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 22 Nov 2019 11:20:07 +0200 Subject: [PATCH 264/442] space between content and frame of modal dialog increased --- src/common/ModalDialog/styles.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/ModalDialog/styles.less b/src/common/ModalDialog/styles.less index 4700d70fc..c6b7c04a1 100644 --- a/src/common/ModalDialog/styles.less +++ b/src/common/ModalDialog/styles.less @@ -60,8 +60,8 @@ .modal-dialog-content { flex: 1; align-self: stretch; - margin: 1rem 0.5rem; - padding: 0 0.5rem; + margin: 2rem 1rem; + padding: 0 1rem; overflow-y: auto; .buttons-container { From 9e9aac8ed387c0af1171613ceccec6ad82c33c59 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 22 Nov 2019 15:19:32 +0200 Subject: [PATCH 265/442] check if library is loaded --- src/routes/Library/Library.js | 2 +- src/routes/Library/useLibrary.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 1b10dc87b..9ea48e5ff 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -38,7 +38,7 @@ const Library = ({ urlParams, queryParams }) => { : error !== null ?
- No items for type {urlParams.type !== (null && '') ? urlParams.type : '"Empty"'} + {error}
: Array.isArray(metaItems) ? diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 240646745..9a3a07895 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -30,7 +30,7 @@ const useLibrary = (urlParams) => { window.location.replace(`#/library/${event.value}${search !== null ? search : ''}`); } }; - const error = state.library.items === 0 ? state.library.items : null; + const error = state.ctx.library.Ready.type !== 'Ready' ? state.ctx.library.Ready.type : null; setLibrary([state.library.items, selectInput, error]); }; core.on('NewModel', onNewState); From 1e132bc8fb7870742b07f5e04ca0a0cd6babc27f Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 22 Nov 2019 15:43:39 +0200 Subject: [PATCH 266/442] unused className removed --- src/routes/Addons/Addons.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 894fec2d7..0a8152a17 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -141,7 +141,6 @@ const Addons = ({ urlParams, queryParams }) => { transportUrl={selectedAddon.transportUrl} installed={installedAddon(selectedAddon)} official={selectedAddon.flags.official} - className={styles['prompt']} cancel={clearSelectedAddon} /> @@ -153,7 +152,6 @@ const Addons = ({ urlParams, queryParams }) => { setSharedAddon(null)}> setSharedAddon(null)} /> From 8524e342eb811d112c3bec6a9486fb2926be0ae2 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 22 Nov 2019 15:44:09 +0200 Subject: [PATCH 267/442] dialog content width removed --- src/routes/Addons/styles.less | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/routes/Addons/styles.less b/src/routes/Addons/styles.less index d97a130ea..ff3b7f2c1 100644 --- a/src/routes/Addons/styles.less +++ b/src/routes/Addons/styles.less @@ -124,8 +124,6 @@ } .add-addon-prompt-container { - width: 30rem; - .url-content { flex: 1; width: 100%; @@ -141,13 +139,7 @@ } .addon-prompt-container { - width: 50rem; - .cancel-button { background-color: var(--color-surfacedark); } -} - -.share-prompt-container { - width: 30rem; } \ No newline at end of file From 823c111c8a7c00f2813701a231bed18fd96d7f44 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 22 Nov 2019 15:49:49 +0200 Subject: [PATCH 268/442] modal dialog with long content added to storybook --- .../ModalDialogWithLongContent.js | 12 ++++++++++++ .../ModalDialog/ModalDialogWithLongContent/index.js | 1 + .../SampleModalDialog/SampleModalDialog.js | 1 - storybook/stories/ModalDialog/index.js | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 storybook/stories/ModalDialog/ModalDialogWithLongContent/ModalDialogWithLongContent.js create mode 100644 storybook/stories/ModalDialog/ModalDialogWithLongContent/index.js diff --git a/storybook/stories/ModalDialog/ModalDialogWithLongContent/ModalDialogWithLongContent.js b/storybook/stories/ModalDialog/ModalDialogWithLongContent/ModalDialogWithLongContent.js new file mode 100644 index 000000000..2874c4701 --- /dev/null +++ b/storybook/stories/ModalDialog/ModalDialogWithLongContent/ModalDialogWithLongContent.js @@ -0,0 +1,12 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { ModalDialog } = require('stremio/common'); + +storiesOf('ModalDialog', module).add('ModalDialogWithLongContent', () => ( + +
+ 1000px height content +
+
+)); \ No newline at end of file diff --git a/storybook/stories/ModalDialog/ModalDialogWithLongContent/index.js b/storybook/stories/ModalDialog/ModalDialogWithLongContent/index.js new file mode 100644 index 000000000..9d6e86c15 --- /dev/null +++ b/storybook/stories/ModalDialog/ModalDialogWithLongContent/index.js @@ -0,0 +1 @@ +require('./ModalDialogWithLongContent'); diff --git a/storybook/stories/ModalDialog/SampleModalDialog/SampleModalDialog.js b/storybook/stories/ModalDialog/SampleModalDialog/SampleModalDialog.js index 980810b0e..f7c8de1de 100644 --- a/storybook/stories/ModalDialog/SampleModalDialog/SampleModalDialog.js +++ b/storybook/stories/ModalDialog/SampleModalDialog/SampleModalDialog.js @@ -1,4 +1,3 @@ - const React = require('react'); const { storiesOf } = require('@storybook/react'); const { action } = require('@storybook/addon-actions'); diff --git a/storybook/stories/ModalDialog/index.js b/storybook/stories/ModalDialog/index.js index 89d26593b..41efd1e48 100644 --- a/storybook/stories/ModalDialog/index.js +++ b/storybook/stories/ModalDialog/index.js @@ -1,2 +1,3 @@ require('./SampleModalDialog'); require('./ModalDialogWithActionButtons'); +require('./ModalDialogWithLongContent'); From 535c0eef8a2042b5fa24aee349c4b14edf9da70f Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 22 Nov 2019 17:53:53 +0200 Subject: [PATCH 269/442] library adapted to stremio-core changes --- src/routes/Library/useLibrary.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 9a3a07895..ed58c8561 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -8,19 +8,21 @@ const useLibrary = (urlParams) => { React.useEffect(() => { const onNewState = () => { const state = core.getState(); - if (state.library.selected === null && state.library.types.length > 0) { + if (state.library.selected === null && state.library.type_names.length > 0) { core.dispatch({ action: 'Load', args: { - load: 'LibItemsByType', - args: state.library.types[0] + load: 'LibraryFiltered', + args: { + type_name: state.library.type_names[0] + } } }); return; } const selectInput = { selected: [state.library.selected], - options: state.library.types + options: state.library.type_names .map((type) => ({ label: type === '' ? '"Empty"' : type, value: type @@ -30,7 +32,7 @@ const useLibrary = (urlParams) => { window.location.replace(`#/library/${event.value}${search !== null ? search : ''}`); } }; - const error = state.ctx.library.Ready.type !== 'Ready' ? state.ctx.library.Ready.type : null; + const error = state.library.library_state.type !== 'Ready' ? state.library.library_state.type : null; setLibrary([state.library.items, selectInput, error]); }; core.on('NewModel', onNewState); @@ -39,16 +41,20 @@ const useLibrary = (urlParams) => { core.dispatch({ action: 'Load', args: { - load: 'LibItemsByType', - args: urlParams.type + load: 'LibraryFiltered', + args: { + type_name: urlParams.type + } } }); - } else if (state.library.types.length > 0) { + } else if (state.library.type_names.length > 0) { core.dispatch({ action: 'Load', args: { - load: 'LibItemsByType', - args: state.library.types[0] + load: 'LibraryFiltered', + args: { + type_name: state.library.type_names[0] + } } }); } From 208e061f4f514b4772db4df2aef450c4f73d7e86 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sat, 23 Nov 2019 15:43:56 +0200 Subject: [PATCH 270/442] fix streams message --- src/routes/MetaDetails/StreamsList/styles.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/MetaDetails/StreamsList/styles.less b/src/routes/MetaDetails/StreamsList/styles.less index 3e6dbca78..f6cc71c59 100644 --- a/src/routes/MetaDetails/StreamsList/styles.less +++ b/src/routes/MetaDetails/StreamsList/styles.less @@ -10,7 +10,7 @@ align-self: stretch; overflow-y: auto; - .no-streams-label { + .message-label { padding: 2rem 0; font-size: 2rem; text-align: center; From 87f1516960dd8d148e79c4e3b1b965fbdc8ce482 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sat, 23 Nov 2019 15:46:42 +0200 Subject: [PATCH 271/442] useMetaDetails adapted to changes in core --- src/routes/MetaDetails/useMetaDetails.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/routes/MetaDetails/useMetaDetails.js b/src/routes/MetaDetails/useMetaDetails.js index f4d5c0e27..705fe8378 100644 --- a/src/routes/MetaDetails/useMetaDetails.js +++ b/src/routes/MetaDetails/useMetaDetails.js @@ -14,10 +14,7 @@ const useMetaDetails = (urlParams) => { React.useEffect(() => { const onNewModel = () => { const state = core.getState(); - const { meta_resource_ref = null, streams_resource_ref = null } = state.meta_details.selected !== null ? - state.meta_details.selected - : - {}; + const selected = state.meta_details.selected; const meta_groups = state.meta_details.meta_groups.map((meta_group) => { if (meta_group.content.type === 'Ready') { meta_group.content.content.released = new Date(meta_group.content.content.released); @@ -37,10 +34,7 @@ const useMetaDetails = (urlParams) => { }); const streams_groups = state.meta_details.streams_groups; setMetaDetails({ - selected: { - meta_resource_ref, - streams_resource_ref - }, + selected, meta_groups, streams_groups }); From 2e8909935e90219197fc769cfa99c2bd1b7c27dc Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 25 Nov 2019 12:04:20 +0200 Subject: [PATCH 272/442] library adapted to new stremio-core changes --- src/routes/Library/useLibrary.js | 6 +++--- src/routes/Library/useSort.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index ed58c8561..8642cf25a 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -8,7 +8,7 @@ const useLibrary = (urlParams) => { React.useEffect(() => { const onNewState = () => { const state = core.getState(); - if (state.library.selected === null && state.library.type_names.length > 0) { + if (state.library.selected.type_name === null && state.library.type_names.length > 0) { core.dispatch({ action: 'Load', args: { @@ -21,7 +21,7 @@ const useLibrary = (urlParams) => { return; } const selectInput = { - selected: [state.library.selected], + selected: [state.library.selected.type_name], options: state.library.type_names .map((type) => ({ label: type === '' ? '"Empty"' : type, @@ -33,7 +33,7 @@ const useLibrary = (urlParams) => { } }; const error = state.library.library_state.type !== 'Ready' ? state.library.library_state.type : null; - setLibrary([state.library.items, selectInput, error]); + setLibrary([state.library.lib_items, selectInput, error]); }; core.on('NewModel', onNewState); const state = core.getState(); diff --git a/src/routes/Library/useSort.js b/src/routes/Library/useSort.js index 8909afa7b..39b92acd8 100644 --- a/src/routes/Library/useSort.js +++ b/src/routes/Library/useSort.js @@ -26,7 +26,7 @@ const useSort = (urlParams, queryParams) => { onSelect: (event) => { const nextQuery = new URLSearchParams({ sort: event.value }); const state = core.getState(); - window.location.replace(`#/library/${state.library.selected !== null ? state.library.selected : ''}?${nextQuery}`); + window.location.replace(`#/library/${state.library.selected.type_name !== null ? state.library.selected.type_name : ''}?${nextQuery}`); } }; setSort([selectInput, sortItems]); From 98fa16c9c13e856b74d6121268efbc4bc0bf5eb3 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 25 Nov 2019 14:21:57 +0200 Subject: [PATCH 273/442] meta details state mapped in the initial state too --- src/routes/MetaDetails/useMetaDetails.js | 60 ++++++++++++------------ 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/src/routes/MetaDetails/useMetaDetails.js b/src/routes/MetaDetails/useMetaDetails.js index 705fe8378..88869c769 100644 --- a/src/routes/MetaDetails/useMetaDetails.js +++ b/src/routes/MetaDetails/useMetaDetails.js @@ -1,43 +1,41 @@ const React = require('react'); const { useServices } = require('stremio/services'); +const mapMetaDetailsState = (state) => { + const selected = state.meta_details.selected; + const meta_groups = state.meta_details.meta_groups.map((meta_group) => { + if (meta_group.content.type === 'Ready') { + meta_group.content.content.released = new Date(meta_group.content.content.released); + meta_group.content.content.videos = meta_group.content.content.videos.map((video) => { + video.released = new Date(video.released); + video.upcoming = !isNaN(video.released.getTime()) ? + video.released.getTime() > Date.now() + : + false; + video.href = `#/metadetails/${meta_group.content.content.type}/${meta_group.content.content.id}/${video.id}`; + // TODO add watched and progress + return video; + }); + } + + return meta_group; + }); + const streams_groups = state.meta_details.streams_groups; + return { selected, meta_groups, streams_groups }; +}; + const useMetaDetails = (urlParams) => { const { core } = useServices(); - const [metaDetails, setMetaDetails] = React.useState({ - selected: { - meta_resource_ref: null, - streams_resource_ref: null - }, - meta_groups: [], - streams_groups: [] + const [metaDetails, setMetaDetails] = React.useState(() => { + const state = core.getState(); + const metaDetails = mapMetaDetailsState(state); + return metaDetails; }); React.useEffect(() => { const onNewModel = () => { const state = core.getState(); - const selected = state.meta_details.selected; - const meta_groups = state.meta_details.meta_groups.map((meta_group) => { - if (meta_group.content.type === 'Ready') { - meta_group.content.content.released = new Date(meta_group.content.content.released); - meta_group.content.content.videos = meta_group.content.content.videos.map((video) => { - video.released = new Date(video.released); - video.upcoming = !isNaN(video.released.getTime()) ? - video.released.getTime() > Date.now() - : - false; - video.href = `#/metadetails/${meta_group.content.content.type}/${meta_group.content.content.id}/${video.id}`; - // TODO add watched and progress - return video; - }); - } - - return meta_group; - }); - const streams_groups = state.meta_details.streams_groups; - setMetaDetails({ - selected, - meta_groups, - streams_groups - }); + const metaDetails = mapMetaDetailsState(state); + setMetaDetails(metaDetails); }; core.on('NewModel', onNewModel); core.dispatch({ From 87f1f8b03c6a38efad68916eb83d8f21892eb5a7 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 25 Nov 2019 15:04:35 +0200 Subject: [PATCH 274/442] useLibrary now returns selected, type_names, lib_items --- src/routes/Library/Library.js | 48 +++++++++++++++++++++----------- src/routes/Library/useLibrary.js | 18 ++---------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 9ea48e5ff..abbb0b136 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -1,4 +1,5 @@ const React = require('react'); +const UrlUtils = require('url'); const classnames = require('classnames'); const { Button, Multiselect, MainNavBar, MetaItem } = require('stremio/common'); const useUser = require('stremio/common/useUser'); @@ -8,11 +9,25 @@ const styles = require('./styles'); const Library = ({ urlParams, queryParams }) => { const user = useUser(); - const [metaItems, selectTypeInput, error] = useLibrary(urlParams); + const [selectedType, typeNames, libItems] = useLibrary(urlParams); const [selectSortInput, sortFunction] = useSort(urlParams, queryParams); const loginButtonOnClick = React.useCallback(() => { window.location.replace('#/intro'); }, []); + const selectTypeInput = React.useMemo(() => { + return { + selected: [selectedType], + options: typeNames + .map((type) => ({ + label: type === '' ? '"Empty"' : type, + value: type + })), + onSelect: (event) => { + const { search } = UrlUtils.parse(window.location.hash.slice(1)); + window.location.replace(`#/library/${event.value}${search !== null ? search : ''}`); + } + } + }, [selectedType, typeNames]); return (
@@ -36,27 +51,26 @@ const Library = ({ urlParams, queryParams }) => {
: - error !== null ? -
- {error} -
- : - Array.isArray(metaItems) ? + selectedType !== null ? + libItems.length > 0 ?
- { - metaItems - .sort(sortFunction) - .map(({ removed, temp, ...metaItem }, index) => ( - - ))} + {libItems + .sort(sortFunction) + .map(({ removed, temp, ...libItem }, index) => ( + + ))}
:
- Loading + Empty library
+ : +
+ Loading +
}
diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 8642cf25a..be70a145a 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -1,10 +1,9 @@ const React = require('react'); -const UrlUtils = require('url'); const { useServices } = require('stremio/services'); const useLibrary = (urlParams) => { const { core } = useServices(); - const [library, setLibrary] = React.useState([[], null, null]); + const [library, setLibrary] = React.useState([null, [], []]); React.useEffect(() => { const onNewState = () => { const state = core.getState(); @@ -20,20 +19,7 @@ const useLibrary = (urlParams) => { }); return; } - const selectInput = { - selected: [state.library.selected.type_name], - options: state.library.type_names - .map((type) => ({ - label: type === '' ? '"Empty"' : type, - value: type - })), - onSelect: (event) => { - const { search } = UrlUtils.parse(window.location.hash.slice(1)); - window.location.replace(`#/library/${event.value}${search !== null ? search : ''}`); - } - }; - const error = state.library.library_state.type !== 'Ready' ? state.library.library_state.type : null; - setLibrary([state.library.lib_items, selectInput, error]); + setLibrary([state.library.selected.type_name, state.library.type_names, state.library.lib_items]); }; core.on('NewModel', onNewState); const state = core.getState(); From 26d9d38f891eac2238ea21bc05508c8725e2eb89 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 25 Nov 2019 15:53:52 +0200 Subject: [PATCH 275/442] lodash.isequal added to dependencies --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index d4f8b4c4b..184d7c8d0 100755 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "events": "1.1.1", "hat": "0.0.3", "lodash.debounce": "4.0.8", + "lodash.isequal": "4.5.0", "prop-types": "15.7.2", "react": "16.11.0", "react-dom": "16.11.0", diff --git a/yarn.lock b/yarn.lock index beaf7fe9d..96097aa20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5954,6 +5954,11 @@ lodash.debounce@4.0.8, lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= +lodash.isequal@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" From 209a150216b8713097adb2bcf451cbda246bda16 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 25 Nov 2019 15:57:12 +0200 Subject: [PATCH 276/442] auto select group only if user not selected already --- src/routes/MetaDetails/useSelectableGroups.js | 81 +++++++++++-------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/src/routes/MetaDetails/useSelectableGroups.js b/src/routes/MetaDetails/useSelectableGroups.js index 37a22c825..1248beb8c 100644 --- a/src/routes/MetaDetails/useSelectableGroups.js +++ b/src/routes/MetaDetails/useSelectableGroups.js @@ -1,44 +1,50 @@ const React = require('react'); +const isEqual = require('lodash.isequal'); + +const readyGroupForReq = (groups, req) => { + return groups.find((group) => { + return isEqual(group.req, req) && group.content.type === 'Ready'; + }); +}; const reducer = (state, action) => { switch (action.type) { case 'groups-changed': { - if (state.selectedGroup !== null) { - const selectedGroupIncluded = action.groups.some((group) => { - return group.req.base === state.selectedGroup.req.base && - group.content.type === 'Ready'; - }); - if (selectedGroupIncluded) { - return { - ...state, - resourceRef: action.resourceRef, - groups: action.groups - }; - } - } - - const readyGroup = action.groups.find((group) => group.content.type === 'Ready'); - const selectedGroup = readyGroup ? readyGroup : null; - return { - ...state, - resourceRef: action.resourceRef, - groups: action.groups, - selectedGroup - }; - } - case 'group-selected': { - const selectedGroup = state.groups.find((group) => { - return group.req.base === action.base && - group.content.type === 'Ready'; - }); - if (selectedGroup) { + if (state.selected.group === null || + !state.selected.byUser || + !readyGroupForReq(action.groups, state.selected.group.req)) { + const firstReadyGroup = action.groups.find((group) => group.content.type === 'Ready'); + const selectedGroup = firstReadyGroup ? firstReadyGroup : null; return { ...state, - selectedGroup + resourceRef: action.resourceRef, + groups: action.groups, + selected: { + group: selectedGroup, + byUser: false + } }; } - return state; + return { + ...state, + resourceRef: action.resourceRef, + groups: action.groups + }; + } + case 'group-selected': { + const selectedGroup = readyGroupForReq(state.groups, action.req); + if (!selectedGroup) { + return state; + } + + return { + ...state, + selected: { + group: selectedGroup, + byUser: true + } + }; } default: { return state; @@ -50,7 +56,10 @@ const initializer = ([resourceRef, groups]) => { const initialState = { resourceRef: null, groups: [], - selectedGroup: null + selected: { + group: null, + byUser: false + } }; const initAction = { type: 'groups-changed', @@ -67,6 +76,12 @@ const useSelectableGroups = (resourceRef, groups) => { [resourceRef, groups], initializer ); + const selectGroup = React.useCallback((req) => { + dispatch({ + type: 'group-selected', + req + }); + }, []); React.useEffect(() => { dispatch({ type: 'groups-changed', @@ -74,7 +89,7 @@ const useSelectableGroups = (resourceRef, groups) => { groups }); }, [groups]); - return [state.resourceRef, state.groups, state.selectedGroup]; + return [state.resourceRef, state.groups, state.selected.group, selectGroup]; }; module.exports = useSelectableGroups; From 343519b5282c631af5d912bb89da21c4de7b7a5c Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 26 Nov 2019 10:58:37 +0200 Subject: [PATCH 277/442] lib items state mapped in the initial state; useLibrary returns lib state --- src/routes/Library/useLibrary.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index be70a145a..48176d1bb 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -1,9 +1,20 @@ const React = require('react'); const { useServices } = require('stremio/services'); +const mapLibItemsState = (state) => { + const library_state = state.library.library_state.type; + const selected = state.library.selected.type_name; + const lib_items = state.library.lib_items.map((lib_item) => { + lib_item._ctime = new Date(lib_item._ctime); + return lib_item; + }); + const type_names = state.library.type_names; + return { library_state, selected, lib_items, type_names }; +}; + const useLibrary = (urlParams) => { const { core } = useServices(); - const [library, setLibrary] = React.useState([null, [], []]); + const [library, setLibrary] = React.useState([null, null, [], []]); React.useEffect(() => { const onNewState = () => { const state = core.getState(); @@ -19,7 +30,8 @@ const useLibrary = (urlParams) => { }); return; } - setLibrary([state.library.selected.type_name, state.library.type_names, state.library.lib_items]); + const libItems = mapLibItemsState(state); + setLibrary([libItems.library_state, libItems.selected, libItems.type_names, libItems.lib_items]); }; core.on('NewModel', onNewState); const state = core.getState(); From 42e8d7ddcd9d4e1b81a8a2db85eb8021d6ebc07a Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 26 Nov 2019 10:59:12 +0200 Subject: [PATCH 278/442] handle all state cases in library --- src/routes/Library/Library.js | 44 +++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index abbb0b136..f27f84f66 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -9,7 +9,7 @@ const styles = require('./styles'); const Library = ({ urlParams, queryParams }) => { const user = useUser(); - const [selectedType, typeNames, libItems] = useLibrary(urlParams); + const [libraryState, selectedType, typeNames, libItems] = useLibrary(urlParams); const [selectSortInput, sortFunction] = useSort(urlParams, queryParams); const loginButtonOnClick = React.useCallback(() => { window.location.replace('#/intro'); @@ -51,26 +51,36 @@ const Library = ({ urlParams, queryParams }) => {
: - selectedType !== null ? - libItems.length > 0 ? -
- {libItems - .sort(sortFunction) - .map(({ removed, temp, ...libItem }, index) => ( - - ))} -
+ libraryState != 'Ready' ? +
+ Loading +
+ : + typeNames.length > 0 ? + selectedType !== null ? + libItems.length > 0 ? +
+ {libItems + .sort(sortFunction) + .map(({ removed, temp, ...libItem }, index) => ( + + ))} +
+ : +
+ Empty library +
+ : +
+ Select a type, please +
:
Empty library
- : -
- Loading -
}
From c284092433b4ddb44ea34a5b824570ba2c7bca1c Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 26 Nov 2019 11:28:26 +0200 Subject: [PATCH 279/442] mapLibItemsState renamed; useLibrary returns the whole library object --- src/routes/Library/Library.js | 18 +++++++++--------- src/routes/Library/useLibrary.js | 16 ++++++++++------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index f27f84f66..2d77621e2 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -9,15 +9,15 @@ const styles = require('./styles'); const Library = ({ urlParams, queryParams }) => { const user = useUser(); - const [libraryState, selectedType, typeNames, libItems] = useLibrary(urlParams); + const library = useLibrary(urlParams); const [selectSortInput, sortFunction] = useSort(urlParams, queryParams); const loginButtonOnClick = React.useCallback(() => { window.location.replace('#/intro'); }, []); const selectTypeInput = React.useMemo(() => { return { - selected: [selectedType], - options: typeNames + selected: [library.selected.type_name], + options: library.type_names .map((type) => ({ label: type === '' ? '"Empty"' : type, value: type @@ -27,7 +27,7 @@ const Library = ({ urlParams, queryParams }) => { window.location.replace(`#/library/${event.value}${search !== null ? search : ''}`); } } - }, [selectedType, typeNames]); + }, [library.selected.type_name, library.type_names]); return (
@@ -51,16 +51,16 @@ const Library = ({ urlParams, queryParams }) => {
: - libraryState != 'Ready' ? + library.library_state.type != 'Ready' ?
Loading
: - typeNames.length > 0 ? - selectedType !== null ? - libItems.length > 0 ? + library.type_names.length > 0 ? + library.selected.type_name !== null ? + library.lib_items.length > 0 ?
- {libItems + {library.lib_items .sort(sortFunction) .map(({ removed, temp, ...libItem }, index) => ( { - const library_state = state.library.library_state.type; - const selected = state.library.selected.type_name; +const mapLibraryState = (state) => { + const library_state = state.library.library_state; + const selected = state.library.selected; const lib_items = state.library.lib_items.map((lib_item) => { lib_item._ctime = new Date(lib_item._ctime); return lib_item; @@ -14,7 +14,11 @@ const mapLibItemsState = (state) => { const useLibrary = (urlParams) => { const { core } = useServices(); - const [library, setLibrary] = React.useState([null, null, [], []]); + const [library, setLibrary] = React.useState(() => { + const state = core.getState(); + const library = mapLibraryState(state); + return library; + }); React.useEffect(() => { const onNewState = () => { const state = core.getState(); @@ -30,8 +34,8 @@ const useLibrary = (urlParams) => { }); return; } - const libItems = mapLibItemsState(state); - setLibrary([libItems.library_state, libItems.selected, libItems.type_names, libItems.lib_items]); + const library = mapLibraryState(state); + setLibrary(library); }; core.on('NewModel', onNewState); const state = core.getState(); From a49bc04d4cf24b41bf51de35780ad2dc6e4452af Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 26 Nov 2019 17:27:52 +0200 Subject: [PATCH 280/442] routesRegexpTests(intro, board) implemented --- package.json | 6 +- tests/routesRegexpTests.spec.js | 40 + yarn.lock | 1519 ++++++++++++++++++++++++++++++- 3 files changed, 1546 insertions(+), 19 deletions(-) create mode 100644 tests/routesRegexpTests.spec.js diff --git a/package.json b/package.json index d4f8b4c4b..e956cc054 100755 --- a/package.json +++ b/package.json @@ -7,9 +7,10 @@ "private": true, "license": "GPLv3", "scripts": { - "start": "webpack-dev-server --mode development", + "start": "webpack-dev-server --config ./webpack.config.js --mode development", "build": "webpack --mode production", - "storybook": "start-storybook --ci --config-dir ./storybook --static-dir ./ --port 6060" + "storybook": "start-storybook --ci --config-dir ./storybook --static-dir ./ --port 6060", + "test": "jest" }, "dependencies": { "a-color-picker": "1.2.1", @@ -45,6 +46,7 @@ "cssnano": "4.1.10", "cssnano-preset-advanced": "4.0.7", "html-webpack-plugin": "3.2.0", + "jest": "^24.9.0", "less": "3.10.3", "less-loader": "5.0.0", "mini-css-extract-plugin": "0.8.0", diff --git a/tests/routesRegexpTests.spec.js b/tests/routesRegexpTests.spec.js new file mode 100644 index 000000000..e9bb84050 --- /dev/null +++ b/tests/routesRegexpTests.spec.js @@ -0,0 +1,40 @@ +const routesRegexp = require('../src/common/routesRegexp'); + +const urlParamsMatch = (result, urlParams) => { + expect(Array.isArray(result)).toBe(true); + expect(result.length).toBe(urlParams.length); + urlParams.forEach((urlParam, index) => { + expect(result[index]).toBe(urlParam); + }); +}; + +describe('routes regex', () => { + describe('intro regexp', () => { + it('goes to /intro', async () => { + const result = '/intro'.match(routesRegexp.intro.regexp); + urlParamsMatch(result, ['/intro']); + }); + + it('goes to /intro/', async () => { + const result = '/intro/'.match(routesRegexp.intro.regexp); + urlParamsMatch(result, ['/intro/']); + }); + + it('goes to /intro/', async () => { + const result = '/intro/a'.match(routesRegexp.intro.regexp); + expect(result).toBe(null); + }); + }); + + describe('board regexp', () => { + it('goes to /', async () => { + const result = '/'.match(routesRegexp.board.regexp); + urlParamsMatch(result, ['/']); + }); + + it('goes to /', async () => { + const result = '/a'.match(routesRegexp.board.regexp); + expect(result).toBe(null); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index beaf7fe9d..2639a2927 100644 --- a/yarn.lock +++ b/yarn.lock @@ -49,6 +49,36 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.1.0": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.4.tgz#37e864532200cb6b50ee9a4045f5f817840166ab" + integrity sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.4" + "@babel/helpers" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + convert-source-map "^1.7.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.4.0", "@babel/generator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" + integrity sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg== + dependencies: + "@babel/types" "^7.7.4" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/generator@^7.6.0", "@babel/generator@^7.6.3", "@babel/generator@^7.6.4": version "7.6.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.4.tgz#a4f8437287bf9671b07f483b76e3bb731bc97671" @@ -129,6 +159,15 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-function-name@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e" + integrity sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ== + dependencies: + "@babel/helper-get-function-arity" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" + "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" @@ -136,6 +175,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-get-function-arity@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" + integrity sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA== + dependencies: + "@babel/types" "^7.7.4" + "@babel/helper-hoist-variables@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" @@ -224,6 +270,13 @@ dependencies: "@babel/types" "^7.4.4" +"@babel/helper-split-export-declaration@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8" + integrity sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug== + dependencies: + "@babel/types" "^7.7.4" + "@babel/helper-wrap-function@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" @@ -243,6 +296,15 @@ "@babel/traverse" "^7.6.2" "@babel/types" "^7.6.0" +"@babel/helpers@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302" + integrity sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg== + dependencies: + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + "@babel/highlight@^7.0.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" @@ -252,6 +314,11 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" + integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== + "@babel/parser@^7.6.0", "@babel/parser@^7.6.3", "@babel/parser@^7.6.4": version "7.6.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81" @@ -374,6 +441,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-object-rest-spread@^7.0.0": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz#47cf220d19d6d0d7b154304701f468fc1cc6ff46" + integrity sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" @@ -889,6 +963,15 @@ "@babel/parser" "^7.6.0" "@babel/types" "^7.6.0" +"@babel/template@^7.4.0", "@babel/template@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" + integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" + "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5", "@babel/traverse@^7.6.0", "@babel/traverse@^7.6.2", "@babel/traverse@^7.6.3": version "7.6.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.3.tgz#66d7dba146b086703c0fb10dd588b7364cec47f9" @@ -904,6 +987,21 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.4.3", "@babel/traverse@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" + integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0", "@babel/types@^7.6.3": version "7.6.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.3.tgz#3f07d96f854f98e2fbd45c64b0cb942d11e8ba09" @@ -913,11 +1011,28 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.4.0", "@babel/types@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" + integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@base2/pretty-print-object@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.0.tgz#860ce718b0b73f4009e153541faff2cb6b85d047" integrity sha512-4Th98KlMHr5+JkxfcoDT//6vY8vM+iSPrLNpHhRyLx2CFYi8e2RfqPLdpbnpo0Q5lQC5hNB79yes07zb02fvCw== +"@cnakazawa/watch@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef" + integrity sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + "@emotion/cache@^10.0.17": version "10.0.19" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.19.tgz#d258d94d9c707dcadaf1558def968b86bb87ad71" @@ -1020,6 +1135,154 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.4.tgz#622a72bebd1e3f48d921563b4b60a762295a81fc" integrity sha512-6PYY5DVdAY1ifaQW6XYTnOMihmBVT27elqSjEoodchsGjzYlEsTQMcEhSud99kVawatyTZRTiVkJ/c6lwbQ7nA== +"@jest/console@^24.7.1", "@jest/console@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" + integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== + dependencies: + "@jest/source-map" "^24.9.0" + chalk "^2.0.1" + slash "^2.0.0" + +"@jest/core@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" + integrity sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A== + dependencies: + "@jest/console" "^24.7.1" + "@jest/reporters" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + graceful-fs "^4.1.15" + jest-changed-files "^24.9.0" + jest-config "^24.9.0" + jest-haste-map "^24.9.0" + jest-message-util "^24.9.0" + jest-regex-util "^24.3.0" + jest-resolve "^24.9.0" + jest-resolve-dependencies "^24.9.0" + jest-runner "^24.9.0" + jest-runtime "^24.9.0" + jest-snapshot "^24.9.0" + jest-util "^24.9.0" + jest-validate "^24.9.0" + jest-watcher "^24.9.0" + micromatch "^3.1.10" + p-each-series "^1.0.0" + realpath-native "^1.1.0" + rimraf "^2.5.4" + slash "^2.0.0" + strip-ansi "^5.0.0" + +"@jest/environment@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" + integrity sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ== + dependencies: + "@jest/fake-timers" "^24.9.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" + jest-mock "^24.9.0" + +"@jest/fake-timers@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" + integrity sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A== + dependencies: + "@jest/types" "^24.9.0" + jest-message-util "^24.9.0" + jest-mock "^24.9.0" + +"@jest/reporters@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" + integrity sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw== + dependencies: + "@jest/environment" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + istanbul-lib-coverage "^2.0.2" + istanbul-lib-instrument "^3.0.1" + istanbul-lib-report "^2.0.4" + istanbul-lib-source-maps "^3.0.1" + istanbul-reports "^2.2.6" + jest-haste-map "^24.9.0" + jest-resolve "^24.9.0" + jest-runtime "^24.9.0" + jest-util "^24.9.0" + jest-worker "^24.6.0" + node-notifier "^5.4.2" + slash "^2.0.0" + source-map "^0.6.0" + string-length "^2.0.0" + +"@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" + integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.1.15" + source-map "^0.6.0" + +"@jest/test-result@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" + integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== + dependencies: + "@jest/console" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/istanbul-lib-coverage" "^2.0.0" + +"@jest/test-sequencer@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" + integrity sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A== + dependencies: + "@jest/test-result" "^24.9.0" + jest-haste-map "^24.9.0" + jest-runner "^24.9.0" + jest-runtime "^24.9.0" + +"@jest/transform@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56" + integrity sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^24.9.0" + babel-plugin-istanbul "^5.1.0" + chalk "^2.0.1" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.1.15" + jest-haste-map "^24.9.0" + jest-regex-util "^24.9.0" + jest-util "^24.9.0" + micromatch "^3.1.10" + pirates "^4.0.1" + realpath-native "^1.1.0" + slash "^2.0.0" + source-map "^0.6.1" + write-file-atomic "2.4.1" + +"@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -1476,6 +1739,39 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/babel__core@^7.1.0": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30" + integrity sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.0.tgz#f1ec1c104d1bb463556ecb724018ab788d0c172a" + integrity sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" + integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.0.8" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.8.tgz#479a4ee3e291a403a1096106013ec22cf9b64012" + integrity sha512-yGeB2dHEdvxjP0y4UbRtQaSkXJ9649fYCmIdRoul5kfAoGCwxuCbMhag0k3RPfnuh9kPGm8x89btcfDEXdVWGw== + dependencies: + "@babel/types" "^7.3.0" + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -1500,6 +1796,26 @@ resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.0.tgz#1b0b819b1636c7baf0d6785d030d12edf70c3e83" integrity sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w== +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" + integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== + +"@types/istanbul-lib-report@*": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#e5471e7fa33c61358dd38426189c037a58433b8c" + integrity sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" + integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -1555,6 +1871,11 @@ resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== +"@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" + integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== + "@types/tapable@*": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" @@ -1593,6 +1914,18 @@ "@types/webpack-sources" "*" source-map "^0.6.0" +"@types/yargs-parser@*": + version "13.1.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.1.0.tgz#c563aa192f39350a1d18da36c5a8da382bbd8228" + integrity sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg== + +"@types/yargs@^13.0.0": + version "13.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.3.tgz#76482af3981d4412d65371a318f992d33464a380" + integrity sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ== + dependencies: + "@types/yargs-parser" "*" + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -1756,6 +2089,11 @@ a-color-picker@1.2.1: dependencies: is-plain-object "^2.0.4" +abab@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" + integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1769,7 +2107,25 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn@^6.2.1: +acorn-globals@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" + integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== + dependencies: + acorn "^6.0.1" + acorn-walk "^6.0.1" + +acorn-walk@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" + integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== + +acorn@^5.5.3: + version "5.7.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" + integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + +acorn@^6.0.1, acorn@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== @@ -1847,7 +2203,7 @@ ansi-colors@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== -ansi-escapes@^3.2.0: +ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== @@ -1867,7 +2223,7 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= -ansi-regex@^4.1.0: +ansi-regex@^4.0.0, ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== @@ -1939,6 +2295,11 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -2046,6 +2407,11 @@ ast-types@0.12.4: resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.12.4.tgz#71ce6383800f24efc9a1a3308f3a6e420a0974d1" integrity sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw== +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + async-each@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" @@ -2140,6 +2506,19 @@ babel-helper-to-multiple-sequence-expressions@^0.5.0: resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d" integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA== +babel-jest@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" + integrity sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw== + dependencies: + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/babel__core" "^7.1.0" + babel-plugin-istanbul "^5.1.0" + babel-preset-jest "^24.9.0" + chalk "^2.4.2" + slash "^2.0.0" + babel-loader@8.0.6: version "8.0.6" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" @@ -2178,6 +2557,23 @@ babel-plugin-emotion@^10.0.14, babel-plugin-emotion@^10.0.17: find-root "^1.1.0" source-map "^0.5.7" +babel-plugin-istanbul@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854" + integrity sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + find-up "^3.0.0" + istanbul-lib-instrument "^3.3.0" + test-exclude "^5.2.3" + +babel-plugin-jest-hoist@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756" + integrity sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw== + dependencies: + "@types/babel__traverse" "^7.0.6" + babel-plugin-macros@2.6.1, babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.4.5: version "2.6.1" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.6.1.tgz#41f7ead616fc36f6a93180e89697f69f51671181" @@ -2346,6 +2742,14 @@ babel-plugin-transform-undefined-to-void@^6.9.4: resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280" integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA= +babel-preset-jest@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" + integrity sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg== + dependencies: + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + babel-plugin-jest-hoist "^24.9.0" + "babel-preset-minify@^0.5.0 || 0.6.0-alpha.5": version "0.5.1" resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz#25f5d0bce36ec818be80338d0e594106e21eaa9f" @@ -2546,6 +2950,18 @@ brorand@^1.0.1: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= +browser-process-hrtime@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz#616f00faef1df7ec1b5bf9cfe2bdc3170f26c7b4" + integrity sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw== + +browser-resolve@^1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== + dependencies: + resolve "1.1.7" + 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" @@ -2623,6 +3039,13 @@ browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.7.0, browserslist@^4.7 electron-to-chromium "^1.3.284" node-releases "^1.1.36" +bser@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -2766,6 +3189,11 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camel-case@3.0.x, camel-case@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" @@ -2799,6 +3227,13 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30000999: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001002.tgz#ba999a737b1abd5bf0fd47efe43a09b9cadbe9b0" integrity sha512-pRuxPE8wdrWmVPKcDmJJiGBxr6lFJq4ivdSeo9FTmGj5Rb8NX3Mby2pARG57MXF15hYAhZ0nHV5XxT2ig4bz3g== +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + case-sensitive-paths-webpack-plugin@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.2.0.tgz#3371ef6365ef9c25fa4b81c16ace0e9c7dc58c3e" @@ -2809,7 +3244,7 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2880,6 +3315,11 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2993,6 +3433,11 @@ clone@^2.1.1, clone@^2.1.2: resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + coa@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" @@ -3179,6 +3624,13 @@ convert-source-map@^1.1.0, convert-source-map@^1.5.0: dependencies: safe-buffer "~5.1.1" +convert-source-map@^1.4.0, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -3545,6 +3997,18 @@ csso@^3.5.1: dependencies: css-tree "1.0.0-alpha.29" +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" + integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== + dependencies: + cssom "0.3.x" + csstype@^2.2.0, csstype@^2.5.7: version "2.6.7" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.7.tgz#20b0024c20b6718f4eda3853a1f5a1cce7f5e4a5" @@ -3562,6 +4026,15 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-urls@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== + dependencies: + abab "^2.0.0" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" @@ -3615,6 +4088,11 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + deep-object-diff@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" @@ -3713,6 +4191,11 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= + detect-node@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" @@ -3734,6 +4217,11 @@ detect-port@^1.3.0: address "^1.0.1" debug "^2.6.0" +diff-sequences@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" + integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -3820,6 +4308,13 @@ domelementtype@^2.0.1: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== + dependencies: + webidl-conversions "^4.0.2" + domhandler@^2.3.0: version "2.4.2" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" @@ -4072,6 +4567,18 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escodegen@^1.9.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.12.0.tgz#f763daf840af172bb3a2b6dd7219c0e17f7ff541" + integrity sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg== + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -4080,6 +4587,11 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= + esprima@^4.0.0, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -4092,7 +4604,7 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -4137,6 +4649,11 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +exec-sh@^0.3.2: + version "0.3.4" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -4163,6 +4680,11 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -4183,6 +4705,18 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" +expect@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" + integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== + dependencies: + "@jest/types" "^24.9.0" + ansi-styles "^3.2.0" + jest-get-type "^24.9.0" + jest-matcher-utils "^24.9.0" + jest-message-util "^24.9.0" + jest-regex-util "^24.9.0" + express@^4.17.0, express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -4294,6 +4828,11 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + fault@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.3.tgz#4da88cf979b6b792b4e13c7ec836767725170b7e" @@ -4315,6 +4854,13 @@ faye-websocket@~0.11.1: dependencies: websocket-driver ">=0.5.1" +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= + dependencies: + bser "^2.0.0" + fbjs@^0.8.0: version "0.8.17" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" @@ -4690,6 +5236,18 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.1: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global-modules@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" @@ -4796,6 +5354,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + gud@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" @@ -4814,6 +5377,17 @@ handle-thing@^2.0.0: resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== +handlebars@^4.1.2: + version "4.5.3" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482" + integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA== + dependencies: + neo-async "^2.6.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -4961,6 +5535,11 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" +hosted-git-info@^2.1.4: + version "2.8.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" + integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== + hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" @@ -4986,6 +5565,13 @@ html-comment-regex@^1.1.0: resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== + dependencies: + whatwg-encoding "^1.0.1" + html-entities@^1.2.0, html-entities@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" @@ -5405,6 +5991,13 @@ is-callable@^1.1.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + is-color-stop@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" @@ -5506,6 +6099,11 @@ is-function@^1.0.1: resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU= +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -5681,7 +6279,390 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -jest-worker@^24.9.0: +istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" + integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== + +istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" + integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== + dependencies: + "@babel/generator" "^7.4.0" + "@babel/parser" "^7.4.3" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.3" + "@babel/types" "^7.4.0" + istanbul-lib-coverage "^2.0.5" + semver "^6.0.0" + +istanbul-lib-report@^2.0.4: + version "2.0.8" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" + integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== + dependencies: + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + supports-color "^6.1.0" + +istanbul-lib-source-maps@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" + integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + rimraf "^2.6.3" + source-map "^0.6.1" + +istanbul-reports@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af" + integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA== + dependencies: + handlebars "^4.1.2" + +jest-changed-files@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" + integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== + dependencies: + "@jest/types" "^24.9.0" + execa "^1.0.0" + throat "^4.0.0" + +jest-cli@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" + integrity sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg== + dependencies: + "@jest/core" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + chalk "^2.0.1" + exit "^0.1.2" + import-local "^2.0.0" + is-ci "^2.0.0" + jest-config "^24.9.0" + jest-util "^24.9.0" + jest-validate "^24.9.0" + prompts "^2.0.1" + realpath-native "^1.1.0" + yargs "^13.3.0" + +jest-config@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" + integrity sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^24.9.0" + "@jest/types" "^24.9.0" + babel-jest "^24.9.0" + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^24.9.0" + jest-environment-node "^24.9.0" + jest-get-type "^24.9.0" + jest-jasmine2 "^24.9.0" + jest-regex-util "^24.3.0" + jest-resolve "^24.9.0" + jest-util "^24.9.0" + jest-validate "^24.9.0" + micromatch "^3.1.10" + pretty-format "^24.9.0" + realpath-native "^1.1.0" + +jest-diff@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" + integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== + dependencies: + chalk "^2.0.1" + diff-sequences "^24.9.0" + jest-get-type "^24.9.0" + pretty-format "^24.9.0" + +jest-docblock@^24.3.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" + integrity sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA== + dependencies: + detect-newline "^2.1.0" + +jest-each@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" + integrity sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog== + dependencies: + "@jest/types" "^24.9.0" + chalk "^2.0.1" + jest-get-type "^24.9.0" + jest-util "^24.9.0" + pretty-format "^24.9.0" + +jest-environment-jsdom@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" + integrity sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA== + dependencies: + "@jest/environment" "^24.9.0" + "@jest/fake-timers" "^24.9.0" + "@jest/types" "^24.9.0" + jest-mock "^24.9.0" + jest-util "^24.9.0" + jsdom "^11.5.1" + +jest-environment-node@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" + integrity sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA== + dependencies: + "@jest/environment" "^24.9.0" + "@jest/fake-timers" "^24.9.0" + "@jest/types" "^24.9.0" + jest-mock "^24.9.0" + jest-util "^24.9.0" + +jest-get-type@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" + integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== + +jest-haste-map@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" + integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== + dependencies: + "@jest/types" "^24.9.0" + anymatch "^2.0.0" + fb-watchman "^2.0.0" + graceful-fs "^4.1.15" + invariant "^2.2.4" + jest-serializer "^24.9.0" + jest-util "^24.9.0" + jest-worker "^24.9.0" + micromatch "^3.1.10" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^1.2.7" + +jest-jasmine2@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" + integrity sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + chalk "^2.0.1" + co "^4.6.0" + expect "^24.9.0" + is-generator-fn "^2.0.0" + jest-each "^24.9.0" + jest-matcher-utils "^24.9.0" + jest-message-util "^24.9.0" + jest-runtime "^24.9.0" + jest-snapshot "^24.9.0" + jest-util "^24.9.0" + pretty-format "^24.9.0" + throat "^4.0.0" + +jest-leak-detector@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" + integrity sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA== + dependencies: + jest-get-type "^24.9.0" + pretty-format "^24.9.0" + +jest-matcher-utils@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" + integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== + dependencies: + chalk "^2.0.1" + jest-diff "^24.9.0" + jest-get-type "^24.9.0" + pretty-format "^24.9.0" + +jest-message-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" + integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/stack-utils" "^1.0.1" + chalk "^2.0.1" + micromatch "^3.1.10" + slash "^2.0.0" + stack-utils "^1.0.1" + +jest-mock@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" + integrity sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w== + dependencies: + "@jest/types" "^24.9.0" + +jest-pnp-resolver@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" + integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== + +jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" + integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== + +jest-resolve-dependencies@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" + integrity sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g== + dependencies: + "@jest/types" "^24.9.0" + jest-regex-util "^24.3.0" + jest-snapshot "^24.9.0" + +jest-resolve@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" + integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== + dependencies: + "@jest/types" "^24.9.0" + browser-resolve "^1.11.3" + chalk "^2.0.1" + jest-pnp-resolver "^1.2.1" + realpath-native "^1.1.0" + +jest-runner@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" + integrity sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg== + dependencies: + "@jest/console" "^24.7.1" + "@jest/environment" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + chalk "^2.4.2" + exit "^0.1.2" + graceful-fs "^4.1.15" + jest-config "^24.9.0" + jest-docblock "^24.3.0" + jest-haste-map "^24.9.0" + jest-jasmine2 "^24.9.0" + jest-leak-detector "^24.9.0" + jest-message-util "^24.9.0" + jest-resolve "^24.9.0" + jest-runtime "^24.9.0" + jest-util "^24.9.0" + jest-worker "^24.6.0" + source-map-support "^0.5.6" + throat "^4.0.0" + +jest-runtime@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" + integrity sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw== + dependencies: + "@jest/console" "^24.7.1" + "@jest/environment" "^24.9.0" + "@jest/source-map" "^24.3.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/yargs" "^13.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.1.15" + jest-config "^24.9.0" + jest-haste-map "^24.9.0" + jest-message-util "^24.9.0" + jest-mock "^24.9.0" + jest-regex-util "^24.3.0" + jest-resolve "^24.9.0" + jest-snapshot "^24.9.0" + jest-util "^24.9.0" + jest-validate "^24.9.0" + realpath-native "^1.1.0" + slash "^2.0.0" + strip-bom "^3.0.0" + yargs "^13.3.0" + +jest-serializer@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" + integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== + +jest-snapshot@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" + integrity sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^24.9.0" + chalk "^2.0.1" + expect "^24.9.0" + jest-diff "^24.9.0" + jest-get-type "^24.9.0" + jest-matcher-utils "^24.9.0" + jest-message-util "^24.9.0" + jest-resolve "^24.9.0" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^24.9.0" + semver "^6.2.0" + +jest-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" + integrity sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg== + dependencies: + "@jest/console" "^24.9.0" + "@jest/fake-timers" "^24.9.0" + "@jest/source-map" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + callsites "^3.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.15" + is-ci "^2.0.0" + mkdirp "^0.5.1" + slash "^2.0.0" + source-map "^0.6.0" + +jest-validate@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" + integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== + dependencies: + "@jest/types" "^24.9.0" + camelcase "^5.3.1" + chalk "^2.0.1" + jest-get-type "^24.9.0" + leven "^3.1.0" + pretty-format "^24.9.0" + +jest-watcher@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" + integrity sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw== + dependencies: + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/yargs" "^13.0.0" + ansi-escapes "^3.0.0" + chalk "^2.0.1" + jest-util "^24.9.0" + string-length "^2.0.0" + +jest-worker@^24.6.0, jest-worker@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== @@ -5689,6 +6670,14 @@ jest-worker@^24.9.0: merge-stream "^2.0.0" supports-color "^6.1.0" +jest@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" + integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw== + dependencies: + import-local "^2.0.0" + jest-cli "^24.9.0" + js-beautify@^1.8.8: version "1.10.2" resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.2.tgz#88c9099cd6559402b124cfab18754936f8a7b178" @@ -5728,6 +6717,38 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= +jsdom@^11.5.1: + version "11.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" + integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== + dependencies: + abab "^2.0.0" + acorn "^5.5.3" + acorn-globals "^4.1.0" + array-equal "^1.0.0" + cssom ">= 0.3.2 < 0.4.0" + cssstyle "^1.0.0" + data-urls "^1.0.0" + domexception "^1.0.1" + escodegen "^1.9.1" + html-encoding-sniffer "^1.0.2" + left-pad "^1.3.0" + nwsapi "^2.0.7" + parse5 "4.0.0" + pn "^1.1.0" + request "^2.87.0" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" + tough-cookie "^2.3.4" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.3" + whatwg-mimetype "^2.1.0" + whatwg-url "^6.4.1" + ws "^5.2.0" + xml-name-validator "^3.0.0" + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -5849,6 +6870,11 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + lazy-cache@^0.2.3: version "0.2.7" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" @@ -5877,6 +6903,11 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" +left-pad@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== + less-loader@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-5.0.0.tgz#498dde3a6c6c4f887458ee9ed3f086a12ad1b466" @@ -5902,6 +6933,29 @@ less@3.10.3: request "^2.83.0" source-map "~0.6.0" +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" @@ -5959,6 +7013,11 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" @@ -6014,7 +7073,7 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -make-dir@^2.0.0: +make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -6029,6 +7088,13 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + mamacro@^0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" @@ -6269,11 +7335,16 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + minipass-collect@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" @@ -6423,6 +7494,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + needle@^2.2.1: version "2.4.0" resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" @@ -6437,7 +7513,7 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.5.0, neo-async@^2.6.1: +neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== @@ -6479,6 +7555,11 @@ node-forge@0.9.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -6508,6 +7589,22 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-notifier@^5.4.2: + version "5.4.3" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50" + integrity sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q== + dependencies: + growly "^1.3.0" + is-wsl "^1.1.0" + semver "^5.5.0" + shellwords "^0.1.1" + which "^1.3.0" + node-pre-gyp@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" @@ -6539,6 +7636,16 @@ nopt@^4.0.1, nopt@~4.0.1: abbrev "1" osenv "^0.1.4" +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -6618,6 +7725,11 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= +nwsapi@^2.0.7: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -6759,6 +7871,26 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" @@ -6803,6 +7935,13 @@ p-defer@^1.0.0: resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= +p-each-series@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" + integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= + dependencies: + p-reduce "^1.0.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -6860,6 +7999,11 @@ p-map@^3.0.0: dependencies: aggregate-error "^3.0.0" +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= + p-retry@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" @@ -6935,6 +8079,11 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -7040,6 +8189,13 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -7061,6 +8217,11 @@ pkg-up@2.0.0: dependencies: find-up "^2.1.0" +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== + pnp-webpack-plugin@1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.4.3.tgz#0a100b63f4a1d09cee6ee55a87393b69f03ab5c7" @@ -7482,6 +8643,11 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.1 source-map "^0.6.1" supports-color "^6.1.0" +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + prepend-http@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -7495,6 +8661,16 @@ pretty-error@^2.0.2, pretty-error@^2.1.1: renderkid "^2.0.1" utila "~0.4" +pretty-format@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + pretty-hrtime@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -7552,6 +8728,14 @@ promise@^7.1.1: dependencies: asap "~2.0.3" +prompts@^2.0.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.0.tgz#a444e968fa4cc7e86689a74050685ac8006c4cc4" + integrity sha512-NfbbPPg/74fT7wk2XYQ7hAIp9zJyZp5Fu19iRbORqqy1BhtrkZ0fPafBU+7bmn8ie69DpT0R6QpJIN2oisYjJg== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.3" + prop-types@15.7.2, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" @@ -7591,7 +8775,7 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= -psl@^1.1.24: +psl@^1.1.24, psl@^1.1.28: version "1.4.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== @@ -7643,7 +8827,7 @@ punycode@^1.2.4, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -7885,6 +9069,11 @@ react-is@^16.7.0, react-is@^16.8.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa" integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw== +react-is@^16.8.4: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" + integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -7948,6 +9137,23 @@ react@16.11.0, react@^16.8.3: object-assign "^4.1.1" prop-types "^15.6.2" +read-pkg-up@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" + integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== + dependencies: + find-up "^3.0.0" + read-pkg "^3.0.0" + +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" @@ -7979,6 +9185,13 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" +realpath-native@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" + integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== + dependencies: + util.promisify "^1.0.0" + recast@^0.14.7: version "0.14.7" resolved "https://registry.yarnpkg.com/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d" @@ -8126,7 +9339,23 @@ repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -request@^2.83.0: +request-promise-core@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" + integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== + dependencies: + lodash "^4.17.15" + +request-promise-native@^1.0.5: + version "1.0.8" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" + integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== + dependencies: + request-promise-core "1.1.3" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +request@^2.83.0, request@^2.87.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== @@ -8207,6 +9436,11 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= + resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.3.2, resolve@^1.8.1: version "1.12.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" @@ -8257,6 +9491,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -8305,6 +9544,21 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + sax@^1.2.4, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -8352,12 +9606,12 @@ selfsigned@^1.10.7: dependencies: node-forge "0.9.0" -semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -8509,6 +9763,11 @@ shelljs@^0.8.3: interpret "^1.0.0" rechoir "^0.6.2" +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + sigmund@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" @@ -8546,11 +9805,21 @@ simplebar@^4.2.3: lodash.throttle "^4.1.1" resize-observer-polyfill "^1.5.1" +sisteransi@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.4.tgz#386713f1ef688c7c0304dc4c0632898941cad2e3" + integrity sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig== + slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -8624,6 +9893,14 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" +source-map-support@^0.5.6: + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@~0.5.12: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -8656,6 +9933,32 @@ space-separated-tokens@^1.0.0: version "1.2.0" resolved "git+ssh://git@github.com/NikolaBorislavovHristov/spatial-navigation.git#964d09bf2b0853e27af6c25924b595d6621a019d" +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + spdy-transport@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" @@ -8726,6 +10029,11 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +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== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -8739,6 +10047,11 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + store2@^2.7.1: version "2.10.0" resolved "https://registry.yarnpkg.com/store2/-/store2-2.10.0.tgz#46b82bb91878daf1b0d56dec2f1d41e54d5103cf" @@ -8803,6 +10116,14 @@ strict-uri-encode@^1.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -8909,6 +10230,11 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -8979,6 +10305,11 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-tree@^3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + symbol.prototype.description@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/symbol.prototype.description/-/symbol.prototype.description-1.0.1.tgz#e44e5db04d977932d1a261570bf65312773406d0" @@ -9064,11 +10395,26 @@ terser@^4.1.2, terser@^4.3.9: source-map "~0.6.1" source-map-support "~0.5.12" +test-exclude@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" + integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== + dependencies: + glob "^7.1.3" + minimatch "^3.0.4" + read-pkg-up "^4.0.0" + require-main-filename "^2.0.0" + text-table@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= + throttle-debounce@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.1.0.tgz#257e648f0a56bd9e54fe0f132c4ab8611df4e1d5" @@ -9116,6 +10462,11 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -9166,6 +10517,14 @@ toposort@^1.0.0: resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk= +tough-cookie@^2.3.3, tough-cookie@^2.3.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -9174,6 +10533,13 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + ts-pnp@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.4.tgz#ae27126960ebaefb874c6d7fa4729729ab200d90" @@ -9201,6 +10567,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + type-fest@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" @@ -9237,6 +10610,14 @@ uglify-js@3.4.x: commander "~2.19.0" source-map "~0.6.1" +uglify-js@^3.1.4: + version "3.7.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.0.tgz#14b854003386b7a7c045910f43afbc96d2aa5307" + integrity sha512-PC/ee458NEMITe1OufAjal65i6lB58R1HWMRcxwvdz1UopW0DYqlRL3xdu3IcTvTXsB02CRHykidkTRL+A3hQA== + dependencies: + commander "~2.20.3" + source-map "~0.6.1" + uglify-js@^3.5.1: version "3.6.3" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.3.tgz#1351533bbe22cc698f012589ed6bd4cbd971bff8" @@ -9400,7 +10781,7 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util.promisify@1.0.0, util.promisify@~1.0.0: +util.promisify@1.0.0, util.promisify@^1.0.0, util.promisify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== @@ -9442,6 +10823,14 @@ v8-compile-cache@2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -9471,6 +10860,20 @@ vtt.js@0.13.0: resolved "https://registry.yarnpkg.com/vtt.js/-/vtt.js-0.13.0.tgz#955c667b34d5325b2012cb9e8ba9bad6e0b11ff8" integrity sha1-lVxmezTVMlsgEsuei6m61uCxH/g= +w3c-hr-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" + integrity sha1-gqwr/2PZUOqeMYmlimViX+3xkEU= + dependencies: + browser-process-hrtime "^0.1.2" + +walker@^1.0.7, walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + warning@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" @@ -9501,6 +10904,11 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + webpack-cli@3.3.9: version "3.3.9" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.9.tgz#79c27e71f94b7fe324d594ab64a8e396b9daa91a" @@ -9637,17 +11045,47 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + whatwg-fetch@>=0.10.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== +whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@^1.2.14, which@^1.2.9, which@^1.3.1: +which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -9668,6 +11106,16 @@ widest-line@^2.0.0: dependencies: string-width "^2.1.1" +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + worker-farm@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" @@ -9704,6 +11152,22 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-file-atomic@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" + integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + ws@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" @@ -9711,6 +11175,11 @@ ws@^6.2.1: dependencies: async-limiter "~1.0.0" +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -9744,7 +11213,7 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^13.1.0: +yargs-parser@^13.1.0, yargs-parser@^13.1.1: version "13.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== @@ -9786,3 +11255,19 @@ yargs@13.2.4: which-module "^2.0.0" y18n "^4.0.0" yargs-parser "^13.1.0" + +yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.1" From 2fbbe42d63f5fd74260b5230261b7f25ecfba32d Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Wed, 27 Nov 2019 10:02:24 +0200 Subject: [PATCH 281/442] config argument removed --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e956cc054..3595590c1 100755 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "private": true, "license": "GPLv3", "scripts": { - "start": "webpack-dev-server --config ./webpack.config.js --mode development", + "start": "webpack-dev-server --mode development", "build": "webpack --mode production", "storybook": "start-storybook --ci --config-dir ./storybook --static-dir ./ --port 6060", "test": "jest" @@ -46,7 +46,7 @@ "cssnano": "4.1.10", "cssnano-preset-advanced": "4.0.7", "html-webpack-plugin": "3.2.0", - "jest": "^24.9.0", + "jest": "24.9.0", "less": "3.10.3", "less-loader": "5.0.0", "mini-css-extract-plugin": "0.8.0", From 60d49536f87480c60f6e7b768452d3c0a9331f02 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Wed, 27 Nov 2019 13:32:57 +0200 Subject: [PATCH 282/442] dataset attribute instead of data-name used for Multiselect/ColorInput --- src/routes/Settings/SectionsList/SectionsList.js | 8 ++++---- src/routes/Settings/Settings.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/routes/Settings/SectionsList/SectionsList.js b/src/routes/Settings/SectionsList/SectionsList.js index d56de298a..8ff5fe581 100644 --- a/src/routes/Settings/SectionsList/SectionsList.js +++ b/src/routes/Settings/SectionsList/SectionsList.js @@ -165,11 +165,11 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre
Caching
- +
Torrent Profile
- +
} @@ -193,7 +193,7 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre return (
{input.header ?
{input.header}
: null} - +
); } else if (input.type === 'link') { @@ -238,7 +238,7 @@ const SectionsList = React.forwardRef(({ className, sections, preferences, onPre return (
{input.header ?
{input.header}
: null} - +
); } else if (input.type === 'info') { diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 90d3a725d..a8d216b20 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -10,7 +10,7 @@ const Settings = () => { const [preferences, setPreferences] = useSettings(); const [dynamicSections, setDynamicSections] = React.useState(settingsSections); // TODO: The Streaming section should be handled separately - const sections = React.useMemo(()=>Object.keys(dynamicSections) + const sections = React.useMemo(() => Object.keys(dynamicSections) .map((section) => ({ id: section, inputs: dynamicSections[section], @@ -39,7 +39,7 @@ const Settings = () => { if (scrollContainer.scrollTop + scrollContainer.clientHeight === scrollContainer.scrollHeight) { setSelectedSectionId(sections[sections.length - 1].id); } else { - for (let i = sections.length - 1;i >= 0;i--) { + for (let i = sections.length - 1; i >= 0; i--) { if (sections[i].ref.current.offsetTop <= scrollContainer.scrollTop) { setSelectedSectionId(sections[i].id); break; From 34cf2280a4542caabd2b6846ace843de8c48e1ab Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 28 Nov 2019 11:51:47 +0200 Subject: [PATCH 283/442] search linked with stremio-core --- src/routes/Search/Search.js | 39 +++++++++++++---- src/routes/Search/styles.less | 78 ++++++++++++++++++++++++++++++++-- src/routes/Search/useSearch.js | 55 ++++++++++++------------ 3 files changed, 133 insertions(+), 39 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index b97096a5b..ff5a32dd6 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -4,18 +4,41 @@ const useSearch = require('./useSearch'); const styles = require('./styles'); const Search = ({ queryParams }) => { - const groups = useSearch(queryParams.get('q')); + const groups = useSearch(queryParams); return (
- {groups.map((group, index) => ( - - ))} + {groups.map(({ req, content }, index) => { + switch (content.type) { + case 'Ready': + return ( + + ); + case 'Err': + return ( + + ); + case 'Loading': + return ( + + ); + } + })}
); diff --git a/src/routes/Search/styles.less b/src/routes/Search/styles.less index 40e01a4d2..338672b2e 100644 --- a/src/routes/Search/styles.less +++ b/src/routes/Search/styles.less @@ -1,7 +1,13 @@ +@import (reference) '~stremio/common/screen-sizes.less'; + :import('~stremio/common/MetaRow/styles.less') { meta-item: meta-item; } +:import('~stremio/common/MetaRow/MetaRowPlaceholder/styles.less') { + meta-item-placeholder: meta-item; +} + .search-container { display: flex; flex-direction: column; @@ -19,7 +25,7 @@ align-self: stretch; overflow-y: auto; - .search-row { + .search-row, .search-row-placeholder { margin: 4rem 2rem; &:first-child { @@ -29,10 +35,74 @@ &:last-child { margin-bottom: 2rem; } + } + } +} - .meta-item { - &:nth-child(n+6) { - display: none; +@media only screen and (min-width: @large) { + .board-container { + .board-content { + .board-row, .board-row-placeholder { + .meta-item, .meta-item-placeholder { + &:nth-child(n+9) { + display: none; + } + } + } + } + } +} + +@media only screen and (max-width: @large) { + .search-container { + .search-content { + .search-row, .search-row-placeholder { + .meta-item, .meta-item-placeholder { + &:nth-child(n+8) { + display: none; + } + } + } + } + } +} + +@media only screen and (max-width: @medium) { + .search-container { + .search-content { + .search-row, .search-row-placeholder { + .meta-item, .meta-item-placeholder { + &:nth-child(n+7) { + display: none; + } + } + } + } + } +} + +@media only screen and (max-width: @small) { + .search-container { + .search-content { + .search-row, .search-row-placeholder { + .meta-item, .meta-item-placeholder { + &:nth-child(n+6) { + display: none; + } + } + } + } + } +} + +@media only screen and (max-width: @xsmall) { + .search-container { + .search-content { + .search-row, .search-row-placeholder { + .meta-item, .meta-item-placeholder { + &:nth-child(n+5) { + display: none; + } } } } diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 68289c202..7cac22bf3 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -1,32 +1,33 @@ const React = require('react'); +const { useServices } = require('stremio/services'); -const useSearch = (query) => { - const items = React.useMemo(() => { - return [ - { - title: 'demo addon', - items: [ - { - id: '1', - type: 'movie', - name: 'Stremio demo item movie 1', - poster: '/images/intro_background.jpg', - logo: '/images/default_avatar.png', - posterShape: 'poster' - }, - { - id: '2', - type: 'movie', - name: 'Stremio demo item movie 2', - poster: '/images/intro_background.jpg', - logo: '/images/default_avatar.png', - posterShape: 'poster' - }, - ] - } - ]; - }, [query]); - return items; +const useSearch = (queryParams) => { + const { core } = useServices(); + const [search, setSearch] = React.useState([]); + React.useEffect(() => { + const onNewState = () => { + const state = core.getState(); + setSearch(state.search.groups); + }; + core.on('NewModel', onNewState); + if (queryParams.has('q')) { + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogGrouped', + args: { + extra: [ + ['search', queryParams.get('q')] + ] + } + } + }); + } + return () => { + core.off('NewModel', onNewState); + }; + }, [queryParams]); + return search; }; module.exports = useSearch; From 609772a9326e7ec8b37a504cdbb55d5875242daa Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 28 Nov 2019 14:50:46 +0200 Subject: [PATCH 284/442] search adapted to stremio-core changes --- src/routes/Search/Search.js | 14 +++++++------- src/routes/Search/useSearch.js | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index ff5a32dd6..45696f8d4 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -9,32 +9,32 @@ const Search = ({ queryParams }) => {
- {groups.map(({ req, content }, index) => { + {groups.map(({ request, content }, index) => { switch (content.type) { case 'Ready': return ( ); case 'Err': return ( ); case 'Loading': return ( ); } diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 7cac22bf3..5271ec2b6 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -7,14 +7,14 @@ const useSearch = (queryParams) => { React.useEffect(() => { const onNewState = () => { const state = core.getState(); - setSearch(state.search.groups); + setSearch(state.search.items_groups); }; core.on('NewModel', onNewState); if (queryParams.has('q')) { core.dispatch({ action: 'Load', args: { - load: 'CatalogGrouped', + load: 'CatalogsGrouped', args: { extra: [ ['search', queryParams.get('q')] From eb9bbeab0b4e04757496b14db58330ce4985cab3 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 28 Nov 2019 17:06:13 +0200 Subject: [PATCH 285/442] board adapted to stremio-core changes --- src/routes/Board/Board.js | 14 +++++++------- src/routes/Board/useCatalogs.js | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index 1b626f6ca..980b47f11 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -20,32 +20,32 @@ const Board = () => {
- {catalogs.map(({ req, content }, index) => { + {catalogs.map(({ request, content }, index) => { switch (content.type) { case 'Ready': return ( ); case 'Message': return ( ); case 'Loading': return ( ); } diff --git a/src/routes/Board/useCatalogs.js b/src/routes/Board/useCatalogs.js index d2470ff9e..ce865f2d5 100644 --- a/src/routes/Board/useCatalogs.js +++ b/src/routes/Board/useCatalogs.js @@ -7,13 +7,13 @@ const useCatalogs = () => { React.useEffect(() => { const onNewState = () => { const state = core.getState(); - setCatalogs(state.board.groups); + setCatalogs(state.board.items_groups); }; core.on('NewModel', onNewState); core.dispatch({ action: 'Load', args: { - load: 'CatalogGrouped', + load: 'CatalogsGrouped', args: { extra: [] } } }); From 8500b40378018ca162f76da3b344b23859aae8f2 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 28 Nov 2019 17:21:28 +0200 Subject: [PATCH 286/442] search: 'no query/groups' cases added --- src/routes/Search/Search.js | 75 +++++++++++++++++++++-------------- src/routes/Search/styles.less | 37 +++++++++++++++++ 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index 45696f8d4..8dcc6b69b 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -1,4 +1,5 @@ const React = require('react'); +const Icon = require('stremio-icons/dom'); const { MainNavBar, MetaRow } = require('stremio/common'); const useSearch = require('./useSearch'); const styles = require('./styles'); @@ -9,36 +10,50 @@ const Search = ({ queryParams }) => {
- {groups.map(({ request, content }, index) => { - switch (content.type) { - case 'Ready': - return ( - - ); - case 'Err': - return ( - - ); - case 'Loading': - return ( - - ); - } - })} + { + !queryParams.has('q') || queryParams.get('q').length === 0 || groups.length === 0 ? +
+
+ +
Search for movies, series, YouTube and TV channels
+
+
+ +
Search for actors, directors and writers
+
+
+ : + groups.map(({ request, content }, index) => { + switch (content.type) { + case 'Ready': + return ( + + ); + case 'Err': + return ( + + ); + case 'Loading': + return ( + + ); + } + }) + }
); diff --git a/src/routes/Search/styles.less b/src/routes/Search/styles.less index 338672b2e..c5f3308a9 100644 --- a/src/routes/Search/styles.less +++ b/src/routes/Search/styles.less @@ -36,6 +36,43 @@ margin-bottom: 2rem; } } + + .message-container { + display: flex; + flex-direction: row; + align-items: flex-start; + justify-content: center; + margin: 5rem; + + .message-content { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .icon { + flex: none; + width: 6rem; + height: 6rem; + margin-bottom: 2rem; + fill: var(--color-surfacelighter40); + } + + .label { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + font-size: 1.2rem; + color: var(--color-surfacelighter40); + text-align: center; + } + + &:not(:last-child) { + margin-right: 5rem;; + } + } + } } } From 921a23b5cda71756ee22833e142628720f253f79 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 29 Nov 2019 13:31:02 +0200 Subject: [PATCH 287/442] useSearch now returns the whole search object; --- src/routes/Search/useSearch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 5271ec2b6..9f26678f9 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -7,7 +7,7 @@ const useSearch = (queryParams) => { React.useEffect(() => { const onNewState = () => { const state = core.getState(); - setSearch(state.search.items_groups); + setSearch(state.search); }; core.on('NewModel', onNewState); if (queryParams.has('q')) { From e8faa09b13dc6d0a75e507e0709293cb1996b676 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 29 Nov 2019 13:31:20 +0200 Subject: [PATCH 288/442] no metadata case added --- src/routes/Search/Search.js | 71 ++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index 8dcc6b69b..f68eeacfe 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -5,13 +5,13 @@ const useSearch = require('./useSearch'); const styles = require('./styles'); const Search = ({ queryParams }) => { - const groups = useSearch(queryParams); + const search = useSearch(queryParams); return (
{ - !queryParams.has('q') || queryParams.get('q').length === 0 || groups.length === 0 ? + !queryParams.has('q') || queryParams.get('q').length === 0 ?
@@ -23,36 +23,43 @@ const Search = ({ queryParams }) => {
: - groups.map(({ request, content }, index) => { - switch (content.type) { - case 'Ready': - return ( - - ); - case 'Err': - return ( - - ); - case 'Loading': - return ( - - ); - } - }) + search.items_groups && search.items_groups.length > 0 && search.items_groups.some(group => group.content.type !== 'Err') ? + search.items_groups.map(({ request, content }, index) => { + switch (content.type) { + case 'Ready': + return ( + + ); + case 'Err': + return ( + + ); + case 'Loading': + return ( + + ); + } + }) + : +
+
+
No metadata was found
+
+
}
From 665e3500c4b8a65a7d8ad1e0e3307d707dce6854 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 29 Nov 2019 13:55:19 +0200 Subject: [PATCH 289/442] use search.selected instead of queryParams --- src/routes/Search/Search.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index f68eeacfe..d38df9347 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -11,18 +11,7 @@ const Search = ({ queryParams }) => {
{ - !queryParams.has('q') || queryParams.get('q').length === 0 ? -
-
- -
Search for movies, series, YouTube and TV channels
-
-
- -
Search for actors, directors and writers
-
-
- : + search.selected && search.selected[0][1].length > 0 ? search.items_groups && search.items_groups.length > 0 && search.items_groups.some(group => group.content.type !== 'Err') ? search.items_groups.map(({ request, content }, index) => { switch (content.type) { @@ -60,6 +49,17 @@ const Search = ({ queryParams }) => {
No metadata was found
+ : +
+
+ +
Search for movies, series, YouTube and TV channels
+
+
+ +
Search for actors, directors and writers
+
+
}
From 07cabd2700cf3a65f510590129246f4deeff61ef Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 29 Nov 2019 16:28:59 +0200 Subject: [PATCH 290/442] onSeeAllButtonClicked prop added in MetaRow --- src/common/MetaRow/MetaRow.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/common/MetaRow/MetaRow.js b/src/common/MetaRow/MetaRow.js index 9658dff1f..b42153893 100644 --- a/src/common/MetaRow/MetaRow.js +++ b/src/common/MetaRow/MetaRow.js @@ -7,7 +7,7 @@ const MetaItem = require('stremio/common/MetaItem'); const MetaRowPlaceholder = require('./MetaRowPlaceholder'); const styles = require('./styles'); -const MetaRow = ({ className, title, message, items, maximumItemsCount, itemMenuOptions }) => { +const MetaRow = ({ className, title, message, items, maximumItemsCount, itemMenuOptions, onSeeAllButtonClicked }) => { maximumItemsCount = maximumItemsCount !== null && isFinite(maximumItemsCount) ? maximumItemsCount : 20; items = Array.isArray(items) ? items.slice(0, maximumItemsCount) : []; return ( @@ -38,7 +38,7 @@ const MetaRow = ({ className, title, message, items, maximumItemsCount, itemMenu
))}
- @@ -58,7 +58,8 @@ MetaRow.propTypes = { posterShape: PropTypes.string })), maximumItemsCount: PropTypes.number, - itemMenuOptions: PropTypes.any + itemMenuOptions: PropTypes.any, + onSeeAllButtonClicked: PropTypes.func }; module.exports = MetaRow; From 96d9332a9e159bcfabc88abf480f1fb58625a3a4 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 29 Nov 2019 16:33:10 +0200 Subject: [PATCH 291/442] 'see all' button shows all relevant items in discover --- src/routes/Search/Search.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index d38df9347..c2ec29b50 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -6,12 +6,15 @@ const styles = require('./styles'); const Search = ({ queryParams }) => { const search = useSearch(queryParams); + const discoverUrls = React.useCallback((request) => { + window.location.replace(`#/discover/${encodeURIComponent(request.base)}/${encodeURIComponent(request.path.id)}/${encodeURIComponent(request.path.type_name)}?search=${search.selected[0][1]}`); + }, [search.selected]); return (
{ - search.selected && search.selected[0][1].length > 0 ? + search.selected && search.selected[0][1] && search.selected[0][1].length > 0 ? search.items_groups && search.items_groups.length > 0 && search.items_groups.some(group => group.content.type !== 'Err') ? search.items_groups.map(({ request, content }, index) => { switch (content.type) { @@ -22,6 +25,7 @@ const Search = ({ queryParams }) => { className={styles['search-row']} title={`${request.path.id} - ${request.path.type_name}`} items={content.content} + onSeeAllButtonClicked={() => discoverUrls(request)} /> ); case 'Err': From 32be8a633a09a9dcb373037310a0efa1891f4ebc Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 29 Nov 2019 17:37:49 +0200 Subject: [PATCH 292/442] handle 'no requested addons' case --- src/routes/Search/Search.js | 73 ++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index c2ec29b50..f1daff287 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -15,42 +15,49 @@ const Search = ({ queryParams }) => {
{ search.selected && search.selected[0][1] && search.selected[0][1].length > 0 ? - search.items_groups && search.items_groups.length > 0 && search.items_groups.some(group => group.content.type !== 'Err') ? - search.items_groups.map(({ request, content }, index) => { - switch (content.type) { - case 'Ready': - return ( - discoverUrls(request)} - /> - ); - case 'Err': - return ( - - ); - case 'Loading': - return ( - - ); - } - }) + search.items_groups && search.items_groups.length > 0 ? + search.items_groups.some(group => group.content.type !== 'Err') ? + search.items_groups.map(({ request, content }, index) => { + switch (content.type) { + case 'Ready': + return ( + discoverUrls(request)} + /> + ); + case 'Err': + return ( + + ); + case 'Loading': + return ( + + ); + } + }) + : +
+
+
No metadata was found
+
+
:
-
No metadata was found
+
No addons were requested for metadata
: From 9696796d6b166df3ac9bc145fe61868419651d49 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 09:47:44 +0200 Subject: [PATCH 293/442] popup compatible with native data props --- src/common/Popup/Popup.js | 3 ++- storybook/stories/Popup/Popup.js | 9 +++++++-- storybook/stories/Popup/styles.less | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index d7830965e..a9498f4d9 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -4,7 +4,7 @@ const classnames = require('classnames'); const FocusLock = require('react-focus-lock').default; const styles = require('./styles'); -const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseRequest }) => { +const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseRequest, ...props }) => { const labelRef = React.useRef(null); const [autoDirection, setAutoDirection] = React.useState(null); const menuOnMouseDown = React.useCallback((event) => { @@ -59,6 +59,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque } }, [open]); return renderLabel({ + ...props, ref: labelRef, className: styles['label-container'], children: open ? diff --git a/storybook/stories/Popup/Popup.js b/storybook/stories/Popup/Popup.js index 8e1f99515..66d0a27a3 100644 --- a/storybook/stories/Popup/Popup.js +++ b/storybook/stories/Popup/Popup.js @@ -22,12 +22,15 @@ storiesOf('Popup', module).add('Popup', () => { action('onCloseRequest')(event); closeMenu(); }, []); + const domEventHandler = React.useCallback((event) => { + action('domEventHandler')(event.currentTarget.dataset); + }, []); return ( ( - @@ -41,6 +44,8 @@ storiesOf('Popup', module).add('Popup', () => { )} dataset={{ prop: 'value' }} onCloseRequest={onCloseRequest} + data-prop={'data-value'} + onMouseEnter={domEventHandler} /> ); }); diff --git a/storybook/stories/Popup/styles.less b/storybook/stories/Popup/styles.less index 82d1d09e2..2853b7210 100644 --- a/storybook/stories/Popup/styles.less +++ b/storybook/stories/Popup/styles.less @@ -13,7 +13,7 @@ margin: 2rem; padding: 0 1.2rem; color: var(--color-surfacelighter); - background: var(--color-backgroundlight); + background: var(--color-secondarylight); .popup-menu-container { right: initial; @@ -22,11 +22,11 @@ .menu-container { width: 20rem; height: 20rem; - padding: 2rem; background: var(--color-surface); overflow-y: auto; .random-button { + margin: 2rem; padding: 0.8rem; background: var(--color-primary); text-align: center; From 2ec1448841e126cf5aede5da752a79012cfe8f88 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 10:37:21 +0200 Subject: [PATCH 294/442] Multiselect compatible with native data props --- src/common/Multiselect/Multiselect.js | 26 +++++++++---------- .../MultiselectSingleValue.js | 5 ++++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/common/Multiselect/Multiselect.js b/src/common/Multiselect/Multiselect.js index 24e3db096..d69f6577b 100644 --- a/src/common/Multiselect/Multiselect.js +++ b/src/common/Multiselect/Multiselect.js @@ -7,21 +7,19 @@ const Popup = require('stremio/common/Popup'); const useBinaryState = require('stremio/common/useBinaryState'); const styles = require('./styles'); -const Multiselect = ({ className, direction, title, options, selected, disabled, dataset, renderLabelContent, renderLabelText, onOpen, onClose, onSelect }) => { - options = Array.isArray(options) ? - options.filter(option => option && typeof option.value === 'string') - : - []; - selected = Array.isArray(selected) ? - selected.filter(value => typeof value === 'string') - : - []; +const Multiselect = ({ className, direction, title, options, selected, disabled, dataset, renderLabelContent, renderLabelText, onOpen, onClose, onSelect, ...props }) => { + options = Array.isArray(options) ? options.filter((option) => option && typeof option.value === 'string') : []; + selected = Array.isArray(selected) ? selected.filter((value) => typeof value === 'string') : []; const [menuOpen, openMenu, closeMenu, toggleMenu] = useBinaryState(false); const popupLabelOnClick = React.useCallback((event) => { + if (typeof props.onClick === 'function') { + props.onClick(event); + } + if (!event.nativeEvent.togglePopupPrevented) { toggleMenu(); } - }, [toggleMenu]); + }, [props.onClick, toggleMenu]); const popupMenuOnClick = React.useCallback((event) => { event.nativeEvent.togglePopupPrevented = true; }, []); @@ -42,7 +40,7 @@ const Multiselect = ({ className, direction, title, options, selected, disabled, if (!event.nativeEvent.closeMenuPrevented) { closeMenu(); } - }, [onSelect, dataset]); + }, [dataset, onSelect]); React.useLayoutEffect(() => { if (menuOpen) { if (typeof onOpen === 'function') { @@ -65,8 +63,8 @@ const Multiselect = ({ className, direction, title, options, selected, disabled, open={menuOpen} direction={direction} onCloseRequest={closeMenu} - renderLabel={({ ref, className: popupLabelClassName, children }) => ( - )} renderMenu={() => ( diff --git a/storybook/stories/Multiselect/MultiselectSingleValue/MultiselectSingleValue.js b/storybook/stories/Multiselect/MultiselectSingleValue/MultiselectSingleValue.js index f143e5f8b..9bf58f2f9 100644 --- a/storybook/stories/Multiselect/MultiselectSingleValue/MultiselectSingleValue.js +++ b/storybook/stories/Multiselect/MultiselectSingleValue/MultiselectSingleValue.js @@ -10,6 +10,9 @@ storiesOf('Multiselect', module).add('MultiselectSingleValue', () => { action('onSelect')(event); setSelected([event.value]); }, []); + const domEventHandler = React.useCallback((event) => { + action('domEventHandler')(event.currentTarget.dataset); + }, []); return ( { onOpen={action('onOpen')} onClose={action('onClose')} onSelect={onSelect} + data-prop={'data-value'} + onClick={domEventHandler} /> ); }); \ No newline at end of file From eed4a632432618a2b751d801ee166c5b766ff21f Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 10:37:53 +0200 Subject: [PATCH 295/442] fix multiselect trigger onOpen/onClose after first render --- src/common/Multiselect/Multiselect.js | 31 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/common/Multiselect/Multiselect.js b/src/common/Multiselect/Multiselect.js index d69f6577b..51b6bef4d 100644 --- a/src/common/Multiselect/Multiselect.js +++ b/src/common/Multiselect/Multiselect.js @@ -41,22 +41,27 @@ const Multiselect = ({ className, direction, title, options, selected, disabled, closeMenu(); } }, [dataset, onSelect]); + const mountedRef = React.useRef(false); React.useLayoutEffect(() => { - if (menuOpen) { - if (typeof onOpen === 'function') { - onOpen({ - type: 'open', - dataset: dataset - }); - } - } else { - if (typeof onClose === 'function') { - onClose({ - type: 'close', - dataset: dataset - }); + if (mountedRef.current) { + if (menuOpen) { + if (typeof onOpen === 'function') { + onOpen({ + type: 'open', + dataset: dataset + }); + } + } else { + if (typeof onClose === 'function') { + onClose({ + type: 'close', + dataset: dataset + }); + } } } + + mountedRef.current = true; }, [menuOpen]); return ( Date: Mon, 2 Dec 2019 10:40:16 +0200 Subject: [PATCH 296/442] MetaItem compatible with native data props --- src/common/MetaItem/MetaItem.js | 18 ++++----- .../MetaItem/SаmpleMetaItem/SаmpleMetaItem.js | 37 +++++++++++-------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/common/MetaItem/MetaItem.js b/src/common/MetaItem/MetaItem.js index c775406f7..d4c0939a5 100644 --- a/src/common/MetaItem/MetaItem.js +++ b/src/common/MetaItem/MetaItem.js @@ -19,15 +19,6 @@ const ICON_FOR_TYPE = new Map([ const MetaItem = React.memo(({ className, type, name, poster, posterShape, playIcon, progress, menuOptions, dataset, onSelect, menuOptionOnSelect, ...props }) => { const [menuOpen, onMenuOpen, onMenuClose] = useBinaryState(false); - const renderPosterFallback = React.useMemo(() => () => ( - - ), [type]); - const renderMenuOptionsLabelContent = React.useMemo(() => () => ( - - ), []); const metaItemOnClick = React.useCallback((event) => { if (typeof props.onClick === 'function') { props.onClick(event); @@ -56,6 +47,15 @@ const MetaItem = React.memo(({ className, type, name, poster, posterShape, playI }); } }, [menuOptionOnSelect, dataset]); + const renderPosterFallback = React.useMemo(() => () => ( + + ), [type]); + const renderMenuOptionsLabelContent = React.useMemo(() => () => ( + + ), []); return ( ); }; ColorInput.propTypes = { - className: PropTypes.string, value: PropTypes.string, dataset: PropTypes.objectOf(String), onChange: PropTypes.func diff --git a/storybook/stories/ColorInput/ColorInput.js b/storybook/stories/ColorInput/ColorInput.js index e79d8d0a7..3e5fc1191 100644 --- a/storybook/stories/ColorInput/ColorInput.js +++ b/storybook/stories/ColorInput/ColorInput.js @@ -10,10 +10,16 @@ storiesOf('ColorInput', module).add('ColorInput', () => { setValue(event.value); action('onChange')(event); }, []); + const domEventHandler = React.useCallback((event) => { + action('domEventHandler')(event.currentTarget.dataset); + }, []); return ( ); From 7a1bf0f83887609c3485583b45eadd0e2ce46892 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 12:51:22 +0200 Subject: [PATCH 301/442] discover url params order changed --- src/common/routesRegexp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index 67313eea0..6b8afca88 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -9,7 +9,7 @@ const routesRegexp = { }, discover: { regexp: /^\/discover(?:\/([^\/]+?)\/([^\/]+?)\/([^\/]+?))?\/?$/i, - urlParamsNames: ['addonTransportUrl', 'catalogId', 'type'] + urlParamsNames: ['addonTransportUrl', 'type', 'catalogId'] }, library: { regexp: /^\/library(?:\/([^\/]*?))?\/?$/i, From 34bf588c3c5e0b5c07b434abc6afa7d1be9c83af Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 13:59:35 +0200 Subject: [PATCH 302/442] PaginateInput simplified --- src/common/PaginateInput/PaginateInput.js | 87 +++---------------- src/common/PaginateInput/styles.less | 8 +- .../SimplePaginateInput.js | 21 +++++ .../SimplePaginateInput/index.js | 1 + .../SimplePaginateInput/styles.less | 19 ++++ storybook/stories/PaginateInput/index.js | 1 + storybook/stories/index.js | 1 + 7 files changed, 59 insertions(+), 79 deletions(-) create mode 100644 storybook/stories/PaginateInput/SimplePaginateInput/SimplePaginateInput.js create mode 100644 storybook/stories/PaginateInput/SimplePaginateInput/index.js create mode 100644 storybook/stories/PaginateInput/SimplePaginateInput/styles.less create mode 100644 storybook/stories/PaginateInput/index.js diff --git a/src/common/PaginateInput/PaginateInput.js b/src/common/PaginateInput/PaginateInput.js index e0f207a31..9795238a3 100644 --- a/src/common/PaginateInput/PaginateInput.js +++ b/src/common/PaginateInput/PaginateInput.js @@ -3,90 +3,29 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const Button = require('stremio/common/Button'); -const Multiselect = require('stremio/common/Multiselect'); const styles = require('./styles'); -const PaginateInput = ({ className, options, selected, dataset, onSelect }) => { - const selectedLabelText = React.useMemo(() => { - if (Array.isArray(options)) { - const selectedOption = options.find(({ value }) => { - return selected === value; - }); - if (selectedOption && typeof selectedOption.label === 'string') { - return selectedOption.label; - } - } - - return selected; - }, [options, selected]); +const PaginateInput = ({ className, label, dataset, onSelect, ...props }) => { const prevNextButtonOnClick = React.useCallback((event) => { if (typeof onSelect === 'function') { - if (Array.isArray(options) && options.length > 0) { - const selectedValueIndex = options.findIndex(({ value }) => { - return selected === value; - }); - const nextSelectedIndex = event.currentTarget.dataset.button === 'next' ? - Math.min(selectedValueIndex + 1, options.length - 1) - : - Math.max(selectedValueIndex - 1, 0); - const nextSelectedValue = options[nextSelectedIndex].value; - onSelect({ - type: 'select', - value: nextSelectedValue, - dataset: dataset, - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } else { - const nextSelectedValue = event.currentTarget.dataset.button === 'next' ? - selected + 1 - : - Math.max(selected - 1, 1); - onSelect({ - type: 'select', - value: nextSelectedValue, - dataset: dataset, - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } - } - }, [options, selected, dataset, onSelect]); - const optionOnSelect = React.useCallback((event) => { - const page = parseInt(event.value); - if (!isNaN(page) && typeof onSelect === 'function') { onSelect({ - type: 'select', - value: page, + type: 'change-page', + value: event.currentTarget.dataset.value, dataset: dataset, - reactEvent: event.reactEvent, + reactEvent: event, nativeEvent: event.nativeEvent }); } }, [dataset, onSelect]); return ( -
- - ( -
{selectedLabelText}
- )} - options={ - Array.isArray(options) ? - options.map(({ value, label }) => ({ - value: String(value), - label - })) - : - null - } - disabled={!Array.isArray(options) || options.length === 0} - onSelect={optionOnSelect} - /> -
@@ -95,11 +34,7 @@ const PaginateInput = ({ className, options, selected, dataset, onSelect }) => { PaginateInput.propTypes = { className: PropTypes.string, - options: PropTypes.arrayOf(PropTypes.shape({ - value: PropTypes.number.isRequired, - label: PropTypes.string - })), - selected: PropTypes.number.isRequired, + label: PropTypes.string, onSelect: PropTypes.func }; diff --git a/src/common/PaginateInput/styles.less b/src/common/PaginateInput/styles.less index e370414f8..aa2ea0c64 100644 --- a/src/common/PaginateInput/styles.less +++ b/src/common/PaginateInput/styles.less @@ -1,7 +1,6 @@ .paginate-input-container { display: flex; flex-direction: row; - overflow: visible; .prev-button-container, .next-button-container { flex: none; @@ -17,15 +16,18 @@ } } - .multiselect-label-container { + .label-container { flex: 1; align-self: stretch; display: flex; align-items: center; justify-content: center; - .multiselect-label { + .label { flex: none; + max-width: 3rem; + white-space: nowrap; + text-overflow: ellipsis; color: var(--color-surfacelighter); } } diff --git a/storybook/stories/PaginateInput/SimplePaginateInput/SimplePaginateInput.js b/storybook/stories/PaginateInput/SimplePaginateInput/SimplePaginateInput.js new file mode 100644 index 000000000..af22bfc28 --- /dev/null +++ b/storybook/stories/PaginateInput/SimplePaginateInput/SimplePaginateInput.js @@ -0,0 +1,21 @@ +const React = require('react'); +const { storiesOf } = require('@storybook/react'); +const { action } = require('@storybook/addon-actions'); +const { PaginateInput } = require('stremio/common'); +const styles = require('./styles'); + +storiesOf('PaginateInput', module).add('SimplePaginateInput', () => { + const domEventHandler = React.useCallback((event) => { + action('domEventHandler')(event.currentTarget.dataset); + }, []); + return ( + + ); +}); diff --git a/storybook/stories/PaginateInput/SimplePaginateInput/index.js b/storybook/stories/PaginateInput/SimplePaginateInput/index.js new file mode 100644 index 000000000..8fe14c08d --- /dev/null +++ b/storybook/stories/PaginateInput/SimplePaginateInput/index.js @@ -0,0 +1 @@ +require('./SimplePaginateInput'); diff --git a/storybook/stories/PaginateInput/SimplePaginateInput/styles.less b/storybook/stories/PaginateInput/SimplePaginateInput/styles.less new file mode 100644 index 000000000..8217acd32 --- /dev/null +++ b/storybook/stories/PaginateInput/SimplePaginateInput/styles.less @@ -0,0 +1,19 @@ +:import('~stremio/common/PaginateInput/styles.less') { + paginate-prev-button-container: prev-button-container; + paginate-next-button-container: next-button-container; +} + +.paginate-input { + flex: none; + align-self: flex-start; + display: flex; + min-width: 8rem; + max-width: 10rem; + margin: 1rem; + background-color: var(--color-backgroundlighter); + + .paginate-prev-button-container, .paginate-next-button-container { + width: 3rem; + height: 3rem; + } +} \ No newline at end of file diff --git a/storybook/stories/PaginateInput/index.js b/storybook/stories/PaginateInput/index.js new file mode 100644 index 000000000..8fe14c08d --- /dev/null +++ b/storybook/stories/PaginateInput/index.js @@ -0,0 +1 @@ +require('./SimplePaginateInput'); diff --git a/storybook/stories/index.js b/storybook/stories/index.js index 8ee1de155..f9d84a2de 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -6,6 +6,7 @@ require('./MetaItem'); require('./ModalDialog'); require('./Multiselect'); require('./Notification'); +require('./PaginateInput'); require('./Popup'); require('./SeasonsBar'); require('./SharePrompt'); From 2ee8f3f1ea0db31015f107091cc065cbec3dbf8a Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 2 Dec 2019 14:36:14 +0200 Subject: [PATCH 303/442] catalogHref prop added to MetaRow --- src/common/MetaRow/MetaRow.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/MetaRow/MetaRow.js b/src/common/MetaRow/MetaRow.js index b42153893..b416207a3 100644 --- a/src/common/MetaRow/MetaRow.js +++ b/src/common/MetaRow/MetaRow.js @@ -7,7 +7,7 @@ const MetaItem = require('stremio/common/MetaItem'); const MetaRowPlaceholder = require('./MetaRowPlaceholder'); const styles = require('./styles'); -const MetaRow = ({ className, title, message, items, maximumItemsCount, itemMenuOptions, onSeeAllButtonClicked }) => { +const MetaRow = ({ className, title, message, items, maximumItemsCount, itemMenuOptions, catalogHref }) => { maximumItemsCount = maximumItemsCount !== null && isFinite(maximumItemsCount) ? maximumItemsCount : 20; items = Array.isArray(items) ? items.slice(0, maximumItemsCount) : []; return ( @@ -38,7 +38,7 @@ const MetaRow = ({ className, title, message, items, maximumItemsCount, itemMenu
))}
- @@ -59,7 +59,7 @@ MetaRow.propTypes = { })), maximumItemsCount: PropTypes.number, itemMenuOptions: PropTypes.any, - onSeeAllButtonClicked: PropTypes.func + catalogHref: PropTypes.string }; module.exports = MetaRow; From e3811c91e25e6e91a19c0c29c833d6aa2b55d7d1 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 2 Dec 2019 14:39:05 +0200 Subject: [PATCH 304/442] search state mapped in the initial state --- src/routes/Search/Search.js | 9 +++------ src/routes/Search/useSearch.js | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index f1daff287..5e3504ea6 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -6,18 +6,15 @@ const styles = require('./styles'); const Search = ({ queryParams }) => { const search = useSearch(queryParams); - const discoverUrls = React.useCallback((request) => { - window.location.replace(`#/discover/${encodeURIComponent(request.base)}/${encodeURIComponent(request.path.id)}/${encodeURIComponent(request.path.type_name)}?search=${search.selected[0][1]}`); - }, [search.selected]); return (
{ - search.selected && search.selected[0][1] && search.selected[0][1].length > 0 ? + search.selected ? search.items_groups && search.items_groups.length > 0 ? search.items_groups.some(group => group.content.type !== 'Err') ? - search.items_groups.map(({ request, content }, index) => { + search.items_groups.map(({ href, request, content }, index) => { switch (content.type) { case 'Ready': return ( @@ -26,7 +23,7 @@ const Search = ({ queryParams }) => { className={styles['search-row']} title={`${request.path.id} - ${request.path.type_name}`} items={content.content} - onSeeAllButtonClicked={() => discoverUrls(request)} + catalogHref={href} /> ); case 'Err': diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 9f26678f9..64ae61a19 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -1,13 +1,27 @@ const React = require('react'); const { useServices } = require('stremio/services'); +const mapSearchState = (state) => { + const selected = state.search.selected && state.search.selected[0] && state.search.selected[0][1] && state.search.selected[0][1].length > 0 ? state.search.selected[0][1] : ''; + const items_groups = state.search.items_groups.map((group) => { + group.href = `#/discover/${encodeURIComponent(group.request.base)}/${encodeURIComponent(group.request.path.id)}/${encodeURIComponent(group.request.path.type_name)}?search=${state.search.selected[0][1]}`; + return group; + }); + return { selected, items_groups }; +}; + const useSearch = (queryParams) => { const { core } = useServices(); - const [search, setSearch] = React.useState([]); + const [search, setSearch] = React.useState(() => { + const state = core.getState(); + const search = mapSearchState(state); + return search; + }); React.useEffect(() => { const onNewState = () => { const state = core.getState(); - setSearch(state.search); + const search = mapSearchState(state); + setSearch(search); }; core.on('NewModel', onNewState); if (queryParams.has('q')) { From 373e5b5d39bfafbb8f103162f63eaa77e41e6535 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 2 Dec 2019 16:21:23 +0200 Subject: [PATCH 305/442] q renamed to search --- src/common/NavBar/SearchBar/SearchBar.js | 4 ++-- src/routes/Search/useSearch.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/NavBar/SearchBar/SearchBar.js b/src/common/NavBar/SearchBar/SearchBar.js index 5e33d44ec..2097c79af 100644 --- a/src/common/NavBar/SearchBar/SearchBar.js +++ b/src/common/NavBar/SearchBar/SearchBar.js @@ -20,7 +20,7 @@ const SearchBar = ({ className }) => { if (routeActive) { const { search: locationSearch } = UrlUtils.parse(locationHash.slice(1)); const queryParams = new URLSearchParams(locationSearch); - return queryParams.has('q') ? queryParams.get('q') : ''; + return queryParams.has('search') ? queryParams.get('search') : ''; } return ''; @@ -32,7 +32,7 @@ const SearchBar = ({ className }) => { }, [routeActive]); const queryInputOnSubmit = React.useCallback(() => { if (routeActive) { - window.location.replace(`#/search?q=${searchInputRef.current.value}`); + window.location.replace(`#/search?search=${searchInputRef.current.value}`); } }, [routeActive]); React.useEffect(() => { diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 64ae61a19..427cb8c9c 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -24,14 +24,14 @@ const useSearch = (queryParams) => { setSearch(search); }; core.on('NewModel', onNewState); - if (queryParams.has('q')) { + if (queryParams.has('search')) { core.dispatch({ action: 'Load', args: { load: 'CatalogsGrouped', args: { extra: [ - ['search', queryParams.get('q')] + ['search', queryParams.get('search')] ] } } From 268d5a6e0b2863705b3682eb67c5d75aa35602b3 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 2 Dec 2019 16:22:24 +0200 Subject: [PATCH 306/442] use query for href --- src/routes/Search/useSearch.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 427cb8c9c..331a34143 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -2,9 +2,15 @@ const React = require('react'); const { useServices } = require('stremio/services'); const mapSearchState = (state) => { - const selected = state.search.selected && state.search.selected[0] && state.search.selected[0][1] && state.search.selected[0][1].length > 0 ? state.search.selected[0][1] : ''; + const query = state.search.selected.reduceRight((query, [name, value]) => { + if (name === 'search') { + return value; + } + return query; + }, ''); + const selected = state.search.selected; const items_groups = state.search.items_groups.map((group) => { - group.href = `#/discover/${encodeURIComponent(group.request.base)}/${encodeURIComponent(group.request.path.id)}/${encodeURIComponent(group.request.path.type_name)}?search=${state.search.selected[0][1]}`; + group.href = `#/discover/${encodeURIComponent(group.request.base)}/${encodeURIComponent(group.request.path.id)}/${encodeURIComponent(group.request.path.type_name)}?search=${query}`; return group; }); return { selected, items_groups }; From be1282bd5dedcd8bc097dc35a158e918f81f8eee Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Mon, 2 Dec 2019 16:22:34 +0200 Subject: [PATCH 307/442] searchSelected func added --- src/routes/Search/Search.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index 5e3504ea6..b91fbea06 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -6,12 +6,15 @@ const styles = require('./styles'); const Search = ({ queryParams }) => { const search = useSearch(queryParams); + const searchSelected = React.useMemo(() => { + return search.selected.some(([name, value]) => name === 'search' && value.length > 0) + }, [search.selected]); return (
{ - search.selected ? + searchSelected ? search.items_groups && search.items_groups.length > 0 ? search.items_groups.some(group => group.content.type !== 'Err') ? search.items_groups.map(({ href, request, content }, index) => { From f4c63c53741c9eceefca79b23625df00d717251c Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 18:37:51 +0200 Subject: [PATCH 308/442] separate ui state from discover hook --- src/routes/Discover/useDiscover.js | 262 ++++++------------- src/routes/Discover/useSelectableControls.js | 185 +++++++++++++ 2 files changed, 259 insertions(+), 188 deletions(-) create mode 100644 src/routes/Discover/useSelectableControls.js diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index aeb29edd6..84bc5599e 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -1,206 +1,92 @@ const React = require('react'); const { useServices } = require('stremio/services'); -const DEFAULT_ADDON_TRANSPORT_URL = 'https://v3-cinemeta.strem.io/manifest.json'; -const DEFAULT_CATALOG_ID = 'top'; -const DEFAULT_TYPE = 'movie'; -const NONE_EXTRA_VALUE = 'None'; -const PAGE_SIZE = 100; +const CATALOG_PAGE_SIZE = 100; + +const mapDiscoverState = (state) => { + const selectable = state.discover.selectable; + const catalog_resource = state.discover.catalog_resource !== null && state.discover.catalog_resource.content.type === 'Ready' ? + { + ...state.discover.catalog_resource, + content: { + ...state.discover.catalog_resource.content, + content: state.discover.catalog_resource.content.content.map((metaItem) => { + metaItem.released = new Date(metaItem.released); + return metaItem; + }) + } + } + : + state.discover.catalog_resource; + return { selectable, catalog_resource }; +}; + +const queryParamsWithValidExtra = (queryParams) => { + queryParams = new URLSearchParams(queryParams); + if (queryParams.has('skip')) { + const skip = parseInt(queryParams.getAll('skip')[0]); + if (isFinite(skip)) { + queryParams.set('skip', Math.floor(skip / CATALOG_PAGE_SIZE) * CATALOG_PAGE_SIZE); + } + } + return queryParams; +}; const useDiscover = (urlParams, queryParams) => { const { core } = useServices(); - const [discover, setDiscover] = React.useState([[], null, null, null]); - React.useEffect(() => { - const addonTransportUrl = typeof urlParams.addonTransportUrl === 'string' ? urlParams.addonTransportUrl : DEFAULT_ADDON_TRANSPORT_URL; - const catalogId = typeof urlParams.catalogId === 'string' ? urlParams.catalogId : DEFAULT_CATALOG_ID; - const type = typeof urlParams.type === 'string' ? urlParams.type : DEFAULT_TYPE; - queryParams = new URLSearchParams(queryParams); - if (queryParams.has('skip')) { - const skip = parseInt(queryParams.get('skip')); - if (!isNaN(skip)) { - queryParams.set('skip', Math.floor(skip / PAGE_SIZE) * PAGE_SIZE); - } - } + const [discover, setDiscover] = React.useState(() => { + const state = core.getState(); + const discover = mapDiscoverState(state); + return discover; + }); + React.useLayoutEffect(() => { + queryParams = queryParamsWithValidExtra(queryParams); const onNewModel = () => { const state = core.getState(); - const navigateWithLoad = (load) => { - const addonTransportUrl = encodeURIComponent(load.base); - const catalogId = encodeURIComponent(load.path.id); - const type = encodeURIComponent(load.path.type_name); - const extra = new URLSearchParams(load.path.extra).toString(); - window.location = `#/discover/${addonTransportUrl}/${catalogId}/${type}?${extra}`; - }; - const selectInputs = [ - { - title: 'Select type', - options: state.discover.types - .map(({ type_name, load }) => ({ - value: JSON.stringify(load), - label: type_name - })), - selected: state.discover.types - .filter(({ is_selected }) => is_selected) - .map(({ load }) => JSON.stringify(load)), - onSelect: (event) => { - navigateWithLoad(JSON.parse(event.value)); + if (state.discover.catalog_resource === null && state.discover.selectable.types.length > 0) { + const load_request = state.discover.selectable.types[0].load_request; + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogFiltered', + args: load_request } - }, - { - title: 'Select catalog', - options: state.discover.catalogs - .filter(({ load: { path: { type_name } } }) => { - return type_name === type; - }) - .map(({ name, load }) => ({ - value: JSON.stringify(load), - label: name - })), - selected: state.discover.catalogs - .filter(({ is_selected }) => is_selected) - .map(({ load }) => JSON.stringify(load)), - onSelect: (event) => { - navigateWithLoad(JSON.parse(event.value)); - } - }, - ...state.discover.selectable_extra - .map((extra) => { - const title = `Select ${extra.name}`; - const options = (extra.isRequired ? [] : [NONE_EXTRA_VALUE]) - .concat(extra.options) - .map((option) => ({ - value: option, - label: option - })); - const selected = state.discover.selected.path.extra - .reduce((selected, [name, value]) => { - if (name === extra.name) { - selected = selected.filter(value => value !== NONE_EXTRA_VALUE) - .concat([value]); - } - - return selected; - }, extra.isRequired ? [] : [NONE_EXTRA_VALUE]); - const renderLabelText = selected.includes(NONE_EXTRA_VALUE) ? - () => title - : - null; - const onSelect = (event) => { - navigateWithLoad({ - base: addonTransportUrl, - path: { - resource: 'catalog', - type_name: type, - id: catalogId, - extra: Array.from(queryParams.entries()) - .concat([[extra.name, event.value]]) - .reduceRight((result, [name, value]) => { - if (extra.name === name) { - if (event.value !== NONE_EXTRA_VALUE) { - const optionsCount = result.reduce((optionsCount, [name]) => { - if (extra.name === name) { - optionsCount++; - } - - return optionsCount; - }, 0); - if (extra.optionsLimit === 1) { - if (optionsCount === 0) { - result.unshift([name, value]); - } - } else if (extra.optionsLimit > 1) { - const valueIndex = result.findIndex(([_name, _value]) => { - return _name === name && _value === value; - }); - if (valueIndex !== -1) { - result.splice(valueIndex, 1); - } else if (extra.optionsLimit > optionsCount) { - result.unshift([name, value]); - } - } - } - } else { - result.unshift([name, value]); - } - - return result; - }, []) - } - }); - } - return { title, options, selected, renderLabelText, onSelect }; - }) - ]; - const paginateInput = state.discover.load_next !== null || state.discover.load_prev !== null || state.discover.selected.path.extra.some(([name]) => name === 'skip') ? - { - selected: state.discover.selected.path.extra.reduce((page, [name, value]) => { - if (name === 'skip') { - const parsedValue = parseInt(value); - if (!isNaN(parsedValue)) { - return Math.floor(parsedValue / 100) + 1; - } - } - - return page; - }, 1), - onSelect: (event) => { - navigateWithLoad({ - base: addonTransportUrl, - path: { - resource: 'catalog', - type_name: type, - id: catalogId, - extra: Array.from(queryParams.entries()) - .concat([['skip', String((event.value - 1) * PAGE_SIZE)]]) - .reduceRight((result, [name, value]) => { - if (name === 'skip') { - const optionsCount = result.reduce((optionsCount, [name]) => { - if (name === 'skip') { - optionsCount++; - } - - return optionsCount; - }, 0); - if (optionsCount === 0) { - result.unshift([name, value]); - } - } else { - result.unshift([name, value]); - } - - return result; - }, []) - } - }); - } - } - : - null; - const items = state.discover.content.type === 'Ready' ? - state.discover.content.content.map((metaItem) => ({ - ...metaItem, - released: new Date(metaItem.released) - })) - : - null; - const error = state.discover.content.type === 'Err' ? state.discover.content.content : null; - setDiscover([selectInputs, paginateInput, items, error]); + }, 'Discover'); + return; + } + const discover = mapDiscoverState(state); + setDiscover(discover); }; core.on('NewModel', onNewModel); - core.dispatch({ - action: 'Load', - args: { - load: 'CatalogFiltered', + if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') { + core.dispatch({ + action: 'Load', args: { - base: addonTransportUrl, - path: { - resource: 'catalog', - type_name: type, - id: catalogId, - extra: Array.from(queryParams.entries()) + load: 'CatalogFiltered', + args: { + base: urlParams.addonTransportUrl, + path: { + resource: 'catalog', + type_name: urlParams.type, + id: urlParams.catalogId, + extra: Array.from(queryParams.entries()) + } } } + }, 'Discover'); + } else { + const state = core.getState(); + if (state.discover.selectable.types.length > 0) { + const load_request = state.discover.selectable.types[0].load_request; + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogFiltered', + args: load_request + } + }, 'Discover'); } - }, 'Discover'); + } return () => { core.off('NewModel', onNewModel); }; diff --git a/src/routes/Discover/useSelectableControls.js b/src/routes/Discover/useSelectableControls.js new file mode 100644 index 000000000..56df19891 --- /dev/null +++ b/src/routes/Discover/useSelectableControls.js @@ -0,0 +1,185 @@ +const React = require('react'); + +const NONE_EXTRA_VALUE = 'None'; +const CATALOG_PAGE_SIZE = 100; +const SKIP_EXTRA = { + name: 'skip', + optionsLimit: 1, + isRequired: false +}; + +const navigateWithLoadRequest = (load_request) => { + const addonTransportUrl = encodeURIComponent(load_request.base); + const type = encodeURIComponent(load_request.path.type_name); + const catalogId = encodeURIComponent(load_request.path.id); + const extra = new URLSearchParams(load_request.path.extra).toString(); + window.location = `#/discover/${addonTransportUrl}/${type}/${catalogId}?${extra}`; +}; + +const getNextExtra = (prevExtra, extraProp, extraValue) => { + return prevExtra + .concat([[extraProp.name, extraValue]]) + .reduceRight((result, [name, value]) => { + if (extraProp.name === name) { + if (extraValue !== NONE_EXTRA_VALUE) { + const optionsCount = result.reduce((optionsCount, [name]) => { + if (extraProp.name === name) { + optionsCount++; + } + + return optionsCount; + }, 0); + if (extraProp.optionsLimit === 1) { + if (optionsCount === 0) { + result.unshift([name, value]); + } + } else if (extraProp.optionsLimit > 1) { + const valueIndex = result.findIndex(([_name, _value]) => { + return _name === name && _value === value; + }); + if (valueIndex !== -1) { + result.splice(valueIndex, 1); + } else if (extraProp.optionsLimit > optionsCount) { + result.unshift([name, value]); + } + } + } + } else { + result.unshift([name, value]); + } + + return result; + }, []); +}; + +const mapSelectableControls = (discover) => { + const selectedTransportUrl = discover.catalog_resource !== null ? + discover.catalog_resource.request.base + : + null; + const selectedTypeName = discover.catalog_resource !== null ? + discover.catalog_resource.request.path.type_name + : + null; + const selectedCatalogId = discover.catalog_resource !== null ? + discover.catalog_resource.request.path.id + : + null; + const selectedExtra = discover.catalog_resource !== null ? + discover.catalog_resource.request.path.extra + : + []; + const selectedPage = selectedExtra.reduce((selectedPage, [name, value]) => { + if (name === SKIP_EXTRA.name) { + const skip = parseInt(value); + if (isFinite(skip)) { + return Math.floor(skip / CATALOG_PAGE_SIZE) + 1; + } + } + + return selectedPage; + }, 1); + const typeSelect = { + title: 'Select type', + options: discover.selectable.types + .map(({ name, load_request }) => ({ + value: JSON.stringify(load_request), + label: name + })), + selected: discover.selectable.types + .filter(({ load_request: { path: { type_name } } }) => { + return type_name === selectedTypeName; + }) + .map(({ load_request }) => JSON.stringify(load_request)), + onSelect: (event) => { + navigateWithLoadRequest(JSON.parse(event.value)); + } + }; + const catalogSelect = { + title: 'Select catalog', + options: discover.selectable.catalogs + .map(({ name, load_request }) => ({ + value: JSON.stringify(load_request), + label: name + })), + selected: discover.selectable.catalogs + .filter(({ load_request: { path: { id } } }) => { + return id === selectedCatalogId; + }) + .map(({ load_request }) => JSON.stringify(load_request)), + onSelect: (event) => { + navigateWithLoadRequest(JSON.parse(event.value)); + } + }; + const extraSelects = discover.selectable.extra.map((extra) => { + const title = `Select ${extra.name}`; + const options = (extra.isRequired ? [] : [NONE_EXTRA_VALUE]) + .concat(extra.options) + .map((option) => ({ + value: option, + label: option + })); + const selected = selectedExtra + .reduce((selected, [name, value]) => { + if (name === extra.name) { + selected = selected + .filter((value) => value !== NONE_EXTRA_VALUE) + .concat([value]); + } + + return selected; + }, extra.isRequired ? [] : [NONE_EXTRA_VALUE]); + const renderLabelText = selected.includes(NONE_EXTRA_VALUE) ? + () => title + : + null; + const onSelect = (event) => { + navigateWithLoadRequest({ + base: selectedTransportUrl, + path: { + resource: 'catalog', + type_name: selectedTypeName, + id: selectedCatalogId, + extra: getNextExtra(selectedExtra, extra, event.value) + } + }); + }; + return { title, options, selected, renderLabelText, onSelect }; + }); + const paginationInput = discover.selectable.has_prev_page || discover.selectable.has_next_page || selectedExtra.some(([name]) => name === 'skip') ? + { + label: String(selectedPage), + onSelect: (event) => { + if (event.value === 'prev' && !discover.selectable.has_prev_page || + event.value === 'next' && !discover.selectable.has_next_page) { + return; + } + + const nextValue = event.value === 'next' ? + String(selectedPage * CATALOG_PAGE_SIZE) + : + String((selectedPage - 2) * CATALOG_PAGE_SIZE); + navigateWithLoadRequest({ + base: selectedTransportUrl, + path: { + resource: 'catalog', + type_name: selectedTypeName, + id: selectedCatalogId, + extra: getNextExtra(selectedExtra, SKIP_EXTRA, nextValue) + } + }); + } + } + : + null; + return [[typeSelect, catalogSelect, ...extraSelects], paginationInput]; +}; + +const useSelectableControls = (discover) => { + const selectableControls = React.useMemo(() => { + return mapSelectableControls(discover); + }, [discover]); + return selectableControls; +}; + +module.exports = useSelectableControls; From 230119274c6bd45a2856dfe8b9250f56a71f3a3d Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 18:38:04 +0200 Subject: [PATCH 309/442] use plain initail state --- src/routes/Discover/useDiscover.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 84bc5599e..6e04bd66c 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -34,11 +34,16 @@ const queryParamsWithValidExtra = (queryParams) => { const useDiscover = (urlParams, queryParams) => { const { core } = useServices(); - const [discover, setDiscover] = React.useState(() => { - const state = core.getState(); - const discover = mapDiscoverState(state); - return discover; - }); + const [discover, setDiscover] = React.useState(() => ({ + selectable: { + types: [], + catalogs: [], + extra: [], + has_next_page: false, + has_prev_page: false + }, + catalog_resource: null + })); React.useLayoutEffect(() => { queryParams = queryParamsWithValidExtra(queryParams); const onNewModel = () => { From 7b14e1c7ca47031168988e6876f858fab8590943 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 18:49:47 +0200 Subject: [PATCH 310/442] drop query params validation in the js layer --- src/routes/Discover/useDiscover.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 6e04bd66c..abe7c951d 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -1,8 +1,6 @@ const React = require('react'); const { useServices } = require('stremio/services'); -const CATALOG_PAGE_SIZE = 100; - const mapDiscoverState = (state) => { const selectable = state.discover.selectable; const catalog_resource = state.discover.catalog_resource !== null && state.discover.catalog_resource.content.type === 'Ready' ? @@ -21,17 +19,6 @@ const mapDiscoverState = (state) => { return { selectable, catalog_resource }; }; -const queryParamsWithValidExtra = (queryParams) => { - queryParams = new URLSearchParams(queryParams); - if (queryParams.has('skip')) { - const skip = parseInt(queryParams.getAll('skip')[0]); - if (isFinite(skip)) { - queryParams.set('skip', Math.floor(skip / CATALOG_PAGE_SIZE) * CATALOG_PAGE_SIZE); - } - } - return queryParams; -}; - const useDiscover = (urlParams, queryParams) => { const { core } = useServices(); const [discover, setDiscover] = React.useState(() => ({ @@ -45,7 +32,6 @@ const useDiscover = (urlParams, queryParams) => { catalog_resource: null })); React.useLayoutEffect(() => { - queryParams = queryParamsWithValidExtra(queryParams); const onNewModel = () => { const state = core.getState(); if (state.discover.catalog_resource === null && state.discover.selectable.types.length > 0) { From 8bd5867f665b41fb09e92c9a9876b84b08272786 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 19:13:29 +0200 Subject: [PATCH 311/442] PaginateInput component renamed --- src/common/PaginateInput/index.js | 3 --- .../PaginationInput.js} | 8 ++++---- src/common/PaginationInput/index.js | 3 +++ .../styles.less | 2 +- src/common/index.js | 4 ++-- .../SimplePaginateInput/index.js | 1 - .../SimplePaginateInput/styles.less | 19 ------------------- storybook/stories/PaginateInput/index.js | 1 - .../SimplePaginationInput.js} | 8 ++++---- .../SimplePaginationInput/index.js | 1 + .../SimplePaginationInput/styles.less | 19 +++++++++++++++++++ storybook/stories/PaginationInput/index.js | 1 + storybook/stories/index.js | 2 +- 13 files changed, 36 insertions(+), 36 deletions(-) delete mode 100644 src/common/PaginateInput/index.js rename src/common/{PaginateInput/PaginateInput.js => PaginationInput/PaginationInput.js} (89%) create mode 100644 src/common/PaginationInput/index.js rename src/common/{PaginateInput => PaginationInput}/styles.less (96%) delete mode 100644 storybook/stories/PaginateInput/SimplePaginateInput/index.js delete mode 100644 storybook/stories/PaginateInput/SimplePaginateInput/styles.less delete mode 100644 storybook/stories/PaginateInput/index.js rename storybook/stories/{PaginateInput/SimplePaginateInput/SimplePaginateInput.js => PaginationInput/SimplePaginationInput/SimplePaginationInput.js} (72%) create mode 100644 storybook/stories/PaginationInput/SimplePaginationInput/index.js create mode 100644 storybook/stories/PaginationInput/SimplePaginationInput/styles.less create mode 100644 storybook/stories/PaginationInput/index.js diff --git a/src/common/PaginateInput/index.js b/src/common/PaginateInput/index.js deleted file mode 100644 index 60b8c3e91..000000000 --- a/src/common/PaginateInput/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const PaginateInput = require('./PaginateInput'); - -module.exports = PaginateInput; \ No newline at end of file diff --git a/src/common/PaginateInput/PaginateInput.js b/src/common/PaginationInput/PaginationInput.js similarity index 89% rename from src/common/PaginateInput/PaginateInput.js rename to src/common/PaginationInput/PaginationInput.js index 9795238a3..77bb38f5c 100644 --- a/src/common/PaginateInput/PaginateInput.js +++ b/src/common/PaginationInput/PaginationInput.js @@ -5,7 +5,7 @@ const Icon = require('stremio-icons/dom'); const Button = require('stremio/common/Button'); const styles = require('./styles'); -const PaginateInput = ({ className, label, dataset, onSelect, ...props }) => { +const PaginationInput = ({ className, label, dataset, onSelect, ...props }) => { const prevNextButtonOnClick = React.useCallback((event) => { if (typeof onSelect === 'function') { onSelect({ @@ -18,7 +18,7 @@ const PaginateInput = ({ className, label, dataset, onSelect, ...props }) => { } }, [dataset, onSelect]); return ( -
+
@@ -32,10 +32,10 @@ const PaginateInput = ({ className, label, dataset, onSelect, ...props }) => { ); }; -PaginateInput.propTypes = { +PaginationInput.propTypes = { className: PropTypes.string, label: PropTypes.string, onSelect: PropTypes.func }; -module.exports = PaginateInput; +module.exports = PaginationInput; diff --git a/src/common/PaginationInput/index.js b/src/common/PaginationInput/index.js new file mode 100644 index 000000000..99f9edf62 --- /dev/null +++ b/src/common/PaginationInput/index.js @@ -0,0 +1,3 @@ +const PaginationInput = require('./PaginationInput'); + +module.exports = PaginationInput; \ No newline at end of file diff --git a/src/common/PaginateInput/styles.less b/src/common/PaginationInput/styles.less similarity index 96% rename from src/common/PaginateInput/styles.less rename to src/common/PaginationInput/styles.less index aa2ea0c64..d3a7ea39e 100644 --- a/src/common/PaginateInput/styles.less +++ b/src/common/PaginationInput/styles.less @@ -1,4 +1,4 @@ -.paginate-input-container { +.pagination-input-container { display: flex; flex-direction: row; diff --git a/src/common/index.js b/src/common/index.js index ec1743b90..320a614d1 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -9,7 +9,7 @@ const MetaRow = require('./MetaRow'); const ModalDialog = require('./ModalDialog'); const Multiselect = require('./Multiselect'); const NavBar = require('./NavBar'); -const PaginateInput = require('./PaginateInput'); +const PaginationInput = require('./PaginationInput'); const PlayIconCircleCentered = require('./PlayIconCircleCentered'); const Popup = require('./Popup'); const SharePrompt = require('./SharePrompt'); @@ -38,7 +38,7 @@ module.exports = { ModalDialog, Multiselect, NavBar, - PaginateInput, + PaginationInput, PlayIconCircleCentered, Popup, SharePrompt, diff --git a/storybook/stories/PaginateInput/SimplePaginateInput/index.js b/storybook/stories/PaginateInput/SimplePaginateInput/index.js deleted file mode 100644 index 8fe14c08d..000000000 --- a/storybook/stories/PaginateInput/SimplePaginateInput/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./SimplePaginateInput'); diff --git a/storybook/stories/PaginateInput/SimplePaginateInput/styles.less b/storybook/stories/PaginateInput/SimplePaginateInput/styles.less deleted file mode 100644 index 8217acd32..000000000 --- a/storybook/stories/PaginateInput/SimplePaginateInput/styles.less +++ /dev/null @@ -1,19 +0,0 @@ -:import('~stremio/common/PaginateInput/styles.less') { - paginate-prev-button-container: prev-button-container; - paginate-next-button-container: next-button-container; -} - -.paginate-input { - flex: none; - align-self: flex-start; - display: flex; - min-width: 8rem; - max-width: 10rem; - margin: 1rem; - background-color: var(--color-backgroundlighter); - - .paginate-prev-button-container, .paginate-next-button-container { - width: 3rem; - height: 3rem; - } -} \ No newline at end of file diff --git a/storybook/stories/PaginateInput/index.js b/storybook/stories/PaginateInput/index.js deleted file mode 100644 index 8fe14c08d..000000000 --- a/storybook/stories/PaginateInput/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./SimplePaginateInput'); diff --git a/storybook/stories/PaginateInput/SimplePaginateInput/SimplePaginateInput.js b/storybook/stories/PaginationInput/SimplePaginationInput/SimplePaginationInput.js similarity index 72% rename from storybook/stories/PaginateInput/SimplePaginateInput/SimplePaginateInput.js rename to storybook/stories/PaginationInput/SimplePaginationInput/SimplePaginationInput.js index af22bfc28..9abc98294 100644 --- a/storybook/stories/PaginateInput/SimplePaginateInput/SimplePaginateInput.js +++ b/storybook/stories/PaginationInput/SimplePaginationInput/SimplePaginationInput.js @@ -1,16 +1,16 @@ const React = require('react'); const { storiesOf } = require('@storybook/react'); const { action } = require('@storybook/addon-actions'); -const { PaginateInput } = require('stremio/common'); +const { PaginationInput } = require('stremio/common'); const styles = require('./styles'); -storiesOf('PaginateInput', module).add('SimplePaginateInput', () => { +storiesOf('PaginationInput', module).add('SimplePaginationInput', () => { const domEventHandler = React.useCallback((event) => { action('domEventHandler')(event.currentTarget.dataset); }, []); return ( - Date: Mon, 2 Dec 2019 19:13:48 +0200 Subject: [PATCH 312/442] check for valid onCloseRequest prop before use it --- src/common/ModalDialog/ModalDialog.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/common/ModalDialog/ModalDialog.js b/src/common/ModalDialog/ModalDialog.js index 152a561a3..b21a92ef1 100644 --- a/src/common/ModalDialog/ModalDialog.js +++ b/src/common/ModalDialog/ModalDialog.js @@ -11,12 +11,14 @@ const ModalDialog = ({ className, title, buttons, children, dataset, onCloseRequ event.nativeEvent.closeModalDialogPrevented = true; }, []); const closeButtonOnClick = React.useCallback((event) => { - onCloseRequest({ - type: 'close', - dataset: dataset, - reactEvent: event, - nativeEvent: event.nativeEvent - }); + if (typeof onCloseRequest === 'function') { + onCloseRequest({ + type: 'close', + dataset: dataset, + reactEvent: event, + nativeEvent: event.nativeEvent + }); + } }, [dataset, onCloseRequest]); React.useEffect(() => { const onCloseEvent = (event) => { From 428ee3e0964ad9796e3afb910121eeb88c87092e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 21:53:08 +0200 Subject: [PATCH 313/442] discover adapted to changes in core --- src/routes/Discover/Discover.js | 110 ++++++++++-------- src/routes/Discover/styles.less | 59 +++++----- ...ableControls.js => useSelectableInputs.js} | 12 +- 3 files changed, 97 insertions(+), 84 deletions(-) rename src/routes/Discover/{useSelectableControls.js => useSelectableInputs.js} (96%) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index e62223248..57cd655c5 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -2,37 +2,47 @@ const React = require('react'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { Modal } = require('stremio-router'); -const { Button, MainNavBar, MetaItem, MetaPreview, Multiselect, PaginateInput, useBinaryState } = require('stremio/common'); +const { Button, MainNavBar, MetaItem, MetaPreview, Multiselect, PaginationInput, useBinaryState } = require('stremio/common'); const useDiscover = require('./useDiscover'); +const useSelectableInputs = require('./useSelectableInputs'); const styles = require('./styles'); +const getMetaItemAtIndex = (catalog_resource, index) => { + return isFinite(index) && + catalog_resource !== null && + catalog_resource.content.type === 'Ready' && + catalog_resource.content.content[index] ? + catalog_resource.content.content[index] + : + null; +}; + const Discover = ({ urlParams, queryParams }) => { - const [selectInputs, paginateInput, metaItems, error] = useDiscover(urlParams, queryParams); - const [selectedMetaItem, setSelectedMetaItem] = React.useState(null); - const [filtersModalOpen, openFiltersModal, closeFiltersModal] = useBinaryState(false); + const discover = useDiscover(urlParams, queryParams); + const [selectInputs, paginationInput] = useSelectableInputs(discover); + const [inputsModalOpen, openInputsModal, closeInputsModal] = useBinaryState(false); + const [selectedMetaItem, setSelectedMetaItem] = React.useState(() => { + return getMetaItemAtIndex(discover.catalog_resource, 0); + }); const metaItemsOnMouseDownCapture = React.useCallback((event) => { event.nativeEvent.buttonBlurPrevented = true; }, []); const metaItemsOnFocusCapture = React.useCallback((event) => { - const metaItem = metaItems.find(({ id }) => { - return id === event.target.dataset.id; - }); - if (metaItem) { - setSelectedMetaItem(metaItem); - } - }, [metaItems]); - React.useEffect(() => { - const metaItem = Array.isArray(metaItems) && metaItems.length > 0 ? metaItems[0] : null; + const metaItem = getMetaItemAtIndex(discover.catalog_resource, event.target.dataset.index); setSelectedMetaItem(metaItem); - }, [metaItems]); - React.useEffect(() => { - closeFiltersModal(); + }, [discover.catalog_resource]); + React.useLayoutEffect(() => { + const metaItem = getMetaItemAtIndex(discover.catalog_resource, 0); + setSelectedMetaItem(metaItem); + }, [discover.catalog_resource]); + React.useLayoutEffect(() => { + closeInputsModal(); }, [urlParams, queryParams]); return (
-
+
{selectInputs.map((selectInput, index) => ( { className={styles['select-input-container']} /> ))} -
{ - paginateInput !== null ? - : null @@ -56,29 +66,39 @@ const Discover = ({ urlParams, queryParams }) => {
{ - error !== null ? + discover.selectable.types.length === 0 && discover.catalog_resource === null ?
- {error.type}{error.type === 'Other' ? ` - ${error.content}` : null} + No catalogs
: - Array.isArray(metaItems) ? -
- {metaItems.map(({ id, type, name, poster, posterShape }, index) => ( - - ))} + discover.catalog_resource === null ? +
+ No select
: -
- Loading -
+ discover.catalog_resource.content.type === 'Err' ? +
+ Catalog Error +
+ : + discover.catalog_resource.content.type === 'Loading' ? +
+ Loading +
+ : +
+ {discover.catalog_resource.content.content.map((metaItem, index) => ( + + ))} +
}
{ @@ -93,14 +113,12 @@ const Discover = ({ urlParams, queryParams }) => {
}
- { - filtersModalOpen ? - - {/* TODO */} - + {/* { + inputsModalOpen ? + : null - } + } */}
); }; diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 74433b0d3..7b0912711 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -4,10 +4,9 @@ multiselect-menu-container: menu-container; } -:import('~stremio/common/PaginateInput/styles.less') { - paginate-prev-button-container: prev-button-container; - paginate-next-button-container: next-button-container; - paginate-multiselect-label: multiselect-label; +:import('~stremio/common/PaginationInput/styles.less') { + pagination-prev-button-container: prev-button-container; + pagination-next-button-container: next-button-container; } .discover-container { @@ -27,31 +26,31 @@ align-self: stretch; display: grid; grid-template-columns: 1fr 28rem; - grid-template-rows: 7rem 1fr; + grid-template-rows: auto 1fr; grid-template-areas: - "controls-area meta-preview-area" + "selectable-inputs-area meta-preview-area" "catalog-content-area meta-preview-area"; - .controls-container { - grid-area: controls-area; + .selectable-inputs-container { + --selectable-input-height: 3rem; + grid-area: selectable-inputs-area; display: flex; flex-direction: row; - margin: 2rem 0; - padding: 0 2rem; + padding: 2rem; overflow: visible; .select-input-container { flex-grow: 0; flex-shrink: 1; flex-basis: 15rem; - height: 3rem; - margin-right: 1rem; + height: var(--selectable-input-height); + margin-right: 2rem; &:nth-child(n+4) { display: none; &~.filter-container { - display: block; + display: flex; } } @@ -62,21 +61,22 @@ } .filter-container { - display: none; flex: none; - width: 3rem; - height: 3rem; + display: none; + align-items: center; + justify-content: center; + width: var(--selectable-input-height); + height: var(--selectable-input-height); background-color: var(--color-backgroundlighter); &:not(:nth-last-child(2)) { - margin-right: 1rem; + margin-right: 2rem; } .filter-icon { - display: block; + flex: none; width: 1.2rem; height: 1.2rem; - margin: 0.9rem; fill: var(--color-surfacelighter); } } @@ -85,33 +85,28 @@ flex: 1; } - .paginate-input-container { + .pagination-input-container { flex: none; + height: var(--selectable-input-height); background-color: var(--color-backgroundlighter); - .paginate-prev-button-container, .paginate-next-button-container { - width: 3rem; - height: 3rem; - } - - .paginate-multiselect-label { - max-width: 3rem; - white-space: nowrap; - text-overflow: ellipsis; + .pagination-prev-button-container, .pagination-next-button-container { + width: var(--selectable-input-height); + height: var(--selectable-input-height); } } } .catalog-content-container { grid-area: catalog-content-area; - margin-right: 2rem; .meta-items-container { display: grid; max-height: 100%; grid-auto-rows: max-content; - grid-gap: 1.5rem; align-items: center; + grid-gap: 2rem; + margin-right: 2rem; padding: 0 2rem; overflow-y: auto; @@ -205,7 +200,7 @@ grid-template-columns: 1fr; grid-template-rows: fit-content(19rem) 1fr; grid-template-areas: - "controls-area" + "selectable-inputs-area" "catalog-content-area"; .catalog-content-container { diff --git a/src/routes/Discover/useSelectableControls.js b/src/routes/Discover/useSelectableInputs.js similarity index 96% rename from src/routes/Discover/useSelectableControls.js rename to src/routes/Discover/useSelectableInputs.js index 56df19891..c33a2a300 100644 --- a/src/routes/Discover/useSelectableControls.js +++ b/src/routes/Discover/useSelectableInputs.js @@ -52,7 +52,7 @@ const getNextExtra = (prevExtra, extraProp, extraValue) => { }, []); }; -const mapSelectableControls = (discover) => { +const mapSelectableInputs = (discover) => { const selectedTransportUrl = discover.catalog_resource !== null ? discover.catalog_resource.request.base : @@ -175,11 +175,11 @@ const mapSelectableControls = (discover) => { return [[typeSelect, catalogSelect, ...extraSelects], paginationInput]; }; -const useSelectableControls = (discover) => { - const selectableControls = React.useMemo(() => { - return mapSelectableControls(discover); +const useSelectableInputs = (discover) => { + const selectableInputs = React.useMemo(() => { + return mapSelectableInputs(discover); }, [discover]); - return selectableControls; + return selectableInputs; }; -module.exports = useSelectableControls; +module.exports = useSelectableInputs; From bb98e0cbab895d296840c32fee617ffb6f9ead41 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 21:53:28 +0200 Subject: [PATCH 314/442] pagination input label min width changed --- src/common/PaginationInput/styles.less | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/PaginationInput/styles.less b/src/common/PaginationInput/styles.less index d3a7ea39e..4a616a57e 100644 --- a/src/common/PaginationInput/styles.less +++ b/src/common/PaginationInput/styles.less @@ -25,9 +25,11 @@ .label { flex: none; + min-width: 1.2rem; max-width: 3rem; white-space: nowrap; text-overflow: ellipsis; + text-align: center; color: var(--color-surfacelighter); } } From 8f289d2f9e6d23c419878fdfd1bd1e859a6546f1 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 2 Dec 2019 21:54:51 +0200 Subject: [PATCH 315/442] images in preview optimized for fast switching --- src/common/MetaPreview/MetaPreview.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/MetaPreview/MetaPreview.js b/src/common/MetaPreview/MetaPreview.js index 0cce24fb1..9cd1b7d8e 100644 --- a/src/common/MetaPreview/MetaPreview.js +++ b/src/common/MetaPreview/MetaPreview.js @@ -74,6 +74,7 @@ const MetaPreview = ({ className, compact, name, logo, background, runtime, rele typeof background === 'string' && background.length > 0 ?
{' 0 ? {' Date: Tue, 3 Dec 2019 10:07:09 +0200 Subject: [PATCH 316/442] discover styles fixed for small screens --- src/routes/Discover/styles.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 7b0912711..b52902c52 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -198,7 +198,7 @@ .discover-container { .discover-content { grid-template-columns: 1fr; - grid-template-rows: fit-content(19rem) 1fr; + grid-template-rows: auto 1fr; grid-template-areas: "selectable-inputs-area" "catalog-content-area"; From b37c1b04c2ea5de80914b1fe1554c98ec9659a58 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 3 Dec 2019 10:30:25 +0200 Subject: [PATCH 317/442] pagination input icon styled separately --- src/common/PaginationInput/styles.less | 2 -- .../PaginationInput/SimplePaginationInput/styles.less | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/common/PaginationInput/styles.less b/src/common/PaginationInput/styles.less index 4a616a57e..2cd440034 100644 --- a/src/common/PaginationInput/styles.less +++ b/src/common/PaginationInput/styles.less @@ -10,8 +10,6 @@ .icon { display: block; - width: 40%; - height: 40%; fill: var(--color-surfacelighter); } } diff --git a/storybook/stories/PaginationInput/SimplePaginationInput/styles.less b/storybook/stories/PaginationInput/SimplePaginationInput/styles.less index 5625c9fc8..62035ebd1 100644 --- a/storybook/stories/PaginationInput/SimplePaginationInput/styles.less +++ b/storybook/stories/PaginationInput/SimplePaginationInput/styles.less @@ -1,6 +1,7 @@ :import('~stremio/common/PaginationInput/styles.less') { pagination-prev-button-container: prev-button-container; pagination-next-button-container: next-button-container; + pagination-button-icon: icon; } .pagination-input { @@ -15,5 +16,10 @@ .pagination-prev-button-container, .pagination-next-button-container { width: 3rem; height: 3rem; + + .pagination-button-icon { + width: 1rem; + height: 1rem; + } } } \ No newline at end of file From 6b273a2a3467139b4b3660ee97ccc7ac373bfe2d Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 3 Dec 2019 10:50:54 +0200 Subject: [PATCH 318/442] discover selectable-inputs styled --- src/routes/Discover/styles.less | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index b52902c52..b2ddb748d 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -7,6 +7,7 @@ :import('~stremio/common/PaginationInput/styles.less') { pagination-prev-button-container: prev-button-container; pagination-next-button-container: next-button-container; + pagination-button-icon: icon; } .discover-container { @@ -32,19 +33,18 @@ "catalog-content-area meta-preview-area"; .selectable-inputs-container { - --selectable-input-height: 3rem; grid-area: selectable-inputs-area; display: flex; flex-direction: row; - padding: 2rem; + padding: 1.5rem; overflow: visible; .select-input-container { flex-grow: 0; flex-shrink: 1; flex-basis: 15rem; - height: var(--selectable-input-height); - margin-right: 2rem; + height: 3rem; + margin-right: 1.5rem; &:nth-child(n+4) { display: none; @@ -65,12 +65,12 @@ display: none; align-items: center; justify-content: center; - width: var(--selectable-input-height); - height: var(--selectable-input-height); + width: 3rem; + height: 3rem; background-color: var(--color-backgroundlighter); &:not(:nth-last-child(2)) { - margin-right: 2rem; + margin-right: 1.5rem; } .filter-icon { @@ -87,12 +87,17 @@ .pagination-input-container { flex: none; - height: var(--selectable-input-height); + height: 3rem; background-color: var(--color-backgroundlighter); .pagination-prev-button-container, .pagination-next-button-container { - width: var(--selectable-input-height); - height: var(--selectable-input-height); + width: 3rem; + height: 3rem; + + .pagination-button-icon { + width: 1rem; + height: 1rem; + } } } } @@ -105,9 +110,9 @@ max-height: 100%; grid-auto-rows: max-content; align-items: center; - grid-gap: 2rem; - margin-right: 2rem; - padding: 0 2rem; + grid-gap: 1.5rem; + margin-right: 1.5rem; + padding: 0 1.5rem; overflow-y: auto; .meta-item { @@ -121,7 +126,7 @@ } .message-container { - padding: 0 2rem; + padding: 0 1.5rem; font-size: 2rem; color: var(--color-surfacelighter); } From 1603d31a3ed75af3637bc69a66d86f3435af0074 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 3 Dec 2019 12:04:56 +0200 Subject: [PATCH 319/442] selected type/catalog improved for duplicated catalog ids --- src/routes/Discover/useSelectableInputs.js | 71 +++++++++++----------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/src/routes/Discover/useSelectableInputs.js b/src/routes/Discover/useSelectableInputs.js index c33a2a300..818083c53 100644 --- a/src/routes/Discover/useSelectableInputs.js +++ b/src/routes/Discover/useSelectableInputs.js @@ -52,24 +52,27 @@ const getNextExtra = (prevExtra, extraProp, extraValue) => { }, []); }; +const equalWithouExtra = (request1, request2) => { + return request1.base === request2.base && + request1.path.resource === request2.path.resource && + request1.path.type_name === request2.path.type_name && + request1.path.id === request2.path.id; +}; + const mapSelectableInputs = (discover) => { - const selectedTransportUrl = discover.catalog_resource !== null ? - discover.catalog_resource.request.base + const selectedCatalogRequest = discover.catalog_resource !== null ? + discover.catalog_resource.request : - null; - const selectedTypeName = discover.catalog_resource !== null ? - discover.catalog_resource.request.path.type_name - : - null; - const selectedCatalogId = discover.catalog_resource !== null ? - discover.catalog_resource.request.path.id - : - null; - const selectedExtra = discover.catalog_resource !== null ? - discover.catalog_resource.request.path.extra - : - []; - const selectedPage = selectedExtra.reduce((selectedPage, [name, value]) => { + { + base: null, + path: { + resource: 'catalog', + id: null, + type_name: null, + extra: [] + } + }; + const requestedPage = selectedCatalogRequest.path.extra.reduce((requestedPage, [name, value]) => { if (name === SKIP_EXTRA.name) { const skip = parseInt(value); if (isFinite(skip)) { @@ -77,7 +80,7 @@ const mapSelectableInputs = (discover) => { } } - return selectedPage; + return requestedPage; }, 1); const typeSelect = { title: 'Select type', @@ -87,8 +90,8 @@ const mapSelectableInputs = (discover) => { label: name })), selected: discover.selectable.types - .filter(({ load_request: { path: { type_name } } }) => { - return type_name === selectedTypeName; + .filter(({ load_request }) => { + return equalWithouExtra(load_request, selectedCatalogRequest); }) .map(({ load_request }) => JSON.stringify(load_request)), onSelect: (event) => { @@ -103,8 +106,8 @@ const mapSelectableInputs = (discover) => { label: name })), selected: discover.selectable.catalogs - .filter(({ load_request: { path: { id } } }) => { - return id === selectedCatalogId; + .filter(({ load_request }) => { + return equalWithouExtra(load_request, selectedCatalogRequest); }) .map(({ load_request }) => JSON.stringify(load_request)), onSelect: (event) => { @@ -119,7 +122,7 @@ const mapSelectableInputs = (discover) => { value: option, label: option })); - const selected = selectedExtra + const selected = selectedCatalogRequest.path.extra .reduce((selected, [name, value]) => { if (name === extra.name) { selected = selected @@ -135,20 +138,20 @@ const mapSelectableInputs = (discover) => { null; const onSelect = (event) => { navigateWithLoadRequest({ - base: selectedTransportUrl, + base: selectedCatalogRequest.base, path: { resource: 'catalog', - type_name: selectedTypeName, - id: selectedCatalogId, - extra: getNextExtra(selectedExtra, extra, event.value) + type_name: selectedCatalogRequest.path.type_name, + id: selectedCatalogRequest.path.id, + extra: getNextExtra(selectedCatalogRequest.path.extra, extra, event.value) } }); }; return { title, options, selected, renderLabelText, onSelect }; }); - const paginationInput = discover.selectable.has_prev_page || discover.selectable.has_next_page || selectedExtra.some(([name]) => name === 'skip') ? + const paginationInput = discover.selectable.has_prev_page || discover.selectable.has_next_page || selectedCatalogRequest.path.extra.some(([name]) => name === 'skip') ? { - label: String(selectedPage), + label: String(requestedPage), onSelect: (event) => { if (event.value === 'prev' && !discover.selectable.has_prev_page || event.value === 'next' && !discover.selectable.has_next_page) { @@ -156,16 +159,16 @@ const mapSelectableInputs = (discover) => { } const nextValue = event.value === 'next' ? - String(selectedPage * CATALOG_PAGE_SIZE) + String(requestedPage * CATALOG_PAGE_SIZE) : - String((selectedPage - 2) * CATALOG_PAGE_SIZE); + String((requestedPage - 2) * CATALOG_PAGE_SIZE); navigateWithLoadRequest({ - base: selectedTransportUrl, + base: selectedCatalogRequest.base, path: { resource: 'catalog', - type_name: selectedTypeName, - id: selectedCatalogId, - extra: getNextExtra(selectedExtra, SKIP_EXTRA, nextValue) + type_name: selectedCatalogRequest.path.type_name, + id: selectedCatalogRequest.path.id, + extra: getNextExtra(selectedCatalogRequest.path.extra, SKIP_EXTRA, nextValue) } }); } From 4ed55625bf0f561ba96e133c1945fe6d49e596f4 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 3 Dec 2019 18:26:58 +0200 Subject: [PATCH 320/442] getMetaItemAtIndex more strict --- src/routes/Discover/Discover.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 57cd655c5..fc9c1b953 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -8,7 +8,8 @@ const useSelectableInputs = require('./useSelectableInputs'); const styles = require('./styles'); const getMetaItemAtIndex = (catalog_resource, index) => { - return isFinite(index) && + return index !== null && + isFinite(index) && catalog_resource !== null && catalog_resource.content.type === 'Ready' && catalog_resource.content.content[index] ? From f2607b24542305575454a24b72fe8cdf205282b3 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 3 Dec 2019 18:27:10 +0200 Subject: [PATCH 321/442] selected type fixed --- src/routes/Discover/useSelectableInputs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Discover/useSelectableInputs.js b/src/routes/Discover/useSelectableInputs.js index 818083c53..f2d3ebf0c 100644 --- a/src/routes/Discover/useSelectableInputs.js +++ b/src/routes/Discover/useSelectableInputs.js @@ -90,8 +90,8 @@ const mapSelectableInputs = (discover) => { label: name })), selected: discover.selectable.types - .filter(({ load_request }) => { - return equalWithouExtra(load_request, selectedCatalogRequest); + .filter(({ load_request: { path: { type_name } } }) => { + return type_name === selectedCatalogRequest.path.type_name; }) .map(({ load_request }) => JSON.stringify(load_request)), onSelect: (event) => { From b6c1f142ccb0da3c08cec261f341d7e2acc7ecf5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 4 Dec 2019 16:35:21 +0200 Subject: [PATCH 322/442] Search adapted to changes in core --- src/common/MetaRow/MetaRow.js | 17 ++-- .../MetaRowPlaceholder/MetaRowPlaceholder.js | 7 +- src/routes/Search/Search.js | 95 +++++++++---------- src/routes/Search/styles.less | 19 ++-- src/routes/Search/useSearch.js | 35 ++++--- 5 files changed, 79 insertions(+), 94 deletions(-) diff --git a/src/common/MetaRow/MetaRow.js b/src/common/MetaRow/MetaRow.js index b416207a3..90008aef9 100644 --- a/src/common/MetaRow/MetaRow.js +++ b/src/common/MetaRow/MetaRow.js @@ -7,9 +7,8 @@ const MetaItem = require('stremio/common/MetaItem'); const MetaRowPlaceholder = require('./MetaRowPlaceholder'); const styles = require('./styles'); -const MetaRow = ({ className, title, message, items, maximumItemsCount, itemMenuOptions, catalogHref }) => { - maximumItemsCount = maximumItemsCount !== null && isFinite(maximumItemsCount) ? maximumItemsCount : 20; - items = Array.isArray(items) ? items.slice(0, maximumItemsCount) : []; +const MetaRow = ({ className, title, message, items, limit, href }) => { + items = Array.isArray(items) ? items.slice(0, limit) : []; return (
{ @@ -28,17 +27,14 @@ const MetaRow = ({ className, title, message, items, maximumItemsCount, itemMenu ))} - {Array(Math.max(maximumItemsCount - items.length, 0)).fill(null).map((_, index) => ( + {Array(limit - items.length).fill(null).map((_, index) => (
))}
- @@ -57,9 +53,8 @@ MetaRow.propTypes = { items: PropTypes.arrayOf(PropTypes.shape({ posterShape: PropTypes.string })), - maximumItemsCount: PropTypes.number, - itemMenuOptions: PropTypes.any, - catalogHref: PropTypes.string + limit: PropTypes.number.isRequired, + href: PropTypes.string }; module.exports = MetaRow; diff --git a/src/common/MetaRow/MetaRowPlaceholder/MetaRowPlaceholder.js b/src/common/MetaRow/MetaRowPlaceholder/MetaRowPlaceholder.js index a6d3bda30..3c219aecd 100644 --- a/src/common/MetaRow/MetaRowPlaceholder/MetaRowPlaceholder.js +++ b/src/common/MetaRow/MetaRowPlaceholder/MetaRowPlaceholder.js @@ -3,13 +3,12 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const styles = require('./styles'); -const MetaRowPlaceholder = ({ className, title, maximumItemsCount }) => { - maximumItemsCount = maximumItemsCount !== null && isFinite(maximumItemsCount) ? maximumItemsCount : 20; +const MetaRowPlaceholder = ({ className, title, limit }) => { return (
{title}
- {Array(maximumItemsCount).fill(null).map((_, index) => ( + {Array(limit).fill(null).map((_, index) => (
@@ -24,7 +23,7 @@ const MetaRowPlaceholder = ({ className, title, maximumItemsCount }) => { MetaRowPlaceholder.propTypes = { className: PropTypes.string, title: PropTypes.string, - maximumItemsCount: PropTypes.number + limit: PropTypes.number.isRequired }; module.exports = MetaRowPlaceholder; diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index b91fbea06..e0468d42d 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -5,62 +5,13 @@ const useSearch = require('./useSearch'); const styles = require('./styles'); const Search = ({ queryParams }) => { - const search = useSearch(queryParams); - const searchSelected = React.useMemo(() => { - return search.selected.some(([name, value]) => name === 'search' && value.length > 0) - }, [search.selected]); + const { selected, catalog_resources } = useSearch(queryParams); return (
{ - searchSelected ? - search.items_groups && search.items_groups.length > 0 ? - search.items_groups.some(group => group.content.type !== 'Err') ? - search.items_groups.map(({ href, request, content }, index) => { - switch (content.type) { - case 'Ready': - return ( - - ); - case 'Err': - return ( - - ); - case 'Loading': - return ( - - ); - } - }) - : -
-
-
No metadata was found
-
-
- : -
-
-
No addons were requested for metadata
-
-
- : + selected === null || selected.extra.every(([name]) => name !== 'search') ?
@@ -71,6 +22,48 @@ const Search = ({ queryParams }) => {
Search for actors, directors and writers
+ : + catalog_resources.length === 0 ? +
+
+
No addons were requested for catalogs
+
+
+ : + catalog_resources.map((catalog, index) => { + switch (catalog.content.type) { + case 'Ready': + return ( + + ); + case 'Err': + return ( + + ); + case 'Loading': + return ( + + ); + } + }) }
diff --git a/src/routes/Search/styles.less b/src/routes/Search/styles.less index c5f3308a9..662baf5d4 100644 --- a/src/routes/Search/styles.less +++ b/src/routes/Search/styles.less @@ -42,6 +42,7 @@ flex-direction: row; align-items: flex-start; justify-content: center; + max-height: calc(100% - 10rem); margin: 5rem; .message-content { @@ -51,12 +52,16 @@ align-items: center; justify-content: center; + &:not(:first-child) { + margin-left: 5rem; + } + .icon { flex: none; width: 6rem; height: 6rem; margin-bottom: 2rem; - fill: var(--color-surfacelighter40); + fill: var(--color-surfacelighter80); } .label { @@ -64,22 +69,18 @@ flex-shrink: 1; flex-basis: auto; font-size: 1.2rem; - color: var(--color-surfacelighter40); + color: var(--color-surfacelighter80); text-align: center; } - - &:not(:last-child) { - margin-right: 5rem;; - } } } } } @media only screen and (min-width: @large) { - .board-container { - .board-content { - .board-row, .board-row-placeholder { + .search-container { + .search-content { + .search-row, .search-row-placeholder { .meta-item, .meta-item-placeholder { &:nth-child(n+9) { display: none; diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 331a34143..74f6c6130 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -2,46 +2,43 @@ const React = require('react'); const { useServices } = require('stremio/services'); const mapSearchState = (state) => { - const query = state.search.selected.reduceRight((query, [name, value]) => { - if (name === 'search') { - return value; - } - return query; - }, ''); + const queryString = state.search.selected !== null ? + new URLSearchParams(state.search.selected.extra).toString() + : + ''; const selected = state.search.selected; - const items_groups = state.search.items_groups.map((group) => { - group.href = `#/discover/${encodeURIComponent(group.request.base)}/${encodeURIComponent(group.request.path.id)}/${encodeURIComponent(group.request.path.type_name)}?search=${query}`; - return group; + const catalog_resources = state.search.catalog_resources.map((catalog_resource) => { + catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}?${queryString}`; + return catalog_resource; }); - return { selected, items_groups }; + return { selected, catalog_resources }; }; const useSearch = (queryParams) => { const { core } = useServices(); - const [search, setSearch] = React.useState(() => { - const state = core.getState(); - const search = mapSearchState(state); - return search; - }); - React.useEffect(() => { + const [search, setSearch] = React.useState(() => ({ + selected: null, + catalog_resources: [] + })); + React.useLayoutEffect(() => { const onNewState = () => { const state = core.getState(); const search = mapSearchState(state); setSearch(search); }; core.on('NewModel', onNewState); - if (queryParams.has('search')) { + if (queryParams.has('search') && queryParams.get('search').length > 0) { core.dispatch({ action: 'Load', args: { - load: 'CatalogsGrouped', + load: 'CatalogsWithExtra', args: { extra: [ ['search', queryParams.get('search')] ] } } - }); + }, 'Search'); } return () => { core.off('NewModel', onNewState); From 371a42c87adcebac5a84195d4eba615cfe0a3608 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 4 Dec 2019 19:46:10 +0200 Subject: [PATCH 323/442] board adapted to changes in CatalogsWithExtra --- .../NotificationsMenu/NotificationsMenu.js | 2 +- src/routes/Board/Board.js | 32 +++++++++------ src/routes/Board/useBoard.js | 41 +++++++++++++++++++ src/routes/Board/useCatalogs.js | 27 ------------ 4 files changed, 61 insertions(+), 41 deletions(-) create mode 100644 src/routes/Board/useBoard.js delete mode 100644 src/routes/Board/useCatalogs.js diff --git a/src/common/NavBar/NotificationsMenu/NotificationsMenu.js b/src/common/NavBar/NotificationsMenu/NotificationsMenu.js index e55d8a415..b0ea6d6d8 100644 --- a/src/common/NavBar/NotificationsMenu/NotificationsMenu.js +++ b/src/common/NavBar/NotificationsMenu/NotificationsMenu.js @@ -6,7 +6,7 @@ const Button = require('stremio/common/Button'); const Popup = require('stremio/common/Popup'); const NotificationsList = require('./NotificationsList'); const useNotifications = require('./useNotifications'); -const useCatalogs = require('stremio/routes/Board/useCatalogs'); +// const useCatalogs = require('stremio/routes/Board/useCatalogs'); const useBinaryState = require('stremio/common/useBinaryState'); const styles = require('./styles'); diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index 980b47f11..944339aa5 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -1,6 +1,6 @@ const React = require('react'); const { MainNavBar, MetaRow } = require('stremio/common'); -const useCatalogs = require('./useCatalogs'); +const useBoard = require('./useBoard'); const styles = require('./styles'); const CONTINUE_WATCHING_MENU = [ @@ -15,37 +15,43 @@ const CONTINUE_WATCHING_MENU = [ ]; const Board = () => { - const catalogs = useCatalogs(); + const { catalog_resources } = useBoard(); return (
- {catalogs.map(({ request, content }, index) => { - switch (content.type) { + {catalog_resources.map((catalog_resource, index) => { + const title = `${catalog_resource.addon_name} - ${catalog_resource.request.path.id} ${catalog_resource.request.path.type_name}`; + switch (catalog_resource.content.type) { case 'Ready': return ( ); - case 'Message': + case 'Err': + const message = `Error(${catalog_resource.content.content.type})${typeof catalog_resource.content.content.content === 'string' ? ` - ${catalog_resource.content.content.content}` : ''}`; return ( ); case 'Loading': return ( ); } diff --git a/src/routes/Board/useBoard.js b/src/routes/Board/useBoard.js new file mode 100644 index 000000000..96a5139e2 --- /dev/null +++ b/src/routes/Board/useBoard.js @@ -0,0 +1,41 @@ +const React = require('react'); +const { useServices } = require('stremio/services'); + +const mapBoardState = (state) => { + const selected = state.board.selected; + const catalog_resources = state.board.catalog_resources.map((catalog_resource) => { + catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}`; + return catalog_resource; + }); + return { selected, catalog_resources }; +}; + +const useBoard = () => { + const { core } = useServices(); + const [board, setBoard] = React.useState(() => { + const state = core.getState(); + const board = mapBoardState(state); + return board; + }); + React.useLayoutEffect(() => { + const onNewState = () => { + const state = core.getState(); + const board = mapBoardState(state); + setBoard(board); + }; + core.on('NewModel', onNewState); + core.dispatch({ + action: 'Load', + args: { + load: 'CatalogsWithExtra', + args: { extra: [] } + } + }, 'Board'); + return () => { + core.off('NewModel', onNewState); + }; + }, []); + return board; +}; + +module.exports = useBoard; diff --git a/src/routes/Board/useCatalogs.js b/src/routes/Board/useCatalogs.js deleted file mode 100644 index ce865f2d5..000000000 --- a/src/routes/Board/useCatalogs.js +++ /dev/null @@ -1,27 +0,0 @@ -const React = require('react'); -const { useServices } = require('stremio/services'); - -const useCatalogs = () => { - const [catalogs, setCatalogs] = React.useState([]); - const { core } = useServices(); - React.useEffect(() => { - const onNewState = () => { - const state = core.getState(); - setCatalogs(state.board.items_groups); - }; - core.on('NewModel', onNewState); - core.dispatch({ - action: 'Load', - args: { - load: 'CatalogsGrouped', - args: { extra: [] } - } - }); - return () => { - core.off('NewModel', onNewState); - }; - }, []); - return catalogs; -}; - -module.exports = useCatalogs; From fe71d5745c5c1e48bbff504ab4a14b223cc17190 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 4 Dec 2019 19:47:38 +0200 Subject: [PATCH 324/442] Search initial state fixed --- src/routes/Search/useSearch.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 74f6c6130..fff36be55 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -16,10 +16,11 @@ const mapSearchState = (state) => { const useSearch = (queryParams) => { const { core } = useServices(); - const [search, setSearch] = React.useState(() => ({ - selected: null, - catalog_resources: [] - })); + const [search, setSearch] = React.useState(() => { + const state = core.getState(); + const search = mapSearchState(state); + return search; + }); React.useLayoutEffect(() => { const onNewState = () => { const state = core.getState(); From 0fceb69e52598844bbfbb44227b2366df0188cf5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 4 Dec 2019 21:56:24 +0200 Subject: [PATCH 325/442] ContinueWatching added to Board --- src/routes/Board/Board.js | 17 +++++++++++-- src/routes/Board/useContinueWatching.js | 33 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 src/routes/Board/useContinueWatching.js diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index 944339aa5..e811b8d77 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -1,6 +1,7 @@ const React = require('react'); const { MainNavBar, MetaRow } = require('stremio/common'); const useBoard = require('./useBoard'); +const useContinueWatching = require('./useContinueWatching'); const styles = require('./styles'); const CONTINUE_WATCHING_MENU = [ @@ -15,12 +16,24 @@ const CONTINUE_WATCHING_MENU = [ ]; const Board = () => { - const { catalog_resources } = useBoard(); + const board = useBoard(); + const continueWatching = useContinueWatching(); return (
- {catalog_resources.map((catalog_resource, index) => { + { + continueWatching.lib_items.length > 0 ? + + : + null + } + {board.catalog_resources.map((catalog_resource, index) => { const title = `${catalog_resource.addon_name} - ${catalog_resource.request.path.id} ${catalog_resource.request.path.type_name}`; switch (catalog_resource.content.type) { case 'Ready': diff --git a/src/routes/Board/useContinueWatching.js b/src/routes/Board/useContinueWatching.js new file mode 100644 index 000000000..d076d3573 --- /dev/null +++ b/src/routes/Board/useContinueWatching.js @@ -0,0 +1,33 @@ +const React = require('react'); +const { useServices } = require('stremio/services'); + +const mapContinueWatchingState = (state) => { + const lib_items = state.continue_watching.lib_items.map((lib_item) => { + lib_item.href = `#/metadetails/${lib_item.type}/${lib_item._id}${lib_item.state.video_id !== null ? `/${lib_item.state.video_id}` : ''}`; + return lib_item; + }); + return { lib_items }; +}; + +const useContinueWatching = () => { + const { core } = useServices(); + const [continueWatching, setContinueWatching] = React.useState(() => { + const state = core.getState(); + const continueWatching = mapContinueWatchingState(state); + return continueWatching; + }); + React.useLayoutEffect(() => { + const onNewState = () => { + const state = core.getState(); + const continueWatching = mapContinueWatchingState(state); + setContinueWatching(continueWatching); + }; + core.on('NewModel', onNewState); + return () => { + core.off('NewModel', onNewState); + }; + }, []); + return continueWatching; +}; + +module.exports = useContinueWatching; From 48754b7aad9918784db16b3ae0e373be80e2b51d Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 09:58:55 +0200 Subject: [PATCH 326/442] see all button styled in route styles --- src/common/MetaRow/MetaRow.js | 17 ++-- .../MetaRowPlaceholder/MetaRowPlaceholder.js | 18 ++-- .../MetaRow/MetaRowPlaceholder/styles.less | 44 ++++----- src/common/MetaRow/styles.less | 97 +++++++++---------- src/routes/Board/styles.less | 6 ++ 5 files changed, 97 insertions(+), 85 deletions(-) diff --git a/src/common/MetaRow/MetaRow.js b/src/common/MetaRow/MetaRow.js index 90008aef9..8922a544e 100644 --- a/src/common/MetaRow/MetaRow.js +++ b/src/common/MetaRow/MetaRow.js @@ -21,7 +21,7 @@ const MetaRow = ({ className, title, message, items, limit, href }) => { typeof message === 'string' && message.length > 0 ?
{message}
: - +
{items.map((item, index) => ( {
))}
- - + { + typeof href === 'string' && href.length > 0 ? + + : + null + } +
}
); diff --git a/src/common/MetaRow/MetaRowPlaceholder/MetaRowPlaceholder.js b/src/common/MetaRow/MetaRowPlaceholder/MetaRowPlaceholder.js index 3c219aecd..57f6e4a33 100644 --- a/src/common/MetaRow/MetaRowPlaceholder/MetaRowPlaceholder.js +++ b/src/common/MetaRow/MetaRowPlaceholder/MetaRowPlaceholder.js @@ -7,15 +7,17 @@ const MetaRowPlaceholder = ({ className, title, limit }) => { return (
{title}
-
- {Array(limit).fill(null).map((_, index) => ( -
-
-
-
- ))} +
+
+ {Array(limit).fill(null).map((_, index) => ( +
+
+
+
+ ))} +
+
-
); }; diff --git a/src/common/MetaRow/MetaRowPlaceholder/styles.less b/src/common/MetaRow/MetaRowPlaceholder/styles.less index 8e563492c..3e74a0ba5 100644 --- a/src/common/MetaRow/MetaRowPlaceholder/styles.less +++ b/src/common/MetaRow/MetaRowPlaceholder/styles.less @@ -1,12 +1,5 @@ .meta-row-placeholder-container { - display: grid; - grid-template-columns: 6fr minmax(12rem, 1fr); - grid-template-areas: - "title-area title-area" - "meta-items-area see-all-area"; - .title-container { - grid-area: title-area; max-height: 2.4em; margin-bottom: 2rem; font-size: 1.5rem; @@ -18,29 +11,36 @@ } } - .meta-items-container { - grid-area: meta-items-area; + .content-container { display: flex; flex-direction: row; + align-items: stretch; - .meta-item { + .meta-items-container { flex: 1; - margin-right: 2rem; - background-color: var(--color-placeholder); + display: flex; + flex-direction: row; + align-items: stretch; - .poster-container { - padding-bottom: calc(100% * var(--poster-shape-ratio)); - } - - .title-bar-container { - height: 2.8rem; + .meta-item { + flex: 1; + margin-right: 2rem; background-color: var(--color-placeholder); + + .poster-container { + padding-bottom: calc(100% * var(--poster-shape-ratio)); + } + + .title-bar-container { + height: 2.8rem; + background-color: var(--color-placeholder); + } } } - } - .see-all-container { - grid-area: see-all-area; - background-color: var(--color-placeholder); + .see-all-container { + flex: none; + background-color: var(--color-placeholder); + } } } \ No newline at end of file diff --git a/src/common/MetaRow/styles.less b/src/common/MetaRow/styles.less index 277b7176b..e4292805a 100644 --- a/src/common/MetaRow/styles.less +++ b/src/common/MetaRow/styles.less @@ -1,14 +1,7 @@ .meta-row-container { - display: grid; - grid-template-columns: 6fr minmax(12rem, 1fr); - grid-template-areas: - "title-area title-area" - "message-area message-area" - "meta-items-area see-all-area"; overflow: visible; .title-container { - grid-area: title-area; max-height: 2.4em; margin-bottom: 2rem; font-size: 1.5rem; @@ -16,65 +9,71 @@ } .message-container { - grid-area: message-area; max-height: 3.6em; font-size: 1.3rem; color: var(--color-surfacelighter); } - .meta-items-container { - grid-area: meta-items-area; + .content-container { display: flex; flex-direction: row; align-items: stretch; overflow: visible; - .meta-item { - margin-right: 2rem; + .meta-items-container { + flex: 1; + display: flex; + flex-direction: row; + align-items: stretch; + overflow: visible; - &.poster-shape-poster { - flex: calc(1 / var(--poster-shape-ratio)); - } + .meta-item { + margin-right: 2rem; - &.poster-shape-square { - flex: 1; - } + &.poster-shape-poster { + flex: calc(1 / var(--poster-shape-ratio)); + } - &.poster-shape-landscape { - flex: calc(1 / var(--landscape-shape-ratio)); + &.poster-shape-square { + flex: 1; + } + + &.poster-shape-landscape { + flex: calc(1 / var(--landscape-shape-ratio)); + } } } - } - .see-all-container { - grid-area: see-all-area; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - padding: 1rem; - background-color: var(--color-backgroundlight); - - &:hover, &:focus { - background-color: var(--color-backgroundlighter); - } - - .label { - flex-grow: 0; - flex-shrink: 1; - flex-basis: auto; - max-height: 2.4em; - font-size: 1.2rem; - text-align: center; - color: var(--color-surfacelighter); - } - - .icon { + .see-all-container { flex: none; - width: 1.3rem; - height: 1.3rem; - margin-left: 0.3rem; - fill: var(--color-surfacelighter); + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + padding: 1rem; + background-color: var(--color-backgroundlight); + + &:hover, &:focus { + background-color: var(--color-backgroundlighter); + } + + .label { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + max-height: 2.4em; + font-size: 1.2rem; + text-align: center; + color: var(--color-surfacelighter); + } + + .icon { + flex: none; + width: 1.3rem; + height: 1.3rem; + margin-left: 0.3rem; + fill: var(--color-surfacelighter); + } } } } \ No newline at end of file diff --git a/src/routes/Board/styles.less b/src/routes/Board/styles.less index 3e9d06859..99c0b4e58 100644 --- a/src/routes/Board/styles.less +++ b/src/routes/Board/styles.less @@ -2,10 +2,12 @@ :import('~stremio/common/MetaRow/styles.less') { meta-item: meta-item; + see-all-container: see-all-container; } :import('~stremio/common/MetaRow/MetaRowPlaceholder/styles.less') { meta-item-placeholder: meta-item; + see-all-container-placeholder: see-all-container; } .board-container { @@ -35,6 +37,10 @@ &:last-child { margin-bottom: 2rem; } + + .see-all-container, .see-all-container-placeholder { + width: 12rem; + } } } } From 8bb1449d1e87f46150e61c6b5b2507450db32a61 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 09:59:36 +0200 Subject: [PATCH 327/442] variable names in search renamed by convention --- src/routes/Search/Search.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index e0468d42d..f76ea5c05 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -5,13 +5,13 @@ const useSearch = require('./useSearch'); const styles = require('./styles'); const Search = ({ queryParams }) => { - const { selected, catalog_resources } = useSearch(queryParams); + const search = useSearch(queryParams); return (
{ - selected === null || selected.extra.every(([name]) => name !== 'search') ? + search.selected === null || search.selected.extra.every(([name]) => name !== 'search') ?
@@ -23,23 +23,23 @@ const Search = ({ queryParams }) => {
: - catalog_resources.length === 0 ? + search.catalog_resources.length === 0 ?
No addons were requested for catalogs
: - catalog_resources.map((catalog, index) => { - switch (catalog.content.type) { + search.catalog_resources.map((catalog_resource, index) => { + switch (catalog_resource.content.type) { case 'Ready': return ( ); @@ -48,8 +48,8 @@ const Search = ({ queryParams }) => { ); @@ -58,7 +58,7 @@ const Search = ({ queryParams }) => { ); From bd9012cad60cb9a9da28a1661c9acac65936ffcf Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 10:02:10 +0200 Subject: [PATCH 328/442] see all button styled in search --- src/routes/Search/styles.less | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/routes/Search/styles.less b/src/routes/Search/styles.less index 662baf5d4..565cc3a94 100644 --- a/src/routes/Search/styles.less +++ b/src/routes/Search/styles.less @@ -2,10 +2,12 @@ :import('~stremio/common/MetaRow/styles.less') { meta-item: meta-item; + see-all-container: see-all-container; } :import('~stremio/common/MetaRow/MetaRowPlaceholder/styles.less') { meta-item-placeholder: meta-item; + see-all-container-placeholder: see-all-container; } .search-container { @@ -35,6 +37,10 @@ &:last-child { margin-bottom: 2rem; } + + .see-all-container, .see-all-container-placeholder { + width: 12rem; + } } .message-container { From ee1c00748ebaa8b6a1d5369e09537c8f63003606 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 10:35:14 +0200 Subject: [PATCH 329/442] Intro validations fixed --- .../Intro/ConsentCheckbox/ConsentCheckbox.js | 4 ++ .../CredentialsTextInput.js | 5 -- src/routes/Intro/Intro.js | 50 ++++++++++++------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js b/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js index 96d2daca3..fe1898b4e 100644 --- a/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js +++ b/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js @@ -6,6 +6,10 @@ const styles = require('./styles'); const ConsentCheckbox = React.forwardRef(({ className, checked, label, link, href, toggle, ...props }, ref) => { const checkboxOnClick = React.useCallback((event) => { + if (typeof props.onClick === 'function') { + props.onClick(event); + } + if (!event.nativeEvent.togglePrevented && typeof toggle === 'function') { toggle(event); } diff --git a/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js b/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js index 942b7a7f5..d3c7696cf 100644 --- a/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js +++ b/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js @@ -1,5 +1,4 @@ const React = require('react'); -const PropTypes = require('prop-types'); const { TextInput } = require('stremio/common'); const CredentialsTextInput = React.forwardRef((props, ref) => { @@ -24,8 +23,4 @@ const CredentialsTextInput = React.forwardRef((props, ref) => { CredentialsTextInput.displayName = 'CredentialsTextInput'; -CredentialsTextInput.propTYpes = { - onKeyDown: PropTypes.func -}; - module.exports = CredentialsTextInput; diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index beb35e26d..6b05700ab 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -9,6 +9,7 @@ const ConsentCheckbox = require('./ConsentCheckbox'); const styles = require('./styles'); const SIGNUP_FORM = 'signup'; +const LOGIN_FORM = 'login'; const Intro = ({ queryParams }) => { const { core } = useServices(); @@ -59,7 +60,7 @@ const Intro = ({ queryParams }) => { } }, { - form: queryParams.get('form'), + form: [LOGIN_FORM, SIGNUP_FORM].includes(queryParams.get('form')) ? queryParams.get('form') : SIGNUP_FORM, email: '', password: '', confirmPassword: '', @@ -71,21 +72,24 @@ const Intro = ({ queryParams }) => { ); React.useEffect(() => { const onEvent = ({ event, args }) => { - if (event === 'CtxActionErr') { - dispatch({ type: 'error', error: args[1].args.message }); - } - if (event === 'CtxChanged') { - const state = core.getState(); - if (state.ctx.content.auth !== null) { - window.location.replace('/'); - } + switch (event) { + case 'CtxActionErr': + const [_action, error] = args; + dispatch({ type: 'error', error: error.args.message }); + case 'CtxChanged': + const state = core.getState(); + if (state.ctx.content.auth !== null) { + window.location.replace('#/'); + } } }; - core.on('Event', onEvent); + if (routeFocused) { + core.on('Event', onEvent); + } return () => { core.off('Event', onEvent); }; - }, []); + }, [routeFocused]); const loginWithFacebook = React.useCallback(() => { FB.login((response) => { if (response.status === 'connected') { @@ -120,7 +124,7 @@ const Intro = ({ queryParams }) => { dispatch({ type: 'error', error: 'Invalid email' }); return; } - if (state.password.length === 0) { + if (typeof state.password !== 'string' || state.password.length === 0) { dispatch({ type: 'error', error: 'Invalid password' }); return; } @@ -146,9 +150,21 @@ const Intro = ({ queryParams }) => { userOp: 'Logout' } }); - location = '#/'; + window.location.replace('#/'); }, [state.termsAccepted]); const signup = React.useCallback(() => { + if (typeof state.email !== 'string' || state.email.length === 0) { + dispatch({ type: 'error', error: 'Invalid email' }); + return; + } + if (typeof state.password !== 'string' || state.password.length === 0) { + dispatch({ type: 'error', error: 'Invalid password' }); + return; + } + if (state.password !== state.confirmPassword) { + dispatch({ type: 'error', error: 'Passwords do not match' }); + return; + } if (!state.termsAccepted) { dispatch({ type: 'error', error: 'You must accept the Terms of Service' }); return; @@ -157,10 +173,6 @@ const Intro = ({ queryParams }) => { dispatch({ type: 'error', error: 'You must accept the Privacy Policy' }); return; } - if (state.password !== state.confirmPassword) { - dispatch({ type: 'error', error: 'Passwords do not match' }); - return; - } core.dispatch({ action: 'UserOp', args: { @@ -223,7 +235,9 @@ const Intro = ({ queryParams }) => { dispatch({ type: 'toggle-checkbox', name: 'marketingAccepted' }); }, []); React.useEffect(() => { - dispatch({ type: 'set-form', form: queryParams.get('form') }); + if ([LOGIN_FORM, SIGNUP_FORM].includes(queryParams.get('form'))) { + dispatch({ type: 'set-form', form: queryParams.get('form') }); + } }, [queryParams]); React.useEffect(() => { if (typeof state.error === 'string' && state.error.length > 0) { From c808f3e6d074eb03833dde2ede1fc8b04ebdcba7 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 10:39:26 +0200 Subject: [PATCH 330/442] lodash.throttle installed --- package.json | 1 + yarn.lock | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 184d7c8d0..5d789a88f 100755 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "hat": "0.0.3", "lodash.debounce": "4.0.8", "lodash.isequal": "4.5.0", + "lodash.throttle": "4.1.1", "prop-types": "15.7.2", "react": "16.11.0", "react-dom": "16.11.0", diff --git a/yarn.lock b/yarn.lock index 96097aa20..f02c93167 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5964,7 +5964,7 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.throttle@^4.1.1: +lodash.throttle@4.1.1, lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= From 53f71f0f76e9d62dfdacf3830fbde87334df2258 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 11:38:53 +0200 Subject: [PATCH 331/442] spread used meta item props in meta row --- src/common/MetaRow/MetaRow.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/common/MetaRow/MetaRow.js b/src/common/MetaRow/MetaRow.js index 8922a544e..d66991038 100644 --- a/src/common/MetaRow/MetaRow.js +++ b/src/common/MetaRow/MetaRow.js @@ -23,11 +23,20 @@ const MetaRow = ({ className, title, message, items, limit, href }) => { :
- {items.map((item, index) => ( + {items.map(({ type, name, poster, posterShape, playIcon, progress, menuOptions, dataset, onSelect, menuOptionOnSelect }, index) => ( ))} {Array(limit - items.length).fill(null).map((_, index) => ( From 5cb9c905eb146f262b3cb06b16faf9b5cf02b611 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 11:45:19 +0200 Subject: [PATCH 332/442] core.getState spead arguments --- src/services/Core/Core.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/Core/Core.js b/src/services/Core/Core.js index 547faad49..73a4b23f3 100644 --- a/src/services/Core/Core.js +++ b/src/services/Core/Core.js @@ -66,12 +66,12 @@ function Core() { args: action }); } - function getState() { + function getState(...args) { if (!active) { return {}; } - return containerService.get_state(); + return containerService.get_state(...args); } Object.defineProperties(this, { From 0c51fef3420523851a594a0d03fa794c2da67838 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 11:50:25 +0200 Subject: [PATCH 333/442] containerService renamed to stremio core --- src/services/Core/Core.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/Core/Core.js b/src/services/Core/Core.js index 73a4b23f3..ee6dbcc21 100644 --- a/src/services/Core/Core.js +++ b/src/services/Core/Core.js @@ -1,11 +1,11 @@ const EventEmitter = require('events'); -const { default: init, ContainerService } = require('stremio-core-web'); +const { default: init, StremioCoreWeb } = require('stremio-core-web'); function Core() { let active = false; let error = null; let starting = false; - let containerService = null; + let stremio_core = null; let events = new EventEmitter(); events.on('error', () => { }); @@ -21,7 +21,7 @@ function Core() { init() .then(() => { if (starting) { - containerService = new ContainerService(({ name, args } = {}) => { + stremio_core = new StremioCoreWeb(({ name, args } = {}) => { if (active) { try { events.emit(name, args); @@ -47,7 +47,7 @@ function Core() { active = false; error = null; starting = false; - containerService = null; + stremio_core = null; onStateChanged(); } function on(name, listener) { @@ -61,7 +61,7 @@ function Core() { return; } - containerService.dispatch({ + stremio_core.dispatch({ model, args: action }); @@ -71,7 +71,7 @@ function Core() { return {}; } - return containerService.get_state(...args); + return stremio_core.get_state(...args); } Object.defineProperties(this, { From a597e00abab69b53b746dcd8e81f12f74b61909a Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 12:36:48 +0200 Subject: [PATCH 334/442] Core getState/dispatch adapted to changes in core-web --- src/services/Core/Core.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/services/Core/Core.js b/src/services/Core/Core.js index ee6dbcc21..739d3b949 100644 --- a/src/services/Core/Core.js +++ b/src/services/Core/Core.js @@ -56,22 +56,19 @@ function Core() { function off(name, listener) { events.off(name, listener); } - function dispatch(action, model = 'All') { + function dispatch(action, model) { if (!active) { return; } - stremio_core.dispatch({ - model, - args: action - }); + stremio_core.dispatch(action, model); } - function getState(...args) { + function getState(model) { if (!active) { return {}; } - return stremio_core.get_state(...args); + return stremio_core.get_state(model); } Object.defineProperties(this, { From b4f5477678436f3432008fd2ff79ff31e58babb2 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 13:30:16 +0200 Subject: [PATCH 335/442] useDeepEqualState hook implemented --- src/common/index.js | 2 ++ src/common/useDeepEqualState.js | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/common/useDeepEqualState.js diff --git a/src/common/index.js b/src/common/index.js index 320a614d1..f8052ba47 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -18,6 +18,7 @@ const TextInput = require('./TextInput'); const routesRegexp = require('./routesRegexp'); const useAnimationFrame = require('./useAnimationFrame'); const useBinaryState = require('./useBinaryState'); +const useDeepEqualState = require('./useDeepEqualState'); const useFullscreen = require('./useFullscreen'); const useInLibrary = require('./useInLibrary'); const useLiveRef = require('./useLiveRef'); @@ -47,6 +48,7 @@ module.exports = { routesRegexp, useAnimationFrame, useBinaryState, + useDeepEqualState, useFullscreen, useInLibrary, useLiveRef, diff --git a/src/common/useDeepEqualState.js b/src/common/useDeepEqualState.js new file mode 100644 index 000000000..8adf750b5 --- /dev/null +++ b/src/common/useDeepEqualState.js @@ -0,0 +1,13 @@ +const React = require('react'); +const isEqual = require('lodash.isequal'); + +const useDeepEqualState = (initialState) => { + return React.useReducer((prevState, nextState) => { + return isEqual(prevState, nextState) ? + prevState + : + nextState; + }, initialState); +}; + +module.exports = useDeepEqualState; From 9c0368c7d8ba048517857394049707279edeb6ae Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 13:47:01 +0200 Subject: [PATCH 336/442] board model entry name changed --- src/routes/Board/useBoard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Board/useBoard.js b/src/routes/Board/useBoard.js index 96a5139e2..829d5543a 100644 --- a/src/routes/Board/useBoard.js +++ b/src/routes/Board/useBoard.js @@ -30,7 +30,7 @@ const useBoard = () => { load: 'CatalogsWithExtra', args: { extra: [] } } - }, 'Board'); + }, 'board'); return () => { core.off('NewModel', onNewState); }; From ca8e8e85cc37d3cdc3626b705c891d1202d4480c Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 14:58:10 +0200 Subject: [PATCH 337/442] useDeepEqualState mimic useState api --- src/common/useDeepEqualState.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/common/useDeepEqualState.js b/src/common/useDeepEqualState.js index 8adf750b5..1dc59e367 100644 --- a/src/common/useDeepEqualState.js +++ b/src/common/useDeepEqualState.js @@ -2,12 +2,21 @@ const React = require('react'); const isEqual = require('lodash.isequal'); const useDeepEqualState = (initialState) => { - return React.useReducer((prevState, nextState) => { - return isEqual(prevState, nextState) ? - prevState - : - nextState; - }, initialState); + return React.useReducer( + (prevState, nextState) => { + return isEqual(prevState, nextState) ? + prevState + : + nextState; + }, + undefined, + () => { + return typeof initialState === 'function' ? + initialState() + : + initialState; + } + ); }; module.exports = useDeepEqualState; From 984b045cedc2c5f6e4466d190de6dfdfe7f3463d Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 16:16:58 +0200 Subject: [PATCH 338/442] generic useModelState hook implemented --- src/common/index.js | 2 ++ src/common/useModelState.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/common/useModelState.js diff --git a/src/common/index.js b/src/common/index.js index f8052ba47..e1d2437a8 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -23,6 +23,7 @@ const useFullscreen = require('./useFullscreen'); const useInLibrary = require('./useInLibrary'); const useLiveRef = require('./useLiveRef'); const useLocationHash = require('./useLocationHash'); +const useModelState = require('./useModelState'); const useRouteActive = require('./useRouteActive'); const useSpreadState = require('./useSpreadState'); const useUser = require('./useUser'); @@ -53,6 +54,7 @@ module.exports = { useInLibrary, useLiveRef, useLocationHash, + useModelState, useRouteActive, useSpreadState, useUser diff --git a/src/common/useModelState.js b/src/common/useModelState.js new file mode 100644 index 000000000..3393bbbd2 --- /dev/null +++ b/src/common/useModelState.js @@ -0,0 +1,32 @@ +const React = require('react'); +const throttle = require('lodash.throttle'); +const { useRouteFocused } = require('stremio-router'); +const { useServices } = require('stremio/services'); +const useDeepEqualState = require('stremio/common/useDeepEqualState'); + +const useModelState = ({ model, action, timeout, map, init }) => { + const modelRef = React.useRef(model); + const { core } = useServices(); + const routeFocused = useRouteFocused(); + const [state, setState] = useDeepEqualState(init); + React.useLayoutEffect(() => { + core.dispatch(action, modelRef.current); + }, [action]); + React.useLayoutEffect(() => { + const onNewState = throttle(() => { + const state = core.getState(modelRef.current); + setState(typeof map === 'function' ? map(state) : state); + }, timeout); + if (routeFocused) { + core.on('NewState', onNewState); + onNewState.call(); + } + return () => { + onNewState.cancel(); + core.off('NewState', onNewState); + }; + }, [routeFocused]); + return state; +}; + +module.exports = useModelState; From 8080f2e72e4a5c4557d2c388278c7c4b54cb953a Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 16:19:09 +0200 Subject: [PATCH 339/442] useModelState integrated in useBoard --- src/routes/Board/useBoard.js | 50 ++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/routes/Board/useBoard.js b/src/routes/Board/useBoard.js index 829d5543a..ac1b3ca33 100644 --- a/src/routes/Board/useBoard.js +++ b/src/routes/Board/useBoard.js @@ -1,9 +1,14 @@ const React = require('react'); -const { useServices } = require('stremio/services'); +const { useModelState } = require('stremio/common'); -const mapBoardState = (state) => { - const selected = state.board.selected; - const catalog_resources = state.board.catalog_resources.map((catalog_resource) => { +const initBoardState = () => ({ + selected: null, + catalog_resources: [] +}); + +const mapBoardState = (board) => { + const selected = board.selected; + const catalog_resources = board.catalog_resources.map((catalog_resource) => { catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}`; return catalog_resource; }); @@ -11,31 +16,20 @@ const mapBoardState = (state) => { }; const useBoard = () => { - const { core } = useServices(); - const [board, setBoard] = React.useState(() => { - const state = core.getState(); - const board = mapBoardState(state); - return board; + const loadBoardAction = React.useMemo(() => ({ + action: 'Load', + args: { + load: 'CatalogsWithExtra', + args: { extra: [] } + } + }), []); + return useModelState({ + model: 'board', + action: loadBoardAction, + timeout: 1000, + map: mapBoardState, + init: initBoardState }); - React.useLayoutEffect(() => { - const onNewState = () => { - const state = core.getState(); - const board = mapBoardState(state); - setBoard(board); - }; - core.on('NewModel', onNewState); - core.dispatch({ - action: 'Load', - args: { - load: 'CatalogsWithExtra', - args: { extra: [] } - } - }, 'board'); - return () => { - core.off('NewModel', onNewState); - }; - }, []); - return board; }; module.exports = useBoard; From c8c18eb1bfcb9e84b799a413de3afbeb5bfce862 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 16:25:49 +0200 Subject: [PATCH 340/442] useModelState integrated in useContinueWatching --- src/routes/Board/useContinueWatching.js | 34 ++++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/routes/Board/useContinueWatching.js b/src/routes/Board/useContinueWatching.js index d076d3573..77183b4c6 100644 --- a/src/routes/Board/useContinueWatching.js +++ b/src/routes/Board/useContinueWatching.js @@ -1,8 +1,11 @@ -const React = require('react'); -const { useServices } = require('stremio/services'); +const { useModelState } = require('stremio/common'); -const mapContinueWatchingState = (state) => { - const lib_items = state.continue_watching.lib_items.map((lib_item) => { +const initContinueWatchingState = () => ({ + lib_items: [] +}); + +const mapContinueWatchingState = (continue_watching) => { + const lib_items = continue_watching.lib_items.map((lib_item) => { lib_item.href = `#/metadetails/${lib_item.type}/${lib_item._id}${lib_item.state.video_id !== null ? `/${lib_item.state.video_id}` : ''}`; return lib_item; }); @@ -10,24 +13,13 @@ const mapContinueWatchingState = (state) => { }; const useContinueWatching = () => { - const { core } = useServices(); - const [continueWatching, setContinueWatching] = React.useState(() => { - const state = core.getState(); - const continueWatching = mapContinueWatchingState(state); - return continueWatching; + return useModelState({ + model: 'continue_watching', + action: null, + timeout: 5000, + map: mapContinueWatchingState, + init: initContinueWatchingState }); - React.useLayoutEffect(() => { - const onNewState = () => { - const state = core.getState(); - const continueWatching = mapContinueWatchingState(state); - setContinueWatching(continueWatching); - }; - core.on('NewModel', onNewState); - return () => { - core.off('NewModel', onNewState); - }; - }, []); - return continueWatching; }; module.exports = useContinueWatching; From 756d4842ddc5328335303af0e89be8014cad09ca Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 16:37:34 +0200 Subject: [PATCH 341/442] metaItem href fixed in board --- src/common/MetaRow/MetaRow.js | 15 +++------------ src/routes/Board/useBoard.js | 7 +++++++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/common/MetaRow/MetaRow.js b/src/common/MetaRow/MetaRow.js index d66991038..8922a544e 100644 --- a/src/common/MetaRow/MetaRow.js +++ b/src/common/MetaRow/MetaRow.js @@ -23,20 +23,11 @@ const MetaRow = ({ className, title, message, items, limit, href }) => { :
- {items.map(({ type, name, poster, posterShape, playIcon, progress, menuOptions, dataset, onSelect, menuOptionOnSelect }, index) => ( + {items.map((item, index) => ( ))} {Array(limit - items.length).fill(null).map((_, index) => ( diff --git a/src/routes/Board/useBoard.js b/src/routes/Board/useBoard.js index ac1b3ca33..c418271c2 100644 --- a/src/routes/Board/useBoard.js +++ b/src/routes/Board/useBoard.js @@ -10,6 +10,13 @@ const mapBoardState = (board) => { const selected = board.selected; const catalog_resources = board.catalog_resources.map((catalog_resource) => { catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}`; + if (catalog_resource.content.type === 'Ready') { + catalog_resource.content.content.map((metaItem) => { + metaItem.href = `#/metadetails/${metaItem.type}/${metaItem.id}`; + return metaItem; + }); + } + return catalog_resource; }); return { selected, catalog_resources }; From 15348b9ad6cb0753abf49fe3c6e3a525be7275b0 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 16:47:21 +0200 Subject: [PATCH 342/442] dependencies updated --- package.json | 30 +- yarn.lock | 2295 +++++++++++++++++++++++++------------------------- 2 files changed, 1151 insertions(+), 1174 deletions(-) diff --git a/package.json b/package.json index 5d789a88f..811329b45 100755 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "lodash.isequal": "4.5.0", "lodash.throttle": "4.1.1", "prop-types": "15.7.2", - "react": "16.11.0", - "react-dom": "16.11.0", + "react": "16.12.0", + "react-dom": "16.12.0", "react-focus-lock": "2.2.1", "spatial-navigation-polyfill": "git+ssh://git@github.com/NikolaBorislavovHristov/spatial-navigation.git#964d09bf2b0853e27af6c25924b595d6621a019d", "stremio-colors": "git+ssh://git@github.com/Stremio/stremio-colors.git#v2.0.4", @@ -30,20 +30,20 @@ "vtt.js": "0.13.0" }, "devDependencies": { - "@babel/core": "7.6.4", - "@babel/plugin-proposal-class-properties": "7.5.5", - "@babel/plugin-proposal-object-rest-spread": "7.6.2", - "@babel/preset-env": "7.6.3", - "@babel/preset-react": "7.6.3", - "@babel/runtime": "7.6.3", - "@storybook/addon-actions": "5.2.5", + "@babel/core": "7.7.4", + "@babel/plugin-proposal-class-properties": "7.7.4", + "@babel/plugin-proposal-object-rest-spread": "7.7.4", + "@babel/preset-env": "7.7.4", + "@babel/preset-react": "7.7.4", + "@babel/runtime": "7.7.4", + "@storybook/addon-actions": "5.2.8", "@storybook/addon-console": "1.2.1", - "@storybook/addons": "5.2.5", - "@storybook/react": "5.2.5", + "@storybook/addons": "5.2.8", + "@storybook/react": "5.2.8", "babel-loader": "8.0.6", "clean-webpack-plugin": "3.0.0", - "copy-webpack-plugin": "5.0.4", - "css-loader": "3.2.0", + "copy-webpack-plugin": "5.0.5", + "css-loader": "3.2.1", "cssnano": "4.1.10", "cssnano-preset-advanced": "4.0.7", "html-webpack-plugin": "3.2.0", @@ -51,10 +51,10 @@ "less-loader": "5.0.0", "mini-css-extract-plugin": "0.8.0", "postcss-loader": "3.0.0", - "storybook-addon-jsx": "7.1.6", + "storybook-addon-jsx": "7.1.13", "terser-webpack-plugin": "2.2.1", "webpack": "4.41.2", - "webpack-cli": "3.3.9", + "webpack-cli": "3.3.10", "webpack-dev-server": "3.9.0" } } diff --git a/yarn.lock b/yarn.lock index f02c93167..d911f8632 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,19 +9,19 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.0.tgz#9b00f73554edd67bebc86df8303ef678be3d7b48" - integrity sha512-FuRhDRtsd6IptKpHXAa+4WPZYY2ZzgowkbLBecEDDSje1X/apG7jQM33or3NdOmjXBKWGOg4JmSiRfUfuTtHXw== +"@babel/core@7.7.4", "@babel/core@^7.0.0", "@babel/core@^7.4.5": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.4.tgz#37e864532200cb6b50ee9a4045f5f817840166ab" + integrity sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ== dependencies: "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.6.0" - "@babel/helpers" "^7.6.0" - "@babel/parser" "^7.6.0" - "@babel/template" "^7.6.0" - "@babel/traverse" "^7.6.0" - "@babel/types" "^7.6.0" - convert-source-map "^1.1.0" + "@babel/generator" "^7.7.4" + "@babel/helpers" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" + convert-source-map "^1.7.0" debug "^4.1.0" json5 "^2.1.0" lodash "^4.17.13" @@ -29,152 +29,140 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@7.6.4", "@babel/core@^7.0.0", "@babel/core@^7.4.5": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.4.tgz#6ebd9fe00925f6c3e177bb726a188b5f578088ff" - integrity sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ== +"@babel/generator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" + integrity sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg== dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.6.4" - "@babel/helpers" "^7.6.2" - "@babel/parser" "^7.6.4" - "@babel/template" "^7.6.0" - "@babel/traverse" "^7.6.3" - "@babel/types" "^7.6.3" - convert-source-map "^1.1.0" - debug "^4.1.0" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.6.0", "@babel/generator@^7.6.3", "@babel/generator@^7.6.4": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.4.tgz#a4f8437287bf9671b07f483b76e3bb731bc97671" - integrity sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w== - dependencies: - "@babel/types" "^7.6.3" + "@babel/types" "^7.7.4" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" - integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== +"@babel/helper-annotate-as-pure@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz#bb3faf1e74b74bd547e867e48f551fa6b098b6ce" + integrity sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.7.4" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" - integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz#5f73f2b28580e224b5b9bd03146a4015d6217f5f" + integrity sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ== dependencies: - "@babel/helper-explode-assignable-expression" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/helper-explode-assignable-expression" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/helper-builder-react-jsx@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz#a1ac95a5d2b3e88ae5e54846bf462eeb81b318a4" - integrity sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw== +"@babel/helper-builder-react-jsx@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.7.4.tgz#da188d247508b65375b2c30cf59de187be6b0c66" + integrity sha512-kvbfHJNN9dg4rkEM4xn1s8d1/h6TYNvajy9L1wx4qLn9HFg0IkTsQi4rfBe92nxrPUFcMsHoMV+8rU7MJb3fCA== dependencies: - "@babel/types" "^7.3.0" + "@babel/types" "^7.7.4" esutils "^2.0.0" -"@babel/helper-call-delegate@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43" - integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ== +"@babel/helper-call-delegate@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz#621b83e596722b50c0066f9dc37d3232e461b801" + integrity sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA== dependencies: - "@babel/helper-hoist-variables" "^7.4.4" - "@babel/traverse" "^7.4.4" - "@babel/types" "^7.4.4" + "@babel/helper-hoist-variables" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/helper-create-class-features-plugin@^7.5.5", "@babel/helper-create-class-features-plugin@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.6.0.tgz#769711acca889be371e9bc2eb68641d55218021f" - integrity sha512-O1QWBko4fzGju6VoVvrZg0RROCVifcLxiApnGP3OWfWzvxRZFCoBD81K5ur5e3bVY2Vf/5rIJm8cqPKn8HUJng== +"@babel/helper-create-class-features-plugin@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.7.4.tgz#fce60939fd50618610942320a8d951b3b639da2d" + integrity sha512-l+OnKACG4uiDHQ/aJT8dwpR+LhCJALxL0mJ6nzjB25e5IPwqV1VOsY7ah6UB1DG+VOXAIMtuC54rFJGiHkxjgA== dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-member-expression-to-functions" "^7.5.5" - "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-member-expression-to-functions" "^7.7.4" + "@babel/helper-optimise-call-expression" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.5.5" - "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/helper-replace-supers" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" -"@babel/helper-define-map@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz#3dec32c2046f37e09b28c93eb0b103fd2a25d369" - integrity sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg== +"@babel/helper-create-regexp-features-plugin@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz#6d5762359fd34f4da1500e4cff9955b5299aaf59" + integrity sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A== dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/types" "^7.5.5" + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.6.0" + +"@babel/helper-define-map@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz#2841bf92eb8bd9c906851546fe6b9d45e162f176" + integrity sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg== + dependencies: + "@babel/helper-function-name" "^7.7.4" + "@babel/types" "^7.7.4" lodash "^4.17.13" -"@babel/helper-explode-assignable-expression@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" - integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== +"@babel/helper-explode-assignable-expression@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz#fa700878e008d85dc51ba43e9fb835cddfe05c84" + integrity sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg== dependencies: - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/helper-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" - integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== +"@babel/helper-function-name@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e" + integrity sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ== dependencies: - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/helper-get-function-arity" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/helper-get-function-arity@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" - integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== +"@babel/helper-get-function-arity@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" + integrity sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.7.4" -"@babel/helper-hoist-variables@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a" - integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w== +"@babel/helper-hoist-variables@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz#612384e3d823fdfaaf9fce31550fe5d4db0f3d12" + integrity sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ== dependencies: - "@babel/types" "^7.4.4" + "@babel/types" "^7.7.4" -"@babel/helper-member-expression-to-functions@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz#1fb5b8ec4453a93c439ee9fe3aeea4a84b76b590" - integrity sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA== +"@babel/helper-member-expression-to-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz#356438e2569df7321a8326644d4b790d2122cb74" + integrity sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw== dependencies: - "@babel/types" "^7.5.5" + "@babel/types" "^7.7.4" -"@babel/helper-module-imports@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" - integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz#e5a92529f8888bf319a6376abfbd1cebc491ad91" + integrity sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.7.4" -"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz#f84ff8a09038dcbca1fd4355661a500937165b4a" - integrity sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw== +"@babel/helper-module-transforms@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz#8d7cdb1e1f8ea3d8c38b067345924ac4f8e0879a" + integrity sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA== dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/template" "^7.4.4" - "@babel/types" "^7.5.5" + "@babel/helper-module-imports" "^7.7.4" + "@babel/helper-simple-access" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" lodash "^4.17.13" -"@babel/helper-optimise-call-expression@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" - integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== +"@babel/helper-optimise-call-expression@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz#034af31370d2995242aa4df402c3b7794b2dcdf2" + integrity sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.7.4" "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" @@ -188,60 +176,60 @@ dependencies: lodash "^4.17.13" -"@babel/helper-remap-async-to-generator@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" - integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== +"@babel/helper-remap-async-to-generator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz#c68c2407350d9af0e061ed6726afb4fff16d0234" + integrity sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw== dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-wrap-function" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/helper-annotate-as-pure" "^7.7.4" + "@babel/helper-wrap-function" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/helper-replace-supers@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz#f84ce43df031222d2bad068d2626cb5799c34bc2" - integrity sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg== +"@babel/helper-replace-supers@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz#3c881a6a6a7571275a72d82e6107126ec9e2cdd2" + integrity sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg== dependencies: - "@babel/helper-member-expression-to-functions" "^7.5.5" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.5.5" - "@babel/types" "^7.5.5" + "@babel/helper-member-expression-to-functions" "^7.7.4" + "@babel/helper-optimise-call-expression" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/helper-simple-access@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" - integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== +"@babel/helper-simple-access@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz#a169a0adb1b5f418cfc19f22586b2ebf58a9a294" + integrity sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A== dependencies: - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/template" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/helper-split-export-declaration@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" - integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== +"@babel/helper-split-export-declaration@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8" + integrity sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug== dependencies: - "@babel/types" "^7.4.4" + "@babel/types" "^7.7.4" -"@babel/helper-wrap-function@^7.1.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" - integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ== +"@babel/helper-wrap-function@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace" + integrity sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg== dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.2.0" + "@babel/helper-function-name" "^7.7.4" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/helpers@^7.6.0", "@babel/helpers@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.6.2.tgz#681ffe489ea4dcc55f23ce469e58e59c1c045153" - integrity sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA== +"@babel/helpers@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302" + integrity sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg== dependencies: - "@babel/template" "^7.6.0" - "@babel/traverse" "^7.6.2" - "@babel/types" "^7.6.0" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" "@babel/highlight@^7.0.0": version "7.5.0" @@ -252,576 +240,554 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.6.0", "@babel/parser@^7.6.3", "@babel/parser@^7.6.4": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81" - integrity sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A== +"@babel/parser@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" + integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== -"@babel/plugin-proposal-async-generator-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" - integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ== +"@babel/plugin-proposal-async-generator-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz#0351c5ac0a9e927845fffd5b82af476947b7ce6d" + integrity sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/helper-remap-async-to-generator" "^7.7.4" + "@babel/plugin-syntax-async-generators" "^7.7.4" -"@babel/plugin-proposal-class-properties@7.5.5", "@babel/plugin-proposal-class-properties@^7.3.3": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.5.5.tgz#a974cfae1e37c3110e71f3c6a2e48b8e71958cd4" - integrity sha512-AF79FsnWFxjlaosgdi421vmYG6/jg79bVD0dpD44QdgobzHKuLZ6S3vl8la9qIeSwGi8i1fS0O1mfuDAAdo1/A== +"@babel/plugin-proposal-class-properties@7.7.4", "@babel/plugin-proposal-class-properties@^7.7.0": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.7.4.tgz#2f964f0cb18b948450362742e33e15211e77c2ba" + integrity sha512-EcuXeV4Hv1X3+Q1TsuOmyyxeTRiSqurGJ26+I/FW1WbymmRRapVORm6x1Zl3iDIHyRxEs+VXWp6qnlcfcJSbbw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.5.5" + "@babel/helper-create-class-features-plugin" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-proposal-decorators@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.6.0.tgz#6659d2572a17d70abd68123e89a12a43d90aa30c" - integrity sha512-ZSyYw9trQI50sES6YxREXKu+4b7MAg6Qx2cvyDDYjP2Hpzd3FleOUwC9cqn1+za8d0A2ZU8SHujxFao956efUg== +"@babel/plugin-proposal-decorators@7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.7.4.tgz#58c1e21d21ea12f9f5f0a757e46e687b94a7ab2b" + integrity sha512-GftcVDcLCwVdzKmwOBDjATd548+IE+mBo7ttgatqNDR7VG7GqIuZPtRWlMLHbhTXhcnFZiGER8iIYl1n/imtsg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.6.0" + "@babel/helper-create-class-features-plugin" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-decorators" "^7.2.0" + "@babel/plugin-syntax-decorators" "^7.7.4" -"@babel/plugin-proposal-dynamic-import@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506" - integrity sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw== +"@babel/plugin-proposal-dynamic-import@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz#dde64a7f127691758cbfed6cf70de0fa5879d52d" + integrity sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-syntax-dynamic-import" "^7.7.4" -"@babel/plugin-proposal-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" - integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg== +"@babel/plugin-proposal-json-strings@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz#7700a6bfda771d8dc81973249eac416c6b4c697d" + integrity sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.7.4" -"@babel/plugin-proposal-object-rest-spread@7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz#61939744f71ba76a3ae46b5eea18a54c16d22e58" - integrity sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw== +"@babel/plugin-proposal-nullish-coalescing-operator@7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.7.4.tgz#7db302c83bc30caa89e38fee935635ef6bd11c28" + integrity sha512-TbYHmr1Gl1UC7Vo2HVuj/Naci5BEGNZ0AJhzqD2Vpr6QPFWpUmBRLrIDjedzx7/CShq0bRDS2gI4FIs77VHLVQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.7.4" -"@babel/plugin-proposal-object-rest-spread@7.6.2", "@babel/plugin-proposal-object-rest-spread@^7.3.2", "@babel/plugin-proposal-object-rest-spread@^7.5.5", "@babel/plugin-proposal-object-rest-spread@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.6.2.tgz#8ffccc8f3a6545e9f78988b6bf4fe881b88e8096" - integrity sha512-LDBXlmADCsMZV1Y9OQwMc0MyGZ8Ta/zlD9N67BfQT8uYwkRswiu2hU6nJKrjrt/58aH/vqfQlR/9yId/7A2gWw== +"@babel/plugin-proposal-numeric-separator@7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.7.4.tgz#7819a17445f4197bb9575e5750ed349776da858a" + integrity sha512-CG605v7lLpVgVldSY6kxsN9ui1DxFOyepBfuX2AzU2TNriMAYApoU55mrGw9Jr4TlrTzPCG10CL8YXyi+E/iPw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-numeric-separator" "^7.7.4" -"@babel/plugin-proposal-optional-catch-binding@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" - integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g== +"@babel/plugin-proposal-object-rest-spread@7.7.4", "@babel/plugin-proposal-object-rest-spread@^7.6.2", "@babel/plugin-proposal-object-rest-spread@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz#cc57849894a5c774214178c8ab64f6334ec8af71" + integrity sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.7.4" -"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.6.2.tgz#05413762894f41bfe42b9a5e80919bd575dcc802" - integrity sha512-NxHETdmpeSCtiatMRYWVJo7266rrvAC3DTeG5exQBIH/fMIUK7ejDNznBbn3HQl/o9peymRRg7Yqkx6PdUXmMw== +"@babel/plugin-proposal-optional-catch-binding@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz#ec21e8aeb09ec6711bc0a39ca49520abee1de379" + integrity sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.6.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" -"@babel/plugin-syntax-async-generators@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" - integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg== +"@babel/plugin-proposal-optional-chaining@7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.7.4.tgz#3f04c2de1a942cbd3008324df8144b9cbc0ca0ba" + integrity sha512-JmgaS+ygAWDR/STPe3/7y0lNlHgS+19qZ9aC06nYLwQ/XB7c0q5Xs+ksFU3EDnp9EiEsO0dnRAOKeyLHTZuW3A== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-chaining" "^7.7.4" + +"@babel/plugin-proposal-unicode-property-regex@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz#7c239ccaf09470dbe1d453d50057460e84517ebb" + integrity sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-async-generators@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz#331aaf310a10c80c44a66b238b6e49132bd3c889" + integrity sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-decorators@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.2.0.tgz#c50b1b957dcc69e4b1127b65e1c33eef61570c1b" - integrity sha512-38QdqVoXdHUQfTpZo3rQwqQdWtCn5tMv4uV6r2RMfTqNBuv4ZBhz79SfaQWKTVmxHjeFv/DnXVC/+agHCklYWA== +"@babel/plugin-syntax-decorators@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.7.4.tgz#3c91cfee2a111663ff3ac21b851140f5a52a4e0b" + integrity sha512-0oNLWNH4k5ZbBVfAwiTU53rKFWIeTh6ZlaWOXWJc4ywxs0tjz5fc3uZ6jKAnZSxN98eXVgg7bJIuzjX+3SXY+A== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-dynamic-import@7.2.0", "@babel/plugin-syntax-dynamic-import@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" - integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== +"@babel/plugin-syntax-dynamic-import@7.7.4", "@babel/plugin-syntax-dynamic-import@^7.2.0", "@babel/plugin-syntax-dynamic-import@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz#29ca3b4415abfe4a5ec381e903862ad1a54c3aec" + integrity sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-flow@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz#a765f061f803bc48f240c26f8747faf97c26bf7c" - integrity sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg== +"@babel/plugin-syntax-flow@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.7.4.tgz#6d91b59e1a0e4c17f36af2e10dd64ef220919d7b" + integrity sha512-2AMAWl5PsmM5KPkB22cvOkUyWk6MjUaqhHNU5nSPUl/ns3j5qLfw2SuYP5RbVZ0tfLvePr4zUScbICtDP2CUNw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-json-strings@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" - integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg== +"@babel/plugin-syntax-json-strings@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" + integrity sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-jsx@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz#0b85a3b4bc7cdf4cc4b8bf236335b907ca22e7c7" - integrity sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw== +"@babel/plugin-syntax-jsx@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.7.4.tgz#dab2b56a36fb6c3c222a1fbc71f7bf97f327a9ec" + integrity sha512-wuy6fiMe9y7HeZBWXYCGt2RGxZOj0BImZ9EyXJVnVGBKO/Br592rbR3rtIQn0eQhAk9vqaKP5n8tVqEFBQMfLg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-object-rest-spread@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" - integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA== +"@babel/plugin-syntax-nullish-coalescing-operator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.7.4.tgz#e53b751d0c3061b1ba3089242524b65a7a9da12b" + integrity sha512-XKh/yIRPiQTOeBg0QJjEus5qiSKucKAiApNtO1psqG7D17xmE+X2i5ZqBEuSvo0HRuyPaKaSN/Gy+Ha9KFQolw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-optional-catch-binding@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" - integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w== +"@babel/plugin-syntax-numeric-separator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.7.4.tgz#39818f8042a09d4c6248d85d82555369da4da5c4" + integrity sha512-vmlUUBlLuFnbpaR+1kKIdo62xQEN+THWbtAHSEilo+0rHl2dKKCn6GLUVKpI848wL/T0ZPQgAy8asRJ9yYEjog== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-typescript@^7.2.0": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" - integrity sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag== +"@babel/plugin-syntax-object-rest-spread@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz#47cf220d19d6d0d7b154304701f468fc1cc6ff46" + integrity sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-arrow-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" - integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg== +"@babel/plugin-syntax-optional-catch-binding@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz#a3e38f59f4b6233867b4a92dcb0ee05b2c334aa6" + integrity sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-async-to-generator@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e" - integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - -"@babel/plugin-transform-block-scoped-functions@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" - integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w== +"@babel/plugin-syntax-optional-chaining@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.7.4.tgz#c91fdde6de85d2eb8906daea7b21944c3610c901" + integrity sha512-2MqYD5WjZSbJdUagnJvIdSfkb/ucOC9/1fRJxm7GAxY6YQLWlUvkfxoNbUPcPLHJyetKUDQ4+yyuUyAoc0HriA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-block-scoping@^7.6.0", "@babel/plugin-transform-block-scoping@^7.6.3": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz#6e854e51fbbaa84351b15d4ddafe342f3a5d542a" - integrity sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw== +"@babel/plugin-syntax-top-level-await@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz#bd7d8fa7b9fee793a36e4027fd6dd1aa32f946da" + integrity sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-typescript@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.7.4.tgz#5d037ffa10f3b25a16f32570ebbe7a8c2efa304b" + integrity sha512-77blgY18Hud4NM1ggTA8xVT/dBENQf17OpiToSa2jSmEY3fWXD2jwrdVlO4kq5yzUTeF15WSQ6b4fByNvJcjpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-arrow-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz#76309bd578addd8aee3b379d809c802305a98a12" + integrity sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-async-to-generator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz#694cbeae6d613a34ef0292713fa42fb45c4470ba" + integrity sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg== + dependencies: + "@babel/helper-module-imports" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.7.4" + +"@babel/plugin-transform-block-scoped-functions@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz#d0d9d5c269c78eaea76227ace214b8d01e4d837b" + integrity sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-block-scoping@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz#200aad0dcd6bb80372f94d9e628ea062c58bf224" + integrity sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.13" -"@babel/plugin-transform-classes@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz#d094299d9bd680a14a2a0edae38305ad60fb4de9" - integrity sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg== +"@babel/plugin-transform-classes@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz#c92c14be0a1399e15df72667067a8f510c9400ec" + integrity sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg== dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-define-map" "^7.5.5" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-annotate-as-pure" "^7.7.4" + "@babel/helper-define-map" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-optimise-call-expression" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.5.5" - "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/helper-replace-supers" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" - integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA== +"@babel/plugin-transform-computed-properties@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz#e856c1628d3238ffe12d668eb42559f79a81910d" + integrity sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-destructuring@7.6.0", "@babel/plugin-transform-destructuring@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz#44bbe08b57f4480094d57d9ffbcd96d309075ba6" - integrity sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ== +"@babel/plugin-transform-destructuring@7.7.4", "@babel/plugin-transform-destructuring@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz#2b713729e5054a1135097b6a67da1b6fe8789267" + integrity sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.6.2.tgz#44abb948b88f0199a627024e1508acaf8dc9b2f9" - integrity sha512-KGKT9aqKV+9YMZSkowzYoYEiHqgaDhGmPNZlZxX6UeHC4z30nC1J9IrZuGqbYFB1jaIGdv91ujpze0exiVK8bA== +"@babel/plugin-transform-dotall-regex@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz#f7ccda61118c5b7a2599a72d5e3210884a021e96" + integrity sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw== dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.6.0" -"@babel/plugin-transform-duplicate-keys@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" - integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ== +"@babel/plugin-transform-duplicate-keys@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz#3d21731a42e3f598a73835299dd0169c3b90ac91" + integrity sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-exponentiation-operator@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" - integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A== +"@babel/plugin-transform-exponentiation-operator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz#dd30c0191e3a1ba19bcc7e389bdfddc0729d5db9" + integrity sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-flow-strip-types@7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.4.tgz#d267a081f49a8705fc9146de0768c6b58dccd8f7" - integrity sha512-WyVedfeEIILYEaWGAUWzVNyqG4sfsNooMhXWsu/YzOvVGcsnPb5PguysjJqI3t3qiaYj0BR8T2f5njdjTGe44Q== +"@babel/plugin-transform-flow-strip-types@7.7.4", "@babel/plugin-transform-flow-strip-types@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.7.4.tgz#cc73f85944782df1d77d80977bc097920a8bf31a" + integrity sha512-w9dRNlHY5ElNimyMYy0oQowvQpwt/PRHI0QS98ZJCTZU2bvSnKXo5zEiD5u76FBPigTm8TkqzmnUTg16T7qbkA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.2.0" + "@babel/plugin-syntax-flow" "^7.7.4" -"@babel/plugin-transform-flow-strip-types@^7.0.0": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.6.3.tgz#8110f153e7360cfd5996eee68706cfad92d85256" - integrity sha512-l0ETkyEofkqFJ9LS6HChNIKtVJw2ylKbhYMlJ5C6df+ldxxaLIyXY4yOdDQQspfFpV8/vDiaWoJlvflstlYNxg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.2.0" - -"@babel/plugin-transform-for-of@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556" - integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ== +"@babel/plugin-transform-for-of@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz#248800e3a5e507b1f103d8b4ca998e77c63932bc" + integrity sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-function-name@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad" - integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA== +"@babel/plugin-transform-function-name@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz#75a6d3303d50db638ff8b5385d12451c865025b1" + integrity sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g== dependencies: - "@babel/helper-function-name" "^7.1.0" + "@babel/helper-function-name" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" - integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg== +"@babel/plugin-transform-literals@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz#27fe87d2b5017a2a5a34d1c41a6b9f6a6262643e" + integrity sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-member-expression-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d" - integrity sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA== +"@babel/plugin-transform-member-expression-literals@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz#aee127f2f3339fc34ce5e3055d7ffbf7aa26f19a" + integrity sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-modules-amd@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" - integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg== +"@babel/plugin-transform-modules-amd@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.4.tgz#276b3845ca2b228f2995e453adc2e6f54d72fb71" + integrity sha512-/542/5LNA18YDtg1F+QHvvUSlxdvjZoD/aldQwkq+E3WCkbEjNSN9zdrOXaSlfg3IfGi22ijzecklF/A7kVZFQ== dependencies: - "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-module-transforms" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-commonjs@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz#39dfe957de4420445f1fcf88b68a2e4aa4515486" - integrity sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g== +"@babel/plugin-transform-modules-commonjs@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.4.tgz#bee4386e550446343dd52a571eda47851ff857a3" + integrity sha512-k8iVS7Jhc367IcNF53KCwIXtKAH7czev866ThsTgy8CwlXjnKZna2VHwChglzLleYrcHz1eQEIJlGRQxB53nqA== dependencies: - "@babel/helper-module-transforms" "^7.4.4" + "@babel/helper-module-transforms" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" + "@babel/helper-simple-access" "^7.7.4" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-systemjs@^7.5.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249" - integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg== +"@babel/plugin-transform-modules-systemjs@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz#cd98152339d3e763dfe838b7d4273edaf520bb30" + integrity sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw== dependencies: - "@babel/helper-hoist-variables" "^7.4.4" + "@babel/helper-hoist-variables" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-umd@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" - integrity sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw== +"@babel/plugin-transform-modules-umd@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz#1027c355a118de0aae9fee00ad7813c584d9061f" + integrity sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw== dependencies: - "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-module-transforms" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-named-capturing-groups-regex@^7.6.0", "@babel/plugin-transform-named-capturing-groups-regex@^7.6.3": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.3.tgz#aaa6e409dd4fb2e50b6e2a91f7e3a3149dbce0cf" - integrity sha512-jTkk7/uE6H2s5w6VlMHeWuH+Pcy2lmdwFoeWCVnvIrDUnB5gQqTVI8WfmEAhF2CDEarGrknZcmSFg1+bkfCoSw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz#fb3bcc4ee4198e7385805007373d6b6f42c98220" + integrity sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw== dependencies: - regexpu-core "^4.6.0" + "@babel/helper-create-regexp-features-plugin" "^7.7.4" -"@babel/plugin-transform-new-target@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5" - integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA== +"@babel/plugin-transform-new-target@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz#4a0753d2d60639437be07b592a9e58ee00720167" + integrity sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-object-super@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz#c70021df834073c65eb613b8679cc4a381d1a9f9" - integrity sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ== +"@babel/plugin-transform-object-super@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz#48488937a2d586c0148451bf51af9d7dda567262" + integrity sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.5.5" + "@babel/helper-replace-supers" "^7.7.4" -"@babel/plugin-transform-parameters@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16" - integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw== +"@babel/plugin-transform-parameters@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz#da4555c97f39b51ac089d31c7380f03bca4075ce" + integrity sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw== dependencies: - "@babel/helper-call-delegate" "^7.4.4" - "@babel/helper-get-function-arity" "^7.0.0" + "@babel/helper-call-delegate" "^7.7.4" + "@babel/helper-get-function-arity" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-property-literals@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905" - integrity sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ== +"@babel/plugin-transform-property-literals@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz#2388d6505ef89b266103f450f9167e6bd73f98c2" + integrity sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.2.0": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.6.3.tgz#9fc9ea060b983c7c035acbe481cbe1fb1245bfff" - integrity sha512-1/YogSSU7Tby9rq2VCmhuRg+6pxsHy2rI7w/oo8RKoBt6uBUFG+mk6x13kK+FY1/ggN92HAfg7ADd1v1+NCOKg== +"@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.6.3": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.7.4.tgz#499cf732a21ffd62cc4b0016e27c3906097f8982" + integrity sha512-U6XkHZ8RnmeEb8jBUOpeo6oFka5RhLgxAVvK4/fBbwoYlsHQYLb8I37ymTPDVsrWjqb94+hueuWQA/1OAA4rAQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-annotate-as-pure" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-react-display-name@7.2.0", "@babel/plugin-transform-react-display-name@^7.0.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz#ebfaed87834ce8dc4279609a4f0c324c156e3eb0" - integrity sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A== +"@babel/plugin-transform-react-display-name@7.7.4", "@babel/plugin-transform-react-display-name@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.7.4.tgz#9f2b80b14ebc97eef4a9b29b612c58ed9c0d10dd" + integrity sha512-sBbIvqYkthai0X0vkD2xsAwluBp+LtNHH+/V4a5ydifmTtb8KOVOlrMIk/MYmIc4uTYDnjZUHQildYNo36SRJw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-react-jsx-self@^7.0.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz#461e21ad9478f1031dd5e276108d027f1b5240ba" - integrity sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg== +"@babel/plugin-transform-react-jsx-self@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.7.4.tgz#81b8fbfd14b2215e8f1c2c3adfba266127b0231c" + integrity sha512-PWYjSfqrO273mc1pKCRTIJXyqfc9vWYBax88yIhQb+bpw3XChVC7VWS4VwRVs63wFHKxizvGSd00XEr+YB9Q2A== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.2.0" + "@babel/plugin-syntax-jsx" "^7.7.4" -"@babel/plugin-transform-react-jsx-source@^7.0.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.5.0.tgz#583b10c49cf057e237085bcbd8cc960bd83bd96b" - integrity sha512-58Q+Jsy4IDCZx7kqEZuSDdam/1oW8OdDX8f+Loo6xyxdfg1yF0GE2XNJQSTZCaMol93+FBzpWiPEwtbMloAcPg== +"@babel/plugin-transform-react-jsx-source@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.7.4.tgz#8994b1bf6014b133f5a46d3b7d1ee5f5e3e72c10" + integrity sha512-5ZU9FnPhqtHsOXxutRtXZAzoEJwDaP32QcobbMP1/qt7NYcsCNK8XgzJcJfoEr/ZnzVvUNInNjIW22Z6I8p9mg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.2.0" + "@babel/plugin-syntax-jsx" "^7.7.4" -"@babel/plugin-transform-react-jsx@^7.0.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz#f2cab99026631c767e2745a5368b331cfe8f5290" - integrity sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg== +"@babel/plugin-transform-react-jsx@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.7.4.tgz#d91205717fae4e2f84d020cd3057ec02a10f11da" + integrity sha512-LixU4BS95ZTEAZdPaIuyg/k8FiiqN9laQ0dMHB4MlpydHY53uQdWCUrwjLr5o6ilS6fAgZey4Q14XBjl5tL6xw== dependencies: - "@babel/helper-builder-react-jsx" "^7.3.0" + "@babel/helper-builder-react-jsx" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-jsx" "^7.2.0" + "@babel/plugin-syntax-jsx" "^7.7.4" -"@babel/plugin-transform-regenerator@^7.4.5": - version "7.4.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f" - integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA== +"@babel/plugin-transform-regenerator@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.4.tgz#d18eac0312a70152d7d914cbed2dc3999601cfc0" + integrity sha512-e7MWl5UJvmPEwFJTwkBlPmqixCtr9yAASBqff4ggXTNicZiwbF8Eefzm6NVgfiBp7JdAGItecnctKTgH44q2Jw== dependencies: regenerator-transform "^0.14.0" -"@babel/plugin-transform-reserved-words@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634" - integrity sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw== +"@babel/plugin-transform-reserved-words@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz#6a7cf123ad175bb5c69aec8f6f0770387ed3f1eb" + integrity sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-runtime@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.6.0.tgz#85a3cce402b28586138e368fce20ab3019b9713e" - integrity sha512-Da8tMf7uClzwUm/pnJ1S93m/aRXmoYNDD7TkHua8xBDdaAs54uZpTWvEt6NGwmoVMb9mZbntfTqmG2oSzN/7Vg== +"@babel/plugin-transform-runtime@7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.4.tgz#51fe458c1c1fa98a8b07934f4ed38b6cd62177a6" + integrity sha512-O8kSkS5fP74Ad/8pfsCMGa8sBRdLxYoSReaARRNSz3FbFQj3z/QUvoUmJ28gn9BO93YfnXc3j+Xyaqe8cKDNBQ== dependencies: - "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-module-imports" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" resolve "^1.8.1" semver "^5.5.1" -"@babel/plugin-transform-shorthand-properties@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" - integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg== +"@babel/plugin-transform-shorthand-properties@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz#74a0a9b2f6d67a684c6fbfd5f0458eb7ba99891e" + integrity sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-spread@^7.2.0", "@babel/plugin-transform-spread@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.6.2.tgz#fc77cf798b24b10c46e1b51b1b88c2bf661bb8dd" - integrity sha512-DpSvPFryKdK1x+EDJYCy28nmAaIMdxmhot62jAXF/o99iA33Zj2Lmcp3vDmz+MUh0LNYVPvfj5iC3feb3/+PFg== +"@babel/plugin-transform-spread@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz#aa673b356fe6b7e70d69b6e33a17fef641008578" + integrity sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-sticky-regex@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" - integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw== +"@babel/plugin-transform-sticky-regex@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz#ffb68c05090c30732076b1285dc1401b404a123c" + integrity sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" -"@babel/plugin-transform-template-literals@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0" - integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g== +"@babel/plugin-transform-template-literals@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz#1eb6411736dd3fe87dbd20cc6668e5121c17d604" + integrity sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-annotate-as-pure" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-typeof-symbol@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" - integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw== +"@babel/plugin-transform-typeof-symbol@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz#3174626214f2d6de322882e498a38e8371b2140e" + integrity sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-typescript@^7.6.0": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.6.3.tgz#dddb50cf3b8b2ef70b22e5326e9a91f05a1db13b" - integrity sha512-aiWINBrPMSC3xTXRNM/dfmyYuPNKY/aexYqBgh0HBI5Y+WO5oRAqW/oROYeYHrF4Zw12r9rK4fMk/ZlAmqx/FQ== +"@babel/plugin-transform-typescript@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.7.4.tgz#2974fd05f4e85c695acaf497f432342de9fc0636" + integrity sha512-X8e3tcPEKnwwPVG+vP/vSqEShkwODOEeyQGod82qrIuidwIrfnsGn11qPM1jBLF4MqguTXXYzm58d0dY+/wdpg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.6.0" + "@babel/helper-create-class-features-plugin" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-typescript" "^7.2.0" + "@babel/plugin-syntax-typescript" "^7.7.4" -"@babel/plugin-transform-unicode-regex@^7.4.4", "@babel/plugin-transform-unicode-regex@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.6.2.tgz#b692aad888a7e8d8b1b214be6b9dc03d5031f698" - integrity sha512-orZI6cWlR3nk2YmYdb0gImrgCUwb5cBUwjf6Ks6dvNVvXERkwtJWOQaEOjPiu0Gu1Tq6Yq/hruCZZOOi9F34Dw== +"@babel/plugin-transform-unicode-regex@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz#a3c0f65b117c4c81c5b6484f2a5e7b95346b83ae" + integrity sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw== dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.4.4" - regexpu-core "^4.6.0" -"@babel/preset-env@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.6.0.tgz#aae4141c506100bb2bfaa4ac2a5c12b395619e50" - integrity sha512-1efzxFv/TcPsNXlRhMzRnkBFMeIqBBgzwmZwlFDw5Ubj0AGLeufxugirwZmkkX/ayi3owsSqoQ4fw8LkfK9SYg== +"@babel/preset-env@7.7.4", "@babel/preset-env@^7.4.5", "@babel/preset-env@^7.7.1": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.4.tgz#ccaf309ae8d1ee2409c85a4e2b5e280ceee830f8" + integrity sha512-Dg+ciGJjwvC1NIe/DGblMbcGq1HOtKbw8RLl4nIjlfcILKEOkWT/vRqPpumswABEBVudii6dnVwrBtzD7ibm4g== dependencies: - "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-module-imports" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.2.0" - "@babel/plugin-proposal-dynamic-import" "^7.5.0" - "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.5.5" - "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-syntax-async-generators" "^7.2.0" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" - "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.5.0" - "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.6.0" - "@babel/plugin-transform-classes" "^7.5.5" - "@babel/plugin-transform-computed-properties" "^7.2.0" - "@babel/plugin-transform-destructuring" "^7.6.0" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/plugin-transform-duplicate-keys" "^7.5.0" - "@babel/plugin-transform-exponentiation-operator" "^7.2.0" - "@babel/plugin-transform-for-of" "^7.4.4" - "@babel/plugin-transform-function-name" "^7.4.4" - "@babel/plugin-transform-literals" "^7.2.0" - "@babel/plugin-transform-member-expression-literals" "^7.2.0" - "@babel/plugin-transform-modules-amd" "^7.5.0" - "@babel/plugin-transform-modules-commonjs" "^7.6.0" - "@babel/plugin-transform-modules-systemjs" "^7.5.0" - "@babel/plugin-transform-modules-umd" "^7.2.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.6.0" - "@babel/plugin-transform-new-target" "^7.4.4" - "@babel/plugin-transform-object-super" "^7.5.5" - "@babel/plugin-transform-parameters" "^7.4.4" - "@babel/plugin-transform-property-literals" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.4.5" - "@babel/plugin-transform-reserved-words" "^7.2.0" - "@babel/plugin-transform-shorthand-properties" "^7.2.0" - "@babel/plugin-transform-spread" "^7.2.0" - "@babel/plugin-transform-sticky-regex" "^7.2.0" - "@babel/plugin-transform-template-literals" "^7.4.4" - "@babel/plugin-transform-typeof-symbol" "^7.2.0" - "@babel/plugin-transform-unicode-regex" "^7.4.4" - "@babel/types" "^7.6.0" - browserslist "^4.6.0" - core-js-compat "^3.1.1" - invariant "^2.2.2" - js-levenshtein "^1.1.3" - semver "^5.5.0" - -"@babel/preset-env@7.6.3", "@babel/preset-env@^7.4.5": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.6.3.tgz#9e1bf05a2e2d687036d24c40e4639dc46cef2271" - integrity sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.2.0" - "@babel/plugin-proposal-dynamic-import" "^7.5.0" - "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.6.2" - "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.6.2" - "@babel/plugin-syntax-async-generators" "^7.2.0" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" - "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.5.0" - "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.6.3" - "@babel/plugin-transform-classes" "^7.5.5" - "@babel/plugin-transform-computed-properties" "^7.2.0" - "@babel/plugin-transform-destructuring" "^7.6.0" - "@babel/plugin-transform-dotall-regex" "^7.6.2" - "@babel/plugin-transform-duplicate-keys" "^7.5.0" - "@babel/plugin-transform-exponentiation-operator" "^7.2.0" - "@babel/plugin-transform-for-of" "^7.4.4" - "@babel/plugin-transform-function-name" "^7.4.4" - "@babel/plugin-transform-literals" "^7.2.0" - "@babel/plugin-transform-member-expression-literals" "^7.2.0" - "@babel/plugin-transform-modules-amd" "^7.5.0" - "@babel/plugin-transform-modules-commonjs" "^7.6.0" - "@babel/plugin-transform-modules-systemjs" "^7.5.0" - "@babel/plugin-transform-modules-umd" "^7.2.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.6.3" - "@babel/plugin-transform-new-target" "^7.4.4" - "@babel/plugin-transform-object-super" "^7.5.5" - "@babel/plugin-transform-parameters" "^7.4.4" - "@babel/plugin-transform-property-literals" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.4.5" - "@babel/plugin-transform-reserved-words" "^7.2.0" - "@babel/plugin-transform-shorthand-properties" "^7.2.0" - "@babel/plugin-transform-spread" "^7.6.2" - "@babel/plugin-transform-sticky-regex" "^7.2.0" - "@babel/plugin-transform-template-literals" "^7.4.4" - "@babel/plugin-transform-typeof-symbol" "^7.2.0" - "@babel/plugin-transform-unicode-regex" "^7.6.2" - "@babel/types" "^7.6.3" + "@babel/plugin-proposal-async-generator-functions" "^7.7.4" + "@babel/plugin-proposal-dynamic-import" "^7.7.4" + "@babel/plugin-proposal-json-strings" "^7.7.4" + "@babel/plugin-proposal-object-rest-spread" "^7.7.4" + "@babel/plugin-proposal-optional-catch-binding" "^7.7.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.7.4" + "@babel/plugin-syntax-async-generators" "^7.7.4" + "@babel/plugin-syntax-dynamic-import" "^7.7.4" + "@babel/plugin-syntax-json-strings" "^7.7.4" + "@babel/plugin-syntax-object-rest-spread" "^7.7.4" + "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" + "@babel/plugin-syntax-top-level-await" "^7.7.4" + "@babel/plugin-transform-arrow-functions" "^7.7.4" + "@babel/plugin-transform-async-to-generator" "^7.7.4" + "@babel/plugin-transform-block-scoped-functions" "^7.7.4" + "@babel/plugin-transform-block-scoping" "^7.7.4" + "@babel/plugin-transform-classes" "^7.7.4" + "@babel/plugin-transform-computed-properties" "^7.7.4" + "@babel/plugin-transform-destructuring" "^7.7.4" + "@babel/plugin-transform-dotall-regex" "^7.7.4" + "@babel/plugin-transform-duplicate-keys" "^7.7.4" + "@babel/plugin-transform-exponentiation-operator" "^7.7.4" + "@babel/plugin-transform-for-of" "^7.7.4" + "@babel/plugin-transform-function-name" "^7.7.4" + "@babel/plugin-transform-literals" "^7.7.4" + "@babel/plugin-transform-member-expression-literals" "^7.7.4" + "@babel/plugin-transform-modules-amd" "^7.7.4" + "@babel/plugin-transform-modules-commonjs" "^7.7.4" + "@babel/plugin-transform-modules-systemjs" "^7.7.4" + "@babel/plugin-transform-modules-umd" "^7.7.4" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.4" + "@babel/plugin-transform-new-target" "^7.7.4" + "@babel/plugin-transform-object-super" "^7.7.4" + "@babel/plugin-transform-parameters" "^7.7.4" + "@babel/plugin-transform-property-literals" "^7.7.4" + "@babel/plugin-transform-regenerator" "^7.7.4" + "@babel/plugin-transform-reserved-words" "^7.7.4" + "@babel/plugin-transform-shorthand-properties" "^7.7.4" + "@babel/plugin-transform-spread" "^7.7.4" + "@babel/plugin-transform-sticky-regex" "^7.7.4" + "@babel/plugin-transform-template-literals" "^7.7.4" + "@babel/plugin-transform-typeof-symbol" "^7.7.4" + "@babel/plugin-transform-unicode-regex" "^7.7.4" + "@babel/types" "^7.7.4" browserslist "^4.6.0" core-js-compat "^3.1.1" invariant "^2.2.2" @@ -829,85 +795,67 @@ semver "^5.5.0" "@babel/preset-flow@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.0.0.tgz#afd764835d9535ec63d8c7d4caf1c06457263da2" - integrity sha512-bJOHrYOPqJZCkPVbG1Lot2r5OSsB+iUOaxiHdlOeB1yPWS6evswVHwvkDLZ54WTaTRIk89ds0iHmGZSnxlPejQ== + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.7.4.tgz#99c1349b6fd7132783196de181e6b32d0949427e" + integrity sha512-6LbUqcHD8BcRtXMOp5bc5nJeU8RlKh6q5U8TgZeCrf9ebBdW8Wyy5ujAUnbJfmzQ56Kkq5XtwErC/5+5RHyFYA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.7.4" -"@babel/preset-react@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.0.0.tgz#e86b4b3d99433c7b3e9e91747e2653958bc6b3c0" - integrity sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w== +"@babel/preset-react@7.7.4", "@babel/preset-react@^7.0.0", "@babel/preset-react@^7.7.0": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.7.4.tgz#3fe2ea698d8fb536d8e7881a592c3c1ee8bf5707" + integrity sha512-j+vZtg0/8pQr1H8wKoaJyGL2IEk3rG/GIvua7Sec7meXVIvGycihlGMx5xcU00kqCJbwzHs18xTu3YfREOqQ+g== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-self" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.7.4" + "@babel/plugin-transform-react-jsx" "^7.7.4" + "@babel/plugin-transform-react-jsx-self" "^7.7.4" + "@babel/plugin-transform-react-jsx-source" "^7.7.4" -"@babel/preset-react@7.6.3", "@babel/preset-react@^7.0.0": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.6.3.tgz#d5242c828322520205ae4eda5d4f4f618964e2f6" - integrity sha512-07yQhmkZmRAfwREYIQgW0HEwMY9GBJVuPY4Q12UC72AbfaawuupVWa8zQs2tlL+yun45Nv/1KreII/0PLfEsgA== +"@babel/preset-typescript@7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.7.4.tgz#780059a78e6fa7f7a4c87f027292a86b31ce080a" + integrity sha512-rqrjxfdiHPsnuPur0jKrIIGQCIgoTWMTjlbWE69G4QJ6TIOVnnRnIJhUxNTL/VwDmEAVX08Tq3B1nirer5341w== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-self" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.7.4" -"@babel/preset-typescript@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.6.0.tgz#25768cb8830280baf47c45ab1a519a9977498c98" - integrity sha512-4xKw3tTcCm0qApyT6PqM9qniseCE79xGHiUnNdKGdxNsGUc2X7WwZybqIpnTmoukg3nhPceI5KPNzNqLNeIJww== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.6.0" - -"@babel/runtime@7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.0.tgz#4fc1d642a9fd0299754e8b5de62c631cf5568205" - integrity sha512-89eSBLJsxNxOERC0Op4vd+0Bqm6wRMqMbFtV3i0/fbaWw/mJ8Q3eBvgX0G4SyrOOLCtbu98HspF8o09MRT+KzQ== +"@babel/runtime@7.7.4", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.4.tgz#b23a856751e4bf099262f867767889c0e3fe175b" + integrity sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw== dependencies: regenerator-runtime "^0.13.2" -"@babel/runtime@7.6.3", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f" - integrity sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA== - dependencies: - regenerator-runtime "^0.13.2" - -"@babel/template@^7.1.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6" - integrity sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ== +"@babel/template@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" + integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.6.0" - "@babel/types" "^7.6.0" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5", "@babel/traverse@^7.6.0", "@babel/traverse@^7.6.2", "@babel/traverse@^7.6.3": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.3.tgz#66d7dba146b086703c0fb10dd588b7364cec47f9" - integrity sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw== +"@babel/traverse@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" + integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== dependencies: "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.6.3" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/parser" "^7.6.3" - "@babel/types" "^7.6.3" + "@babel/generator" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0", "@babel/types@^7.6.3": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.3.tgz#3f07d96f854f98e2fbd45c64b0cb942d11e8ba09" - integrity sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA== +"@babel/types@^7.4.4", "@babel/types@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" + integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA== dependencies: esutils "^2.0.2" lodash "^4.17.13" @@ -929,35 +877,35 @@ "@emotion/weak-memoize" "0.2.4" "@emotion/core@^10.0.14": - version "10.0.21" - resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.21.tgz#2e8398d2b92fd90d4ed6ac4d0b66214971de3458" - integrity sha512-U9zbc7ovZ2ceIwbLXYZPJy6wPgnOdTNT4jENZ31ee6v2lojetV5bTbCVk6ciT8G3wQRyVaTTfUCH9WCrMzpRIw== + version "10.0.22" + resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.22.tgz#2ac7bcf9b99a1979ab5b0a876fbf37ab0688b177" + integrity sha512-7eoP6KQVUyOjAkE6y4fdlxbZRA4ILs7dqkkm6oZUJmihtHv0UBq98VgPirq9T8F9K2gKu0J/au/TpKryKMinaA== dependencies: "@babel/runtime" "^7.5.5" "@emotion/cache" "^10.0.17" - "@emotion/css" "^10.0.14" - "@emotion/serialize" "^0.11.10" + "@emotion/css" "^10.0.22" + "@emotion/serialize" "^0.11.12" "@emotion/sheet" "0.9.3" "@emotion/utils" "0.11.2" -"@emotion/css@^10.0.14": - version "10.0.14" - resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.14.tgz#95dacabdd0e22845d1a1b0b5968d9afa34011139" - integrity sha512-MozgPkBEWvorcdpqHZE5x1D/PLEHUitALQCQYt2wayf4UNhpgQs2tN0UwHYS4FMy5ROBH+0ALyCFVYJ/ywmwlg== +"@emotion/css@^10.0.22": + version "10.0.22" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.22.tgz#37b1abb6826759fe8ac0af0ac0034d27de6d1793" + integrity sha512-8phfa5mC/OadBTmGpMpwykIVH0gFCbUoO684LUkyixPq4F1Wwri7fK5Xlm8lURNBrd2TuvTbPUGxFsGxF9UacA== dependencies: - "@emotion/serialize" "^0.11.8" + "@emotion/serialize" "^0.11.12" "@emotion/utils" "0.11.2" - babel-plugin-emotion "^10.0.14" + babel-plugin-emotion "^10.0.22" "@emotion/hash@0.7.3": version "0.7.3" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.7.3.tgz#a166882c81c0c6040975dd30df24fae8549bd96f" integrity sha512-14ZVlsB9akwvydAdaEnVnvqu6J2P6ySv39hYyl/aoB6w/V+bXX0tay8cF6paqbgZsN2n5Xh15uF4pE+GvE+itw== -"@emotion/is-prop-valid@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.3.tgz#cbe62ddbea08aa022cdf72da3971570a33190d29" - integrity sha512-We7VBiltAJ70KQA0dWkdPMXnYoizlxOXpvtjmu5/MBnExd+u0PGgV27WCYanmLAbCwAU30Le/xA0CQs/F/Otig== +"@emotion/is-prop-valid@0.8.5": + version "0.8.5" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.5.tgz#2dda0791f0eafa12b7a0a5b39858405cc7bde983" + integrity sha512-6ZODuZSFofbxSbcxwsFz+6ioPjb0ISJRRPLZ+WIbjcU2IMU0Io+RGQjjaTgOvNQl007KICBm7zXQaYQEC1r6Bg== dependencies: "@emotion/memoize" "0.7.3" @@ -966,10 +914,10 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.3.tgz#5b6b1c11d6a6dddf1f2fc996f74cf3b219644d78" integrity sha512-2Md9mH6mvo+ygq1trTeVp2uzAKwE2P7In0cRpD/M9Q70aH8L+rxMLbb3JCN2JoSWsV2O+DdFjfbbXoMoLBczow== -"@emotion/serialize@^0.11.10", "@emotion/serialize@^0.11.11", "@emotion/serialize@^0.11.8": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.11.tgz#c92a5e5b358070a7242d10508143306524e842a4" - integrity sha512-YG8wdCqoWtuoMxhHZCTA+egL0RSGdHEc+YCsmiSBPBEDNuVeMWtjEWtGrhUterSChxzwnWBXvzSxIFQI/3sHLw== +"@emotion/serialize@^0.11.12", "@emotion/serialize@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.14.tgz#56a6d8d04d837cc5b0126788b2134c51353c6488" + integrity sha512-6hTsySIuQTbDbv00AnUO6O6Xafdwo5GswRlMZ5hHqiFx+4pZ7uGWXUQFW46Kc2taGhP89uXMXn/lWQkdyTosPA== dependencies: "@emotion/hash" "0.7.3" "@emotion/memoize" "0.7.3" @@ -982,23 +930,23 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.3.tgz#689f135ecf87d3c650ed0c4f5ddcbe579883564a" integrity sha512-c3Q6V7Df7jfwSq5AzQWbXHa5soeE4F5cbqi40xn0CzXxWW9/6Mxq48WJEtqfWzbZtW9odZdnRAkwCQwN12ob4A== -"@emotion/styled-base@^10.0.17": - version "10.0.19" - resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.19.tgz#53655274797194d86453354fdb2c947b46032db6" - integrity sha512-Sz6GBHTbOZoeZQKvkE9gQPzaJ6/qtoQ/OPvyG2Z/6NILlYk60Es1cEcTgTkm26H8y7A0GSgp4UmXl+srvsnFPg== +"@emotion/styled-base@^10.0.23": + version "10.0.24" + resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.24.tgz#9497efd8902dfeddee89d24b0eeb26b0665bfe8b" + integrity sha512-AnBImerf0h4dGAJVo0p0VE8KoAns71F28ErGFK474zbNAHX6yqSWQUasb+1jvg/VPwZjCp19+tAr6oOB0pwmLQ== dependencies: "@babel/runtime" "^7.5.5" - "@emotion/is-prop-valid" "0.8.3" - "@emotion/serialize" "^0.11.11" + "@emotion/is-prop-valid" "0.8.5" + "@emotion/serialize" "^0.11.14" "@emotion/utils" "0.11.2" "@emotion/styled@^10.0.14": - version "10.0.17" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.17.tgz#0cd38b8b36259541f2c6717fc22607a120623654" - integrity sha512-zHMgWjHDMNjD+ux64POtDnjLAObniu3znxFBLSdV/RiEhSLjHIowfvSbbd/C33/3uwtI6Uzs2KXnRZtka/PpAQ== + version "10.0.23" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.23.tgz#2f8279bd59b99d82deade76d1046249ddfab7c1b" + integrity sha512-gNr04eqBQ2iYUx8wFLZDfm3N8/QUOODu/ReDXa693uyQGy2OqA+IhPJk+kA7id8aOfwAsMuvZ0pJImEXXKtaVQ== dependencies: - "@emotion/styled-base" "^10.0.17" - babel-plugin-emotion "^10.0.17" + "@emotion/styled-base" "^10.0.23" + babel-plugin-emotion "^10.0.23" "@emotion/stylis@0.8.4": version "0.8.4" @@ -1044,17 +992,17 @@ react-lifecycles-compat "^3.0.4" warning "^3.0.0" -"@storybook/addon-actions@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.2.5.tgz#e8279907367392387d5c3c6af6031f9da2be9816" - integrity sha512-81N+M1GX4XB7Mirhhu3kiZJkjspfk2e1ysoJtwULjWeZfo2CLYLUAil4onr08Os2LH4RLJaj2hpS3hLflBio4g== +"@storybook/addon-actions@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.2.8.tgz#f63c6e1afb59e94ca1ebc776b7cad9b815e7419e" + integrity sha512-hadk+UaU6upOW0g447RfLRrnXRgE2rjRVk5sT8mVxBMj032NnwUd7ie/BZwy1yg5B8oFtpkgQYwqhPtoO2xBaQ== dependencies: - "@storybook/addons" "5.2.5" - "@storybook/api" "5.2.5" - "@storybook/client-api" "5.2.5" - "@storybook/components" "5.2.5" - "@storybook/core-events" "5.2.5" - "@storybook/theming" "5.2.5" + "@storybook/addons" "5.2.8" + "@storybook/api" "5.2.8" + "@storybook/client-api" "5.2.8" + "@storybook/components" "5.2.8" + "@storybook/core-events" "5.2.8" + "@storybook/theming" "5.2.8" core-js "^3.0.1" fast-deep-equal "^2.0.1" global "^4.3.2" @@ -1071,29 +1019,29 @@ dependencies: global "^4.3.2" -"@storybook/addons@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.2.5.tgz#e3e23d5ea6eb221df31e1a5d125be47454e9a0e8" - integrity sha512-CvMj7Bs3go9tv5rZuAvFwuwe8p/16LDCHS7+5nVFosvcL8nuN339V3rzakw8nLy/S6XKeZ1ACu4t3vYkreRE3w== +"@storybook/addons@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.2.8.tgz#f8bf8bd555b7a69fb1e9a52ab8cdb96384d931ff" + integrity sha512-yAo1N5z/45bNIQP8SD+HVTr7X898bYAtz1EZBrQ6zD8bGamzA2Br06rOLL9xXw29eQhsaVnPlqgDwCS1sTC7aQ== dependencies: - "@storybook/api" "5.2.5" - "@storybook/channels" "5.2.5" - "@storybook/client-logger" "5.2.5" - "@storybook/core-events" "5.2.5" + "@storybook/api" "5.2.8" + "@storybook/channels" "5.2.8" + "@storybook/client-logger" "5.2.8" + "@storybook/core-events" "5.2.8" core-js "^3.0.1" global "^4.3.2" util-deprecate "^1.0.2" -"@storybook/api@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.2.5.tgz#dcc68c873820485372a47c095a8fc5e4fb53a34c" - integrity sha512-JvLafqFVgA3dIWpLMoGNk4sRuogE5imhD6/g0d8DOwnCID9xowj5xIptSrCTKvGGGxuN3wWRGn6I2lEbY6969g== +"@storybook/api@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.2.8.tgz#21f03df8041114eb929bd10b570a17f266568b7f" + integrity sha512-rFrPtTFDIPQoicLwq1AVsOvZNTUKnjD1w/NX1kKcyuWLL9BcOkU3YNLBlliGBg2JX/yS+fJKMyKk4NMzNBCZCg== dependencies: - "@storybook/channels" "5.2.5" - "@storybook/client-logger" "5.2.5" - "@storybook/core-events" "5.2.5" - "@storybook/router" "5.2.5" - "@storybook/theming" "5.2.5" + "@storybook/channels" "5.2.8" + "@storybook/client-logger" "5.2.8" + "@storybook/core-events" "5.2.8" + "@storybook/router" "5.2.8" + "@storybook/theming" "5.2.8" core-js "^3.0.1" fast-deep-equal "^2.0.1" global "^4.3.2" @@ -1107,35 +1055,35 @@ telejson "^3.0.2" util-deprecate "^1.0.2" -"@storybook/channel-postmessage@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.2.5.tgz#47397e543a87ea525cbe93f7d85bd8533edc9127" - integrity sha512-GoiC6dUM3YfNKpvj3syxQIQJLHBnH61CfLJzz4xygmn+3keHtjtz6yPHaU4+00MSSP2uDzqePkjgXx4DcLedHA== +"@storybook/channel-postmessage@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.2.8.tgz#7a84869ce0fc270c3b5dcd7fa4ed798b6055816f" + integrity sha512-RS3iDW1kpfODN+kBq3youn+KtLqHslZ4m7mTlOL80BUHKb4YkrA1lVkzpy1kVMWBU523pyDVQUVXr+M8y3iVug== dependencies: - "@storybook/channels" "5.2.5" - "@storybook/client-logger" "5.2.5" + "@storybook/channels" "5.2.8" + "@storybook/client-logger" "5.2.8" core-js "^3.0.1" global "^4.3.2" telejson "^3.0.2" -"@storybook/channels@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.2.5.tgz#d6ca2b490281dacb272096563fe760ccb353c4bb" - integrity sha512-I+zB3ym5ozBcNBqyzZbvB6gRIG/ZKKkqy5k6LwKd5NMx7NU7zU74+LQUBBOcSIrigj8kCArZz7rlgb0tlSKXxQ== +"@storybook/channels@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.2.8.tgz#79a99ad85dcacb688073c22340c5b7d16b801202" + integrity sha512-mFwQec27QSrqcl+IH0xA+4jfoEqC4m1G99LBHt/aTDjLZXclX1A470WqeZCp7Gx4OALpaPEVTaaaKPbiKz4C6w== dependencies: core-js "^3.0.1" -"@storybook/client-api@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.2.5.tgz#53151a236b6ffc2088acc4535a08e010013e3278" - integrity sha512-n7CAZ3+DZ7EUdmXbq8mXRb+stOavC8GMw3CzjGSo8O6t4rFcMpZQAzjS0YRX1RG/CGFSv9d3R3TNvEBcBGTwRg== +"@storybook/client-api@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.2.8.tgz#1de791f7888442287f848e5f544eb883c5edc0da" + integrity sha512-OCKhZ+2sS3ot0ZV48nD79BWVzvvdMjUFYl0073ps5q+1+TLic1AlNmH0Sb5/9NrYXNV86v3VrM2jUbGsKe1qyw== dependencies: - "@storybook/addons" "5.2.5" - "@storybook/channel-postmessage" "5.2.5" - "@storybook/channels" "5.2.5" - "@storybook/client-logger" "5.2.5" - "@storybook/core-events" "5.2.5" - "@storybook/router" "5.2.5" + "@storybook/addons" "5.2.8" + "@storybook/channel-postmessage" "5.2.8" + "@storybook/channels" "5.2.8" + "@storybook/client-logger" "5.2.8" + "@storybook/core-events" "5.2.8" + "@storybook/router" "5.2.8" common-tags "^1.8.0" core-js "^3.0.1" eventemitter3 "^4.0.0" @@ -1144,22 +1092,23 @@ lodash "^4.17.15" memoizerific "^1.11.3" qs "^6.6.0" + stable "^0.1.8" util-deprecate "^1.0.2" -"@storybook/client-logger@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.2.5.tgz#6f386ac6f81b4a783c57d54bb328281abbea1bab" - integrity sha512-6DyYUrMgAvF+th0foH7UNz+2JJpRdvNbpvYKtvi/+hlvRIaI6AqANgLkPUgMibaif5TLzjCr0bLdAYcjeJz03w== +"@storybook/client-logger@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.2.8.tgz#5affe2f9dbbee374721fd2e8729116f5ac39c779" + integrity sha512-+oVSEJdeh7TQ1Bhanb3mCr7fc3Bug3+K79abZ28J45Ub5x4L/ZVClj1xMgUsJs30BZ5FB8vhdgH6TQb0NSxR4A== dependencies: core-js "^3.0.1" -"@storybook/components@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.2.5.tgz#40190dafbee34f083182255d26c19a0ea50789c8" - integrity sha512-6NVaBJm5wY53e9k+2ZiL2ABsHghE1ssQciLTG3jJPahnM6rfkM8ue66rhxhP88jE9isT48JgOZOJepEyxDz/fg== +"@storybook/components@5.2.8", "@storybook/components@^5.2.5": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.2.8.tgz#f5d4a06ba4ba8c700b2d962deae182105b72fb99" + integrity sha512-h9l/LAMaj+emUCOyY/+ETy/S3P0npwQU280J88uL4O9XJALJ72EKfyttBCvMLvpM50E+fAPeDzuYn0t5qzGGxg== dependencies: - "@storybook/client-logger" "5.2.5" - "@storybook/theming" "5.2.5" + "@storybook/client-logger" "5.2.8" + "@storybook/theming" "5.2.8" "@types/react-syntax-highlighter" "10.1.0" "@types/react-textarea-autosize" "^4.3.3" core-js "^3.0.1" @@ -1178,32 +1127,32 @@ react-textarea-autosize "^7.1.0" simplebar-react "^1.0.0-alpha.6" -"@storybook/core-events@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.2.5.tgz#62881164a4a01aa99ff0691e70eaed2dd58e229e" - integrity sha512-O5GM8XEBbYNbM6Z7a4H1bbnbO2cxQrXMhEwansC7a7YinQdkTPiuGxke3NiyK+7pLDh778kpQyjoCjXq6UfAoQ== +"@storybook/core-events@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.2.8.tgz#93fc458ea0820ff1409d268b0fe51abba200f5a4" + integrity sha512-NkQKC5doO/YL9gsO61bqaxgveKktkiJWZ3XyyhL1ZebgnO9wTlrU+i9b5aX73Myk1oxbicQw9KcwDGYk0qFuNQ== dependencies: core-js "^3.0.1" -"@storybook/core@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.2.5.tgz#cc04313480a1847aa6881420c675517cc400dc2e" - integrity sha512-R6A6VzSh++pB1a+9DsywW5Mlp0/eauQz1A8m2DrllWcTHTjbn0ZovlG5HBrKjpknFXpCWxkUKE4eTAE2tWsryA== +"@storybook/core@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.2.8.tgz#3f6ddbacc705c1893deb15582c3a0a1ecd882cd1" + integrity sha512-P1Xx4setLBESPgS5KgL7Jskf5Q6fRa3ApwPt+ocjDoSDGCvsV7cUEpAp09U65u+89e5K4nQxvaZouhknFQBc1A== dependencies: - "@babel/plugin-proposal-class-properties" "^7.3.3" - "@babel/plugin-proposal-object-rest-spread" "^7.3.2" + "@babel/plugin-proposal-class-properties" "^7.7.0" + "@babel/plugin-proposal-object-rest-spread" "^7.6.2" "@babel/plugin-syntax-dynamic-import" "^7.2.0" - "@babel/plugin-transform-react-constant-elements" "^7.2.0" - "@babel/preset-env" "^7.4.5" - "@storybook/addons" "5.2.5" - "@storybook/channel-postmessage" "5.2.5" - "@storybook/client-api" "5.2.5" - "@storybook/client-logger" "5.2.5" - "@storybook/core-events" "5.2.5" - "@storybook/node-logger" "5.2.5" - "@storybook/router" "5.2.5" - "@storybook/theming" "5.2.5" - "@storybook/ui" "5.2.5" + "@babel/plugin-transform-react-constant-elements" "^7.6.3" + "@babel/preset-env" "^7.7.1" + "@storybook/addons" "5.2.8" + "@storybook/channel-postmessage" "5.2.8" + "@storybook/client-api" "5.2.8" + "@storybook/client-logger" "5.2.8" + "@storybook/core-events" "5.2.8" + "@storybook/node-logger" "5.2.8" + "@storybook/router" "5.2.8" + "@storybook/theming" "5.2.8" + "@storybook/ui" "5.2.8" airbnb-js-shims "^1 || ^2" ansi-to-html "^0.6.11" autoprefixer "^9.4.9" @@ -1259,10 +1208,10 @@ webpack-dev-middleware "^3.7.0" webpack-hot-middleware "^2.25.0" -"@storybook/node-logger@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.2.5.tgz#87f53de795db6eed912b54d3cca82fd7b7857771" - integrity sha512-UNyXGOhOr4Bn9wKwBTZABTBXQzrgvGxPLSmvAFZuMx9ZhqoT/EXAuLUl0/wiJtkyuYpoOOskNwIdKxLBdTKS2w== +"@storybook/node-logger@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.2.8.tgz#4a3df21d731014d54b9ca53d5b9a72dd350bb075" + integrity sha512-3TK5mx6VWbfJO+WUrqwPhTbTQ4qESTnwJY/02xPzOhvuC6tIG1QOxzi+Rq6rFlwxTpUuWh6iyDYnGIqFFQywkA== dependencies: chalk "^2.4.2" core-js "^3.0.1" @@ -1270,17 +1219,17 @@ pretty-hrtime "^1.0.3" regenerator-runtime "^0.12.1" -"@storybook/react@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.2.5.tgz#f0082d75b14a10642986c7934fcbc8ff855b07fe" - integrity sha512-yPOL0jBEfYo3YkRJkXnIzAQ3L9lTju27mg+0bW+y3lpJAM23ffAxrRyOGV7bzj99EA7dak2lw8Hj4yVHTplBdg== +"@storybook/react@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.2.8.tgz#8d44c2d34caa1d7d748ec1fc9cf0fe2a88b001f9" + integrity sha512-T1DoWpSz33vaGx85Dh7q2KYetg7dQyiYhuOnZm2WxZTFZOw1jP62si53JGFp0PKxnT6iOBLHo3v2QkRkjt2mdQ== dependencies: - "@babel/plugin-transform-react-constant-elements" "^7.2.0" + "@babel/plugin-transform-react-constant-elements" "^7.6.3" "@babel/preset-flow" "^7.0.0" - "@babel/preset-react" "^7.0.0" - "@storybook/addons" "5.2.5" - "@storybook/core" "5.2.5" - "@storybook/node-logger" "5.2.5" + "@babel/preset-react" "^7.7.0" + "@storybook/addons" "5.2.8" + "@storybook/core" "5.2.8" + "@storybook/node-logger" "5.2.8" "@svgr/webpack" "^4.0.3" "@types/webpack-env" "^1.13.7" babel-plugin-add-react-displayname "^0.0.5" @@ -1298,10 +1247,10 @@ semver "^6.0.0" webpack "^4.33.0" -"@storybook/router@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.2.5.tgz#a005332bc6aa1e7849503187ad50c41b3f3bef92" - integrity sha512-e6ElDAWSoEW1KSnsTbVwbpzaZ8CNWYw0Ok3b5AHfY2fuSH5L4l6s6k/bP7QSYqvWUeTvkFQYux7A2rOFCriAgA== +"@storybook/router@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.2.8.tgz#d7de2d401701857c033e28560c30e16512f7f72f" + integrity sha512-wnbyKESUMyv9fwo9W+n4Fev/jXylB8whpjtHrOttjguUOYX1zGSHdwNI66voPetbtVLxUeHyJteJwdyRDSirJg== dependencies: "@reach/router" "^1.2.1" "@types/reach__router" "^1.2.3" @@ -1311,14 +1260,14 @@ memoizerific "^1.11.3" qs "^6.6.0" -"@storybook/theming@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.2.5.tgz#9579e7944f61ded637d1d79be5fb859a617620f5" - integrity sha512-PGZNYrRgAhXFJKnktFpyyKlaDXEhtTi5XPq5ASVJrsPW6l963Mk2EMKSm4TCTxIJhs0Kx4cv2MnNZFDqHf47eg== +"@storybook/theming@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.2.8.tgz#a4c9e0e9a5789c1aa71e4fcb7a8ee86efe3dadcf" + integrity sha512-rGb66GkXb0jNJMH8UQ3Ru4FL+m1x0+UdxM8a8HSE/qb1GMv2qOwjVETfAL6nVL9u6ZmrtbhHoero4f6xDwZdRg== dependencies: "@emotion/core" "^10.0.14" "@emotion/styled" "^10.0.14" - "@storybook/client-logger" "5.2.5" + "@storybook/client-logger" "5.2.8" common-tags "^1.8.0" core-js "^3.0.1" deep-object-diff "^1.1.0" @@ -1329,19 +1278,19 @@ prop-types "^15.7.2" resolve-from "^5.0.0" -"@storybook/ui@5.2.5": - version "5.2.5" - resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.2.5.tgz#0c2c67216e4c808e39cdb48301cafde81b77d074" - integrity sha512-C+5KmeTtdG6xkGXPmFDHPxTcSvVohuFD1399fnzjYhfLlRJ04ix3g16rcyDTxRtrFgFidOyGHdzCypgkdaN8dQ== +"@storybook/ui@5.2.8": + version "5.2.8" + resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.2.8.tgz#da8afca9eb29a40ef3ddc6a9f6e76d7a3344f2ef" + integrity sha512-7t1ARBfylhEsLmGsZBUCj1Wf1oAgCDDrf7fi+Fhdg5Rr16CMoBbe24Gv/mPYv01/pUDhGodxzltKGX5x0Hto2w== dependencies: - "@storybook/addons" "5.2.5" - "@storybook/api" "5.2.5" - "@storybook/channels" "5.2.5" - "@storybook/client-logger" "5.2.5" - "@storybook/components" "5.2.5" - "@storybook/core-events" "5.2.5" - "@storybook/router" "5.2.5" - "@storybook/theming" "5.2.5" + "@storybook/addons" "5.2.8" + "@storybook/api" "5.2.8" + "@storybook/channels" "5.2.8" + "@storybook/client-logger" "5.2.8" + "@storybook/components" "5.2.8" + "@storybook/core-events" "5.2.8" + "@storybook/router" "5.2.8" + "@storybook/theming" "5.2.8" copy-to-clipboard "^3.0.8" core-js "^3.0.1" core-js-pure "^3.0.1" @@ -1506,9 +1455,14 @@ integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*": - version "12.11.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.5.tgz#6c3c8dc84988aff11fd2a63d7b5fbf39eaaab7b1" - integrity sha512-LC8ALj/24PhByn39nr5jnTvpE7MujK8y7LQmV74kHYF5iQ0odCPkMH4IZNZw+cobKfSXqaC8GgegcbIsQpffdA== + version "12.12.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.14.tgz#1c1d6e3c75dba466e0326948d56e8bd72a1903d2" + integrity sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prop-types@*": version "15.7.3" @@ -1536,16 +1490,16 @@ "@types/react" "*" "@types/react-textarea-autosize@^4.3.3": - version "4.3.4" - resolved "https://registry.yarnpkg.com/@types/react-textarea-autosize/-/react-textarea-autosize-4.3.4.tgz#9a93f751c91ad5e86387bce75e3b7e11ed195813" - integrity sha512-LLqG27BJGt8ja9x4umQXbnK9pRd0dI23X/GXBcuf476feOZ+e5QiKJYmWOHwAJC3YLl3YixDSigzfF4gzVQZ5w== + version "4.3.5" + resolved "https://registry.yarnpkg.com/@types/react-textarea-autosize/-/react-textarea-autosize-4.3.5.tgz#6c4d2753fa1864c98c0b2b517f67bb1f6e4c46de" + integrity sha512-PiDL83kPMTolyZAWW3lyzO6ktooTb9tFTntVy7CA83/qFLWKLJ5bLeRboy6J6j3b1e8h2Eec6gBTEOOJRjV14A== dependencies: "@types/react" "*" "@types/react@*": - version "16.9.9" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.9.tgz#a62c6f40f04bc7681be5e20975503a64fe783c3a" - integrity sha512-L+AudFJkDukk+ukInYvpoAPyJK5q1GanFOINOJnM0w6tUgITuWvJ4jyoBPFL7z4/L8hGLd+K/6xR5uUjXu0vVg== + version "16.9.15" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.15.tgz#aeabb7a50f96c9e31a16079ada20ede9ed602977" + integrity sha512-WsmM1b6xQn1tG3X2Hx4F3bZwc2E82pJXt5OPs2YJgg71IzvUoKOSSSYOvLXYCg1ttipM+UuA4Lj3sfvqjVxyZw== dependencies: "@types/prop-types" "*" csstype "^2.2.0" @@ -1582,9 +1536,9 @@ source-map "^0.6.1" "@types/webpack@^4.4.31": - version "4.39.5" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.39.5.tgz#3671b65928d9e0c6fcd4adff3f8167d48b174681" - integrity sha512-9twG6D97ao13MBLvigwfBJe6rxtb04UY3TcYHBYkW5sXZjUrNhqIRxLYg74VzK/YAE8xlVhOyd+3Whr7E5RrBA== + version "4.41.0" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.0.tgz#b813a044d8b0dec7dfcd7622fdbe327bde06eb9a" + integrity sha512-tWkdf9nO0zFgAY/EumUKwrDUhraHKDqCPhwfFR/R8l0qnPdgb9le0Gzhvb7uzVpouuDGBgiE//ZdY+5jcZy2TA== dependencies: "@types/anymatch" "*" "@types/node" "*" @@ -1770,9 +1724,9 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: negotiator "0.6.2" acorn@^6.2.1: - version "6.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" - integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== + version "6.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" + integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== address@1.1.2, address@^1.0.1: version "1.1.2" @@ -1788,9 +1742,9 @@ aggregate-error@^3.0.0: indent-string "^4.0.0" "airbnb-js-shims@^1 || ^2": - version "2.2.0" - resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-2.2.0.tgz#46e1d9d9516f704ef736de76a3b6d484df9a96d8" - integrity sha512-pcSQf1+Kx7/0ibRmxj6rmMYc5V8SHlKu+rkQ80h0bjSLDaIxHg/3PiiFJi4A9mDc01CoBHoc8Fls2G/W0/+s5g== + version "2.2.1" + resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz#db481102d682b98ed1daa4c5baa697a05ce5c040" + integrity sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ== dependencies: array-includes "^3.0.3" array.prototype.flat "^1.2.1" @@ -1805,7 +1759,7 @@ aggregate-error@^3.0.0: object.values "^1.1.0" promise.allsettled "^1.0.0" promise.prototype.finally "^3.1.0" - string.prototype.matchall "^3.0.1" + string.prototype.matchall "^4.0.0 || ^3.0.1" string.prototype.padend "^3.0.0" string.prototype.padstart "^3.0.0" symbol.prototype.description "^1.0.0" @@ -1885,9 +1839,9 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: color-convert "^1.9.0" ansi-to-html@^0.6.11: - version "0.6.12" - resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.12.tgz#9dcd1646f17770d02ec065615e97f979f4e313cb" - integrity sha512-qBkIqLW979675mP76yB7yVkzeAWtATegdnDQ0RA3CZzknx0yUlNxMSML4xFdBfTs2GWYFQ1FELfbGbVSPzJ+LA== + version "0.6.13" + resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.13.tgz#c72eae8b63e5ca0643aab11bfc6e6f2217425833" + integrity sha512-Ys2/umuaTlQvP9DLkaa7UzRKF2FLrfod/hNHXS9QhXCrw7seObG6ksOGmNz3UoK+adwM8L9vQfG7mvaxfJ3Jvw== dependencies: entities "^1.1.2" @@ -2074,16 +2028,16 @@ atob@^2.1.1: integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== autoprefixer@^9.4.7, autoprefixer@^9.4.9: - version "9.6.5" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.5.tgz#98f4afe7e93cccf323287515d426019619775e5e" - integrity sha512-rGd50YV8LgwFQ2WQp4XzOTG69u1qQsXn0amww7tjqV5jJuNazgFKYEVItEBngyyvVITKOg20zr2V+9VsrXJQ2g== + version "9.7.3" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.3.tgz#fd42ed03f53de9beb4ca0d61fb4f7268a9bb50b4" + integrity sha512-8T5Y1C5Iyj6PgkPSFd0ODvK9DIleuPKUPYniNxybS47g2k2wFgLZ46lGQHlBuGKIAEV8fbCDfKCCRS1tvOgc3Q== dependencies: - browserslist "^4.7.0" - caniuse-lite "^1.0.30000999" + browserslist "^4.8.0" + caniuse-lite "^1.0.30001012" chalk "^2.4.2" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^7.0.18" + postcss "^7.0.23" postcss-value-parser "^4.0.2" aws-sign2@~0.7.0: @@ -2092,9 +2046,9 @@ aws-sign2@~0.7.0: integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + version "1.9.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" + integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A== babel-code-frame@^6.22.0: version "6.26.0" @@ -2162,15 +2116,15 @@ babel-plugin-dynamic-import-node@2.3.0, babel-plugin-dynamic-import-node@^2.3.0: dependencies: object.assign "^4.1.0" -babel-plugin-emotion@^10.0.14, babel-plugin-emotion@^10.0.17: - version "10.0.21" - resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.21.tgz#9ebeb12edeea3e60a5476b0e07c9868605e65968" - integrity sha512-03o+T6sfVAJhNDcSdLapgv4IeewcFPzxlvBUVdSf7o5PI57ZSxoDvmy+ZulVWSu+rOWAWkEejNcsb29TuzJHbg== +babel-plugin-emotion@^10.0.14, babel-plugin-emotion@^10.0.22, babel-plugin-emotion@^10.0.23: + version "10.0.23" + resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.23.tgz#040d40bf61dcab6d31dd6043d10e180240b8515b" + integrity sha512-1JiCyXU0t5S2xCbItejCduLGGcKmF3POT0Ujbexog2MI4IlRcIn/kWjkYwCUZlxpON0O5FC635yPl/3slr7cKQ== dependencies: "@babel/helper-module-imports" "^7.0.0" "@emotion/hash" "0.7.3" "@emotion/memoize" "0.7.3" - "@emotion/serialize" "^0.11.11" + "@emotion/serialize" "^0.11.14" babel-plugin-macros "^2.0.0" babel-plugin-syntax-jsx "^6.18.0" convert-source-map "^1.5.0" @@ -2178,14 +2132,14 @@ babel-plugin-emotion@^10.0.14, babel-plugin-emotion@^10.0.17: find-root "^1.1.0" source-map "^0.5.7" -babel-plugin-macros@2.6.1, babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.4.5: - version "2.6.1" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.6.1.tgz#41f7ead616fc36f6a93180e89697f69f51671181" - integrity sha512-6W2nwiXme6j1n2erPOnmRiWfObUhWH7Qw1LMi9XZy8cj+KtESu3T6asZvtk5bMQQjX8te35o7CFueiSdL/2NmQ== +babel-plugin-macros@2.7.1, babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.4.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.7.1.tgz#ee294383c1a38f9d6535be3d89734824cb3ed415" + integrity sha512-HNM284amlKSQ6FddI4jLXD+XTqF0cTYOe5uemOIZxHJHnamC+OhFQ57rMF9sgnYhkJQptVl9U1SKVZsV9/GLQQ== dependencies: - "@babel/runtime" "^7.4.2" - cosmiconfig "^5.2.0" - resolve "^1.10.0" + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" babel-plugin-minify-builtins@^0.5.0: version "0.5.0" @@ -2264,17 +2218,17 @@ babel-plugin-minify-type-constructors@^0.4.3: babel-helper-is-void-0 "^0.4.3" babel-plugin-named-asset-import@^0.3.1: - version "0.3.4" - resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.4.tgz#4a8fc30e9a3e2b1f5ed36883386ab2d84e1089bd" - integrity sha512-S6d+tEzc5Af1tKIMbsf2QirCcPdQ+mKUCY2H1nJj1DyA1ShwpsoxEOAwbWsG5gcXNV/olpvQd9vrUWRx4bnhpw== + version "0.3.5" + resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.5.tgz#d3fa1a7f1f4babd4ed0785b75e2f926df0d70d0d" + integrity sha512-sGhfINU+AuMw9oFAdIn/nD5sem3pn/WgxAfDZ//Q3CnF+5uaho7C7shh2rKLk6sKE/XkfmyibghocwKdVjLIKg== babel-plugin-react-docgen@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-3.1.0.tgz#14b02b363a38cc9e08c871df16960d27ef92030f" - integrity sha512-W6xqZnZIWjZuE9IjP7XolxxgFGB5Y9GZk4cLPSWKa10MrT86q7bX4ke9jbrNhFVIRhbmzL8wE1Sn++mIWoJLbw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-3.2.0.tgz#c072364d61d1f6bb19a6ca81734fc270870e8b96" + integrity sha512-MZ3fhnJ+/tUDhWFGgWsajuLct/dD1xoprmStqrBgtt9flFLPrKIOKOfqwjXjsn6/THs5QrG5rkcDFE3TMMZDjQ== dependencies: - lodash "^4.17.11" - react-docgen "^4.1.0" + lodash "^4.17.15" + react-docgen "^4.1.1" recast "^0.14.7" babel-plugin-syntax-jsx@^6.18.0: @@ -2376,25 +2330,28 @@ babel-plugin-transform-undefined-to-void@^6.9.4: lodash "^4.17.11" babel-preset-react-app@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-9.0.2.tgz#247d37e883d6d6f4b4691e5f23711bb2dd80567d" - integrity sha512-aXD+CTH8Chn8sNJr4tO/trWKqe5sSE4hdO76j9fhVezJSzmpWYWUSc5JoPmdSxADwef5kQFNGKXd433vvkd2VQ== + version "9.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-9.1.0.tgz#74c644d809f098d4b131646730c7bed0696084ca" + integrity sha512-0qMOv/pCcCQWxX1eNyKD9GlzZTdzZIK/Pq3O6TGe65tZSJTSplw1pFlaPujm0GjBj4g3GeCQbP08vvzlH7OGHg== dependencies: - "@babel/core" "7.6.0" - "@babel/plugin-proposal-class-properties" "7.5.5" - "@babel/plugin-proposal-decorators" "7.6.0" - "@babel/plugin-proposal-object-rest-spread" "7.5.5" - "@babel/plugin-syntax-dynamic-import" "7.2.0" - "@babel/plugin-transform-destructuring" "7.6.0" - "@babel/plugin-transform-flow-strip-types" "7.4.4" - "@babel/plugin-transform-react-display-name" "7.2.0" - "@babel/plugin-transform-runtime" "7.6.0" - "@babel/preset-env" "7.6.0" - "@babel/preset-react" "7.0.0" - "@babel/preset-typescript" "7.6.0" - "@babel/runtime" "7.6.0" + "@babel/core" "7.7.4" + "@babel/plugin-proposal-class-properties" "7.7.4" + "@babel/plugin-proposal-decorators" "7.7.4" + "@babel/plugin-proposal-nullish-coalescing-operator" "7.7.4" + "@babel/plugin-proposal-numeric-separator" "7.7.4" + "@babel/plugin-proposal-object-rest-spread" "7.7.4" + "@babel/plugin-proposal-optional-chaining" "7.7.4" + "@babel/plugin-syntax-dynamic-import" "7.7.4" + "@babel/plugin-transform-destructuring" "7.7.4" + "@babel/plugin-transform-flow-strip-types" "7.7.4" + "@babel/plugin-transform-react-display-name" "7.7.4" + "@babel/plugin-transform-runtime" "7.7.4" + "@babel/preset-env" "7.7.4" + "@babel/preset-react" "7.7.4" + "@babel/preset-typescript" "7.7.4" + "@babel/runtime" "7.7.4" babel-plugin-dynamic-import-node "2.3.0" - babel-plugin-macros "2.6.1" + babel-plugin-macros "2.7.1" babel-plugin-transform-react-remove-prop-types "0.4.24" babel-runtime@^6.18.0, babel-runtime@^6.26.0: @@ -2461,9 +2418,9 @@ binary-extensions@^1.0.0: integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== bluebird@^3.3.5, bluebird@^3.5.5: - version "3.7.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" - integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" @@ -2614,14 +2571,14 @@ browserslist@4.7.0: electron-to-chromium "^1.3.247" node-releases "^1.1.29" -browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.7.0, browserslist@^4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.1.tgz#bd400d1aea56538580e8c4d5f1c54ac11b5ab468" - integrity sha512-QtULFqKIAtiyNx7NhZ/p4rB8m3xDozVo/pi5VgTlADLF2tNigz/QH+v0m5qhn7XfHT7u+607NcCNOnC0HZAlMg== +browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.8.0: + version "4.8.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.1.tgz#df0f50cc4b3255322fae60ae82a946baae69f8c6" + integrity sha512-X/lIDboA5bvFg9SOhHN7OBgHHlaZQWcwTXBLBGgrB8+6Iy1dL0wmUfHRe7OdETRTuD2d6f5JPa7iTEcbVyVf6Q== dependencies: - caniuse-lite "^1.0.30000999" - electron-to-chromium "^1.3.284" - node-releases "^1.1.36" + caniuse-lite "^1.0.30001015" + electron-to-chromium "^1.3.322" + node-releases "^1.1.42" buffer-from@^1.0.0: version "1.1.1" @@ -2639,9 +2596,9 @@ buffer-xor@^1.0.3: integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= buffer@^4.3.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -2662,27 +2619,7 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -cacache@^11.3.3: - version "11.3.3" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc" - integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^12.0.2: +cacache@^12.0.2, cacache@^12.0.3: version "12.0.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== @@ -2766,6 +2703,11 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camel-case@3.0.x, camel-case@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" @@ -2794,10 +2736,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30000999: - version "1.0.30001002" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001002.tgz#ba999a737b1abd5bf0fd47efe43a09b9cadbe9b0" - integrity sha512-pRuxPE8wdrWmVPKcDmJJiGBxr6lFJq4ivdSeo9FTmGj5Rb8NX3Mby2pARG57MXF15hYAhZ0nHV5XxT2ig4bz3g== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001012, caniuse-lite@^1.0.30001015: + version "1.0.30001015" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz#15a7ddf66aba786a71d99626bc8f2b91c6f0f5f0" + integrity sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ== case-sensitive-paths-webpack-plugin@^2.2.0: version "2.2.0" @@ -3070,11 +3012,16 @@ commander@2.17.x: resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== -commander@^2.19.0, commander@^2.20.0, commander@~2.20.3: +commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +commander@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.0.1.tgz#b67622721785993182e807f4883633e6401ba53c" + integrity sha512-IPF4ouhCP+qdlcmCedhxX4xiGBPyigb8v5NeUp+0LyhwLgxMqyp3S0vl7TAPfS/hiP7FC3caI/PB9lTmP8r1NA== + commander@~2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -3144,11 +3091,9 @@ connect-history-api-fallback@^1.6.0: integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= - dependencies: - date-now "^0.1.4" + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" @@ -3172,10 +3117,10 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.1.0, convert-source-map@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== +convert-source-map@^1.5.0, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== dependencies: safe-buffer "~5.1.1" @@ -3213,12 +3158,12 @@ copy-to-clipboard@^3.0.8: dependencies: toggle-selection "^1.0.6" -copy-webpack-plugin@5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.0.4.tgz#c78126f604e24f194c6ec2f43a64e232b5d43655" - integrity sha512-YBuYGpSzoCHSSDGyHy6VJ7SHojKp6WHT4D7ItcQFNAYx2hrwkMe56e97xfVR0/ovDuMTrMffXUiltvQljtAGeg== +copy-webpack-plugin@5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.0.5.tgz#731df6a837a2ef0f8f8e2345bdfe9b7c62a2da68" + integrity sha512-7N68eIoQTyudAuxkfPT7HzGoQ+TsmArN/I3HFwG+lVE3FNzqvZKIiaxtYh4o3BIznioxUvx9j26+Rtsc9htQUQ== dependencies: - cacache "^11.3.3" + cacache "^12.0.3" find-cache-dir "^2.1.0" glob-parent "^3.1.0" globby "^7.1.1" @@ -3226,23 +3171,23 @@ copy-webpack-plugin@5.0.4: loader-utils "^1.2.3" minimatch "^3.0.4" normalize-path "^3.0.0" - p-limit "^2.2.0" + p-limit "^2.2.1" schema-utils "^1.0.0" - serialize-javascript "^1.7.0" + serialize-javascript "^2.1.0" webpack-log "^2.0.0" core-js-compat@^3.1.1: - version "3.3.3" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.3.3.tgz#82642808cf484a35292b2f8e83ef9376884e760f" - integrity sha512-GNZkENsx5pMnS7Inwv7ZO/s3B68a9WU5kIjxqrD/tkNR8mtfXJRk8fAKRlbvWZSGPc59/TkiOBDYl5Cb65pTVA== + version "3.4.7" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.4.7.tgz#39f8080b1d92a524d6d90505c42b9c5c1eb90611" + integrity sha512-57+mgz/P/xsGdjwQYkwtBZR3LuISaxD1dEwVDtbk8xJMqAmwqaxLOvnNT7kdJ7jYE/NjNptyzXi+IQFMi/2fCw== dependencies: - browserslist "^4.7.1" + browserslist "^4.8.0" semver "^6.3.0" core-js-pure@^3.0.1: - version "3.3.3" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.3.3.tgz#c6a796e371782394ffb60d82ff67e0e073070093" - integrity sha512-sBLE90LngoFYwhLsy5ftt+WWxkQnMufRsn2uyYxJxW73SkvAlxonAdZARimkKrK1c+w01eX9r19vA/J5KMtqfA== + version "3.4.7" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.4.7.tgz#c998e1892da9949200c7452cbd33c0df95be9f54" + integrity sha512-Am3uRS8WCdTFA3lP7LtKR0PxgqYzjAMGKXaZKSNSC/8sqU0Wfq8R/YzoRs2rqtOVEunfgH+0q3O0BKOg0AvjPw== core-js@^1.0.0: version "1.2.7" @@ -3255,9 +3200,9 @@ core-js@^2.4.0: integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA== core-js@^3.0.1, core-js@^3.0.4: - version "3.3.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.3.3.tgz#b7048d3c6c1a52b5fe55a729c1d4ccdffe0891bb" - integrity sha512-0xmD4vUJRY8nfLyV9zcpC17FtSie5STXzw+HyYw2t8IIvmDnbq7RJUULECCo+NstpJtwK9kx8S+898iyqgeUow== + version "3.4.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.4.7.tgz#57c35937da80fe494fbc3adcf9cf3dc00eb86b34" + integrity sha512-qaPVGw30J1wQ0GR3GvoPqlGf9GZfKKF4kFC7kiHlcsPTqH3txrs9crCp3ZiMAXuSenhz89Jnl4GZs/67S5VOSg== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -3272,7 +3217,7 @@ corejs-upgrade-webpack-plugin@^2.2.0: resolve-from "^5.0.0" webpack "^4.38.0" -cosmiconfig@^5.0.0, cosmiconfig@^5.2.0, cosmiconfig@^5.2.1: +cosmiconfig@^5.0.0, cosmiconfig@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== @@ -3282,6 +3227,17 @@ cosmiconfig@^5.0.0, cosmiconfig@^5.2.0, cosmiconfig@^5.2.1: js-yaml "^3.13.1" parse-json "^4.0.0" +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -3379,23 +3335,23 @@ css-declaration-sorter@^4.0.1: postcss "^7.0.1" timsort "^0.3.0" -css-loader@3.2.0, css-loader@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.2.0.tgz#bb570d89c194f763627fcf1f80059c6832d009b2" - integrity sha512-QTF3Ud5H7DaZotgdcJjGMvyDj5F3Pn1j/sC6VBEOVp94cbwqyIBdcs/quzj4MC1BKQSrTpQznegH/5giYbhnCQ== +css-loader@3.2.1, css-loader@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.2.1.tgz#62849b45a414b7bde0bfba17325a026471040eae" + integrity sha512-q40kYdcBNzMvkIImCL2O+wk8dh+RGwPPV9Dfz3n7XtOYPXqe2Z6VgtvoxjkLHz02gmhepG9sOAJOUlx+3hHsBg== dependencies: camelcase "^5.3.1" cssesc "^3.0.0" icss-utils "^4.1.1" loader-utils "^1.2.3" normalize-path "^3.0.0" - postcss "^7.0.17" + postcss "^7.0.23" postcss-modules-extract-imports "^2.0.0" postcss-modules-local-by-default "^3.0.2" - postcss-modules-scope "^2.1.0" + postcss-modules-scope "^2.1.1" postcss-modules-values "^3.0.0" - postcss-value-parser "^4.0.0" - schema-utils "^2.0.0" + postcss-value-parser "^4.0.2" + schema-utils "^2.6.0" css-select-base-adapter@^0.1.1: version "0.1.1" @@ -3413,41 +3369,38 @@ css-select@^1.1.0: nth-check "~1.0.1" css-select@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.0.2.tgz#ab4386cec9e1f668855564b17c3733b43b2a5ede" - integrity sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ== + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== dependencies: boolbase "^1.0.0" - css-what "^2.1.2" + css-what "^3.2.1" domutils "^1.7.0" nth-check "^1.0.2" -css-tree@1.0.0-alpha.29: - version "1.0.0-alpha.29" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39" - integrity sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg== - dependencies: - mdn-data "~1.1.0" - source-map "^0.5.3" - -css-tree@1.0.0-alpha.33: - version "1.0.0-alpha.33" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.33.tgz#970e20e5a91f7a378ddd0fc58d0b6c8d4f3be93e" - integrity sha512-SPt57bh5nQnpsTBsx/IXbO14sRc9xXu5MtMAVuo0BaQQmyf0NupNPPSoMaqiAF5tDFafYsTkfeH4Q/HCKXkg4w== +css-tree@1.0.0-alpha.37: + 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.5.3" + 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" integrity sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY= -css-what@2.1, css-what@^2.1.2: +css-what@2.1: version "2.1.3" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== +css-what@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1" + integrity sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw== + cssesc@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" @@ -3538,12 +3491,12 @@ cssnano@4.1.10: is-resolvable "^1.0.0" postcss "^7.0.0" -csso@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" - integrity sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg== +csso@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.2.tgz#e5f81ab3a56b8eefb7f0092ce7279329f454de3d" + integrity sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg== dependencies: - css-tree "1.0.0-alpha.29" + css-tree "1.0.0-alpha.37" csstype@^2.2.0, csstype@^2.5.7: version "2.6.7" @@ -3562,11 +3515,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= - debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -3599,9 +3547,9 @@ decode-uri-component@^0.2.0: integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= deep-equal@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.0.tgz#3103cdf8ab6d32cf4a8df7865458f2b8d33f3745" - integrity sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== dependencies: is-arguments "^1.0.4" is-date-object "^1.0.1" @@ -3691,9 +3639,9 @@ depd@~1.1.2: integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + 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" @@ -3793,9 +3741,9 @@ dom-converter@^0.2: utila "~0.4" dom-serializer@0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.1.tgz#13650c850daffea35d8b626a4cfc4d3a17643fdb" - integrity sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q== + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== dependencies: domelementtype "^2.0.1" entities "^2.0.0" @@ -3918,14 +3866,14 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= ejs@^2.6.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.1.tgz#5b5ab57f718b79d4aca9254457afecd36fa80228" - integrity sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ== + version "2.7.4" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" + integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== -electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.284: - version "1.3.293" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.293.tgz#e52a30026b89276e211be36083a4d7136fd480ea" - integrity sha512-DQSBRuU2Z1vG+CEWUIfCEVMHtuaGlhVojzg39mX5dx7PLSFDJ7DSrGUWzaPFFgWR1jo26hj1nXXRQZvFwk7F8w== +electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.322: + version "1.3.322" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz#a6f7e1c79025c2b05838e8e344f6e89eb83213a8" + integrity sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA== element-resize-detector@^1.1.15: version "1.1.15" @@ -3935,9 +3883,9 @@ element-resize-detector@^1.1.15: batch-processor "^1.0.0" elliptic@^6.0.0: - version "6.5.1" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.1.tgz#c380f5f909bf1b9b4428d028cd18d3b0efd6b52b" - integrity sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg== + version "6.5.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" + integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -4027,26 +3975,26 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.12.0, es-abstract@^1.13.0, es-abstract@^1.14.2, es-abstract@^1.15.0, es-abstract@^1.16.0, es-abstract@^1.4.3, es-abstract@^1.5.1, es-abstract@^1.7.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d" - integrity sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg== +es-abstract@^1.12.0, es-abstract@^1.13.0, es-abstract@^1.15.0, es-abstract@^1.16.0, es-abstract@^1.4.3, es-abstract@^1.5.1, es-abstract@^1.7.0: + version "1.16.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.3.tgz#52490d978f96ff9f89ec15b5cf244304a5bca161" + integrity sha512-WtY7Fx5LiOnSYgF5eg/1T+GONaGmpvpPdCpSnYij+U2gDTL0UPfWrhDw7b2IYb+9NQJsYpCA0wOQvZfsd6YwRw== dependencies: - es-to-primitive "^1.2.0" + es-to-primitive "^1.2.1" function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.0" + has-symbols "^1.0.1" is-callable "^1.1.4" is-regex "^1.0.4" - object-inspect "^1.6.0" + object-inspect "^1.7.0" object-keys "^1.1.1" string.prototype.trimleft "^2.1.0" string.prototype.trimright "^2.1.0" -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: is-callable "^1.1.4" is-date-object "^1.0.1" @@ -4395,9 +4343,9 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: pkg-dir "^3.0.0" find-cache-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.0.0.tgz#cd4b7dd97b7185b7e17dbfe2d6e4115ee3eeb8fc" - integrity sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw== + version "3.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.1.0.tgz#9935894999debef4cf9f677fdf646d002c4cdecb" + integrity sha512-zw+EFiNBNPgI2NTrKkDd1xd7q0cs6wr/iWnr/oUkI0yF9K9GqQ+riIt4aiyFaaqpaWbxPrJXHI+QvmNUQbX+0Q== dependencies: commondir "^1.0.1" make-dir "^3.0.0" @@ -4613,9 +4561,9 @@ functions-have-names@^1.1.1: integrity sha512-zKXyzksTeaCSw5wIX79iCA40YAa6CJMJgNg9wdkU/ERBrIdPSimPICYiLp65lRbSBqtiHql/HZfS2DyI/AH6tQ== fuse.js@^3.4.4: - version "3.4.5" - resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.4.5.tgz#8954fb43f9729bd5dbcb8c08f251db552595a7a6" - integrity sha512-s9PGTaQIkT69HaeoTVjwGsLfb8V8ScJLx5XGFcKHg0MqLUH/UZ4EKOtqtXX9k7AFqCGxD1aJmYb8Q5VYDibVRQ== + version "3.4.6" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.4.6.tgz#545c3411fed88bf2e27c457cab6e73e7af697a45" + integrity sha512-H6aJY4UpLFwxj1+5nAvufom5b2BT2v45P1MkPvdGIK8fWjQx/7o6tTT1+ALV0yawQvbmvCF0ufl2et8eJ7v7Cg== gauge@~2.7.3: version "2.7.4" @@ -4679,9 +4627,9 @@ glob-to-regexp@^0.3.0: integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.1.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" - integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -4792,9 +4740,9 @@ good-listener@^1.2.2: delegate "^3.1.2" graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" - integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== gud@^1.0.0: version "1.0.0" @@ -4839,10 +4787,10 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== has-unicode@^2.0.0: version "2.0.1" @@ -4903,19 +4851,19 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hast-util-parse-selector@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.2.tgz#66aabccb252c47d94975f50a281446955160380b" - integrity sha512-jIMtnzrLTjzqgVEQqPEmwEZV+ea4zHRFTP8Z2Utw0I5HuBOXHzUPPQWr6ouJdJqDKLbFU/OEiYwZ79LalZkmmw== +hast-util-parse-selector@^2.0.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.3.tgz#57edd449103900c7f63fd9e6f694ffd7e4634719" + integrity sha512-nxbeqjQNxsvo/uYYAw9kij6td05YVUlf1qti09rVfbWSLT5H6wo3c+USIwX6nzXWk5kFZzXnEqO82856r0aM2Q== hastscript@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.0.tgz#a19b3cca6a26a2bcd0f1b1eac574af9427c1c7df" - integrity sha512-7mOQX5VfVs/gmrOGlN8/EDfp1GqV6P3gTNVt+KnX4gbYhpASTM8bklFdFQCbFRAadURXAmw0R1QQdBdqp7jswQ== + version "5.1.1" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.1.tgz#71726ee1e97220575d1f29a8e937387d99d48275" + integrity sha512-xHo1Hkcqd0LlWNuDL3/BxwhgAGp3d7uEvCMgCTrBY+zsOooPPH+8KAvW8PCgl+GB8H3H44nfSaF0A4BQ+4xlYg== dependencies: comma-separated-tokens "^1.0.0" - hast-util-parse-selector "^2.2.0" - property-information "^5.0.1" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" space-separated-tokens "^1.0.0" hat@0.0.3: @@ -4948,9 +4896,9 @@ hmac-drbg@^1.0.0: minimalistic-crypto-utils "^1.0.1" hoist-non-react-statics@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" - integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== + version "3.3.1" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#101685d3aff3b23ea213163f6e8e12f4f111e19f" + integrity sha512-wbg3bpgA/ZqWrZuMOeJi8+SKMhr7X9TesL/rXMjTzh0p0JUBo3II8DHboYbuIXWRlttrUFxwcu/5kygrCw8fJw== dependencies: react-is "^16.7.0" @@ -4991,6 +4939,19 @@ html-entities@^1.2.0, html-entities@^1.2.1: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= +html-minifier-terser@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.0.2.tgz#0e67a0b062ae1dd0719fc73199479298f807ae16" + integrity sha512-VAaitmbBuHaPKv9bj47XKypRhgDxT/cDLvsPiiF7w+omrN3K0eQhpigV9Z1ilrmHa9e0rOYcD6R/+LCDADGcnQ== + dependencies: + camel-case "^3.0.0" + clean-css "^4.2.1" + commander "^4.0.0" + he "^1.2.0" + param-case "^2.1.1" + relateurl "^0.2.7" + terser "^4.3.9" + html-minifier@^3.2.3: version "3.5.21" resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" @@ -5004,19 +4965,6 @@ html-minifier@^3.2.3: relateurl "0.2.x" uglify-js "3.4.x" -html-minifier@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56" - integrity sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig== - dependencies: - camel-case "^3.0.0" - clean-css "^4.2.1" - commander "^2.19.0" - he "^1.2.0" - param-case "^2.1.1" - relateurl "^0.2.7" - uglify-js "^3.5.1" - html-webpack-plugin@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b" @@ -5031,13 +4979,13 @@ html-webpack-plugin@3.2.0: util.promisify "1.0.0" html-webpack-plugin@^4.0.0-beta.2: - version "4.0.0-beta.8" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.8.tgz#d9a8d4322d8cf310f1568f6f4f585a80df0ad378" - integrity sha512-n5S2hJi3/vioRvEDswZP2WFgZU8TUqFoYIrkg5dt+xDC4TigQEhIcl4Y81Qs2La/EqKWuJZP8+ikbHGVmzQ4Mg== + version "4.0.0-beta.11" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz#3059a69144b5aecef97708196ca32f9e68677715" + integrity sha512-4Xzepf0qWxf8CGg7/WQM5qBB2Lc/NFI7MhU59eUDTkuQp3skZczH4UA1d6oQyDEIoMDgERVhRyTdtUPZ5s5HBg== dependencies: - html-minifier "^4.0.0" + html-minifier-terser "^5.0.1" loader-utils "^1.2.3" - lodash "^4.17.11" + lodash "^4.17.15" pretty-error "^2.1.1" tapable "^1.1.3" util.promisify "1.0.0" @@ -5190,6 +5138,14 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" +import-fresh@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-from@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" @@ -5614,12 +5570,12 @@ is-svg@^3.0.0: dependencies: html-comment-regex "^1.1.0" -is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== dependencies: - has-symbols "^1.0.0" + has-symbols "^1.0.1" is-typedarray@~1.0.0: version "1.0.0" @@ -5902,6 +5858,11 @@ less@3.10.3: request "^2.83.0" source-map "~0.6.0" +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" @@ -5980,9 +5941,9 @@ lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17 integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== loglevel@^1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.4.tgz#f408f4f006db8354d0577dcf6d33485b3cb90d56" - integrity sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g== + version "1.6.6" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312" + integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ== loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" @@ -6085,11 +6046,6 @@ mdn-data@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" - integrity sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA== - media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -6188,22 +6144,17 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== - -"mime-db@>= 1.40.0 < 2": +mime-db@1.42.0, "mime-db@>= 1.40.0 < 2": version "1.42.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + version "2.1.25" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437" + integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg== dependencies: - mime-db "1.40.0" + mime-db "1.42.0" mime@1.6.0, mime@^1.4.1: version "1.6.0" @@ -6308,10 +6259,10 @@ minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: safe-buffer "^5.1.2" yallist "^3.0.0" -minipass@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.0.1.tgz#b4fec73bd61e8a40f0b374ddd04260ade2c8ec20" - integrity sha512-2y5okJ4uBsjoD2vAbLKL9EUQPPkC0YMIp+2mZOXG3nBba++pdfJWRxx2Ewirc0pwAJYu4XtWg2EkVo1nRXuO/w== +minipass@^3.0.0, minipass@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" + integrity sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w== dependencies: yallist "^4.0.0" @@ -6529,10 +6480,10 @@ node-pre-gyp@^0.12.0: semver "^5.3.0" tar "^4" -node-releases@^1.1.29, node-releases@^1.1.36: - version "1.1.38" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.38.tgz#d81b365df2936654ba37f509ba2fbe91eff2578b" - integrity sha512-/5NZAaOyTj134Oy5Cp/J8mso8OD/D9CSuL+6TOXXsTKO8yjc5e4up75SRPCganCjwFKMj2jbp5tR0dViVdox7g== +node-releases@^1.1.29, node-releases@^1.1.42: + version "1.1.42" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.42.tgz#a999f6a62f8746981f6da90627a8d2fc090bbad7" + integrity sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA== dependencies: semver "^6.3.0" @@ -6642,10 +6593,10 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" - integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== object-is@^1.0.1: version "1.0.1" @@ -6825,7 +6776,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== @@ -6903,6 +6854,13 @@ param-case@2.1.x, param-case@^2.1.1: dependencies: no-case "^2.2.0" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-asn1@^5.0.0: version "5.1.5" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" @@ -6935,6 +6893,16 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-json@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" + integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + lines-and-columns "^1.1.6" + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -7002,6 +6970,11 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -7074,11 +7047,11 @@ pnp-webpack-plugin@1.4.3: ts-pnp "^1.1.2" polished@^3.3.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/polished/-/polished-3.4.1.tgz#1eb5597ec1792206365635811d465751f5cbf71c" - integrity sha512-GflTnlP5rrpDoigjczEkS6Ye7NDA4sFvAnlr5hSDrEvjiVj97Xzev3hZlLi3UB27fpxyTS9rWU64VzVLWkG+mg== + version "3.4.2" + resolved "https://registry.yarnpkg.com/polished/-/polished-3.4.2.tgz#b4780dad81d64df55615fbfc77acb52fd17d88cd" + integrity sha512-9Rch6iMZckABr6EFCLPZsxodeBpXMo9H4fRlfR/9VjMEyy5xpo1/WgXlJGgSjPyVhEZNycbW7UmYMNyWS5MI0g== dependencies: - "@babel/runtime" "^7.4.5" + "@babel/runtime" "^7.6.3" popper.js@^1.14.4, popper.js@^1.14.7: version "1.16.0" @@ -7279,10 +7252,10 @@ postcss-modules-local-by-default@^3.0.2: postcss-selector-parser "^6.0.2" postcss-value-parser "^4.0.0" -postcss-modules-scope@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb" - integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A== +postcss-modules-scope@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz#33d4fc946602eb5e9355c4165d68a10727689dba" + integrity sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ== dependencies: postcss "^7.0.6" postcss-selector-parser "^6.0.0" @@ -7478,10 +7451,10 @@ postcss-zindex@^4.0.1: postcss "^7.0.0" uniqs "^2.0.0" -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.18, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.18" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.18.tgz#4b9cda95ae6c069c67a4d933029eddd4838ac233" - integrity sha512-/7g1QXXgegpF+9GJj4iN7ChGF40sYuGYJ8WZu8DZWnmhQ/G36hfdk3q9LBJmoK+lZ+yzZ5KYpOoxq7LF1BxE8g== +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.23, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.23.tgz#9f9759fad661b15964f3cfc3140f66f1e05eadc1" + integrity sha512-hOlMf3ouRIFXD+j2VJecwssTwbvsPGJVMzupptg+85WA+i7MwyrydmQAgY3R+m0Bc0exunhbJmijy8u8+vufuQ== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -7505,7 +7478,7 @@ pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= -prismjs@^1.15.0, prismjs@^1.8.4, prismjs@~1.17.0: +prismjs@^1.8.4, prismjs@~1.17.0: version "1.17.1" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.17.1.tgz#e669fcbd4cdd873c35102881c33b14d0d68519be" integrity sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q== @@ -7566,7 +7539,7 @@ prop-types@15.7.2, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, p object-assign "^4.1.1" react-is "^16.8.1" -property-information@^5.0.1: +property-information@^5.0.0: version "5.3.0" resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.3.0.tgz#bc87ac82dc4e72a31bb62040544b1bf9653da039" integrity sha512-IslotQn1hBCZDY7SaJ3zmCjVea219VTwmOk6Pu3z9haU9m4+T8GwaDubur+6NMHEU+Fjs/6/p66z6QULPkcL1w== @@ -7597,9 +7570,9 @@ pseudomap@^1.0.2: integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= psl@^1.1.24: - version "1.4.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" - integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== + version "1.5.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.5.0.tgz#47fd1292def7fdb1e138cd78afa8814cebcf7b13" + integrity sha512-4vqUjKi2huMu1OJiLhi3jN6jeeKvMZdI1tYgi/njW5zV52jNLgSAZSdN16m9bJFe61/cT8ulmw4qFitV9QRsEA== public-encrypt@^4.0.0: version "4.0.3" @@ -7664,9 +7637,9 @@ qs@6.7.0: integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== qs@^6.6.0: - version "6.9.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.0.tgz#d1297e2a049c53119cb49cca366adbbacc80b409" - integrity sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA== + version "6.9.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" + integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== qs@~6.5.2: version "6.5.2" @@ -7787,7 +7760,7 @@ react-dev-utils@^9.0.0: strip-ansi "5.2.0" text-table "0.2.0" -react-docgen@^4.1.0: +react-docgen@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-4.1.1.tgz#8fef0212dbf14733e09edecef1de6b224d87219e" integrity sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw== @@ -7800,20 +7773,20 @@ react-docgen@^4.1.0: node-dir "^0.1.10" recast "^0.17.3" -react-dom@16.11.0, react-dom@^16.8.3: - version "16.11.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.11.0.tgz#7e7c4a5a85a569d565c2462f5d345da2dd849af5" - integrity sha512-nrRyIUE1e7j8PaXSPtyRKtz+2y9ubW/ghNgqKFHHAHaeP0fpF5uXR+sq8IMRHC+ZUxw7W9NyCDTBtwWxvkb0iA== +react-dom@16.12.0, react-dom@^16.8.3: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.12.0.tgz#0da4b714b8d13c2038c9396b54a92baea633fe11" + integrity sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" - scheduler "^0.17.0" + scheduler "^0.18.0" react-draggable@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.0.3.tgz#6b9f76f66431c47b9070e9b805bbc520df8ca481" - integrity sha512-4vD6zms+9QGeZ2RQXzlUBw8PBYUXy+dzYX5r22idjp9YwQKIIvD/EojL0rbjS1GK4C3P0rAJnmKa8gDQYWUDyA== + version "4.1.0" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.1.0.tgz#e1c5b774001e32f0bff397254e1e9d5448ac92a4" + integrity sha512-Or/qe70cfymshqoC8Lsp0ukTzijJObehb7Vfl7tb5JRxoV+b6PDkOGoqYaWBzZ59k9dH/bwraLGsnlW78/3vrA== dependencies: classnames "^2.2.5" prop-types "^15.6.0" @@ -7827,9 +7800,9 @@ react-element-to-jsx-string@^14.0.3: is-plain-object "3.0.0" react-error-overlay@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.3.tgz#c378c4b0a21e88b2e159a3e62b2f531fd63bf60d" - integrity sha512-bOUvMWFQVk5oz8Ded9Xb7WVdEi3QGLC8tH7HmYP0Fdp4Bn3qw0tRFmr5TW6mvahzvmrK4a6bqWGfCevBflP+Xw== + version "6.0.4" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.4.tgz#0d165d6d27488e660bc08e57bdabaad741366f7a" + integrity sha512-ueZzLmHltszTshDMwyfELDq8zOA803wQ1ZuzCccXa1m57k1PxSHfflPD5W9YIiTXLs0JTLzoj6o1LuM5N6zzNA== react-fast-compare@^2.0.4: version "2.0.4" @@ -7886,9 +7859,9 @@ react-inspector@^3.0.2: prop-types "^15.6.1" react-is@^16.7.0, react-is@^16.8.1: - version "16.11.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa" - integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw== + version "16.12.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" + integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== react-lifecycles-compat@^3.0.4: version "3.0.4" @@ -7896,17 +7869,17 @@ react-lifecycles-compat@^3.0.4: integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== react-popper-tooltip@^2.8.3: - version "2.9.1" - resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-2.9.1.tgz#cc602c89a937aea378d9e2675b1ce62805beb4f6" - integrity sha512-LSbvXLEQlNKWig2GMKQW/1bBwCkWIr9cpJ+WJpSGGGhX45CthRtwyilPPLJQkc3qI6UMTAXPp0Fe/pj9E77trg== + version "2.10.1" + resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-2.10.1.tgz#e10875f31916297c694d64a677d6f8fa0a48b4d1" + integrity sha512-cib8bKiyYcrIlHo9zXx81G0XvARfL8Jt+xum709MFCgQa3HTqTi4au3iJ9tm7vi7WU7ngnqbpWkMinBOtwo+IQ== dependencies: - "@babel/runtime" "^7.6.3" - react-popper "^1.3.4" + "@babel/runtime" "^7.7.4" + react-popper "^1.3.6" -react-popper@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.4.tgz#f0cd3b0d30378e1f663b0d79bcc8614221652ced" - integrity sha512-9AcQB29V+WrBKk6X7p0eojd1f25/oJajVdMZkywIoAV6Ag7hzE1Mhyeup2Q1QnvFRtGQFQvtqfhlEoDAPfKAVA== +react-popper@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.6.tgz#32122f83af8fda01bdd4f86625ddacaf64fdd06d" + integrity sha512-kLTfa9z8n+0jJvRVal9+vIuirg41rObg4Bbrvv/ZfsGPQDN9reyVVSxqnHF1ZNgXgV7x11PeUfd5ItF8DZnqhg== dependencies: "@babel/runtime" "^7.1.2" create-react-context "^0.3.0" @@ -7937,17 +7910,17 @@ react-syntax-highlighter@^8.0.1: refractor "^2.4.1" react-textarea-autosize@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.1.0.tgz#3132cb77e65d94417558d37c0bfe415a5afd3445" - integrity sha512-c2FlR/fP0qbxmlrW96SdrbgP/v0XZMTupqB90zybvmDVDutytUgPl7beU35klwcTeMepUIQEpQUn3P3bdshGPg== + version "7.1.2" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.1.2.tgz#70fdb333ef86bcca72717e25e623e90c336e2cda" + integrity sha512-uH3ORCsCa3C6LHxExExhF4jHoXYCQwE5oECmrRsunlspaDAbS4mGKNlWZqjLfInWtFQcf0o1n1jC/NGXFdUBCg== dependencies: "@babel/runtime" "^7.1.2" prop-types "^15.6.0" -react@16.11.0, react@^16.8.3: - version "16.11.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.11.0.tgz#d294545fe62299ccee83363599bf904e4a07fdbb" - integrity sha512-M5Y8yITaLmU0ynd0r1Yvfq98Rmll6q8AxaEe88c8e7LxO8fZ2cNgmFt0aGAS9wzf1Ao32NKXtCl+/tVVtkxq6g== +react@16.12.0, react@^16.8.3: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.12.0.tgz#0c0a9c6a142429e3614834d5a778e18aa78a0b83" + integrity sha512-fglqy3k5E+81pA8s+7K0/T3DBCF0ZDOher1elBFzF7O6arXJgzyu/FW+COxFvAWXJoJN9KIZbT2LXlukwphYTA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -8202,6 +8175,11 @@ resolve-from@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" integrity sha1-six699nWiBvItuZTM17rywoYh0g= +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-from@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" @@ -8212,10 +8190,10 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.3.2, resolve@^1.8.1: - version "1.12.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" - integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== +resolve@^1.1.6, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.3.2, resolve@^1.8.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16" + integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w== dependencies: path-parse "^1.0.6" @@ -8315,10 +8293,10 @@ sax@^1.2.4, sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.17.0: - version "0.17.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.17.0.tgz#7c9c673e4ec781fac853927916d1c426b6f3ddfe" - integrity sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA== +scheduler@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" + integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -8332,10 +8310,10 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.0, schema-utils@^2.4.1, schema-utils@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f" - integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ== +schema-utils@^2.5.0, schema-utils@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.1.tgz#eb78f0b945c7bcfa2082b3565e8db3548011dc4f" + integrity sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg== dependencies: ajv "^6.10.2" ajv-keywords "^3.4.1" @@ -8392,9 +8370,9 @@ serialize-javascript@^1.7.0: integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== serialize-javascript@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.0.tgz#9310276819efd0eb128258bb341957f6eb2fc570" - integrity sha512-a/mxFfU00QT88umAJQsNWOnUKckhNCqOl028N48e7wFmo2/EHpTo9Wso+iJJCMrQnmFvcjto5RJdAHEvVhcyUQ== + version "2.1.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.1.tgz#952907a04a3e3a75af7f73d92d15e233862048b2" + integrity sha512-MPLPRpD4FNqWq9tTIjYG5LesFouDhdyH0EPY3gVK4DRD5+g4aDqdNSzLIwceulo3Yj+PL1bPh6laE5+H6LTcrQ== serve-favicon@^2.5.0: version "2.5.0" @@ -8630,9 +8608,9 @@ source-map-resolve@^0.5.0: urix "^0.1.0" source-map-support@~0.5.12: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -8642,7 +8620,7 @@ 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.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7: +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -8719,12 +8697,12 @@ ssri@^6.0.1: figgy-pudding "^3.5.1" ssri@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-7.0.1.tgz#b0cab7bbb11ac9ea07f003453e2011f8cbed9f34" - integrity sha512-FfndBvkXL9AHyGLNzU3r9AvYIBBZ7gm+m+kd0p8cT3/v4OliMAyipZAhLVEv1Zi/k4QFq9CstRGVd9pW/zcHFQ== + version "7.1.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-7.1.0.tgz#92c241bf6de82365b5c7fb4bd76e975522e1294d" + integrity sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g== dependencies: figgy-pudding "^3.5.1" - minipass "^3.0.0" + minipass "^3.1.1" stable@^0.1.8: version "0.1.8" @@ -8749,14 +8727,14 @@ store2@^2.7.1: resolved "https://registry.yarnpkg.com/store2/-/store2-2.10.0.tgz#46b82bb91878daf1b0d56dec2f1d41e54d5103cf" integrity sha512-tWEpK0snS2RPUq1i3R6OahfJNjWCQYNxq0+by1amCSuw0mXtymJpzmZIeYpA1UAa+7B0grCpNYIbDcd7AgTbFg== -storybook-addon-jsx@7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/storybook-addon-jsx/-/storybook-addon-jsx-7.1.6.tgz#56177cc0c98d836fcec837c8bb2f7e2c64838f7f" - integrity sha512-1aCF4xFYImjwJDJhI9f7l8PEt1ScCNfkgvofFRB7CwxFf4chepM5HirH4wc2kSWhFcBRoQhx/Y0cNxnlsJAN4A== +storybook-addon-jsx@7.1.13: + version "7.1.13" + resolved "https://registry.yarnpkg.com/storybook-addon-jsx/-/storybook-addon-jsx-7.1.13.tgz#1bc18a64bd9053b0c2f9669d398697ec6fdb6b36" + integrity sha512-JHWbVUzpkyIMiGeFWFkxg6qNkR0fLeT++v1Q4IN9s7JfxrHksPskMnCkDra+rmx/Mtdq4uk5XKREJNIl0H8d/w== dependencies: + "@storybook/components" "^5.2.5" copy-to-clipboard "^3.0.8" js-beautify "^1.8.8" - prismjs "^1.15.0" react-element-to-jsx-string "^14.0.3" stream-browserify@^2.0.1: @@ -8834,13 +8812,13 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string.prototype.matchall@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-3.0.2.tgz#c1fdb23f90058e929a69cfa2e8b12300daefe030" - integrity sha512-hsRe42jQ8+OJej2GVjhnSVodQ3NQgHV0FDD6dW7ZTM22J4uIbuYiAADCCc1tfyN7ocEl/KUUbudM36E2tZcF8w== +"string.prototype.matchall@^4.0.0 || ^3.0.1": + version "4.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.0.tgz#47191e37b67dca43131706bc9c4550df31b2c471" + integrity sha512-/cSuf1qsUaPicdvXcVZJ98fM9FmvkXvw7PKSM5pTtlj4R9VLQc7B51fOZBMsGfv9UXhUhdpxSrEsGe2ObsR2cw== dependencies: define-properties "^1.1.3" - es-abstract "^1.14.2" + es-abstract "^1.15.0" function-bind "^1.1.1" has-symbols "^1.0.0" regexp.prototype.flags "^1.2.0" @@ -8966,16 +8944,16 @@ svg-parser@^2.0.0: integrity sha512-1gtApepKFweigFZj3sGO8KT8LvVZK8io146EzXrpVuWCDAbISz/yMucco3hWTkpZNoPabM+dnMOpy6Swue68Zg== svgo@^1.0.0, svgo@^1.2.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.0.tgz#bae51ba95ded9a33a36b7c46ce9c359ae9154313" - integrity sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ== + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== dependencies: chalk "^2.4.1" coa "^2.0.2" css-select "^2.0.0" css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.33" - csso "^3.5.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" js-yaml "^3.13.1" mkdirp "~0.5.1" object.values "^1.1.0" @@ -9011,15 +8989,15 @@ tar@^4: yallist "^3.0.3" telejson@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/telejson/-/telejson-3.0.3.tgz#442af55f78d791d3744c9e7a696be6cdf789a4b5" - integrity sha512-gUOh6wox1zJjbGMg+e26NquZcp/F18EbIaqVvjiGqikRqVB4fYEAM8Nyin8smgwX30XhaRBOg+kCj4vInmvwAg== + version "3.3.0" + resolved "https://registry.yarnpkg.com/telejson/-/telejson-3.3.0.tgz#6d814f3c0d254d5c4770085aad063e266b56ad03" + integrity sha512-er08AylQ+LEbDLp1GRezORZu5wKOHaBczF6oYJtgC3Idv10qZ8A3p6ffT+J5BzDKkV9MqBvu8HAKiIIOp6KJ2w== dependencies: "@types/is-function" "^1.0.0" global "^4.4.0" is-function "^1.0.1" is-regex "^1.0.4" - is-symbol "^1.0.2" + is-symbol "^1.0.3" isobject "^4.0.0" lodash "^4.17.15" memoizerific "^1.11.3" @@ -9061,9 +9039,9 @@ terser-webpack-plugin@^1.2.4, terser-webpack-plugin@^1.4.1: worker-farm "^1.7.0" terser@^4.1.2, terser@^4.3.9: - version "4.3.9" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.9.tgz#e4be37f80553d02645668727777687dad26bbca8" - integrity sha512-NFGMpHjlzmyOtPL+fDw3G7+6Ueh/sz4mkaUYa4lJCxOPTNzd0Uj0aZJOmsDYoSQyfuVoWDMSWTPU3huyOm2zdA== + version "4.4.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.2.tgz#448fffad0245f4c8a277ce89788b458bfd7706e8" + integrity sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -9180,9 +9158,9 @@ tough-cookie@~2.4.3: punycode "^1.4.1" ts-pnp@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.4.tgz#ae27126960ebaefb874c6d7fa4729729ab200d90" - integrity sha512-1J/vefLC+BWSo+qe8OnJQfWTYRS6ingxjwqmHMqaMxXMj7kFtKLgAaYW3JeX3mktjgUL+etlU8/B4VUAUI9QGw== + version "1.1.5" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.5.tgz#840e0739c89fce5f3abd9037bb091dbff16d9dec" + integrity sha512-ti7OGMOUOzo66wLF3liskw6YQIaSsBgc4GOAlWRnIEj8htCxJUxskanMUoJOD6MDCRAXo36goXJZch+nOS0VMA== tslib@^1.9.0, tslib@^1.9.3: version "1.10.0" @@ -9242,14 +9220,6 @@ uglify-js@3.4.x: commander "~2.19.0" source-map "~0.6.1" -uglify-js@^3.5.1: - version "3.6.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.3.tgz#1351533bbe22cc698f012589ed6bd4cbd971bff8" - integrity sha512-KfQUgOqTkLp2aZxrMbCuKCDGW9slFYu2A23A36Gs7sGzTLcRBDORdOi5E21KWHFIfkY8kzgi/Pr1cXCh0yIp5g== - dependencies: - commander "~2.20.3" - source-map "~0.6.1" - unfetch@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.1.0.tgz#6ec2dd0de887e58a4dee83a050ded80ffc4137db" @@ -9358,13 +9328,13 @@ urix@^0.1.0: integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url-loader@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.2.0.tgz#af321aece1fd0d683adc8aaeb27829f29c75b46e" - integrity sha512-G8nk3np8ZAnwhHXas1JxJEwJyQdqFXAKJehfgZ/XrC48volFBRtO+FIKtF2u0Ma3bw+4vnDVjHPAQYlF9p2vsw== + version "2.3.0" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.3.0.tgz#e0e2ef658f003efb8ca41b0f3ffbf76bab88658b" + integrity sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog== dependencies: loader-utils "^1.2.3" mime "^2.4.4" - schema-utils "^2.4.1" + schema-utils "^2.5.0" url-parse@^1.4.3: version "1.4.7" @@ -9388,9 +9358,9 @@ use-callback-ref@^1.2.1: integrity sha512-C3nvxh0ZpaOxs9RCnWwAJ+7bJPwQI8LHF71LzbQ3BvzH5XkdtlkMadqElGevg5bYBDFip4sAnD4m06zAKebg1w== use-sidecar@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.1.tgz#75c7a5fdacc14bd3ab64992c638e45a396ad2fad" - integrity sha512-CLTDS2AZmUcXXFnxP/h/OadtvBOoHHnLYMMpKGntb5vKOQT94icrXMXX0mEdGiMhQU8vxHlndB72sRwRBHXTzw== + version "1.0.2" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.2.tgz#e72f582a75842f7de4ef8becd6235a4720ad8af6" + integrity sha512-287RZny6m5KNMTb/Kq9gmjafi7lQL0YHO1lYolU6+tY1h9+Z3uCtkJJ3OSOq3INwYf2hBryCcDh4520AhJibMA== dependencies: detect-node "^2.0.4" tslib "^1.9.3" @@ -9467,9 +9437,9 @@ verror@1.10.0: extsprintf "^1.2.0" vm-browserify@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" - integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== vtt.js@0.13.0: version "0.13.0" @@ -9506,10 +9476,10 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -webpack-cli@3.3.9: - version "3.3.9" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.9.tgz#79c27e71f94b7fe324d594ab64a8e396b9daa91a" - integrity sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A== +webpack-cli@3.3.10: + version "3.3.10" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13" + integrity sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg== dependencies: chalk "2.4.2" cross-spawn "6.0.5" @@ -9741,6 +9711,13 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.7.2.tgz#f26aabf738590ab61efaca502358e48dc9f348b2" + integrity sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw== + dependencies: + "@babel/runtime" "^7.6.3" + yargs-parser@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" From 468f5976732ce4ec4f2b4de9eb7d91e4e904c684 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 17:28:37 +0200 Subject: [PATCH 343/442] useUser implemented with useModelState --- src/common/NavBar/NavMenu/NavMenu.js | 19 +++++---------- src/common/NavBar/NavMenu/useUser.js | 13 ----------- src/common/useUser.js | 35 +++++++++++++++++----------- 3 files changed, 27 insertions(+), 40 deletions(-) delete mode 100644 src/common/NavBar/NavMenu/useUser.js diff --git a/src/common/NavBar/NavMenu/NavMenu.js b/src/common/NavBar/NavMenu/NavMenu.js index 329e93dfb..9a008a73e 100644 --- a/src/common/NavBar/NavMenu/NavMenu.js +++ b/src/common/NavBar/NavMenu/NavMenu.js @@ -2,7 +2,6 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); -const { useServices } = require('stremio/services'); const Button = require('stremio/common/Button'); const Popup = require('stremio/common/Popup'); const useBinaryState = require('stremio/common/useBinaryState'); @@ -11,10 +10,9 @@ const useUser = require('stremio/common/useUser'); const styles = require('./styles'); const NavMenu = ({ className }) => { - const { core } = useServices(); const [menuOpen, openMenu, closeMenu, toggleMenu] = useBinaryState(false); const [fullscreen, requestFullscreen, exitFullscreen] = useFullscreen(); - const user = useUser(); + const [user, logout] = useUser(); const popupLabelOnClick = React.useCallback((event) => { if (!event.nativeEvent.togglePopupPrevented) { toggleMenu(); @@ -24,12 +22,7 @@ const NavMenu = ({ className }) => { event.nativeEvent.togglePopupPrevented = true; }, []); const logoutButtonOnClick = React.useCallback(() => { - core.dispatch({ - action: 'UserOp', - args: { - userOp: 'Logout' - } - }); + logout(); }, []); return ( {
-
{!user ? 'Anonymous user' : user.email}
+
{user === null ? 'Anonymous user' : user.email}
-
diff --git a/src/common/NavBar/NavMenu/useUser.js b/src/common/NavBar/NavMenu/useUser.js deleted file mode 100644 index 0f3305809..000000000 --- a/src/common/NavBar/NavMenu/useUser.js +++ /dev/null @@ -1,13 +0,0 @@ -const React = require('react'); - -const useUser = () => { - const [user] = React.useState({ - email: '', - avatar: '', - anonymous: true, - logout: () => { } - }); - return user; -}; - -module.exports = useUser; diff --git a/src/common/useUser.js b/src/common/useUser.js index cb92a36b6..b344dfd8c 100644 --- a/src/common/useUser.js +++ b/src/common/useUser.js @@ -1,23 +1,30 @@ const React = require('react'); const { useServices } = require('stremio/services'); +const useModelState = require('stremio/common/useModelState'); + +const initUserState = () => null; + +const mapUserState = (ctx) => { + return ctx.content.auth ? ctx.content.auth.user : null; +}; const useUser = () => { const { core } = useServices(); - const [user, setUser] = React.useState(() => { - const state = core.getState(); - return state.ctx.content.auth ? state.ctx.content.auth.user : null; - }); - React.useEffect(() => { - const onNewState = () => { - const state = core.getState(); - setUser(state.ctx.content.auth ? state.ctx.content.auth.user : null); - }; - core.on('NewModel', onNewState); - return () => { - core.off('NewModel', onNewState); - }; + const logout = React.useCallback(() => { + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'Logout' + } + }); }, []); - return user; + const user = useModelState({ + model: 'ctx', + action: null, + map: mapUserState, + init: initUserState + }); + return [user, logout]; }; module.exports = useUser; From cba604047b9488875d245b355993e3924b80b6cf Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 17:34:18 +0200 Subject: [PATCH 344/442] null action removed from useUser --- src/common/useUser.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/useUser.js b/src/common/useUser.js index b344dfd8c..5a71b72e0 100644 --- a/src/common/useUser.js +++ b/src/common/useUser.js @@ -20,7 +20,6 @@ const useUser = () => { }, []); const user = useModelState({ model: 'ctx', - action: null, map: mapUserState, init: initUserState }); From 66eddaed8c6d4ac111949eb5c1d36b5847100689 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 17:48:32 +0200 Subject: [PATCH 345/442] useSearch implemented with useModelState --- src/routes/Search/useSearch.js | 45 +++++++++++++++------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index fff36be55..730e48a00 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -1,13 +1,18 @@ const React = require('react'); -const { useServices } = require('stremio/services'); +const { useModelState } = require('stremio/common'); -const mapSearchState = (state) => { - const queryString = state.search.selected !== null ? - new URLSearchParams(state.search.selected.extra).toString() +const initSearchState = () => ({ + selected: null, + catalog_resources: [] +}); + +const mapSearchState = (search) => { + const queryString = search.selected !== null ? + new URLSearchParams(search.selected.extra).toString() : ''; - const selected = state.search.selected; - const catalog_resources = state.search.catalog_resources.map((catalog_resource) => { + const selected = search.selected; + const catalog_resources = search.catalog_resources.map((catalog_resource) => { catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}?${queryString}`; return catalog_resource; }); @@ -15,21 +20,9 @@ const mapSearchState = (state) => { }; const useSearch = (queryParams) => { - const { core } = useServices(); - const [search, setSearch] = React.useState(() => { - const state = core.getState(); - const search = mapSearchState(state); - return search; - }); - React.useLayoutEffect(() => { - const onNewState = () => { - const state = core.getState(); - const search = mapSearchState(state); - setSearch(search); - }; - core.on('NewModel', onNewState); + const loadSearchAction = React.useMemo(() => { if (queryParams.has('search') && queryParams.get('search').length > 0) { - core.dispatch({ + return { action: 'Load', args: { load: 'CatalogsWithExtra', @@ -39,13 +32,15 @@ const useSearch = (queryParams) => { ] } } - }, 'Search'); + }; } - return () => { - core.off('NewModel', onNewState); - }; }, [queryParams]); - return search; + return useModelState({ + model: 'search', + action: loadSearchAction, + map: mapSearchState, + init: initSearchState + }); }; module.exports = useSearch; From 02f4383b87ca02af08cc10e6b035d4207822074c Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 18:06:30 +0200 Subject: [PATCH 346/442] dispatch unload action on unmount --- src/common/useModelState.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/common/useModelState.js b/src/common/useModelState.js index 3393bbbd2..a790b33cc 100644 --- a/src/common/useModelState.js +++ b/src/common/useModelState.js @@ -4,6 +4,10 @@ const { useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); const useDeepEqualState = require('stremio/common/useDeepEqualState'); +const UNLOAD_ACTION = { + action: 'Unload', +}; + const useModelState = ({ model, action, timeout, map, init }) => { const modelRef = React.useRef(model); const { core } = useServices(); @@ -12,6 +16,11 @@ const useModelState = ({ model, action, timeout, map, init }) => { React.useLayoutEffect(() => { core.dispatch(action, modelRef.current); }, [action]); + React.useLayoutEffect(() => { + return () => { + core.dispatch(UNLOAD_ACTION, modelRef.current); + }; + }, []); React.useLayoutEffect(() => { const onNewState = throttle(() => { const state = core.getState(modelRef.current); From ab88feee724fe2c829f3098706c7926da0ac8f7e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 18:06:51 +0200 Subject: [PATCH 347/442] Unload search when query is not valid --- src/routes/Search/useSearch.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 730e48a00..1cbfe80cd 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -33,6 +33,10 @@ const useSearch = (queryParams) => { } } }; + } else { + return { + action: 'Unload' + }; } }, [queryParams]); return useModelState({ From 6e7684324698f74309323fc91d6b5a15d978d83e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 18:09:52 +0200 Subject: [PATCH 348/442] transform autoFocus prop to bool in Modal --- src/router/Modal/Modal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/router/Modal/Modal.js b/src/router/Modal/Modal.js index 75f20a13a..fcf65b15c 100644 --- a/src/router/Modal/Modal.js +++ b/src/router/Modal/Modal.js @@ -8,7 +8,7 @@ const { useModalsContainer } = require('../ModalsContainerContext'); const Modal = ({ className, autoFocus, children, ...props }) => { const modalsContainer = useModalsContainer(); return ReactDOM.createPortal( - + {children} , modalsContainer From 49df82a2daff5078cf943c06a74d89116bd9564e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 18:14:39 +0200 Subject: [PATCH 349/442] routeConfigForPath moved to a separate file --- src/router/Router/Router.js | 20 +++++--------------- src/router/Router/routeConfigForPath.js | 13 +++++++++++++ 2 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 src/router/Router/routeConfigForPath.js diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index f8e59f2f6..3d75fda67 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -6,23 +6,13 @@ const UrlUtils = require('url'); const deepEqual = require('deep-equal'); const { RouteFocusedProvider } = require('../RouteFocusedContext'); const Route = require('../Route'); +const routeConfigForPath = require('./routeConfigForPath'); const Router = ({ className, onPathNotMatch, ...props }) => { - const [{ homePath, viewsConfig }] = React.useState(() => ({ + const { homePath, viewsConfig } = React.useMemo(() => ({ homePath: props.homePath, viewsConfig: props.viewsConfig - })); - const routeConfigForPath = React.useCallback((path) => { - for (const viewConfig of viewsConfig) { - for (const routeConfig of viewConfig) { - if (typeof path === 'string' && path.match(routeConfig.regexp)) { - return routeConfig; - } - } - } - - return null; - }, []); + }), []); const [views, setViews] = React.useState(() => { return Array(viewsConfig.length).fill(null); }); @@ -31,7 +21,7 @@ const Router = ({ className, onPathNotMatch, ...props }) => { const { pathname, path } = UrlUtils.parse(window.location.hash.slice(1)); if (homePath !== path) { window.location.replace(`#${homePath}`); - const routeConfig = routeConfigForPath(pathname); + const routeConfig = routeConfigForPath(viewsConfig, pathname); if (routeConfig) { window.location = `#${path}`; } @@ -42,7 +32,7 @@ const Router = ({ className, onPathNotMatch, ...props }) => { const onLocationHashChange = () => { const { pathname, query } = UrlUtils.parse(window.location.hash.slice(1)); const queryParams = new URLSearchParams(typeof query === 'string' ? query : ''); - const routeConfig = routeConfigForPath(pathname); + const routeConfig = routeConfigForPath(viewsConfig, pathname); if (!routeConfig) { if (typeof onPathNotMatch === 'function') { const component = onPathNotMatch(); diff --git a/src/router/Router/routeConfigForPath.js b/src/router/Router/routeConfigForPath.js new file mode 100644 index 000000000..5b8892814 --- /dev/null +++ b/src/router/Router/routeConfigForPath.js @@ -0,0 +1,13 @@ +const routeConfigForPath = (viewsConfig, path) => { + for (const viewConfig of viewsConfig) { + for (const routeConfig of viewConfig) { + if (typeof path === 'string' && path.match(routeConfig.regexp)) { + return routeConfig; + } + } + } + + return null; +}; + +module.exports = routeConfigForPath; From aabca44a29a42572e1a5be92aa52b6fe1c8ae80c Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 18:20:22 +0200 Subject: [PATCH 350/442] urlParamsForPath moved to separate file --- src/router/Router/Router.js | 12 ++---------- src/router/Router/urlParamsForPath.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 src/router/Router/urlParamsForPath.js diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index 3d75fda67..bdb0628f0 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -7,6 +7,7 @@ const deepEqual = require('deep-equal'); const { RouteFocusedProvider } = require('../RouteFocusedContext'); const Route = require('../Route'); const routeConfigForPath = require('./routeConfigForPath'); +const urlParamsForPath = require('./urlParamsForPath'); const Router = ({ className, onPathNotMatch, ...props }) => { const { homePath, viewsConfig } = React.useMemo(() => ({ @@ -52,16 +53,7 @@ const Router = ({ className, onPathNotMatch, ...props }) => { return; } - const matches = pathname.match(routeConfig.regexp); - const urlParams = routeConfig.urlParamsNames.reduce((urlParams, name, index) => { - if (Array.isArray(matches) && typeof matches[index + 1] === 'string') { - urlParams[name] = decodeURIComponent(matches[index + 1]); - } else { - urlParams[name] = null; - } - - return urlParams; - }, {}); + const urlParams = urlParamsForPath(routeConfig, pathname); const routeViewIndex = viewsConfig.findIndex((vc) => vc.includes(routeConfig)); const routeIndex = viewsConfig[routeViewIndex].findIndex((rc) => rc === routeConfig); setViews((views) => { diff --git a/src/router/Router/urlParamsForPath.js b/src/router/Router/urlParamsForPath.js new file mode 100644 index 000000000..5a518094f --- /dev/null +++ b/src/router/Router/urlParamsForPath.js @@ -0,0 +1,14 @@ +const urlParamsForPath = (routeConfig, path) => { + const matches = path.match(routeConfig.regexp); + return routeConfig.urlParamsNames.reduce((urlParams, name, index) => { + if (Array.isArray(matches) && typeof matches[index + 1] === 'string') { + urlParams[name] = decodeURIComponent(matches[index + 1]); + } else { + urlParams[name] = null; + } + + return urlParams; + }, {}); +}; + +module.exports = urlParamsForPath; From ac40771ce464a056b14c34785bc547387378118e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 18:23:48 +0200 Subject: [PATCH 351/442] routeConfigForPath depend on valid arguments --- src/router/Router/Router.js | 5 ++++- src/router/Router/routeConfigForPath.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index bdb0628f0..2f5d496ee 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -33,7 +33,10 @@ const Router = ({ className, onPathNotMatch, ...props }) => { const onLocationHashChange = () => { const { pathname, query } = UrlUtils.parse(window.location.hash.slice(1)); const queryParams = new URLSearchParams(typeof query === 'string' ? query : ''); - const routeConfig = routeConfigForPath(viewsConfig, pathname); + const routeConfig = typeof pathname === 'string' ? + routeConfigForPath(viewsConfig, pathname) + : + null; if (!routeConfig) { if (typeof onPathNotMatch === 'function') { const component = onPathNotMatch(); diff --git a/src/router/Router/routeConfigForPath.js b/src/router/Router/routeConfigForPath.js index 5b8892814..0c215b769 100644 --- a/src/router/Router/routeConfigForPath.js +++ b/src/router/Router/routeConfigForPath.js @@ -1,7 +1,7 @@ const routeConfigForPath = (viewsConfig, path) => { for (const viewConfig of viewsConfig) { for (const routeConfig of viewConfig) { - if (typeof path === 'string' && path.match(routeConfig.regexp)) { + if (path.match(routeConfig.regexp)) { return routeConfig; } } From 98f690e3a50cda4f30d2c8b4c7682429cacafc74 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 5 Dec 2019 18:24:40 +0200 Subject: [PATCH 352/442] deepEqual replaced by lodash.isequal --- src/router/Router/Router.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index 2f5d496ee..9e8e08fbe 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -3,7 +3,7 @@ const ReactIs = require('react-is'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const UrlUtils = require('url'); -const deepEqual = require('deep-equal'); +const isEqual = require('lodash.isequal'); const { RouteFocusedProvider } = require('../RouteFocusedContext'); const Route = require('../Route'); const routeConfigForPath = require('./routeConfigForPath'); @@ -67,11 +67,11 @@ const Router = ({ className, onPathNotMatch, ...props }) => { return { key: `${routeViewIndex}${routeIndex}`, component: routeConfig.component, - urlParams: view !== null && deepEqual(view.urlParams, urlParams) ? + urlParams: view !== null && isEqual(view.urlParams, urlParams) ? view.urlParams : urlParams, - queryParams: view !== null && deepEqual(Array.from(view.queryParams.entries()), Array.from(queryParams.entries())) ? + queryParams: view !== null && isEqual(Array.from(view.queryParams.entries()), Array.from(queryParams.entries())) ? view.queryParams : queryParams From 24a1600918f7ef2740b3f1f91a998268ac9e848b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 10:06:47 +0200 Subject: [PATCH 353/442] reorganize router views --- src/App/routerViewsConfig.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/App/routerViewsConfig.js b/src/App/routerViewsConfig.js index b53ee54fb..f2d92cff7 100644 --- a/src/App/routerViewsConfig.js +++ b/src/App/routerViewsConfig.js @@ -3,13 +3,15 @@ const { routesRegexp } = require('stremio/common'); const routerViewsConfig = [ [ - { - ...routesRegexp.intro, - component: routes.Intro - }, { ...routesRegexp.board, component: routes.Board + } + ], + [ + { + ...routesRegexp.intro, + component: routes.Intro }, { ...routesRegexp.discover, @@ -28,7 +30,9 @@ const routerViewsConfig = [ { ...routesRegexp.metadetails, component: routes.MetaDetails - }, + } + ], + [ { ...routesRegexp.addons, component: routes.Addons From 3912b596cb06c08d9bf22668a299b0082029b10d Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 10:24:55 +0200 Subject: [PATCH 354/442] extract used props is Checkbox --- src/common/Checkbox/Checkbox.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/Checkbox/Checkbox.js b/src/common/Checkbox/Checkbox.js index 9f9ba45db..96c29f334 100644 --- a/src/common/Checkbox/Checkbox.js +++ b/src/common/Checkbox/Checkbox.js @@ -4,18 +4,18 @@ const Icon = require('stremio-icons/dom'); const Button = require('stremio/common/Button'); const styles = require('./styles'); -const Checkbox = React.forwardRef((props, ref) => { +const Checkbox = React.forwardRef(({ className, checked, children, ...props }, ref) => { return ( - ); }); From 80aed6bca33b5d6e60fecd83cd43a66a1b0d55b3 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 10:27:28 +0200 Subject: [PATCH 355/442] extract used props in Button --- src/common/Button/Button.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 8cbf3f03a..fcdaf7aff 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -2,7 +2,7 @@ const React = require('react'); const classnames = require('classnames'); const styles = require('./styles'); -const Button = React.forwardRef(({ children, ...props }, ref) => { +const Button = React.forwardRef(({ className, href, disabled, children, ...props }, ref) => { const onKeyDown = React.useCallback((event) => { if (typeof props.onKeyDown === 'function') { props.onKeyDown(event); @@ -25,12 +25,12 @@ const Button = React.forwardRef(({ children, ...props }, ref) => { } }, [props.onMouseDown]); return React.createElement( - typeof props.href === 'string' && props.href.length > 0 ? 'a' : 'div', + typeof href === 'string' && href.length > 0 ? 'a' : 'div', { tabIndex: 0, ...props, ref, - className: classnames(props.className, styles['button-container'], { 'disabled': props.disabled }), + className: classnames(className, styles['button-container'], { 'disabled': disabled }), onKeyDown, onMouseDown }, From d9a9c0ad9ce9dabb10b7932ebdf47efc70de76a4 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 10:28:56 +0200 Subject: [PATCH 356/442] fix ColorPicker flickering --- .../ColorInput/ColorPicker/ColorPicker.js | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/common/ColorInput/ColorPicker/ColorPicker.js b/src/common/ColorInput/ColorPicker/ColorPicker.js index 15fcf47c2..b26f68e6a 100644 --- a/src/common/ColorInput/ColorPicker/ColorPicker.js +++ b/src/common/ColorInput/ColorPicker/ColorPicker.js @@ -4,41 +4,42 @@ const classnames = require('classnames'); const AColorPicker = require('a-color-picker'); const styles = require('./styles'); -const COLOR_FORMAT = 'hexcss4'; +const parseColor = (value) => { + return AColorPicker.parseColor(value, 'hexcss4'); +}; -// TODO implement custom picker which is keyboard accessible const ColorPicker = ({ className, value, onInput }) => { const pickerRef = React.useRef(null); const pickerElementRef = React.useRef(null); - React.useEffect(() => { + React.useLayoutEffect(() => { pickerRef.current = AColorPicker.createPicker(pickerElementRef.current, { - color: AColorPicker.parseColor(value, COLOR_FORMAT), + color: parseColor(value), showHSL: false, showHEX: false, showRGB: false, showAlpha: true }); - const clipboardPicker = pickerElementRef.current.querySelector('.a-color-picker-clipbaord'); - if (clipboardPicker instanceof HTMLElement) { - clipboardPicker.tabIndex = -1; + const pickerClipboard = pickerElementRef.current.querySelector('.a-color-picker-clipbaord'); + if (pickerClipboard instanceof HTMLElement) { + pickerClipboard.tabIndex = -1; } }, []); - React.useEffect(() => { - pickerRef.current.on('change', (picker, value) => { - if (typeof onInput === 'function') { + React.useLayoutEffect(() => { + if (typeof onInput === 'function') { + pickerRef.current.on('change', (picker, value) => { onInput({ type: 'input', - value: AColorPicker.parseColor(value, COLOR_FORMAT) + value: parseColor(value) }); - } - }); + }); + } return () => { pickerRef.current.off('change'); }; }, [onInput]); - React.useEffect(() => { - const nextValue = AColorPicker.parseColor(value, COLOR_FORMAT); - if (AColorPicker.parseColor(pickerRef.current.color, COLOR_FORMAT) !== nextValue) { + React.useLayoutEffect(() => { + const nextValue = parseColor(value); + if (nextValue !== parseColor(pickerRef.current.color)) { pickerRef.current.color = nextValue; } }, [value]); From 94323725a402b4173b6b4d0146b245dfcc681616 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 10:34:09 +0200 Subject: [PATCH 357/442] fix flickering in ColorInput --- src/common/ColorInput/ColorInput.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/common/ColorInput/ColorInput.js b/src/common/ColorInput/ColorInput.js index f82ce3d1a..f493a11f1 100644 --- a/src/common/ColorInput/ColorInput.js +++ b/src/common/ColorInput/ColorInput.js @@ -2,16 +2,18 @@ const React = require('react'); const PropTypes = require('prop-types'); const AColorPicker = require('a-color-picker'); const Button = require('stremio/common/Button'); -const useBinaryState = require('stremio/common/useBinaryState'); const ModalDialog = require('stremio/common/ModalDialog'); +const useBinaryState = require('stremio/common/useBinaryState'); const ColorPicker = require('./ColorPicker'); -const COLOR_FORMAT = 'hexcss4'; +const parseColor = (value) => { + return AColorPicker.parseColor(value, 'hexcss4'); +}; const ColorInput = ({ className, value, dataset, onChange, ...props }) => { const [modalOpen, openModal, closeModal] = useBinaryState(false); const [tempValue, setTempValue] = React.useState(() => { - return AColorPicker.parseColor(value, COLOR_FORMAT); + return parseColor(value); }); const labelButtonStyle = React.useMemo(() => ({ ...props.style, @@ -43,22 +45,21 @@ const ColorInput = ({ className, value, dataset, onChange, ...props }) => { closeModal(); }; - return [ { label: 'Select', props: { - onClick: selectButtonOnClick, - 'data-autofocus': true + 'data-autofocus': true, + onClick: selectButtonOnClick } } ]; }, [tempValue, dataset, onChange]); const colorPickerOnInput = React.useCallback((event) => { - setTempValue(AColorPicker.parseColor(event.value, COLOR_FORMAT)); + setTempValue(parseColor(event.value)); }, []); - React.useEffect(() => { - setTempValue(AColorPicker.parseColor(value, COLOR_FORMAT)); + React.useLayoutEffect(() => { + setTempValue(parseColor(value)); }, [value, modalOpen]); return ( )} renderMenu={() => (
{ options.length > 0 ? - options.map(({ label, value }) => { - const isSelected = selected.includes(value); - const title = typeof label === 'string' ? label : value; - return ( - - ) - }) + options.map(({ label, value }) => ( + + )) :
No options available
From 784367fb5384b7d51f55de8db59b4c869a226d3a Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 12:34:34 +0200 Subject: [PATCH 361/442] RouteFocusedProvider added to Router decorator in story book --- storybook/RouterDecorator/RouterDecorator.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/storybook/RouterDecorator/RouterDecorator.js b/storybook/RouterDecorator/RouterDecorator.js index 54cb193d4..6a3d3a717 100644 --- a/storybook/RouterDecorator/RouterDecorator.js +++ b/storybook/RouterDecorator/RouterDecorator.js @@ -1,17 +1,20 @@ const React = require('react'); const classnames = require('classnames'); const Route = require('stremio-router/Route'); +const { RouteFocusedProvider } = require('stremio-router/RouteFocusedContext'); const appStyles = require('stremio/App/styles'); const styles = require('./styles'); const RouterDecorator = ({ children }) => (
- -
- {children} -
-
+ + +
+ {children} +
+
+
); From aaf5423c4e7eb2f1e187552aabd66c17d13f54a7 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 12:34:58 +0200 Subject: [PATCH 362/442] select share propmpt url only if its mounted in focused route --- src/common/SharePrompt/SharePrompt.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/SharePrompt/SharePrompt.js b/src/common/SharePrompt/SharePrompt.js index 0e6073380..dabe71f1e 100644 --- a/src/common/SharePrompt/SharePrompt.js +++ b/src/common/SharePrompt/SharePrompt.js @@ -2,12 +2,14 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); +const { useRouteFocused } = require('stremio-router'); const Button = require('stremio/common/Button'); const TextInput = require('stremio/common/TextInput'); const styles = require('./styles'); const SharePrompt = ({ className, url }) => { const inputRef = React.useRef(null); + const routeFocused = useRouteFocused(); const selectInputContent = React.useCallback(() => { if (inputRef.current !== null) { inputRef.current.select(); @@ -20,7 +22,7 @@ const SharePrompt = ({ className, url }) => { } }, []); React.useEffect(() => { - if (inputRef.current !== null) { + if (routeFocused && inputRef.current !== null) { inputRef.current.select(); } }, []); From df8e1864482711dce1860b46c0c760c38f98e504 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 12:39:49 +0200 Subject: [PATCH 363/442] href validation in Board improved --- src/routes/Board/useBoard.js | 2 +- src/routes/Board/useContinueWatching.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Board/useBoard.js b/src/routes/Board/useBoard.js index c418271c2..c96a520c6 100644 --- a/src/routes/Board/useBoard.js +++ b/src/routes/Board/useBoard.js @@ -12,7 +12,7 @@ const mapBoardState = (board) => { catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}`; if (catalog_resource.content.type === 'Ready') { catalog_resource.content.content.map((metaItem) => { - metaItem.href = `#/metadetails/${metaItem.type}/${metaItem.id}`; + metaItem.href = `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}`; return metaItem; }); } diff --git a/src/routes/Board/useContinueWatching.js b/src/routes/Board/useContinueWatching.js index 77183b4c6..80d54d7f6 100644 --- a/src/routes/Board/useContinueWatching.js +++ b/src/routes/Board/useContinueWatching.js @@ -6,7 +6,7 @@ const initContinueWatchingState = () => ({ const mapContinueWatchingState = (continue_watching) => { const lib_items = continue_watching.lib_items.map((lib_item) => { - lib_item.href = `#/metadetails/${lib_item.type}/${lib_item._id}${lib_item.state.video_id !== null ? `/${lib_item.state.video_id}` : ''}`; + lib_item.href = `#/metadetails/${encodeURIComponent(lib_item.type)}/${encodeURIComponent(lib_item._id)}${lib_item.state.video_id !== null ? `/${encodeURIComponent(lib_item.state.video_id)}` : ''}`; return lib_item; }); return { lib_items }; From 0f5474acc95e188f5857c53cfb933c3667b42fc3 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 12:47:52 +0200 Subject: [PATCH 364/442] meta item hrefs added to Search --- src/routes/Search/useSearch.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 1cbfe80cd..6a3f4e6b8 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -14,6 +14,13 @@ const mapSearchState = (search) => { const selected = search.selected; const catalog_resources = search.catalog_resources.map((catalog_resource) => { catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}?${queryString}`; + if (catalog_resource.content.type === 'Ready') { + catalog_resource.content.content.map((metaItem) => { + metaItem.href = `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}`; + return metaItem; + }); + } + return catalog_resource; }); return { selected, catalog_resources }; From 8542120fe35ff967cae1423dac782f17e0fdafa7 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 13:02:50 +0200 Subject: [PATCH 365/442] mapWithCtx prop added to useModelState --- src/common/useModelState.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/common/useModelState.js b/src/common/useModelState.js index a790b33cc..f5c1b9311 100644 --- a/src/common/useModelState.js +++ b/src/common/useModelState.js @@ -8,7 +8,7 @@ const UNLOAD_ACTION = { action: 'Unload', }; -const useModelState = ({ model, action, timeout, map, init }) => { +const useModelState = ({ model, action, timeout, map, mapWithCtx, init }) => { const modelRef = React.useRef(model); const { core } = useServices(); const routeFocused = useRouteFocused(); @@ -24,7 +24,14 @@ const useModelState = ({ model, action, timeout, map, init }) => { React.useLayoutEffect(() => { const onNewState = throttle(() => { const state = core.getState(modelRef.current); - setState(typeof map === 'function' ? map(state) : state); + if (typeof mapWithCtx === 'function') { + const ctx = core.getState('ctx'); + setState(mapWithCtx(state, ctx)); + } else if (typeof map === 'function') { + setState(map(state)); + } else { + setState(state); + } }, timeout); if (routeFocused) { core.on('NewState', onNewState); From cfe4caa9a156a47f68b5e59ca6809ed2e3b9200f Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 13:03:46 +0200 Subject: [PATCH 366/442] board addon names mapped from ctx --- src/routes/Board/useBoard.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/routes/Board/useBoard.js b/src/routes/Board/useBoard.js index c96a520c6..272609e7c 100644 --- a/src/routes/Board/useBoard.js +++ b/src/routes/Board/useBoard.js @@ -6,9 +6,16 @@ const initBoardState = () => ({ catalog_resources: [] }); -const mapBoardState = (board) => { +const mapBoardState = (board, ctx) => { const selected = board.selected; const catalog_resources = board.catalog_resources.map((catalog_resource) => { + catalog_resource.addon_name = ctx.content.addons.reduce((addon_name, addon) => { + if (addon.transportUrl === catalog_resource.request.base) { + return addon.manifest.name; + } + + return addon_name; + }, catalog_resource.request.base); catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}`; if (catalog_resource.content.type === 'Ready') { catalog_resource.content.content.map((metaItem) => { @@ -34,7 +41,7 @@ const useBoard = () => { model: 'board', action: loadBoardAction, timeout: 1000, - map: mapBoardState, + mapWithCtx: mapBoardState, init: initBoardState }); }; From 76665b804036f120da7b7312f5a3ae6ebb332223 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 14:27:53 +0200 Subject: [PATCH 367/442] addon name mapped in search hook --- src/routes/Search/useSearch.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 6a3f4e6b8..2b80d0188 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -6,13 +6,20 @@ const initSearchState = () => ({ catalog_resources: [] }); -const mapSearchState = (search) => { +const mapSearchState = (search, ctx) => { const queryString = search.selected !== null ? new URLSearchParams(search.selected.extra).toString() : ''; const selected = search.selected; const catalog_resources = search.catalog_resources.map((catalog_resource) => { + catalog_resource.addon_name = ctx.content.addons.reduce((addon_name, addon) => { + if (addon.transportUrl === catalog_resource.request.base) { + return addon.manifest.name; + } + + return addon_name; + }, catalog_resource.request.base); catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}?${queryString}`; if (catalog_resource.content.type === 'Ready') { catalog_resource.content.content.map((metaItem) => { @@ -49,7 +56,7 @@ const useSearch = (queryParams) => { return useModelState({ model: 'search', action: loadSearchAction, - map: mapSearchState, + mapWithCtx: mapSearchState, init: initSearchState }); }; From 136e9121dac22b17f2053b3b35a0e44c1fffb641 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 15:12:42 +0200 Subject: [PATCH 368/442] Core service adapted to the latest changes in stremio-core --- src/services/Core/Core.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/Core/Core.js b/src/services/Core/Core.js index 739d3b949..dc0c48894 100644 --- a/src/services/Core/Core.js +++ b/src/services/Core/Core.js @@ -58,14 +58,14 @@ function Core() { } function dispatch(action, model) { if (!active) { - return; + return false; } - stremio_core.dispatch(action, model); + return stremio_core.dispatch(action, model); } function getState(model) { if (!active) { - return {}; + return null; } return stremio_core.get_state(model); From cb0194f241c3c79cfaf9e3e76e1da3caf2b30ed6 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 15:53:25 +0200 Subject: [PATCH 369/442] dispatch actions on new state implemented in useModelState --- src/common/useModelState.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/common/useModelState.js b/src/common/useModelState.js index f5c1b9311..9d949df36 100644 --- a/src/common/useModelState.js +++ b/src/common/useModelState.js @@ -8,8 +8,9 @@ const UNLOAD_ACTION = { action: 'Unload', }; -const useModelState = ({ model, action, timeout, map, mapWithCtx, init }) => { +const useModelState = ({ model, action, timeout, onNewState, map, mapWithCtx, init }) => { const modelRef = React.useRef(model); + const mountedRef = React.useRef(false); const { core } = useServices(); const routeFocused = useRouteFocused(); const [state, setState] = useDeepEqualState(init); @@ -22,8 +23,16 @@ const useModelState = ({ model, action, timeout, map, mapWithCtx, init }) => { }; }, []); React.useLayoutEffect(() => { - const onNewState = throttle(() => { + const onNewStateThrottled = throttle(() => { const state = core.getState(modelRef.current); + if (typeof onNewState === 'function') { + const action = onNewState(state); + const handled = core.dispatch(action, modelRef.current); + if (handled) { + return; + } + } + if (typeof mapWithCtx === 'function') { const ctx = core.getState('ctx'); setState(mapWithCtx(state, ctx)); @@ -34,14 +43,19 @@ const useModelState = ({ model, action, timeout, map, mapWithCtx, init }) => { } }, timeout); if (routeFocused) { - core.on('NewState', onNewState); - onNewState.call(); + core.on('NewState', onNewStateThrottled); + if (mountedRef.current) { + onNewStateThrottled.call(); + } } return () => { - onNewState.cancel(); - core.off('NewState', onNewState); + onNewStateThrottled.cancel(); + core.off('NewState', onNewStateThrottled); }; }, [routeFocused]); + React.useLayoutEffect(() => { + mountedRef.current = true; + }, []); return state; }; From 95ab541c8159e176cfa94f7a19d1d68caf7905a9 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 15:57:54 +0200 Subject: [PATCH 370/442] useDiscover implemented with useModelState --- src/routes/Discover/useDiscover.js | 94 +++++++++++++++--------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index abe7c951d..f66f585aa 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -1,56 +1,42 @@ const React = require('react'); const { useServices } = require('stremio/services'); +const { useModelState } = require('stremio/common'); -const mapDiscoverState = (state) => { - const selectable = state.discover.selectable; - const catalog_resource = state.discover.catalog_resource !== null && state.discover.catalog_resource.content.type === 'Ready' ? +const initDiscoverState = () => ({ + selectable: { + types: [], + catalogs: [], + extra: [], + has_next_page: false, + has_prev_page: false + }, + catalog_resource: null +}); + +const mapDiscoverState = (discover) => { + const selectable = discover.selectable; + const catalog_resource = discover.catalog_resource !== null && discover.catalog_resource.content.type === 'Ready' ? { - ...state.discover.catalog_resource, + ...discover.catalog_resource, content: { - ...state.discover.catalog_resource.content, - content: state.discover.catalog_resource.content.content.map((metaItem) => { + ...discover.catalog_resource.content, + content: discover.catalog_resource.content.content.map((metaItem) => { metaItem.released = new Date(metaItem.released); + metaItem.href = `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}`; return metaItem; }) } } : - state.discover.catalog_resource; + discover.catalog_resource; return { selectable, catalog_resource }; }; const useDiscover = (urlParams, queryParams) => { const { core } = useServices(); - const [discover, setDiscover] = React.useState(() => ({ - selectable: { - types: [], - catalogs: [], - extra: [], - has_next_page: false, - has_prev_page: false - }, - catalog_resource: null - })); - React.useLayoutEffect(() => { - const onNewModel = () => { - const state = core.getState(); - if (state.discover.catalog_resource === null && state.discover.selectable.types.length > 0) { - const load_request = state.discover.selectable.types[0].load_request; - core.dispatch({ - action: 'Load', - args: { - load: 'CatalogFiltered', - args: load_request - } - }, 'Discover'); - return; - } - const discover = mapDiscoverState(state); - setDiscover(discover); - }; - core.on('NewModel', onNewModel); - if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') { - core.dispatch({ + const loadDiscoverAction = React.useMemo(() => { + if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.type === 'string' && typeof urlParams.catalogId === 'string') { + return { action: 'Load', args: { load: 'CatalogFiltered', @@ -64,25 +50,39 @@ const useDiscover = (urlParams, queryParams) => { } } } - }, 'Discover'); + }; } else { - const state = core.getState(); - if (state.discover.selectable.types.length > 0) { - const load_request = state.discover.selectable.types[0].load_request; - core.dispatch({ + const discover = core.getState('discover'); + if (discover.selectable.types.length > 0) { + const load_request = discover.selectable.types[0].load_request; + return { action: 'Load', args: { load: 'CatalogFiltered', args: load_request } - }, 'Discover'); + }; } } - return () => { - core.off('NewModel', onNewModel); - }; }, [urlParams, queryParams]); - return discover; + const onNewDiscoverState = React.useCallback((discover) => { + if (discover.catalog_resource === null && discover.selectable.types.length > 0) { + return { + action: 'Load', + args: { + load: 'CatalogFiltered', + args: discover.selectable.types[0].load_request + } + }; + } + }, []); + return useModelState({ + model: 'discover', + action: loadDiscoverAction, + map: mapDiscoverState, + init: initDiscoverState, + onNewState: onNewDiscoverState + }); }; module.exports = useDiscover; From 67334bd07342cba4979b718f7f499c0167ac3818 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 16:17:10 +0200 Subject: [PATCH 371/442] disable pagination input if skip is manually entered in the url --- src/routes/Discover/useSelectableInputs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Discover/useSelectableInputs.js b/src/routes/Discover/useSelectableInputs.js index f2d3ebf0c..276cac043 100644 --- a/src/routes/Discover/useSelectableInputs.js +++ b/src/routes/Discover/useSelectableInputs.js @@ -149,7 +149,7 @@ const mapSelectableInputs = (discover) => { }; return { title, options, selected, renderLabelText, onSelect }; }); - const paginationInput = discover.selectable.has_prev_page || discover.selectable.has_next_page || selectedCatalogRequest.path.extra.some(([name]) => name === 'skip') ? + const paginationInput = discover.selectable.has_prev_page || discover.selectable.has_next_page ? { label: String(requestedPage), onSelect: (event) => { From 29717ba34b7f3b92f68ac5b2cb327e0c6e31c3fe Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 16:26:41 +0200 Subject: [PATCH 372/442] stream metaItem props in discover --- src/routes/Discover/Discover.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index fc9c1b953..f699f73bc 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -90,12 +90,9 @@ const Discover = ({ urlParams, queryParams }) => {
{discover.catalog_resource.content.content.map((metaItem, index) => ( ))} From 0b9d368769d06e00821e4c1fcfa7ef7748709ec8 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 16:31:39 +0200 Subject: [PATCH 373/442] mount empty modal dialog in discover for now --- src/routes/Discover/Discover.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index f699f73bc..fd3597dc8 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -1,8 +1,7 @@ const React = require('react'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); -const { Modal } = require('stremio-router'); -const { Button, MainNavBar, MetaItem, MetaPreview, Multiselect, PaginationInput, useBinaryState } = require('stremio/common'); +const { Button, MainNavBar, MetaItem, MetaPreview, Multiselect, ModalDialog, PaginationInput, useBinaryState } = require('stremio/common'); const useDiscover = require('./useDiscover'); const useSelectableInputs = require('./useSelectableInputs'); const styles = require('./styles'); @@ -111,12 +110,12 @@ const Discover = ({ urlParams, queryParams }) => {
}
- {/* { + { inputsModalOpen ? - + : null - } */} + }
); }; From 5f1f855ed463427ecaafb15697fd85a6c119d92d Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 16:52:29 +0200 Subject: [PATCH 374/442] discover regexp updated --- src/common/routesRegexp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index 7dfee0c44..3694a9b64 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -8,7 +8,7 @@ const routesRegexp = { urlParamsNames: [] }, discover: { - regexp: /^\/discover(?:\/([^\/]+?)\/([^\/]+?)\/([^\/]+?))?\/?$/i, + regexp: /^\/discover\/(?:([^\/]*))\/(?:([^\/]*))\/(?:([^\/]*))\/?$/i, urlParamsNames: ['addonTransportUrl', 'type', 'catalogId'] }, library: { From 46e7e0c21abf4b3f4b01bf16ae49809972ee15c4 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 17:20:47 +0200 Subject: [PATCH 375/442] useUser initialized from core --- src/common/useUser.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/common/useUser.js b/src/common/useUser.js index 5a71b72e0..36ff01acd 100644 --- a/src/common/useUser.js +++ b/src/common/useUser.js @@ -2,8 +2,6 @@ const React = require('react'); const { useServices } = require('stremio/services'); const useModelState = require('stremio/common/useModelState'); -const initUserState = () => null; - const mapUserState = (ctx) => { return ctx.content.auth ? ctx.content.auth.user : null; }; @@ -18,6 +16,10 @@ const useUser = () => { } }); }, []); + const initUserState = React.useCallback(() => { + const ctx = core.getState('ctx'); + return mapUserState(ctx); + }, []); const user = useModelState({ model: 'ctx', map: mapUserState, From dfebba9e1c5765d986e2f3dd2df3305f41ae1da7 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 17:23:12 +0200 Subject: [PATCH 376/442] useLibrary implemented with useModelState --- src/routes/Library/useLibrary.js | 100 +++++++++++++++++-------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index fab0c359a..24928ad7d 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -1,46 +1,50 @@ const React = require('react'); const { useServices } = require('stremio/services'); +const { useModelState } = require('stremio/common'); -const mapLibraryState = (state) => { - const library_state = state.library.library_state; - const selected = state.library.selected; - const lib_items = state.library.lib_items.map((lib_item) => { +const initLibraryState = () => ({ + library_state: { + type: 'NotLoaded' + }, + selected: { + type_name: null + }, + type_names: [], + lib_items: [] +}); + +const mapLibraryState = (library) => { + const library_state = library.library_state; + const selected = library.selected; + const type_names = library.type_names; + const lib_items = library.lib_items.map((lib_item) => { + // TODO what else lib_item._ctime = new Date(lib_item._ctime); + lib_item.href = `#/metadetails/${encodeURIComponent(lib_item.type)}/${encodeURIComponent(lib_item._id)}${lib_item.state.video_id !== null ? `/${encodeURIComponent(lib_item.state.video_id)}` : ''}`; return lib_item; }); - const type_names = state.library.type_names; - return { library_state, selected, lib_items, type_names }; + return { library_state, selected, type_names, lib_items }; +}; + +const onNewLibraryState = (library) => { + if (library.selected.type_name === null && library.type_names.length > 0) { + return { + action: 'Load', + args: { + load: 'LibraryFiltered', + args: { + type_name: library.type_names[0] + } + } + }; + } }; const useLibrary = (urlParams) => { const { core } = useServices(); - const [library, setLibrary] = React.useState(() => { - const state = core.getState(); - const library = mapLibraryState(state); - return library; - }); - React.useEffect(() => { - const onNewState = () => { - const state = core.getState(); - if (state.library.selected.type_name === null && state.library.type_names.length > 0) { - core.dispatch({ - action: 'Load', - args: { - load: 'LibraryFiltered', - args: { - type_name: state.library.type_names[0] - } - } - }); - return; - } - const library = mapLibraryState(state); - setLibrary(library); - }; - core.on('NewModel', onNewState); - const state = core.getState(); + const loadLibraryAction = React.useMemo(() => { if (typeof urlParams.type === 'string') { - core.dispatch({ + return { action: 'Load', args: { load: 'LibraryFiltered', @@ -48,23 +52,29 @@ const useLibrary = (urlParams) => { type_name: urlParams.type } } - }); - } else if (state.library.type_names.length > 0) { - core.dispatch({ - action: 'Load', - args: { - load: 'LibraryFiltered', + }; + } else { + const library = core.getState('library'); + if (library.type_names.length > 0) { + return { + action: 'Load', args: { - type_name: state.library.type_names[0] + load: 'LibraryFiltered', + args: { + type_name: library.type_names[0] + } } - } - }); + }; + } } - return () => { - core.off('NewModel', onNewState); - }; }, [urlParams]); - return library; + return useModelState({ + model: 'library', + action: loadLibraryAction, + map: mapLibraryState, + init: initLibraryState, + onNewState: onNewLibraryState + }); } module.exports = useLibrary; From b749cb1c0882d6a198f64629f569f311dd93e086 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 17:23:30 +0200 Subject: [PATCH 377/442] Library use new common useUser hook --- src/routes/Library/Library.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 2d77621e2..0273fe201 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -1,14 +1,13 @@ const React = require('react'); const UrlUtils = require('url'); const classnames = require('classnames'); -const { Button, Multiselect, MainNavBar, MetaItem } = require('stremio/common'); -const useUser = require('stremio/common/useUser'); +const { Button, Multiselect, MainNavBar, MetaItem, useUser } = require('stremio/common'); const useLibrary = require('./useLibrary'); const useSort = require('./useSort'); const styles = require('./styles'); const Library = ({ urlParams, queryParams }) => { - const user = useUser(); + const [user] = useUser(); const library = useLibrary(urlParams); const [selectSortInput, sortFunction] = useSort(urlParams, queryParams); const loginButtonOnClick = React.useCallback(() => { From f1f9428b4b153071d723c6000e78f8f17c38bfff Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 17:30:23 +0200 Subject: [PATCH 378/442] replace location in discover when choose option from picker --- src/routes/Discover/useSelectableInputs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Discover/useSelectableInputs.js b/src/routes/Discover/useSelectableInputs.js index 276cac043..6ce6a4190 100644 --- a/src/routes/Discover/useSelectableInputs.js +++ b/src/routes/Discover/useSelectableInputs.js @@ -13,7 +13,7 @@ const navigateWithLoadRequest = (load_request) => { const type = encodeURIComponent(load_request.path.type_name); const catalogId = encodeURIComponent(load_request.path.id); const extra = new URLSearchParams(load_request.path.extra).toString(); - window.location = `#/discover/${addonTransportUrl}/${type}/${catalogId}?${extra}`; + window.location.replace(`#/discover/${addonTransportUrl}/${type}/${catalogId}?${extra}`); }; const getNextExtra = (prevExtra, extraProp, extraValue) => { From 1b7dfe50d8d3d7c3257f801c91814c8d723b25d2 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 17:50:43 +0200 Subject: [PATCH 379/442] discover regexp fixed --- src/common/routesRegexp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index 3694a9b64..e0a414f76 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -8,7 +8,7 @@ const routesRegexp = { urlParamsNames: [] }, discover: { - regexp: /^\/discover\/(?:([^\/]*))\/(?:([^\/]*))\/(?:([^\/]*))\/?$/i, + regexp: /^\/discover(?:\/([^\/]*)\/([^\/]*)\/([^\/]*))?\/?$/i, urlParamsNames: ['addonTransportUrl', 'type', 'catalogId'] }, library: { From 5e24bae69c0a07ab47282dd7a8e9a08436b533ea Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 6 Dec 2019 17:51:02 +0200 Subject: [PATCH 380/442] onNewDiscoverState moved out of the hook --- src/routes/Discover/useDiscover.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index f66f585aa..62e007992 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -32,6 +32,18 @@ const mapDiscoverState = (discover) => { return { selectable, catalog_resource }; }; +const onNewDiscoverState = (discover) => { + if (discover.catalog_resource === null && discover.selectable.types.length > 0) { + return { + action: 'Load', + args: { + load: 'CatalogFiltered', + args: discover.selectable.types[0].load_request + } + }; + } +}; + const useDiscover = (urlParams, queryParams) => { const { core } = useServices(); const loadDiscoverAction = React.useMemo(() => { @@ -54,28 +66,16 @@ const useDiscover = (urlParams, queryParams) => { } else { const discover = core.getState('discover'); if (discover.selectable.types.length > 0) { - const load_request = discover.selectable.types[0].load_request; return { action: 'Load', args: { load: 'CatalogFiltered', - args: load_request + args: discover.selectable.types[0].load_request } }; } } }, [urlParams, queryParams]); - const onNewDiscoverState = React.useCallback((discover) => { - if (discover.catalog_resource === null && discover.selectable.types.length > 0) { - return { - action: 'Load', - args: { - load: 'CatalogFiltered', - args: discover.selectable.types[0].load_request - } - }; - } - }, []); return useModelState({ model: 'discover', action: loadDiscoverAction, From 9cbe8ce1274e823e92e48b9db73c2b2ab85d2cd6 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 14:36:50 +0200 Subject: [PATCH 381/442] library regexp changed --- src/common/routesRegexp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index e0a414f76..d3173b300 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -12,7 +12,7 @@ const routesRegexp = { urlParamsNames: ['addonTransportUrl', 'type', 'catalogId'] }, library: { - regexp: /^\/library(?:\/([^\/]*)\/?)?$/i, + regexp: /^\/library(?:\/([^\/]*))?\/?$/i, urlParamsNames: ['type'] }, search: { From 5bcab12f4d3deb5c7f34acf93db567223a4883e6 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 14:37:24 +0200 Subject: [PATCH 382/442] useLibrary uses sort_prop from query param --- src/routes/Library/useLibrary.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 24928ad7d..2140aa59e 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -6,9 +6,7 @@ const initLibraryState = () => ({ library_state: { type: 'NotLoaded' }, - selected: { - type_name: null - }, + selected: null, type_names: [], lib_items: [] }); @@ -18,8 +16,8 @@ const mapLibraryState = (library) => { const selected = library.selected; const type_names = library.type_names; const lib_items = library.lib_items.map((lib_item) => { - // TODO what else lib_item._ctime = new Date(lib_item._ctime); + lib_item._mtime = new Date(lib_item._mtime); lib_item.href = `#/metadetails/${encodeURIComponent(lib_item.type)}/${encodeURIComponent(lib_item._id)}${lib_item.state.video_id !== null ? `/${encodeURIComponent(lib_item.state.video_id)}` : ''}`; return lib_item; }); @@ -27,20 +25,21 @@ const mapLibraryState = (library) => { }; const onNewLibraryState = (library) => { - if (library.selected.type_name === null && library.type_names.length > 0) { + if (library.selected === null && library.type_names.length > 0) { return { action: 'Load', args: { load: 'LibraryFiltered', args: { - type_name: library.type_names[0] + type_name: library.type_names[0], + sort_prop: null } } }; } }; -const useLibrary = (urlParams) => { +const useLibrary = (urlParams, queryParams) => { const { core } = useServices(); const loadLibraryAction = React.useMemo(() => { if (typeof urlParams.type === 'string') { @@ -49,7 +48,8 @@ const useLibrary = (urlParams) => { args: { load: 'LibraryFiltered', args: { - type_name: urlParams.type + type_name: urlParams.type, + sort_prop: queryParams.get('sort_prop') } } }; @@ -61,13 +61,14 @@ const useLibrary = (urlParams) => { args: { load: 'LibraryFiltered', args: { - type_name: library.type_names[0] + type_name: library.type_names[0], + sort_prop: null } } }; } } - }, [urlParams]); + }, [urlParams, queryParams]); return useModelState({ model: 'library', action: loadLibraryAction, From 466cbd0f23c2d6bd697fcb9947fcf2b4d60d83f0 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 14:37:54 +0200 Subject: [PATCH 383/442] ueSort dropped --- src/routes/Library/useSort.js | 37 ----------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 src/routes/Library/useSort.js diff --git a/src/routes/Library/useSort.js b/src/routes/Library/useSort.js deleted file mode 100644 index 39b92acd8..000000000 --- a/src/routes/Library/useSort.js +++ /dev/null @@ -1,37 +0,0 @@ -const React = require('react'); -const { useServices } = require('stremio/services'); - -const DEFAULT_SORT = 'recent'; -const SORTS = [DEFAULT_SORT, 'year', 'a-z']; -const SORT_PROPS = new Map([ - ['recent', '_ctime'], - ['a-z', 'name'], - ['year', 'year'] -]); - -const useSort = (urlParams, queryParams) => { - const { core } = useServices(); - const [sort, setSort] = React.useState([null, () => { }]); - React.useEffect(() => { - const sort = queryParams.has('sort') && SORTS.includes(queryParams.get('sort')) ? queryParams.get('sort') : DEFAULT_SORT; - const sortProp = SORT_PROPS.get(sort); - const sortItems = (a, b) => { - if (a[sortProp] < b[sortProp]) return -1; - if (a[sortProp] > b[sortProp]) return 1; - return 0; - }; - const selectInput = { - selected: [sort], - options: [{ label: 'Recent', value: 'recent' }, { label: 'A-Z', value: 'a-z' }, { label: 'Year', value: 'year' }], - onSelect: (event) => { - const nextQuery = new URLSearchParams({ sort: event.value }); - const state = core.getState(); - window.location.replace(`#/library/${state.library.selected.type_name !== null ? state.library.selected.type_name : ''}?${nextQuery}`); - } - }; - setSort([selectInput, sortItems]); - }, [urlParams, queryParams]); - return sort; -}; - -module.exports = useSort; From 6a196c3f06be19284cca32dd142596c9d2233a73 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 14:39:06 +0200 Subject: [PATCH 384/442] useSelectableInputs hook to map inputs from library implemented --- src/routes/Library/useSelectableInputs.js | 50 +++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/routes/Library/useSelectableInputs.js diff --git a/src/routes/Library/useSelectableInputs.js b/src/routes/Library/useSelectableInputs.js new file mode 100644 index 000000000..2b79d915f --- /dev/null +++ b/src/routes/Library/useSelectableInputs.js @@ -0,0 +1,50 @@ +const React = require('react'); + +const SORT_PROP_OPTIONS = [ + { label: 'Recent', value: '_ctime' }, + { label: 'A-Z', value: 'name' }, + { label: 'Year', value: 'year' }, +]; + +const mapSelectableInputs = (library) => { + const typeSelect = { + selected: library.selected !== null ? + [library.selected.type_name] + : + [], + options: library.type_names + .map((type) => ({ label: type, value: type })), + onSelect: (event) => { + const queryParams = new URLSearchParams( + library.selected !== null ? + [['sort_prop', library.selected.sort_prop]] + : + [] + ); + window.location.replace(`#/library/${encodeURIComponent(event.value)}?${queryParams.toString()}`); + } + }; + const sortPropSelect = { + selected: library.selected !== null ? + [library.selected.sort_prop] + : + [], + options: SORT_PROP_OPTIONS, + onSelect: (event) => { + const queryParams = new URLSearchParams([['sort_prop', event.value]]); + if (library.selected !== null) { + window.location.replace(`#/library/${encodeURIComponent(library.selected.type_name)}?${queryParams.toString()}`); + } + } + }; + return [typeSelect, sortPropSelect]; +}; + +const useSelectableInputs = (library) => { + const selectableInputs = React.useMemo(() => { + return mapSelectableInputs(library); + }, [library]); + return selectableInputs; +}; + +module.exports = useSelectableInputs; From 391b32e9510df0885a948a776700ed2945a6834a Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 15:11:29 +0200 Subject: [PATCH 385/442] fix library load action across browsers --- src/routes/Library/useLibrary.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 2140aa59e..05bb98f7c 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -49,7 +49,10 @@ const useLibrary = (urlParams, queryParams) => { load: 'LibraryFiltered', args: { type_name: urlParams.type, - sort_prop: queryParams.get('sort_prop') + sort_prop: queryParams.has('sort_prop') ? + queryParams.get('sort_prop') + : + null } } }; From dd657daa73928ca330e88451b4c9b9c933554679 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 15:29:33 +0200 Subject: [PATCH 386/442] title added to library selects --- src/routes/Library/useSelectableInputs.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routes/Library/useSelectableInputs.js b/src/routes/Library/useSelectableInputs.js index 2b79d915f..601ce9731 100644 --- a/src/routes/Library/useSelectableInputs.js +++ b/src/routes/Library/useSelectableInputs.js @@ -8,6 +8,7 @@ const SORT_PROP_OPTIONS = [ const mapSelectableInputs = (library) => { const typeSelect = { + title: 'Select type', selected: library.selected !== null ? [library.selected.type_name] : @@ -25,6 +26,7 @@ const mapSelectableInputs = (library) => { } }; const sortPropSelect = { + title: 'Select sort', selected: library.selected !== null ? [library.selected.sort_prop] : From 7d470c9e2d5c26de5742aace1f89729806e9a07d Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 16:20:44 +0200 Subject: [PATCH 387/442] Library ui adapted to the latest changes in core --- src/routes/Library/Library.js | 98 +++++++++++------------------- src/routes/Library/styles.less | 105 +++++++++++++++++++-------------- 2 files changed, 96 insertions(+), 107 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 0273fe201..f271799f8 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -1,87 +1,61 @@ const React = require('react'); -const UrlUtils = require('url'); const classnames = require('classnames'); -const { Button, Multiselect, MainNavBar, MetaItem, useUser } = require('stremio/common'); +const { Button, Multiselect, MainNavBar, MetaItem } = require('stremio/common'); const useLibrary = require('./useLibrary'); -const useSort = require('./useSort'); +const useSelectableInputs = require('./useSelectableInputs'); const styles = require('./styles'); const Library = ({ urlParams, queryParams }) => { - const [user] = useUser(); - const library = useLibrary(urlParams); - const [selectSortInput, sortFunction] = useSort(urlParams, queryParams); - const loginButtonOnClick = React.useCallback(() => { - window.location.replace('#/intro'); - }, []); - const selectTypeInput = React.useMemo(() => { - return { - selected: [library.selected.type_name], - options: library.type_names - .map((type) => ({ - label: type === '' ? '"Empty"' : type, - value: type - })), - onSelect: (event) => { - const { search } = UrlUtils.parse(window.location.hash.slice(1)); - window.location.replace(`#/library/${event.value}${search !== null ? search : ''}`); - } - } - }, [library.selected.type_name, library.type_names]); + const library = useLibrary(urlParams, queryParams); + const [typeSelect, sortPropSelect] = useSelectableInputs(library); return (
{ - user ? -
- - + library.library_state.type === 'Ready' && library.library_state.content.uid !== null && library.type_names.length > 0 ? +
+ +
: null } -
- { - !user ? -
- Please log into this app - + { + library.library_state.type === 'Ready' && library.library_state.content.uid === null ? +
+
Library is only availavle for logged in users
+ +
+ : + library.library_state.type !== 'Ready' ? +
+
Loading
: - library.library_state.type != 'Ready' ? + library.type_names.length === 0 ?
- Loading +
Empty library
: - library.type_names.length > 0 ? - library.selected.type_name !== null ? - library.lib_items.length > 0 ? -
- {library.lib_items - .sort(sortFunction) - .map(({ removed, temp, ...libItem }, index) => ( - - ))} -
- : -
- Empty library -
- : -
- Select a type, please -
- : + library.selected === null ?
- Empty library +
Please select a type
- } -
+ : + library.lib_items.length === 0 ? +
+
There are no items for the selected type
+
+ : +
+ {library.lib_items.map((libItem, index) => ( + + ))} +
+ }
); diff --git a/src/routes/Library/styles.less b/src/routes/Library/styles.less index a09fb601e..5dab0caa9 100644 --- a/src/routes/Library/styles.less +++ b/src/routes/Library/styles.less @@ -1,5 +1,9 @@ @import (reference) '~stremio/common/screen-sizes.less'; +:import('~stremio/common/Multiselect/styles.less') { + multiselect-menu-container: menu-container; +} + .library-container { display: flex; flex-direction: column; @@ -15,18 +19,15 @@ .library-content { flex: 1; align-self: stretch; - display: grid; - grid-template-columns: 1fr auto; - grid-template-rows: auto 1fr; - grid-template-areas: - "controls-area switch-view-area" - "type-content-area type-content-area"; + display: flex; + flex-direction: column; - .controls-container { - grid-area: controls-area; + .selectable-inputs-container { + flex: none; + align-self: stretch; display: flex; flex-direction: row; - margin: 2rem; + margin: 1.5rem; overflow: visible; .select-input-container { @@ -36,68 +37,82 @@ height: 3rem; &:not(:last-child) { - margin-right: 1rem; + margin-right: 1.5rem; + } + + .multiselect-menu-container { + max-height: calc(3.2rem * 7); + overflow: auto; } } } - .type-content-container { - grid-area: type-content-area; + .message-container, .meta-items-container { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + padding: 0 1.5rem; + overflow-y: auto; + } - .meta-items-container { - display: grid; - max-height: 100%; - grid-auto-rows: max-content; - grid-gap: 1.5rem; - align-items: center; - padding: 0 2rem; - overflow-y: auto; + .message-container { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + + &:first-child { + .message-label { + margin: 1.5rem 0; + } } - .message-container { - padding: 0 2rem; - font-size: 2rem; - color: var(--color-surfacelighter); - } - - .anonymous-user-message-container { - display: flex; - flex-direction: column; + &.no-user-message-container { + flex: 1; justify-content: center; - align-items: center; - width: 100%; - height: 100%; - .login-button { + .login-button-container { + flex: none; display: flex; - flex-direction: column; + flex-direction: row; align-items: center; justify-content: center; width: 20rem; min-height: 4rem; - margin-top: 2rem; padding: 0.5rem 1rem; background-color: var(--color-primarydark); - .label { - flex-grow: 0; - flex-shrink: 1; - flex-basis: auto; - font-size: 1.1rem; - font-weight: 700; - color: var(--color-surfacelighter); - text-align: center; - } - &:hover { background-color: var(--color-primary); } .label { + flex-grow: 0; + flex-shrink: 1; + flex-basis: auto; + max-height: 4.8em; font-size: 1.2rem; + font-weight: 700; + color: var(--color-surfacelighter); + text-align: center; } } } + + .message-label { + flex: none; + max-height: 4.8em; + font-size: 2rem; + color: var(--color-surfacelighter); + text-align: center; + } + } + + .meta-items-container { + display: grid; + grid-auto-rows: max-content; + align-items: center; + grid-gap: 1.5rem; } } } From 949fe7fccf5cc3c975325b92c8717c390b61d3f9 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 16:43:19 +0200 Subject: [PATCH 388/442] prevent selecting meta item when clicking inside menu --- src/common/MetaItem/MetaItem.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/common/MetaItem/MetaItem.js b/src/common/MetaItem/MetaItem.js index 2f699051c..c42d3ff94 100644 --- a/src/common/MetaItem/MetaItem.js +++ b/src/common/MetaItem/MetaItem.js @@ -19,6 +19,14 @@ const ICON_FOR_TYPE = new Map([ const MetaItem = React.memo(({ className, type, name, poster, posterShape, playIcon, progress, options, dataset, ...props }) => { const [menuOpen, onMenuOpen, onMenuClose] = useBinaryState(false); + const metaItemOnClick = React.useCallback((event) => { + if (event.nativeEvent.selectPrevented) { + event.preventDefault(); + } + }, []); + const menuOnClick = React.useCallback((event) => { + event.nativeEvent.selectPrevented = true; + }, []); const optionOnSelect = React.useCallback((event) => { if (typeof props.optionOnSelect === 'function') { props.optionOnSelect({ @@ -40,7 +48,7 @@ const MetaItem = React.memo(({ className, type, name, poster, posterShape, playI ), []); return ( - Date: Sun, 8 Dec 2019 20:22:32 +0200 Subject: [PATCH 395/442] board item maps fixed --- src/routes/Board/Board.js | 20 ++++++++------------ src/routes/Board/useBoard.js | 22 ++++++++++++---------- src/routes/Board/useContinueWatching.js | 22 +++++++++++++++------- src/routes/Board/useItemOptions.js | 25 +++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 29 deletions(-) create mode 100644 src/routes/Board/useItemOptions.js diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index e811b8d77..33b6638ae 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -2,22 +2,13 @@ const React = require('react'); const { MainNavBar, MetaRow } = require('stremio/common'); const useBoard = require('./useBoard'); const useContinueWatching = require('./useContinueWatching'); +const useItemOptions = require('./useItemOptions'); const styles = require('./styles'); -const CONTINUE_WATCHING_MENU = [ - { - label: 'Play', - value: 'play' - }, - { - label: 'Dismiss', - value: 'dismiss' - } -]; - const Board = () => { const board = useBoard(); const continueWatching = useContinueWatching(); + const [options, optionOnSelect] = useItemOptions(); return (
@@ -27,7 +18,12 @@ const Board = () => { ({ + ...libItem, + dataset: { id, videoId, type: libItem.type }, + options, + optionOnSelect + }))} limit={10} /> : diff --git a/src/routes/Board/useBoard.js b/src/routes/Board/useBoard.js index 272609e7c..d5cc92d17 100644 --- a/src/routes/Board/useBoard.js +++ b/src/routes/Board/useBoard.js @@ -6,7 +6,7 @@ const initBoardState = () => ({ catalog_resources: [] }); -const mapBoardState = (board, ctx) => { +const mapBoardStateWithCtx = (board, ctx) => { const selected = board.selected; const catalog_resources = board.catalog_resources.map((catalog_resource) => { catalog_resource.addon_name = ctx.content.addons.reduce((addon_name, addon) => { @@ -16,14 +16,16 @@ const mapBoardState = (board, ctx) => { return addon_name; }, catalog_resource.request.base); - catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}`; if (catalog_resource.content.type === 'Ready') { - catalog_resource.content.content.map((metaItem) => { - metaItem.href = `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}`; - return metaItem; - }); + catalog_resource.content.content = catalog_resource.content.content.map((metaItem) => ({ + type: metaItem.type, + name: metaItem.name, + poster: metaItem.poster, + posterShape: metaItem.posterShape, + href: `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}` // TODO this should redirect with videoId at some cases + })); } - + catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}`; return catalog_resource; }); return { selected, catalog_resources }; @@ -40,9 +42,9 @@ const useBoard = () => { return useModelState({ model: 'board', action: loadBoardAction, - timeout: 1000, - mapWithCtx: mapBoardState, - init: initBoardState + mapWithCtx: mapBoardStateWithCtx, + init: initBoardState, + timeout: 1000 }); }; diff --git a/src/routes/Board/useContinueWatching.js b/src/routes/Board/useContinueWatching.js index 80d54d7f6..ab13697e0 100644 --- a/src/routes/Board/useContinueWatching.js +++ b/src/routes/Board/useContinueWatching.js @@ -5,20 +5,28 @@ const initContinueWatchingState = () => ({ }); const mapContinueWatchingState = (continue_watching) => { - const lib_items = continue_watching.lib_items.map((lib_item) => { - lib_item.href = `#/metadetails/${encodeURIComponent(lib_item.type)}/${encodeURIComponent(lib_item._id)}${lib_item.state.video_id !== null ? `/${encodeURIComponent(lib_item.state.video_id)}` : ''}`; - return lib_item; - }); + const lib_items = continue_watching.lib_items.map((lib_item) => ({ + id: lib_item._id, + type: lib_item.type, + name: lib_item.name, + poster: lib_item.poster, + posterShape: lib_item.posterShape, + progress: lib_item.state.timeOffset > 0 && lib_item.state.duration > 0 ? + lib_item.state.timeOffset / lib_item.state.duration + : + null, + videoId: lib_item.state.video_id, + href: `#/metadetails/${encodeURIComponent(lib_item.type)}/${encodeURIComponent(lib_item._id)}${lib_item.state.video_id !== null ? `/${encodeURIComponent(lib_item.state.video_id)}` : ''}` + })); return { lib_items }; }; const useContinueWatching = () => { return useModelState({ model: 'continue_watching', - action: null, - timeout: 5000, map: mapContinueWatchingState, - init: initContinueWatchingState + init: initContinueWatchingState, + timeout: 5000 }); }; diff --git a/src/routes/Board/useItemOptions.js b/src/routes/Board/useItemOptions.js new file mode 100644 index 000000000..870c14936 --- /dev/null +++ b/src/routes/Board/useItemOptions.js @@ -0,0 +1,25 @@ +const React = require('react'); + +const PLAY_OPTION = { + label: 'Play', + value: 'play' +}; + +const DISMISS_OPTION = { + label: 'Dismiss', + value: 'dismiss' +}; + +const onSelect = (event) => { + // TODO {{event.value}} {{event.dataset}} +}; + +const useItemOptions = () => { + const options = React.useMemo(() => ([ + PLAY_OPTION, + DISMISS_OPTION + ]), []); + return [options, onSelect]; +}; + +module.exports = useItemOptions; From 9ed75f3a32eaeeb344b13ef21cc3d39deecdeff4 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 20:22:42 +0200 Subject: [PATCH 396/442] useRouteActive validation improved --- src/common/useRouteActive.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/useRouteActive.js b/src/common/useRouteActive.js index 14225a8f7..1fde72466 100644 --- a/src/common/useRouteActive.js +++ b/src/common/useRouteActive.js @@ -5,8 +5,8 @@ const useLocationHash = require('stremio/common/useLocationHash'); const useRouteActive = (routeRegexp) => { const locationHash = useLocationHash(); const active = React.useMemo(() => { - const { pathname: locationPathname } = UrlUtils.parse(locationHash.slice(1)); - return routeRegexp instanceof RegExp && !!locationPathname.match(routeRegexp); + const { pathname } = UrlUtils.parse(locationHash.slice(1)); + return typeof pathname === 'string' && routeRegexp instanceof RegExp && !!pathname.match(routeRegexp); }, [locationHash, routeRegexp]); return active; }; From 9e3b4ea78e35058d8c115b1830804fb8661d96d5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 20:42:11 +0200 Subject: [PATCH 397/442] Search map fixed --- src/routes/Search/useSearch.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/routes/Search/useSearch.js b/src/routes/Search/useSearch.js index 2b80d0188..078d53840 100644 --- a/src/routes/Search/useSearch.js +++ b/src/routes/Search/useSearch.js @@ -6,7 +6,7 @@ const initSearchState = () => ({ catalog_resources: [] }); -const mapSearchState = (search, ctx) => { +const mapSearchStateWithCtx = (search, ctx) => { const queryString = search.selected !== null ? new URLSearchParams(search.selected.extra).toString() : @@ -20,14 +20,16 @@ const mapSearchState = (search, ctx) => { return addon_name; }, catalog_resource.request.base); - catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}?${queryString}`; if (catalog_resource.content.type === 'Ready') { - catalog_resource.content.content.map((metaItem) => { - metaItem.href = `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}`; - return metaItem; - }); + catalog_resource.content.content = catalog_resource.content.content.map((metaItem) => ({ + type: metaItem.type, + name: metaItem.name, + poster: metaItem.poster, + posterShape: metaItem.posterShape, + href: `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}` // TODO this should redirect with videoId at some cases + })); } - + catalog_resource.href = `#/discover/${encodeURIComponent(catalog_resource.request.base)}/${encodeURIComponent(catalog_resource.request.path.type_name)}/${encodeURIComponent(catalog_resource.request.path.id)}?${queryString}`; return catalog_resource; }); return { selected, catalog_resources }; @@ -56,7 +58,7 @@ const useSearch = (queryParams) => { return useModelState({ model: 'search', action: loadSearchAction, - mapWithCtx: mapSearchState, + mapWithCtx: mapSearchStateWithCtx, init: initSearchState }); }; From 376189086239dc464606f61bb19121c6e9794846 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 20:44:01 +0200 Subject: [PATCH 398/442] unload library if cannot be loaded --- src/routes/Library/useLibrary.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index db82cd4bf..4acaa6e78 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -76,6 +76,10 @@ const useLibrary = (urlParams, queryParams) => { } } }; + } else { + return { + action: 'Unload' + }; } } }, [urlParams, queryParams]); From bd754174d1fc3b352a8e2733e727bec4138ea8a1 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 20:47:41 +0200 Subject: [PATCH 399/442] Unload Discover if cannot be loaded --- src/routes/Discover/useDiscover.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 62e007992..08171bbd8 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -73,6 +73,10 @@ const useDiscover = (urlParams, queryParams) => { args: discover.selectable.types[0].load_request } }; + } else { + return { + action: 'Unload' + }; } } }, [urlParams, queryParams]); From 251b7e6f5ed3dbdeeb239f62ff88b34e4953578e Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 8 Dec 2019 20:54:41 +0200 Subject: [PATCH 400/442] discover map more explicit --- src/routes/Discover/useDiscover.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/routes/Discover/useDiscover.js b/src/routes/Discover/useDiscover.js index 08171bbd8..62ef18dbc 100644 --- a/src/routes/Discover/useDiscover.js +++ b/src/routes/Discover/useDiscover.js @@ -20,11 +20,21 @@ const mapDiscoverState = (discover) => { ...discover.catalog_resource, content: { ...discover.catalog_resource.content, - content: discover.catalog_resource.content.content.map((metaItem) => { - metaItem.released = new Date(metaItem.released); - metaItem.href = `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}`; - return metaItem; - }) + content: discover.catalog_resource.content.content.map((metaItem) => ({ + type: metaItem.type, + name: metaItem.name, + logo: metaItem.logo, + background: metaItem.background, + poster: metaItem.poster, + posterShape: metaItem.posterShape, + runtime: metaItem.runtime, + releaseInfo: metaItem.releaseInfo, + released: new Date(metaItem.released), + description: metaItem.description, + links: metaItem.links, + trailer: metaItem.trailer, + href: `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}` // TODO this should redirect with videoId at some cases + })) } } : From 4ac390eafb3f89779fd9b982def450815e211a2a Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 00:23:41 +0200 Subject: [PATCH 401/442] call onClick from metaItem when have to --- src/common/MetaItem/MetaItem.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/common/MetaItem/MetaItem.js b/src/common/MetaItem/MetaItem.js index 849b9b25c..5c130933a 100644 --- a/src/common/MetaItem/MetaItem.js +++ b/src/common/MetaItem/MetaItem.js @@ -20,10 +20,14 @@ const ICON_FOR_TYPE = new Map([ const MetaItem = React.memo(({ className, type, name, poster, posterShape, playIcon, progress, options, dataset, optionOnSelect, ...props }) => { const [menuOpen, onMenuOpen, onMenuClose] = useBinaryState(false); const metaItemOnClick = React.useCallback((event) => { + if (typeof props.onClick === 'function') { + props.onClick(event); + } + if (event.nativeEvent.selectPrevented) { event.preventDefault(); } - }, []); + }, [props.onClick]); const menuOnClick = React.useCallback((event) => { event.nativeEvent.selectPrevented = true; }, []); From 06e0e758da8796e8691353c26740ae4f7469384b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 00:23:57 +0200 Subject: [PATCH 402/442] metaitem props spread in Discover --- src/routes/Discover/Discover.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index fd3597dc8..736c0a1f4 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -89,9 +89,13 @@ const Discover = ({ urlParams, queryParams }) => {
{discover.catalog_resource.content.content.map((metaItem, index) => ( ))} From 77cae939a53a572e34ca2ab56bcc3b98b290bd17 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 09:09:35 +0200 Subject: [PATCH 403/442] selecting items ux in discover improved --- src/routes/Discover/Discover.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 736c0a1f4..e6f13aa9f 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -24,13 +24,17 @@ const Discover = ({ urlParams, queryParams }) => { const [selectedMetaItem, setSelectedMetaItem] = React.useState(() => { return getMetaItemAtIndex(discover.catalog_resource, 0); }); - const metaItemsOnMouseDownCapture = React.useCallback((event) => { - event.nativeEvent.buttonBlurPrevented = true; - }, []); const metaItemsOnFocusCapture = React.useCallback((event) => { const metaItem = getMetaItemAtIndex(discover.catalog_resource, event.target.dataset.index); setSelectedMetaItem(metaItem); }, [discover.catalog_resource]); + const metaItemOnClick = React.useCallback((event) => { + const metaItem = getMetaItemAtIndex(discover.catalog_resource, event.currentTarget.dataset.index); + if (metaItem !== selectedMetaItem) { + event.preventDefault(); + event.currentTarget.focus(); + } + }, [discover.catalog_resource, selectedMetaItem]); React.useLayoutEffect(() => { const metaItem = getMetaItemAtIndex(discover.catalog_resource, 0); setSelectedMetaItem(metaItem); @@ -86,7 +90,7 @@ const Discover = ({ urlParams, queryParams }) => { Loading
: -
+
{discover.catalog_resource.content.content.map((metaItem, index) => ( { posterShape={metaItem.posterShape} href={metaItem.href} data-index={index} + onClick={metaItemOnClick} /> ))}
From 2bfd7a3b5871ed96e21f97b1dc5dc7babe1b3a9c Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 09:15:49 +0200 Subject: [PATCH 404/442] spread only used props for --- src/routes/Discover/Discover.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index e6f13aa9f..0db14b05e 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -110,10 +110,16 @@ const Discover = ({ urlParams, queryParams }) => { { selectedMetaItem !== null ? :
From 5ad4f085fe4d260617a2dcfc18132b0aa46a6713 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 09:40:14 +0200 Subject: [PATCH 405/442] useMetaDetails hook implemented with useModelState --- src/routes/MetaDetails/useMetaDetails.js | 57 ++++++++++++------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/routes/MetaDetails/useMetaDetails.js b/src/routes/MetaDetails/useMetaDetails.js index 88869c769..8c4d9f8ae 100644 --- a/src/routes/MetaDetails/useMetaDetails.js +++ b/src/routes/MetaDetails/useMetaDetails.js @@ -1,44 +1,41 @@ const React = require('react'); -const { useServices } = require('stremio/services'); +const { useModelState } = require('stremio/common'); -const mapMetaDetailsState = (state) => { - const selected = state.meta_details.selected; - const meta_groups = state.meta_details.meta_groups.map((meta_group) => { - if (meta_group.content.type === 'Ready') { - meta_group.content.content.released = new Date(meta_group.content.content.released); - meta_group.content.content.videos = meta_group.content.content.videos.map((video) => { +const initMetaDetailsState = () => ({ + selected: { + meta_resource_ref: null, + streams_resource_ref: null, + }, + meta_resources: [], + streams_resources: [] +}); + +const mapMetaDetailsState = (meta_details) => { + const selected = meta_details.selected; + const meta_resources = meta_details.meta_resources.map((meta_resource) => { + if (meta_resource.content.type === 'Ready') { + meta_resource.content.content.released = new Date(meta_resource.content.content.released); + meta_resource.content.content.videos = meta_resource.content.content.videos.map((video) => { video.released = new Date(video.released); video.upcoming = !isNaN(video.released.getTime()) ? video.released.getTime() > Date.now() : false; - video.href = `#/metadetails/${meta_group.content.content.type}/${meta_group.content.content.id}/${video.id}`; + video.href = `#/metadetails/${meta_resource.content.content.type}/${meta_resource.content.content.id}/${video.id}`; // TODO add watched and progress return video; }); } - return meta_group; + return meta_resource; }); - const streams_groups = state.meta_details.streams_groups; - return { selected, meta_groups, streams_groups }; + const streams_resources = meta_details.streams_resources; + return { selected, meta_resources, streams_resources }; }; const useMetaDetails = (urlParams) => { - const { core } = useServices(); - const [metaDetails, setMetaDetails] = React.useState(() => { - const state = core.getState(); - const metaDetails = mapMetaDetailsState(state); - return metaDetails; - }); - React.useEffect(() => { - const onNewModel = () => { - const state = core.getState(); - const metaDetails = mapMetaDetailsState(state); - setMetaDetails(metaDetails); - }; - core.on('NewModel', onNewModel); - core.dispatch({ + const loadMetaDetailsAction = React.useMemo(() => { + return { action: 'Load', args: { load: 'MetaDetails', @@ -48,12 +45,14 @@ const useMetaDetails = (urlParams) => { video_id: urlParams.videoId } } - }); - return () => { - core.off('NewModel', onNewModel); }; }, [urlParams]); - return metaDetails; + return useModelState({ + model: 'meta_details', + action: loadMetaDetailsAction, + map: mapMetaDetailsState, + init: initMetaDetailsState + }); }; module.exports = useMetaDetails; From 5f1c776a2365a27d9ba59c7ecef8443c4cc93976 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 10:01:29 +0200 Subject: [PATCH 406/442] useSelectableResource hook replace useSelectableGroups --- src/routes/MetaDetails/useSelectableGroups.js | 95 ------------------- .../MetaDetails/useSelectableResource.js | 88 +++++++++++++++++ 2 files changed, 88 insertions(+), 95 deletions(-) delete mode 100644 src/routes/MetaDetails/useSelectableGroups.js create mode 100644 src/routes/MetaDetails/useSelectableResource.js diff --git a/src/routes/MetaDetails/useSelectableGroups.js b/src/routes/MetaDetails/useSelectableGroups.js deleted file mode 100644 index 1248beb8c..000000000 --- a/src/routes/MetaDetails/useSelectableGroups.js +++ /dev/null @@ -1,95 +0,0 @@ -const React = require('react'); -const isEqual = require('lodash.isequal'); - -const readyGroupForReq = (groups, req) => { - return groups.find((group) => { - return isEqual(group.req, req) && group.content.type === 'Ready'; - }); -}; - -const reducer = (state, action) => { - switch (action.type) { - case 'groups-changed': { - if (state.selected.group === null || - !state.selected.byUser || - !readyGroupForReq(action.groups, state.selected.group.req)) { - const firstReadyGroup = action.groups.find((group) => group.content.type === 'Ready'); - const selectedGroup = firstReadyGroup ? firstReadyGroup : null; - return { - ...state, - resourceRef: action.resourceRef, - groups: action.groups, - selected: { - group: selectedGroup, - byUser: false - } - }; - } - - return { - ...state, - resourceRef: action.resourceRef, - groups: action.groups - }; - } - case 'group-selected': { - const selectedGroup = readyGroupForReq(state.groups, action.req); - if (!selectedGroup) { - return state; - } - - return { - ...state, - selected: { - group: selectedGroup, - byUser: true - } - }; - } - default: { - return state; - } - } -}; - -const initializer = ([resourceRef, groups]) => { - const initialState = { - resourceRef: null, - groups: [], - selected: { - group: null, - byUser: false - } - }; - const initAction = { - type: 'groups-changed', - resourceRef, - groups - }; - - return reducer(initialState, initAction); -}; - -const useSelectableGroups = (resourceRef, groups) => { - const [state, dispatch] = React.useReducer( - reducer, - [resourceRef, groups], - initializer - ); - const selectGroup = React.useCallback((req) => { - dispatch({ - type: 'group-selected', - req - }); - }, []); - React.useEffect(() => { - dispatch({ - type: 'groups-changed', - resourceRef, - groups - }); - }, [groups]); - return [state.resourceRef, state.groups, state.selected.group, selectGroup]; -}; - -module.exports = useSelectableGroups; diff --git a/src/routes/MetaDetails/useSelectableResource.js b/src/routes/MetaDetails/useSelectableResource.js new file mode 100644 index 000000000..ac85d7f5a --- /dev/null +++ b/src/routes/MetaDetails/useSelectableResource.js @@ -0,0 +1,88 @@ +const React = require('react'); +const isEqual = require('lodash.isequal'); + +const readyResourceForRequest = (resources, request) => { + return resources.find((resource) => { + return isEqual(resource.request, request) && resource.content.type === 'Ready'; + }); +}; + +const reducer = (state, action) => { + switch (action.type) { + case 'resources-changed': { + if (state.selected.resource === null || + !state.selected.byUser || + !readyResourceForRequest(action.resources, state.selected.resource.request)) { + const firstReadyResource = action.resources.find((resource) => resource.content.type === 'Ready'); + const selectedResource = firstReadyResource ? firstReadyResource : null; + return { + ...state, + resourceRef: action.resourceRef, + resources: action.resources, + selected: { + resource: selectedResource, + byUser: false + } + }; + } + + return { + ...state, + resourceRef: action.resourceRef, + resources: action.resources + }; + } + case 'resource-selected': { + const selectedResource = readyResourceForRequest(state.resources, action.request); + if (!selectedResource) { + return state; + } + + return { + ...state, + selected: { + resource: selectedResource, + byUser: true + } + }; + } + default: { + return state; + } + } +}; + +const initializer = ([resourceRef, resources]) => { + const initialState = { + resourceRef: null, + resources: [], + selected: { + resource: null, + byUser: false + } + }; + const initAction = { + type: 'resources-changed', + resourceRef, + resources + }; + + return reducer(initialState, initAction); +}; + +const useSelectableResource = (resourceRef, resources) => { + const [state, dispatch] = React.useReducer( + reducer, + [resourceRef, resources], + initializer + ); + const selectResource = React.useCallback((request) => { + dispatch({ type: 'resource-selected', request }); + }, []); + React.useEffect(() => { + dispatch({ type: 'resources-changed', resourceRef, resources }); + }, [resources]); + return [state.resourceRef, state.resources, state.selected.resource, selectResource]; +}; + +module.exports = useSelectableResource; From 8272f252cb2f90c9b481aa7e1aa6788f042212ef Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 12:27:16 +0200 Subject: [PATCH 407/442] MetaDetails adapted to the new core api --- src/routes/MetaDetails/MetaDetails.js | 94 ++++++++++--------- .../MetaDetails/StreamsList/StreamsList.js | 34 ++++--- .../MetaDetails/VideosList/VideosList.js | 14 +-- 3 files changed, 78 insertions(+), 64 deletions(-) diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js index 925ecea2e..a19227a6c 100644 --- a/src/routes/MetaDetails/MetaDetails.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -3,82 +3,92 @@ const { NavBar, MetaPreview, useInLibrary } = require('stremio/common'); const VideosList = require('./VideosList'); const StreamsList = require('./StreamsList'); const useMetaDetails = require('./useMetaDetails'); -const useSelectableGroups = require('./useSelectableGroups'); +const useSelectableResource = require('./useSelectableResource'); const styles = require('./styles'); const MetaDetails = ({ urlParams }) => { const metaDetails = useMetaDetails(urlParams); - const [metaResourceRef, metaGroups, selectedMetaGroup] = useSelectableGroups(metaDetails.selected.meta_resource_ref, metaDetails.meta_groups); + const [metaResourceRef, metaResources, selectedMetaResource] = useSelectableResource(metaDetails.selected.meta_resource_ref, metaDetails.meta_resources); const streamsResourceRef = metaDetails.selected.streams_resource_ref; - const streamsGroups = metaDetails.streams_groups; - const [inLibrary, , , toggleInLibrary] = useInLibrary(metaResourceRef ? metaResourceRef.id : null); + const streamsResources = metaDetails.streams_resources; + const [inLibrary, , , toggleInLibrary] = useInLibrary(metaResourceRef !== null ? metaResourceRef.id : null); return (
{ - metaResourceRef !== null ? - selectedMetaGroup !== null ? - - { - typeof selectedMetaGroup.content.content.background === 'string' && - selectedMetaGroup.content.content.background.length > 0 ? -
- {' -
- : - null - } - -
+ metaResourceRef === null ? + + : + metaResources.length === 0 ? + : - metaGroups.length === 0 ? + metaResources.every((metaResource) => metaResource.content.type === 'Err') ? : - metaGroups.every((group) => group.content.type === 'Err') ? - + selectedMetaResource !== null ? + + { + typeof selectedMetaResource.content.content.background === 'string' && + selectedMetaResource.content.content.background.length > 0 ? +
+ {' +
+ : + null + } + +
: - : - null } { streamsResourceRef !== null ? : metaResourceRef !== null ? : null diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index 855615f3c..01163b29a 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -6,27 +6,31 @@ const { Button } = require('stremio/common'); const Stream = require('./Stream'); const styles = require('./styles'); -const StreamsList = ({ className, streamsGroups }) => { - const readyStreams = React.useMemo(() => { - return streamsGroups - .filter((stream) => stream.content.type === 'Ready') - .map((stream) => stream.content.content) +const StreamsList = ({ className, streamsResources }) => { + const streams = React.useMemo(() => { + return streamsResources + .filter((streamsResource) => streamsResource.content.type === 'Ready') + .map((streamsResource) => streamsResource.content.content) .flat(1); - }, [streamsGroups]); + }, [streamsResources]); return (
{ - readyStreams.length > 0 ? - readyStreams.map((stream, index) => ( - - )) + streamsResources.length === 0 ? +
No addons ware requested for streams
: - streamsGroups.length === 0 ? -
No addons ware requested for streams
+ streamsResources.every((streamsResource) => streamsResource.content.type === 'Err') ? +
No streams were found
: - streamsGroups.every((group) => group.content.type === 'Err') ? -
No streams were found
+ streams.length > 0 ? + streams.map((stream, index) => ( + + )) : @@ -44,7 +48,7 @@ const StreamsList = ({ className, streamsGroups }) => { StreamsList.propTypes = { className: PropTypes.string, - streamsGroups: PropTypes.arrayOf(PropTypes.object) + streamsResources: PropTypes.arrayOf(PropTypes.object) }; module.exports = StreamsList; diff --git a/src/routes/MetaDetails/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js index 32d6efbb0..d7e04b78a 100644 --- a/src/routes/MetaDetails/VideosList/VideosList.js +++ b/src/routes/MetaDetails/VideosList/VideosList.js @@ -6,13 +6,13 @@ const Video = require('./Video'); const useSelectableSeasons = require('./useSelectableSeasons'); const styles = require('./styles'); -const VideosList = ({ className, metaGroup }) => { +const VideosList = ({ className, metaResource }) => { const videos = React.useMemo(() => { - return metaGroup && metaGroup.content.type === 'Ready' ? - metaGroup.content.content.videos + return metaResource && metaResource.content.type === 'Ready' ? + metaResource.content.content.videos : []; - }, [metaGroup]); + }, [metaResource]); const [seasons, selectedSeason, videosForSeason, selectSeason] = useSelectableSeasons(videos); const seasonOnSelect = React.useCallback((event) => { selectSeason(event.value); @@ -20,7 +20,7 @@ const VideosList = ({ className, metaGroup }) => { return (
{ - !metaGroup || metaGroup.content.type === 'Loading' ? + !metaResource || metaResource.content.type === 'Loading' ?
@@ -32,7 +32,7 @@ const VideosList = ({ className, metaGroup }) => {
: - metaGroup.content.type === 'Err' || videosForSeason.length === 0 ? + metaResource.content.type === 'Err' || videosForSeason.length === 0 ?
No videos found for this meta
@@ -66,7 +66,7 @@ const VideosList = ({ className, metaGroup }) => { VideosList.propTypes = { className: PropTypes.string, - metaGroup: PropTypes.object + metaResource: PropTypes.object }; module.exports = VideosList; From eeb72f27603b028ba7c36d564ae7d477b432203f Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 13:15:47 +0200 Subject: [PATCH 408/442] routesRegexp spec uses jest methods --- tests/routesRegexp.spec.js | 32 ++++++++++++++++++++++++++ tests/routesRegexpTests.spec.js | 40 --------------------------------- 2 files changed, 32 insertions(+), 40 deletions(-) create mode 100644 tests/routesRegexp.spec.js delete mode 100644 tests/routesRegexpTests.spec.js diff --git a/tests/routesRegexp.spec.js b/tests/routesRegexp.spec.js new file mode 100644 index 000000000..ebf236a30 --- /dev/null +++ b/tests/routesRegexp.spec.js @@ -0,0 +1,32 @@ +const routesRegexp = require('../src/common/routesRegexp'); + +describe('routesRegexp', () => { + describe('intro route regexp', () => { + it('match /intro', async () => { + expect(Array.from('/intro'.match(routesRegexp.intro.regexp))) + .toEqual(['/intro']); + }); + + it('match /intro/', async () => { + expect(Array.from('/intro/'.match(routesRegexp.intro.regexp))) + .toEqual(['/intro/']); + }); + + it('not match /intro/$', async () => { + expect('/intro/$'.match(routesRegexp.intro.regexp)) + .toBe(null); + }); + }); + + describe('board route regexp', () => { + it('match /', async () => { + expect(Array.from('/'.match(routesRegexp.board.regexp))) + .toEqual(['/']); + }); + + it('not match /$', async () => { + expect('/$'.match(routesRegexp.board.regexp)) + .toBe(null); + }); + }); +}); diff --git a/tests/routesRegexpTests.spec.js b/tests/routesRegexpTests.spec.js deleted file mode 100644 index e9bb84050..000000000 --- a/tests/routesRegexpTests.spec.js +++ /dev/null @@ -1,40 +0,0 @@ -const routesRegexp = require('../src/common/routesRegexp'); - -const urlParamsMatch = (result, urlParams) => { - expect(Array.isArray(result)).toBe(true); - expect(result.length).toBe(urlParams.length); - urlParams.forEach((urlParam, index) => { - expect(result[index]).toBe(urlParam); - }); -}; - -describe('routes regex', () => { - describe('intro regexp', () => { - it('goes to /intro', async () => { - const result = '/intro'.match(routesRegexp.intro.regexp); - urlParamsMatch(result, ['/intro']); - }); - - it('goes to /intro/', async () => { - const result = '/intro/'.match(routesRegexp.intro.regexp); - urlParamsMatch(result, ['/intro/']); - }); - - it('goes to /intro/', async () => { - const result = '/intro/a'.match(routesRegexp.intro.regexp); - expect(result).toBe(null); - }); - }); - - describe('board regexp', () => { - it('goes to /', async () => { - const result = '/'.match(routesRegexp.board.regexp); - urlParamsMatch(result, ['/']); - }); - - it('goes to /', async () => { - const result = '/a'.match(routesRegexp.board.regexp); - expect(result).toBe(null); - }); - }); -}); From 62422efbf587aeff0826d89e9aea7f995d6323d0 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 13:32:03 +0200 Subject: [PATCH 409/442] use layout effects in Router --- src/router/Router/Router.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index 9e8e08fbe..1f3add2db 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -17,7 +17,7 @@ const Router = ({ className, onPathNotMatch, ...props }) => { const [views, setViews] = React.useState(() => { return Array(viewsConfig.length).fill(null); }); - React.useEffect(() => { + React.useLayoutEffect(() => { if (typeof homePath === 'string') { const { pathname, path } = UrlUtils.parse(window.location.hash.slice(1)); if (homePath !== path) { @@ -29,7 +29,7 @@ const Router = ({ className, onPathNotMatch, ...props }) => { } } }, []); - React.useEffect(() => { + React.useLayoutEffect(() => { const onLocationHashChange = () => { const { pathname, query } = UrlUtils.parse(window.location.hash.slice(1)); const queryParams = new URLSearchParams(typeof query === 'string' ? query : ''); From 069256a3657d5069ed5b65fdd09441828052d0a6 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 13:36:28 +0200 Subject: [PATCH 410/442] fix home path replace --- src/router/Router/Router.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index 1f3add2db..dd8321e70 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -22,7 +22,10 @@ const Router = ({ className, onPathNotMatch, ...props }) => { const { pathname, path } = UrlUtils.parse(window.location.hash.slice(1)); if (homePath !== path) { window.location.replace(`#${homePath}`); - const routeConfig = routeConfigForPath(viewsConfig, pathname); + const routeConfig = typeof pathname === 'string' ? + routeConfigForPath(viewsConfig, pathname) + : + null; if (routeConfig) { window.location = `#${path}`; } From ef98e252b62c1ae99208483a8ff860aeffc08ca5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 9 Dec 2019 14:00:18 +0200 Subject: [PATCH 411/442] trailing slash removed from route regexps --- src/common/routesRegexp.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index d3173b300..32ad25ec4 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -1,38 +1,38 @@ const routesRegexp = { intro: { - regexp: /^\/intro\/?$/i, + regexp: /^\/intro$/, urlParamsNames: [] }, board: { - regexp: /^\/?$/i, + regexp: /^\/$/, urlParamsNames: [] }, discover: { - regexp: /^\/discover(?:\/([^\/]*)\/([^\/]*)\/([^\/]*))?\/?$/i, + regexp: /^\/discover(?:\/([^\/]*)\/([^\/]*)\/([^\/]*))?$/, urlParamsNames: ['addonTransportUrl', 'type', 'catalogId'] }, library: { - regexp: /^\/library(?:\/([^\/]*))?\/?$/i, + regexp: /^\/library(?:\/([^\/]*))?$/, urlParamsNames: ['type'] }, search: { - regexp: /^\/search\/?$/i, + regexp: /^\/search$/, urlParamsNames: [] }, metadetails: { - regexp: /^\/metadetails\/(?:([^\/]*))\/(?:([^\/]*))(?:\/([^\/]*)\/?)?$/i, + regexp: /^\/metadetails\/([^\/]*)\/([^\/]*)(?:\/([^\/]*))?$/, urlParamsNames: ['type', 'id', 'videoId'] }, addons: { - regexp: /^\/addons(?:\/([^\/]*?))?(?:\/([^\/]*?))?\/?$/i, // TODO both are required or none + regexp: /^\/addons(?:\/([^\/]*)\/([^\/]*))?$/, urlParamsNames: ['category', 'type'] }, settings: { - regexp: /^\/settings\/?$/i, + regexp: /^\/settings$/, urlParamsNames: [] }, player: { - regexp: /^\/player\/(?:([^\/]+?))\/(?:([^\/]+?))\/(?:([^\/]+?))\/(?:([^\/]+?))\/?$/i, + regexp: /^\/player\/([^\/]*)\/([^\/]*)\/([^\/]*)\/([^\/]*)$/, urlParamsNames: ['type', 'id', 'videoId', 'stream'] } }; From 1c48552f3a421eca9b455cdfaed921daaf349cb7 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 10 Dec 2019 14:47:31 +0200 Subject: [PATCH 412/442] addons url changed --- src/common/routesRegexp.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index 32ad25ec4..df7f4e069 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -24,8 +24,8 @@ const routesRegexp = { urlParamsNames: ['type', 'id', 'videoId'] }, addons: { - regexp: /^\/addons(?:\/([^\/]*)\/([^\/]*))?$/, - urlParamsNames: ['category', 'type'] + regexp: /^\/addons(?:\/([^\/]*)\/([^\/]*)\/([^\/]*))?$/, + urlParamsNames: ['addonTransportUrl', 'catalogId', 'type'] }, settings: { regexp: /^\/settings$/, From b9f04a8637305b4fc406a85e1701c501c4c23f42 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 10 Dec 2019 14:48:19 +0200 Subject: [PATCH 413/442] useAddons implemented with useModelState --- src/routes/Addons/useAddons.js | 181 ++++++++++++--------------------- 1 file changed, 66 insertions(+), 115 deletions(-) diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index 154af9940..b29b23cd4 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -1,129 +1,80 @@ const React = require('react'); const { useServices } = require('stremio/services'); +const { useModelState } = require('stremio/common'); -const DEFAULT_TYPE = 'movie'; -const DEFAULT_CATEGORY = 'thirdparty'; +const initAddonsState = () => ({ + selectable: { + types: [], + catalogs: [], + extra: [], + has_next_page: false, + has_prev_page: false + }, + catalog_resource: null +}); -const useAddons = (urlParams, queryParams) => { - const { core } = useServices(); - const [addons, setAddons] = React.useState([[], [], [], [], null]); - const installAddon = React.useCallback(descriptor => { - core.dispatch({ - action: 'AddonOp', - args: { - addonOp: 'Install', - args: descriptor - } - }); - }, []); - const uninstallAddon = React.useCallback(descriptor => { - core.dispatch({ - action: 'AddonOp', - args: { - addonOp: 'Remove', - args: { - transport_url: descriptor.transportUrl - } - } - }); - }, []); - React.useEffect(() => { - const type = typeof urlParams.type === 'string' && urlParams.type.length > 0 ? urlParams.type : DEFAULT_TYPE; - const category = typeof urlParams.category === 'string' && urlParams.category.length > 0 ? urlParams.category : DEFAULT_CATEGORY; - const onNewState = () => { - const state = core.getState(); - [...new Set( - ['all'].concat(...state.ctx.content.addons.map(addon => addon.manifest.types)) - )] - .map((type) => ( - { - is_selected: urlParams.category === 'my' && urlParams.type === type, - name: 'my', - load: { - base: 'https://v3-cinemeta.strem.io/manifest.json', - path: { - resource: 'addon_catalog', - type_name: type, - id: 'my', - extra: [] - } - } - }) - ) - .forEach(addon => state.addons.catalogs.push(addon)); - const selectAddon = (transportUrl) => { - window.location = `#/addons/${category}/${type}?addon=${transportUrl}`; - }; - const selectInputs = [ - { - selected: state.addons.catalogs - .filter(({ is_selected }) => is_selected) - .map(({ load }) => load.path.id), - options: state.addons.catalogs - .filter((catalog, index, catalogs) => { - return catalogs.map(ctg => ctg.name).indexOf(catalog.name) === index; - }) - .map(({ name, load }) => ({ - value: load.path.id, - label: name - })), - onSelect: (event) => { - const load = state.addons.catalogs.find(({ load: { path: { id } } }) => { - return id === event.value; - }).load; - window.location = `#/addons/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; - } - }, - { - selected: state.addons.catalogs - .filter(({ is_selected }) => is_selected) - .map(({ load }) => JSON.stringify(load)), - options: state.addons.catalogs - .filter(({ load: { path: { id } } }) => { - return id === category; - }) - .map(({ load }) => ({ - value: JSON.stringify(load), - label: load.path.type_name - })), - onSelect: (event) => { - const load = JSON.parse(event.value); - window.location = `#/addons/${encodeURIComponent(load.path.id)}/${encodeURIComponent(load.path.type_name)}`; - } - } - ]; - const installedAddons = state.ctx.is_loaded ? state.ctx.content.addons : []; - const addonsItems = urlParams.category === 'my' ? - installedAddons.filter(addon => urlParams.type === 'all' || addon.manifest.types.includes(urlParams.type)) - : - state.addons.content.type === 'Ready' ? - state.addons.content.content - : - []; - const error = state.addons.content.type === 'Err' && !state.ctx.is_loaded ? state.addons.content.content : null; - setAddons([addonsItems, selectInputs, selectAddon, installedAddons, error]); - }; - core.on('NewModel', onNewState); - core.dispatch({ +const mapAddonsStateWithCtx = (addons, ctx) => { + const selectable = addons.selectable; + const catalog_resource = addons.catalog_resource; + // TODO add MY catalogId replace catalog content if resource catalog id is MY + return { selectable, catalog_resource }; +}; + +const onNewAddonsState = (addons) => { + if (addons.catalog_resource === null && addons.selectable.catalogs.length > 0) { + return { action: 'Load', args: { load: 'CatalogFiltered', + args: addons.selectable.catalogs[0].load_request + } + }; + } +}; + +const useAddons = (urlParams) => { + const { core } = useServices(); + const loadAddonsAction = React.useMemo(() => { + if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') { + return { + action: 'Load', args: { - base: 'https://v3-cinemeta.strem.io/manifest.json', - path: { - resource: 'addon_catalog', - type_name: type, - id: category, - extra: [] + load: 'CatalogFiltered', + args: { + base: urlParams.addonTransportUrl, + path: { + resource: 'addon_catalog', + type_name: urlParams.type, + id: urlParams.catalogId, + extra: [] + } } } + }; + } else { + const addons = core.getState('addons'); + if (addons.selectable.catalogs.length > 0) { + return { + action: 'Load', + args: { + load: 'CatalogFiltered', + args: addons.selectable.catalogs[0].load_request + } + }; + } else { + return { + action: 'Unload' + }; } - }); - return () => { - core.off('NewModel', onNewState); - }; - }, [urlParams, queryParams]); - return [addons, installAddon, uninstallAddon]; + } + }, [urlParams]); + return useModelState({ + model: 'addons', + action: loadAddonsAction, + mapWithCtx: mapAddonsStateWithCtx, + init: initAddonsState, + onNewState: onNewAddonsState + }); }; module.exports = useAddons; From e2961e50f43bdef7561f962879c1948bdefd34d1 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Tue, 10 Dec 2019 14:48:28 +0200 Subject: [PATCH 414/442] useSelectableInputs implemented for addons --- src/routes/Addons/useSelectableInputs.js | 72 ++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/routes/Addons/useSelectableInputs.js diff --git a/src/routes/Addons/useSelectableInputs.js b/src/routes/Addons/useSelectableInputs.js new file mode 100644 index 000000000..8376fa846 --- /dev/null +++ b/src/routes/Addons/useSelectableInputs.js @@ -0,0 +1,72 @@ +const React = require('react'); + +const navigateWithLoadRequest = (load_request) => { + const addonTransportUrl = encodeURIComponent(load_request.base); + const catalogId = encodeURIComponent(load_request.path.id); + const type = encodeURIComponent(load_request.path.type_name); + window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}`); +}; + +const equalWithouExtra = (request1, request2) => { + return request1.base === request2.base && + request1.path.resource === request2.path.resource && + request1.path.type_name === request2.path.type_name && + request1.path.id === request2.path.id; +}; + +const mapSelectableInputs = (addons) => { + const selectedCatalogRequest = addons.catalog_resource !== null ? + addons.catalog_resource.request + : + { + base: null, + path: { + resource: 'addon_catalog', + id: null, + type_name: null, + extra: [] + } + }; + const catalogSelect = { + title: 'Select catalog', + options: addons.selectable.catalogs + .map(({ name, load_request }) => ({ + value: JSON.stringify(load_request), + label: name + })), + selected: addons.selectable.catalogs + .filter(({ load_request: { path: { id } } }) => { + return id === selectedCatalogRequest.path.id; + }) + .map(({ load_request }) => JSON.stringify(load_request)), + onSelect: (event) => { + navigateWithLoadRequest(JSON.parse(event.value)); + } + }; + const typeSelect = { + title: 'Select type', + options: addons.selectable.types + .map(({ name, load_request }) => ({ + value: JSON.stringify(load_request), + label: name + })), + selected: addons.selectable.types + .filter(({ load_request }) => { + return equalWithouExtra(load_request, selectedCatalogRequest); + }) + .map(({ load_request }) => JSON.stringify(load_request)), + onSelect: (event) => { + navigateWithLoadRequest(JSON.parse(event.value)); + } + }; + return [catalogSelect, typeSelect]; +}; + +const useSelectableInputs = (addons) => { + const selectableInputs = React.useMemo(() => { + return mapSelectableInputs(addons); + }, [addons]); + return selectableInputs; +}; + +module.exports = useSelectableInputs; From eb815532295396f79dba55a3e82d96a6efe41e31 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Tue, 10 Dec 2019 18:55:48 +0200 Subject: [PATCH 415/442] eslint added --- .eslintrc.js | 85 +++++++++++++ package.json | 5 +- yarn.lock | 350 +++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 426 insertions(+), 14 deletions(-) create mode 100644 .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..f7747c8ab --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,85 @@ +module.exports = { + "extends": [ + "eslint:recommended", + "plugin:react/recommended" + ], + "rules": { + "arrow-parens": "error", + "arrow-spacing": "error", + "block-spacing": "error", + "comma-spacing": [ + "error", + { + "before": false, + "after": true + } + ], + "eol-last": [ + "error", + "always" + ], + "eqeqeq": [ + "error", + "always" + ], + "func-call-spacing": [ + "error", + "never" + ], + "indent": [ + "error", + 4, + { + "SwitchCase": 1 + } + ], + "no-console": [ + "error", + { + allow: ["error"] + } + ], + "no-extra-semi": "error", + "no-eq-null": "error", + "no-multi-spaces": "error", + "no-multiple-empty-lines": [ + "error", + { + "max": 2 + } + ], + "no-template-curly-in-string": "error", + "no-trailing-spaces": "error", + "no-useless-concat": "error", + "no-unreachable": "error", + "prefer-const": "error", + "quotes": [ + "warn", + "single" + ], + "semi": [ + "error", + "always" + ], + "semi-spacing": [ + "error", + { + "before": false, + "after": true + } + ], + "space-before-blocks": "error", + "valid-typeof": "error" + }, + "env": { + "node": true, + "browser": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 9, + "ecmaFeatures": { + "experimentalObjectRestSpread": true + } + } +} diff --git a/package.json b/package.json index da4427714..85d2ae48a 100755 --- a/package.json +++ b/package.json @@ -10,11 +10,14 @@ "start": "webpack-dev-server --mode development", "build": "webpack --mode production", "storybook": "start-storybook --ci --config-dir ./storybook --static-dir ./ --port 6060", - "test": "jest" + "test": "jest", + "lint": "eslint src" }, "dependencies": { "a-color-picker": "1.2.1", "classnames": "2.2.6", + "eslint": "^6.7.2", + "eslint-plugin-react": "^7.17.0", "events": "1.1.1", "hat": "0.0.3", "lodash.debounce": "4.0.8", diff --git a/yarn.lock b/yarn.lock index 31faaf37c..07e5dd3cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2046,6 +2046,11 @@ acorn-globals@^4.1.0: acorn "^6.0.1" acorn-walk "^6.0.1" +acorn-jsx@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384" + integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw== + acorn-walk@^6.0.1: version "6.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" @@ -2061,6 +2066,11 @@ acorn@^6.0.1, acorn@^6.2.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== +acorn@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" + integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== + address@1.1.2, address@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" @@ -2107,7 +2117,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5: version "6.10.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== @@ -2139,6 +2149,13 @@ ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== +ansi-escapes@^4.2.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d" + integrity sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg== + dependencies: + type-fest "^0.8.1" + ansi-html@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" @@ -2159,6 +2176,11 @@ ansi-regex@^4.0.0, ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -3167,7 +3189,7 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -3298,6 +3320,13 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + cli-table3@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" @@ -3711,7 +3740,7 @@ create-react-context@^0.3.0: gud "^1.0.0" warning "^4.0.3" -cross-spawn@6.0.5, cross-spawn@^6.0.0: +cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -3976,7 +4005,7 @@ debug@^3.0.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -4188,6 +4217,13 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -4369,6 +4405,11 @@ emoji-regex@^7.0.1: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -4501,6 +4542,27 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-plugin-eslint-plugin@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-2.1.0.tgz#a7a00f15a886957d855feacaafee264f039e62d5" + integrity sha512-kT3A/ZJftt28gbl/Cv04qezb/NQ1dwYIbi8lyf806XMxkus7DvOVCLIfTXMrorp322Pnoez7+zabXH29tADIDg== + +eslint-plugin-react@^7.17.0: + version "7.17.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.17.0.tgz#a31b3e134b76046abe3cd278e7482bd35a1d12d7" + integrity sha512-ODB7yg6lxhBVMeiH1c7E95FLD4E/TwmFjltiU+ethv7KPdCwgiFuOZg9zNRHyufStTDLl/dEFqI2Q1VPmCd78A== + dependencies: + array-includes "^3.0.3" + doctrine "^2.1.0" + eslint-plugin-eslint-plugin "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.2.3" + object.entries "^1.1.0" + object.fromentries "^2.0.1" + object.values "^1.1.0" + prop-types "^15.7.2" + resolve "^1.13.1" + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -4509,6 +4571,78 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.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" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^6.7.2: + version "6.7.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.7.2.tgz#c17707ca4ad7b2d8af986a33feba71e18a9fecd1" + integrity sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.3" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d" + integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA== + dependencies: + acorn "^7.1.0" + acorn-jsx "^5.1.0" + eslint-visitor-keys "^1.1.0" + esprima@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" @@ -4519,6 +4653,13 @@ esprima@^4.0.0, esprima@~4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== + dependencies: + estraverse "^4.0.0" + esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" @@ -4526,7 +4667,7 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -4808,6 +4949,20 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" +figures@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.1.0.tgz#4b198dd07d8d71530642864af2d45dd9e459c4ec" + integrity sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + file-loader@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" @@ -4908,6 +5063,20 @@ findup-sync@3.0.0: micromatch "^3.0.4" resolve-dir "^1.0.1" +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + flush-write-stream@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -5075,6 +5244,11 @@ function.prototype.name@^1.1.0: functions-have-names "^1.1.1" is-callable "^1.1.4" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + functions-have-names@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.0.tgz#83da7583e4ea0c9ac5ff530f73394b033e0bf77d" @@ -5141,6 +5315,13 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" + integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== + dependencies: + is-glob "^4.0.1" + glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" @@ -5207,6 +5388,13 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^12.1.0: + version "12.3.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13" + integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw== + dependencies: + type-fest "^0.8.1" + globalthis@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.0.tgz#c5fb98213a9b4595f59cf3e7074f141b4169daae" @@ -5661,6 +5849,11 @@ ignore@^3.3.5: resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + image-size@~0.5.0: version "0.5.5" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" @@ -5686,7 +5879,7 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" -import-fresh@^3.1.0: +import-fresh@^3.0.0, import-fresh@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== @@ -5795,6 +5988,25 @@ inquirer@^6.2.0: strip-ansi "^5.1.0" through "^2.3.6" +inquirer@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.0.tgz#9e2b032dde77da1db5db804758b8fea3a970519a" + integrity sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ== + dependencies: + ansi-escapes "^4.2.1" + chalk "^2.4.2" + cli-cursor "^3.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.15" + mute-stream "0.0.8" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^4.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" @@ -6012,6 +6224,11 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-function@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" @@ -6692,6 +6909,11 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -6745,6 +6967,14 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jsx-ast-utils@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz#8a9364e402448a3ce7f14d357738310d9248054f" + integrity sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA== + dependencies: + array-includes "^3.0.3" + object.assign "^4.1.0" + killable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" @@ -6856,7 +7086,7 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== -levn@~0.3.0: +levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= @@ -7199,7 +7429,7 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mimic-fn@^2.0.0: +mimic-fn@^2.0.0, mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== @@ -7390,6 +7620,11 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + nan@^2.12.1: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" @@ -7709,7 +7944,7 @@ object.entries@^1.1.0: function-bind "^1.1.1" has "^1.0.3" -"object.fromentries@^2.0.0 || ^1.0.0": +"object.fromentries@^2.0.0 || ^1.0.0", object.fromentries@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.1.tgz#050f077855c7af8ae6649f45c80b16ee2d31e704" integrity sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA== @@ -7775,6 +8010,13 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" +onetime@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" + integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== + dependencies: + mimic-fn "^2.1.0" + open@^6.1.0, open@^6.3.0: version "6.4.0" resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" @@ -7797,7 +8039,7 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.1: +optionator@^0.8.1, optionator@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -8638,6 +8880,11 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -9219,6 +9466,11 @@ regexp.prototype.flags@^1.2.0: dependencies: define-properties "^1.1.2" +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + regexpu-core@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" @@ -9381,7 +9633,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.3.2, resolve@^1.8.1: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2, resolve@^1.8.1: version "1.13.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16" integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w== @@ -9396,6 +9648,14 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -9416,6 +9676,13 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -9551,7 +9818,7 @@ selfsigned@^1.10.7: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -9755,6 +10022,15 @@ slash@^2.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -10077,6 +10353,15 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + "string.prototype.matchall@^4.0.0 || ^3.0.1": version "4.0.0" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.0.tgz#47191e37b67dca43131706bc9c4550df31b2c471" @@ -10157,6 +10442,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -10167,6 +10459,11 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -10245,6 +10542,16 @@ symbol.prototype.description@^1.0.0: es-abstract "^1.16.0" has-symbols "^1.0.0" +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + tapable@^1.0.0, tapable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" @@ -10332,7 +10639,7 @@ test-exclude@^5.2.3: read-pkg-up "^4.0.0" require-main-filename "^2.0.0" -text-table@0.2.0: +text-table@0.2.0, text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= @@ -10506,6 +10813,11 @@ type-fest@^0.3.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -10742,6 +11054,11 @@ v8-compile-cache@2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== +v8-compile-cache@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -11080,6 +11397,13 @@ write-file-atomic@2.4.1: imurmurhash "^0.1.4" signal-exit "^3.0.2" +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + ws@^5.2.0: version "5.2.2" resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" From 78f7d614e4154c83585b73b8bc6a1fe8f157a136 Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Wed, 11 Dec 2019 11:10:51 +0200 Subject: [PATCH 416/442] disable react/prop-types rule --- .eslintrc.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index f7747c8ab..1fd52540f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,11 +52,13 @@ module.exports = { "no-trailing-spaces": "error", "no-useless-concat": "error", "no-unreachable": "error", + "no-unused-vars": "error", "prefer-const": "error", "quotes": [ "warn", "single" ], + "react/prop-types": 0, "semi": [ "error", "always" From d5de64fc05743332351f933650397246fad256fa Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 12 Dec 2019 11:41:24 +0200 Subject: [PATCH 417/442] linter overrides added --- .eslintrc.js | 61 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1fd52540f..cf07f3159 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,6 +3,11 @@ module.exports = { "eslint:recommended", "plugin:react/recommended" ], + "globals": { + "YT": "readonly", + "FB": "readonly" + }, + "ignorePatterns": ["src/routes/Settings/**", "src/routes/Player/**", "src/video/**"], "rules": { "arrow-parens": "error", "arrow-spacing": "error", @@ -58,7 +63,6 @@ module.exports = { "warn", "single" ], - "react/prop-types": 0, "semi": [ "error", "always" @@ -71,7 +75,8 @@ module.exports = { } ], "space-before-blocks": "error", - "valid-typeof": "error" + "valid-typeof": "error", + "react/no-unescaped-entities": 0 }, "env": { "node": true, @@ -83,5 +88,55 @@ module.exports = { "ecmaFeatures": { "experimentalObjectRestSpread": true } - } + }, + "overrides": [ + { + "files": [ + "src/common/Button/Button.js", + "src/common/Checkbox/Checkbox.js", + "src/common/ColorInput/ColorInput.js", + "src/common/Image/Image.js", + "src/common/MetaItem/MetaItem.js", + "src/common/Multiselect/Multiselect.js", + "src/common/TextInput/TextInput.js", + "src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js", + "src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js", + "src/common/PaginationInput/PaginationInput.js" + ], + "rules": { + "react/prop-types": 0, + } + }, + { + "files": [ + "src/routes/Intro/Intro.js", + "src/routes/Addons/useAddons.js", + "src/routes/Board/useItemOptions.js", + "src/common/NavBar/NavMenu/NavMenu.js", + "src/routes/Library/useItemOptions.js", + "src/common/Multiselect/Multiselect.js", + "src/common/NavBar/NotificationsMenu/NotificationsMenu.js" + ], + "rules": { + "no-unused-vars": "off" + } + }, + { + "files": [ + "src/common/NavBar/NavMenu/NavMenu.js" + ], + "rules": { + "quotes": "off" + } + }, + { + "files": [ + "src/services/Shell/Shell.js", + "src/services/Core/Core.js" + ], + "rules": { + "prefer-const": "off" + } + } + ] } From 41415f895dc0ecadf31955c8770258a310b9bb7d Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Thu, 12 Dec 2019 11:43:32 +0200 Subject: [PATCH 418/442] fix files according to linter rules --- src/common/MainNavBar/MainNavBar.js | 2 ++ src/common/ModalDialog/index.js | 2 +- .../NotificationsList/Notification/Notification.js | 2 +- .../NotificationPlaceholder.js | 3 +-- .../NotificationsList/NotificationsList.js | 2 +- src/common/PaginationInput/index.js | 2 +- src/common/Popup/Popup.js | 2 +- src/common/routesRegexp.js | 10 +++++----- src/router/Router/Router.js | 2 +- src/routes/Addons/Addon/Addon.js | 3 +-- src/routes/Addons/Addons.js | 6 ++++++ src/routes/Board/Board.js | 9 ++++++--- src/routes/Discover/Discover.js | 6 ++++++ src/routes/Intro/Intro.js | 12 ++++++++++-- src/routes/Library/Library.js | 8 +++++++- src/routes/Library/useItemOptions.js | 2 +- src/routes/Library/useLibrary.js | 2 +- src/routes/MetaDetails/MetaDetails.js | 5 +++++ src/routes/MetaDetails/StreamsList/StreamsList.js | 2 +- src/routes/Search/Search.js | 7 ++++++- src/services/Core/Core.js | 2 +- .../KeyboardNavigation/KeyboardNavigation.js | 2 +- src/services/ServicesContext/index.js | 2 +- src/services/Shell/Shell.js | 2 +- 24 files changed, 68 insertions(+), 29 deletions(-) diff --git a/src/common/MainNavBar/MainNavBar.js b/src/common/MainNavBar/MainNavBar.js index c6920ce42..507f8d229 100644 --- a/src/common/MainNavBar/MainNavBar.js +++ b/src/common/MainNavBar/MainNavBar.js @@ -23,6 +23,8 @@ const MainNavBar = React.memo(({ className }) => { ); }); +MainNavBar.displayName = 'MainNavBar'; + MainNavBar.propTypes = { className: PropTypes.string }; diff --git a/src/common/ModalDialog/index.js b/src/common/ModalDialog/index.js index 7dadbbd9e..6717dbe87 100644 --- a/src/common/ModalDialog/index.js +++ b/src/common/ModalDialog/index.js @@ -1,3 +1,3 @@ const ModalDialog = require('./ModalDialog'); -module.exports = ModalDialog; \ No newline at end of file +module.exports = ModalDialog; diff --git a/src/common/NavBar/NotificationsMenu/NotificationsList/Notification/Notification.js b/src/common/NavBar/NotificationsMenu/NotificationsList/Notification/Notification.js index 53c7b0e81..8bba1d435 100644 --- a/src/common/NavBar/NotificationsMenu/NotificationsList/Notification/Notification.js +++ b/src/common/NavBar/NotificationsMenu/NotificationsList/Notification/Notification.js @@ -80,7 +80,7 @@ const Notification = ({ className, id, type, name, poster, thumbnail, season, ep } ); -} +}; Notification.propTypes = { className: PropTypes.string, diff --git a/src/common/NavBar/NotificationsMenu/NotificationsList/NotificationPlaceholder/NotificationPlaceholder.js b/src/common/NavBar/NotificationsMenu/NotificationsList/NotificationPlaceholder/NotificationPlaceholder.js index 3bbac1538..0ee602b64 100644 --- a/src/common/NavBar/NotificationsMenu/NotificationsList/NotificationPlaceholder/NotificationPlaceholder.js +++ b/src/common/NavBar/NotificationsMenu/NotificationsList/NotificationPlaceholder/NotificationPlaceholder.js @@ -1,7 +1,6 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const Icon = require('stremio-icons/dom'); const styles = require('./styles'); const NotificationPlaceholder = ({ className }) => { @@ -20,6 +19,6 @@ const NotificationPlaceholder = ({ className }) => { NotificationPlaceholder.propTypes = { className: PropTypes.string -} +}; module.exports = NotificationPlaceholder; diff --git a/src/common/NavBar/NotificationsMenu/NotificationsList/NotificationsList.js b/src/common/NavBar/NotificationsMenu/NotificationsList/NotificationsList.js index e54bacb68..3fca82728 100644 --- a/src/common/NavBar/NotificationsMenu/NotificationsList/NotificationsList.js +++ b/src/common/NavBar/NotificationsMenu/NotificationsList/NotificationsList.js @@ -57,7 +57,7 @@ const NotificationsList = ({ className, metaItems }) => { }
); -} +}; NotificationsList.propTypes = { className: PropTypes.string, diff --git a/src/common/PaginationInput/index.js b/src/common/PaginationInput/index.js index 99f9edf62..4500ec5a6 100644 --- a/src/common/PaginationInput/index.js +++ b/src/common/PaginationInput/index.js @@ -1,3 +1,3 @@ const PaginationInput = require('./PaginationInput'); -module.exports = PaginationInput; \ No newline at end of file +module.exports = PaginationInput; diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index d0b26fa03..b956f764f 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -96,7 +96,7 @@ const Popup = ({ open, direction, renderLabel, renderMenu, dataset, onCloseReque : null }); -} +}; Popup.propTypes = { open: PropTypes.bool, diff --git a/src/common/routesRegexp.js b/src/common/routesRegexp.js index df7f4e069..113497ec5 100644 --- a/src/common/routesRegexp.js +++ b/src/common/routesRegexp.js @@ -8,11 +8,11 @@ const routesRegexp = { urlParamsNames: [] }, discover: { - regexp: /^\/discover(?:\/([^\/]*)\/([^\/]*)\/([^\/]*))?$/, + regexp: /^\/discover(?:\/([^/]*)\/([^/]*)\/([^/]*))?$/, urlParamsNames: ['addonTransportUrl', 'type', 'catalogId'] }, library: { - regexp: /^\/library(?:\/([^\/]*))?$/, + regexp: /^\/library(?:\/([^/]*))?$/, urlParamsNames: ['type'] }, search: { @@ -20,11 +20,11 @@ const routesRegexp = { urlParamsNames: [] }, metadetails: { - regexp: /^\/metadetails\/([^\/]*)\/([^\/]*)(?:\/([^\/]*))?$/, + regexp: /^\/metadetails\/([^/]*)\/([^/]*)(?:\/([^/]*))?$/, urlParamsNames: ['type', 'id', 'videoId'] }, addons: { - regexp: /^\/addons(?:\/([^\/]*)\/([^\/]*)\/([^\/]*))?$/, + regexp: /^\/addons(?:\/([^/]*)\/([^/]*)\/([^/]*))?$/, urlParamsNames: ['addonTransportUrl', 'catalogId', 'type'] }, settings: { @@ -32,7 +32,7 @@ const routesRegexp = { urlParamsNames: [] }, player: { - regexp: /^\/player\/([^\/]*)\/([^\/]*)\/([^\/]*)\/([^\/]*)$/, + regexp: /^\/player\/([^/]*)\/([^/]*)\/([^/]*)\/([^/]*)$/, urlParamsNames: ['type', 'id', 'videoId', 'stream'] } }; diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index dd8321e70..60fc0334b 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -95,7 +95,7 @@ const Router = ({ className, onPathNotMatch, ...props }) => {
{ views - .filter(view => view !== null) + .filter((view) => view !== null) .map(({ key, component, urlParams, queryParams }, index, views) => ( diff --git a/src/routes/Addons/Addon/Addon.js b/src/routes/Addons/Addon/Addon.js index 023c17732..f26dbcf3b 100644 --- a/src/routes/Addons/Addon/Addon.js +++ b/src/routes/Addons/Addon/Addon.js @@ -5,7 +5,7 @@ const Icon = require('stremio-icons/dom'); const { Button } = require('stremio/common'); const styles = require('./styles'); -const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, toggle, onShareButtonClicked }) => { +const Addon = ({ className, id, name, logo, description, types, version, installed, toggle, onShareButtonClicked }) => { const onKeyUp = React.useCallback((event) => { if (event.key === 'Enter' && typeof toggle === 'function') { toggle(event); @@ -72,7 +72,6 @@ Addon.propTypes = { description: PropTypes.string, types: PropTypes.arrayOf(PropTypes.string), version: PropTypes.string, - transportUrl: PropTypes.string, installed: PropTypes.bool, toggle: PropTypes.func, onShareButtonClicked: PropTypes.func diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 0a8152a17..cd68402df 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const Icon = require('stremio-icons/dom'); const { Button, Multiselect, NavBar, TextInput, SharePrompt, ModalDialog } = require('stremio/common'); const Addon = require('./Addon'); @@ -163,4 +164,9 @@ const Addons = ({ urlParams, queryParams }) => { ); }; +Addons.propTypes = { + urlParams: PropTypes.instanceOf(URLSearchParams), + queryParams: PropTypes.instanceOf(URLSearchParams) +}; + module.exports = Addons; diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index 33b6638ae..47f293f45 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -32,7 +32,7 @@ const Board = () => { {board.catalog_resources.map((catalog_resource, index) => { const title = `${catalog_resource.addon_name} - ${catalog_resource.request.path.id} ${catalog_resource.request.path.type_name}`; switch (catalog_resource.content.type) { - case 'Ready': + case 'Ready': { return ( { limit={10} /> ); - case 'Err': + } + case 'Err': { const message = `Error(${catalog_resource.content.content.type})${typeof catalog_resource.content.content.content === 'string' ? ` - ${catalog_resource.content.content.content}` : ''}`; return ( { limit={10} /> ); - case 'Loading': + } + case 'Loading': { return ( { limit={10} /> ); + } } })}
diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 0db14b05e..72baa410b 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { Button, MainNavBar, MetaItem, MetaPreview, Multiselect, ModalDialog, PaginationInput, useBinaryState } = require('stremio/common'); @@ -135,4 +136,9 @@ const Discover = ({ urlParams, queryParams }) => { ); }; +Discover.propTypes = { + urlParams: PropTypes.instanceOf(URLSearchParams), + queryParams: PropTypes.instanceOf(URLSearchParams) +}; + module.exports = Discover; diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 6b05700ab..8f4959499 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const { useRouteFocused } = require('stremio-router'); @@ -73,14 +74,17 @@ const Intro = ({ queryParams }) => { React.useEffect(() => { const onEvent = ({ event, args }) => { switch (event) { - case 'CtxActionErr': + case 'CtxActionErr': { const [_action, error] = args; dispatch({ type: 'error', error: error.args.message }); - case 'CtxChanged': + break; + } + case 'CtxChanged': { const state = core.getState(); if (state.ctx.content.auth !== null) { window.location.replace('#/'); } + } } }; if (routeFocused) { @@ -343,4 +347,8 @@ const Intro = ({ queryParams }) => { ); }; +Intro.propTypes = { + queryParams: PropTypes.instanceOf(URLSearchParams) +}; + module.exports = Intro; diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 0f3013cfb..3de671136 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const classnames = require('classnames'); const { Button, Multiselect, MainNavBar, MetaItem } = require('stremio/common'); const useLibrary = require('./useLibrary'); @@ -67,6 +68,11 @@ const Library = ({ urlParams, queryParams }) => {
); -} +}; + +Library.propTypes = { + urlParams: PropTypes.instanceOf(URLSearchParams), + queryParams: PropTypes.instanceOf(URLSearchParams) +}; module.exports = Library; diff --git a/src/routes/Library/useItemOptions.js b/src/routes/Library/useItemOptions.js index 870c14936..37edcd1a1 100644 --- a/src/routes/Library/useItemOptions.js +++ b/src/routes/Library/useItemOptions.js @@ -10,7 +10,7 @@ const DISMISS_OPTION = { value: 'dismiss' }; -const onSelect = (event) => { +const onSelect = (_event) => { // TODO {{event.value}} {{event.dataset}} }; diff --git a/src/routes/Library/useLibrary.js b/src/routes/Library/useLibrary.js index 4acaa6e78..b2426e055 100644 --- a/src/routes/Library/useLibrary.js +++ b/src/routes/Library/useLibrary.js @@ -90,6 +90,6 @@ const useLibrary = (urlParams, queryParams) => { init: initLibraryState, onNewState: onNewLibraryState }); -} +}; module.exports = useLibrary; diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js index a19227a6c..16417e77a 100644 --- a/src/routes/MetaDetails/MetaDetails.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const { NavBar, MetaPreview, useInLibrary } = require('stremio/common'); const VideosList = require('./VideosList'); const StreamsList = require('./StreamsList'); @@ -98,4 +99,8 @@ const MetaDetails = ({ urlParams }) => { ); }; +MetaDetails.propTypes = { + urlParams: PropTypes.instanceOf(URLSearchParams) +}; + module.exports = MetaDetails; diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index 01163b29a..2e0f8de86 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -44,7 +44,7 @@ const StreamsList = ({ className, streamsResources }) => {
); -} +}; StreamsList.propTypes = { className: PropTypes.string, diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index f76ea5c05..a860bce47 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const Icon = require('stremio-icons/dom'); const { MainNavBar, MetaRow } = require('stremio/common'); const useSearch = require('./useSearch'); @@ -68,6 +69,10 @@ const Search = ({ queryParams }) => {
); -} +}; + +Search.propTypes = { + queryParams: PropTypes.instanceOf(URLSearchParams) +}; module.exports = Search; diff --git a/src/services/Core/Core.js b/src/services/Core/Core.js index dc0c48894..cbb741f3c 100644 --- a/src/services/Core/Core.js +++ b/src/services/Core/Core.js @@ -96,6 +96,6 @@ function Core() { this.getState = getState; Object.freeze(this); -}; +} module.exports = Core; diff --git a/src/services/KeyboardNavigation/KeyboardNavigation.js b/src/services/KeyboardNavigation/KeyboardNavigation.js index 4dc1586f5..bd46169d2 100644 --- a/src/services/KeyboardNavigation/KeyboardNavigation.js +++ b/src/services/KeyboardNavigation/KeyboardNavigation.js @@ -41,6 +41,6 @@ function KeyboardNavigation() { this.stop = stop; Object.freeze(this); -}; +} module.exports = KeyboardNavigation; diff --git a/src/services/ServicesContext/index.js b/src/services/ServicesContext/index.js index 95c276ac2..d61874550 100644 --- a/src/services/ServicesContext/index.js +++ b/src/services/ServicesContext/index.js @@ -4,4 +4,4 @@ const useServices = require('./useServices'); module.exports = { ServicesProvider, useServices -}; \ No newline at end of file +}; diff --git a/src/services/Shell/Shell.js b/src/services/Shell/Shell.js index efc3613ff..f1ae8bbb4 100644 --- a/src/services/Shell/Shell.js +++ b/src/services/Shell/Shell.js @@ -66,6 +66,6 @@ function Shell() { this.dispatch = dispatch; Object.freeze(this); -}; +} module.exports = Shell; From b2bfcee2f82b5b879a7267236faebf405d66998b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Thu, 12 Dec 2019 18:34:25 +0200 Subject: [PATCH 419/442] useInLibrary hook linked with the core --- src/common/useInLibrary.js | 64 +++++++++++++++++++++++---- src/routes/MetaDetails/MetaDetails.js | 15 ++++++- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/common/useInLibrary.js b/src/common/useInLibrary.js index 2f595ed15..f9de835c0 100644 --- a/src/common/useInLibrary.js +++ b/src/common/useInLibrary.js @@ -1,12 +1,60 @@ -const useBinaryState = require('stremio/common/useBinaryState'); +const React = require('react'); +const { useServices } = require('stremio/services'); +const useModelState = require('stremio/common/useModelState'); -const useInLibrary = (id) => { - const [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary] = useBinaryState(false); - if (typeof id === 'string') { - return [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary]; - } else { - return [false, null, null, null]; - } +const useInLibrary = (metaItem) => { + const { core } = useServices(); + const initLibraryItemsState = React.useCallback(() => { + return core.getState('library_items'); + }, []); + const libraryItems = useModelState({ + model: 'library_items', + init: initLibraryItemsState + }); + const addToLibrary = React.useCallback((metaItem) => { + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'AddToLibrary', + args: { + meta_item: metaItem, + now: new Date() + } + } + }); + }, []); + const removeFromLibrary = React.useCallback((id) => { + core.dispatch({ + action: 'UserOp', + args: { + userOp: 'RemoveFromLibrary', + args: { + id, + now: new Date() + } + } + }); + }, []); + const inLibrary = React.useMemo(() => { + return typeof metaItem === 'object' && metaItem !== null ? + libraryItems.ids.includes(metaItem.id) + : + false; + }, [metaItem, libraryItems]); + const toggleInLibrary = React.useMemo(() => { + if (typeof metaItem !== 'object' || metaItem === null) { + return null; + } + + return () => { + if (inLibrary) { + removeFromLibrary(metaItem.id); + } else { + addToLibrary(metaItem); + } + }; + }, [metaItem, inLibrary]); + return [inLibrary, toggleInLibrary]; }; module.exports = useInLibrary; diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js index a19227a6c..a800ea1a7 100644 --- a/src/routes/MetaDetails/MetaDetails.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -11,7 +11,20 @@ const MetaDetails = ({ urlParams }) => { const [metaResourceRef, metaResources, selectedMetaResource] = useSelectableResource(metaDetails.selected.meta_resource_ref, metaDetails.meta_resources); const streamsResourceRef = metaDetails.selected.streams_resource_ref; const streamsResources = metaDetails.streams_resources; - const [inLibrary, , , toggleInLibrary] = useInLibrary(metaResourceRef !== null ? metaResourceRef.id : null); + const metaItem = React.useMemo(() => { + return selectedMetaResource !== null ? + selectedMetaResource.content.content + : + metaResourceRef !== null ? + { + id: metaResourceRef.id, + type: metaResourceRef.type_name, + name: '' + } + : + null; + }, [metaResourceRef, selectedMetaResource]); + const [inLibrary, toggleInLibrary] = useInLibrary(metaItem); return (
Date: Fri, 13 Dec 2019 13:34:28 +0200 Subject: [PATCH 420/442] Addons screen ui adapted to changes in core --- src/routes/Addons/Addons.js | 254 +++++++++++------------ src/routes/Addons/styles.less | 65 +++--- src/routes/Addons/useAddons.js | 25 ++- src/routes/Addons/useSelectableInputs.js | 18 +- 4 files changed, 188 insertions(+), 174 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 0a8152a17..6e47ee363 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -1,49 +1,69 @@ const React = require('react'); const Icon = require('stremio-icons/dom'); -const { Button, Multiselect, NavBar, TextInput, SharePrompt, ModalDialog } = require('stremio/common'); +const { Button, Multiselect, NavBar, TextInput, SharePrompt, ModalDialog, useBinaryState } = require('stremio/common'); const Addon = require('./Addon'); -const AddonPrompt = require('./AddonPrompt'); const useAddons = require('./useAddons'); -const useSelectedAddon = require('./useSelectedAddon'); +const useSelectableInputs = require('./useSelectableInputs'); const styles = require('./styles'); const Addons = ({ urlParams, queryParams }) => { - const inputRef = React.useRef(null); - const [query, setQuery] = React.useState(''); - const queryOnChange = React.useCallback((event) => { - setQuery(event.currentTarget.value); - }, []); - const [[addons, dropdowns, setSelectedAddon, installedAddons, error], installSelectedAddon, uninstallSelectedAddon] = useAddons(urlParams, queryParams); - const [addAddonModalOpened, setAddAddonModalOpened] = React.useState(false); - const [selectedAddon, clearSelectedAddon] = useSelectedAddon(queryParams.get('addon')); - const [sharedAddon, setSharedAddon] = React.useState(null); - const onAddAddonButtonClicked = React.useCallback(() => { - setAddAddonModalOpened(true); - }, []); - const onAddButtonClicked = React.useCallback(() => { - if (inputRef.current.value.length > 0) { - setSelectedAddon(inputRef.current.value); - setAddAddonModalOpened(false); + const addons = useAddons(urlParams); + const selectInputs = useSelectableInputs(addons); + const [addAddonModalOpen, openAddAddonModal, closeAddAddonModal] = useBinaryState(false); + const addAddonUrlInputRef = React.useRef(null); + const addAddonOnSubmit = React.useCallback(() => { + if (addAddonUrlInputRef.current !== null) { + // TODO install addon } - }, [setSelectedAddon]); - const installedAddon = React.useCallback((currentAddon) => { - return installedAddons.some((installedAddon) => installedAddon.transportUrl === currentAddon.transportUrl); - }, [installedAddons]); - const toggleAddon = React.useCallback(() => { - installedAddon(selectedAddon) ? uninstallSelectedAddon(selectedAddon) : installSelectedAddon(selectedAddon); - clearSelectedAddon(); - }, [selectedAddon]); + }, []); + const addAddonModalButtons = React.useMemo(() => { + return [ + { + className: styles['cancel-button'], + label: 'Cancel', + props: { + onClick: closeAddAddonModal + } + }, + { + label: 'Add', + props: { + onClick: addAddonOnSubmit + } + } + ]; + }, []); + const [search, setSearch] = React.useState(''); + const searchInputOnChange = React.useCallback((event) => { + setSearch(event.currentTarget.value); + }, []); + const [sharedTransportUrl, setSharedTransportUrl] = React.useState(null); + const shareModalOnClose = React.useCallback(() => { + setSharedTransportUrl(null); + }, []); + const onAddonShare = React.useCallback((event) => { + setSharedTransportUrl(event.dataset.transportUrl); + }, []); + React.useLayoutEffect(() => { + closeAddAddonModal(null); + setSearch(''); + setSharedTransportUrl(null); + }, [urlParams, queryParams]); return (
-
- - {dropdowns.map((dropdown, index) => ( - + {selectInputs.map((selectInput, index) => ( + ))}
-
- { - error !== null ? + { + addons.selectable.catalogs.length === 0 && addons.catalog_resource === null ? +
+ No addons +
+ : + addons.catalog_resource === null ?
- {error.type}{error.type === 'Other' ? ` - ${error.content}` : null} + No select
: - Array.isArray(addons) ? - addons.filter((addon) => query.length === 0 || - ((typeof addon.manifest.name === 'string' && addon.manifest.name.toLowerCase().includes(query.toLowerCase())) || - (typeof addon.manifest.description === 'string' && addon.manifest.description.toLowerCase().includes(query.toLowerCase())) - )) - .map((addon, index) => ( - setSelectedAddon(addon.transportUrl)} - onShareButtonClicked={() => setSharedAddon(addon)} - /> - )) - : + addons.catalog_resource.content.type === 'Err' ?
- Loading + Addons could not be loaded
- } -
- { - addAddonModalOpened ? - setAddAddonModalOpened(false) - } - }, - { - label: 'Add', - props: { - title: 'Add', - onClick: onAddButtonClicked - } - } - ]} - onCloseRequest={() => setAddAddonModalOpened(false)} - > - - - : - null - } - { - selectedAddon !== null ? - - - - : - null - } - { - sharedAddon !== null ? - setSharedAddon(null)}> - setSharedAddon(null)} - /> - - : - null + : + addons.catalog_resource.content.type === 'Loading' ? +
+ Loading +
+ : +
+ { + addons.catalog_resource.content.content + .filter((addon) => { + return search.length === 0 || + ( + (typeof addon.manifest.name === 'string' && addon.manifest.name.toLowerCase().includes(search.toLowerCase())) || + (typeof addon.manifest.description === 'string' && addon.manifest.description.toLowerCase().includes(search.toLowerCase())) + ); + }) + .map((addon, index) => ( + + )) + } +
}
+ { + addAddonModalOpen ? + + + + : + null + } + { + typeof sharedTransportUrl === 'string' ? + + + + : + null + }
); }; diff --git a/src/routes/Addons/styles.less b/src/routes/Addons/styles.less index ff3b7f2c1..b17fbfd46 100644 --- a/src/routes/Addons/styles.less +++ b/src/routes/Addons/styles.less @@ -1,3 +1,7 @@ +:import('~stremio/common/Multiselect/styles.less') { + multiselect-menu-container: menu-container; +} + .addons-container { display: flex; flex-direction: column; @@ -16,11 +20,12 @@ display: flex; flex-direction: column; - .top-bar-container { + .selectable-inputs-container { flex: none; + align-self: stretch; display: flex; flex-direction: row; - margin: 2rem; + padding: 1.5rem; overflow: visible; .add-button-container { @@ -30,7 +35,7 @@ align-items: center; height: 3rem; max-width: 15rem; - margin-right: 1rem; + margin-right: 1.5rem; padding: 0 1rem; background-color: var(--color-signal5); @@ -40,8 +45,8 @@ .icon { flex: none; - width: 1.5rem; - height: 1.5rem; + width: 1.2rem; + height: 1.2rem; margin-right: 1rem; fill: var(--color-surfacelighter); } @@ -56,12 +61,17 @@ } } - .dropdown { + .select-input-container { flex-grow: 0; flex-shrink: 1; flex-basis: 15rem; height: 3rem; - margin-right: 1rem; + margin-right: 1.5rem; + + .multiselect-menu-container { + max-height: calc(3.2rem * 7); + overflow: auto; + } } .search-bar-container { @@ -72,7 +82,6 @@ flex-direction: row; align-items: center; height: 3rem; - margin-right: 1rem; padding: 0 1rem; background-color: var(--color-backgroundlighter); cursor: text; @@ -82,7 +91,7 @@ } .icon { - display: block; + flex: none; width: 1.2rem; height: 1.2rem; margin-right: 1rem; @@ -91,7 +100,6 @@ .search-input { flex: 1; - align-self: stretch; color: var(--color-surfacelighter); &::placeholder { @@ -103,32 +111,31 @@ } } - .addons-list-container { + .message-container { flex: 1; align-self: stretch; - padding: 0 2rem; + padding: 0 1.5rem; + font-size: 2rem; + color: var(--color-surfacelighter); + } + + .addons-container { + flex: 1; + align-self: stretch; + padding: 0 1.5rem; overflow-y: auto; .addon { - width: 100%; - margin-bottom: 2rem; - } - - .message-container { - padding: 0 2rem; - font-size: 2rem; - color: var(--color-surfacelighter); + margin-bottom: 1.5rem; } } } } -.add-addon-prompt-container { - .url-content { - flex: 1; - width: 100%; - padding: 0.5rem; - font-size: 0.9rem; +.add-addon-modal-container { + .addon-url-input { + width: 25rem; + padding: 0.5rem 1rem; color: var(--color-surfacedark); border: thin solid var(--color-surface); } @@ -138,8 +145,8 @@ } } -.addon-prompt-container { - .cancel-button { - background-color: var(--color-surfacedark); +.share-modal-container { + .share-prompt-container { + width: 25rem; } } \ No newline at end of file diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index b29b23cd4..aad7086bc 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -15,8 +15,29 @@ const initAddonsState = () => ({ const mapAddonsStateWithCtx = (addons, ctx) => { const selectable = addons.selectable; - const catalog_resource = addons.catalog_resource; - // TODO add MY catalogId replace catalog content if resource catalog id is MY + // TODO replace catalog content if resource catalog id is MY + const catalog_resource = addons.catalog_resource !== null && addons.catalog_resource.content.type === 'Ready' ? + { + ...addons.catalog_resource, + content: { + ...addons.catalog_resource.content, + content: addons.catalog_resource.content.content.map((descriptor) => ({ + transportUrl: descriptor.transportUrl, + installed: ctx.content.addons.some((addon) => addon.transportUrl === descriptor.transportUrl), + manifest: { + id: descriptor.manifest.id, + name: descriptor.manifest.name, + version: descriptor.manifest.version, + logo: descriptor.manifest.logo, + description: descriptor.manifest.description, + types: descriptor.manifest.types, + catalogs: descriptor.manifest.catalogs, + } + })) + } + } + : + addons.catalog_resource; return { selectable, catalog_resource }; }; diff --git a/src/routes/Addons/useSelectableInputs.js b/src/routes/Addons/useSelectableInputs.js index 8376fa846..1b1c4dd15 100644 --- a/src/routes/Addons/useSelectableInputs.js +++ b/src/routes/Addons/useSelectableInputs.js @@ -15,18 +15,6 @@ const equalWithouExtra = (request1, request2) => { }; const mapSelectableInputs = (addons) => { - const selectedCatalogRequest = addons.catalog_resource !== null ? - addons.catalog_resource.request - : - { - base: null, - path: { - resource: 'addon_catalog', - id: null, - type_name: null, - extra: [] - } - }; const catalogSelect = { title: 'Select catalog', options: addons.selectable.catalogs @@ -36,7 +24,8 @@ const mapSelectableInputs = (addons) => { })), selected: addons.selectable.catalogs .filter(({ load_request: { path: { id } } }) => { - return id === selectedCatalogRequest.path.id; + return addons.catalog_resource !== null && + addons.catalog_resource.request.path.id === id; }) .map(({ load_request }) => JSON.stringify(load_request)), onSelect: (event) => { @@ -52,7 +41,8 @@ const mapSelectableInputs = (addons) => { })), selected: addons.selectable.types .filter(({ load_request }) => { - return equalWithouExtra(load_request, selectedCatalogRequest); + return addons.catalog_resource !== null && + equalWithouExtra(addons.catalog_resource.request, load_request); }) .map(({ load_request }) => JSON.stringify(load_request)), onSelect: (event) => { From afc2355580e85866df0f299f0d5c42344a55c37a Mon Sep 17 00:00:00 2001 From: svetlagasheva Date: Fri, 13 Dec 2019 15:18:05 +0200 Subject: [PATCH 421/442] routes regexp tests added --- tests/routesRegexp.spec.js | 457 ++++++++++++++++++++++++++++++++++++- 1 file changed, 448 insertions(+), 9 deletions(-) diff --git a/tests/routesRegexp.spec.js b/tests/routesRegexp.spec.js index ebf236a30..2d688f82b 100644 --- a/tests/routesRegexp.spec.js +++ b/tests/routesRegexp.spec.js @@ -7,13 +7,8 @@ describe('routesRegexp', () => { .toEqual(['/intro']); }); - it('match /intro/', async () => { - expect(Array.from('/intro/'.match(routesRegexp.intro.regexp))) - .toEqual(['/intro/']); - }); - - it('not match /intro/$', async () => { - expect('/intro/$'.match(routesRegexp.intro.regexp)) + it('not match /intro/', async () => { + expect('/intro/'.match(routesRegexp.intro.regexp)) .toBe(null); }); }); @@ -24,8 +19,452 @@ describe('routesRegexp', () => { .toEqual(['/']); }); - it('not match /$', async () => { - expect('/$'.match(routesRegexp.board.regexp)) + it('not match /1', async () => { + expect('/1'.match(routesRegexp.board.regexp)) + .toBe(null); + }); + }); + + describe('discover route regexp', () => { + it('match /discover', async () => { + expect(Array.from('/discover'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover', undefined, undefined, undefined]); + }); + + it('match /discover///', async () => { + expect(Array.from('/discover///'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover///', '', '', '']); + }); + + it('match /discover/1//', async () => { + expect(Array.from('/discover/1//'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover/1//', '1', '', '']); + }); + + it('match /discover//2/', async () => { + expect(Array.from('/discover//2/'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover//2/', '', '2', '']); + }); + + it('match /discover///3', async () => { + expect(Array.from('/discover///3'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover///3', '', '', '3']); + }); + + it('match /discover/1/2/', async () => { + expect(Array.from('/discover/1/2/'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover/1/2/', '1', '2', '']); + }); + + it('match /discover/1//3', async () => { + expect(Array.from('/discover/1//3'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover/1//3', '1', '', '3']); + }); + + it('match /discover//2/3', async () => { + expect(Array.from('/discover//2/3'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover//2/3', '', '2', '3']); + }); + + it('match /discover/1/2/3', async () => { + expect(Array.from('/discover/1/2/3'.match(routesRegexp.discover.regexp))) + .toEqual(['/discover/1/2/3', '1', '2', '3']); + }); + + it('not match /discover/', async () => { + expect('/discover/'.match(routesRegexp.discover.regexp)) + .toBe(null); + }); + + it('not match /discover//', async () => { + expect('/discover//'.match(routesRegexp.discover.regexp)) + .toBe(null); + }); + + it('not match /discover////', async () => { + expect('/discover////'.match(routesRegexp.discover.regexp)) + .toBe(null); + }); + + it('not match /discover/1', async () => { + expect('/discover/1'.match(routesRegexp.discover.regexp)) + .toBe(null); + }); + + it('not match /discover/1/', async () => { + expect('/discover/1/'.match(routesRegexp.discover.regexp)) + .toBe(null); + }); + + it('not match /discover//2', async () => { + expect('/discover//2'.match(routesRegexp.discover.regexp)) + .toBe(null); + }); + + it('not match /discover/1/2', async () => { + expect('/discover/1/2'.match(routesRegexp.discover.regexp)) + .toBe(null); + }); + + it('not match /discover/1/2/3/', async () => { + expect('/discover/1/2/3/'.match(routesRegexp.discover.regexp)) + .toBe(null); + }); + }); + + //TODO library route regexp + + describe('search route regexp', () => { + it('match /search', async () => { + expect(Array.from('/search'.match(routesRegexp.search.regexp))) + .toEqual(['/search']); + }); + + it('not match /search/', async () => { + expect('/search/'.match(routesRegexp.search.regexp)) + .toBe(null); + }); + }); + + describe('metadetails route regexp', () => { + it('match /metadetails//', async () => { + expect(Array.from('/metadetails//'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails//', '', '', undefined]); + }); + + it('match /metadetails///', async () => { + expect(Array.from('/metadetails///'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails///', '', '', '']); + }); + + it('match /metadetails/1/', async () => { + expect(Array.from('/metadetails/1/'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails/1/', '1', '', undefined]); + }); + + it('match /metadetails/1//', async () => { + expect(Array.from('/metadetails/1//'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails/1//', '1', '', '']); + }); + + it('match /metadetails//2/', async () => { + expect(Array.from('/metadetails//2/'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails//2/', '', '2', '']); + }); + + it('match /metadetails///3', async () => { + expect(Array.from('/metadetails///3'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails///3', '', '', '3']); + }); + + it('match /metadetails/1/2', async () => { + expect(Array.from('/metadetails/1/2'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails/1/2', '1', '2', undefined]); + }); + + it('match /metadetails/1/2/', async () => { + expect(Array.from('/metadetails/1/2/'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails/1/2/', '1', '2', '']); + }); + + it('match /metadetails/1//3', async () => { + expect(Array.from('/metadetails/1//3'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails/1//3', '1', '', '3']); + }); + + it('match /metadetails//2/3', async () => { + expect(Array.from('/metadetails//2/3'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails//2/3', '', '2', '3']); + }); + + it('match /metadetails/1/2/3', async () => { + expect(Array.from('/metadetails/1/2/3'.match(routesRegexp.metadetails.regexp))) + .toEqual(['/metadetails/1/2/3', '1', '2', '3']); + }); + + it('not match /metadetails', async () => { + expect('/metadetails'.match(routesRegexp.metadetails.regexp)) + .toBe(null); + }); + + it('not match /metadetails/', async () => { + expect('/metadetails/'.match(routesRegexp.metadetails.regexp)) + .toBe(null); + }); + + it('not match /metadetails////', async () => { + expect('/metadetails////'.match(routesRegexp.metadetails.regexp)) + .toBe(null); + }); + + it('not match /metadetails/1', async () => { + expect('/metadetails/1'.match(routesRegexp.metadetails.regexp)) + .toBe(null); + }); + + it('not match /metadetails/1/2/3/', async () => { + expect('/metadetails/1/2/3/'.match(routesRegexp.metadetails.regexp)) + .toBe(null); + }); + }); + + describe('addons route regexp', () => { + it('match /addons', async () => { + expect(Array.from('/addons'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons', undefined, undefined, undefined]); + }); + + it('match /addons///', async () => { + expect(Array.from('/addons///'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons///', '', '', '']); + }); + + it('match /addons/1//', async () => { + expect(Array.from('/addons/1//'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons/1//', '1', '', '']); + }); + + it('match /addons//2/', async () => { + expect(Array.from('/addons//2/'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons//2/', '', '2', '']); + }); + + it('match /addons///3', async () => { + expect(Array.from('/addons///3'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons///3', '', '', '3']); + }); + + it('match /addons/1/2/', async () => { + expect(Array.from('/addons/1/2/'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons/1/2/', '1', '2', '']); + }); + + it('match /addons/1//3', async () => { + expect(Array.from('/addons/1//3'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons/1//3', '1', '', '3']); + }); + + it('match /addons//2/3', async () => { + expect(Array.from('/addons//2/3'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons//2/3', '', '2', '3']); + }); + + it('match /addons/1/2/3', async () => { + expect(Array.from('/addons/1/2/3'.match(routesRegexp.addons.regexp))) + .toEqual(['/addons/1/2/3', '1', '2', '3']); + }); + + it('not match /addons/', async () => { + expect('/addons/'.match(routesRegexp.addons.regexp)) + .toBe(null); + }); + + it('not match /addons//', async () => { + expect('/addons//'.match(routesRegexp.addons.regexp)) + .toBe(null); + }); + + it('not match /addons////', async () => { + expect('/addons////'.match(routesRegexp.addons.regexp)) + .toBe(null); + }); + + it('not match /addons/1', async () => { + expect('/addons/1'.match(routesRegexp.addons.regexp)) + .toBe(null); + }); + + it('not match /addons/1/', async () => { + expect('/addons/1/'.match(routesRegexp.addons.regexp)) + .toBe(null); + }); + + it('not match /addons//2', async () => { + expect('/addons//2'.match(routesRegexp.addons.regexp)) + .toBe(null); + }); + + it('not match /addons/1/2', async () => { + expect('/addons/1/2'.match(routesRegexp.addons.regexp)) + .toBe(null); + }); + + it('not match /addons/1/2/3/', async () => { + expect('/addons/1/2/3/'.match(routesRegexp.addons.regexp)) + .toBe(null); + }); + }); + + describe('settings route regexp', () => { + it('match /settings', async () => { + expect(Array.from('/settings'.match(routesRegexp.settings.regexp))) + .toEqual(['/settings']); + }); + + it('not match /settings/', async () => { + expect('/settings/'.match(routesRegexp.settings.regexp)) + .toBe(null); + }); + }); + + describe('player route regexp', () => { + it('match /player////', async () => { + expect(Array.from('/player////'.match(routesRegexp.player.regexp))) + .toEqual(['/player////', '', '', '', '']); + }); + + it('match /player/1///', async () => { + expect(Array.from('/player/1///'.match(routesRegexp.player.regexp))) + .toEqual(['/player/1///', '1', '', '', '']); + }); + + it('match /player//2//', async () => { + expect(Array.from('/player//2//'.match(routesRegexp.player.regexp))) + .toEqual(['/player//2//', '', '2', '', '']); + }); + + it('match /player///3/', async () => { + expect(Array.from('/player///3/'.match(routesRegexp.player.regexp))) + .toEqual(['/player///3/', '', '', '3', '']); + }); + + it('match /player////4', async () => { + expect(Array.from('/player////4'.match(routesRegexp.player.regexp))) + .toEqual(['/player////4', '', '', '', '4']); + }); + + it('match /player/1/2//', async () => { + expect(Array.from('/player/1/2//'.match(routesRegexp.player.regexp))) + .toEqual(['/player/1/2//', '1', '2', '', '']); + }); + + it('match /player/1//3/', async () => { + expect(Array.from('/player/1//3/'.match(routesRegexp.player.regexp))) + .toEqual(['/player/1//3/', '1', '', '3', '']); + }); + + it('match /player/1///4', async () => { + expect(Array.from('/player/1///4'.match(routesRegexp.player.regexp))) + .toEqual(['/player/1///4', '1', '', '', '4']); + }); + + it('match /player//2/3/', async () => { + expect(Array.from('/player//2/3/'.match(routesRegexp.player.regexp))) + .toEqual(['/player//2/3/', '', '2', '3', '']); + }); + + it('match /player//2//4', async () => { + expect(Array.from('/player//2//4'.match(routesRegexp.player.regexp))) + .toEqual(['/player//2//4', '', '2', '', '4']); + }); + + it('match /player///3/4', async () => { + expect(Array.from('/player///3/4'.match(routesRegexp.player.regexp))) + .toEqual(['/player///3/4', '', '', '3', '4']); + }); + + it('match /player/1/2/3/', async () => { + expect(Array.from('/player/1/2/3/'.match(routesRegexp.player.regexp))) + .toEqual(['/player/1/2/3/', '1', '2', '3', '']); + }); + + it('match /player/1/2//4', async () => { + expect(Array.from('/player/1/2//4'.match(routesRegexp.player.regexp))) + .toEqual(['/player/1/2//4', '1', '2', '', '4']); + }); + + it('match /player/1//3/4', async () => { + expect(Array.from('/player/1//3/4'.match(routesRegexp.player.regexp))) + .toEqual(['/player/1//3/4', '1', '', '3', '4']); + }); + + it('match /player//2/3/4', async () => { + expect(Array.from('/player//2/3/4'.match(routesRegexp.player.regexp))) + .toEqual(['/player//2/3/4', '', '2', '3', '4']); + }); + + it('match /player/1/2/3/4', async () => { + expect(Array.from('/player/1/2/3/4'.match(routesRegexp.player.regexp))) + .toEqual(['/player/1/2/3/4', '1', '2', '3', '4']); + }); + + it('not match /player', async () => { + expect('/player'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/', async () => { + expect('/player/'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player//', async () => { + expect('/player//'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player///', async () => { + expect('/player///'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/////', async () => { + expect('/player/////'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/1', async () => { + expect('/player/1'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/1/', async () => { + expect('/player/1/'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/1//', async () => { + expect('/player/1//'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player//2/', async () => { + expect('/player//2/'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player///3', async () => { + expect('/player///3'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player////4/', async () => { + expect('/player////4/'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/1/2', async () => { + expect('/player/1/2'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/1/2/', async () => { + expect('/player/1/2/'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/1//3', async () => { + expect('/player/1//3'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/1/2/3', async () => { + expect('/player/1/2/3'.match(routesRegexp.player.regexp)) + .toBe(null); + }); + + it('not match /player/1/2/3/4/', async () => { + expect('/player/1/2/3/4/'.match(routesRegexp.player.regexp)) .toBe(null); }); }); From 5939a98bc633ae062e9cc3f4ac8be4045531f03b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 13 Dec 2019 18:12:00 +0200 Subject: [PATCH 422/442] redirect to addon details on submit --- src/routes/Addons/Addons.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 6e47ee363..504145fcf 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -13,9 +13,17 @@ const Addons = ({ urlParams, queryParams }) => { const addAddonUrlInputRef = React.useRef(null); const addAddonOnSubmit = React.useCallback(() => { if (addAddonUrlInputRef.current !== null) { - // TODO install addon + const queryParams = new URLSearchParams([['addon', addAddonUrlInputRef.current.value]]); + if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') { + const addonTransportUrl = encodeURIComponent(urlParams.addonTransportUrl); + const catalogId = encodeURIComponent(urlParams.catalogId); + const type = encodeURIComponent(urlParams.type); + window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}?${queryParams}`); + } else { + window.location.replace(`#/addons?${queryParams}`); + } } - }, []); + }, [urlParams]); const addAddonModalButtons = React.useMemo(() => { return [ { @@ -32,7 +40,7 @@ const Addons = ({ urlParams, queryParams }) => { } } ]; - }, []); + }, [addAddonOnSubmit]); const [search, setSearch] = React.useState(''); const searchInputOnChange = React.useCallback((event) => { setSearch(event.currentTarget.value); From bd03788c3d96aaed9f3f78bc676893095c1b5e42 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 13 Dec 2019 18:14:30 +0200 Subject: [PATCH 423/442] navigate to addon details moved in a separate function --- src/routes/Addons/Addons.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 504145fcf..054fd5b57 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -7,23 +7,26 @@ const useSelectableInputs = require('./useSelectableInputs'); const styles = require('./styles'); const Addons = ({ urlParams, queryParams }) => { + const navigateToAddonDetails = React.useCallback((transportUrl) => { + const queryParams = new URLSearchParams([['addon', transportUrl]]); + if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') { + const addonTransportUrl = encodeURIComponent(urlParams.addonTransportUrl); + const catalogId = encodeURIComponent(urlParams.catalogId); + const type = encodeURIComponent(urlParams.type); + window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}?${queryParams}`); + } else { + window.location.replace(`#/addons?${queryParams}`); + } + }, [urlParams]); const addons = useAddons(urlParams); const selectInputs = useSelectableInputs(addons); const [addAddonModalOpen, openAddAddonModal, closeAddAddonModal] = useBinaryState(false); const addAddonUrlInputRef = React.useRef(null); const addAddonOnSubmit = React.useCallback(() => { if (addAddonUrlInputRef.current !== null) { - const queryParams = new URLSearchParams([['addon', addAddonUrlInputRef.current.value]]); - if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') { - const addonTransportUrl = encodeURIComponent(urlParams.addonTransportUrl); - const catalogId = encodeURIComponent(urlParams.catalogId); - const type = encodeURIComponent(urlParams.type); - window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}?${queryParams}`); - } else { - window.location.replace(`#/addons?${queryParams}`); - } + navigateToAddonDetails(addAddonUrlInputRef.current.value); } - }, [urlParams]); + }, [navigateToAddonDetails]); const addAddonModalButtons = React.useMemo(() => { return [ { From 160b8b4a5b1f9c0a5e511126015d48a8ce83a010 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 13 Dec 2019 18:16:41 +0200 Subject: [PATCH 424/442] onToggle cb added to Addon --- src/routes/Addons/Addons.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 054fd5b57..4dfaff765 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -55,6 +55,9 @@ const Addons = ({ urlParams, queryParams }) => { const onAddonShare = React.useCallback((event) => { setSharedTransportUrl(event.dataset.transportUrl); }, []); + const onAddonToggle = React.useCallback((event) => { + navigateToAddonDetails(event.dataset.transportUrl); + }, []); React.useLayoutEffect(() => { closeAddAddonModal(null); setSearch(''); @@ -128,8 +131,8 @@ const Addons = ({ urlParams, queryParams }) => { description={addon.manifest.description} types={addon.manifest.types} version={addon.manifest.version} - transportUrl={addon.transportUrl} onShare={onAddonShare} + onToggle={onAddonToggle} dataset={{ transportUrl: addon.transportUrl }} /> )) From 5282ad936799bc45aff763f2a0e1a720c42e3b03 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 13 Dec 2019 18:19:17 +0200 Subject: [PATCH 425/442] addons list ui fixed --- src/routes/Addons/Addons.js | 2 +- src/routes/Addons/styles.less | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 4dfaff765..c99f7bc30 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -111,7 +111,7 @@ const Addons = ({ urlParams, queryParams }) => { Loading
: -
+
{ addons.catalog_resource.content.content .filter((addon) => { diff --git a/src/routes/Addons/styles.less b/src/routes/Addons/styles.less index b17fbfd46..f7ef52dcd 100644 --- a/src/routes/Addons/styles.less +++ b/src/routes/Addons/styles.less @@ -119,7 +119,7 @@ color: var(--color-surfacelighter); } - .addons-container { + .addons-list-container { flex: 1; align-self: stretch; padding: 0 1.5rem; From 91c692a0c46e0eae0afa8633ce9555f5da863ed5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Fri, 13 Dec 2019 18:20:03 +0200 Subject: [PATCH 426/442] useSelectedAddon dropped --- src/routes/Addons/useSelectedAddon.js | 35 --------------------------- 1 file changed, 35 deletions(-) delete mode 100644 src/routes/Addons/useSelectedAddon.js diff --git a/src/routes/Addons/useSelectedAddon.js b/src/routes/Addons/useSelectedAddon.js deleted file mode 100644 index 5bffaec37..000000000 --- a/src/routes/Addons/useSelectedAddon.js +++ /dev/null @@ -1,35 +0,0 @@ -const React = require('react'); -const UrlUtils = require('url'); -const { routesRegexp, useLocationHash, useRouteActive } = require('stremio/common'); - -const useSelectedAddon = (transportUrl) => { - const [addon, setAddon] = React.useState(null); - const locationHash = useLocationHash(); - const active = useRouteActive(routesRegexp.addons.regexp); - React.useEffect(() => { - if (typeof transportUrl !== 'string') { - setAddon(null); - return; - } - - fetch(transportUrl) // TODO - .then((resp) => resp.json()) - .then((manifest) => setAddon({ manifest, transportUrl, flags: {} })); - }, [transportUrl]); - const clear = React.useCallback(() => { - if (active) { - const { pathname, search } = UrlUtils.parse(locationHash.slice(1)); - const queryParams = new URLSearchParams(search || ''); - queryParams.delete('addon'); - if ([...queryParams].length !== 0) { - window.location.replace(`#${pathname}?${queryParams.toString()}`); - } else { - window.location.replace(`#${pathname}`); - } - setAddon(null); - } - }, [active, locationHash]); - return [addon, clear, setAddon]; -}; - -module.exports = useSelectedAddon; From 3e1ab699f54b5d415932018af3afa07a1dcd9d9c Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Sun, 15 Dec 2019 01:38:16 +0200 Subject: [PATCH 427/442] Addon layout changed --- src/routes/Addons/Addon/Addon.js | 72 ++++++++++++++++++++--------- src/routes/Addons/Addon/styles.less | 25 +++------- src/routes/Addons/Addons.js | 57 ++++++++++++++--------- src/routes/Addons/useAddons.js | 3 +- 4 files changed, 93 insertions(+), 64 deletions(-) diff --git a/src/routes/Addons/Addon/Addon.js b/src/routes/Addons/Addon/Addon.js index 023c17732..d646ed2b9 100644 --- a/src/routes/Addons/Addon/Addon.js +++ b/src/routes/Addons/Addon/Addon.js @@ -2,24 +2,54 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); -const { Button } = require('stremio/common'); +const { Button, Image } = require('stremio/common'); const styles = require('./styles'); -const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, toggle, onShareButtonClicked }) => { - const onKeyUp = React.useCallback((event) => { - if (event.key === 'Enter' && typeof toggle === 'function') { - toggle(event); +const Addon = ({ className, id, name, version, logo, description, types, installed, onToggle, onShare, dataset }) => { + const toggleButtonOnClick = React.useCallback((event) => { + if (typeof onToggle === 'function') { + onToggle({ + type: 'toggle', + nativeEvent: event.nativeEvent, + reactEvent: event, + dataset: dataset + }); } - }, [toggle]); + }, [onToggle, dataset]); + const shareButtonOnClick = React.useCallback((event) => { + if (typeof onShare === 'function') { + onShare({ + type: 'share', + nativeEvent: event.nativeEvent, + reactEvent: event, + dataset: dataset + }); + } + }, [onShare, dataset]); + const onKeyDown = React.useCallback((event) => { + if (event.key === 'Enter' && typeof onToggle === 'function') { + onToggle({ + type: 'toggle', + nativeEvent: event.nativeEvent, + reactEvent: event, + dataset: dataset + }); + } + }, [onToggle, dataset]); + const renderLogoFallback = React.useMemo(() => () => { + return ( + + ); + }, []); return ( - - @@ -68,14 +98,14 @@ Addon.propTypes = { className: PropTypes.string, id: PropTypes.string, name: PropTypes.string, + version: PropTypes.string, logo: PropTypes.string, description: PropTypes.string, types: PropTypes.arrayOf(PropTypes.string), - version: PropTypes.string, - transportUrl: PropTypes.string, installed: PropTypes.bool, - toggle: PropTypes.func, - onShareButtonClicked: PropTypes.func + onToggle: PropTypes.func, + onShare: PropTypes.func, + dataset: PropTypes.objectOf(PropTypes.string) }; module.exports = Addon; diff --git a/src/routes/Addons/Addon/styles.less b/src/routes/Addons/Addon/styles.less index 2ae172544..e57eea428 100644 --- a/src/routes/Addons/Addon/styles.less +++ b/src/routes/Addons/Addon/styles.less @@ -1,7 +1,6 @@ .addon-container { display: flex; flex-direction: row; - flex-wrap: wrap; align-items: flex-start; padding: 1rem; background-color: var(--color-backgroundlighter); @@ -17,6 +16,7 @@ display: block; width: 100%; height: 100%; + padding: 0.5rem; object-fit: contain; object-position: center; } @@ -31,14 +31,13 @@ } .info-container { - flex-grow: 1000; + flex-grow: 1; flex-shrink: 1; flex-basis: 0; display: flex; flex-direction: row; flex-wrap: wrap; align-items: baseline; - min-width: 40rem; padding: 0 0.5rem; .name-container { @@ -47,7 +46,7 @@ flex-basis: auto; padding: 0 0.5rem; max-height: 3.6em; - font-size: 1.5rem; + font-size: 1.6rem; color: var(--color-surfacelighter); } @@ -55,6 +54,7 @@ flex-grow: 1; flex-shrink: 1; flex-basis: auto; + margin-top: 0.5rem; padding: 0 0.5rem; max-height: 2.4em; color: var(--color-surfacelight); @@ -83,22 +83,14 @@ } .buttons-container { - flex-grow: 1; - flex-shrink: 0; - flex-basis: 0; - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-items: flex-end; - min-width: 17rem; + flex: none; + width: 17rem; .install-button-container, .uninstall-button-container, .share-button-container { - flex: none; display: flex; flex-direction: row; align-items: center; justify-content: center; - width: 17rem; height: 3.5rem; padding: 0 1rem; @@ -106,13 +98,8 @@ margin-top: 1rem; } - &:not(:last-child) { - margin-right: 1rem; - } - .icon { flex: none; - display: block; width: 1.5rem; height: 1.5rem; margin-right: 1rem; diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index c99f7bc30..083c16747 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -6,27 +6,32 @@ const useAddons = require('./useAddons'); const useSelectableInputs = require('./useSelectableInputs'); const styles = require('./styles'); +const navigateToAddonDetails = (addonsCatalogRequest, transportUrl) => { + const queryParams = new URLSearchParams([['addon', transportUrl]]); + if (addonsCatalogRequest !== null) { + const addonTransportUrl = encodeURIComponent(addonsCatalogRequest.base); + const catalogId = encodeURIComponent(addonsCatalogRequest.path.id); + const type = encodeURIComponent(addonsCatalogRequest.path.type_name); + window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}?${queryParams}`); + } else { + window.location.replace(`#/addons?${queryParams}`); + } +}; + const Addons = ({ urlParams, queryParams }) => { - const navigateToAddonDetails = React.useCallback((transportUrl) => { - const queryParams = new URLSearchParams([['addon', transportUrl]]); - if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') { - const addonTransportUrl = encodeURIComponent(urlParams.addonTransportUrl); - const catalogId = encodeURIComponent(urlParams.catalogId); - const type = encodeURIComponent(urlParams.type); - window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}?${queryParams}`); - } else { - window.location.replace(`#/addons?${queryParams}`); - } - }, [urlParams]); const addons = useAddons(urlParams); const selectInputs = useSelectableInputs(addons); const [addAddonModalOpen, openAddAddonModal, closeAddAddonModal] = useBinaryState(false); const addAddonUrlInputRef = React.useRef(null); const addAddonOnSubmit = React.useCallback(() => { if (addAddonUrlInputRef.current !== null) { - navigateToAddonDetails(addAddonUrlInputRef.current.value); + const addonsCatalogRequest = addons.catalog_resource !== null ? + addons.catalog_resource.request + : + null; + navigateToAddonDetails(addonsCatalogRequest, addAddonUrlInputRef.current.value); } - }, [navigateToAddonDetails]); + }, [addons]); const addAddonModalButtons = React.useMemo(() => { return [ { @@ -49,19 +54,23 @@ const Addons = ({ urlParams, queryParams }) => { setSearch(event.currentTarget.value); }, []); const [sharedTransportUrl, setSharedTransportUrl] = React.useState(null); - const shareModalOnClose = React.useCallback(() => { + const clearSharedTransportUrl = React.useCallback(() => { setSharedTransportUrl(null); }, []); const onAddonShare = React.useCallback((event) => { setSharedTransportUrl(event.dataset.transportUrl); }, []); const onAddonToggle = React.useCallback((event) => { - navigateToAddonDetails(event.dataset.transportUrl); - }, []); + const addonsCatalogRequest = addons.catalog_resource !== null ? + addons.catalog_resource.request + : + null; + navigateToAddonDetails(addonsCatalogRequest, event.dataset.transportUrl); + }, [addons]); React.useLayoutEffect(() => { - closeAddAddonModal(null); + closeAddAddonModal(); setSearch(''); - setSharedTransportUrl(null); + clearSharedTransportUrl(); }, [urlParams, queryParams]); return (
@@ -127,12 +136,13 @@ const Addons = ({ urlParams, queryParams }) => { className={styles['addon']} id={addon.manifest.id} name={addon.manifest.name} + version={addon.manifest.version} logo={addon.manifest.logo} description={addon.manifest.description} types={addon.manifest.types} - version={addon.manifest.version} - onShare={onAddonShare} + installed={addon.installed} onToggle={onAddonToggle} + onShare={onAddonShare} dataset={{ transportUrl: addon.transportUrl }} /> )) @@ -163,8 +173,11 @@ const Addons = ({ urlParams, queryParams }) => { - + onCloseRequest={clearSharedTransportUrl}> + : null diff --git a/src/routes/Addons/useAddons.js b/src/routes/Addons/useAddons.js index aad7086bc..57be65b45 100644 --- a/src/routes/Addons/useAddons.js +++ b/src/routes/Addons/useAddons.js @@ -30,8 +30,7 @@ const mapAddonsStateWithCtx = (addons, ctx) => { version: descriptor.manifest.version, logo: descriptor.manifest.logo, description: descriptor.manifest.description, - types: descriptor.manifest.types, - catalogs: descriptor.manifest.catalogs, + types: descriptor.manifest.types } })) } From d78f2f66964780cfdb83afdc3baaf1d5c8b3ccba Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 16 Dec 2019 11:22:55 +0200 Subject: [PATCH 428/442] useAddonDetails hook implemented --- src/routes/Addons/useAddonDetails.js | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/routes/Addons/useAddonDetails.js diff --git a/src/routes/Addons/useAddonDetails.js b/src/routes/Addons/useAddonDetails.js new file mode 100644 index 000000000..afa45eceb --- /dev/null +++ b/src/routes/Addons/useAddonDetails.js @@ -0,0 +1,48 @@ +const React = require('react'); +const { useModelState } = require('stremio/common'); + +const initAddonDetailsState = () => ({ + descriptor: null +}); + +const mapAddonDetailsStateWithCtx = (addonDetails, ctx) => { + const descriptor = addonDetails.descriptor !== null && addonDetails.descriptor.content.type === 'Ready' ? + { + ...addonDetails.descriptor, + content: { + ...addonDetails.descriptor.content, + installed: ctx.content.addons.some((addon) => addon.transportUrl === addonDetails.descriptor.transport_url), + } + } + : + addonDetails.descriptor; + return { descriptor }; +}; + +const useAddonDetails = (queryParams) => { + const loadAddonDetailsAction = React.useMemo(() => { + if (queryParams.has('addon')) { + return { + action: 'Load', + args: { + load: 'AddonDetails', + args: { + transport_url: queryParams.get('addon') + } + } + }; + } else { + return { + action: 'Unload' + }; + } + }, [queryParams]); + return useModelState({ + model: 'addon_details', + action: loadAddonDetailsAction, + mapWithCtx: mapAddonDetailsStateWithCtx, + init: initAddonDetailsState, + }); +}; + +module.exports = useAddonDetails; From 7eccd100ab3f069eec89febcba590be0e04d8d2b Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 16 Dec 2019 11:40:27 +0200 Subject: [PATCH 429/442] urlParams proptypes fixed --- src/routes/Addons/Addons.js | 6 +++++- src/routes/Discover/Discover.js | 6 +++++- src/routes/Library/Library.js | 4 +++- src/routes/MetaDetails/MetaDetails.js | 6 +++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js index 5362c92e3..3f7874666 100644 --- a/src/routes/Addons/Addons.js +++ b/src/routes/Addons/Addons.js @@ -188,7 +188,11 @@ const Addons = ({ urlParams, queryParams }) => { }; Addons.propTypes = { - urlParams: PropTypes.instanceOf(URLSearchParams), + urlParams: PropTypes.exact({ + addonTransportUrl: PropTypes.string, + catalogId: PropTypes.string, + type: PropTypes.string + }), queryParams: PropTypes.instanceOf(URLSearchParams) }; diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 72baa410b..4f8358b32 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -137,7 +137,11 @@ const Discover = ({ urlParams, queryParams }) => { }; Discover.propTypes = { - urlParams: PropTypes.instanceOf(URLSearchParams), + urlParams: PropTypes.exact({ + addonTransportUrl: PropTypes.string, + type: PropTypes.string, + catalogId: PropTypes.string + }), queryParams: PropTypes.instanceOf(URLSearchParams) }; diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 3de671136..d3c081646 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -71,7 +71,9 @@ const Library = ({ urlParams, queryParams }) => { }; Library.propTypes = { - urlParams: PropTypes.instanceOf(URLSearchParams), + urlParams: PropTypes.exact({ + type: PropTypes.string, + }), queryParams: PropTypes.instanceOf(URLSearchParams) }; diff --git a/src/routes/MetaDetails/MetaDetails.js b/src/routes/MetaDetails/MetaDetails.js index 42221f5a8..3cd804345 100644 --- a/src/routes/MetaDetails/MetaDetails.js +++ b/src/routes/MetaDetails/MetaDetails.js @@ -113,7 +113,11 @@ const MetaDetails = ({ urlParams }) => { }; MetaDetails.propTypes = { - urlParams: PropTypes.instanceOf(URLSearchParams) + urlParams: PropTypes.exact({ + type: PropTypes.string, + id: PropTypes.string, + videoId: PropTypes.string + }) }; module.exports = MetaDetails; From 6a07be3504959cbcbe67a1f8b189f04d22832b14 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 16 Dec 2019 12:01:19 +0200 Subject: [PATCH 430/442] eslint moved to dev deps --- package.json | 4 ++-- yarn.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 85d2ae48a..9c26d2763 100755 --- a/package.json +++ b/package.json @@ -16,8 +16,6 @@ "dependencies": { "a-color-picker": "1.2.1", "classnames": "2.2.6", - "eslint": "^6.7.2", - "eslint-plugin-react": "^7.17.0", "events": "1.1.1", "hat": "0.0.3", "lodash.debounce": "4.0.8", @@ -50,6 +48,8 @@ "css-loader": "3.2.1", "cssnano": "4.1.10", "cssnano-preset-advanced": "4.0.7", + "eslint": "6.7.2", + "eslint-plugin-react": "7.17.0", "html-webpack-plugin": "3.2.0", "jest": "24.9.0", "less": "3.10.3", diff --git a/yarn.lock b/yarn.lock index 07e5dd3cf..11542419f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4547,7 +4547,7 @@ eslint-plugin-eslint-plugin@^2.1.0: resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-2.1.0.tgz#a7a00f15a886957d855feacaafee264f039e62d5" integrity sha512-kT3A/ZJftt28gbl/Cv04qezb/NQ1dwYIbi8lyf806XMxkus7DvOVCLIfTXMrorp322Pnoez7+zabXH29tADIDg== -eslint-plugin-react@^7.17.0: +eslint-plugin-react@7.17.0: version "7.17.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.17.0.tgz#a31b3e134b76046abe3cd278e7482bd35a1d12d7" integrity sha512-ODB7yg6lxhBVMeiH1c7E95FLD4E/TwmFjltiU+ethv7KPdCwgiFuOZg9zNRHyufStTDLl/dEFqI2Q1VPmCd78A== @@ -4591,7 +4591,7 @@ eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@^6.7.2: +eslint@6.7.2: version "6.7.2" resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.7.2.tgz#c17707ca4ad7b2d8af986a33feba71e18a9fecd1" integrity sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng== From 1b5eb1244240bea171d553d03d915ddad7c7a4cf Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 16 Dec 2019 12:07:42 +0200 Subject: [PATCH 431/442] use eslintrc file --- .eslintrc.js => .eslintrc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) rename .eslintrc.js => .eslintrc (93%) diff --git a/.eslintrc.js b/.eslintrc similarity index 93% rename from .eslintrc.js rename to .eslintrc index cf07f3159..97c755374 100644 --- a/.eslintrc.js +++ b/.eslintrc @@ -1,4 +1,4 @@ -module.exports = { +{ "extends": [ "eslint:recommended", "plugin:react/recommended" @@ -7,7 +7,11 @@ module.exports = { "YT": "readonly", "FB": "readonly" }, - "ignorePatterns": ["src/routes/Settings/**", "src/routes/Player/**", "src/video/**"], + "ignorePatterns": [ + "src/routes/Settings/**", + "src/routes/Player/**", + "src/video/**" + ], "rules": { "arrow-parens": "error", "arrow-spacing": "error", @@ -41,7 +45,9 @@ module.exports = { "no-console": [ "error", { - allow: ["error"] + "allow": [ + "error" + ] } ], "no-extra-semi": "error", @@ -104,7 +110,7 @@ module.exports = { "src/common/PaginationInput/PaginationInput.js" ], "rules": { - "react/prop-types": 0, + "react/prop-types": 0 } }, { @@ -139,4 +145,4 @@ module.exports = { } } ] -} +} \ No newline at end of file From 8917c88f1cb141129706416d80abcf0bf8ed63d5 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 16 Dec 2019 12:09:00 +0200 Subject: [PATCH 432/442] eslint detect react version --- .eslintrc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.eslintrc b/.eslintrc index 97c755374..60e232c22 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,6 +3,11 @@ "eslint:recommended", "plugin:react/recommended" ], + "settings": { + "react": { + "version": "detect" + } + }, "globals": { "YT": "readonly", "FB": "readonly" From fba4e9f18faef08eda24edde9efb1240ca1e5703 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 16 Dec 2019 13:06:43 +0200 Subject: [PATCH 433/442] eslint config updated --- .eslintrc | 78 +++++++++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/.eslintrc b/.eslintrc index 60e232c22..a9ac04609 100644 --- a/.eslintrc +++ b/.eslintrc @@ -12,6 +12,17 @@ "YT": "readonly", "FB": "readonly" }, + "env": { + "commonjs": true, + "browser": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 9, + "ecmaFeatures": { + "jsx": true + } + }, "ignorePatterns": [ "src/routes/Settings/**", "src/routes/Player/**", @@ -21,25 +32,10 @@ "arrow-parens": "error", "arrow-spacing": "error", "block-spacing": "error", - "comma-spacing": [ - "error", - { - "before": false, - "after": true - } - ], - "eol-last": [ - "error", - "always" - ], - "eqeqeq": [ - "error", - "always" - ], - "func-call-spacing": [ - "error", - "never" - ], + "comma-spacing": "error", + "eol-last": "error", + "eqeqeq": "error", + "func-call-spacing": "error", "indent": [ "error", 4, @@ -47,21 +43,14 @@ "SwitchCase": 1 } ], - "no-console": [ - "error", - { - "allow": [ - "error" - ] - } - ], + "no-console": "error", "no-extra-semi": "error", "no-eq-null": "error", "no-multi-spaces": "error", "no-multiple-empty-lines": [ "error", { - "max": 2 + "max": 1 } ], "no-template-curly-in-string": "error", @@ -71,34 +60,25 @@ "no-unused-vars": "error", "prefer-const": "error", "quotes": [ - "warn", + "error", "single" ], - "semi": [ - "error", - "always" - ], - "semi-spacing": [ + "quote-props": [ "error", + "as-needed", { - "before": false, - "after": true + "unnecessary": false } ], + "semi": "error", + "semi-spacing": "error", "space-before-blocks": "error", - "valid-typeof": "error", - "react/no-unescaped-entities": 0 - }, - "env": { - "node": true, - "browser": true, - "es6": true - }, - "parserOptions": { - "ecmaVersion": 9, - "ecmaFeatures": { - "experimentalObjectRestSpread": true - } + "valid-typeof": [ + "error", + { + "requireStringLiterals": true + } + ] }, "overrides": [ { From 5a84605c1522b5b2b7bd31befc1286c924b9a06a Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Mon, 16 Dec 2019 13:07:11 +0200 Subject: [PATCH 434/442] console.error removed from intro --- src/routes/Intro/Intro.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 8f4959499..984b29369 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -117,9 +117,7 @@ const Intro = ({ queryParams }) => { } }); }) - .catch((err) => { - console.error(err); - }); + .catch((err) => { }); } }); }, [state.email, state.password]); @@ -260,7 +258,7 @@ const Intro = ({ queryParams }) => {
Continue with Facebook
-
We won't post anything on your behalf
+
We won't post anything on your behalf
Date: Mon, 16 Dec 2019 14:59:18 +0200 Subject: [PATCH 435/442] eslint react/prop-types enabled for all --- .eslintrc | 17 ----------------- src/common/Button/Button.js | 10 ++++++++++ src/common/Checkbox/Checkbox.js | 7 +++++++ src/common/ColorInput/ColorInput.js | 9 +++++---- src/common/Image/Image.js | 3 ++- src/common/MetaItem/MetaItem.js | 5 +++-- src/common/MetaPreview/MetaPreview.js | 4 ++-- src/common/ModalDialog/ModalDialog.js | 2 +- src/common/Multiselect/Multiselect.js | 5 +++-- src/common/PaginationInput/PaginationInput.js | 1 + src/common/Popup/Popup.js | 2 +- src/common/TextInput/TextInput.js | 8 ++++++++ .../Intro/ConsentCheckbox/ConsentCheckbox.js | 15 ++++++++++----- .../CredentialsTextInput.js | 5 +++++ src/routes/Intro/Intro.js | 6 +++--- .../VideosList/SeasonsBar/SeasonsBar.js | 8 +++----- .../MetaDetails/VideosList/Video/Video.js | 3 ++- 17 files changed, 66 insertions(+), 44 deletions(-) diff --git a/.eslintrc b/.eslintrc index a9ac04609..81b685301 100644 --- a/.eslintrc +++ b/.eslintrc @@ -81,23 +81,6 @@ ] }, "overrides": [ - { - "files": [ - "src/common/Button/Button.js", - "src/common/Checkbox/Checkbox.js", - "src/common/ColorInput/ColorInput.js", - "src/common/Image/Image.js", - "src/common/MetaItem/MetaItem.js", - "src/common/Multiselect/Multiselect.js", - "src/common/TextInput/TextInput.js", - "src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js", - "src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js", - "src/common/PaginationInput/PaginationInput.js" - ], - "rules": { - "react/prop-types": 0 - } - }, { "files": [ "src/routes/Intro/Intro.js", diff --git a/src/common/Button/Button.js b/src/common/Button/Button.js index 21512b041..89d7d342d 100644 --- a/src/common/Button/Button.js +++ b/src/common/Button/Button.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const classnames = require('classnames'); const styles = require('./styles'); @@ -41,4 +42,13 @@ const Button = React.forwardRef(({ className, href, disabled, children, ...props Button.displayName = 'Button'; +Button.propTypes = { + className: PropTypes.string, + href: PropTypes.string, + disabled: PropTypes.bool, + children: PropTypes.node, + onKeyDown: PropTypes.func, + onMouseDown: PropTypes.func +}; + module.exports = Button; diff --git a/src/common/Checkbox/Checkbox.js b/src/common/Checkbox/Checkbox.js index 96c29f334..6fd3f3a72 100644 --- a/src/common/Checkbox/Checkbox.js +++ b/src/common/Checkbox/Checkbox.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const classnames = require('classnames'); const Icon = require('stremio-icons/dom'); const Button = require('stremio/common/Button'); @@ -22,4 +23,10 @@ const Checkbox = React.forwardRef(({ className, checked, children, ...props }, r Checkbox.displayName = 'Checkbox'; +Checkbox.propTypes = { + className: PropTypes.string, + checked: PropTypes.bool, + children: PropTypes.node +}; + module.exports = Checkbox; diff --git a/src/common/ColorInput/ColorInput.js b/src/common/ColorInput/ColorInput.js index f493a11f1..7e846a4a8 100644 --- a/src/common/ColorInput/ColorInput.js +++ b/src/common/ColorInput/ColorInput.js @@ -16,9 +16,8 @@ const ColorInput = ({ className, value, dataset, onChange, ...props }) => { return parseColor(value); }); const labelButtonStyle = React.useMemo(() => ({ - ...props.style, backgroundColor: value - }), [props.style, value]); + }), [value]); const labelButtonOnClick = React.useCallback((event) => { if (typeof props.onClick === 'function') { props.onClick(event); @@ -76,9 +75,11 @@ const ColorInput = ({ className, value, dataset, onChange, ...props }) => { }; ColorInput.propTypes = { + className: PropTypes.string, value: PropTypes.string, - dataset: PropTypes.objectOf(String), - onChange: PropTypes.func + dataset: PropTypes.objectOf(PropTypes.string), + onChange: PropTypes.func, + onClick: PropTypes.func }; module.exports = ColorInput; diff --git a/src/common/Image/Image.js b/src/common/Image/Image.js index 520fade03..8091c2615 100644 --- a/src/common/Image/Image.js +++ b/src/common/Image/Image.js @@ -27,7 +27,8 @@ Image.propTypes = { src: PropTypes.string, alt: PropTypes.string, fallbackSrc: PropTypes.string, - renderFallback: PropTypes.func + renderFallback: PropTypes.func, + onError: PropTypes.func }; module.exports = Image; diff --git a/src/common/MetaItem/MetaItem.js b/src/common/MetaItem/MetaItem.js index 5c130933a..4d4f6cb1f 100644 --- a/src/common/MetaItem/MetaItem.js +++ b/src/common/MetaItem/MetaItem.js @@ -121,8 +121,9 @@ MetaItem.propTypes = { playIcon: PropTypes.bool, progress: PropTypes.number, options: PropTypes.array, - dataset: PropTypes.objectOf(String), - optionOnSelect: PropTypes.func + dataset: PropTypes.objectOf(PropTypes.string), + optionOnSelect: PropTypes.func, + onClick: PropTypes.func }; module.exports = MetaItem; diff --git a/src/common/MetaPreview/MetaPreview.js b/src/common/MetaPreview/MetaPreview.js index 9cd1b7d8e..0aca83e9a 100644 --- a/src/common/MetaPreview/MetaPreview.js +++ b/src/common/MetaPreview/MetaPreview.js @@ -179,7 +179,7 @@ const MetaPreview = ({ className, compact, name, logo, background, runtime, rele null } { - linksGroups.hasOwnProperty(IMDB_LINK_CATEGORY) ? + typeof linksGroups[IMDB_LINK_CATEGORY] === 'object' ? { PaginationInput.propTypes = { className: PropTypes.string, label: PropTypes.string, + dataset: PropTypes.objectOf(PropTypes.string), onSelect: PropTypes.func }; diff --git a/src/common/Popup/Popup.js b/src/common/Popup/Popup.js index b956f764f..59b89f26e 100644 --- a/src/common/Popup/Popup.js +++ b/src/common/Popup/Popup.js @@ -103,7 +103,7 @@ Popup.propTypes = { direction: PropTypes.oneOf(['top-left', 'bottom-left', 'top-right', 'bottom-right']), renderLabel: PropTypes.func.isRequired, renderMenu: PropTypes.func.isRequired, - dataset: PropTypes.objectOf(String), + dataset: PropTypes.objectOf(PropTypes.string), onCloseRequest: PropTypes.func }; diff --git a/src/common/TextInput/TextInput.js b/src/common/TextInput/TextInput.js index 4f7db50f1..8b9606d6f 100644 --- a/src/common/TextInput/TextInput.js +++ b/src/common/TextInput/TextInput.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const classnames = require('classnames'); const styles = require('./styles'); @@ -30,4 +31,11 @@ const TextInput = React.forwardRef((props, ref) => { TextInput.displayName = 'TextInput'; +TextInput.propTypes = { + className: PropTypes.string, + disabled: PropTypes.bool, + onKeyDown: PropTypes.func, + onSubmit: PropTypes.func +}; + module.exports = TextInput; diff --git a/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js b/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js index fe1898b4e..df05b7e60 100644 --- a/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js +++ b/src/routes/Intro/ConsentCheckbox/ConsentCheckbox.js @@ -4,16 +4,20 @@ const classnames = require('classnames'); const { Button, Checkbox } = require('stremio/common'); const styles = require('./styles'); -const ConsentCheckbox = React.forwardRef(({ className, checked, label, link, href, toggle, ...props }, ref) => { +const ConsentCheckbox = React.forwardRef(({ className, checked, label, link, href, onToggle, ...props }, ref) => { const checkboxOnClick = React.useCallback((event) => { if (typeof props.onClick === 'function') { props.onClick(event); } - if (!event.nativeEvent.togglePrevented && typeof toggle === 'function') { - toggle(event); + if (!event.nativeEvent.togglePrevented && typeof onToggle === 'function') { + onToggle({ + type: 'toggle', + reactEvent: event, + nativeEvent: event.nativeEvent + }); } - }, [toggle]); + }, [onToggle]); const linkOnClick = React.useCallback((event) => { event.nativeEvent.togglePrevented = true; }, []); @@ -42,7 +46,8 @@ ConsentCheckbox.propTypes = { label: PropTypes.string, link: PropTypes.string, href: PropTypes.string, - toggle: PropTypes.func + onToggle: PropTypes.func, + onClick: PropTypes.func }; module.exports = ConsentCheckbox; diff --git a/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js b/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js index d3c7696cf..43a2bb087 100644 --- a/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js +++ b/src/routes/Intro/CredentialsTextInput/CredentialsTextInput.js @@ -1,4 +1,5 @@ const React = require('react'); +const PropTypes = require('prop-types'); const { TextInput } = require('stremio/common'); const CredentialsTextInput = React.forwardRef((props, ref) => { @@ -23,4 +24,8 @@ const CredentialsTextInput = React.forwardRef((props, ref) => { CredentialsTextInput.displayName = 'CredentialsTextInput'; +CredentialsTextInput.propTypes = { + onKeyDown: PropTypes.func +}; + module.exports = CredentialsTextInput; diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index 984b29369..dc26b97e7 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -296,7 +296,7 @@ const Intro = ({ queryParams }) => { link={'Terms and conditions'} href={'https://www.stremio.com/tos'} checked={state.termsAccepted} - toggle={toggleTermsAccepted} + onToggle={toggleTermsAccepted} /> { link={'Privacy Policy'} href={'https://www.stremio.com/privacy'} checked={state.privacyPolicyAccepted} - toggle={togglePrivacyPolicyAccepted} + onToggle={togglePrivacyPolicyAccepted} /> : diff --git a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js index cfe24abe3..d830d710d 100644 --- a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js @@ -16,11 +16,9 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { const selected = React.useMemo(() => { return [String(season)]; }, [season]); - const renderMultiselectLabelContent = React.useMemo(() => { - return () => ( -
Season {season}
- ); - }, [season]); + const renderMultiselectLabelContent = React.useMemo(() => () => ( +
Season {season}
+ ), [season]); const prevNextButtonOnClick = React.useCallback((event) => { if (typeof onSelect === 'function') { const seasonIndex = seasons.indexOf(season); diff --git a/src/routes/MetaDetails/VideosList/Video/Video.js b/src/routes/MetaDetails/VideosList/Video/Video.js index 2bcd22f27..4b13e30e6 100644 --- a/src/routes/MetaDetails/VideosList/Video/Video.js +++ b/src/routes/MetaDetails/VideosList/Video/Video.js @@ -6,7 +6,7 @@ const Icon = require('stremio-icons/dom'); const VideoPlaceholder = require('./VideoPlaceholder'); const styles = require('./styles'); -const Video = ({ className, title, thumbnail, episode, released, upcoming, watched, progress, ...props }) => { +const Video = ({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, ...props }) => { return (