cogsbox-state 0.5.285 → 0.5.287

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.285",
3
+ "version": "0.5.287",
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
@@ -42,7 +42,7 @@ import useMeasure from "react-use-measure";
42
42
  type Prettify<T> = { [K in keyof T]: T[K] } & {};
43
43
 
44
44
  export type VirtualViewOptions = {
45
- itemHeight: number;
45
+ itemHeight?: number;
46
46
  overscan?: number;
47
47
  stickToBottom?: boolean;
48
48
  };
@@ -1466,6 +1466,8 @@ function createProxyHandler<T>(
1466
1466
  if (localStorage.getItem(storageKey)) {
1467
1467
  localStorage.removeItem(storageKey);
1468
1468
  }
1469
+
1470
+ console.log("udpating intial State", stateKey, newState);
1469
1471
  startTransition(() => {
1470
1472
  updateInitialStateGlobal(stateKey, newState);
1471
1473
  getGlobalStore.getState().initializeShadowState(stateKey, newState);
@@ -1802,7 +1804,7 @@ function createProxyHandler<T>(
1802
1804
  options: VirtualViewOptions
1803
1805
  ): VirtualStateObjectResult<any[]> => {
1804
1806
  const {
1805
- itemHeight = 50, // Now optional with default
1807
+ itemHeight = 50, // Default height for unmeasured items
1806
1808
  overscan = 5,
1807
1809
  stickToBottom = false,
1808
1810
  } = options;
@@ -1813,34 +1815,7 @@ function createProxyHandler<T>(
1813
1815
  endIndex: 10,
1814
1816
  });
1815
1817
 
1816
- // Get item height from shadow state or fall back to default
1817
- const getItemHeight = useCallback(
1818
- (index: number) => {
1819
- const metadata = getGlobalStore
1820
- .getState()
1821
- .getShadowMetadata(stateKey, [...path, index.toString()]);
1822
- return metadata?.virtualizer?.itemHeight || itemHeight;
1823
- },
1824
- [itemHeight]
1825
- );
1826
-
1827
- // Calculate total height and item positions
1828
- const calculateHeights = useCallback(() => {
1829
- const sourceArray = getGlobalStore
1830
- .getState()
1831
- .getNestedState(stateKey, path) as any[];
1832
-
1833
- let totalHeight = 0;
1834
- const positions: number[] = [];
1835
-
1836
- for (let i = 0; i < sourceArray.length; i++) {
1837
- positions[i] = totalHeight;
1838
- totalHeight += getItemHeight(i);
1839
- }
1840
-
1841
- return { totalHeight, positions };
1842
- }, [getItemHeight]);
1843
-
1818
+ // --- State Tracking Refs for stickToBottom ---
1844
1819
  const isAtBottomRef = useRef(stickToBottom);
1845
1820
  const previousTotalCountRef = useRef(0);
1846
1821
  const isInitialMountRef = useRef(true);
@@ -1851,6 +1826,28 @@ function createProxyHandler<T>(
1851
1826
  ) as any[];
1852
1827
  const totalCount = sourceArray.length;
1853
1828
 
1829
+ // Helper to get an item's measured height or the default
1830
+ const getItemHeight = useCallback(
1831
+ (index: number): number => {
1832
+ const metadata = getGlobalStore
1833
+ .getState()
1834
+ .getShadowMetadata(stateKey, [...path, index.toString()]);
1835
+ return metadata?.virtualizer?.itemHeight || itemHeight;
1836
+ },
1837
+ [itemHeight, stateKey, path]
1838
+ );
1839
+
1840
+ // Pre-calculate total height and the top offset of each item
1841
+ const { totalHeight, positions } = useMemo(() => {
1842
+ let currentHeight = 0;
1843
+ const pos: number[] = [];
1844
+ for (let i = 0; i < totalCount; i++) {
1845
+ pos[i] = currentHeight;
1846
+ currentHeight += getItemHeight(i);
1847
+ }
1848
+ return { totalHeight: currentHeight, positions: pos };
1849
+ }, [totalCount, getItemHeight]);
1850
+
1854
1851
  const virtualState = useMemo(() => {
1855
1852
  const start = Math.max(0, range.startIndex);
1856
1853
  const end = Math.min(totalCount, range.endIndex);
@@ -1872,44 +1869,39 @@ function createProxyHandler<T>(
1872
1869
  const wasAtBottom = isAtBottomRef.current;
1873
1870
  const listGrew = totalCount > previousTotalCountRef.current;
1874
1871
  previousTotalCountRef.current = totalCount;
1875
-
1876
- const { totalHeight, positions } = calculateHeights();
1877
-
1878
1872
  const handleScroll = () => {
1879
1873
  const { scrollTop, clientHeight, scrollHeight } = container;
1880
1874
  isAtBottomRef.current =
1881
1875
  scrollHeight - scrollTop - clientHeight < 10;
1882
1876
 
1883
- // Find start index using binary search
1884
- let start = 0;
1885
- let end = positions.length - 1;
1886
- while (start < end) {
1887
- const mid = Math.floor((start + end) / 2);
1888
- if (positions[mid]! < scrollTop) {
1889
- start = mid + 1;
1890
- } else {
1891
- end = mid;
1877
+ // Find the start index by searching for the first item in the viewport
1878
+ let startIndex = 0;
1879
+ for (let i = 0; i < positions.length; i++) {
1880
+ if (positions[i]! >= scrollTop) {
1881
+ startIndex = i;
1882
+ break;
1892
1883
  }
1893
1884
  }
1894
- start = Math.max(0, start - overscan);
1895
1885
 
1896
- // Find end index
1897
- const visibleEnd = scrollTop + clientHeight;
1898
- let endIndex = start;
1886
+ // Find the end index by seeing how many items fit in the viewport
1887
+ let endIndex = startIndex;
1899
1888
  while (
1900
- endIndex < positions.length &&
1901
- positions[endIndex]! < visibleEnd
1889
+ endIndex < totalCount &&
1890
+ positions[endIndex]! < scrollTop + clientHeight
1902
1891
  ) {
1903
1892
  endIndex++;
1904
1893
  }
1894
+
1895
+ // Apply overscan
1896
+ startIndex = Math.max(0, startIndex - overscan);
1905
1897
  endIndex = Math.min(totalCount, endIndex + overscan);
1906
1898
 
1907
1899
  setRange((prevRange) => {
1908
1900
  if (
1909
- prevRange.startIndex !== start ||
1901
+ prevRange.startIndex !== startIndex ||
1910
1902
  prevRange.endIndex !== endIndex
1911
1903
  ) {
1912
- return { startIndex: start, endIndex: endIndex };
1904
+ return { startIndex, endIndex };
1913
1905
  }
1914
1906
  return prevRange;
1915
1907
  });
@@ -1919,6 +1911,7 @@ function createProxyHandler<T>(
1919
1911
  passive: true,
1920
1912
  });
1921
1913
 
1914
+ // Logic to keep the view scrolled to the bottom
1922
1915
  if (stickToBottom) {
1923
1916
  if (isInitialMountRef.current) {
1924
1917
  container.scrollTo({
@@ -1936,11 +1929,11 @@ function createProxyHandler<T>(
1936
1929
  }
1937
1930
 
1938
1931
  isInitialMountRef.current = false;
1939
- handleScroll();
1932
+ handleScroll(); // Initial calculation
1940
1933
 
1941
1934
  return () =>
1942
1935
  container.removeEventListener("scroll", handleScroll);
1943
- }, [totalCount, calculateHeights, overscan, stickToBottom]);
1936
+ }, [totalCount, overscan, stickToBottom, positions]);
1944
1937
 
1945
1938
  const scrollToBottom = useCallback(
1946
1939
  (behavior: ScrollBehavior = "smooth") => {
@@ -1956,45 +1949,37 @@ function createProxyHandler<T>(
1956
1949
 
1957
1950
  const scrollToIndex = useCallback(
1958
1951
  (index: number, behavior: ScrollBehavior = "smooth") => {
1959
- if (containerRef.current) {
1960
- const { positions } = calculateHeights();
1952
+ if (containerRef.current && positions[index] !== undefined) {
1961
1953
  containerRef.current.scrollTo({
1962
- top: positions[index] || 0,
1954
+ top: positions[index],
1963
1955
  behavior,
1964
1956
  });
1965
1957
  }
1966
1958
  },
1967
- [calculateHeights]
1959
+ [positions] // Depends on the calculated positions
1968
1960
  );
1969
1961
 
1970
- // Calculate actual heights for rendering
1971
- const {
1972
- totalHeight: totalHeightForRender,
1973
- positions: positionsForRender,
1974
- } = calculateHeights();
1975
- const offsetY = positionsForRender[range.startIndex] || 0;
1976
-
1977
1962
  const virtualizerProps = {
1978
1963
  outer: {
1979
1964
  ref: containerRef,
1980
- style: { overflowY: "auto", height: "100%" } as CSSProperties,
1965
+ style: { overflowY: "auto", height: "100%" },
1981
1966
  },
1982
1967
  inner: {
1983
1968
  style: {
1984
- height: `${totalHeightForRender}px`,
1969
+ height: `${totalHeight}px`,
1985
1970
  position: "relative",
1986
- } as CSSProperties,
1971
+ },
1987
1972
  },
1988
1973
  list: {
1989
1974
  style: {
1990
- transform: `translateY(${offsetY}px)`,
1991
- } as CSSProperties,
1975
+ transform: `translateY(${positions[range.startIndex] || 0}px)`,
1976
+ },
1992
1977
  },
1993
1978
  };
1994
1979
 
1995
1980
  return {
1996
1981
  virtualState,
1997
- virtualizerProps,
1982
+ virtualizerProps: virtualizerProps as any,
1998
1983
  scrollToBottom,
1999
1984
  scrollToIndex,
2000
1985
  };