History

fix: attach wheel handler with { passive: false } to enable preventDefault

React 17+ registers onWheel handlers as passive by default, making event.preventDefault() a no-op. This caused vertical-to-horizontal scroll conversion on the turn chip strip to fail silently. Replaced the React onWheel JSX prop with a useEffect that attaches the handler via addEventListener('wheel', handler, { passive: false }) on the ref element directly.

Cursor Agent committed 8 months ago

Commit 9bf6ec71 parent f3b773f1 file · +7 −13Browse files

Unified · Split

apps/web/src/components/DiffPanel.tsx+7−13
@@ -8,15 +8,7 @@ import { · 7 unmodified lines
8import { useQuery } from "@tanstack/react-query";8import { useQuery } from "@tanstack/react-query";
9import { useParams } from "@tanstack/react-router";9import { useParams } from "@tanstack/react-router";
10import { ChevronLeftIcon, ChevronRightIcon, Columns2Icon, Rows3Icon } from "lucide-react";10import { ChevronLeftIcon, ChevronRightIcon, Columns2Icon, Rows3Icon } from "lucide-react";
11import {11import { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
12 type ReactNode,
13 type WheelEvent as ReactWheelEvent,
14 useCallback,
15 useEffect,
16 useMemo,
17 useRef,
18 useState,
19} from "react";
20import { checkpointDiffQueryOptions } from "~/lib/providerReactQuery";12import { checkpointDiffQueryOptions } from "~/lib/providerReactQuery";
21import { cn } from "~/lib/utils";13import { cn } from "~/lib/utils";
22import { isElectron } from "../env";14import { isElectron } from "../env";
@@ -92,7 +84,8 @@ interface DiffPanelProps { · 69 unmodified lines
92 84
93export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) {85export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) {
94 const workerPoolSize = useMemo(() => {86 const workerPoolSize = useMemo(() => {
95 const cores = typeof navigator === "undefined" ? 4 : Math.max(1, navigator.hardwareConcurrency || 4);87 const cores =
88 typeof navigator === "undefined" ? 4 : Math.max(1, navigator.hardwareConcurrency || 4);
96 return Math.max(2, Math.min(6, Math.floor(cores / 2)));89 return Math.max(2, Math.min(6, Math.floor(cores / 2)));
97 }, []);90 }, []);
98 91
@@ -265,7 +258,7 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { · 166 unmodified lines
265 if (!element) return;258 if (!element) return;
266 element.scrollBy({ left: offset, behavior: "smooth" });259 element.scrollBy({ left: offset, behavior: "smooth" });
267 }, []);260 }, []);
268 const onTurnStripWheel = useCallback((event: ReactWheelEvent<HTMLDivElement>) => {261 const onTurnStripWheel = useCallback((event: WheelEvent) => {
269 const element = turnStripRef.current;262 const element = turnStripRef.current;
270 if (!element) return;263 if (!element) return;
271 if (element.scrollWidth <= element.clientWidth + 1) return;264 if (element.scrollWidth <= element.clientWidth + 1) return;
@@ -282,15 +275,17 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { · 10 unmodified lines
282 updateTurnStripScrollState();275 updateTurnStripScrollState();
283 const onScroll = () => updateTurnStripScrollState();276 const onScroll = () => updateTurnStripScrollState();
284 element.addEventListener("scroll", onScroll, { passive: true });277 element.addEventListener("scroll", onScroll, { passive: true });
278 element.addEventListener("wheel", onTurnStripWheel, { passive: false });
285 279
286 const resizeObserver = new ResizeObserver(() => updateTurnStripScrollState());280 const resizeObserver = new ResizeObserver(() => updateTurnStripScrollState());
287 resizeObserver.observe(element);281 resizeObserver.observe(element);
288 282
289 return () => {283 return () => {
290 element.removeEventListener("scroll", onScroll);284 element.removeEventListener("scroll", onScroll);
285 element.removeEventListener("wheel", onTurnStripWheel);
291 resizeObserver.disconnect();286 resizeObserver.disconnect();
292 };287 };
293 }, [updateTurnStripScrollState]);288 }, [updateTurnStripScrollState, onTurnStripWheel]);
294 289
295 useEffect(() => {290 useEffect(() => {
296 updateTurnStripScrollState();291 updateTurnStripScrollState();
@@ -359,7 +354,6 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { · 62 unmodified lines
359 <div354 <div
360 ref={turnStripRef}355 ref={turnStripRef}
361 className="turn-chip-strip flex gap-1 overflow-x-auto px-8 py-0.5"356 className="turn-chip-strip flex gap-1 overflow-x-auto px-8 py-0.5"
362 onWheel={onTurnStripWheel}
363 >357 >
364 <button358 <button
365 type="button"359 type="button"