cogsbox-state 0.5.316 → 0.5.318
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 +397 -374
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +80 -57
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1814,17 +1814,13 @@ function createProxyHandler<T>(
|
|
|
1814
1814
|
endIndex: 10,
|
|
1815
1815
|
});
|
|
1816
1816
|
|
|
1817
|
-
// This ref tracks if the user is locked to the bottom.
|
|
1818
1817
|
const isLockedToBottomRef = useRef(stickToBottom);
|
|
1819
|
-
|
|
1820
|
-
// This state triggers a re-render when item heights change.
|
|
1821
1818
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1822
1819
|
|
|
1823
|
-
// Track
|
|
1824
|
-
const
|
|
1820
|
+
// Track if we've scrolled to bottom after initial load
|
|
1821
|
+
const hasScrolledToBottomRef = useRef(false);
|
|
1825
1822
|
const lastTotalCountRef = useRef(0);
|
|
1826
1823
|
|
|
1827
|
-
// Subscribe to shadow state changes with limited logging
|
|
1828
1824
|
useEffect(() => {
|
|
1829
1825
|
let updateCount = 0;
|
|
1830
1826
|
const unsubscribe = getGlobalStore
|
|
@@ -1832,7 +1828,6 @@ function createProxyHandler<T>(
|
|
|
1832
1828
|
.subscribeToShadowState(stateKey, () => {
|
|
1833
1829
|
updateCount++;
|
|
1834
1830
|
if (updateCount <= 5) {
|
|
1835
|
-
// Only log first 5 updates to avoid spam
|
|
1836
1831
|
console.log(
|
|
1837
1832
|
`[VirtualView] Shadow update #${updateCount}`
|
|
1838
1833
|
);
|
|
@@ -1852,49 +1847,65 @@ function createProxyHandler<T>(
|
|
|
1852
1847
|
`[VirtualView] Initial setup - totalCount: ${totalCount}, itemHeight: ${itemHeight}, stickToBottom: ${stickToBottom}`
|
|
1853
1848
|
);
|
|
1854
1849
|
|
|
1855
|
-
// Reset
|
|
1850
|
+
// Reset when array size changes significantly
|
|
1856
1851
|
if (totalCount !== lastTotalCountRef.current) {
|
|
1857
1852
|
console.log(
|
|
1858
1853
|
`[VirtualView] Array size changed from ${lastTotalCountRef.current} to ${totalCount}`
|
|
1859
1854
|
);
|
|
1860
|
-
|
|
1855
|
+
hasScrolledToBottomRef.current = false;
|
|
1861
1856
|
lastTotalCountRef.current = totalCount;
|
|
1862
1857
|
}
|
|
1863
1858
|
|
|
1864
|
-
// Calculate heights from shadow state
|
|
1865
|
-
const { totalHeight, positions,
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1859
|
+
// Calculate heights from shadow state
|
|
1860
|
+
const { totalHeight, positions, visibleMeasured } =
|
|
1861
|
+
useMemo(() => {
|
|
1862
|
+
const shadowArray =
|
|
1863
|
+
getGlobalStore
|
|
1864
|
+
.getState()
|
|
1865
|
+
.getShadowMetadata(stateKey, path) || [];
|
|
1866
|
+
let height = 0;
|
|
1867
|
+
const pos: number[] = [];
|
|
1868
|
+
let measuredCount = 0;
|
|
1869
|
+
let visibleMeasuredCount = 0;
|
|
1870
|
+
|
|
1871
|
+
for (let i = 0; i < totalCount; i++) {
|
|
1872
|
+
pos[i] = height;
|
|
1873
|
+
const measuredHeight =
|
|
1874
|
+
shadowArray[i]?.virtualizer?.itemHeight;
|
|
1875
|
+
if (measuredHeight) {
|
|
1876
|
+
measuredCount++;
|
|
1877
|
+
// Count measured items in current visible range
|
|
1878
|
+
if (i >= range.startIndex && i < range.endIndex) {
|
|
1879
|
+
visibleMeasuredCount++;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
height += measuredHeight || itemHeight;
|
|
1883
|
+
}
|
|
1880
1884
|
|
|
1881
|
-
|
|
1882
|
-
|
|
1885
|
+
// Check if all VISIBLE items are measured
|
|
1886
|
+
const visibleCount = range.endIndex - range.startIndex;
|
|
1887
|
+
const allVisibleMeasured =
|
|
1888
|
+
visibleMeasuredCount === visibleCount && visibleCount > 0;
|
|
1883
1889
|
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1890
|
+
console.log(
|
|
1891
|
+
`[VirtualView] Heights calc - measured: ${measuredCount}/${totalCount}, visible measured: ${visibleMeasuredCount}/${visibleCount}, totalHeight: ${height}`
|
|
1892
|
+
);
|
|
1887
1893
|
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1894
|
+
return {
|
|
1895
|
+
totalHeight: height,
|
|
1896
|
+
positions: pos,
|
|
1897
|
+
visibleMeasured: allVisibleMeasured,
|
|
1898
|
+
};
|
|
1899
|
+
}, [
|
|
1900
|
+
totalCount,
|
|
1901
|
+
stateKey,
|
|
1902
|
+
path.join("."),
|
|
1903
|
+
itemHeight,
|
|
1904
|
+
shadowUpdateTrigger,
|
|
1905
|
+
range, // Add range dependency
|
|
1906
|
+
]);
|
|
1896
1907
|
|
|
1897
|
-
// Memoize the virtualized slice
|
|
1908
|
+
// Memoize the virtualized slice
|
|
1898
1909
|
const virtualState = useMemo(() => {
|
|
1899
1910
|
const start = Math.max(0, range.startIndex);
|
|
1900
1911
|
const end = Math.min(totalCount, range.endIndex);
|
|
@@ -1914,12 +1925,11 @@ function createProxyHandler<T>(
|
|
|
1914
1925
|
});
|
|
1915
1926
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1916
1927
|
|
|
1917
|
-
//
|
|
1928
|
+
// Main layout effect
|
|
1918
1929
|
useLayoutEffect(() => {
|
|
1919
1930
|
const container = containerRef.current;
|
|
1920
1931
|
if (!container) return;
|
|
1921
1932
|
|
|
1922
|
-
// This function determines what's visible in the viewport.
|
|
1923
1933
|
const updateVirtualRange = () => {
|
|
1924
1934
|
if (!container) return;
|
|
1925
1935
|
const { scrollTop } = container;
|
|
@@ -1943,7 +1953,6 @@ function createProxyHandler<T>(
|
|
|
1943
1953
|
setRange({ startIndex, endIndex });
|
|
1944
1954
|
};
|
|
1945
1955
|
|
|
1946
|
-
// This function handles ONLY user-initiated scrolls.
|
|
1947
1956
|
const handleUserScroll = () => {
|
|
1948
1957
|
isLockedToBottomRef.current =
|
|
1949
1958
|
container.scrollHeight -
|
|
@@ -1957,38 +1966,52 @@ function createProxyHandler<T>(
|
|
|
1957
1966
|
passive: true,
|
|
1958
1967
|
});
|
|
1959
1968
|
|
|
1960
|
-
//
|
|
1969
|
+
// For stick to bottom: check conditions without triggering re-renders
|
|
1961
1970
|
if (
|
|
1962
1971
|
stickToBottom &&
|
|
1963
|
-
!
|
|
1972
|
+
!hasScrolledToBottomRef.current &&
|
|
1964
1973
|
totalCount > 0
|
|
1965
1974
|
) {
|
|
1966
|
-
|
|
1967
|
-
|
|
1975
|
+
// Check current range without dependency
|
|
1976
|
+
const currentRange = range;
|
|
1977
|
+
const atEnd = currentRange.endIndex >= totalCount - 5; // Close to end
|
|
1978
|
+
|
|
1979
|
+
if (atEnd) {
|
|
1968
1980
|
console.log(
|
|
1969
|
-
`[VirtualView]
|
|
1981
|
+
`[VirtualView] At end of list, scrolling to bottom`
|
|
1970
1982
|
);
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1983
|
+
hasScrolledToBottomRef.current = true;
|
|
1984
|
+
|
|
1985
|
+
setTimeout(() => {
|
|
1986
|
+
const scrollTarget = container.scrollHeight + 1000;
|
|
1987
|
+
container.scrollTo({
|
|
1988
|
+
top: scrollTarget,
|
|
1989
|
+
behavior: "auto",
|
|
1990
|
+
});
|
|
1991
|
+
isLockedToBottomRef.current = true;
|
|
1992
|
+
}, 50);
|
|
1976
1993
|
} else {
|
|
1977
|
-
//
|
|
1994
|
+
// Jump close to the bottom
|
|
1978
1995
|
console.log(
|
|
1979
|
-
`[VirtualView]
|
|
1996
|
+
`[VirtualView] Jumping near bottom to trigger measurements`
|
|
1980
1997
|
);
|
|
1998
|
+
const estimatedScrollPosition = Math.max(
|
|
1999
|
+
0,
|
|
2000
|
+
(totalCount - 20) * itemHeight
|
|
2001
|
+
);
|
|
2002
|
+
container.scrollTo({
|
|
2003
|
+
top: estimatedScrollPosition,
|
|
2004
|
+
behavior: "auto",
|
|
2005
|
+
});
|
|
1981
2006
|
}
|
|
1982
2007
|
}
|
|
1983
2008
|
|
|
1984
|
-
// Update the visible range on initial load.
|
|
1985
2009
|
updateVirtualRange();
|
|
1986
2010
|
|
|
1987
|
-
// Cleanup function
|
|
1988
2011
|
return () => {
|
|
1989
2012
|
container.removeEventListener("scroll", handleUserScroll);
|
|
1990
2013
|
};
|
|
1991
|
-
}, [totalCount, positions, stickToBottom
|
|
2014
|
+
}, [totalCount, positions, stickToBottom]); // Removed visibleMeasured and range.endIndex
|
|
1992
2015
|
|
|
1993
2016
|
const scrollToBottom = useCallback(
|
|
1994
2017
|
(behavior: ScrollBehavior = "smooth") => {
|