diff --git a/packages/ui/src/dropdowns/custom-menu.tsx b/packages/ui/src/dropdowns/custom-menu.tsx index 7c2d95a18..d6b0281ce 100644 --- a/packages/ui/src/dropdowns/custom-menu.tsx +++ b/packages/ui/src/dropdowns/custom-menu.tsx @@ -2,6 +2,9 @@ import * as React from "react"; // react-poppper import { usePopper } from "react-popper"; +// hooks +import { useDropdownKeyDown } from "../hooks/use-dropdown-key-down"; +import useOutsideClickDetector from "../hooks/use-outside-click-detector"; // headless ui import { Menu } from "@headlessui/react"; // type @@ -27,16 +30,35 @@ const CustomMenu = (props: ICustomMenuDropdownProps) => { verticalEllipsis = false, width = "auto", menuButtonOnClick, + tabIndex, } = props; const [referenceElement, setReferenceElement] = React.useState(null); const [popperElement, setPopperElement] = React.useState(null); + const [isOpen, setIsOpen] = React.useState(false); + // refs + const dropdownRef = React.useRef(null); const { styles, attributes } = usePopper(referenceElement, popperElement, { placement: placement ?? "auto", }); + + const openDropdown = () => { + setIsOpen(true); + if (referenceElement) referenceElement.focus(); + }; + const closeDropdown = () => setIsOpen(false); + const handleKeyDown = useDropdownKeyDown(openDropdown, closeDropdown, isOpen); + useOutsideClickDetector(dropdownRef, closeDropdown); + return ( - + {({ open }) => ( <> {customButton ? ( @@ -44,7 +66,10 @@ const CustomMenu = (props: ICustomMenuDropdownProps) => { diff --git a/packages/ui/src/dropdowns/custom-search-select.tsx b/packages/ui/src/dropdowns/custom-search-select.tsx index 759a88349..f9af00c93 100644 --- a/packages/ui/src/dropdowns/custom-search-select.tsx +++ b/packages/ui/src/dropdowns/custom-search-select.tsx @@ -1,7 +1,10 @@ -import React, { useState } from "react"; +import React, { useRef, useState } from "react"; // react-popper import { usePopper } from "react-popper"; +// hooks +import { useDropdownKeyDown } from "../hooks/use-dropdown-key-down"; +import useOutsideClickDetector from "../hooks/use-outside-click-detector"; // headless ui import { Combobox } from "@headlessui/react"; // icons @@ -29,11 +32,15 @@ export const CustomSearchSelect = (props: ICustomSearchSelectProps) => { optionsClassName = "", value, width = "auto", + tabIndex, } = props; const [query, setQuery] = useState(""); const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState(null); + const [isOpen, setIsOpen] = useState(false); + // refs + const dropdownRef = useRef(null); const { styles, attributes } = usePopper(referenceElement, popperElement, { placement: placement ?? "bottom-start", @@ -50,8 +57,23 @@ export const CustomSearchSelect = (props: ICustomSearchSelectProps) => { if (multiple) comboboxProps.multiple = true; + const openDropdown = () => { + setIsOpen(true); + if (referenceElement) referenceElement.focus(); + }; + const closeDropdown = () => setIsOpen(false); + const handleKeyDown = useDropdownKeyDown(openDropdown, closeDropdown, isOpen); + useOutsideClickDetector(dropdownRef, closeDropdown); + return ( - + {({ open }: { open: boolean }) => { if (open && onOpen) onOpen(); @@ -67,6 +89,7 @@ export const CustomSearchSelect = (props: ICustomSearchSelectProps) => { ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80" } ${customButtonClassName}`} + onClick={openDropdown} > {customButton} @@ -83,86 +106,89 @@ export const CustomSearchSelect = (props: ICustomSearchSelectProps) => { ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80" } ${buttonClassName}`} + onClick={openDropdown} > {label} {!noChevron && !disabled &&