cogsbox-state 0.5.347 → 0.5.349
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 +524 -525
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +49 -65
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1813,7 +1813,12 @@ function createProxyHandler<T>(
|
|
|
1813
1813
|
startIndex: 0,
|
|
1814
1814
|
endIndex: 10,
|
|
1815
1815
|
});
|
|
1816
|
+
const sourceArray = getGlobalStore().getNestedState(
|
|
1817
|
+
stateKey,
|
|
1818
|
+
path
|
|
1819
|
+
) as any[];
|
|
1816
1820
|
const isLockedToBottomRef = useRef(stickToBottom);
|
|
1821
|
+
const prevTotalCountRef = useRef(sourceArray.length);
|
|
1817
1822
|
|
|
1818
1823
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1819
1824
|
|
|
@@ -1826,10 +1831,6 @@ function createProxyHandler<T>(
|
|
|
1826
1831
|
return unsubscribe;
|
|
1827
1832
|
}, [stateKey]);
|
|
1828
1833
|
|
|
1829
|
-
const sourceArray = getGlobalStore().getNestedState(
|
|
1830
|
-
stateKey,
|
|
1831
|
-
path
|
|
1832
|
-
) as any[];
|
|
1833
1834
|
const totalCount = sourceArray.length;
|
|
1834
1835
|
|
|
1835
1836
|
const { totalHeight, positions } = useMemo(() => {
|
|
@@ -1867,67 +1868,14 @@ function createProxyHandler<T>(
|
|
|
1867
1868
|
});
|
|
1868
1869
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1869
1870
|
|
|
1870
|
-
//
|
|
1871
|
-
// This effect is the entry point. It triggers when new items are added.
|
|
1871
|
+
// The one and only layout effect.
|
|
1872
1872
|
useLayoutEffect(() => {
|
|
1873
|
-
const container = containerRef.current;
|
|
1874
|
-
// Only run if we are supposed to be at the bottom.
|
|
1875
|
-
if (
|
|
1876
|
-
!container ||
|
|
1877
|
-
!isLockedToBottomRef.current ||
|
|
1878
|
-
totalCount === 0
|
|
1879
|
-
) {
|
|
1880
|
-
return;
|
|
1881
|
-
}
|
|
1882
|
-
|
|
1883
|
-
// STEP 1: Set the range to the end so the last items are rendered.
|
|
1884
|
-
const visibleCount = 10;
|
|
1885
|
-
setRange({
|
|
1886
|
-
startIndex: Math.max(0, totalCount - visibleCount - overscan),
|
|
1887
|
-
endIndex: totalCount,
|
|
1888
|
-
});
|
|
1889
|
-
|
|
1890
|
-
// STEP 2: Start the LOOP.
|
|
1891
|
-
let loopCount = 0;
|
|
1892
|
-
const intervalId = setInterval(() => {
|
|
1893
|
-
loopCount++;
|
|
1894
|
-
// The Check: Get the last item's height FROM THE SHADOW OBJECT.
|
|
1895
|
-
const lastItemIndex = totalCount - 1;
|
|
1896
|
-
const shadowArray =
|
|
1897
|
-
getGlobalStore
|
|
1898
|
-
.getState()
|
|
1899
|
-
.getShadowMetadata(stateKey, path) || [];
|
|
1900
|
-
const lastItemHeight =
|
|
1901
|
-
shadowArray[lastItemIndex]?.virtualizer?.itemHeight || 0;
|
|
1902
|
-
|
|
1903
|
-
if (lastItemHeight > 0) {
|
|
1904
|
-
// EXIT CONDITION MET
|
|
1905
|
-
clearInterval(intervalId); // Stop the loop.
|
|
1906
|
-
|
|
1907
|
-
// STEP 3: Scroll.
|
|
1908
|
-
container.scrollTo({
|
|
1909
|
-
top: container.scrollHeight,
|
|
1910
|
-
behavior: "smooth",
|
|
1911
|
-
});
|
|
1912
|
-
} else {
|
|
1913
|
-
if (loopCount > 20) {
|
|
1914
|
-
// Safety break
|
|
1915
|
-
clearInterval(intervalId);
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
}, 100);
|
|
1919
|
-
|
|
1920
|
-
// Cleanup: Stop the loop if the component unmounts.
|
|
1921
|
-
return () => clearInterval(intervalId);
|
|
1922
|
-
}, [totalCount]); // This whole process triggers ONLY when totalCount changes.
|
|
1923
|
-
|
|
1924
|
-
// --- THE FIX IS HERE ---
|
|
1925
|
-
// This effect now correctly handles user scrolling AND updates the view.
|
|
1926
|
-
useEffect(() => {
|
|
1927
1873
|
const container = containerRef.current;
|
|
1928
1874
|
if (!container) return;
|
|
1929
1875
|
|
|
1930
|
-
|
|
1876
|
+
const hasNewItems = totalCount > prevTotalCountRef.current;
|
|
1877
|
+
|
|
1878
|
+
// This function is now ALWAYS fresh.
|
|
1931
1879
|
const updateVirtualRange = () => {
|
|
1932
1880
|
const { scrollTop, clientHeight } = container;
|
|
1933
1881
|
let low = 0,
|
|
@@ -1952,6 +1900,39 @@ function createProxyHandler<T>(
|
|
|
1952
1900
|
});
|
|
1953
1901
|
};
|
|
1954
1902
|
|
|
1903
|
+
// --- YOUR SCROLLING LOGIC ---
|
|
1904
|
+
// It only runs if we have new items and are locked to the bottom.
|
|
1905
|
+
if (hasNewItems && isLockedToBottomRef.current) {
|
|
1906
|
+
// STEP 1: Set range to the end to start measuring.
|
|
1907
|
+
setRange({
|
|
1908
|
+
startIndex: Math.max(0, totalCount - 10 - overscan),
|
|
1909
|
+
endIndex: totalCount,
|
|
1910
|
+
});
|
|
1911
|
+
|
|
1912
|
+
// STEP 2: Start the LOOP.
|
|
1913
|
+
const intervalId = setInterval(() => {
|
|
1914
|
+
const lastItemIndex = totalCount - 1;
|
|
1915
|
+
const shadowArray =
|
|
1916
|
+
getGlobalStore
|
|
1917
|
+
.getState()
|
|
1918
|
+
.getShadowMetadata(stateKey, path) || [];
|
|
1919
|
+
const lastItemHeight =
|
|
1920
|
+
shadowArray[lastItemIndex]?.virtualizer?.itemHeight || 0;
|
|
1921
|
+
|
|
1922
|
+
if (lastItemHeight > 0) {
|
|
1923
|
+
clearInterval(intervalId);
|
|
1924
|
+
container.scrollTo({
|
|
1925
|
+
top: container.scrollHeight,
|
|
1926
|
+
behavior: "smooth",
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
}, 100);
|
|
1930
|
+
|
|
1931
|
+
// This return is the cleanup for the if-block.
|
|
1932
|
+
return () => clearInterval(intervalId);
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
// --- USER SCROLL HANDLING ---
|
|
1955
1936
|
const handleUserScroll = () => {
|
|
1956
1937
|
const isAtBottom =
|
|
1957
1938
|
container.scrollHeight -
|
|
@@ -1961,20 +1942,23 @@ function createProxyHandler<T>(
|
|
|
1961
1942
|
if (!isAtBottom) {
|
|
1962
1943
|
isLockedToBottomRef.current = false;
|
|
1963
1944
|
}
|
|
1964
|
-
// This always calls the fresh version of updateVirtualRange.
|
|
1965
1945
|
updateVirtualRange();
|
|
1966
1946
|
};
|
|
1967
1947
|
|
|
1968
1948
|
container.addEventListener("scroll", handleUserScroll, {
|
|
1969
1949
|
passive: true,
|
|
1970
1950
|
});
|
|
1971
|
-
updateVirtualRange(); //
|
|
1951
|
+
updateVirtualRange(); // Always update range for current view.
|
|
1972
1952
|
|
|
1973
|
-
// This
|
|
1953
|
+
// This return is the cleanup for the whole effect.
|
|
1974
1954
|
return () =>
|
|
1975
1955
|
container.removeEventListener("scroll", handleUserScroll);
|
|
1976
|
-
}, [totalCount, positions]); //
|
|
1956
|
+
}, [totalCount, positions]); // Re-run when layout-related data changes.
|
|
1977
1957
|
|
|
1958
|
+
// This simple effect tracks the item count for the next render.
|
|
1959
|
+
useEffect(() => {
|
|
1960
|
+
prevTotalCountRef.current = totalCount;
|
|
1961
|
+
});
|
|
1978
1962
|
const scrollToBottom = useCallback(
|
|
1979
1963
|
(behavior: ScrollBehavior = "smooth") => {
|
|
1980
1964
|
if (containerRef.current) {
|