cogsbox-state 0.5.304 → 0.5.305

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-state",
3
- "version": "0.5.304",
3
+ "version": "0.5.305",
4
4
  "description": "React state management library with form controls and server sync",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/CogsState.tsx CHANGED
@@ -1817,6 +1817,7 @@ function createProxyHandler<T>(
1817
1817
  const isAtBottomRef = useRef(stickToBottom);
1818
1818
  const previousTotalCountRef = useRef(0);
1819
1819
  const isInitialMountRef = useRef(true);
1820
+ const hasMeasurementsRef = useRef(false);
1820
1821
 
1821
1822
  const sourceArray = getGlobalStore().getNestedState(
1822
1823
  stateKey,
@@ -1831,14 +1832,17 @@ function createProxyHandler<T>(
1831
1832
  [];
1832
1833
  let height = 0;
1833
1834
  const pos: number[] = [];
1835
+ let hasMeasurements = false;
1834
1836
 
1835
1837
  for (let i = 0; i < totalCount; i++) {
1836
1838
  pos[i] = height;
1837
1839
  const measuredHeight =
1838
1840
  shadowArray[i]?.virtualizer?.itemHeight;
1841
+ if (measuredHeight) hasMeasurements = true;
1839
1842
  height += measuredHeight || itemHeight;
1840
1843
  }
1841
1844
 
1845
+ hasMeasurementsRef.current = hasMeasurements;
1842
1846
  return { totalHeight: height, positions: pos };
1843
1847
  }, [totalCount, stateKey, path.join("."), itemHeight]);
1844
1848
 
@@ -1909,20 +1913,9 @@ function createProxyHandler<T>(
1909
1913
  });
1910
1914
 
1911
1915
  // Handle stick to bottom
1912
- if (stickToBottom) {
1913
- if (isInitialMountRef.current && totalCount > 0) {
1914
- // Delay initial scroll to ensure items are rendered
1915
- setTimeout(() => {
1916
- if (containerRef.current) {
1917
- containerRef.current.scrollTo({
1918
- top: containerRef.current.scrollHeight,
1919
- behavior: "auto",
1920
- });
1921
- }
1922
- }, 0);
1923
- isInitialMountRef.current = false;
1924
- } else if (wasAtBottom && listGrew) {
1925
- // New items added and we were at bottom - stay at bottom
1916
+ if (stickToBottom && !isInitialMountRef.current) {
1917
+ // Only auto-scroll for new items after initial mount
1918
+ if (wasAtBottom && listGrew) {
1926
1919
  requestAnimationFrame(() => {
1927
1920
  container.scrollTo({
1928
1921
  top: container.scrollHeight,
@@ -1930,8 +1923,6 @@ function createProxyHandler<T>(
1930
1923
  });
1931
1924
  });
1932
1925
  }
1933
- } else {
1934
- isInitialMountRef.current = false;
1935
1926
  }
1936
1927
 
1937
1928
  // Run handleScroll once to set initial range
@@ -1941,6 +1932,30 @@ function createProxyHandler<T>(
1941
1932
  container.removeEventListener("scroll", handleScroll);
1942
1933
  }, [totalCount, positions, overscan, stickToBottom]);
1943
1934
 
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
+
1944
1959
  const scrollToBottom = useCallback(
1945
1960
  (behavior: ScrollBehavior = "smooth") => {
1946
1961
  if (containerRef.current) {