cogsbox-state 0.5.387 → 0.5.389
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 +101 -97
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +31 -21
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1885,26 +1885,37 @@ function createProxyHandler<T>(
|
|
|
1885
1885
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1886
1886
|
|
|
1887
1887
|
// --- 1. STATE CONTROLLER ---
|
|
1888
|
-
//
|
|
1888
|
+
// --- 1. STATE CONTROLLER (CORRECTED) ---
|
|
1889
1889
|
useLayoutEffect(() => {
|
|
1890
|
-
// THIS `IF` BLOCK IS THE NEW LOGIC
|
|
1891
1890
|
const container = containerRef.current;
|
|
1891
|
+
if (!container) return;
|
|
1892
|
+
|
|
1892
1893
|
const hasNewItems = totalCount > prevTotalCountRef.current;
|
|
1893
1894
|
|
|
1894
|
-
|
|
1895
|
-
|
|
1895
|
+
// THIS IS THE NEW, IMPORTANT LOGIC FOR ANCHORING
|
|
1896
|
+
if (hasNewItems && scrollAnchorRef.current) {
|
|
1896
1897
|
const { top: prevScrollTop, height: prevScrollHeight } =
|
|
1897
1898
|
scrollAnchorRef.current;
|
|
1899
|
+
|
|
1900
|
+
// This is the key: Tell the app we are about to programmatically scroll.
|
|
1901
|
+
isProgrammaticScroll.current = true;
|
|
1902
|
+
|
|
1903
|
+
// Restore the scroll position.
|
|
1898
1904
|
container.scrollTop =
|
|
1899
1905
|
prevScrollTop + (container.scrollHeight - prevScrollHeight);
|
|
1900
|
-
|
|
1901
|
-
// IMPORTANT: Clear the anchor after using it.
|
|
1902
|
-
scrollAnchorRef.current = null;
|
|
1903
1906
|
console.log(
|
|
1904
1907
|
`ANCHOR RESTORED to scrollTop: ${container.scrollTop}`
|
|
1905
1908
|
);
|
|
1909
|
+
|
|
1910
|
+
// IMPORTANT: After the scroll, allow user scroll events again.
|
|
1911
|
+
// Use a timeout to ensure this runs after the scroll event has fired and been ignored.
|
|
1912
|
+
setTimeout(() => {
|
|
1913
|
+
isProgrammaticScroll.current = false;
|
|
1914
|
+
}, 100);
|
|
1915
|
+
|
|
1916
|
+
scrollAnchorRef.current = null; // Clear the anchor after using it.
|
|
1906
1917
|
}
|
|
1907
|
-
// YOUR
|
|
1918
|
+
// YOUR ORIGINAL LOGIC CONTINUES UNCHANGED IN THE `ELSE` BLOCK
|
|
1908
1919
|
else {
|
|
1909
1920
|
const depsChanged = !isDeepEqual(
|
|
1910
1921
|
dependencies,
|
|
@@ -1914,7 +1925,7 @@ function createProxyHandler<T>(
|
|
|
1914
1925
|
if (depsChanged) {
|
|
1915
1926
|
console.log("TRANSITION: Deps changed -> IDLE_AT_TOP");
|
|
1916
1927
|
setStatus("IDLE_AT_TOP");
|
|
1917
|
-
return;
|
|
1928
|
+
return;
|
|
1918
1929
|
}
|
|
1919
1930
|
|
|
1920
1931
|
if (
|
|
@@ -2021,35 +2032,35 @@ function createProxyHandler<T>(
|
|
|
2021
2032
|
const scrollThreshold = itemHeight;
|
|
2022
2033
|
|
|
2023
2034
|
const handleUserScroll = () => {
|
|
2035
|
+
// This guard is now critical. It will ignore our anchor restoration scroll.
|
|
2024
2036
|
if (isProgrammaticScroll.current) {
|
|
2025
2037
|
return;
|
|
2026
2038
|
}
|
|
2027
2039
|
|
|
2028
2040
|
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
2029
2041
|
|
|
2042
|
+
// Part 1: Handle Status and Anchoring
|
|
2030
2043
|
const isAtBottom =
|
|
2031
2044
|
scrollHeight - scrollTop - clientHeight < 10;
|
|
2032
2045
|
|
|
2033
2046
|
if (isAtBottom) {
|
|
2034
2047
|
if (status !== "LOCKED_AT_BOTTOM") {
|
|
2035
2048
|
setStatus("LOCKED_AT_BOTTOM");
|
|
2036
|
-
// We are at the bottom, so we don't need an anchor.
|
|
2037
|
-
scrollAnchorRef.current = null;
|
|
2038
2049
|
}
|
|
2050
|
+
// If we are at the bottom, there is no anchor needed.
|
|
2051
|
+
scrollAnchorRef.current = null;
|
|
2039
2052
|
} else {
|
|
2040
2053
|
if (status !== "IDLE_NOT_AT_BOTTOM") {
|
|
2041
2054
|
setStatus("IDLE_NOT_AT_BOTTOM");
|
|
2042
|
-
// THE USER SCROLLED UP. SET THE ANCHOR.
|
|
2043
|
-
scrollAnchorRef.current = {
|
|
2044
|
-
top: scrollTop,
|
|
2045
|
-
height: scrollHeight,
|
|
2046
|
-
};
|
|
2047
|
-
console.log(`ANCHOR SET at scrollTop: ${scrollTop}`);
|
|
2048
2055
|
}
|
|
2056
|
+
// User is scrolled up. Continuously update the anchor with their latest position.
|
|
2057
|
+
scrollAnchorRef.current = {
|
|
2058
|
+
top: scrollTop,
|
|
2059
|
+
height: scrollHeight,
|
|
2060
|
+
};
|
|
2049
2061
|
}
|
|
2050
|
-
// --- END OF MINIMAL FIX ---
|
|
2051
2062
|
|
|
2052
|
-
//
|
|
2063
|
+
// Part 2: YOUR original, working logic for updating the visible range.
|
|
2053
2064
|
if (
|
|
2054
2065
|
Math.abs(scrollTop - lastUpdateAtScrollTop.current) <
|
|
2055
2066
|
scrollThreshold
|
|
@@ -2061,7 +2072,7 @@ function createProxyHandler<T>(
|
|
|
2061
2072
|
`Threshold passed at ${scrollTop}px. Recalculating range...`
|
|
2062
2073
|
);
|
|
2063
2074
|
|
|
2064
|
-
//
|
|
2075
|
+
// ... your logic to find startIndex and endIndex ...
|
|
2065
2076
|
let high = totalCount - 1;
|
|
2066
2077
|
let low = 0;
|
|
2067
2078
|
let topItemIndex = 0;
|
|
@@ -2090,7 +2101,6 @@ function createProxyHandler<T>(
|
|
|
2090
2101
|
endIndex: Math.min(totalCount, endIndex + overscan),
|
|
2091
2102
|
});
|
|
2092
2103
|
|
|
2093
|
-
// Finally, we record that we did the work at THIS scroll position.
|
|
2094
2104
|
lastUpdateAtScrollTop.current = scrollTop;
|
|
2095
2105
|
};
|
|
2096
2106
|
|