cogsbox-state 0.5.346 → 0.5.347

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.346",
3
+ "version": "0.5.347",
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
@@ -1867,11 +1867,11 @@ function createProxyHandler<T>(
1867
1867
  });
1868
1868
  }, [range.startIndex, range.endIndex, sourceArray, totalCount]);
1869
1869
 
1870
- // --- YOUR ALGORITHM IMPLEMENTED ---
1870
+ // --- YOUR SCROLLING ALGORITHM (UNCHANGED and WORKING) ---
1871
1871
  // This effect is the entry point. It triggers when new items are added.
1872
1872
  useLayoutEffect(() => {
1873
1873
  const container = containerRef.current;
1874
- // Only run if we have new items and are supposed to be at the bottom.
1874
+ // Only run if we are supposed to be at the bottom.
1875
1875
  if (
1876
1876
  !container ||
1877
1877
  !isLockedToBottomRef.current ||
@@ -1881,7 +1881,6 @@ function createProxyHandler<T>(
1881
1881
  }
1882
1882
 
1883
1883
  // STEP 1: Set the range to the end so the last items are rendered.
1884
- console.log("ALGORITHM: Starting...");
1885
1884
  const visibleCount = 10;
1886
1885
  setRange({
1887
1886
  startIndex: Math.max(0, totalCount - visibleCount - overscan),
@@ -1889,14 +1888,9 @@ function createProxyHandler<T>(
1889
1888
  });
1890
1889
 
1891
1890
  // STEP 2: Start the LOOP.
1892
- console.log(
1893
- "ALGORITHM: Starting LOOP to wait for measurement."
1894
- );
1895
1891
  let loopCount = 0;
1896
1892
  const intervalId = setInterval(() => {
1897
1893
  loopCount++;
1898
- console.log(`LOOP ${loopCount}: Checking last item...`);
1899
-
1900
1894
  // The Check: Get the last item's height FROM THE SHADOW OBJECT.
1901
1895
  const lastItemIndex = totalCount - 1;
1902
1896
  const shadowArray =
@@ -1908,10 +1902,6 @@ function createProxyHandler<T>(
1908
1902
 
1909
1903
  if (lastItemHeight > 0) {
1910
1904
  // EXIT CONDITION MET
1911
- console.log(
1912
- `%cSUCCESS: Last item height is ${lastItemHeight}. Scrolling now.`,
1913
- "color: green; font-weight: bold;"
1914
- );
1915
1905
  clearInterval(intervalId); // Stop the loop.
1916
1906
 
1917
1907
  // STEP 3: Scroll.
@@ -1920,32 +1910,48 @@ function createProxyHandler<T>(
1920
1910
  behavior: "smooth",
1921
1911
  });
1922
1912
  } else {
1923
- console.log("...WAITING. Height is not ready.");
1924
1913
  if (loopCount > 20) {
1925
- // Safety break to prevent infinite loops
1926
- console.error(
1927
- "LOOP TIMEOUT: Last item was never measured. Stopping loop."
1928
- );
1914
+ // Safety break
1929
1915
  clearInterval(intervalId);
1930
1916
  }
1931
1917
  }
1932
- }, 100); // Check every 100ms.
1918
+ }, 100);
1933
1919
 
1934
1920
  // Cleanup: Stop the loop if the component unmounts.
1935
- return () => {
1936
- console.log("ALGORITHM: Cleaning up loop.");
1937
- clearInterval(intervalId);
1938
- };
1921
+ return () => clearInterval(intervalId);
1939
1922
  }, [totalCount]); // This whole process triggers ONLY when totalCount changes.
1940
1923
 
1941
- // Effect to handle user scrolling.
1924
+ // --- THE FIX IS HERE ---
1925
+ // This effect now correctly handles user scrolling AND updates the view.
1942
1926
  useEffect(() => {
1943
1927
  const container = containerRef.current;
1944
1928
  if (!container) return;
1945
1929
 
1930
+ // This function now always has the LATEST totalCount and positions.
1946
1931
  const updateVirtualRange = () => {
1947
- /* ... same as before ... */
1932
+ const { scrollTop, clientHeight } = container;
1933
+ let low = 0,
1934
+ high = totalCount - 1;
1935
+ while (low <= high) {
1936
+ const mid = Math.floor((low + high) / 2);
1937
+ if (positions[mid]! < scrollTop) low = mid + 1;
1938
+ else high = mid - 1;
1939
+ }
1940
+ const startIndex = Math.max(0, high - overscan);
1941
+ let endIndex = startIndex;
1942
+ const visibleEnd = scrollTop + clientHeight;
1943
+ while (
1944
+ endIndex < totalCount &&
1945
+ positions[endIndex]! < visibleEnd
1946
+ ) {
1947
+ endIndex++;
1948
+ }
1949
+ setRange({
1950
+ startIndex,
1951
+ endIndex: Math.min(totalCount, endIndex + overscan),
1952
+ });
1948
1953
  };
1954
+
1949
1955
  const handleUserScroll = () => {
1950
1956
  const isAtBottom =
1951
1957
  container.scrollHeight -
@@ -1954,23 +1960,25 @@ function createProxyHandler<T>(
1954
1960
  1;
1955
1961
  if (!isAtBottom) {
1956
1962
  isLockedToBottomRef.current = false;
1957
- console.log("USER ACTION: Scroll lock DISABLED.");
1958
1963
  }
1964
+ // This always calls the fresh version of updateVirtualRange.
1959
1965
  updateVirtualRange();
1960
1966
  };
1967
+
1961
1968
  container.addEventListener("scroll", handleUserScroll, {
1962
1969
  passive: true,
1963
1970
  });
1971
+ updateVirtualRange(); // Update range on initial load and when data changes.
1972
+
1973
+ // This cleanup is crucial. It removes the old listener before adding a new one.
1964
1974
  return () =>
1965
1975
  container.removeEventListener("scroll", handleUserScroll);
1966
- }, []);
1976
+ }, [totalCount, positions]); // Its dependency array now includes totalCount and positions.
1967
1977
 
1968
1978
  const scrollToBottom = useCallback(
1969
1979
  (behavior: ScrollBehavior = "smooth") => {
1970
1980
  if (containerRef.current) {
1971
1981
  isLockedToBottomRef.current = true;
1972
- console.log("USER ACTION: Scroll lock ENABLED.");
1973
- // This is a manual trigger, so we don't need the loop. Just scroll.
1974
1982
  containerRef.current.scrollTo({
1975
1983
  top: containerRef.current.scrollHeight,
1976
1984
  behavior,
@@ -1984,7 +1992,6 @@ function createProxyHandler<T>(
1984
1992
  (index: number, behavior: ScrollBehavior = "smooth") => {
1985
1993
  if (containerRef.current && positions[index] !== undefined) {
1986
1994
  isLockedToBottomRef.current = false;
1987
- console.log("USER ACTION: Scroll lock DISABLED.");
1988
1995
  containerRef.current.scrollTo({
1989
1996
  top: positions[index],
1990
1997
  behavior,