Repository: floating-ui/floating-ui (TypeScript)

Issue:
[React] `useHover` and `useClick` no longer play nice in >= 0.24.3
`useHover` and `useClick`, no longer behave like they used to. Clicking on the button doesn't keep the popover opened after hovering off.

Works as expect with 0.24.2:
https://codesandbox.io/s/serverless-flower-f3p7yv?file=/src/Popover.tsx

Doesn't work as expected with  0.24.7:
https://codesandbox.io/s/tender-sid-gyflqh?file=/src/Popover.tsx

`ignoreMouse` doesn't seem to do anything: https://floating-ui.com/docs/useClick#ignoremouse

Steps to reproduce the behavior:
1. Hover the button
2. Click it
3. Hover off

**Expected behavior**
After clicking, the popover should remain open, even after hovering off.


**Context:**
 - OS: Windows 11
 - Browser: Chrome 
 - Version: 114.0.5735.199





Discussion:
Looks like it's caused by #2362 which moved the `dataRef.current.openEvent` assignment to be in `onOpenChange`, so the value only changes on open state changes, and not whenever the event fires (which is necessary in this case).
Fixed in `0.24.8` (releasing now)

Side note: if you want it to not close after mouseleave after click-toggling it as well (e.g. triple-click) then `move: false` should be set in `useHover`.
@atomiks awesome, thank you.



Patch:
diff --git a/packages/react/src/hooks/useClick.ts b/packages/react/src/hooks/useClick.ts
index c2348f9929..48555e7f99 100644
--- a/packages/react/src/hooks/useClick.ts
+++ b/packages/react/src/hooks/useClick.ts
@@ -71,15 +71,14 @@ export function useClick<RT extends ReferenceType = ReferenceType>(
             return;
           }
 
-          if (open) {
-            if (
-              toggle &&
-              (dataRef.current.openEvent
-                ? dataRef.current.openEvent.type === 'mousedown'
-                : true)
-            ) {
-              onOpenChange(false, event.nativeEvent);
-            }
+          if (
+            open &&
+            toggle &&
+            (dataRef.current.openEvent
+              ? dataRef.current.openEvent.type === 'mousedown'
+              : true)
+          ) {
+            onOpenChange(false, event.nativeEvent);
           } else {
             // Prevent stealing focus from the floating element
             event.preventDefault();
@@ -99,15 +98,14 @@ export function useClick<RT extends ReferenceType = ReferenceType>(
             return;
           }
 
-          if (open) {
-            if (
-              toggle &&
-              (dataRef.current.openEvent
-                ? dataRef.current.openEvent.type === 'click'
-                : true)
-            ) {
-              onOpenChange(false, event.nativeEvent);
-            }
+          if (
+            open &&
+            toggle &&
+            (dataRef.current.openEvent
+              ? dataRef.current.openEvent.type === 'click'
+              : true)
+          ) {
+            onOpenChange(false, event.nativeEvent);
           } else {
             onOpenChange(true, event.nativeEvent);
           }
@@ -130,10 +128,8 @@ export function useClick<RT extends ReferenceType = ReferenceType>(
           }
 
           if (event.key === 'Enter') {
-            if (open) {
-              if (toggle) {
-                onOpenChange(false, event.nativeEvent);
-              }
+            if (open && toggle) {
+              onOpenChange(false, event.nativeEvent);
             } else {
               onOpenChange(true, event.nativeEvent);
             }
@@ -151,10 +147,8 @@ export function useClick<RT extends ReferenceType = ReferenceType>(
 
           if (event.key === ' ' && didKeyDownRef.current) {
             didKeyDownRef.current = false;
-            if (open) {
-              if (toggle) {
-                onOpenChange(false, event.nativeEvent);
-              }
+            if (open && toggle) {
+              onOpenChange(false, event.nativeEvent);
             } else {
               onOpenChange(true, event.nativeEvent);
             }


Test patch:
diff --git a/packages/react/test/unit/useClick.test.tsx b/packages/react/test/unit/useClick.test.tsx
index 8f7b0a27d4..de243c668a 100644
--- a/packages/react/test/unit/useClick.test.tsx
+++ b/packages/react/test/unit/useClick.test.tsx
@@ -1,7 +1,7 @@
 import {act, cleanup, fireEvent, render, screen} from '@testing-library/react';
 import {useState} from 'react';
 
-import {useClick, useFloating, useInteractions} from '../../src';
+import {useClick, useFloating, useHover, useInteractions} from '../../src';
 import type {UseClickProps} from '../../src/hooks/useClick';
 
 function App({
@@ -196,3 +196,39 @@ test('ignores Space keydown on another element then keyup on the button', async
 
   expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
 });
+
+test('with useHover does not close on mouseleave after click', async () => {
+  function App() {
+    const [open, setOpen] = useState(false);
+    const {refs, context} = useFloating({
+      open,
+      onOpenChange: setOpen,
+    });
+    const {getReferenceProps, getFloatingProps} = useInteractions([
+      useHover(context),
+      useClick(context),
+    ]);
+
+    return (
+      <>
+        <button
+          {...getReferenceProps({ref: refs.setReference})}
+          data-testid="reference"
+        />
+        {open && (
+          <div role="tooltip" {...getFloatingProps({ref: refs.setFloating})} />
+        )}
+      </>
+    );
+  }
+
+  render(<App />);
+
+  const button = screen.getByTestId('reference');
+  fireEvent.mouseEnter(button);
+  fireEvent.click(button);
+  fireEvent.mouseLeave(button);
+
+  expect(screen.queryByRole('tooltip')).toBeInTheDocument();
+  cleanup();
+});