cogsbox-state 0.5.411 → 0.5.413

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.411",
3
+ "version": "0.5.413",
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
@@ -1821,8 +1821,9 @@ function createProxyHandler<T>(
1821
1821
  endIndex: 10,
1822
1822
  });
1823
1823
  const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
1824
- const wasAtBottomRef = useRef(true);
1824
+ const wasAtBottomRef = useRef(false);
1825
1825
  const previousCountRef = useRef(0);
1826
+ const hasInitializedRef = useRef(false); // Track if we've done initial scroll
1826
1827
 
1827
1828
  // Subscribe to shadow state updates
1828
1829
  useEffect(() => {
@@ -1901,52 +1902,60 @@ function createProxyHandler<T>(
1901
1902
  return false;
1902
1903
  }, [stateKey, path, totalCount]);
1903
1904
 
1904
- // Handle new items when at bottom
1905
+ // Handle ONLY new items - not height changes
1905
1906
  useEffect(() => {
1906
1907
  if (!stickToBottom || totalCount === 0) return;
1907
1908
 
1908
1909
  const hasNewItems = totalCount > previousCountRef.current;
1909
- const isInitialLoad =
1910
- previousCountRef.current === 0 && totalCount > 0;
1911
1910
 
1912
- if ((hasNewItems || isInitialLoad) && wasAtBottomRef.current) {
1913
- // First, ensure the last items are in range
1911
+ // Initial load
1912
+ if (
1913
+ previousCountRef.current === 0 &&
1914
+ totalCount > 0 &&
1915
+ !hasInitializedRef.current
1916
+ ) {
1917
+ hasInitializedRef.current = true;
1914
1918
  const visibleCount = Math.ceil(
1915
- containerRef.current?.clientHeight || 0 / itemHeight
1919
+ (containerRef.current?.clientHeight || 600) / itemHeight
1916
1920
  );
1917
- const newRange = {
1921
+ setRange({
1918
1922
  startIndex: Math.max(
1919
1923
  0,
1920
1924
  totalCount - visibleCount - overscan
1921
1925
  ),
1922
1926
  endIndex: totalCount,
1923
- };
1924
-
1925
- setRange(newRange);
1927
+ });
1926
1928
 
1927
- // Then scroll to the last item after it renders
1928
- const timeoutId = setTimeout(() => {
1929
- const scrolled = scrollToLastItem();
1930
- if (!scrolled && containerRef.current) {
1931
- // Fallback if ref not available yet
1929
+ setTimeout(() => {
1930
+ if (containerRef.current) {
1932
1931
  containerRef.current.scrollTop =
1933
1932
  containerRef.current.scrollHeight;
1933
+ wasAtBottomRef.current = true;
1934
1934
  }
1935
- }, 50);
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
+ };
1936
1949
 
1937
- previousCountRef.current = totalCount;
1950
+ setRange(newRange);
1938
1951
 
1939
- return () => clearTimeout(timeoutId);
1952
+ setTimeout(() => {
1953
+ scrollToLastItem();
1954
+ }, 50);
1940
1955
  }
1941
1956
 
1942
1957
  previousCountRef.current = totalCount;
1943
- }, [
1944
- totalCount,
1945
- stickToBottom,
1946
- itemHeight,
1947
- overscan,
1948
- scrollToLastItem,
1949
- ]);
1958
+ }, [totalCount]); // ONLY depend on totalCount, not positions!
1950
1959
 
1951
1960
  // Handle scroll events
1952
1961
  useEffect(() => {
@@ -1958,7 +1967,7 @@ function createProxyHandler<T>(
1958
1967
  const distanceFromBottom =
1959
1968
  scrollHeight - scrollTop - clientHeight;
1960
1969
 
1961
- // Track if we're at bottom (with tolerance)
1970
+ // Track if we're at bottom
1962
1971
  wasAtBottomRef.current = distanceFromBottom < 100;
1963
1972
 
1964
1973
  // Update visible range based on scroll position
@@ -1989,17 +1998,13 @@ function createProxyHandler<T>(
1989
1998
  passive: true,
1990
1999
  });
1991
2000
 
1992
- // Initial setup
1993
- if (stickToBottom && totalCount > 0) {
1994
- // For initial load, jump to bottom
1995
- container.scrollTop = container.scrollHeight;
1996
- }
2001
+ // Just calculate visible range, no scrolling
1997
2002
  handleScroll();
1998
2003
 
1999
2004
  return () => {
2000
2005
  container.removeEventListener("scroll", handleScroll);
2001
2006
  };
2002
- }, [positions, totalCount, itemHeight, overscan, stickToBottom]);
2007
+ }, [positions, totalCount, itemHeight, overscan]);
2003
2008
 
2004
2009
  const scrollToBottom = useCallback(() => {
2005
2010
  wasAtBottomRef.current = true;