import { React } from '@gravityforms/libraries';
const { useEffect, useState } = React;
const ESCAPE = 'Escape';
/**
* @module usePopup
* @description A hook to manage a popup state.
*
* @since 4.0.1
*
* @param {object} args The arguments for the hook.
* @param {boolean} args.closeOnClickOutside Whether to close the popup when clicking outside.
* @param {Function} args.customClickOutsideLogic Custom logic to determine if the popup should close when clicking outside.
* @param {number} args.duration The duration of the popup animation.
* @param {boolean} args.initialOpen The initial open state of the popup.
* @param {Function} args.onAfterClose The callback after the popup is closed.
* @param {Function} args.onAfterOpen The callback after the popup is opened.
* @param {Function} args.onClose The callback when the popup is closed.
* @param {Function} args.onOpen The callback when the popup is opened.
* @param {object} args.popupRef The reference to the popup element.
* @param {object} args.triggerRef The reference to the trigger element.
*
* @return {object} The popup state.
*/
const usePopup = ( {
closeOnClickOutside = true,
customClickOutsideLogic = () => {},
duration = 150,
initialOpen = false,
onAfterClose = () => {},
onAfterOpen = () => {},
onClose = () => {},
onOpen = () => {},
popupRef = null,
triggerRef = null,
} ) => {
const [ popupReveal, setPopupReveal ] = useState( false );
const [ popupHide, setPopupHide ] = useState( false );
const [ popupOpen, setPopupOpen ] = useState( initialOpen );
useEffect( () => {
if ( ! closeOnClickOutside ) {
return;
}
const handleClickOutside = ( event ) => {
// If refs don't exist, return early.
if ( ! popupOpen || ! triggerRef?.current || ! popupRef?.current ) {
return;
}
if (
! triggerRef.current.contains( event.target ) &&
! popupRef.current.contains( event.target ) &&
! customClickOutsideLogic( event )
) {
closePopup();
}
};
document.addEventListener( 'click', handleClickOutside );
return () => {
document.removeEventListener( 'click', handleClickOutside );
};
}, [ popupOpen, popupRef, triggerRef ] );
/**
* @function openPopup
* @description Open the popup.
*
* @since 4.0.1
*/
const openPopup = () => {
onOpen();
setPopupReveal( true );
requestAnimationFrame( () => {
setPopupOpen( true );
setTimeout( () => {
setPopupReveal( false );
onAfterOpen();
}, duration );
} );
};
/**
* @function closePopup
* @description Close the popup.
*
* @since 4.0.1
*/
const closePopup = () => {
onClose();
setPopupOpen( false );
setPopupHide( true );
setTimeout( () => {
setPopupHide( false );
onAfterClose();
}, duration );
};
/**
* @function handleEscKeyDown
* @description Handles the keydown event for the escape key.
*
* @since 4.0.1
*
* @param {Event} event The event object.
*/
const handleEscKeyDown = ( event ) => {
if ( event.key !== ESCAPE ) {
return;
}
// Close dropdown if escape is pressed.
closePopup();
triggerRef?.current?.focus();
};
return {
closePopup,
openPopup,
handleEscKeyDown,
popupHide,
popupOpen,
popupReveal,
setPopupHide,
setPopupOpen,
setPopupReveal,
};
};
export default usePopup;