material-ui-popup-state icon indicating copy to clipboard operation
material-ui-popup-state copied to clipboard

Delay Before Popover Appears

Open shelbyt opened this issue 3 years ago • 6 comments

for the Mouse Over Interaction is it possible to have a delay (for debounce purposes) before the popover appears? i.e. Instead of the content showing up immediately, a user has to hover for about 800ms before the popover shows up.

Transition duration doesn't work because that just delays the animation, an 800ms transitionDuration just makes the fade come in over 800ms.

shelbyt avatar Dec 01 '21 19:12 shelbyt

sorry for the delay. I'm busy with work stuff so it will take me awhile to look into this. I'd be open to a PR if I don't get to it first

jedwards1211 avatar Dec 07 '21 18:12 jedwards1211

Did this ever get implemented?

braco avatar Feb 26 '22 00:02 braco

+1 for this

sidrak19 avatar Mar 21 '22 14:03 sidrak19

+1

yunxu1630 avatar Sep 21 '22 06:09 yunxu1630

I wonder has anyone found a work around to achieve this?

punkle avatar Dec 16 '22 07:12 punkle

+1.

I wonder has anyone found a work around to achieve this?

A workaround might be to wrap the event handlers returned from bindHover() to inject a delay; seems to work with some light testing. e.g. with a custom hook:

export function bindDelayedHover(popupState: PopupState, delayMs = 200) {
  const { onTouchStart, onMouseOver, onMouseLeave, ...hoverAriaProps } =
    bindHover(popupState);

  const timeout = useRef<NodeJS.Timeout | null>(null);

  const delayedMouseOver = useCallback(
    (e: React.MouseEvent) => {
      if (timeout.current) clearTimeout(timeout.current);

      // material-ui-popup-state's event handler uses currentTarget to set the anchorEl, but
      // currentTarget is only defined while the initial event is firing. Save the original
      // and set it again before calling the delayed event handler
      const { currentTarget } = e;
      timeout.current = setTimeout(() => {
        e.currentTarget = currentTarget;
        onMouseOver(e);
      }, delayMs);
    },
    [onMouseOver]
  );

  const handleMouseLeave = useCallback(
    (e: React.MouseEvent) => {
      if (timeout.current) clearTimeout(timeout.current);
      onMouseLeave(e);
    },
    [onMouseLeave]
  );

  return {
    onTouchStart,
    onMouseOver: delayedMouseOver,
    onMouseLeave: handleMouseLeave,
    ...hoverAriaProps,
  };
}

Sample usage:

const popupState = usePopupState({
  variant: "popover",
  popupId: "example"
});

return (
  <>
    <span {...bindDelayedHover(popupState, 500)}>
      Example Hover
    </span>
    <HoverMenu
      {...bindMenu(popupState)}
      ...

mfen avatar Apr 14 '23 19:04 mfen