diff --git a/src/router/FocusableContext/FocusableProvider.js b/src/router/FocusableContext/FocusableProvider.js index 398c1c106..b68e1f331 100644 --- a/src/router/FocusableContext/FocusableProvider.js +++ b/src/router/FocusableContext/FocusableProvider.js @@ -1,38 +1,36 @@ const React = require('react'); const PropTypes = require('prop-types'); -const { useRoutesContainer } = require('../RoutesContainerContext'); const { useModalsContainer } = require('../ModalsContainerContext'); +const { useRoutesContainer } = require('../RoutesContainerContext'); const FocusableContext = require('./FocusableContext'); -const FocusableProvider = ({ children, onRoutesContainerDomTreeChange, onModalsContainerDomTreeChange }) => { +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 onDomTreeChange = () => { - const focusable = - onRoutesContainerDomTreeChange({ + const onContainerChildrenChange = () => { + setFocusable( + onRoutesContainerChildrenChange({ routesContainer: routesContainer, contentContainer: contentContainerRef.current }) && - onModalsContainerDomTreeChange({ + onModalsContainerChildrenChange({ modalsContainer: modalsContainer, contentContainer: contentContainerRef.current - }); - setFocusable(focusable); + }) + ); }; - const routesContainerDomTreeObserver = new MutationObserver(onDomTreeChange); - const modalsContainerDomTreeObserver = new MutationObserver(onDomTreeChange); - routesContainerDomTreeObserver.observe(routesContainer, { childList: true }); - modalsContainerDomTreeObserver.observe(modalsContainer, { childList: true }); - onDomTreeChange(); + routesContainer.addEventListener('childrenchange', onContainerChildrenChange); + modalsContainer.addEventListener('childrenchange', onContainerChildrenChange); + onContainerChildrenChange(); return () => { - routesContainerDomTreeObserver.disconnect(); - modalsContainerDomTreeObserver.disconnect(); + routesContainer.removeEventListener('childrenchange', onContainerChildrenChange); + modalsContainer.removeEventListener('childrenchange', onContainerChildrenChange); }; - }, [routesContainer, modalsContainer, onRoutesContainerDomTreeChange, onModalsContainerDomTreeChange]); + }, [routesContainer, modalsContainer, onRoutesContainerChildrenChange, onModalsContainerChildrenChange]); React.useEffect(() => { if (focusable && !contentContainerRef.current.contains(document.activeElement)) { contentContainerRef.current.focus(); @@ -50,8 +48,8 @@ const FocusableProvider = ({ children, onRoutesContainerDomTreeChange, onModalsC FocusableProvider.propTypes = { children: PropTypes.node.isRequired, - onModalsContainerDomTreeChange: PropTypes.func.isRequired, - onRoutesContainerDomTreeChange: PropTypes.func.isRequired + onRoutesContainerChildrenChange: PropTypes.func.isRequired, + onModalsContainerChildrenChange: PropTypes.func.isRequired }; module.exports = FocusableProvider; diff --git a/src/router/Modal/Modal.js b/src/router/Modal/Modal.js index 5f69afbec..a02c4795d 100644 --- a/src/router/Modal/Modal.js +++ b/src/router/Modal/Modal.js @@ -7,14 +7,26 @@ const { useModalsContainer } = require('../ModalsContainerContext'); const Modal = ({ className, children }) => { const modalsContainer = useModalsContainer(); - const onRoutesContainerDomTreeChange = React.useCallback(({ routesContainer, contentContainer }) => { - return routesContainer.lastElementChild === contentContainer.parentElement.parentElement; + const onRoutesContainerChildrenChange = React.useCallback(({ routesContainer, contentContainer }) => { + return routesContainer.lastElementChild.contains(contentContainer); }, []); - const onModalsContainerDomTreeChange = React.useCallback(({ modalsContainer, contentContainer }) => { + const onModalsContainerChildrenChange = React.useCallback(({ modalsContainer, contentContainer }) => { return modalsContainer.lastElementChild === contentContainer; }, []); + React.useEffect(() => { + modalsContainer.dispatchEvent(new CustomEvent('childrenchange', { + bubbles: false, + cancelable: false + })); + return () => { + modalsContainer.dispatchEvent(new CustomEvent('childrenchange', { + bubbles: false, + cancelable: false + })); + }; + }, [modalsContainer]); return ReactDOM.createPortal( - +
{children}
, modalsContainer diff --git a/src/router/Route/Route.js b/src/router/Route/Route.js new file mode 100644 index 000000000..015ed3e49 --- /dev/null +++ b/src/router/Route/Route.js @@ -0,0 +1,45 @@ +const React = require('react'); +const PropTypes = require('prop-types'); +const { FocusableProvider } = require('../FocusableContext'); +const { ModalsContainerProvider } = require('../ModalsContainerContext'); +const { useRoutesContainer } = require('../RoutesContainerContext'); + +const Route = ({ children }) => { + const routesContainer = useRoutesContainer(); + const onRoutesContainerChildrenChange = React.useCallback(({ routesContainer, contentContainer }) => { + return routesContainer.lastElementChild.contains(contentContainer); + }, []); + const onModalsContainerChildrenChange = React.useCallback(({ modalsContainer }) => { + return modalsContainer.childElementCount === 0; + }, []); + React.useEffect(() => { + routesContainer.dispatchEvent(new CustomEvent('childrenchange', { + bubbles: false, + cancelable: false + })); + return () => { + routesContainer.dispatchEvent(new CustomEvent('childrenchange', { + bubbles: false, + cancelable: false + })); + }; + }, [routesContainer]); + return ( +
+ + +
{children}
+
+
+
+ ); +}; + +Route.propTypes = { + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]) +}; + +module.exports = Route; diff --git a/src/router/Route/index.js b/src/router/Route/index.js new file mode 100644 index 000000000..c23450959 --- /dev/null +++ b/src/router/Route/index.js @@ -0,0 +1,3 @@ +const Route = require('./Route'); + +module.exports = Route; diff --git a/src/router/Router/Route.js b/src/router/Router/Route.js deleted file mode 100644 index 5156b113c..000000000 --- a/src/router/Router/Route.js +++ /dev/null @@ -1,31 +0,0 @@ -const React = require('react'); -const PropTypes = require('prop-types'); -const { FocusableProvider } = require('../FocusableContext'); -const { ModalsContainerProvider } = require('../ModalsContainerContext'); - -const Route = ({ children }) => { - const onRoutesContainerDomTreeChange = React.useCallback(({ routesContainer, contentContainer }) => { - return routesContainer.lastElementChild === contentContainer.parentElement; - }, []); - const onModalsContainerDomTreeChange = React.useCallback(({ modalsContainer }) => { - return modalsContainer.childElementCount === 0; - }, []); - return ( -
- - -
{children}
-
-
-
- ); -}; - -Route.propTypes = { - children: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.node), - PropTypes.node - ]) -}; - -module.exports = Route; diff --git a/src/router/Router/Router.js b/src/router/Router/Router.js index f020b3b00..2acc8dba7 100644 --- a/src/router/Router/Router.js +++ b/src/router/Router/Router.js @@ -1,12 +1,12 @@ const React = require('react'); -const PropTypes = require('prop-types'); const ReactIs = require('react-is'); +const PropTypes = require('prop-types'); const UrlUtils = require('url'); +const Route = require('../Route'); const { RoutesContainerProvider } = require('../RoutesContainerContext'); -const queryParamsForQuery = require('../queryParamsForQuery'); -const routeConfigForPath = require('../routeConfigForPath'); -const urlParamsForPath = require('../urlParamsForPath'); -const Route = require('./Route'); +const queryParamsForQuery = require('./queryParamsForQuery'); +const routeConfigForPath = require('./routeConfigForPath'); +const urlParamsForPath = require('./urlParamsForPath'); const Router = ({ onPathNotMatch, ...props }) => { const [{ homePath, viewsConfig }] = React.useState(() => ({ diff --git a/src/router/queryParamsForQuery.js b/src/router/Router/queryParamsForQuery.js similarity index 100% rename from src/router/queryParamsForQuery.js rename to src/router/Router/queryParamsForQuery.js diff --git a/src/router/routeConfigForPath.js b/src/router/Router/routeConfigForPath.js similarity index 100% rename from src/router/routeConfigForPath.js rename to src/router/Router/routeConfigForPath.js diff --git a/src/router/urlParamsForPath.js b/src/router/Router/urlParamsForPath.js similarity index 100% rename from src/router/urlParamsForPath.js rename to src/router/Router/urlParamsForPath.js