cogsbox-state 0.5.356 → 0.5.357
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 +550 -559
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +71 -87
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1807,6 +1807,7 @@ function createProxyHandler<T>(
|
|
|
1807
1807
|
itemHeight = 50,
|
|
1808
1808
|
overscan = 6,
|
|
1809
1809
|
stickToBottom = false,
|
|
1810
|
+
dependencies = [],
|
|
1810
1811
|
} = options;
|
|
1811
1812
|
|
|
1812
1813
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
@@ -1814,9 +1815,9 @@ function createProxyHandler<T>(
|
|
|
1814
1815
|
startIndex: 0,
|
|
1815
1816
|
endIndex: 10,
|
|
1816
1817
|
});
|
|
1817
|
-
|
|
1818
1818
|
const isLockedToBottomRef = useRef(stickToBottom);
|
|
1819
|
-
const
|
|
1819
|
+
const prevTotalCountRef = useRef(0);
|
|
1820
|
+
|
|
1820
1821
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1821
1822
|
|
|
1822
1823
|
useEffect(() => {
|
|
@@ -1869,85 +1870,17 @@ function createProxyHandler<T>(
|
|
|
1869
1870
|
});
|
|
1870
1871
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1871
1872
|
|
|
1872
|
-
//
|
|
1873
|
-
// This effect is the entry point. It triggers when new items are added.
|
|
1873
|
+
// The SINGLE effect for all layout logic.
|
|
1874
1874
|
useLayoutEffect(() => {
|
|
1875
|
-
const container = containerRef.current;
|
|
1876
|
-
// Only run if we have new items and are supposed to be at the bottom.
|
|
1877
|
-
if (
|
|
1878
|
-
!container ||
|
|
1879
|
-
!isLockedToBottomRef.current ||
|
|
1880
|
-
totalCount === 0
|
|
1881
|
-
) {
|
|
1882
|
-
return;
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
|
-
// STEP 1: Set the range to the end so the last items are rendered.
|
|
1886
|
-
console.log("ALGORITHM: Starting...");
|
|
1887
|
-
const visibleCount = 10;
|
|
1888
|
-
setRange({
|
|
1889
|
-
startIndex: Math.max(0, totalCount - visibleCount - overscan),
|
|
1890
|
-
endIndex: totalCount,
|
|
1891
|
-
});
|
|
1892
|
-
|
|
1893
|
-
// STEP 2: Start the LOOP.
|
|
1894
|
-
console.log(
|
|
1895
|
-
"ALGORITHM: Starting LOOP to wait for measurement."
|
|
1896
|
-
);
|
|
1897
|
-
let loopCount = 0;
|
|
1898
|
-
const intervalId = setInterval(() => {
|
|
1899
|
-
loopCount++;
|
|
1900
|
-
console.log(`LOOP ${loopCount}: Checking last item...`);
|
|
1901
|
-
|
|
1902
|
-
// The Check: Get the last item's height FROM THE SHADOW OBJECT.
|
|
1903
|
-
const lastItemIndex = totalCount - 1;
|
|
1904
|
-
const shadowArray =
|
|
1905
|
-
getGlobalStore
|
|
1906
|
-
.getState()
|
|
1907
|
-
.getShadowMetadata(stateKey, path) || [];
|
|
1908
|
-
const lastItemHeight =
|
|
1909
|
-
shadowArray[lastItemIndex]?.virtualizer?.itemHeight || 0;
|
|
1910
|
-
|
|
1911
|
-
if (lastItemHeight > 0) {
|
|
1912
|
-
// EXIT CONDITION MET
|
|
1913
|
-
console.log(
|
|
1914
|
-
`%cSUCCESS: Last item height is ${lastItemHeight}. Scrolling now.`,
|
|
1915
|
-
"color: green; font-weight: bold;"
|
|
1916
|
-
);
|
|
1917
|
-
clearInterval(intervalId); // Stop the loop.
|
|
1918
|
-
isAutoScrolling.current = true;
|
|
1919
|
-
// STEP 3: Scroll.
|
|
1920
|
-
container.scrollTo({
|
|
1921
|
-
top: container.scrollHeight,
|
|
1922
|
-
behavior: "smooth",
|
|
1923
|
-
});
|
|
1924
|
-
setTimeout(() => {
|
|
1925
|
-
isAutoScrolling.current = false;
|
|
1926
|
-
}, 1000);
|
|
1927
|
-
} else {
|
|
1928
|
-
console.log("...WAITING. Height is not ready.");
|
|
1929
|
-
if (loopCount > 20) {
|
|
1930
|
-
// Safety break to prevent infinite loops
|
|
1931
|
-
console.error(
|
|
1932
|
-
"LOOP TIMEOUT: Last item was never measured. Stopping loop."
|
|
1933
|
-
);
|
|
1934
|
-
clearInterval(intervalId);
|
|
1935
|
-
}
|
|
1936
|
-
}
|
|
1937
|
-
}, 100); // Check every 100ms.
|
|
1938
|
-
|
|
1939
|
-
return () => {
|
|
1940
|
-
console.log("ALGORITHM: Cleaning up loop.");
|
|
1941
|
-
clearInterval(intervalId);
|
|
1942
|
-
};
|
|
1943
|
-
}, [totalCount, totalHeight, ...(options.dependencies ?? [])]); // This whole process triggers ONLY when totalCount changes.
|
|
1944
|
-
|
|
1945
|
-
// Effect to handle user scrolling.
|
|
1946
|
-
useEffect(() => {
|
|
1947
1875
|
const container = containerRef.current;
|
|
1948
1876
|
if (!container) return;
|
|
1949
1877
|
|
|
1950
|
-
const
|
|
1878
|
+
const hasNewItems = totalCount > prevTotalCountRef.current;
|
|
1879
|
+
const shouldAutoScroll =
|
|
1880
|
+
stickToBottom && isLockedToBottomRef.current && hasNewItems;
|
|
1881
|
+
|
|
1882
|
+
// This function is for manual scrolling.
|
|
1883
|
+
const updateVirtualRangeForUser = () => {
|
|
1951
1884
|
const { scrollTop, clientHeight } = container;
|
|
1952
1885
|
let low = 0,
|
|
1953
1886
|
high = totalCount - 1;
|
|
@@ -1971,11 +1904,55 @@ function createProxyHandler<T>(
|
|
|
1971
1904
|
});
|
|
1972
1905
|
};
|
|
1973
1906
|
|
|
1907
|
+
let intervalId: NodeJS.Timeout | undefined;
|
|
1908
|
+
|
|
1909
|
+
if (shouldAutoScroll) {
|
|
1910
|
+
// --- YOUR ALGORITHM PATH ---
|
|
1911
|
+
console.log("ALGORITHM: Auto-scroll triggered.");
|
|
1912
|
+
|
|
1913
|
+
// STEP 1: LOAD THE LAST ITEM INTO THE RANGE.
|
|
1914
|
+
console.log(
|
|
1915
|
+
"...Setting range to the end to render last item."
|
|
1916
|
+
);
|
|
1917
|
+
setRange({
|
|
1918
|
+
startIndex: Math.max(0, totalCount - 10 - overscan),
|
|
1919
|
+
endIndex: totalCount,
|
|
1920
|
+
});
|
|
1921
|
+
|
|
1922
|
+
// STEP 2: START THE LOOP.
|
|
1923
|
+
console.log("...Starting loop to wait for measurement.");
|
|
1924
|
+
intervalId = setInterval(() => {
|
|
1925
|
+
const lastItemIndex = totalCount - 1;
|
|
1926
|
+
const shadowArray =
|
|
1927
|
+
getGlobalStore
|
|
1928
|
+
.getState()
|
|
1929
|
+
.getShadowMetadata(stateKey, path) || [];
|
|
1930
|
+
const lastItemHeight =
|
|
1931
|
+
shadowArray[lastItemIndex]?.virtualizer?.itemHeight || 0;
|
|
1932
|
+
|
|
1933
|
+
if (lastItemHeight > 0) {
|
|
1934
|
+
console.log(
|
|
1935
|
+
"%c...SUCCESS: Last item measured. Scrolling.",
|
|
1936
|
+
"color: green; font-weight: bold;"
|
|
1937
|
+
);
|
|
1938
|
+
clearInterval(intervalId);
|
|
1939
|
+
container.scrollTo({
|
|
1940
|
+
top: container.scrollHeight,
|
|
1941
|
+
behavior: "smooth",
|
|
1942
|
+
});
|
|
1943
|
+
} else {
|
|
1944
|
+
console.log("...WAITING for measurement.");
|
|
1945
|
+
}
|
|
1946
|
+
}, 100);
|
|
1947
|
+
} else {
|
|
1948
|
+
// --- MANUAL SCROLL PATH ---
|
|
1949
|
+
// If we are not auto-scrolling, just update the view for the user's position.
|
|
1950
|
+
updateVirtualRangeForUser();
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
// --- USER INTERACTION ---
|
|
1974
1954
|
const handleUserScroll = () => {
|
|
1975
|
-
|
|
1976
|
-
// <--- ADD THIS CHECK
|
|
1977
|
-
return;
|
|
1978
|
-
}
|
|
1955
|
+
// If the user scrolls up, break the lock.
|
|
1979
1956
|
const isAtBottom =
|
|
1980
1957
|
container.scrollHeight -
|
|
1981
1958
|
container.scrollTop -
|
|
@@ -1983,20 +1960,27 @@ function createProxyHandler<T>(
|
|
|
1983
1960
|
1;
|
|
1984
1961
|
if (!isAtBottom) {
|
|
1985
1962
|
isLockedToBottomRef.current = false;
|
|
1986
|
-
console.log("USER ACTION: Scroll lock DISABLED.");
|
|
1987
1963
|
}
|
|
1988
|
-
|
|
1964
|
+
// And update the view to where they scrolled.
|
|
1965
|
+
updateVirtualRangeForUser();
|
|
1989
1966
|
};
|
|
1990
1967
|
|
|
1991
1968
|
container.addEventListener("scroll", handleUserScroll, {
|
|
1992
1969
|
passive: true,
|
|
1993
1970
|
});
|
|
1994
|
-
// Always run on mount and when data changes to show correct initial view
|
|
1995
|
-
updateVirtualRange();
|
|
1996
1971
|
|
|
1997
|
-
return () =>
|
|
1972
|
+
return () => {
|
|
1998
1973
|
container.removeEventListener("scroll", handleUserScroll);
|
|
1999
|
-
|
|
1974
|
+
if (intervalId) {
|
|
1975
|
+
clearInterval(intervalId);
|
|
1976
|
+
}
|
|
1977
|
+
};
|
|
1978
|
+
}, [totalCount, positions, ...dependencies]);
|
|
1979
|
+
|
|
1980
|
+
// This simple effect tracks the item count for the next render.
|
|
1981
|
+
useEffect(() => {
|
|
1982
|
+
prevTotalCountRef.current = totalCount;
|
|
1983
|
+
});
|
|
2000
1984
|
|
|
2001
1985
|
const scrollToBottom = useCallback(
|
|
2002
1986
|
(behavior: ScrollBehavior = "smooth") => {
|