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