cogsbox-state 0.5.374 → 0.5.376
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CogsState.jsx +518 -510
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +53 -19
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1827,6 +1827,7 @@ function createProxyHandler<T>(
|
|
|
1827
1827
|
const isProgrammaticScroll = useRef(false);
|
|
1828
1828
|
const prevTotalCountRef = useRef(0);
|
|
1829
1829
|
const prevDepsRef = useRef(dependencies);
|
|
1830
|
+
const lastScrollTopRef = useRef(0);
|
|
1830
1831
|
|
|
1831
1832
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1832
1833
|
|
|
@@ -2000,39 +2001,71 @@ function createProxyHandler<T>(
|
|
|
2000
2001
|
const container = containerRef.current;
|
|
2001
2002
|
if (!container) return;
|
|
2002
2003
|
|
|
2004
|
+
// We no longer need a manual threshold. The `positions` array is our threshold.
|
|
2005
|
+
|
|
2003
2006
|
const handleUserScroll = () => {
|
|
2004
|
-
//
|
|
2007
|
+
// Essential check to ignore our own programmatic scrolls.
|
|
2005
2008
|
if (isProgrammaticScroll.current) {
|
|
2006
2009
|
return;
|
|
2007
2010
|
}
|
|
2011
|
+
|
|
2012
|
+
const { scrollTop, clientHeight } = container;
|
|
2013
|
+
|
|
2014
|
+
// --- Part 1: Quick state update logic (still important) ---
|
|
2008
2015
|
const isAtBottom =
|
|
2009
2016
|
container.scrollHeight -
|
|
2010
|
-
|
|
2017
|
+
scrollTop -
|
|
2011
2018
|
container.clientHeight <
|
|
2012
2019
|
1;
|
|
2013
2020
|
|
|
2014
2021
|
if (!isAtBottom) {
|
|
2015
|
-
|
|
2016
|
-
"
|
|
2017
|
-
|
|
2018
|
-
shouldNotScroll.current = true;
|
|
2019
|
-
setStatus("IDLE_NOT_AT_BOTTOM");
|
|
2022
|
+
if (status !== "IDLE_NOT_AT_BOTTOM") {
|
|
2023
|
+
setStatus("IDLE_NOT_AT_BOTTOM");
|
|
2024
|
+
}
|
|
2020
2025
|
} else {
|
|
2021
|
-
|
|
2026
|
+
if (status === "IDLE_NOT_AT_BOTTOM") {
|
|
2027
|
+
setStatus("LOCKED_AT_BOTTOM");
|
|
2028
|
+
}
|
|
2022
2029
|
}
|
|
2030
|
+
// NOTE: We've removed `shouldNotScroll` as its purpose is now better
|
|
2031
|
+
// served by the state machine itself. The state `IDLE_NOT_AT_BOTTOM`
|
|
2032
|
+
// already tells us the user has scrolled up.
|
|
2023
2033
|
|
|
2024
|
-
//
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2034
|
+
// --- Part 2: Index-Based Invalidation (The real optimization) ---
|
|
2035
|
+
|
|
2036
|
+
// Find the index of the item at the top of the viewport.
|
|
2037
|
+
// This binary search is extremely fast.
|
|
2038
|
+
let high = totalCount - 1;
|
|
2039
|
+
let low = 0;
|
|
2040
|
+
let potentialTopIndex = 0;
|
|
2029
2041
|
while (low <= high) {
|
|
2030
2042
|
const mid = Math.floor((low + high) / 2);
|
|
2031
|
-
if (positions[mid]! < scrollTop)
|
|
2032
|
-
|
|
2043
|
+
if (positions[mid]! < scrollTop) {
|
|
2044
|
+
potentialTopIndex = mid;
|
|
2045
|
+
low = mid + 1;
|
|
2046
|
+
} else {
|
|
2047
|
+
high = mid - 1;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
// Compare the potential new start index with the current one.
|
|
2052
|
+
// Remember to account for the overscan!
|
|
2053
|
+
const potentialStartIndex = Math.max(
|
|
2054
|
+
0,
|
|
2055
|
+
potentialTopIndex - overscan
|
|
2056
|
+
);
|
|
2057
|
+
if (potentialStartIndex === range.startIndex) {
|
|
2058
|
+
// The visible items haven't changed, so we do nothing.
|
|
2059
|
+
// This is the core of the optimization.
|
|
2060
|
+
return;
|
|
2033
2061
|
}
|
|
2034
|
-
|
|
2035
|
-
|
|
2062
|
+
|
|
2063
|
+
// --- Part 3: If we're here, we MUST update the range ---
|
|
2064
|
+
console.log(
|
|
2065
|
+
`Index changed from ${range.startIndex} to ${potentialStartIndex}. Updating range.`
|
|
2066
|
+
);
|
|
2067
|
+
|
|
2068
|
+
let endIndex = potentialStartIndex;
|
|
2036
2069
|
const visibleEnd = scrollTop + clientHeight;
|
|
2037
2070
|
while (
|
|
2038
2071
|
endIndex < totalCount &&
|
|
@@ -2040,8 +2073,9 @@ function createProxyHandler<T>(
|
|
|
2040
2073
|
) {
|
|
2041
2074
|
endIndex++;
|
|
2042
2075
|
}
|
|
2076
|
+
|
|
2043
2077
|
setRange({
|
|
2044
|
-
startIndex,
|
|
2078
|
+
startIndex: potentialStartIndex,
|
|
2045
2079
|
endIndex: Math.min(totalCount, endIndex + overscan),
|
|
2046
2080
|
});
|
|
2047
2081
|
};
|
|
@@ -2051,7 +2085,7 @@ function createProxyHandler<T>(
|
|
|
2051
2085
|
});
|
|
2052
2086
|
return () =>
|
|
2053
2087
|
container.removeEventListener("scroll", handleUserScroll);
|
|
2054
|
-
}, [totalCount, positions, status]); //
|
|
2088
|
+
}, [totalCount, positions, status, range.startIndex]); // Add range.startIndex!
|
|
2055
2089
|
|
|
2056
2090
|
const scrollToBottom = useCallback(() => {
|
|
2057
2091
|
console.log(
|