diff --git a/src/components/display/Dropdown.tsx b/src/components/display/Dropdown.tsx index 316108b6..6c1fa478 100644 --- a/src/components/display/Dropdown.tsx +++ b/src/components/display/Dropdown.tsx @@ -23,7 +23,7 @@ import { StrictModifiers, VirtualElement } from '@popperjs/core'; -import { find } from 'lodash'; +import { find, forEach } from 'lodash'; import styled, { css, SimpleInterpolation } from 'styled-components'; import { pseudoClasses } from '../../theme/theme-utils'; import { Padding } from '../layout/Padding'; @@ -402,6 +402,15 @@ const Dropdown = React.forwardRef(function Dropdo const endSentinelRef = useRef(null); const [position, setPosition] = useState(null); const [currentHover, setCurrentHover] = useState(null); + const openPopperTimoutRef = useRef>(); + + useEffect( + // clear timers on unmount + () => (): void => { + openPopperTimoutRef.current && clearTimeout(openPopperTimoutRef.current); + }, + [] + ); useEffect(() => { setOpen(forceOpen); @@ -461,7 +470,7 @@ const Dropdown = React.forwardRef(function Dropdo }) }; setPosition(virtualElement); - setTimeout(() => { + openPopperTimoutRef.current = setTimeout(() => { if (!disabled && !openRef.current) { openPopper(); } @@ -555,36 +564,40 @@ const Dropdown = React.forwardRef(function Dropdo }, [open, placement, contextMenu, position, dropdownRef, innerTriggerRef]); useEffect(() => { - if (!disableAutoFocus) { - open && - setTimeout(() => { - const selectedItems = dropdownRef.current - ? dropdownRef.current.querySelectorAll('.zapp-selected') - : []; - selectedItems.length > 0 - ? selectedItems[0].focus() - : popperItemsRef.current && - popperItemsRef.current.children[0] && - popperItemsRef.current.children[0] instanceof HTMLElement && - popperItemsRef.current.children[0].focus(); - }, 1); + let timeout: ReturnType; + if (!disableAutoFocus && open) { + timeout = setTimeout(() => { + const selectedItems = dropdownRef.current + ? dropdownRef.current.querySelectorAll('.zapp-selected') + : []; + selectedItems.length > 0 + ? selectedItems[0].focus() + : popperItemsRef.current && + popperItemsRef.current.children[0] && + popperItemsRef.current.children[0] instanceof HTMLElement && + popperItemsRef.current.children[0].focus(); + }, 1); } + + return (): void => { + timeout && clearTimeout(timeout); + }; }, [disableAutoFocus, dropdownRef, open]); useEffect(() => { openRef.current = open; + let timeout: ReturnType; if (open) { - setTimeout(() => windowObj.document.addEventListener('click', clickOutsidePopper, true), 1); - contextMenu && - setTimeout( - () => windowObj.document.addEventListener('contextmenu', clickOutsidePopper, true), - 1 - ); + timeout = setTimeout(() => { + windowObj.document.addEventListener('click', clickOutsidePopper, true); + contextMenu && windowObj.document.addEventListener('contextmenu', clickOutsidePopper, true); + }, 1); } return (): void => { windowObj.document.removeEventListener('click', clickOutsidePopper, true); windowObj.document.removeEventListener('contextmenu', clickOutsidePopper, true); + timeout && clearTimeout(timeout); }; }, [open, closePopper, clickOutsidePopper, contextMenu, windowObj.document]); diff --git a/src/components/display/Tooltip.tsx b/src/components/display/Tooltip.tsx index 4f2254cf..d09ba616 100644 --- a/src/components/display/Tooltip.tsx +++ b/src/components/display/Tooltip.tsx @@ -147,7 +147,7 @@ const Tooltip = React.forwardRef(function TooltipF useEffect(() => { // Added timeout to fix Preact weird bug - setTimeout(() => { + const timeout = setTimeout(() => { if (triggerRef.current && !disabled) { triggerRef.current.addEventListener('focus', showTooltip); triggerRef.current.addEventListener('blur', hideTooltip); @@ -163,6 +163,7 @@ const Tooltip = React.forwardRef(function TooltipF refSave.removeEventListener('mouseenter', showTooltip); refSave.removeEventListener('mouseleave', hideTooltip); } + clearTimeout(timeout); }; }, [triggerRef, showTooltip, hideTooltip, disabled]); diff --git a/src/components/feedback/CustomModal.tsx b/src/components/feedback/CustomModal.tsx index 78b3a883..8b0175a3 100644 --- a/src/components/feedback/CustomModal.tsx +++ b/src/components/feedback/CustomModal.tsx @@ -126,7 +126,10 @@ const CustomModal = React.forwardRef(function }, [open, onStartSentinelFocus, onEndSentinelFocus, windowObj]); useEffect(() => { - setTimeout(() => setDelayedOpen(open), 1); + const timeout = setTimeout(() => setDelayedOpen(open), 1); + return (): void => { + clearTimeout(timeout); + }; }, [open]); const modalWrapperClickHandler = useCallback((e) => { diff --git a/src/components/feedback/Modal.tsx b/src/components/feedback/Modal.tsx index 677fb3d9..369c71a8 100644 --- a/src/components/feedback/Modal.tsx +++ b/src/components/feedback/Modal.tsx @@ -349,7 +349,11 @@ const Modal = React.forwardRef(function ModalFn( }, [open, onStartSentinelFocus, onEndSentinelFocus, windowObj]); useEffect(() => { - setTimeout(() => setDelayedOpen(open), 1); + const timeout = setTimeout(() => setDelayedOpen(open), 1); + + return (): void => { + clearTimeout(timeout); + }; }, [open]); return ( diff --git a/src/components/utilities/Transition.tsx b/src/components/utilities/Transition.tsx index f045128a..0f600315 100644 --- a/src/components/utilities/Transition.tsx +++ b/src/components/utilities/Transition.tsx @@ -191,7 +191,7 @@ const TransitionOn = React.forwardRef(function T }; } - setTimeout(() => { + const applyStyleTimeout = setTimeout(() => { if (childElement) { const fromStyles = from || STYLES[type].from; applyStyle(fromStyles, childElement); @@ -199,7 +199,7 @@ const TransitionOn = React.forwardRef(function T } }, 1); - const timeout = setTimeout(() => { + const resetStyleTimeout = setTimeout(() => { if (childElement) { childElement.style.transition = ''; const endStyles = end || STYLES[type].end || {}; @@ -208,7 +208,8 @@ const TransitionOn = React.forwardRef(function T }, duration); return (): void => { - clearTimeout(timeout); + clearTimeout(applyStyleTimeout); + clearTimeout(resetStyleTimeout); }; }, [ apply,