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 | import { useQuery } from "@tanstack/react-query"; | 8 | import { useQuery } from "@tanstack/react-query"; |
| 9 | import { useParams } from "@tanstack/react-router"; | 9 | import { useParams } from "@tanstack/react-router"; |
| 10 | import { ChevronLeftIcon, ChevronRightIcon, Columns2Icon, Rows3Icon } from "lucide-react"; | 10 | import { ChevronLeftIcon, ChevronRightIcon, Columns2Icon, Rows3Icon } from "lucide-react"; |
| 11 | import { | 11 | import { 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"; | ||
| 20 | import { checkpointDiffQueryOptions } from "~/lib/providerReactQuery"; | 12 | import { checkpointDiffQueryOptions } from "~/lib/providerReactQuery"; |
| 21 | import { cn } from "~/lib/utils"; | 13 | import { cn } from "~/lib/utils"; |
| 22 | import { isElectron } from "../env"; | 14 | import { isElectron } from "../env"; |
| @@ -92,7 +84,8 @@ interface DiffPanelProps { · 69 unmodified lines | |||
| 92 | 84 | ||
| 93 | export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { | 85 | export 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 | <div | 354 | <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 | <button | 358 | <button |
| 365 | type="button" | 359 | type="button" |