cogsbox-state 0.5.301 → 0.5.302
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 +257 -253
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +50 -40
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1803,7 +1803,7 @@ function createProxyHandler<T>(
|
|
|
1803
1803
|
options: VirtualViewOptions
|
|
1804
1804
|
): VirtualStateObjectResult<any[]> => {
|
|
1805
1805
|
const {
|
|
1806
|
-
itemHeight = 50,
|
|
1806
|
+
itemHeight = 50,
|
|
1807
1807
|
overscan = 5,
|
|
1808
1808
|
stickToBottom = false,
|
|
1809
1809
|
} = options;
|
|
@@ -1820,6 +1820,11 @@ function createProxyHandler<T>(
|
|
|
1820
1820
|
[]
|
|
1821
1821
|
);
|
|
1822
1822
|
|
|
1823
|
+
// Track scroll position
|
|
1824
|
+
const isAtBottomRef = useRef(stickToBottom);
|
|
1825
|
+
const previousTotalCountRef = useRef(0);
|
|
1826
|
+
const isInitialMountRef = useRef(true);
|
|
1827
|
+
|
|
1823
1828
|
useEffect(() => {
|
|
1824
1829
|
const unsubscribe = getGlobalStore
|
|
1825
1830
|
.getState()
|
|
@@ -1831,10 +1836,6 @@ function createProxyHandler<T>(
|
|
|
1831
1836
|
};
|
|
1832
1837
|
}, [stateKey, forceRecalculate]);
|
|
1833
1838
|
|
|
1834
|
-
const isAtBottomRef = useRef(stickToBottom);
|
|
1835
|
-
const isInitialMountRef = useRef(true);
|
|
1836
|
-
const previousTotalCountRef = useRef(0);
|
|
1837
|
-
|
|
1838
1839
|
const sourceArray = getGlobalStore().getNestedState(
|
|
1839
1840
|
stateKey,
|
|
1840
1841
|
path
|
|
@@ -1868,46 +1869,46 @@ function createProxyHandler<T>(
|
|
|
1868
1869
|
...meta,
|
|
1869
1870
|
validIndices,
|
|
1870
1871
|
});
|
|
1871
|
-
}, [range.startIndex, range.endIndex, sourceArray]);
|
|
1872
|
+
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1872
1873
|
|
|
1873
1874
|
useLayoutEffect(() => {
|
|
1874
1875
|
const container = containerRef.current;
|
|
1875
1876
|
if (!container) return;
|
|
1876
1877
|
|
|
1878
|
+
const wasAtBottom = isAtBottomRef.current;
|
|
1877
1879
|
const listGrew = totalCount > previousTotalCountRef.current;
|
|
1878
1880
|
previousTotalCountRef.current = totalCount;
|
|
1879
1881
|
|
|
1880
|
-
const wasAtBottom = isAtBottomRef.current;
|
|
1881
|
-
|
|
1882
1882
|
const handleScroll = () => {
|
|
1883
1883
|
const { scrollTop, clientHeight, scrollHeight } = container;
|
|
1884
|
+
// Consider "at bottom" if within 10px
|
|
1884
1885
|
isAtBottomRef.current =
|
|
1885
|
-
scrollHeight - scrollTop - clientHeight <
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
high = mid - 1;
|
|
1897
|
-
}
|
|
1886
|
+
scrollHeight - scrollTop - clientHeight < 10;
|
|
1887
|
+
|
|
1888
|
+
// Binary search for start index
|
|
1889
|
+
let low = 0,
|
|
1890
|
+
high = totalCount - 1;
|
|
1891
|
+
while (low <= high) {
|
|
1892
|
+
const mid = Math.floor((low + high) / 2);
|
|
1893
|
+
if (positions[mid]! < scrollTop) {
|
|
1894
|
+
low = mid + 1;
|
|
1895
|
+
} else {
|
|
1896
|
+
high = mid - 1;
|
|
1898
1897
|
}
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1898
|
+
}
|
|
1899
|
+
const startIndex = Math.max(0, high - overscan);
|
|
1900
|
+
|
|
1901
|
+
// Find end index
|
|
1902
1902
|
let endIndex = startIndex;
|
|
1903
|
+
const visibleEnd = scrollTop + clientHeight;
|
|
1903
1904
|
while (
|
|
1904
1905
|
endIndex < totalCount &&
|
|
1905
|
-
positions[endIndex]! <
|
|
1906
|
+
positions[endIndex]! < visibleEnd
|
|
1906
1907
|
) {
|
|
1907
1908
|
endIndex++;
|
|
1908
1909
|
}
|
|
1909
|
-
startIndex = Math.max(0, startIndex - overscan);
|
|
1910
1910
|
endIndex = Math.min(totalCount, endIndex + overscan);
|
|
1911
|
+
|
|
1911
1912
|
setRange((prevRange) => {
|
|
1912
1913
|
if (
|
|
1913
1914
|
prevRange.startIndex !== startIndex ||
|
|
@@ -1922,29 +1923,35 @@ function createProxyHandler<T>(
|
|
|
1922
1923
|
container.addEventListener("scroll", handleScroll, {
|
|
1923
1924
|
passive: true,
|
|
1924
1925
|
});
|
|
1925
|
-
handleScroll();
|
|
1926
1926
|
|
|
1927
|
+
// Handle stick to bottom
|
|
1927
1928
|
if (stickToBottom) {
|
|
1928
1929
|
if (isInitialMountRef.current) {
|
|
1930
|
+
// First render - go to bottom instantly
|
|
1929
1931
|
container.scrollTo({
|
|
1930
1932
|
top: container.scrollHeight,
|
|
1931
1933
|
behavior: "auto",
|
|
1932
1934
|
});
|
|
1933
|
-
} else if (
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1935
|
+
} else if (wasAtBottom && listGrew) {
|
|
1936
|
+
// New items added and we were at bottom - stay at bottom
|
|
1937
|
+
requestAnimationFrame(() => {
|
|
1938
|
+
container.scrollTo({
|
|
1939
|
+
top: container.scrollHeight,
|
|
1940
|
+
behavior: "smooth",
|
|
1941
|
+
});
|
|
1937
1942
|
});
|
|
1938
1943
|
}
|
|
1939
1944
|
}
|
|
1940
1945
|
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1946
|
+
// Mark as no longer initial mount after first render
|
|
1947
|
+
isInitialMountRef.current = false;
|
|
1948
|
+
|
|
1949
|
+
// Run handleScroll once to set initial range
|
|
1950
|
+
handleScroll();
|
|
1944
1951
|
|
|
1945
1952
|
return () =>
|
|
1946
1953
|
container.removeEventListener("scroll", handleScroll);
|
|
1947
|
-
}, [totalCount, overscan, stickToBottom
|
|
1954
|
+
}, [totalCount, positions, overscan, stickToBottom]);
|
|
1948
1955
|
|
|
1949
1956
|
const scrollToBottom = useCallback(
|
|
1950
1957
|
(behavior: ScrollBehavior = "smooth") => {
|
|
@@ -1960,9 +1967,9 @@ function createProxyHandler<T>(
|
|
|
1960
1967
|
|
|
1961
1968
|
const scrollToIndex = useCallback(
|
|
1962
1969
|
(index: number, behavior: ScrollBehavior = "smooth") => {
|
|
1963
|
-
if (containerRef.current) {
|
|
1970
|
+
if (containerRef.current && positions[index] !== undefined) {
|
|
1964
1971
|
containerRef.current.scrollTo({
|
|
1965
|
-
top: positions[index]
|
|
1972
|
+
top: positions[index],
|
|
1966
1973
|
behavior,
|
|
1967
1974
|
});
|
|
1968
1975
|
}
|
|
@@ -1973,10 +1980,13 @@ function createProxyHandler<T>(
|
|
|
1973
1980
|
const virtualizerProps = {
|
|
1974
1981
|
outer: {
|
|
1975
1982
|
ref: containerRef,
|
|
1976
|
-
style: { overflowY: "auto", height: "100%" },
|
|
1983
|
+
style: { overflowY: "auto" as const, height: "100%" },
|
|
1977
1984
|
},
|
|
1978
1985
|
inner: {
|
|
1979
|
-
style: {
|
|
1986
|
+
style: {
|
|
1987
|
+
height: `${totalHeight}px`,
|
|
1988
|
+
position: "relative" as const,
|
|
1989
|
+
},
|
|
1980
1990
|
},
|
|
1981
1991
|
list: {
|
|
1982
1992
|
style: {
|
|
@@ -1987,7 +1997,7 @@ function createProxyHandler<T>(
|
|
|
1987
1997
|
|
|
1988
1998
|
return {
|
|
1989
1999
|
virtualState,
|
|
1990
|
-
virtualizerProps
|
|
2000
|
+
virtualizerProps,
|
|
1991
2001
|
scrollToBottom,
|
|
1992
2002
|
scrollToIndex,
|
|
1993
2003
|
};
|