From ed57bed8e71b2e89a9350c94bda0dacc71cd4817 Mon Sep 17 00:00:00 2001 From: Morgana Allen Date: Mon, 28 Sep 2026 11:10:54 -0700 Subject: [PATCH] fix(web): skip unchanged shortcut modifier updates - 195x typing latency improvement (#13884) Co-authored-by: GPT-6 Astra --- apps/web/src/shortcutModifierState.test.ts | 68 +++++++++++++++++++++- apps/web/src/shortcutModifierState.ts | 18 +++--- 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/apps/web/src/shortcutModifierState.test.ts b/apps/web/src/shortcutModifierState.test.ts index 4ef4b3b6bf2dc0116c39f13f4065d0ffbfceb3b7..20b63220072d6c39b5178b2631ef688618825d1b 100644 --- a/apps/web/src/shortcutModifierState.test.ts +++ b/apps/web/src/shortcutModifierState.test.ts @@ -1,8 +1,13 @@ -import { describe, expect, it } from "vite-plus/test"; +// @vitest-environment jsdom + +import { act, createElement } from "react"; +import { createRoot, type Root } from "react-dom/client"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test"; import { areShortcutModifierStatesEqual, shortcutModifierStateAfterKeyboardEvent, + useShortcutModifierState, type ShortcutModifierState, } from "./shortcutModifierState"; @@ -13,6 +18,67 @@ const emptyState = (): ShortcutModifierState => ({ shiftKey: false, }); +describe("useShortcutModifierState", () => { + let root: Root; + let container: HTMLDivElement; + + beforeEach(() => { + vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true); + container = document.createElement("div"); + document.body.append(container); + root = createRoot(container); + }); + + afterEach(async () => { + await act(async () => root.unmount()); + container.remove(); + vi.unstubAllGlobals(); + }); + + it.each(["keyup", "paste", "blur"] as const)( + "does not render for unchanged modifiers after %s resets the state", + async (reset) => { + const render = vi.fn(); + function Consumer() { + render(useShortcutModifierState()); + return null; + } + await act(async () => { + root.render(createElement(Consumer)); + }); + const press = async (type: "keydown" | "keyup", key: string, shiftKey = false) => { + await act(async () => { + window.dispatchEvent(new KeyboardEvent(type, { key, shiftKey })); + }); + }; + + await press("keydown", "Shift", true); + expect(render).toHaveBeenLastCalledWith({ ...emptyState(), shiftKey: true }); + if (reset === "keyup") { + await press("keyup", "Shift"); + } else { + await act(async () => { + window.dispatchEvent(new Event(reset)); + }); + } + expect(render).toHaveBeenLastCalledWith(emptyState()); + render.mockClear(); + + for (const key of "typing") { + await press("keydown", key); + await press("keyup", key); + } + await act(async () => { + window.dispatchEvent(new Event("paste")); + window.dispatchEvent(new Event("blur")); + }); + expect(render).not.toHaveBeenCalled(); + await press("keydown", "Shift", true); + expect(render).toHaveBeenCalledExactlyOnceWith({ ...emptyState(), shiftKey: true }); + }, + ); +}); + function keyboardEventLike(type: "keydown" | "keyup", init: Partial): KeyboardEvent { return { type, diff --git a/apps/web/src/shortcutModifierState.ts b/apps/web/src/shortcutModifierState.ts index 3abeeaa3e8aa7b3723ad1e62a8637e78a3b8dd5b..15d6e0a1bcae79e30a514fd94e4e495e1a34f4cb 100644 --- a/apps/web/src/shortcutModifierState.ts +++ b/apps/web/src/shortcutModifierState.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; export interface ShortcutModifierState { metaKey: boolean; @@ -28,10 +28,18 @@ export function areShortcutModifierStatesEqual( export function useShortcutModifierState(): ShortcutModifierState { const [state, setState] = useState(EMPTY_SHORTCUT_MODIFIER_STATE); + const stateRef = useRef(EMPTY_SHORTCUT_MODIFIER_STATE); useEffect(() => { + const updateState = (next: ShortcutModifierState) => { + // Even a no-op state dispatch can cost work in the sidebar's large tree. + // Ordinary typing must return before dispatching a React update. + if (areShortcutModifierStatesEqual(stateRef.current, next)) return; + stateRef.current = next; + setState(next); + }; const onKeyboardEvent = (event: KeyboardEvent) => { - setState((current) => shortcutModifierStateAfterKeyboardEvent(current, event)); + updateState(shortcutModifierStateAfterKeyboardEvent(stateRef.current, event)); }; // Dictation tools (Wispr Flow) paste with a synthetic ⌘V whose Meta keyup // never reaches the page, so the tracked state stays "⌘ held" forever and @@ -39,11 +47,7 @@ export function useShortcutModifierState(): ShortcutModifierState { // treat it like a blur and reset. A physically held modifier re-registers // on the next real key event. const onResetEvent = () => { - setState((current) => - areShortcutModifierStatesEqual(current, EMPTY_SHORTCUT_MODIFIER_STATE) - ? current - : EMPTY_SHORTCUT_MODIFIER_STATE, - ); + updateState(EMPTY_SHORTCUT_MODIFIER_STATE); }; window.addEventListener("keydown", onKeyboardEvent, true); -- 2.54.0