cogsbox-state 0.5.295 → 0.5.296

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.295",
3
+ "version": "0.5.296",
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
@@ -1802,7 +1802,6 @@ function createProxyHandler<T>(
1802
1802
  return (
1803
1803
  options: VirtualViewOptions
1804
1804
  ): VirtualStateObjectResult<any[]> => {
1805
- // --- CHANGE 1: itemHeight is now optional, with a default fallback.
1806
1805
  const {
1807
1806
  itemHeight = 50, // Default/estimated height
1808
1807
  overscan = 5,
@@ -1815,7 +1814,6 @@ function createProxyHandler<T>(
1815
1814
  endIndex: 10,
1816
1815
  });
1817
1816
 
1818
- // --- CHANGE 2: Add a helper to get the real height of each item. ---
1819
1817
  const getItemHeight = useCallback(
1820
1818
  (index: number): number => {
1821
1819
  const metadata = getGlobalStore
@@ -1826,7 +1824,6 @@ function createProxyHandler<T>(
1826
1824
  [itemHeight, stateKey, path]
1827
1825
  );
1828
1826
 
1829
- // --- These refs are from your original code. NO CHANGE. ---
1830
1827
  const isAtBottomRef = useRef(stickToBottom);
1831
1828
  const previousTotalCountRef = useRef(0);
1832
1829
  const isInitialMountRef = useRef(true);
@@ -1837,19 +1834,18 @@ function createProxyHandler<T>(
1837
1834
  ) as any[];
1838
1835
  const totalCount = sourceArray.length;
1839
1836
 
1840
- // --- CHANGE 3: Calculate the total height and position of each item. ---
1841
- // This is the only new block of logic required.
1842
1837
  const { totalHeight, positions } = useMemo(() => {
1843
1838
  let height = 0;
1844
1839
  const pos: number[] = [];
1845
1840
  for (let i = 0; i < totalCount; i++) {
1846
1841
  pos[i] = height;
1847
1842
  height += getItemHeight(i);
1843
+ console.log("height", getItemHeight(i), height);
1848
1844
  }
1849
1845
  return { totalHeight: height, positions: pos };
1850
1846
  }, [totalCount, getItemHeight]);
1851
1847
 
1852
- // --- The virtualState logic is IDENTICAL to your original. NO CHANGE. ---
1848
+ // This logic is IDENTICAL to your original code.
1853
1849
  const virtualState = useMemo(() => {
1854
1850
  const start = Math.max(0, range.startIndex);
1855
1851
  const end = Math.min(totalCount, range.endIndex);
@@ -1864,8 +1860,7 @@ function createProxyHandler<T>(
1864
1860
  });
1865
1861
  }, [range.startIndex, range.endIndex, sourceArray, totalCount]);
1866
1862
 
1867
- // --- This useLayoutEffect is from your original code. ---
1868
- // --- We only change the math inside handleScroll. ---
1863
+ // This useLayoutEffect is from your original code.
1869
1864
  useLayoutEffect(() => {
1870
1865
  const container = containerRef.current;
1871
1866
  if (!container) return;
@@ -1879,19 +1874,26 @@ function createProxyHandler<T>(
1879
1874
  isAtBottomRef.current =
1880
1875
  scrollHeight - scrollTop - clientHeight < 10;
1881
1876
 
1882
- // --- CHANGE 4: The math to find the start and end index. ---
1883
- // This replaces `scrollTop / itemHeight` with a more accurate search.
1884
- let startIndex = 0;
1885
- // Find the first item whose top position is past the scroll top.
1886
- for (let i = 0; i < positions.length; i++) {
1887
- if (positions[i]! >= scrollTop) {
1888
- startIndex = i;
1889
- break;
1877
+ // --- THE ROBUST FIX: Binary search to find the start index ---
1878
+ // This is extremely fast and correctly handles all scroll positions.
1879
+ let search = (list: number[], value: number) => {
1880
+ let low = 0;
1881
+ let high = list.length - 1;
1882
+ while (low <= high) {
1883
+ const mid = Math.floor((low + high) / 2);
1884
+ const midValue = list[mid]!;
1885
+ if (midValue < value) {
1886
+ low = mid + 1;
1887
+ } else {
1888
+ high = mid - 1;
1889
+ }
1890
1890
  }
1891
- }
1891
+ return low;
1892
+ };
1893
+
1894
+ let startIndex = search(positions, scrollTop);
1892
1895
 
1893
1896
  let endIndex = startIndex;
1894
- // Find the first item whose top position is past the bottom of the viewport.
1895
1897
  while (
1896
1898
  endIndex < totalCount &&
1897
1899
  positions[endIndex]! < scrollTop + clientHeight
@@ -1899,23 +1901,15 @@ function createProxyHandler<T>(
1899
1901
  endIndex++;
1900
1902
  }
1901
1903
 
1902
- // Apply overscan, identical to your original code.
1903
1904
  startIndex = Math.max(0, startIndex - overscan);
1904
1905
  endIndex = Math.min(totalCount, endIndex + overscan);
1905
- console.log(
1906
- "startIndex",
1907
- startIndex,
1908
- "endIndex",
1909
- endIndex,
1910
- "totalHeight",
1911
- totalHeight
1912
- );
1906
+ console.log("startIndex", startIndex, "endIndex", endIndex);
1913
1907
  setRange((prevRange) => {
1914
1908
  if (
1915
1909
  prevRange.startIndex !== startIndex ||
1916
1910
  prevRange.endIndex !== endIndex
1917
1911
  ) {
1918
- return { startIndex: startIndex, endIndex: endIndex };
1912
+ return { startIndex, endIndex };
1919
1913
  }
1920
1914
  return prevRange;
1921
1915
  });
@@ -1925,7 +1919,7 @@ function createProxyHandler<T>(
1925
1919
  passive: true,
1926
1920
  });
1927
1921
 
1928
- // --- This stickToBottom logic is IDENTICAL to your original. NO CHANGE. ---
1922
+ // This stickToBottom logic is IDENTICAL to your original.
1929
1923
  if (stickToBottom) {
1930
1924
  if (isInitialMountRef.current) {
1931
1925
  container.scrollTo({
@@ -1947,7 +1941,6 @@ function createProxyHandler<T>(
1947
1941
 
1948
1942
  return () =>
1949
1943
  container.removeEventListener("scroll", handleScroll);
1950
- // --- We swap `itemHeight` for `positions` in the dependency array. ---
1951
1944
  }, [totalCount, overscan, stickToBottom, positions]);
1952
1945
 
1953
1946
  const scrollToBottom = useCallback(
@@ -1962,34 +1955,29 @@ function createProxyHandler<T>(
1962
1955
  []
1963
1956
  );
1964
1957
 
1965
- // --- CHANGE 5: Update scrollToIndex to use the positions array. ---
1966
1958
  const scrollToIndex = useCallback(
1967
1959
  (index: number, behavior: ScrollBehavior = "smooth") => {
1968
1960
  if (containerRef.current) {
1969
1961
  containerRef.current.scrollTo({
1970
- top: positions[index] || 0, // Use the calculated position
1962
+ top: positions[index] || 0,
1971
1963
  behavior,
1972
1964
  });
1973
1965
  }
1974
1966
  },
1975
- [positions] // Dependency is now `positions`
1967
+ [positions]
1976
1968
  );
1977
1969
 
1978
- // --- CHANGE 6: Update virtualizer props to use dynamic values. ---
1979
1970
  const virtualizerProps = {
1980
1971
  outer: {
1981
1972
  ref: containerRef,
1982
1973
  style: { overflowY: "auto", height: "100%" },
1983
1974
  },
1984
1975
  inner: {
1985
- style: {
1986
- height: `${totalHeight}px`, // Use calculated dynamic height
1987
- position: "relative",
1988
- },
1976
+ style: { height: `${totalHeight}px`, position: "relative" },
1989
1977
  },
1990
1978
  list: {
1991
1979
  style: {
1992
- transform: `translateY(${positions[range.startIndex] || 0}px)`, // Use calculated position
1980
+ transform: `translateY(${positions[range.startIndex] || 0}px)`,
1993
1981
  },
1994
1982
  },
1995
1983
  };