cogsbox-state 0.5.360 → 0.5.361
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 +696 -686
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +80 -82
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);
|
|
1894
1924
|
|
|
1895
|
-
|
|
1896
|
-
|
|
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);
|
|
1942
|
+
|
|
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;
|
|
@@ -1920,66 +1977,15 @@ function createProxyHandler<T>(
|
|
|
1920
1977
|
});
|
|
1921
1978
|
};
|
|
1922
1979
|
|
|
1923
|
-
let intervalId: NodeJS.Timeout | undefined;
|
|
1924
|
-
|
|
1925
|
-
if (shouldStartLoop) {
|
|
1926
|
-
// --- YOUR ALGORITHM ---
|
|
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
|
-
}
|
|
1939
|
-
|
|
1940
|
-
const shadowArray =
|
|
1941
|
-
getGlobalStore
|
|
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
|
-
}
|
|
1968
|
-
|
|
1969
1980
|
const handleUserScroll = () => {
|
|
1970
|
-
// If our code is scrolling, ignore this event.
|
|
1971
1981
|
if (isAutoScrolling.current) return;
|
|
1972
|
-
|
|
1973
1982
|
const isAtBottom =
|
|
1974
1983
|
container.scrollHeight -
|
|
1975
1984
|
container.scrollTop -
|
|
1976
1985
|
container.clientHeight <
|
|
1977
1986
|
1;
|
|
1978
|
-
if (!isAtBottom
|
|
1979
|
-
console.log("USER SCROLL: Lock broken.");
|
|
1987
|
+
if (!isAtBottom) {
|
|
1980
1988
|
isLockedToBottomRef.current = false;
|
|
1981
|
-
// If a loop was somehow running, kill it.
|
|
1982
|
-
if (intervalId) clearInterval(intervalId);
|
|
1983
1989
|
}
|
|
1984
1990
|
updateVirtualRange();
|
|
1985
1991
|
};
|
|
@@ -1987,23 +1993,16 @@ function createProxyHandler<T>(
|
|
|
1987
1993
|
container.addEventListener("scroll", handleUserScroll, {
|
|
1988
1994
|
passive: true,
|
|
1989
1995
|
});
|
|
1996
|
+
updateVirtualRange();
|
|
1990
1997
|
|
|
1991
|
-
|
|
1992
|
-
prevDepsRef.current = dependencies;
|
|
1993
|
-
prevTotalCountRef.current = totalCount;
|
|
1994
|
-
|
|
1995
|
-
return () => {
|
|
1998
|
+
return () =>
|
|
1996
1999
|
container.removeEventListener("scroll", handleUserScroll);
|
|
1997
|
-
|
|
1998
|
-
};
|
|
1999
|
-
}, [totalCount, positions, ...dependencies]);
|
|
2000
|
+
}, [...dependencies]);
|
|
2000
2001
|
|
|
2001
2002
|
const scrollToBottom = useCallback(
|
|
2002
2003
|
(behavior: ScrollBehavior = "smooth") => {
|
|
2003
2004
|
if (containerRef.current) {
|
|
2004
2005
|
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
2006
|
containerRef.current.scrollTo({
|
|
2008
2007
|
top: containerRef.current.scrollHeight,
|
|
2009
2008
|
behavior,
|
|
@@ -2017,7 +2016,6 @@ function createProxyHandler<T>(
|
|
|
2017
2016
|
(index: number, behavior: ScrollBehavior = "smooth") => {
|
|
2018
2017
|
if (containerRef.current && positions[index] !== undefined) {
|
|
2019
2018
|
isLockedToBottomRef.current = false;
|
|
2020
|
-
console.log("USER ACTION: Scroll lock DISABLED.");
|
|
2021
2019
|
containerRef.current.scrollTo({
|
|
2022
2020
|
top: positions[index],
|
|
2023
2021
|
behavior,
|