cogsbox-state 0.5.356 → 0.5.358
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 +600 -614
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +58 -61
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1798,7 +1798,6 @@ function createProxyHandler<T>(
|
|
|
1798
1798
|
return selectedIndex ?? -1;
|
|
1799
1799
|
};
|
|
1800
1800
|
}
|
|
1801
|
-
|
|
1802
1801
|
if (prop === "useVirtualView") {
|
|
1803
1802
|
return (
|
|
1804
1803
|
options: VirtualViewOptions
|
|
@@ -1807,6 +1806,7 @@ function createProxyHandler<T>(
|
|
|
1807
1806
|
itemHeight = 50,
|
|
1808
1807
|
overscan = 6,
|
|
1809
1808
|
stickToBottom = false,
|
|
1809
|
+
dependencies = [],
|
|
1810
1810
|
} = options;
|
|
1811
1811
|
|
|
1812
1812
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
@@ -1814,9 +1814,11 @@ function createProxyHandler<T>(
|
|
|
1814
1814
|
startIndex: 0,
|
|
1815
1815
|
endIndex: 10,
|
|
1816
1816
|
});
|
|
1817
|
-
|
|
1818
1817
|
const isLockedToBottomRef = useRef(stickToBottom);
|
|
1819
|
-
|
|
1818
|
+
|
|
1819
|
+
// This ref will hold the ID of our loop so we can stop it.
|
|
1820
|
+
const scrollLoopId = useRef<NodeJS.Timeout | null>(null);
|
|
1821
|
+
|
|
1820
1822
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1821
1823
|
|
|
1822
1824
|
useEffect(() => {
|
|
@@ -1856,6 +1858,7 @@ function createProxyHandler<T>(
|
|
|
1856
1858
|
]);
|
|
1857
1859
|
|
|
1858
1860
|
const virtualState = useMemo(() => {
|
|
1861
|
+
// ... same as before ...
|
|
1859
1862
|
const start = Math.max(0, range.startIndex);
|
|
1860
1863
|
const end = Math.min(totalCount, range.endIndex);
|
|
1861
1864
|
const validIndices = Array.from(
|
|
@@ -1869,24 +1872,28 @@ function createProxyHandler<T>(
|
|
|
1869
1872
|
});
|
|
1870
1873
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1871
1874
|
|
|
1872
|
-
// ---
|
|
1873
|
-
// This
|
|
1875
|
+
// --- EFFECT #1: THE SCROLL ALGORITHM ---
|
|
1876
|
+
// This runs when the data or dependencies change.
|
|
1874
1877
|
useLayoutEffect(() => {
|
|
1875
1878
|
const container = containerRef.current;
|
|
1876
|
-
// Only run if we have new items and are supposed to be at the bottom.
|
|
1877
1879
|
if (
|
|
1878
1880
|
!container ||
|
|
1879
|
-
!
|
|
1880
|
-
|
|
1881
|
+
!stickToBottom ||
|
|
1882
|
+
!isLockedToBottomRef.current
|
|
1881
1883
|
) {
|
|
1882
1884
|
return;
|
|
1883
1885
|
}
|
|
1884
1886
|
|
|
1885
|
-
//
|
|
1887
|
+
// If a loop is already running, stop it before starting a new one.
|
|
1888
|
+
if (scrollLoopId.current) {
|
|
1889
|
+
clearInterval(scrollLoopId.current);
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1886
1892
|
console.log("ALGORITHM: Starting...");
|
|
1887
|
-
|
|
1893
|
+
|
|
1894
|
+
// STEP 1: Set range to render the last item.
|
|
1888
1895
|
setRange({
|
|
1889
|
-
startIndex: Math.max(0, totalCount -
|
|
1896
|
+
startIndex: Math.max(0, totalCount - 10 - overscan),
|
|
1890
1897
|
endIndex: totalCount,
|
|
1891
1898
|
});
|
|
1892
1899
|
|
|
@@ -1895,12 +1902,16 @@ function createProxyHandler<T>(
|
|
|
1895
1902
|
"ALGORITHM: Starting LOOP to wait for measurement."
|
|
1896
1903
|
);
|
|
1897
1904
|
let loopCount = 0;
|
|
1898
|
-
|
|
1905
|
+
scrollLoopId.current = setInterval(() => {
|
|
1899
1906
|
loopCount++;
|
|
1900
1907
|
console.log(`LOOP ${loopCount}: Checking last item...`);
|
|
1901
1908
|
|
|
1902
|
-
// The Check: Get the last item's height FROM THE SHADOW OBJECT.
|
|
1903
1909
|
const lastItemIndex = totalCount - 1;
|
|
1910
|
+
if (lastItemIndex < 0) {
|
|
1911
|
+
clearInterval(scrollLoopId.current!);
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1904
1915
|
const shadowArray =
|
|
1905
1916
|
getGlobalStore
|
|
1906
1917
|
.getState()
|
|
@@ -1909,81 +1920,68 @@ function createProxyHandler<T>(
|
|
|
1909
1920
|
shadowArray[lastItemIndex]?.virtualizer?.itemHeight || 0;
|
|
1910
1921
|
|
|
1911
1922
|
if (lastItemHeight > 0) {
|
|
1912
|
-
// EXIT CONDITION MET
|
|
1913
1923
|
console.log(
|
|
1914
|
-
`%cSUCCESS: Last item
|
|
1924
|
+
`%cSUCCESS: Last item is measured. Scrolling.`,
|
|
1915
1925
|
"color: green; font-weight: bold;"
|
|
1916
1926
|
);
|
|
1917
|
-
clearInterval(
|
|
1918
|
-
|
|
1919
|
-
|
|
1927
|
+
clearInterval(scrollLoopId.current!);
|
|
1928
|
+
scrollLoopId.current = null;
|
|
1929
|
+
|
|
1920
1930
|
container.scrollTo({
|
|
1921
1931
|
top: container.scrollHeight,
|
|
1922
1932
|
behavior: "smooth",
|
|
1923
1933
|
});
|
|
1924
|
-
setTimeout(() => {
|
|
1925
|
-
isAutoScrolling.current = false;
|
|
1926
|
-
}, 1000);
|
|
1927
1934
|
} else {
|
|
1928
1935
|
console.log("...WAITING. Height is not ready.");
|
|
1929
|
-
if (loopCount >
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
);
|
|
1934
|
-
clearInterval(intervalId);
|
|
1936
|
+
if (loopCount > 30) {
|
|
1937
|
+
console.error("LOOP TIMEOUT. Stopping.");
|
|
1938
|
+
clearInterval(scrollLoopId.current!);
|
|
1939
|
+
scrollLoopId.current = null;
|
|
1935
1940
|
}
|
|
1936
1941
|
}
|
|
1937
|
-
}, 100);
|
|
1942
|
+
}, 100);
|
|
1938
1943
|
|
|
1939
1944
|
return () => {
|
|
1940
|
-
|
|
1941
|
-
|
|
1945
|
+
if (scrollLoopId.current) {
|
|
1946
|
+
clearInterval(scrollLoopId.current);
|
|
1947
|
+
}
|
|
1942
1948
|
};
|
|
1943
|
-
}, [totalCount,
|
|
1949
|
+
}, [totalCount, ...dependencies]);
|
|
1944
1950
|
|
|
1945
|
-
//
|
|
1951
|
+
// --- EFFECT #2: USER INTERACTION & RESET ---
|
|
1952
|
+
// This handles manual scrolling and resetting when the chat changes.
|
|
1946
1953
|
useEffect(() => {
|
|
1947
1954
|
const container = containerRef.current;
|
|
1948
1955
|
if (!container) return;
|
|
1949
1956
|
|
|
1957
|
+
// When the chat changes (dependencies change), reset the lock.
|
|
1958
|
+
console.log(
|
|
1959
|
+
"DEPENDENCY CHANGE: Resetting scroll lock to:",
|
|
1960
|
+
stickToBottom
|
|
1961
|
+
);
|
|
1962
|
+
isLockedToBottomRef.current = stickToBottom;
|
|
1963
|
+
|
|
1950
1964
|
const updateVirtualRange = () => {
|
|
1951
|
-
|
|
1952
|
-
let low = 0,
|
|
1953
|
-
high = totalCount - 1;
|
|
1954
|
-
while (low <= high) {
|
|
1955
|
-
const mid = Math.floor((low + high) / 2);
|
|
1956
|
-
if (positions[mid]! < scrollTop) low = mid + 1;
|
|
1957
|
-
else high = mid - 1;
|
|
1958
|
-
}
|
|
1959
|
-
const startIndex = Math.max(0, high - overscan);
|
|
1960
|
-
let endIndex = startIndex;
|
|
1961
|
-
const visibleEnd = scrollTop + clientHeight;
|
|
1962
|
-
while (
|
|
1963
|
-
endIndex < totalCount &&
|
|
1964
|
-
positions[endIndex]! < visibleEnd
|
|
1965
|
-
) {
|
|
1966
|
-
endIndex++;
|
|
1967
|
-
}
|
|
1968
|
-
setRange({
|
|
1969
|
-
startIndex,
|
|
1970
|
-
endIndex: Math.min(totalCount, endIndex + overscan),
|
|
1971
|
-
});
|
|
1965
|
+
/* ... same as before ... */
|
|
1972
1966
|
};
|
|
1973
1967
|
|
|
1974
1968
|
const handleUserScroll = () => {
|
|
1975
|
-
if (isAutoScrolling.current) {
|
|
1976
|
-
// <--- ADD THIS CHECK
|
|
1977
|
-
return;
|
|
1978
|
-
}
|
|
1979
1969
|
const isAtBottom =
|
|
1980
1970
|
container.scrollHeight -
|
|
1981
1971
|
container.scrollTop -
|
|
1982
1972
|
container.clientHeight <
|
|
1983
1973
|
1;
|
|
1984
1974
|
if (!isAtBottom) {
|
|
1985
|
-
isLockedToBottomRef.current
|
|
1986
|
-
|
|
1975
|
+
if (isLockedToBottomRef.current) {
|
|
1976
|
+
console.log("USER SCROLL: Lock broken.");
|
|
1977
|
+
isLockedToBottomRef.current = false;
|
|
1978
|
+
// If a scroll loop was running, kill it.
|
|
1979
|
+
if (scrollLoopId.current) {
|
|
1980
|
+
clearInterval(scrollLoopId.current);
|
|
1981
|
+
scrollLoopId.current = null;
|
|
1982
|
+
console.log("...Auto-scroll loop terminated by user.");
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1987
1985
|
}
|
|
1988
1986
|
updateVirtualRange();
|
|
1989
1987
|
};
|
|
@@ -1991,12 +1989,11 @@ function createProxyHandler<T>(
|
|
|
1991
1989
|
container.addEventListener("scroll", handleUserScroll, {
|
|
1992
1990
|
passive: true,
|
|
1993
1991
|
});
|
|
1994
|
-
// Always run on mount and when data changes to show correct initial view
|
|
1995
1992
|
updateVirtualRange();
|
|
1996
1993
|
|
|
1997
1994
|
return () =>
|
|
1998
1995
|
container.removeEventListener("scroll", handleUserScroll);
|
|
1999
|
-
}, [totalCount, positions]);
|
|
1996
|
+
}, [totalCount, positions, ...dependencies]);
|
|
2000
1997
|
|
|
2001
1998
|
const scrollToBottom = useCallback(
|
|
2002
1999
|
(behavior: ScrollBehavior = "smooth") => {
|