diff --git a/src/router/FocusableContext/FocusableProvider.js b/src/router/FocusableContext/FocusableProvider.js index 398c1c106..41679316d 100644 --- a/src/router/FocusableContext/FocusableProvider.js +++ b/src/router/FocusableContext/FocusableProvider.js @@ -4,35 +4,32 @@ const { useRoutesContainer } = require('../RoutesContainerContext'); const { useModalsContainer } = require('../ModalsContainerContext'); 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); + const [focusable, setFocusable] = React.useState(true); React.useEffect(() => { - const onDomTreeChange = () => { - const focusable = - onRoutesContainerDomTreeChange({ + const onContainersChildrenChange = () => { + 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', onContainersChildrenChange); + modalsContainer.addEventListener('childrenchange', onContainersChildrenChange); return () => { - routesContainerDomTreeObserver.disconnect(); - modalsContainerDomTreeObserver.disconnect(); + routesContainer.removeEventListener('childrenchange', onContainersChildrenChange); + modalsContainer.removeEventListener('childrenchange', onContainersChildrenChange); }; - }, [routesContainer, modalsContainer, onRoutesContainerDomTreeChange, onModalsContainerDomTreeChange]); + }, [routesContainer, modalsContainer, onRoutesContainerChildrenChange, onModalsContainerChildrenChange]); React.useEffect(() => { if (focusable && !contentContainerRef.current.contains(document.activeElement)) { contentContainerRef.current.focus(); @@ -50,8 +47,8 @@ const FocusableProvider = ({ children, onRoutesContainerDomTreeChange, onModalsC FocusableProvider.propTypes = { children: PropTypes.node.isRequired, - onModalsContainerDomTreeChange: PropTypes.func.isRequired, - onRoutesContainerDomTreeChange: PropTypes.func.isRequired + onModalsContainerChildrenChange: PropTypes.func.isRequired, + onRoutesContainerChildrenChange: PropTypes.func.isRequired }; module.exports = FocusableProvider; diff --git a/src/router/Modal/Modal.js b/src/router/Modal/Modal.js index 5f69afbec..314ffe120 100644 --- a/src/router/Modal/Modal.js +++ b/src/router/Modal/Modal.js @@ -7,14 +7,14 @@ const { useModalsContainer } = require('../ModalsContainerContext'); const Modal = ({ className, children }) => { const modalsContainer = useModalsContainer(); - const onRoutesContainerDomTreeChange = React.useCallback(({ routesContainer, contentContainer }) => { + const onRoutesContainerChildrenChange = React.useCallback(({ routesContainer, contentContainer }) => { return routesContainer.lastElementChild === contentContainer.parentElement.parentElement; }, []); - const onModalsContainerDomTreeChange = React.useCallback(({ modalsContainer, contentContainer }) => { + const onModalsContainerChildrenChange = React.useCallback(({ modalsContainer, contentContainer }) => { return modalsContainer.lastElementChild === contentContainer; }, []); return ReactDOM.createPortal( - +
{children}
, modalsContainer diff --git a/src/router/ModalsContainerContext/ModalsContainerProvider.js b/src/router/ModalsContainerContext/ModalsContainerProvider.js index 00e9c6928..d61a6d578 100644 --- a/src/router/ModalsContainerContext/ModalsContainerProvider.js +++ b/src/router/ModalsContainerContext/ModalsContainerProvider.js @@ -1,9 +1,11 @@ const React = require('react'); const PropTypes = require('prop-types'); +const useChildrenChangeEffect = require('../useChildrenChangeEffect'); const ModalsContainerContext = require('./ModalsContainerContext'); const ModalsContainerProvider = ({ children }) => { const [container, setContainer] = React.useState(null); + useChildrenChangeEffect(container, children); return ( {container instanceof HTMLElement ? children : null} diff --git a/src/router/Router/Route.js b/src/router/Router/Route.js index 5156b113c..d2e76f5fa 100644 --- a/src/router/Router/Route.js +++ b/src/router/Router/Route.js @@ -4,16 +4,16 @@ const { FocusableProvider } = require('../FocusableContext'); const { ModalsContainerProvider } = require('../ModalsContainerContext'); const Route = ({ children }) => { - const onRoutesContainerDomTreeChange = React.useCallback(({ routesContainer, contentContainer }) => { + const onRoutesContainerChildrenChange = React.useCallback(({ routesContainer, contentContainer }) => { return routesContainer.lastElementChild === contentContainer.parentElement; }, []); - const onModalsContainerDomTreeChange = React.useCallback(({ modalsContainer }) => { + const onModalsContainerChildrenChange = React.useCallback(({ modalsContainer }) => { return modalsContainer.childElementCount === 0; }, []); return (
- +
{children}
diff --git a/src/router/RoutesContainerContext/RoutesContainerProvider.js b/src/router/RoutesContainerContext/RoutesContainerProvider.js index 390445d6f..f0bdfbb65 100644 --- a/src/router/RoutesContainerContext/RoutesContainerProvider.js +++ b/src/router/RoutesContainerContext/RoutesContainerProvider.js @@ -1,9 +1,11 @@ const React = require('react'); const PropTypes = require('prop-types'); +const useChildrenChangeEffect = require('../useChildrenChangeEffect'); const RoutesContainerContext = require('./RoutesContainerContext'); const RoutesContainerProvider = ({ children }) => { const [container, setContainer] = React.useState(null); + useChildrenChangeEffect(container, children); return (
diff --git a/src/router/useChildrenChangeEffect.js b/src/router/useChildrenChangeEffect.js new file mode 100644 index 000000000..39f0d75dc --- /dev/null +++ b/src/router/useChildrenChangeEffect.js @@ -0,0 +1,14 @@ +const React = require('react'); + +const useChildrenChangeEffect = (parent, children) => { + React.useEffect(() => { + if (parent instanceof HTMLElement) { + parent.dispatchEvent(new CustomEvent('childrenchange', { + bubbles: false, + cancelable: false + })); + } + }, [parent, children]); +}; + +module.exports = useChildrenChangeEffect;