From cbd6fb817c5ca095f7d6f279c7833b4d0e9a5712 Mon Sep 17 00:00:00 2001 From: Julien BIANCHI Date: Tue, 27 Oct 2026 08:22:00 +0100 Subject: [PATCH] fix: keep a click landing as a tooltip arms on its button A tooltip mounts once a pointer enters its trigger, mounting the trigger again. React renders that later than the pointer entering, so a click following it at once could press the old trigger and be released on the new one, and the browser fired no click: in WebKit, a click on the commit's delete button right after the pointer reached it was lost about one time in five. The tooltip now arms at once, before the press. Not unit-tested: the unit tests have no DOM. Checked with Playwright in WebKit, clicking the delete button as the pointer reaches it: 3 lost clicks in 15 before, none after; tabbing onto the composer's buttons still shows their tooltips. --- resources/js/components/ui/tooltip.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/js/components/ui/tooltip.tsx b/resources/js/components/ui/tooltip.tsx index 9680d9c01..151590950 100644 --- a/resources/js/components/ui/tooltip.tsx +++ b/resources/js/components/ui/tooltip.tsx @@ -1,6 +1,7 @@ import { Slot } from "@radix-ui/react-slot" import * as TooltipPrimitive from "@radix-ui/react-tooltip" import * as React from "react" +import { flushSync } from "react-dom" import { cn } from "@/lib/utils" @@ -47,7 +48,9 @@ function Tooltip({ isArmed, arm: (byFocus) => { takesFocus.current = byFocus - setHasArmed(true) + // At once: React waits to render after a pointer enters, and a click landing meanwhile would press the trigger + // before it is mounted again and be released on the new one, which loses it. + flushSync(() => setHasArmed(true)) }, consumeFocus: () => { const takes = takesFocus.current