cogsbox-state 0.5.412 → 0.5.414
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 +631 -682
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +33 -115
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1823,7 +1823,6 @@ function createProxyHandler<T>(
|
|
|
1823
1823
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1824
1824
|
const wasAtBottomRef = useRef(false);
|
|
1825
1825
|
const previousCountRef = useRef(0);
|
|
1826
|
-
const hasInitializedRef = useRef(false); // Track if we've done initial scroll
|
|
1827
1826
|
|
|
1828
1827
|
// Subscribe to shadow state updates
|
|
1829
1828
|
useEffect(() => {
|
|
@@ -1833,7 +1832,7 @@ function createProxyHandler<T>(
|
|
|
1833
1832
|
setShadowUpdateTrigger((prev) => prev + 1);
|
|
1834
1833
|
});
|
|
1835
1834
|
return unsubscribe;
|
|
1836
|
-
}, [
|
|
1835
|
+
}, []); // Empty deps - stateKey never changes
|
|
1837
1836
|
|
|
1838
1837
|
const sourceArray = getGlobalStore().getNestedState(
|
|
1839
1838
|
stateKey,
|
|
@@ -1855,13 +1854,7 @@ function createProxyHandler<T>(
|
|
|
1855
1854
|
height += measuredHeight || itemHeight;
|
|
1856
1855
|
}
|
|
1857
1856
|
return { totalHeight: height, positions: pos };
|
|
1858
|
-
}, [
|
|
1859
|
-
totalCount,
|
|
1860
|
-
stateKey,
|
|
1861
|
-
path.join("."),
|
|
1862
|
-
itemHeight,
|
|
1863
|
-
shadowUpdateTrigger,
|
|
1864
|
-
]);
|
|
1857
|
+
}, [totalCount, itemHeight, shadowUpdateTrigger]);
|
|
1865
1858
|
|
|
1866
1859
|
// Create virtual state
|
|
1867
1860
|
const virtualState = useMemo(() => {
|
|
@@ -1876,47 +1869,26 @@ function createProxyHandler<T>(
|
|
|
1876
1869
|
...meta,
|
|
1877
1870
|
validIndices,
|
|
1878
1871
|
});
|
|
1879
|
-
}, [range.startIndex, range.endIndex, sourceArray
|
|
1880
|
-
|
|
1881
|
-
// Helper to scroll to last item using stored ref
|
|
1882
|
-
const scrollToLastItem = useCallback(() => {
|
|
1883
|
-
const shadowArray =
|
|
1884
|
-
getGlobalStore.getState().getShadowMetadata(stateKey, path) ||
|
|
1885
|
-
[];
|
|
1886
|
-
const lastIndex = totalCount - 1;
|
|
1887
|
-
|
|
1888
|
-
if (lastIndex >= 0) {
|
|
1889
|
-
const lastItemData = shadowArray[lastIndex];
|
|
1890
|
-
if (lastItemData?.virtualizer?.domRef) {
|
|
1891
|
-
const element = lastItemData.virtualizer.domRef;
|
|
1892
|
-
if (element && element.scrollIntoView) {
|
|
1893
|
-
element.scrollIntoView({
|
|
1894
|
-
behavior: "auto",
|
|
1895
|
-
block: "end",
|
|
1896
|
-
inline: "nearest",
|
|
1897
|
-
});
|
|
1898
|
-
return true;
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
return false;
|
|
1903
|
-
}, [stateKey, path, totalCount]);
|
|
1872
|
+
}, [range.startIndex, range.endIndex, sourceArray]);
|
|
1904
1873
|
|
|
1905
|
-
// Handle
|
|
1874
|
+
// Handle new items when at bottom
|
|
1906
1875
|
useEffect(() => {
|
|
1907
1876
|
if (!stickToBottom || totalCount === 0) return;
|
|
1908
1877
|
|
|
1909
1878
|
const hasNewItems = totalCount > previousCountRef.current;
|
|
1910
1879
|
|
|
1911
|
-
//
|
|
1880
|
+
// Only scroll if we were at bottom AND new items arrived
|
|
1912
1881
|
if (
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1882
|
+
hasNewItems &&
|
|
1883
|
+
wasAtBottomRef.current &&
|
|
1884
|
+
previousCountRef.current > 0
|
|
1916
1885
|
) {
|
|
1917
|
-
|
|
1886
|
+
const container = containerRef.current;
|
|
1887
|
+
if (!container) return;
|
|
1888
|
+
|
|
1889
|
+
// Update range to show end
|
|
1918
1890
|
const visibleCount = Math.ceil(
|
|
1919
|
-
|
|
1891
|
+
container.clientHeight / itemHeight
|
|
1920
1892
|
);
|
|
1921
1893
|
setRange({
|
|
1922
1894
|
startIndex: Math.max(
|
|
@@ -1926,36 +1898,14 @@ function createProxyHandler<T>(
|
|
|
1926
1898
|
endIndex: totalCount,
|
|
1927
1899
|
});
|
|
1928
1900
|
|
|
1901
|
+
// Scroll to bottom after render
|
|
1929
1902
|
setTimeout(() => {
|
|
1930
|
-
|
|
1931
|
-
containerRef.current.scrollTop =
|
|
1932
|
-
containerRef.current.scrollHeight;
|
|
1933
|
-
wasAtBottomRef.current = true;
|
|
1934
|
-
}
|
|
1935
|
-
}, 100);
|
|
1936
|
-
}
|
|
1937
|
-
// New items added AFTER initial load
|
|
1938
|
-
else if (hasNewItems && wasAtBottomRef.current) {
|
|
1939
|
-
const visibleCount = Math.ceil(
|
|
1940
|
-
(containerRef.current?.clientHeight || 600) / itemHeight
|
|
1941
|
-
);
|
|
1942
|
-
const newRange = {
|
|
1943
|
-
startIndex: Math.max(
|
|
1944
|
-
0,
|
|
1945
|
-
totalCount - visibleCount - overscan
|
|
1946
|
-
),
|
|
1947
|
-
endIndex: totalCount,
|
|
1948
|
-
};
|
|
1949
|
-
|
|
1950
|
-
setRange(newRange);
|
|
1951
|
-
|
|
1952
|
-
setTimeout(() => {
|
|
1953
|
-
scrollToLastItem();
|
|
1903
|
+
container.scrollTop = container.scrollHeight;
|
|
1954
1904
|
}, 50);
|
|
1955
1905
|
}
|
|
1956
1906
|
|
|
1957
1907
|
previousCountRef.current = totalCount;
|
|
1958
|
-
}, [totalCount]); // ONLY
|
|
1908
|
+
}, [totalCount]); // ONLY totalCount - nothing else matters
|
|
1959
1909
|
|
|
1960
1910
|
// Handle scroll events
|
|
1961
1911
|
useEffect(() => {
|
|
@@ -1964,74 +1914,42 @@ function createProxyHandler<T>(
|
|
|
1964
1914
|
|
|
1965
1915
|
const handleScroll = () => {
|
|
1966
1916
|
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
1967
|
-
const distanceFromBottom =
|
|
1968
|
-
scrollHeight - scrollTop - clientHeight;
|
|
1969
|
-
|
|
1970
|
-
// Track if we're at bottom
|
|
1971
|
-
wasAtBottomRef.current = distanceFromBottom < 100;
|
|
1972
|
-
|
|
1973
|
-
// Update visible range based on scroll position
|
|
1974
|
-
let startIndex = 0;
|
|
1975
|
-
for (let i = 0; i < positions.length; i++) {
|
|
1976
|
-
if (positions[i]! > scrollTop - itemHeight * overscan) {
|
|
1977
|
-
startIndex = Math.max(0, i - 1);
|
|
1978
|
-
break;
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
1917
|
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1918
|
+
// Check if at bottom
|
|
1919
|
+
wasAtBottomRef.current =
|
|
1920
|
+
scrollHeight - scrollTop - clientHeight < 100;
|
|
1921
|
+
|
|
1922
|
+
// Calculate visible range
|
|
1923
|
+
const firstVisible = Math.floor(scrollTop / itemHeight);
|
|
1924
|
+
const lastVisible = Math.ceil(
|
|
1925
|
+
(scrollTop + clientHeight) / itemHeight
|
|
1926
|
+
);
|
|
1990
1927
|
|
|
1991
1928
|
setRange({
|
|
1992
|
-
startIndex: Math.max(0,
|
|
1993
|
-
endIndex: Math.min(totalCount,
|
|
1929
|
+
startIndex: Math.max(0, firstVisible - overscan),
|
|
1930
|
+
endIndex: Math.min(totalCount, lastVisible + overscan),
|
|
1994
1931
|
});
|
|
1995
1932
|
};
|
|
1996
1933
|
|
|
1997
1934
|
container.addEventListener("scroll", handleScroll, {
|
|
1998
1935
|
passive: true,
|
|
1999
1936
|
});
|
|
2000
|
-
|
|
2001
|
-
// Just calculate visible range, no scrolling
|
|
2002
1937
|
handleScroll();
|
|
2003
1938
|
|
|
2004
|
-
return () =>
|
|
1939
|
+
return () =>
|
|
2005
1940
|
container.removeEventListener("scroll", handleScroll);
|
|
2006
|
-
|
|
2007
|
-
}, [positions, totalCount, itemHeight, overscan]);
|
|
1941
|
+
}, [positions]); // Only re-attach when positions change
|
|
2008
1942
|
|
|
2009
1943
|
const scrollToBottom = useCallback(() => {
|
|
2010
|
-
|
|
2011
|
-
const scrolled = scrollToLastItem();
|
|
2012
|
-
if (!scrolled && containerRef.current) {
|
|
1944
|
+
if (containerRef.current) {
|
|
2013
1945
|
containerRef.current.scrollTop =
|
|
2014
1946
|
containerRef.current.scrollHeight;
|
|
1947
|
+
wasAtBottomRef.current = true;
|
|
2015
1948
|
}
|
|
2016
|
-
}, [
|
|
1949
|
+
}, []);
|
|
2017
1950
|
|
|
2018
1951
|
const scrollToIndex = useCallback(
|
|
2019
1952
|
(index: number, behavior: ScrollBehavior = "smooth") => {
|
|
2020
|
-
const shadowArray =
|
|
2021
|
-
getGlobalStore
|
|
2022
|
-
.getState()
|
|
2023
|
-
.getShadowMetadata(stateKey, path) || [];
|
|
2024
|
-
const itemData = shadowArray[index];
|
|
2025
|
-
|
|
2026
|
-
if (itemData?.virtualizer?.domRef) {
|
|
2027
|
-
const element = itemData.virtualizer.domRef;
|
|
2028
|
-
if (element && element.scrollIntoView) {
|
|
2029
|
-
element.scrollIntoView({ behavior, block: "center" });
|
|
2030
|
-
return;
|
|
2031
|
-
}
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
|
-
// Fallback to position-based scrolling
|
|
2035
1953
|
if (containerRef.current && positions[index] !== undefined) {
|
|
2036
1954
|
containerRef.current.scrollTo({
|
|
2037
1955
|
top: positions[index],
|
|
@@ -2039,7 +1957,7 @@ function createProxyHandler<T>(
|
|
|
2039
1957
|
});
|
|
2040
1958
|
}
|
|
2041
1959
|
},
|
|
2042
|
-
[positions
|
|
1960
|
+
[positions]
|
|
2043
1961
|
);
|
|
2044
1962
|
|
|
2045
1963
|
const virtualizerProps = {
|