import React, { useCallback, useEffect, useRef, useState } from "react"; import { getMainCanvas } from "./WidgetUtils"; import styled from "styled-components"; import type { BaseSelectRef } from "rc-select"; import type { RenderMode } from "constants/WidgetConstants"; import { RenderModes } from "constants/WidgetConstants"; const BackDropContainer = styled.div` position: fixed; width: 100vw; height: 100vh; background: transparent; top: 0; left: 0; display: none; `; interface useDropdownProps { inputRef: React.RefObject; renderMode?: RenderMode; onDropdownOpen?: () => void; onDropdownClose?: () => void; } const FOCUS_TIMEOUT = 500; // TODO: Refactor More functionalities in MultiSelect, MultiTreeSelect and TreeSelect Components const useDropdown = ({ inputRef, onDropdownClose, onDropdownOpen, renderMode, }: useDropdownProps) => { // This is to make the dropdown controlled const [isOpen, setIsOpen] = useState(false); const popupContainer = useRef(getMainCanvas()); const selectRef = useRef(null); useEffect(() => { if (!popupContainer.current) { popupContainer.current = getMainCanvas(); } }, []); const onKeyDown = (event: React.KeyboardEvent) => { // Backspace would simultaneously remove an option, so it should only be used within the search input if (event.key === "Backspace") { event.stopPropagation(); } }; // Avoid scrolls when Popup is opened function BackDrop() { return ; } // Get PopupContainer on main Canvas const getPopupContainer = useCallback(() => popupContainer.current, []); const handleOnDropdownOpen = useCallback(() => { if (!isOpen && onDropdownOpen) { onDropdownOpen(); } }, [onDropdownOpen, isOpen]); const handleOnDropdownClose = useCallback(() => { if (isOpen && onDropdownClose) { onDropdownClose(); } }, [onDropdownClose, isOpen]); // When Dropdown is opened disable scrolling within the app except the list of options const onOpen = useCallback( (open: boolean) => { setIsOpen(open); if (open) { handleOnDropdownOpen(); setTimeout(() => inputRef.current?.focus(), FOCUS_TIMEOUT); // for more context, the Element we attach to in view mode doesn't have an overflow style, so this only applies to edit mode. if (popupContainer.current && renderMode === RenderModes.CANVAS) { popupContainer.current.style.overflowY = "hidden"; } } else { handleOnDropdownClose(); if (popupContainer.current && renderMode === RenderModes.CANVAS) { popupContainer.current.style.overflowY = "auto"; } selectRef.current?.blur(); } }, [renderMode, handleOnDropdownOpen, handleOnDropdownOpen], ); const closeBackDrop = useCallback(() => { if (selectRef.current) { selectRef.current.blur(); onOpen(false); } }, [onOpen]); return { BackDrop, getPopupContainer, onOpen, isOpen, selectRef, onKeyDown, }; }; export default useDropdown;