cogsbox-state 0.5.288 → 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.288",
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" &&
@@ -1803,9 +1804,8 @@ function createProxyHandler<T>(
1803
1804
  return (
1804
1805
  options: VirtualViewOptions
1805
1806
  ): VirtualStateObjectResult<any[]> => {
1806
- // --- CHANGE 1: itemHeight is now optional with a default ---
1807
1807
  const {
1808
- itemHeight = 50, // Serves as a fallback for unmeasured items
1808
+ itemHeight,
1809
1809
  overscan = 5,
1810
1810
  stickToBottom = false,
1811
1811
  } = options;
@@ -1815,20 +1815,16 @@ function createProxyHandler<T>(
1815
1815
  startIndex: 0,
1816
1816
  endIndex: 10,
1817
1817
  });
1818
-
1819
- // --- CHANGE 2: Add a helper to get heights from shadow store ---
1820
- const getItemHeight = useCallback(
1821
- (index: number): number => {
1822
- const metadata = getGlobalStore
1823
- .getState()
1824
- .getShadowMetadata(stateKey, [...path, index.toString()]);
1825
- return metadata?.virtualizer?.itemHeight || itemHeight;
1826
- },
1827
- [itemHeight, stateKey, path]
1828
- );
1829
-
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 ---
1830
1825
  const isAtBottomRef = useRef(stickToBottom);
1831
1826
  const previousTotalCountRef = useRef(0);
1827
+ // NEW: Ref to explicitly track if this is the component's first render cycle.
1832
1828
  const isInitialMountRef = useRef(true);
1833
1829
 
1834
1830
  const sourceArray = getGlobalStore().getNestedState(
@@ -1837,19 +1833,6 @@ function createProxyHandler<T>(
1837
1833
  ) as any[];
1838
1834
  const totalCount = sourceArray.length;
1839
1835
 
1840
- // --- CHANGE 3: Pre-calculate total height and item positions ---
1841
- // This replaces all instances of `totalCount * itemHeight`.
1842
- const { totalHeight, positions } = useMemo(() => {
1843
- let currentHeight = 0;
1844
- const pos: number[] = [];
1845
- for (let i = 0; i < totalCount; i++) {
1846
- pos[i] = currentHeight;
1847
- currentHeight += getItemHeight(i);
1848
- }
1849
- return { totalHeight: currentHeight, positions: pos };
1850
- }, [totalCount, getItemHeight]);
1851
-
1852
- // This part is IDENTICAL to your original code
1853
1836
  const virtualState = useMemo(() => {
1854
1837
  const start = Math.max(0, range.startIndex);
1855
1838
  const end = Math.min(totalCount, range.endIndex);
@@ -1876,36 +1859,21 @@ function createProxyHandler<T>(
1876
1859
  const { scrollTop, clientHeight, scrollHeight } = container;
1877
1860
  isAtBottomRef.current =
1878
1861
  scrollHeight - scrollTop - clientHeight < 10;
1879
-
1880
- // --- CHANGE 4: Update scroll logic to use positions array ---
1881
- // This is the dynamic equivalent of `Math.floor(scrollTop / itemHeight)`.
1882
- let startIndex = 0;
1883
- // A simple loop is robust and easy to understand.
1884
- for (let i = 0; i < positions.length; i++) {
1885
- if (positions[i]! >= scrollTop) {
1886
- startIndex = i;
1887
- break;
1888
- }
1889
- }
1890
-
1891
- let endIndex = startIndex;
1892
- while (
1893
- endIndex < totalCount &&
1894
- positions[endIndex] &&
1895
- positions[endIndex]! < scrollTop + clientHeight
1896
- ) {
1897
- endIndex++;
1898
- }
1899
-
1900
- startIndex = Math.max(0, startIndex - overscan);
1901
- endIndex = Math.min(totalCount, endIndex + overscan);
1902
-
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
+ );
1903
1871
  setRange((prevRange) => {
1904
1872
  if (
1905
- prevRange.startIndex !== startIndex ||
1906
- prevRange.endIndex !== endIndex
1873
+ prevRange.startIndex !== start ||
1874
+ prevRange.endIndex !== end
1907
1875
  ) {
1908
- return { startIndex: startIndex, endIndex: endIndex };
1876
+ return { startIndex: start, endIndex: end };
1909
1877
  }
1910
1878
  return prevRange;
1911
1879
  });
@@ -1915,14 +1883,19 @@ function createProxyHandler<T>(
1915
1883
  passive: true,
1916
1884
  });
1917
1885
 
1918
- // This logic is IDENTICAL to your original code
1886
+ // --- THE CORRECTED DECISION LOGIC ---
1919
1887
  if (stickToBottom) {
1920
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.
1921
1891
  container.scrollTo({
1922
1892
  top: container.scrollHeight,
1923
1893
  behavior: "auto",
1924
1894
  });
1925
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.
1926
1899
  requestAnimationFrame(() => {
1927
1900
  container.scrollTo({
1928
1901
  top: container.scrollHeight,
@@ -1931,13 +1904,16 @@ function createProxyHandler<T>(
1931
1904
  });
1932
1905
  }
1933
1906
  }
1907
+
1908
+ // After the logic runs, it's no longer the initial mount.
1934
1909
  isInitialMountRef.current = false;
1910
+
1911
+ // Always run handleScroll once to set the initial visible window.
1935
1912
  handleScroll();
1936
1913
 
1937
1914
  return () =>
1938
1915
  container.removeEventListener("scroll", handleScroll);
1939
- // The dependencies are almost identical, just swapping itemHeight for `positions`
1940
- }, [totalCount, overscan, stickToBottom, positions]);
1916
+ }, [totalCount, itemHeight, overscan, stickToBottom]);
1941
1917
 
1942
1918
  const scrollToBottom = useCallback(
1943
1919
  (behavior: ScrollBehavior = "smooth") => {
@@ -1951,20 +1927,19 @@ function createProxyHandler<T>(
1951
1927
  []
1952
1928
  );
1953
1929
 
1954
- // --- CHANGE 5: Update scrollToIndex to use positions array ---
1955
1930
  const scrollToIndex = useCallback(
1956
1931
  (index: number, behavior: ScrollBehavior = "smooth") => {
1957
- if (containerRef.current && positions[index] !== undefined) {
1932
+ if (containerRef.current) {
1958
1933
  containerRef.current.scrollTo({
1959
- top: positions[index], // Instead of `index * itemHeight`
1934
+ top: index * itemHeight,
1960
1935
  behavior,
1961
1936
  });
1962
1937
  }
1963
1938
  },
1964
- [positions] // Depends on `positions` now instead of `itemHeight`
1939
+ [itemHeight]
1965
1940
  );
1966
1941
 
1967
- // --- CHANGE 6: Update props to use dynamic totalHeight and offsets ---
1942
+ // Same virtualizer props as before
1968
1943
  const virtualizerProps = {
1969
1944
  outer: {
1970
1945
  ref: containerRef,
@@ -1972,14 +1947,13 @@ function createProxyHandler<T>(
1972
1947
  },
1973
1948
  inner: {
1974
1949
  style: {
1975
- height: `${totalHeight}px`, // Use calculated total height
1950
+ height: `${totalCount * itemHeight}px`,
1976
1951
  position: "relative",
1977
1952
  },
1978
1953
  },
1979
1954
  list: {
1980
1955
  style: {
1981
- // Use the pre-calculated position of the first visible item
1982
- transform: `translateY(${positions[range.startIndex] || 0}px)`,
1956
+ transform: `translateY(${range.startIndex * itemHeight}px)`,
1983
1957
  },
1984
1958
  },
1985
1959
  };