fix(timeline): wait for canvas width before scrolling to today
CI / Assistant Split Regression (pull_request) Has been cancelled
CI / Lint (pull_request) Has been cancelled
CI / Typecheck (pull_request) Has been cancelled
CI / Unit Tests (pull_request) Has been cancelled
CI / Build (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
CI / Fresh-Linux Docker Deploy (pull_request) Has been cancelled
CI / Release Images (pull_request) Has been cancelled
CI / Architecture Guardrails (pull_request) Has been cancelled
CI / Assistant Split Regression (pull_request) Has been cancelled
CI / Lint (pull_request) Has been cancelled
CI / Typecheck (pull_request) Has been cancelled
CI / Unit Tests (pull_request) Has been cancelled
CI / Build (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
CI / Fresh-Linux Docker Deploy (pull_request) Has been cancelled
CI / Release Images (pull_request) Has been cancelled
CI / Architecture Guardrails (pull_request) Has been cancelled
useLayoutEffect([]) fired before isInitialLoading resolved, so the scroll container had no canvas yet — scrollLeft was clipped to 0. Now the scroll-to-today fires on the first render where totalCanvasWidth becomes non-zero. The cleanup effect resets the guard on unmount so React Strict Mode's fake-unmount+remount also scrolls correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -689,15 +689,25 @@ function TimelineViewContent({
|
|||||||
const pendingLeftCompensationPx = useRef(0);
|
const pendingLeftCompensationPx = useRef(0);
|
||||||
// Flag: scroll viewport to today after the next viewStart-driven re-layout.
|
// Flag: scroll viewport to today after the next viewStart-driven re-layout.
|
||||||
const pendingScrollToTodayRef = useRef(false);
|
const pendingScrollToTodayRef = useRef(false);
|
||||||
|
// Guard reset on every real unmount (including Strict Mode fake-unmount) so the
|
||||||
// Scroll to today on mount so the viewport opens with today at the left edge.
|
// scroll-to-today fires correctly on remount.
|
||||||
// Empty deps: intentionally runs once (and twice in React Strict Mode dev, both correct).
|
const hasScrolledToTodayOnLoad = useRef(false);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
return () => {
|
||||||
|
hasScrolledToTodayOnLoad.current = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Scroll to today the first time the canvas has its full width (after initial data load).
|
||||||
|
// Depends on totalCanvasWidth so it fires after isInitialLoading → false renders the canvas.
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (totalCanvasWidth === 0) return;
|
||||||
|
if (hasScrolledToTodayOnLoad.current) return;
|
||||||
const el = scrollContainerRef.current;
|
const el = scrollContainerRef.current;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
el.scrollLeft = toLeft(today);
|
el.scrollLeft = toLeft(today);
|
||||||
}, []);
|
hasScrolledToTodayOnLoad.current = true;
|
||||||
|
}, [totalCanvasWidth, toLeft, today]);
|
||||||
|
|
||||||
// Apply scroll compensation synchronously after the canvas grows (left-extend or Today button).
|
// Apply scroll compensation synchronously after the canvas grows (left-extend or Today button).
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user