plane/web/hooks/use-dropdown.ts

77 lines
2.2 KiB
TypeScript
Raw Normal View History

import { useEffect } from "react";
// hooks
import { useDropdownKeyDown } from "@/hooks/use-dropdown-key-down";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
type TArguments = {
dropdownRef: React.RefObject<HTMLDivElement>;
inputRef?: React.RefObject<HTMLInputElement | null>;
isOpen: boolean;
onClose?: () => void;
onOpen?: () => Promise<void> | void;
query?: string;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
setQuery?: React.Dispatch<React.SetStateAction<string>>;
};
export const useDropdown = (args: TArguments) => {
const { dropdownRef, inputRef, isOpen, onClose, onOpen, query, setIsOpen, setQuery } = args;
/**
* @description clear the search input when the user presses the escape key, if the search input is not empty
* @param {React.KeyboardEvent<HTMLInputElement>} e
*/
const searchInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (query !== "" && e.key === "Escape") {
e.stopPropagation();
setQuery?.("");
}
};
/**
* @description close the dropdown, clear the search input, and call the onClose callback
*/
const handleClose = () => {
if (!isOpen) return;
setIsOpen(false);
onClose?.();
setQuery?.("");
};
// toggle the dropdown, call the onOpen callback if the dropdown is closed, and call the onClose callback if the dropdown is open
const toggleDropdown = () => {
if (!isOpen) onOpen?.();
setIsOpen((prevIsOpen) => !prevIsOpen);
if (isOpen) onClose?.();
};
const handleKeyDown = useDropdownKeyDown(toggleDropdown, handleClose);
/**
* @description toggle the dropdown on click
* @param {React.MouseEvent<HTMLButtonElement, MouseEvent>} e
*/
const handleOnClick = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.stopPropagation();
e.preventDefault();
toggleDropdown();
};
// close the dropdown when the user clicks outside of the dropdown
useOutsideClickDetector(dropdownRef, handleClose);
// focus the search input when the dropdown is open
useEffect(() => {
if (isOpen && inputRef?.current) {
inputRef.current.focus();
}
}, [inputRef, isOpen]);
return {
handleClose,
handleKeyDown,
handleOnClick,
searchInputKeyDown,
};
};