import React, { CSSProperties, FormEvent, forwardRef, MutableRefObject, ReactElement, Ref, useEffect, useRef, } from "react"; import classnames from "classnames"; import FocusLock from "react-focus-lock"; import { Manager as PopperManager, Reference as PopperReference, Popper, } from "react-popper-2"; import { bem } from "../../utilities/bem"; import { useOutsideClick, useKeyPress } from "../../hooks"; import { Icon, ICON_TYPE } from "../Icon"; import { Flex } from "../Flex"; import { Box } from "../Box"; import { Portal } from "../Portal"; import { PopoverMenu } from "../PopoverMenu"; import { Heading } from "../Heading"; import { Input, INPUT_ICON_POSITION } from "../Input"; import { Link } from "../Link"; import { Divider } from "../Divider"; import { ORIENTATION, KEY_CODE, PopperPlacement } from "../../types"; import { CheckboxProps } from "../Checkbox"; const cn = "TableHeaderCell"; // Typescript can't actually enforce children having certain props, // so this interface doesn't work. TODO: Handle this some other way interface FilterProps extends CheckboxProps { label: string; } type ElementRefType = MutableRefObject; interface FilterDropdownMenuButtonProps { onSetVisible: (isVisible: boolean) => void; } interface FilterDropdownButtonProps { isVisible: boolean; filterApplied: boolean; } interface FilterDropdownMenuProps { hideFilterSearch: boolean; searchInputValue: string; onFilterInputChange: (e: FormEvent) => void; onFilterSelectAll: () => void; onFilterClear: () => void; filterOptions?: ReactElement[]; filterControl?: ReactElement; } interface FilterDropdownProps extends FilterDropdownMenuButtonProps, FilterDropdownMenuProps, FilterDropdownButtonProps { className?: string; } interface FilterMenuProps extends FilterDropdownMenuButtonProps, FilterDropdownMenuProps { menuRef: ElementRefType; buttonRef: ElementRefType; placement: PopperPlacement; style: CSSProperties; className?: string; } interface FilterButtonProps extends FilterDropdownMenuButtonProps, FilterDropdownButtonProps {} const FilterToggleButton = forwardRef( ( { onSetVisible, isVisible, filterApplied }: FilterButtonProps, ref: Ref, ) => { const handleButtonClick = () => { onSetVisible(!isVisible); }; return ( ); }, ); const FilterMenu = forwardRef( ( { style, placement, onSetVisible, menuRef, buttonRef, hideFilterSearch, searchInputValue, onFilterInputChange, onFilterSelectAll, onFilterClear, filterOptions, filterControl, className, }: FilterMenuProps, ref: Ref, ) => { const closeDropdown = () => { onSetVisible(false); }; useOutsideClick([menuRef, buttonRef], () => { closeDropdown(); }); useKeyPress(KEY_CODE.ESC, () => { closeDropdown(); }); const inputRef: Ref = useRef(null); useEffect(() => { if (inputRef.current !== null) { inputRef.current.focus(); } }, []); return ( Filter {!hideFilterSearch && ( <> Select All Clear )} {filterOptions || filterControl} ); }, ); export const FilterDropdown = ({ isVisible = false, filterApplied = false, onSetVisible, searchInputValue, onFilterInputChange, onFilterSelectAll, onFilterClear, filterOptions, filterControl, hideFilterSearch, className, }: FilterDropdownProps) => { const menuRef: ElementRefType = React.useRef(); const buttonRef: ElementRefType = React.useRef(); const getPopperElement = (popperElement: HTMLDivElement) => { menuRef.current = popperElement; }; const getButtonElement = (buttonElement: HTMLButtonElement) => { buttonRef.current = buttonElement; }; return ( {isVisible && ( {({ ref, placement, style }) => ( )} )} {({ ref }) => ( )} ); };