diff --git a/package.json b/package.json index d2f4b81e8..03b12da14 100755 --- a/package.json +++ b/package.json @@ -20,10 +20,11 @@ "prop-types": "15.7.2", "react": "16.9.0", "react-dom": "16.9.0", + "react-focus-lock": "2.1.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", - "stremio-icons": "git+ssh://git@github.com/Stremio/stremio-icons.git#v1.0.11", "stremio-core-web": "git+ssh://git@github.com/stremio/stremio-core-web.git#v0.6.0", + "stremio-icons": "git+ssh://git@github.com/Stremio/stremio-icons.git#v1.0.11", "vtt.js": "0.13.0" }, "devDependencies": { @@ -54,4 +55,4 @@ "webpack-cli": "3.3.9", "webpack-dev-server": "3.8.1" } -} \ No newline at end of file +} diff --git a/src/router/FocusableContext/FocusableContext.js b/src/router/FocusableContext/FocusableContext.js deleted file mode 100644 index 5fbec1a1f..000000000 --- a/src/router/FocusableContext/FocusableContext.js +++ /dev/null @@ -1,7 +0,0 @@ -const React = require('react'); - -const FocusableContext = React.createContext(false); - -FocusableContext.displayName = 'FocusableContext'; - -module.exports = FocusableContext; diff --git a/src/router/FocusableContext/FocusableProvider.js b/src/router/FocusableContext/FocusableProvider.js deleted file mode 100644 index 3bf6bafab..000000000 --- a/src/router/FocusableContext/FocusableProvider.js +++ /dev/null @@ -1,57 +0,0 @@ -const React = require('react'); -const PropTypes = require('prop-types'); -const { useModalsContainer } = require('../ModalsContainerContext'); -const { useRoutesContainer } = require('../RoutesContainerContext'); -const FocusableContext = require('./FocusableContext'); - -const FocusableProvider = ({ children, onRoutesContainerChildrenChange, onModalsContainerChildrenChange }) => { - const routesContainer = useRoutesContainer(); - const modalsContainer = useModalsContainer(); - const contentContainerRef = React.useRef(null); - const [focusable, setFocusable] = React.useState(false); - React.useEffect(() => { - const onContainerChildrenChange = () => { - setFocusable( - onRoutesContainerChildrenChange({ - routesContainer: routesContainer, - contentContainer: contentContainerRef.current - }) - && - onModalsContainerChildrenChange({ - modalsContainer: modalsContainer, - contentContainer: contentContainerRef.current - }) - ); - }; - const routesContainerChildrenObserver = new MutationObserver(onContainerChildrenChange); - const modalsContainerChildrenObserver = new MutationObserver(onContainerChildrenChange); - routesContainerChildrenObserver.observe(routesContainer, { childList: true }); - modalsContainerChildrenObserver.observe(modalsContainer, { childList: true }); - onContainerChildrenChange(); - return () => { - routesContainerChildrenObserver.disconnect(); - modalsContainerChildrenObserver.disconnect(); - }; - }, [routesContainer, modalsContainer, onRoutesContainerChildrenChange, onModalsContainerChildrenChange]); - React.useEffect(() => { - if (focusable && !contentContainerRef.current.contains(document.activeElement)) { - contentContainerRef.current.focus(); - } - }, [focusable]); - return ( - - {React.cloneElement(React.Children.only(children), { - ref: contentContainerRef, - tabIndex: -1 - })} - - ); -}; - -FocusableProvider.propTypes = { - children: PropTypes.node.isRequired, - onRoutesContainerChildrenChange: PropTypes.func.isRequired, - onModalsContainerChildrenChange: PropTypes.func.isRequired -}; - -module.exports = FocusableProvider; diff --git a/src/router/FocusableContext/index.js b/src/router/FocusableContext/index.js deleted file mode 100644 index 2e8686ca1..000000000 --- a/src/router/FocusableContext/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const FocusableProvider = require('./FocusableProvider'); -const useFocusable = require('./useFocusable'); - -module.exports = { - FocusableProvider, - useFocusable -}; diff --git a/src/router/FocusableContext/useFocusable.js b/src/router/FocusableContext/useFocusable.js deleted file mode 100644 index 751eb1d25..000000000 --- a/src/router/FocusableContext/useFocusable.js +++ /dev/null @@ -1,8 +0,0 @@ -const React = require('react'); -const FocusableContext = require('./FocusableContext'); - -const useFocusable = () => { - return React.useContext(FocusableContext); -}; - -module.exports = useFocusable; diff --git a/src/router/FocusedRouteContext/FocusedRouteContext.js b/src/router/FocusedRouteContext/FocusedRouteContext.js new file mode 100644 index 000000000..d1323e8e9 --- /dev/null +++ b/src/router/FocusedRouteContext/FocusedRouteContext.js @@ -0,0 +1,7 @@ +const React = require('react'); + +const FocusedRouteContext = React.createContext(false); + +FocusedRouteContext.displayName = 'FocusedRouteContext'; + +module.exports = FocusedRouteContext; diff --git a/src/router/FocusedRouteContext/index.js b/src/router/FocusedRouteContext/index.js new file mode 100644 index 000000000..5163ca12c --- /dev/null +++ b/src/router/FocusedRouteContext/index.js @@ -0,0 +1,7 @@ +const FocusedRouteContext = require('./FocusedRouteContext'); +const useFocusedRoute = require('./useFocusedRoute'); + +module.exports = { + FocusedRouteProvider: FocusedRouteContext.Provider, + useFocusedRoute +}; diff --git a/src/router/FocusedRouteContext/useFocusedRoute.js b/src/router/FocusedRouteContext/useFocusedRoute.js new file mode 100644 index 000000000..3c893f027 --- /dev/null +++ b/src/router/FocusedRouteContext/useFocusedRoute.js @@ -0,0 +1,8 @@ +const React = require('react'); +const FocusedRouteContext = require('./FocusedRouteContext'); + +const useFocusedRoute = () => { + return React.useContext(FocusedRouteContext); +}; + +module.exports = useFocusedRoute; diff --git a/src/router/Modal/Modal.js b/src/router/Modal/Modal.js index 89bb8d1e5..115b7aaab 100644 --- a/src/router/Modal/Modal.js +++ b/src/router/Modal/Modal.js @@ -1,21 +1,15 @@ const React = require('react'); const ReactDOM = require('react-dom'); const classnames = require('classnames'); -const { FocusableProvider } = require('../FocusableContext'); +const FocusLock = require('react-focus-lock').default; const { useModalsContainer } = require('../ModalsContainerContext'); -const Modal = (props) => { +const Modal = ({ className, children, ...props }) => { const modalsContainer = useModalsContainer(); - const onRoutesContainerChildrenChange = React.useCallback(({ routesContainer, contentContainer }) => { - return routesContainer.lastElementChild.contains(contentContainer); - }, []); - const onModalsContainerChildrenChange = React.useCallback(({ modalsContainer, contentContainer }) => { - return modalsContainer.lastElementChild === contentContainer; - }, []); return ReactDOM.createPortal( - -
- , + + {children} + , modalsContainer ); }; diff --git a/src/router/Route/Route.js b/src/router/Route/Route.js index 81d978396..440b20bb0 100644 --- a/src/router/Route/Route.js +++ b/src/router/Route/Route.js @@ -1,21 +1,15 @@ const React = require('react'); const PropTypes = require('prop-types'); -const { FocusableProvider } = require('../FocusableContext'); +const FocusLock = require('react-focus-lock').default; const { ModalsContainerProvider } = require('../ModalsContainerContext'); const Route = ({ children }) => { - const onRoutesContainerChildrenChange = React.useCallback(({ routesContainer, contentContainer }) => { - return routesContainer.lastElementChild.contains(contentContainer); - }, []); - const onModalsContainerChildrenChange = React.useCallback(({ modalsContainer }) => { - return modalsContainer.childElementCount === 0; - }, []); return (
- -
{children}
-
+ + {children} +
); diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index 50bbab579..e8617bfca 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -1,9 +1,10 @@ const React = require('react'); const ReactIs = require('react-is'); const PropTypes = require('prop-types'); +const classnames = require('classnames'); const UrlUtils = require('url'); +const { FocusedRouteProvider } = require('../FocusedRouteContext'); const Route = require('../Route'); -const { RoutesContainerProvider } = require('../RoutesContainerContext'); const Router = ({ className, onPathNotMatch, ...props }) => { const [{ homePath, viewsConfig }] = React.useState(() => ({ @@ -96,17 +97,19 @@ const Router = ({ className, onPathNotMatch, ...props }) => { }; }, [onPathNotMatch]); return ( - +
{ views .filter(view => view !== null) - .map(({ key, component, urlParams, queryParams }) => ( - - {React.createElement(component, { urlParams, queryParams })} - + .map(({ key, component, urlParams, queryParams }, index, views) => ( + + + {React.createElement(component, { urlParams, queryParams })} + + )) } - +
); }; diff --git a/src/router/RoutesContainerContext/RoutesContainerContext.js b/src/router/RoutesContainerContext/RoutesContainerContext.js deleted file mode 100644 index 4c1adcbb5..000000000 --- a/src/router/RoutesContainerContext/RoutesContainerContext.js +++ /dev/null @@ -1,7 +0,0 @@ -const React = require('react'); - -const RoutesContainerContext = React.createContext(null); - -RoutesContainerContext.displayName = 'RoutesContainerContext'; - -module.exports = RoutesContainerContext; diff --git a/src/router/RoutesContainerContext/RoutesContainerProvider.js b/src/router/RoutesContainerContext/RoutesContainerProvider.js deleted file mode 100644 index 7f04b062c..000000000 --- a/src/router/RoutesContainerContext/RoutesContainerProvider.js +++ /dev/null @@ -1,25 +0,0 @@ -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -const RoutesContainerContext = require('./RoutesContainerContext'); - -const RoutesContainerProvider = ({ className, children }) => { - const [container, setContainer] = React.useState(null); - return ( - -
- {container instanceof HTMLElement ? children : null} -
-
- ); -}; - -RoutesContainerProvider.propTypes = { - className: PropTypes.string, - children: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.node), - PropTypes.node - ]) -}; - -module.exports = RoutesContainerProvider; diff --git a/src/router/RoutesContainerContext/index.js b/src/router/RoutesContainerContext/index.js deleted file mode 100644 index b96f7dc8b..000000000 --- a/src/router/RoutesContainerContext/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const RoutesContainerProvider = require('./RoutesContainerProvider'); -const useRoutesContainer = require('./useRoutesContainer'); - -module.exports = { - RoutesContainerProvider, - useRoutesContainer -}; diff --git a/src/router/RoutesContainerContext/useRoutesContainer.js b/src/router/RoutesContainerContext/useRoutesContainer.js deleted file mode 100644 index 046b294fc..000000000 --- a/src/router/RoutesContainerContext/useRoutesContainer.js +++ /dev/null @@ -1,8 +0,0 @@ -const React = require('react'); -const RoutesContainerContext = require('./RoutesContainerContext'); - -const useRoutesContainer = () => { - return React.useContext(RoutesContainerContext); -}; - -module.exports = useRoutesContainer; diff --git a/src/router/index.js b/src/router/index.js index 9407ff0da..71623af39 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,9 +1,9 @@ -const { useFocusable } = require('./FocusableContext'); +const { useFocusedRoute } = require('./FocusedRouteContext'); const Modal = require('./Modal'); const Router = require('./Router'); module.exports = { - useFocusable, + useFocusedRoute, Modal, Router }; diff --git a/yarn.lock b/yarn.lock index dc8ca098e..7fcc217df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4404,7 +4404,7 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -focus-lock@^0.6.3: +focus-lock@^0.6.3, focus-lock@^0.6.5: version "0.6.5" resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.6.5.tgz#f6eb37832a9b1b205406175f5277396a28c0fce1" integrity sha512-i/mVBOoa9o+tl+u9owOJUF8k8L85odZNIsctB+JAK2HFT8jckiBwmk+3uydlm6FN8czgnkIwQtBv6yyAbrzXjw== @@ -7662,7 +7662,7 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-clientside-effect@^1.2.0: +react-clientside-effect@^1.2.0, react-clientside-effect@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.2.tgz#6212fb0e07b204e714581dd51992603d1accc837" integrity sha512-nRmoyxeok5PBO6ytPvSjKp9xwXg9xagoTK1mMjwnQxqM9Hd7MNPl+LS1bOSOe+CV2+4fnEquc7H/S8QD3q697A== @@ -7761,6 +7761,17 @@ react-fast-compare@2.0.4: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== +react-focus-lock@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.1.1.tgz#49762377119ecd52eb56519ddd10a87c0c1ddd98" + integrity sha512-IKfloS8Ifx5v+Gwm64hoTqT0NmzXksTKYROOAq+HlBIxUqUS2yA5NNzQJtuOsx3nyPs7wrgycbVsffRfcA5OTw== + dependencies: + "@babel/runtime" "^7.0.0" + focus-lock "^0.6.5" + prop-types "^15.6.2" + react-clientside-effect "^1.2.2" + use-sidecar "^1.0.1" + react-focus-lock@^1.18.3: version "1.19.1" resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-1.19.1.tgz#2f3429793edaefe2d077121f973ce5a3c7a0651a" @@ -9132,7 +9143,7 @@ ts-pnp@^1.1.2: resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.4.tgz#ae27126960ebaefb874c6d7fa4729729ab200d90" integrity sha512-1J/vefLC+BWSo+qe8OnJQfWTYRS6ingxjwqmHMqaMxXMj7kFtKLgAaYW3JeX3mktjgUL+etlU8/B4VUAUI9QGw== -tslib@^1.9.0: +tslib@^1.9.0, tslib@^1.9.3: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== @@ -9330,6 +9341,14 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +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== + dependencies: + detect-node "^2.0.4" + tslib "^1.9.3" + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"