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 7c082b18fb..ddcc66904f 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 @@ -96,14 +96,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; }; @@ -171,15 +183,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(() => { @@ -284,7 +287,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 32173e9341..bb8176099b 100644 --- a/web/src/lib/components/timeline/base-components/timeline-day.svelte +++ b/web/src/lib/components/timeline/base-components/timeline-day.svelte @@ -25,14 +25,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; @@ -47,7 +47,7 @@ showArchiveIcon, monthGroup, timelineManager, - onScrollCompensation, + onScrollCompensationMonthInDOM, onHover, onAssetOpen, @@ -74,8 +74,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 e93d5aa3dd..cf77d872bc 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 @@ -25,7 +25,7 @@ onAssetOpen?: (dayGroup: DayGroup, asset: TimelineAsset, defaultAssetOpen: () => void) => void; onSelect?: (isSingleSelect: boolean, asset: TimelineAsset) => void; - onScrollCompensation: (compensation: { heightDelta?: number; scrollTop?: number }) => void; + onScrollCompensationMonthInDOM: (compensation: { heightDelta?: number; scrollTop?: number }) => void; } let { @@ -39,7 +39,7 @@ timelineManager, onAssetOpen, onSelect, - onScrollCompensation, + onScrollCompensationMonthInDOM, }: Props = $props(); let lastAssetMouseEvent: TimelineAsset | null = $state(null); @@ -264,7 +264,7 @@ {showArchiveIcon} {monthGroup} {timelineManager} - {onScrollCompensation} + {onScrollCompensationMonthInDOM} onHover={handleOnHover} onAssetOpen={handleOnAssetOpen} onAssetSelect={handleAssetSelect}