cogsbox-state 0.5.405 → 0.5.407

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.405",
3
+ "version": "0.5.407",
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
@@ -1805,6 +1805,9 @@ function createProxyHandler<T>(
1805
1805
  }
1806
1806
  // Simplified useVirtualView approach
1807
1807
  // Optimal approach - replace the useVirtualView implementation
1808
+ // Complete useVirtualView implementation with comprehensive logging
1809
+ // Complete fixed useVirtualView implementation
1810
+ // Complete fixed useVirtualView implementation
1808
1811
  if (prop === "useVirtualView") {
1809
1812
  return (
1810
1813
  options: VirtualViewOptions
@@ -1822,7 +1825,7 @@ function createProxyHandler<T>(
1822
1825
  endIndex: 10,
1823
1826
  });
1824
1827
  const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
1825
- const isUserScrollingRef = useRef(false);
1828
+ const isProgrammaticScrollRef = useRef(false); // Track if we're scrolling programmatically
1826
1829
  const shouldStickToBottomRef = useRef(true);
1827
1830
  const scrollToBottomIntervalRef = useRef<NodeJS.Timeout | null>(
1828
1831
  null
@@ -1882,18 +1885,10 @@ function createProxyHandler<T>(
1882
1885
  }, [range.startIndex, range.endIndex, sourceArray, totalCount]);
1883
1886
 
1884
1887
  // Handle auto-scroll to bottom
1885
- const [hasMounted, setHasMounted] = useState(false);
1886
-
1887
- // Add this effect to track mounting:
1888
- useEffect(() => {
1889
- setHasMounted(true);
1890
- }, []);
1891
-
1892
- // Replace the auto-scroll effect with this version:
1893
1888
  useEffect(() => {
1894
1889
  if (!stickToBottom || !containerRef.current || totalCount === 0)
1895
1890
  return;
1896
- if (!shouldStickToBottomRef.current && hasMounted) return; // Only check shouldStickToBottom after mount
1891
+ if (!shouldStickToBottomRef.current) return;
1897
1892
 
1898
1893
  // Clear any existing interval
1899
1894
  if (scrollToBottomIntervalRef.current) {
@@ -1906,11 +1901,19 @@ function createProxyHandler<T>(
1906
1901
  const isBigJump = totalCount > range.endIndex + jumpThreshold;
1907
1902
 
1908
1903
  if (isInitialLoad || isBigJump) {
1909
- // Jump to show the last items immediately
1910
- setRange({
1904
+ // Set programmatic scroll flag BEFORE changing range
1905
+ isProgrammaticScrollRef.current = true;
1906
+
1907
+ const newRange = {
1911
1908
  startIndex: Math.max(0, totalCount - 20),
1912
1909
  endIndex: totalCount,
1913
- });
1910
+ };
1911
+ setRange(newRange);
1912
+
1913
+ // Reset flag after a delay to ensure scroll events are ignored
1914
+ setTimeout(() => {
1915
+ isProgrammaticScrollRef.current = false;
1916
+ }, 100);
1914
1917
  }
1915
1918
 
1916
1919
  // Keep scrolling to bottom until we're actually there
@@ -1928,19 +1931,18 @@ function createProxyHandler<T>(
1928
1931
  const actualBottom = scrollHeight;
1929
1932
  const isAtBottom = actualBottom - currentBottom < 5;
1930
1933
 
1931
- console.log(
1932
- `Scroll attempt ${attempts}: currentBottom=${currentBottom}, actualBottom=${actualBottom}, isAtBottom=${isAtBottom}, hasMounted=${hasMounted}`
1933
- );
1934
-
1935
1934
  if (isAtBottom || attempts >= maxAttempts) {
1936
1935
  clearInterval(scrollToBottomIntervalRef.current!);
1937
1936
  scrollToBottomIntervalRef.current = null;
1938
- console.log(
1939
- isAtBottom ? "Reached bottom!" : "Timeout - giving up"
1940
- );
1941
1937
  } else {
1942
- // Use instant scroll, not smooth
1938
+ // Set flag before scrolling
1939
+ isProgrammaticScrollRef.current = true;
1943
1940
  container.scrollTop = container.scrollHeight;
1941
+
1942
+ // Reset flag after a short delay
1943
+ setTimeout(() => {
1944
+ isProgrammaticScrollRef.current = false;
1945
+ }, 50);
1944
1946
  }
1945
1947
  }, 100);
1946
1948
 
@@ -1951,18 +1953,21 @@ function createProxyHandler<T>(
1951
1953
  scrollToBottomIntervalRef.current = null;
1952
1954
  }
1953
1955
  };
1954
- }, [totalCount, stickToBottom, hasMounted]);
1956
+ }, [totalCount, stickToBottom, range.startIndex, range.endIndex]);
1955
1957
 
1956
1958
  // Handle user scroll
1957
1959
  useEffect(() => {
1958
1960
  const container = containerRef.current;
1959
1961
  if (!container) return;
1960
1962
 
1961
- let scrollTimeout: NodeJS.Timeout;
1962
-
1963
1963
  const handleScroll = () => {
1964
+ // Ignore programmatic scrolls
1965
+ if (isProgrammaticScrollRef.current) {
1966
+ return;
1967
+ }
1968
+
1969
+ // This is a real user scroll
1964
1970
  if (scrollToBottomIntervalRef.current) {
1965
- // Stop auto-scrolling if user scrolls
1966
1971
  clearInterval(scrollToBottomIntervalRef.current);
1967
1972
  scrollToBottomIntervalRef.current = null;
1968
1973
  }
@@ -1971,16 +1976,9 @@ function createProxyHandler<T>(
1971
1976
  const isAtBottom =
1972
1977
  scrollHeight - scrollTop - clientHeight < 10;
1973
1978
 
1974
- // Update whether we should stick to bottom
1979
+ // Only update this for real user scrolls
1975
1980
  shouldStickToBottomRef.current = isAtBottom;
1976
1981
 
1977
- // Mark as user scrolling
1978
- clearTimeout(scrollTimeout);
1979
- isUserScrollingRef.current = true;
1980
- scrollTimeout = setTimeout(() => {
1981
- isUserScrollingRef.current = false;
1982
- }, 150);
1983
-
1984
1982
  // Update visible range
1985
1983
  let startIndex = 0;
1986
1984
  for (let i = 0; i < positions.length; i++) {
@@ -2012,29 +2010,36 @@ function createProxyHandler<T>(
2012
2010
 
2013
2011
  return () => {
2014
2012
  container.removeEventListener("scroll", handleScroll);
2015
- clearTimeout(scrollTimeout);
2016
2013
  };
2017
2014
  }, [positions, totalCount, itemHeight, overscan]);
2018
2015
 
2019
2016
  const scrollToBottom = useCallback(
2020
2017
  (behavior: ScrollBehavior = "auto") => {
2021
2018
  shouldStickToBottomRef.current = true;
2019
+ isProgrammaticScrollRef.current = true;
2022
2020
  if (containerRef.current) {
2023
2021
  containerRef.current.scrollTop =
2024
2022
  containerRef.current.scrollHeight;
2025
2023
  }
2024
+ setTimeout(() => {
2025
+ isProgrammaticScrollRef.current = false;
2026
+ }, 100);
2026
2027
  },
2027
2028
  []
2028
2029
  );
2029
2030
 
2030
2031
  const scrollToIndex = useCallback(
2031
2032
  (index: number, behavior: ScrollBehavior = "smooth") => {
2033
+ isProgrammaticScrollRef.current = true;
2032
2034
  if (containerRef.current && positions[index] !== undefined) {
2033
2035
  containerRef.current.scrollTo({
2034
2036
  top: positions[index],
2035
2037
  behavior,
2036
2038
  });
2037
2039
  }
2040
+ setTimeout(() => {
2041
+ isProgrammaticScrollRef.current = false;
2042
+ }, 100);
2038
2043
  },
2039
2044
  [positions]
2040
2045
  );