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]);
// 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(() => {
if (isLoading) return;
if (lastScrollRef.current == null) return;
@@ -168,8 +168,17 @@ function DatabaseViews({
let rafCount = 0;
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
// This handles Board's autoScrollForElements which may still interfere on first display
const enforceScroll = () => {
const currentScroll = scrollElement.scrollTop;
const delta = Math.abs(currentScroll - targetScroll);
@@ -185,16 +194,22 @@ function DatabaseViews({
}
rafCount++;
// Run for 3 frames (~48ms) - shorter than before since views stay mounted
if (rafCount < 3) {
// Run for 5 frames (~80ms) to catch delayed scroll changes from Board mount
if (rafCount < 5) {
rafId = requestAnimationFrame(enforceScroll);
} else {
logDebug('[DatabaseViews] scroll restoration completed', {
final: scrollElement.scrollTop,
target: targetScroll,
});
// Remove scroll listener and clean up
scrollElement.removeEventListener('scroll', preventScroll);
lastScrollRef.current = null;
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) {
cancelAnimationFrame(rafId);
}
scrollElement.removeEventListener('scroll', preventScroll);
};
}, [isLoading, viewId]);
@@ -251,20 +267,17 @@ function DatabaseViews({
className={'relative flex h-full w-full flex-1 flex-col overflow-hidden'}
style={
effectiveHeight !== null
? { height: `${effectiveHeight}px` }
? { height: `${effectiveHeight}px`, maxHeight: `${effectiveHeight}px` }
: undefined
}
>
<div
className='h-full w-full transition-opacity duration-100'
style={{
...(effectiveHeight !== null
? { minHeight: `${effectiveHeight}px`, height: `${effectiveHeight}px` }
: {}),
opacity: viewVisible ? 1 : 0,
pointerEvents: viewVisible ? undefined : 'none',
}}
aria-hidden={!viewVisible}
className='h-full w-full'
style={
effectiveHeight !== null
? { height: `${effectiveHeight}px`, maxHeight: `${effectiveHeight}px` }
: {}
}
>
<Suspense fallback={skeleton}>
<ErrorBoundary fallbackRender={ElementFallbackRender}>{view}</ErrorBoundary>

View File

@@ -67,25 +67,6 @@ export const DatabaseBlock = memo(
};
}, [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 (
<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'>
@@ -95,11 +76,6 @@ export const DatabaseBlock = memo(
contentEditable={false}
ref={containerRef}
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
selectedViewId={selectedViewId}
@@ -121,7 +97,6 @@ export const DatabaseBlock = memo(
onChangeView={onChangeView}
// eslint-disable-next-line
context={context as DatabaseContextState}
fixedHeight={EMBEDDED_DB_HEIGHT}
/>
</div>
</div>