fix: scroll to top when swithc embeded database view

This commit is contained in:
Nathan
2025-11-18 13:53:58 +08:00
parent b1ec6d45ac
commit 8f04b73050
2 changed files with 27 additions and 39 deletions

View File

@@ -153,7 +153,7 @@ function DatabaseViews({
}, [isLoading, viewVisible, layout, viewId]); }, [isLoading, viewVisible, layout, viewId]);
// Scroll restoration with RAF enforcement // Scroll restoration with RAF enforcement
// Even with keep-mounted, Board's autoScrollForElements can still interfere on first switch // Board's autoScrollForElements interferes with scroll, so we enforce for multiple frames
useEffect(() => { useEffect(() => {
if (isLoading) return; if (isLoading) return;
if (lastScrollRef.current == null) return; if (lastScrollRef.current == null) return;
@@ -168,8 +168,17 @@ function DatabaseViews({
let rafCount = 0; let rafCount = 0;
let rafId: number; let rafId: number;
// Temporarily prevent scroll events during restoration
const preventScroll = (e: Event) => {
if (scrollElement.scrollTop !== targetScroll) {
e.preventDefault();
scrollElement.scrollTop = targetScroll;
}
};
scrollElement.addEventListener('scroll', preventScroll, { passive: false });
// Use RAF loop to enforce scroll position // Use RAF loop to enforce scroll position
// This handles Board's autoScrollForElements which may still interfere on first display
const enforceScroll = () => { const enforceScroll = () => {
const currentScroll = scrollElement.scrollTop; const currentScroll = scrollElement.scrollTop;
const delta = Math.abs(currentScroll - targetScroll); const delta = Math.abs(currentScroll - targetScroll);
@@ -185,16 +194,22 @@ function DatabaseViews({
} }
rafCount++; rafCount++;
// Run for 3 frames (~48ms) - shorter than before since views stay mounted // Run for 5 frames (~80ms) to catch delayed scroll changes from Board mount
if (rafCount < 3) { if (rafCount < 5) {
rafId = requestAnimationFrame(enforceScroll); rafId = requestAnimationFrame(enforceScroll);
} else { } else {
logDebug('[DatabaseViews] scroll restoration completed', { logDebug('[DatabaseViews] scroll restoration completed', {
final: scrollElement.scrollTop, final: scrollElement.scrollTop,
target: targetScroll, target: targetScroll,
}); });
// Remove scroll listener and clean up
scrollElement.removeEventListener('scroll', preventScroll);
lastScrollRef.current = null; lastScrollRef.current = null;
setViewVisible(true); setViewVisible(true);
// Release height lock to allow view to resize to its natural height
if (!fixedHeight) {
setLockedHeight(null);
}
} }
}; };
@@ -204,6 +219,7 @@ function DatabaseViews({
if (rafId) { if (rafId) {
cancelAnimationFrame(rafId); cancelAnimationFrame(rafId);
} }
scrollElement.removeEventListener('scroll', preventScroll);
}; };
}, [isLoading, viewId]); }, [isLoading, viewId]);
@@ -251,20 +267,17 @@ function DatabaseViews({
className={'relative flex h-full w-full flex-1 flex-col overflow-hidden'} className={'relative flex h-full w-full flex-1 flex-col overflow-hidden'}
style={ style={
effectiveHeight !== null effectiveHeight !== null
? { height: `${effectiveHeight}px` } ? { height: `${effectiveHeight}px`, maxHeight: `${effectiveHeight}px` }
: undefined : undefined
} }
> >
<div <div
className='h-full w-full transition-opacity duration-100' className='h-full w-full'
style={{ style={
...(effectiveHeight !== null effectiveHeight !== null
? { minHeight: `${effectiveHeight}px`, height: `${effectiveHeight}px` } ? { height: `${effectiveHeight}px`, maxHeight: `${effectiveHeight}px` }
: {}), : {}
opacity: viewVisible ? 1 : 0, }
pointerEvents: viewVisible ? undefined : 'none',
}}
aria-hidden={!viewVisible}
> >
<Suspense fallback={skeleton}> <Suspense fallback={skeleton}>
<ErrorBoundary fallbackRender={ElementFallbackRender}>{view}</ErrorBoundary> <ErrorBoundary fallbackRender={ElementFallbackRender}>{view}</ErrorBoundary>

View File

@@ -67,25 +67,6 @@ export const DatabaseBlock = memo(
}; };
}, [doc, viewId]); }, [doc, viewId]);
const EMBEDDED_DB_HEIGHT = 560;
const logContainerSize = () => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
console.debug('[DatabaseBlock] container size', {
viewId,
selectedViewId,
width,
height: rect.height,
paddingStart,
paddingEnd,
});
};
useEffect(() => {
logContainerSize();
}, [selectedViewId, width, paddingStart, paddingEnd]);
return ( return (
<div {...attributes} contentEditable={readOnly ? false : undefined} className='relative w-full cursor-pointer'> <div {...attributes} contentEditable={readOnly ? false : undefined} className='relative w-full cursor-pointer'>
<div ref={ref} className='absolute left-0 top-0 h-full w-full caret-transparent'> <div ref={ref} className='absolute left-0 top-0 h-full w-full caret-transparent'>
@@ -95,11 +76,6 @@ export const DatabaseBlock = memo(
contentEditable={false} contentEditable={false}
ref={containerRef} ref={containerRef}
className='container-bg relative my-1 flex w-full select-none flex-col' className='container-bg relative my-1 flex w-full select-none flex-col'
style={{
minHeight: EMBEDDED_DB_HEIGHT,
height: EMBEDDED_DB_HEIGHT,
width: '100%',
}}
> >
<DatabaseContent <DatabaseContent
selectedViewId={selectedViewId} selectedViewId={selectedViewId}
@@ -121,7 +97,6 @@ export const DatabaseBlock = memo(
onChangeView={onChangeView} onChangeView={onChangeView}
// eslint-disable-next-line // eslint-disable-next-line
context={context as DatabaseContextState} context={context as DatabaseContextState}
fixedHeight={EMBEDDED_DB_HEIGHT}
/> />
</div> </div>
</div> </div>