cogsbox-state 0.5.403 → 0.5.405
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 +553 -540
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +92 -54
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1804,6 +1804,7 @@ function createProxyHandler<T>(
|
|
|
1804
1804
|
};
|
|
1805
1805
|
}
|
|
1806
1806
|
// Simplified useVirtualView approach
|
|
1807
|
+
// Optimal approach - replace the useVirtualView implementation
|
|
1807
1808
|
if (prop === "useVirtualView") {
|
|
1808
1809
|
return (
|
|
1809
1810
|
options: VirtualViewOptions
|
|
@@ -1820,9 +1821,12 @@ function createProxyHandler<T>(
|
|
|
1820
1821
|
startIndex: 0,
|
|
1821
1822
|
endIndex: 10,
|
|
1822
1823
|
});
|
|
1823
|
-
const isUserScrolling = useRef(false);
|
|
1824
|
-
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
1825
1824
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1825
|
+
const isUserScrollingRef = useRef(false);
|
|
1826
|
+
const shouldStickToBottomRef = useRef(true);
|
|
1827
|
+
const scrollToBottomIntervalRef = useRef<NodeJS.Timeout | null>(
|
|
1828
|
+
null
|
|
1829
|
+
);
|
|
1826
1830
|
|
|
1827
1831
|
// Subscribe to shadow state updates
|
|
1828
1832
|
useEffect(() => {
|
|
@@ -1877,38 +1881,79 @@ function createProxyHandler<T>(
|
|
|
1877
1881
|
});
|
|
1878
1882
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1879
1883
|
|
|
1880
|
-
//
|
|
1884
|
+
// Handle auto-scroll to bottom
|
|
1885
|
+
const [hasMounted, setHasMounted] = useState(false);
|
|
1886
|
+
|
|
1887
|
+
// Add this effect to track mounting:
|
|
1888
|
+
useEffect(() => {
|
|
1889
|
+
setHasMounted(true);
|
|
1890
|
+
}, []);
|
|
1891
|
+
|
|
1892
|
+
// Replace the auto-scroll effect with this version:
|
|
1881
1893
|
useEffect(() => {
|
|
1882
1894
|
if (!stickToBottom || !containerRef.current || totalCount === 0)
|
|
1883
1895
|
return;
|
|
1896
|
+
if (!shouldStickToBottomRef.current && hasMounted) return; // Only check shouldStickToBottom after mount
|
|
1884
1897
|
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
container.clientHeight <
|
|
1890
|
-
100;
|
|
1891
|
-
|
|
1892
|
-
// If user is near bottom or we're auto-scrolling, scroll to bottom
|
|
1893
|
-
if (isNearBottom || !isUserScrolling.current) {
|
|
1894
|
-
// Clear any pending scroll
|
|
1895
|
-
if (scrollTimeoutRef.current) {
|
|
1896
|
-
clearTimeout(scrollTimeoutRef.current);
|
|
1897
|
-
}
|
|
1898
|
+
// Clear any existing interval
|
|
1899
|
+
if (scrollToBottomIntervalRef.current) {
|
|
1900
|
+
clearInterval(scrollToBottomIntervalRef.current);
|
|
1901
|
+
}
|
|
1898
1902
|
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1903
|
+
// For initial load or big jumps, show the end immediately
|
|
1904
|
+
const jumpThreshold = 50;
|
|
1905
|
+
const isInitialLoad = range.endIndex < jumpThreshold;
|
|
1906
|
+
const isBigJump = totalCount > range.endIndex + jumpThreshold;
|
|
1907
|
+
|
|
1908
|
+
if (isInitialLoad || isBigJump) {
|
|
1909
|
+
// Jump to show the last items immediately
|
|
1910
|
+
setRange({
|
|
1911
|
+
startIndex: Math.max(0, totalCount - 20),
|
|
1912
|
+
endIndex: totalCount,
|
|
1913
|
+
});
|
|
1908
1914
|
}
|
|
1909
|
-
}, [totalCount, stickToBottom]);
|
|
1910
1915
|
|
|
1911
|
-
|
|
1916
|
+
// Keep scrolling to bottom until we're actually there
|
|
1917
|
+
let attempts = 0;
|
|
1918
|
+
const maxAttempts = 50; // 5 seconds max
|
|
1919
|
+
|
|
1920
|
+
scrollToBottomIntervalRef.current = setInterval(() => {
|
|
1921
|
+
const container = containerRef.current;
|
|
1922
|
+
if (!container) return;
|
|
1923
|
+
|
|
1924
|
+
attempts++;
|
|
1925
|
+
|
|
1926
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
1927
|
+
const currentBottom = scrollTop + clientHeight;
|
|
1928
|
+
const actualBottom = scrollHeight;
|
|
1929
|
+
const isAtBottom = actualBottom - currentBottom < 5;
|
|
1930
|
+
|
|
1931
|
+
console.log(
|
|
1932
|
+
`Scroll attempt ${attempts}: currentBottom=${currentBottom}, actualBottom=${actualBottom}, isAtBottom=${isAtBottom}, hasMounted=${hasMounted}`
|
|
1933
|
+
);
|
|
1934
|
+
|
|
1935
|
+
if (isAtBottom || attempts >= maxAttempts) {
|
|
1936
|
+
clearInterval(scrollToBottomIntervalRef.current!);
|
|
1937
|
+
scrollToBottomIntervalRef.current = null;
|
|
1938
|
+
console.log(
|
|
1939
|
+
isAtBottom ? "Reached bottom!" : "Timeout - giving up"
|
|
1940
|
+
);
|
|
1941
|
+
} else {
|
|
1942
|
+
// Use instant scroll, not smooth
|
|
1943
|
+
container.scrollTop = container.scrollHeight;
|
|
1944
|
+
}
|
|
1945
|
+
}, 100);
|
|
1946
|
+
|
|
1947
|
+
// Cleanup
|
|
1948
|
+
return () => {
|
|
1949
|
+
if (scrollToBottomIntervalRef.current) {
|
|
1950
|
+
clearInterval(scrollToBottomIntervalRef.current);
|
|
1951
|
+
scrollToBottomIntervalRef.current = null;
|
|
1952
|
+
}
|
|
1953
|
+
};
|
|
1954
|
+
}, [totalCount, stickToBottom, hasMounted]);
|
|
1955
|
+
|
|
1956
|
+
// Handle user scroll
|
|
1912
1957
|
useEffect(() => {
|
|
1913
1958
|
const container = containerRef.current;
|
|
1914
1959
|
if (!container) return;
|
|
@@ -1916,21 +1961,27 @@ function createProxyHandler<T>(
|
|
|
1916
1961
|
let scrollTimeout: NodeJS.Timeout;
|
|
1917
1962
|
|
|
1918
1963
|
const handleScroll = () => {
|
|
1919
|
-
|
|
1920
|
-
|
|
1964
|
+
if (scrollToBottomIntervalRef.current) {
|
|
1965
|
+
// Stop auto-scrolling if user scrolls
|
|
1966
|
+
clearInterval(scrollToBottomIntervalRef.current);
|
|
1967
|
+
scrollToBottomIntervalRef.current = null;
|
|
1968
|
+
}
|
|
1921
1969
|
|
|
1922
|
-
|
|
1923
|
-
|
|
1970
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
1971
|
+
const isAtBottom =
|
|
1972
|
+
scrollHeight - scrollTop - clientHeight < 10;
|
|
1973
|
+
|
|
1974
|
+
// Update whether we should stick to bottom
|
|
1975
|
+
shouldStickToBottomRef.current = isAtBottom;
|
|
1924
1976
|
|
|
1925
|
-
//
|
|
1977
|
+
// Mark as user scrolling
|
|
1978
|
+
clearTimeout(scrollTimeout);
|
|
1979
|
+
isUserScrollingRef.current = true;
|
|
1926
1980
|
scrollTimeout = setTimeout(() => {
|
|
1927
|
-
|
|
1981
|
+
isUserScrollingRef.current = false;
|
|
1928
1982
|
}, 150);
|
|
1929
1983
|
|
|
1930
1984
|
// Update visible range
|
|
1931
|
-
const { scrollTop, clientHeight } = container;
|
|
1932
|
-
|
|
1933
|
-
// Find first visible item
|
|
1934
1985
|
let startIndex = 0;
|
|
1935
1986
|
for (let i = 0; i < positions.length; i++) {
|
|
1936
1987
|
if (positions[i]! > scrollTop - itemHeight * overscan) {
|
|
@@ -1939,7 +1990,6 @@ function createProxyHandler<T>(
|
|
|
1939
1990
|
}
|
|
1940
1991
|
}
|
|
1941
1992
|
|
|
1942
|
-
// Find last visible item
|
|
1943
1993
|
let endIndex = startIndex;
|
|
1944
1994
|
const viewportEnd = scrollTop + clientHeight;
|
|
1945
1995
|
for (let i = startIndex; i < positions.length; i++) {
|
|
@@ -1958,9 +2008,7 @@ function createProxyHandler<T>(
|
|
|
1958
2008
|
container.addEventListener("scroll", handleScroll, {
|
|
1959
2009
|
passive: true,
|
|
1960
2010
|
});
|
|
1961
|
-
|
|
1962
|
-
// Initial range calculation
|
|
1963
|
-
handleScroll();
|
|
2011
|
+
handleScroll(); // Initial calculation
|
|
1964
2012
|
|
|
1965
2013
|
return () => {
|
|
1966
2014
|
container.removeEventListener("scroll", handleScroll);
|
|
@@ -1968,22 +2016,12 @@ function createProxyHandler<T>(
|
|
|
1968
2016
|
};
|
|
1969
2017
|
}, [positions, totalCount, itemHeight, overscan]);
|
|
1970
2018
|
|
|
1971
|
-
// Cleanup scroll timeout on unmount
|
|
1972
|
-
useEffect(() => {
|
|
1973
|
-
return () => {
|
|
1974
|
-
if (scrollTimeoutRef.current) {
|
|
1975
|
-
clearTimeout(scrollTimeoutRef.current);
|
|
1976
|
-
}
|
|
1977
|
-
};
|
|
1978
|
-
}, []);
|
|
1979
|
-
|
|
1980
2019
|
const scrollToBottom = useCallback(
|
|
1981
|
-
(behavior: ScrollBehavior = "
|
|
2020
|
+
(behavior: ScrollBehavior = "auto") => {
|
|
2021
|
+
shouldStickToBottomRef.current = true;
|
|
1982
2022
|
if (containerRef.current) {
|
|
1983
|
-
containerRef.current.
|
|
1984
|
-
|
|
1985
|
-
behavior,
|
|
1986
|
-
});
|
|
2023
|
+
containerRef.current.scrollTop =
|
|
2024
|
+
containerRef.current.scrollHeight;
|
|
1987
2025
|
}
|
|
1988
2026
|
},
|
|
1989
2027
|
[]
|