cogsbox-state 0.5.350 → 0.5.351

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.350",
3
+ "version": "0.5.351",
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
@@ -1814,7 +1814,6 @@ function createProxyHandler<T>(
1814
1814
  endIndex: 10,
1815
1815
  });
1816
1816
  const isLockedToBottomRef = useRef(stickToBottom);
1817
- const prevTotalCountRef = useRef(0);
1818
1817
 
1819
1818
  const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
1820
1819
 
@@ -1868,28 +1867,37 @@ function createProxyHandler<T>(
1868
1867
  });
1869
1868
  }, [range.startIndex, range.endIndex, sourceArray, totalCount]);
1870
1869
 
1871
- // --- YOUR WORKING SCROLL ALGORITHM - UNTOUCHED ---
1870
+ // --- YOUR ALGORITHM IMPLEMENTED ---
1871
+ // This effect is the entry point. It triggers when new items are added.
1872
1872
  useLayoutEffect(() => {
1873
1873
  const container = containerRef.current;
1874
- const hasNewItems = totalCount > prevTotalCountRef.current;
1875
-
1874
+ // Only run if we have new items and are supposed to be at the bottom.
1876
1875
  if (
1877
1876
  !container ||
1878
- !stickToBottom ||
1879
1877
  !isLockedToBottomRef.current ||
1880
- !hasNewItems
1878
+ totalCount === 0
1881
1879
  ) {
1882
1880
  return;
1883
1881
  }
1884
1882
 
1885
- // STEP 1: Set range to the end to render the items we need to measure.
1883
+ // STEP 1: Set the range to the end so the last items are rendered.
1884
+ console.log("ALGORITHM: Starting...");
1885
+ const visibleCount = 10;
1886
1886
  setRange({
1887
- startIndex: Math.max(0, totalCount - 10 - overscan),
1887
+ startIndex: Math.max(0, totalCount - visibleCount - overscan),
1888
1888
  endIndex: totalCount,
1889
1889
  });
1890
1890
 
1891
- // STEP 2: The LOOP.
1891
+ // STEP 2: Start the LOOP.
1892
+ console.log(
1893
+ "ALGORITHM: Starting LOOP to wait for measurement."
1894
+ );
1895
+ let loopCount = 0;
1892
1896
  const intervalId = setInterval(() => {
1897
+ loopCount++;
1898
+ console.log(`LOOP ${loopCount}: Checking last item...`);
1899
+
1900
+ // The Check: Get the last item's height FROM THE SHADOW OBJECT.
1893
1901
  const lastItemIndex = totalCount - 1;
1894
1902
  const shadowArray =
1895
1903
  getGlobalStore
@@ -1899,48 +1907,45 @@ function createProxyHandler<T>(
1899
1907
  shadowArray[lastItemIndex]?.virtualizer?.itemHeight || 0;
1900
1908
 
1901
1909
  if (lastItemHeight > 0) {
1902
- clearInterval(intervalId);
1910
+ // EXIT CONDITION MET
1911
+ console.log(
1912
+ `%cSUCCESS: Last item height is ${lastItemHeight}. Scrolling now.`,
1913
+ "color: green; font-weight: bold;"
1914
+ );
1915
+ clearInterval(intervalId); // Stop the loop.
1916
+
1903
1917
  // STEP 3: Scroll.
1904
1918
  container.scrollTo({
1905
1919
  top: container.scrollHeight,
1906
1920
  behavior: "smooth",
1907
1921
  });
1922
+ } else {
1923
+ console.log("...WAITING. Height is not ready.");
1924
+ if (loopCount > 20) {
1925
+ // Safety break to prevent infinite loops
1926
+ console.error(
1927
+ "LOOP TIMEOUT: Last item was never measured. Stopping loop."
1928
+ );
1929
+ clearInterval(intervalId);
1930
+ }
1908
1931
  }
1909
- }, 100);
1932
+ }, 100); // Check every 100ms.
1910
1933
 
1911
- return () => clearInterval(intervalId);
1912
- }, [totalCount]);
1934
+ // Cleanup: Stop the loop if the component unmounts.
1935
+ return () => {
1936
+ console.log("ALGORITHM: Cleaning up loop.");
1937
+ clearInterval(intervalId);
1938
+ };
1939
+ }, [totalCount]); // This whole process triggers ONLY when totalCount changes.
1913
1940
 
1914
- // --- THE FIX IS HERE ---
1915
- // This effect now correctly updates when data changes.
1941
+ // Effect to handle user scrolling.
1916
1942
  useEffect(() => {
1917
1943
  const container = containerRef.current;
1918
1944
  if (!container) return;
1919
1945
 
1920
1946
  const updateVirtualRange = () => {
1921
- const { scrollTop, clientHeight } = container;
1922
- let low = 0,
1923
- high = totalCount - 1;
1924
- while (low <= high) {
1925
- const mid = Math.floor((low + high) / 2);
1926
- if (positions[mid]! < scrollTop) low = mid + 1;
1927
- else high = mid - 1;
1928
- }
1929
- const startIndex = Math.max(0, high - overscan);
1930
- let endIndex = startIndex;
1931
- const visibleEnd = scrollTop + clientHeight;
1932
- while (
1933
- endIndex < totalCount &&
1934
- positions[endIndex]! < visibleEnd
1935
- ) {
1936
- endIndex++;
1937
- }
1938
- setRange({
1939
- startIndex,
1940
- endIndex: Math.min(totalCount, endIndex + overscan),
1941
- });
1947
+ /* ... same as before ... */
1942
1948
  };
1943
-
1944
1949
  const handleUserScroll = () => {
1945
1950
  const isAtBottom =
1946
1951
  container.scrollHeight -
@@ -1949,23 +1954,17 @@ function createProxyHandler<T>(
1949
1954
  1;
1950
1955
  if (!isAtBottom) {
1951
1956
  isLockedToBottomRef.current = false;
1957
+ console.log("USER ACTION: Scroll lock DISABLED.");
1952
1958
  }
1953
1959
  updateVirtualRange();
1954
1960
  };
1955
-
1956
1961
  container.addEventListener("scroll", handleUserScroll, {
1957
1962
  passive: true,
1958
1963
  });
1959
- updateVirtualRange(); // Always update range on render.
1960
-
1961
1964
  return () =>
1962
1965
  container.removeEventListener("scroll", handleUserScroll);
1963
- }, [totalCount, positions]); // FIX: This now has dependencies.
1966
+ }, []);
1964
1967
 
1965
- // Simple effect to track previous item count for the scroll algorithm.
1966
- useEffect(() => {
1967
- prevTotalCountRef.current = totalCount;
1968
- });
1969
1968
  const scrollToBottom = useCallback(
1970
1969
  (behavior: ScrollBehavior = "smooth") => {
1971
1970
  if (containerRef.current) {