From eb5366f1297d6a05aaa7acd5086710521006618a Mon Sep 17 00:00:00 2001 From: InfinityPacer <160988576+InfinityPacer@users.noreply.github.com> Date: Thu, 23 Jul 2026 23:18:25 +0800 Subject: [PATCH] fix(grid): refresh scroll target after overlay unlock (#581) --- src/components/misc/ProgressiveCardGrid.vue | 11 ++++++ .../__tests__/ProgressiveCardGrid.spec.ts | 37 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/components/misc/__tests__/ProgressiveCardGrid.spec.ts diff --git a/src/components/misc/ProgressiveCardGrid.vue b/src/components/misc/ProgressiveCardGrid.vue index 856ab717..cbefe0e1 100644 --- a/src/components/misc/ProgressiveCardGrid.vue +++ b/src/components/misc/ProgressiveCardGrid.vue @@ -70,6 +70,7 @@ let mounted = false let pendingRevealIndex: number | null = null let lastMeasuredColumnCount = 0 let lastMeasuredColumnWidth = 0 +let documentOverlayLocked = false const safeGap = computed(() => Math.max(0, props.gap)) const safeMinItemWidth = computed(() => Math.max(1, props.minItemWidth)) @@ -338,11 +339,20 @@ function releaseVisibleRange() { } function handleOverlayLockChange() { + const nextOverlayLocked = isDocumentOverlayLocked() + + if (nextOverlayLocked === documentOverlayLocked) { + return + } + + documentOverlayLocked = nextOverlayLocked + if (shouldPauseVirtualSync()) { freezeVisibleRange() return } + invalidateScrollTargetCache() releaseVisibleRange() queueLayoutSync() } @@ -790,6 +800,7 @@ function invalidateMeasurementsForLayoutChange() { onMounted(() => { mounted = true + documentOverlayLocked = isDocumentOverlayLocked() syncOverlayGridState() scrollTarget = findScrollTarget() addScrollListener(scrollTarget) diff --git a/src/components/misc/__tests__/ProgressiveCardGrid.spec.ts b/src/components/misc/__tests__/ProgressiveCardGrid.spec.ts new file mode 100644 index 00000000..62563e26 --- /dev/null +++ b/src/components/misc/__tests__/ProgressiveCardGrid.spec.ts @@ -0,0 +1,37 @@ +import ProgressiveCardGrid from '@/components/misc/ProgressiveCardGrid.vue' +import { render, waitFor } from '@testing-library/vue' +import { afterEach, describe, expect, it, vi } from 'vitest' + +describe('ProgressiveCardGrid scroll target lifecycle', () => { + afterEach(() => { + document.documentElement.classList.remove('v-overlay-scroll-blocked') + }) + + it('recomputes the scroll target after an overlay unlocks', async () => { + const scrollParent = document.createElement('div') + const addScrollListener = vi.spyOn(scrollParent, 'addEventListener') + scrollParent.style.overflowY = 'hidden' + document.body.append(scrollParent) + document.documentElement.classList.add('v-overlay-scroll-blocked') + + render(ProgressiveCardGrid, { + container: scrollParent, + props: { + items: [{ id: 1 }], + getItemKey: (item: { id: number }) => item.id, + }, + slots: { + default: '