cogsbox-state 0.5.287 → 0.5.289

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.287",
3
+ "version": "0.5.289",
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,8 +1466,6 @@ 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);
1471
1469
  startTransition(() => {
1472
1470
  updateInitialStateGlobal(stateKey, newState);
1473
1471
  getGlobalStore.getState().initializeShadowState(stateKey, newState);
@@ -1560,7 +1558,10 @@ function createProxyHandler<T>(
1560
1558
  "_stateKey",
1561
1559
  "getComponents",
1562
1560
  ]);
1561
+
1562
+ console.log("prop", target, path, prop);
1563
1563
  if (
1564
+ prop &&
1564
1565
  prop !== "then" &&
1565
1566
  !prop.startsWith("$") &&
1566
1567
  prop !== "stateMapNoRender" &&
@@ -1804,7 +1805,7 @@ function createProxyHandler<T>(
1804
1805
  options: VirtualViewOptions
1805
1806
  ): VirtualStateObjectResult<any[]> => {
1806
1807
  const {
1807
- itemHeight = 50, // Default height for unmeasured items
1808
+ itemHeight,
1808
1809
  overscan = 5,
1809
1810
  stickToBottom = false,
1810
1811
  } = options;
@@ -1814,10 +1815,16 @@ function createProxyHandler<T>(
1814
1815
  startIndex: 0,
1815
1816
  endIndex: 10,
1816
1817
  });
1817
-
1818
- // --- State Tracking Refs for stickToBottom ---
1818
+ // const getItemHeight = useCallback((index: number) => {
1819
+ // const metadata = getGlobalStore
1820
+ // .getState()
1821
+ // .getShadowMetadata(stateKey, [...path, index.toString()]);
1822
+ // return metadata?.virtualizer?.itemHeight || options.itemHeight;
1823
+ // }, []);
1824
+ // --- State Tracking Refs ---
1819
1825
  const isAtBottomRef = useRef(stickToBottom);
1820
1826
  const previousTotalCountRef = useRef(0);
1827
+ // NEW: Ref to explicitly track if this is the component's first render cycle.
1821
1828
  const isInitialMountRef = useRef(true);
1822
1829
 
1823
1830
  const sourceArray = getGlobalStore().getNestedState(
@@ -1826,28 +1833,6 @@ function createProxyHandler<T>(
1826
1833
  ) as any[];
1827
1834
  const totalCount = sourceArray.length;
1828
1835
 
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
-
1851
1836
  const virtualState = useMemo(() => {
1852
1837
  const start = Math.max(0, range.startIndex);
1853
1838
  const end = Math.min(totalCount, range.endIndex);
@@ -1869,39 +1854,26 @@ function createProxyHandler<T>(
1869
1854
  const wasAtBottom = isAtBottomRef.current;
1870
1855
  const listGrew = totalCount > previousTotalCountRef.current;
1871
1856
  previousTotalCountRef.current = totalCount;
1857
+
1872
1858
  const handleScroll = () => {
1873
1859
  const { scrollTop, clientHeight, scrollHeight } = container;
1874
1860
  isAtBottomRef.current =
1875
1861
  scrollHeight - scrollTop - clientHeight < 10;
1876
-
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;
1883
- }
1884
- }
1885
-
1886
- // Find the end index by seeing how many items fit in the viewport
1887
- let endIndex = startIndex;
1888
- while (
1889
- endIndex < totalCount &&
1890
- positions[endIndex]! < scrollTop + clientHeight
1891
- ) {
1892
- endIndex++;
1893
- }
1894
-
1895
- // Apply overscan
1896
- startIndex = Math.max(0, startIndex - overscan);
1897
- endIndex = Math.min(totalCount, endIndex + overscan);
1898
-
1862
+ const start = Math.max(
1863
+ 0,
1864
+ Math.floor(scrollTop / itemHeight) - overscan
1865
+ );
1866
+ const end = Math.min(
1867
+ totalCount,
1868
+ Math.ceil((scrollTop + clientHeight) / itemHeight) +
1869
+ overscan
1870
+ );
1899
1871
  setRange((prevRange) => {
1900
1872
  if (
1901
- prevRange.startIndex !== startIndex ||
1902
- prevRange.endIndex !== endIndex
1873
+ prevRange.startIndex !== start ||
1874
+ prevRange.endIndex !== end
1903
1875
  ) {
1904
- return { startIndex, endIndex };
1876
+ return { startIndex: start, endIndex: end };
1905
1877
  }
1906
1878
  return prevRange;
1907
1879
  });
@@ -1911,14 +1883,19 @@ function createProxyHandler<T>(
1911
1883
  passive: true,
1912
1884
  });
1913
1885
 
1914
- // Logic to keep the view scrolled to the bottom
1886
+ // --- THE CORRECTED DECISION LOGIC ---
1915
1887
  if (stickToBottom) {
1916
1888
  if (isInitialMountRef.current) {
1889
+ // SCENARIO 1: First render of the component.
1890
+ // Go to the bottom unconditionally. Use `auto` scroll for an instant jump.
1917
1891
  container.scrollTo({
1918
1892
  top: container.scrollHeight,
1919
1893
  behavior: "auto",
1920
1894
  });
1921
1895
  } else if (wasAtBottom && listGrew) {
1896
+ // SCENARIO 2: Subsequent renders (new messages arrive).
1897
+ // Only scroll if the user was already at the bottom.
1898
+ // Use `smooth` for a nice animated scroll for new messages.
1922
1899
  requestAnimationFrame(() => {
1923
1900
  container.scrollTo({
1924
1901
  top: container.scrollHeight,
@@ -1928,12 +1905,15 @@ function createProxyHandler<T>(
1928
1905
  }
1929
1906
  }
1930
1907
 
1908
+ // After the logic runs, it's no longer the initial mount.
1931
1909
  isInitialMountRef.current = false;
1932
- handleScroll(); // Initial calculation
1910
+
1911
+ // Always run handleScroll once to set the initial visible window.
1912
+ handleScroll();
1933
1913
 
1934
1914
  return () =>
1935
1915
  container.removeEventListener("scroll", handleScroll);
1936
- }, [totalCount, overscan, stickToBottom, positions]);
1916
+ }, [totalCount, itemHeight, overscan, stickToBottom]);
1937
1917
 
1938
1918
  const scrollToBottom = useCallback(
1939
1919
  (behavior: ScrollBehavior = "smooth") => {
@@ -1949,16 +1929,17 @@ function createProxyHandler<T>(
1949
1929
 
1950
1930
  const scrollToIndex = useCallback(
1951
1931
  (index: number, behavior: ScrollBehavior = "smooth") => {
1952
- if (containerRef.current && positions[index] !== undefined) {
1932
+ if (containerRef.current) {
1953
1933
  containerRef.current.scrollTo({
1954
- top: positions[index],
1934
+ top: index * itemHeight,
1955
1935
  behavior,
1956
1936
  });
1957
1937
  }
1958
1938
  },
1959
- [positions] // Depends on the calculated positions
1939
+ [itemHeight]
1960
1940
  );
1961
1941
 
1942
+ // Same virtualizer props as before
1962
1943
  const virtualizerProps = {
1963
1944
  outer: {
1964
1945
  ref: containerRef,
@@ -1966,13 +1947,13 @@ function createProxyHandler<T>(
1966
1947
  },
1967
1948
  inner: {
1968
1949
  style: {
1969
- height: `${totalHeight}px`,
1950
+ height: `${totalCount * itemHeight}px`,
1970
1951
  position: "relative",
1971
1952
  },
1972
1953
  },
1973
1954
  list: {
1974
1955
  style: {
1975
- transform: `translateY(${positions[range.startIndex] || 0}px)`,
1956
+ transform: `translateY(${range.startIndex * itemHeight}px)`,
1976
1957
  },
1977
1958
  },
1978
1959
  };