cogsbox-state 0.5.360 → 0.5.362
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 +709 -699
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +87 -85
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1815,11 +1815,7 @@ function createProxyHandler<T>(
|
|
|
1815
1815
|
endIndex: 10,
|
|
1816
1816
|
});
|
|
1817
1817
|
const isLockedToBottomRef = useRef(stickToBottom);
|
|
1818
|
-
|
|
1819
|
-
// This flag prevents our own scroll animation from breaking the lock.
|
|
1820
1818
|
const isAutoScrolling = useRef(false);
|
|
1821
|
-
|
|
1822
|
-
const prevDepsRef = useRef(dependencies);
|
|
1823
1819
|
const prevTotalCountRef = useRef(0);
|
|
1824
1820
|
|
|
1825
1821
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
@@ -1840,7 +1836,6 @@ function createProxyHandler<T>(
|
|
|
1840
1836
|
const totalCount = sourceArray.length;
|
|
1841
1837
|
|
|
1842
1838
|
const { totalHeight, positions } = useMemo(() => {
|
|
1843
|
-
// ... same as before ...
|
|
1844
1839
|
const shadowArray =
|
|
1845
1840
|
getGlobalStore.getState().getShadowMetadata(stateKey, path) ||
|
|
1846
1841
|
[];
|
|
@@ -1862,7 +1857,6 @@ function createProxyHandler<T>(
|
|
|
1862
1857
|
]);
|
|
1863
1858
|
|
|
1864
1859
|
const virtualState = useMemo(() => {
|
|
1865
|
-
// ... same as before ...
|
|
1866
1860
|
const start = Math.max(0, range.startIndex);
|
|
1867
1861
|
const end = Math.min(totalCount, range.endIndex);
|
|
1868
1862
|
const validIndices = Array.from(
|
|
@@ -1876,27 +1870,90 @@ function createProxyHandler<T>(
|
|
|
1876
1870
|
});
|
|
1877
1871
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1878
1872
|
|
|
1879
|
-
//
|
|
1873
|
+
// --- PHASE 1: Detect auto-scroll need and SET THE RANGE ---
|
|
1874
|
+
useLayoutEffect(() => {
|
|
1875
|
+
const hasNewItems = totalCount > prevTotalCountRef.current;
|
|
1876
|
+
if (isLockedToBottomRef.current && hasNewItems) {
|
|
1877
|
+
console.log(
|
|
1878
|
+
"PHASE 1: Auto-scroll needed. Setting range to render the last item."
|
|
1879
|
+
);
|
|
1880
|
+
setRange({
|
|
1881
|
+
startIndex: Math.max(0, totalCount - 10 - overscan),
|
|
1882
|
+
endIndex: totalCount,
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
prevTotalCountRef.current = totalCount;
|
|
1886
|
+
}, [totalCount]);
|
|
1887
|
+
|
|
1888
|
+
// --- PHASE 2: Wait for measurement and SCROLL ---
|
|
1880
1889
|
useLayoutEffect(() => {
|
|
1881
1890
|
const container = containerRef.current;
|
|
1882
|
-
|
|
1891
|
+
const isRangeAtEnd =
|
|
1892
|
+
range.endIndex === totalCount && totalCount > 0;
|
|
1883
1893
|
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1894
|
+
if (
|
|
1895
|
+
!container ||
|
|
1896
|
+
!isLockedToBottomRef.current ||
|
|
1897
|
+
!isRangeAtEnd
|
|
1898
|
+
) {
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
console.log(
|
|
1903
|
+
"PHASE 2: Range is at the end. Starting the measurement loop."
|
|
1887
1904
|
);
|
|
1888
|
-
|
|
1905
|
+
let loopCount = 0;
|
|
1906
|
+
const intervalId = setInterval(() => {
|
|
1907
|
+
loopCount++;
|
|
1908
|
+
console.log(`LOOP ${loopCount}: Checking last item...`);
|
|
1889
1909
|
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1910
|
+
const lastItemIndex = totalCount - 1;
|
|
1911
|
+
const shadowArray =
|
|
1912
|
+
getGlobalStore
|
|
1913
|
+
.getState()
|
|
1914
|
+
.getShadowMetadata(stateKey, path) || [];
|
|
1915
|
+
const lastItemHeight =
|
|
1916
|
+
shadowArray[lastItemIndex]?.virtualizer?.itemHeight || 0;
|
|
1917
|
+
|
|
1918
|
+
if (lastItemHeight > 0) {
|
|
1919
|
+
console.log(
|
|
1920
|
+
`%cSUCCESS: Last item height is ${lastItemHeight}. Scrolling now.`,
|
|
1921
|
+
"color: green; font-weight: bold;"
|
|
1922
|
+
);
|
|
1923
|
+
clearInterval(intervalId);
|
|
1924
|
+
|
|
1925
|
+
isAutoScrolling.current = true;
|
|
1926
|
+
container.scrollTo({
|
|
1927
|
+
top: container.scrollHeight,
|
|
1928
|
+
behavior: "smooth",
|
|
1929
|
+
});
|
|
1930
|
+
setTimeout(() => {
|
|
1931
|
+
isAutoScrolling.current = false;
|
|
1932
|
+
}, 1000);
|
|
1933
|
+
} else if (loopCount > 20) {
|
|
1934
|
+
console.error(
|
|
1935
|
+
"LOOP TIMEOUT: Last item was never measured. Stopping loop."
|
|
1936
|
+
);
|
|
1937
|
+
clearInterval(intervalId);
|
|
1938
|
+
} else {
|
|
1939
|
+
console.log("...WAITING. Height is not ready.");
|
|
1940
|
+
}
|
|
1941
|
+
}, 100);
|
|
1894
1942
|
|
|
1895
|
-
|
|
1896
|
-
|
|
1943
|
+
return () => clearInterval(intervalId);
|
|
1944
|
+
}, [range.endIndex, totalCount, positions]);
|
|
1945
|
+
|
|
1946
|
+
// --- PHASE 3: Handle User Interaction and Resets ---
|
|
1947
|
+
useEffect(() => {
|
|
1948
|
+
const container = containerRef.current;
|
|
1949
|
+
if (!container) return;
|
|
1950
|
+
|
|
1951
|
+
console.log(
|
|
1952
|
+
"DEPENDENCY CHANGE: Resetting scroll lock and initial view."
|
|
1953
|
+
);
|
|
1954
|
+
isLockedToBottomRef.current = stickToBottom;
|
|
1897
1955
|
|
|
1898
1956
|
const updateVirtualRange = () => {
|
|
1899
|
-
// This is the full, non-placeholder function.
|
|
1900
1957
|
const { scrollTop, clientHeight } = container;
|
|
1901
1958
|
let low = 0,
|
|
1902
1959
|
high = totalCount - 1;
|
|
@@ -1914,72 +1971,25 @@ function createProxyHandler<T>(
|
|
|
1914
1971
|
) {
|
|
1915
1972
|
endIndex++;
|
|
1916
1973
|
}
|
|
1917
|
-
|
|
1918
|
-
startIndex,
|
|
1919
|
-
endIndex: Math.min(totalCount, endIndex + overscan),
|
|
1920
|
-
});
|
|
1921
|
-
};
|
|
1974
|
+
const newEndIndex = Math.min(totalCount, endIndex + overscan);
|
|
1922
1975
|
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
console.log("ALGORITHM: Starting...");
|
|
1928
|
-
setRange({
|
|
1929
|
-
startIndex: Math.max(0, totalCount - 10 - overscan),
|
|
1930
|
-
endIndex: totalCount,
|
|
1931
|
-
});
|
|
1932
|
-
|
|
1933
|
-
intervalId = setInterval(() => {
|
|
1934
|
-
const lastItemIndex = totalCount - 1;
|
|
1935
|
-
if (lastItemIndex < 0) {
|
|
1936
|
-
clearInterval(intervalId);
|
|
1937
|
-
return;
|
|
1938
|
-
}
|
|
1976
|
+
// --- LOGGING ADDED HERE ---
|
|
1977
|
+
console.log(
|
|
1978
|
+
`RANGE UPDATE: Start: ${startIndex}, End: ${newEndIndex}, Total: ${totalCount}`
|
|
1979
|
+
);
|
|
1939
1980
|
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
.getState()
|
|
1943
|
-
.getShadowMetadata(stateKey, path) || [];
|
|
1944
|
-
const lastItemHeight =
|
|
1945
|
-
shadowArray[lastItemIndex]?.virtualizer?.itemHeight || 0;
|
|
1946
|
-
|
|
1947
|
-
if (lastItemHeight > 0) {
|
|
1948
|
-
clearInterval(intervalId);
|
|
1949
|
-
console.log("%cSUCCESS: Scrolling now.", "color: green;");
|
|
1950
|
-
|
|
1951
|
-
// Set the flag to true before we start our animation.
|
|
1952
|
-
isAutoScrolling.current = true;
|
|
1953
|
-
|
|
1954
|
-
container.scrollTo({
|
|
1955
|
-
top: container.scrollHeight,
|
|
1956
|
-
behavior: "smooth",
|
|
1957
|
-
});
|
|
1958
|
-
|
|
1959
|
-
// After 1 second, assume animation is done and unset the flag.
|
|
1960
|
-
setTimeout(() => {
|
|
1961
|
-
isAutoScrolling.current = false;
|
|
1962
|
-
}, 1000);
|
|
1963
|
-
}
|
|
1964
|
-
}, 100);
|
|
1965
|
-
} else {
|
|
1966
|
-
updateVirtualRange();
|
|
1967
|
-
}
|
|
1981
|
+
setRange({ startIndex, endIndex: newEndIndex });
|
|
1982
|
+
};
|
|
1968
1983
|
|
|
1969
1984
|
const handleUserScroll = () => {
|
|
1970
|
-
// If our code is scrolling, ignore this event.
|
|
1971
1985
|
if (isAutoScrolling.current) return;
|
|
1972
|
-
|
|
1973
1986
|
const isAtBottom =
|
|
1974
1987
|
container.scrollHeight -
|
|
1975
1988
|
container.scrollTop -
|
|
1976
1989
|
container.clientHeight <
|
|
1977
1990
|
1;
|
|
1978
|
-
if (!isAtBottom
|
|
1979
|
-
console.log("USER SCROLL: Lock broken.");
|
|
1991
|
+
if (!isAtBottom) {
|
|
1980
1992
|
isLockedToBottomRef.current = false;
|
|
1981
|
-
// If a loop was somehow running, kill it.
|
|
1982
|
-
if (intervalId) clearInterval(intervalId);
|
|
1983
1993
|
}
|
|
1984
1994
|
updateVirtualRange();
|
|
1985
1995
|
};
|
|
@@ -1987,23 +1997,16 @@ function createProxyHandler<T>(
|
|
|
1987
1997
|
container.addEventListener("scroll", handleUserScroll, {
|
|
1988
1998
|
passive: true,
|
|
1989
1999
|
});
|
|
2000
|
+
updateVirtualRange();
|
|
1990
2001
|
|
|
1991
|
-
|
|
1992
|
-
prevDepsRef.current = dependencies;
|
|
1993
|
-
prevTotalCountRef.current = totalCount;
|
|
1994
|
-
|
|
1995
|
-
return () => {
|
|
2002
|
+
return () =>
|
|
1996
2003
|
container.removeEventListener("scroll", handleUserScroll);
|
|
1997
|
-
|
|
1998
|
-
};
|
|
1999
|
-
}, [totalCount, positions, ...dependencies]);
|
|
2004
|
+
}, [...dependencies, totalCount, positions]); // <--- THE FIX
|
|
2000
2005
|
|
|
2001
2006
|
const scrollToBottom = useCallback(
|
|
2002
2007
|
(behavior: ScrollBehavior = "smooth") => {
|
|
2003
2008
|
if (containerRef.current) {
|
|
2004
2009
|
isLockedToBottomRef.current = true;
|
|
2005
|
-
console.log("USER ACTION: Scroll lock ENABLED.");
|
|
2006
|
-
// This is a manual trigger, so we don't need the loop. Just scroll.
|
|
2007
2010
|
containerRef.current.scrollTo({
|
|
2008
2011
|
top: containerRef.current.scrollHeight,
|
|
2009
2012
|
behavior,
|
|
@@ -2017,7 +2020,6 @@ function createProxyHandler<T>(
|
|
|
2017
2020
|
(index: number, behavior: ScrollBehavior = "smooth") => {
|
|
2018
2021
|
if (containerRef.current && positions[index] !== undefined) {
|
|
2019
2022
|
isLockedToBottomRef.current = false;
|
|
2020
|
-
console.log("USER ACTION: Scroll lock DISABLED.");
|
|
2021
2023
|
containerRef.current.scrollTo({
|
|
2022
2024
|
top: positions[index],
|
|
2023
2025
|
behavior,
|