cogsbox-state 0.5.305 → 0.5.307
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 +396 -392
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +62 -37
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1814,10 +1814,21 @@ function createProxyHandler<T>(
|
|
|
1814
1814
|
endIndex: 10,
|
|
1815
1815
|
});
|
|
1816
1816
|
|
|
1817
|
+
// Force re-render when heights change
|
|
1818
|
+
const [, forceUpdate] = useState({});
|
|
1819
|
+
|
|
1817
1820
|
const isAtBottomRef = useRef(stickToBottom);
|
|
1818
1821
|
const previousTotalCountRef = useRef(0);
|
|
1819
1822
|
const isInitialMountRef = useRef(true);
|
|
1820
|
-
const
|
|
1823
|
+
const previousTotalHeightRef = useRef(0);
|
|
1824
|
+
|
|
1825
|
+
// Subscribe to shadow state changes
|
|
1826
|
+
useEffect(() => {
|
|
1827
|
+
const unsubscribe = getGlobalStore
|
|
1828
|
+
.getState()
|
|
1829
|
+
.subscribeToShadowState(stateKey, () => forceUpdate({}));
|
|
1830
|
+
return unsubscribe;
|
|
1831
|
+
}, [stateKey]);
|
|
1821
1832
|
|
|
1822
1833
|
const sourceArray = getGlobalStore().getNestedState(
|
|
1823
1834
|
stateKey,
|
|
@@ -1832,20 +1843,39 @@ function createProxyHandler<T>(
|
|
|
1832
1843
|
[];
|
|
1833
1844
|
let height = 0;
|
|
1834
1845
|
const pos: number[] = [];
|
|
1835
|
-
let hasMeasurements = false;
|
|
1836
1846
|
|
|
1837
1847
|
for (let i = 0; i < totalCount; i++) {
|
|
1838
1848
|
pos[i] = height;
|
|
1839
1849
|
const measuredHeight =
|
|
1840
1850
|
shadowArray[i]?.virtualizer?.itemHeight;
|
|
1841
|
-
if (measuredHeight) hasMeasurements = true;
|
|
1842
1851
|
height += measuredHeight || itemHeight;
|
|
1843
1852
|
}
|
|
1844
1853
|
|
|
1845
|
-
hasMeasurementsRef.current = hasMeasurements;
|
|
1846
1854
|
return { totalHeight: height, positions: pos };
|
|
1847
1855
|
}, [totalCount, stateKey, path.join("."), itemHeight]);
|
|
1848
1856
|
|
|
1857
|
+
// Adjust scroll when height changes while at bottom
|
|
1858
|
+
useLayoutEffect(() => {
|
|
1859
|
+
const container = containerRef.current;
|
|
1860
|
+
if (!container) return;
|
|
1861
|
+
|
|
1862
|
+
const heightChanged =
|
|
1863
|
+
totalHeight !== previousTotalHeightRef.current;
|
|
1864
|
+
previousTotalHeightRef.current = totalHeight;
|
|
1865
|
+
|
|
1866
|
+
// If we're at bottom and height changed, maintain bottom position
|
|
1867
|
+
if (
|
|
1868
|
+
heightChanged &&
|
|
1869
|
+
isAtBottomRef.current &&
|
|
1870
|
+
!isInitialMountRef.current
|
|
1871
|
+
) {
|
|
1872
|
+
container.scrollTo({
|
|
1873
|
+
top: container.scrollHeight,
|
|
1874
|
+
behavior: "auto",
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
}, [totalHeight]);
|
|
1878
|
+
|
|
1849
1879
|
const virtualState = useMemo(() => {
|
|
1850
1880
|
const start = Math.max(0, range.startIndex);
|
|
1851
1881
|
const end = Math.min(totalCount, range.endIndex);
|
|
@@ -1912,17 +1942,36 @@ function createProxyHandler<T>(
|
|
|
1912
1942
|
passive: true,
|
|
1913
1943
|
});
|
|
1914
1944
|
|
|
1915
|
-
// Handle stick to bottom
|
|
1916
|
-
if (
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1945
|
+
// Handle stick to bottom for initial mount only
|
|
1946
|
+
if (
|
|
1947
|
+
stickToBottom &&
|
|
1948
|
+
isInitialMountRef.current &&
|
|
1949
|
+
totalCount > 0
|
|
1950
|
+
) {
|
|
1951
|
+
// Set flag first to prevent height adjustment from interfering
|
|
1952
|
+
isAtBottomRef.current = true;
|
|
1953
|
+
// Wait for next frame to ensure everything is rendered
|
|
1954
|
+
requestAnimationFrame(() => {
|
|
1955
|
+
if (containerRef.current) {
|
|
1956
|
+
containerRef.current.scrollTo({
|
|
1957
|
+
top: containerRef.current.scrollHeight,
|
|
1958
|
+
behavior: "auto",
|
|
1923
1959
|
});
|
|
1960
|
+
isInitialMountRef.current = false;
|
|
1961
|
+
}
|
|
1962
|
+
});
|
|
1963
|
+
} else if (
|
|
1964
|
+
!isInitialMountRef.current &&
|
|
1965
|
+
wasAtBottom &&
|
|
1966
|
+
listGrew
|
|
1967
|
+
) {
|
|
1968
|
+
// New items added and we were at bottom - stay at bottom
|
|
1969
|
+
requestAnimationFrame(() => {
|
|
1970
|
+
container.scrollTo({
|
|
1971
|
+
top: container.scrollHeight,
|
|
1972
|
+
behavior: "smooth",
|
|
1924
1973
|
});
|
|
1925
|
-
}
|
|
1974
|
+
});
|
|
1926
1975
|
}
|
|
1927
1976
|
|
|
1928
1977
|
// Run handleScroll once to set initial range
|
|
@@ -1932,30 +1981,6 @@ function createProxyHandler<T>(
|
|
|
1932
1981
|
container.removeEventListener("scroll", handleScroll);
|
|
1933
1982
|
}, [totalCount, positions, overscan, stickToBottom]);
|
|
1934
1983
|
|
|
1935
|
-
// Separate effect for initial scroll to bottom
|
|
1936
|
-
useEffect(() => {
|
|
1937
|
-
if (
|
|
1938
|
-
stickToBottom &&
|
|
1939
|
-
isInitialMountRef.current &&
|
|
1940
|
-
totalCount > 0 &&
|
|
1941
|
-
hasMeasurementsRef.current
|
|
1942
|
-
) {
|
|
1943
|
-
const container = containerRef.current;
|
|
1944
|
-
if (container) {
|
|
1945
|
-
// Use rAF to ensure DOM is updated
|
|
1946
|
-
requestAnimationFrame(() => {
|
|
1947
|
-
requestAnimationFrame(() => {
|
|
1948
|
-
container.scrollTo({
|
|
1949
|
-
top: container.scrollHeight,
|
|
1950
|
-
behavior: "auto",
|
|
1951
|
-
});
|
|
1952
|
-
isInitialMountRef.current = false;
|
|
1953
|
-
});
|
|
1954
|
-
});
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
}, [stickToBottom, totalCount, positions]); // positions change triggers this when measurements come in
|
|
1958
|
-
|
|
1959
1984
|
const scrollToBottom = useCallback(
|
|
1960
1985
|
(behavior: ScrollBehavior = "smooth") => {
|
|
1961
1986
|
if (containerRef.current) {
|