From 3194bf43b1a11924865c83a2d81882cac49aace5 Mon Sep 17 00:00:00 2001 From: midzelis Date: Sun, 24 Aug 2025 18:13:16 +0000 Subject: [PATCH] refactor scrollCompensation a bit more --- .../base-timeline-viewer.svelte | 25 +++++++++++-------- .../base-components/timeline-day.svelte | 9 +++---- .../selectable-timeline-day.svelte | 6 ++--- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/web/src/lib/components/timeline/base-components/base-timeline-viewer.svelte b/web/src/lib/components/timeline/base-components/base-timeline-viewer.svelte index d037ca9ae9..5768ff2952 100644 --- a/web/src/lib/components/timeline/base-components/base-timeline-viewer.svelte +++ b/web/src/lib/components/timeline/base-components/base-timeline-viewer.svelte @@ -88,14 +88,26 @@ updateSlidingWindow(); }; + const scrollCompensation = (compensation: { heightDelta?: number; scrollTop?: number }) => { + const { heightDelta, scrollTop } = compensation; + if (heightDelta !== undefined) { + scrollBy(heightDelta); + } else if (scrollTop !== undefined) { + scrollTo(scrollTop); + } + timelineManager.clearScrollCompensation(); + }; + const getAssetHeight = (assetId: string, monthGroup: MonthGroup) => { // the following method may trigger any layouts, so need to // handle any scroll compensation that may have been set const height = monthGroup!.findAssetAbsolutePosition(assetId); + // this is in a while loop, since scrollCompensations invoke scrolls + // which may load months, triggering more scrollCompensations. Call + // this in a loop, until no more layouts occur. while (timelineManager.scrollCompensation.monthGroup) { scrollCompensation(timelineManager.scrollCompensation); - timelineManager.clearScrollCompensation(); } return height; }; @@ -163,15 +175,6 @@ // Also note: don't throttle, debounce, or otherwise do this function async - it causes flicker const updateSlidingWindow = () => timelineManager.updateSlidingWindow(element?.scrollTop || 0); - const scrollCompensation = ({ heightDelta, scrollTop }: { heightDelta?: number; scrollTop?: number }) => { - if (heightDelta !== undefined) { - scrollBy(heightDelta); - } else if (scrollTop !== undefined) { - scrollTo(scrollTop); - } - }; - const onScrollCompensation = scrollCompensation; - const topSectionResizeObserver: OnResizeCallback = ({ height }) => (timelineManager.topSectionHeight = height); onMount(() => { @@ -274,7 +277,7 @@ } onSelect?.(asset); }} - {onScrollCompensation} + onScrollCompensationMonthInDOM={scrollCompensation} /> {/if} diff --git a/web/src/lib/components/timeline/base-components/timeline-day.svelte b/web/src/lib/components/timeline/base-components/timeline-day.svelte index 64b8294080..122ebbce01 100644 --- a/web/src/lib/components/timeline/base-components/timeline-day.svelte +++ b/web/src/lib/components/timeline/base-components/timeline-day.svelte @@ -23,14 +23,14 @@ monthGroup: MonthGroup; timelineManager: TimelineManager; - onScrollCompensation: (compensation: { heightDelta?: number; scrollTop?: number }) => void; + onScrollCompensationMonthInDOM: (compensation: { heightDelta?: number; scrollTop?: number }) => void; onHover: (dayGroup: DayGroup, asset: TimelineAsset) => void; onAssetOpen: (dayGroup: DayGroup, asset: TimelineAsset) => void; onAssetSelect: (dayGroup: DayGroup, asset: TimelineAsset) => void; onDayGroupSelect: (dayGroup: DayGroup, assets: TimelineAsset[]) => void; - // these should be replaced with reactive properties in timelinemanager + // these should be replaced with reactive properties in timeline-manager.svelte.ts isDayGroupSelected: (dayGroup: DayGroup) => boolean; isAssetSelected: (asset: TimelineAsset) => boolean; isAssetSelectionCandidate: (asset: TimelineAsset) => boolean; @@ -43,7 +43,7 @@ showArchiveIcon, monthGroup, timelineManager, - onScrollCompensation, + onScrollCompensationMonthInDOM, onHover, onAssetOpen, @@ -70,8 +70,7 @@ $effect.root(() => { if (timelineManager.scrollCompensation.monthGroup === monthGroup) { - onScrollCompensation(timelineManager.scrollCompensation); - timelineManager.clearScrollCompensation(); + onScrollCompensationMonthInDOM(timelineManager.scrollCompensation); } }); diff --git a/web/src/lib/components/timeline/internal-components/selectable-timeline-day.svelte b/web/src/lib/components/timeline/internal-components/selectable-timeline-day.svelte index 715d8a3602..8d7a57a25d 100644 --- a/web/src/lib/components/timeline/internal-components/selectable-timeline-day.svelte +++ b/web/src/lib/components/timeline/internal-components/selectable-timeline-day.svelte @@ -20,7 +20,7 @@ timelineManager: TimelineManager; assetInteraction: AssetInteraction; onSelect?: (isSingleSelect: boolean, asset: TimelineAsset) => void; - onScrollCompensation: (compensation: { heightDelta?: number; scrollTop?: number }) => void; + onScrollCompensationMonthInDOM: (compensation: { heightDelta?: number; scrollTop?: number }) => void; } let { @@ -32,7 +32,7 @@ assetInteraction, timelineManager, onSelect, - onScrollCompensation, + onScrollCompensationMonthInDOM, }: Props = $props(); let lastAssetMouseEvent: TimelineAsset | null = $state(null); @@ -248,7 +248,7 @@ {showArchiveIcon} {monthGroup} {timelineManager} - {onScrollCompensation} + {onScrollCompensationMonthInDOM} onHover={handleOnHover} onAssetOpen={handleOnAssetOpen} onAssetSelect={handleAssetSelect}