Skip to content

Commit 9343c77

Browse files
committed
fix(ui): prevent header bounce on scroll bottom
- Detect bottom overscroll using scrollHeight/clientHeight - Ignore scroll-up events when near bottom to prevent header popping
1 parent 1ef0309 commit 9343c77

2 files changed

Lines changed: 23 additions & 4 deletions

File tree

example-web/react2/src/components/ReactWindowMock.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ export const FixedSizeList = ({ children, itemCount, itemSize, height, width, on
2222
<div
2323
ref={ref}
2424
style={{ height, width, overflow: "auto", position: 'relative' }}
25-
onScroll={(e) => onScroll && onScroll({ scrollOffset: e.currentTarget.scrollTop })}
25+
onScroll={(e) => onScroll && onScroll({
26+
scrollOffset: e.currentTarget.scrollTop,
27+
scrollHeight: e.currentTarget.scrollHeight,
28+
clientHeight: e.currentTarget.clientHeight
29+
})}
2630
>
2731
{items}
2832
{bottomPadding > 0 && <div style={{ height: bottomPadding }} />}
@@ -64,7 +68,11 @@ export const FixedSizeGrid = ({ children, columnCount, rowCount, columnWidth, ro
6468
<div
6569
ref={ref}
6670
style={{ height, width, overflowY: "auto", overflowX: "hidden", position: 'relative', ...style }}
67-
onScroll={(e) => onScroll && onScroll({ scrollTop: e.currentTarget.scrollTop })}
71+
onScroll={(e) => onScroll && onScroll({
72+
scrollTop: e.currentTarget.scrollTop,
73+
scrollHeight: e.currentTarget.scrollHeight,
74+
clientHeight: e.currentTarget.clientHeight
75+
})}
6876
>
6977
<div style={{ height: rowCount * rowHeight + bottomPadding, width: columnWidth * columnCount }}>
7078
{items}

example-web/react2/src/hooks/useCollapsibleHeader.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const useCollapsibleHeader = (options: UseCollapsibleHeaderOptions = {})
1616
const lastScrollTop = useRef(0);
1717
const scrollRef = useRef<number>(0);
1818

19-
const handleScroll = ({ scrollOffset, scrollTop }: { scrollOffset?: number, scrollTop?: number }) => {
19+
const handleScroll = ({ scrollOffset, scrollTop, scrollHeight, clientHeight }: { scrollOffset?: number, scrollTop?: number, scrollHeight?: number, clientHeight?: number }) => {
2020
if (disabled) {
2121
setShowHeader(true);
2222
return;
@@ -25,14 +25,25 @@ export const useCollapsibleHeader = (options: UseCollapsibleHeaderOptions = {})
2525
const currentScrollTop = scrollTop ?? scrollOffset ?? 0;
2626
const scrollDelta = currentScrollTop - lastScrollTop.current;
2727

28+
// Bounce Protection: Detect if we are near the bottom
29+
// If we are at the bottom, a "scroll up" might be a bounce.
30+
let isNearBottom = false;
31+
if (scrollHeight && clientHeight) {
32+
// Buffer of 100px to be safe
33+
isNearBottom = (currentScrollTop + clientHeight) >= (scrollHeight - 100);
34+
}
35+
2836
// Threshold to prevent jitter
2937
if (Math.abs(scrollDelta) > threshold) {
3038
if (scrollDelta > 0 && currentScrollTop > triggerStart) {
3139
// Scrolling Down & checked some distance
3240
setShowHeader(false);
3341
} else if (scrollDelta < 0) {
3442
// Scrolling Up
35-
setShowHeader(true);
43+
// ONLY show header if we are NOT at the very bottom (prevent bounce triggering it)
44+
if (!isNearBottom) {
45+
setShowHeader(true);
46+
}
3647
}
3748
}
3849
lastScrollTop.current = currentScrollTop;

0 commit comments

Comments
 (0)