alexkatz / react-tiny-popover

A simple and highly customizable popover react higher order component with no other dependencies! Typescript friendly.
MIT License
447 stars 119 forks source link

Close popover when new popover opens #109

Closed SirKadogan closed 3 years ago

SirKadogan commented 3 years ago

Currently I have a table and the last column is a button that opens the popover. When I click each button the popover opens, but it doesn't close the currently opened ones.

Clicking outside closes the popover just fine. I believe it's just not recognizing that each button is a differenty entity.

Example:

image

How can I solve that?

sezeregrek commented 3 years ago

Hi @SirKadogan, I had a workaround for this problem. It worked for me.

type Props = Omit<PopoverProps, "isOpen"> & {
    className?: string
}

const MenuBase: React.FC<Props> = ({ content, children, onClickOutside, className, ...props }) => {
    const { isOpen, closeMenu } = useMenu() // this is coming from context
    const ref = React.useRef<HTMLDivElement>(null)
    const listRef = React.useRef<HTMLDivElement>(null)

    const handleOnClickOutside = React.useCallback(
        (e: MouseEvent) => {
            const menu = ref?.current
            const list = listRef?.current

            if (!isOpen || menu?.contains(e?.target as Node) || list?.contains(e?.target as Node)) {
                return
            }

            closeMenu()
            onClickOutside?.(e)
        },
        [isOpen, onClickOutside, ref, listRef],
    )

    React.useEffect(() => {
        document.addEventListener("mousedown", handleOnClickOutside)
        return () => {
            document.removeEventListener("mousedown", handleOnClickOutside)
        }
    }, [handleOnClickOutside])

    return (
        <Popover
            isOpen={isOpen}
            align="start"
            positions={["bottom", "top"]}
            arrow={false}
            content={isOpen ? <div ref={listRef}>{content}</div> : <span />}
            {...props}
        >
            <div className={className}>
                <div ref={ref}>{children}</div> // If you put ref to parent, it doesn't work.
            </div>
        </Popover>
    )
}
Harut1991 commented 3 years ago

const PopoverWrapper = ({ children, toggleHandler, ...props }) => {

const toggle = useCallback(() => { const popoverOpened = document.getElementsByClassName('popover-opened'); popoverOpened.length && popoverOpened[0].click(); toggleHandler(); }, [toggleHandler]);

return ( <Popover toggleHandler={toggle} {...props}

{children} ); };

alexkatz commented 3 years ago

I don't think the library should close an open popover when a new one opens, since perhaps a user would actually want multiple popovers behaving independently.

I think the correct approach is to handle this functionality externally.

garciaalvaro commented 3 years ago

I believe the issue is that onClickOutside of popover A is not triggering when clicking the button that opens popover B. I noticed this behaviour in version 6.0.5.