UNPKG

@zohodesk/hooks

Version:

Unified Component Library - Hooks

140 lines (123 loc) 5.64 kB
import { useLayoutEffect, useCallback } from 'react'; import usePopupHandlers from "./usePopupHandlers"; import useClickOutside from "../utils/useClickOutside"; import useEscape from "../utils/useEscape"; import useScrollParents from "../scroll/useScrollParents"; import useScrollStopper from "../scroll/useScrollStopper"; import useFixedPopupScrollHandling from "./useFixedPopupScrollHandling"; import usePopupObservers from "./usePopupObservers"; import usePopupFloating from "./usePopupFloating"; /** A custom React hook that provides advanced functionality for handling popups. @param {Object} props - An object containing optional configuration for the popup. @param {boolean} props.isPopupOpen - A boolean indicating whether the popup should be open or not. @param {boolean} props.isAbsolutePosition - A boolean indicating whether the popup should be positioned absolutely or fixed. @param {boolean} props.isArrow - A boolean indicating whether the popup should have an arrow pointing to the target element. @param {Array} props.customPositionOrder - An array of preferred positions for the popup, in order of priority. @param {string} props.defaultPosition - A string indicating the default position for the popup. @param {Function} props.getTargetElement - A function that returns the target element for the popup. @param {Function} props.getDropdownElement - A function that returns the dropdown element for the popup. @param {boolean} props.needPositionUpdateOnScroll - A boolean indicating whether the popup position should be updated on scroll events. @param {Function} props.onTargetMovement - A function that is called when the target element moves. @param {boolean} props.isMobileView - A boolean indicating whether the popup should be optimized for mobile view. @param {string} groupName - A string indicating the name of the popup group. @returns {Object} An object containing the current state of the popup and functions to open, close, or toggle the popup. */ export default function useAdvancedPopup() { let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; let groupName = arguments.length > 1 ? arguments[1] : undefined; const { isPopupOpen: propsPopupOpen, isAbsolutePosition, isArrow, customPositionOrder, defaultPosition, getTargetElement, getDropdownElement, needPositionUpdateOnScroll = false, onTargetMovement, isMobileView = false } = props; // --- Popup state and function --- const { isPopupOpen, handleOpenPopup, handleClosePopup, handleTogglePopup } = usePopupHandlers(propsPopupOpen, groupName); // --- Scroll Parents --- const { immediateScrollParent, otherScrollParents } = useScrollParents(getTargetElement()); // --- Floating data --- const { floating, reCalcFloating } = usePopupFloating({ getTargetElement, getDropdownElement, defaultPosition, isAbsolutePosition, isArrow, customPositionOrder, onTargetMovement }); // --- Calculate floating when popup opens --- useLayoutEffect(() => { if (isPopupOpen && !isMobileView) { reCalcFloating(); } }, [isPopupOpen]); // --- Resize handlings --- usePopupObservers({ isObserve: isPopupOpen && !isMobileView, isAbsolutePosition, handleClosePopup, reCalcFloating, getTargetElement, getDropdownElement }); // --- Exclude Elements --- const getExcludeElements = useCallback(() => { return [getTargetElement(), getDropdownElement()]; }, []); // --- Close popup on outside click --- useClickOutside({ getElements: getExcludeElements, callback: handleClosePopup, isRegister: isPopupOpen }); // --- Close popup on escape key press --- useEscape({ callback: handleClosePopup, isRegister: isPopupOpen }); // --- Scroll handlings for fixed popup --- useScrollStopper({ getExcludeElements, element: immediateScrollParent, isStop: !isAbsolutePosition && !needPositionUpdateOnScroll && isPopupOpen && !isMobileView }); // --- Update popup position on parent scroll & Close popup on other parent's scroll --- useFixedPopupScrollHandling({ isScrollHandleNeed: !(isAbsolutePosition || isMobileView) && isPopupOpen, immediateScrollParent, otherScrollParents, immediateParentScrollHandler: needPositionUpdateOnScroll ? reCalcFloating : null, otherParentsScrollHandler: handleClosePopup }); // --- Return --- return { isPopupOpen, handleOpenPopup, handleClosePopup, handleTogglePopup, floating }; } /* To Do: - Update floating on scroll for fixed popup - DONE - Close popup when target element hides inside scroll for fixed popup - DONE - Block all scrolls for fixed popup - DONE - Hide dropbox when scroll the other parents - DONE - Update floating and visibility on window resize for fixed popup - DONE - Update floating and visibility on window resize on scroll - InterSectionObserver - DONE - Update floating state only change happens on floating data in reCalcFloating - PARTIALLY DONE (Using JSON.stringifiy) - Update floating and visibility on target & dropbox resize - ResizeObserver - PARTIALLY DONE - Use popup inside another popup & Need to maintain order - PARTIALLY DONE - Resizes & floating should not be calculated for mobile case - Need flag - DONE - Close dropbox on parent elements scroll - Get parent with data attr - WILL CHECK - Close popup once complete the animation - WILL CHECK - $ Floating data equal validation will not be useful, bcoz while scroll popupOffset (fixed popup's top position is changing) */