cogsbox-state 0.5.298 → 0.5.300

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.298",
3
+ "version": "0.5.300",
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
@@ -1876,20 +1876,28 @@ function createProxyHandler<T>(
1876
1876
  validIndices,
1877
1877
  });
1878
1878
  }, [range.startIndex, range.endIndex, sourceArray]);
1879
-
1880
1879
  useLayoutEffect(() => {
1881
1880
  const container = containerRef.current;
1882
1881
  if (!container) return;
1883
1882
 
1884
- const wasAtBottom = isAtBottomRef.current;
1885
1883
  const listGrew = totalCount > previousTotalCountRef.current;
1884
+
1885
+ // --- THE FIX for BOTH initial load and new entries ---
1886
+ // We capture the scroll position *before* we do anything else.
1887
+ // We also check if we are VERY close to the bottom. This will be true
1888
+ // on initial load (0 scrollHeight, 0 scrollTop) and when user is at the end.
1889
+ const wasAtBottom =
1890
+ container.scrollHeight -
1891
+ container.scrollTop -
1892
+ container.clientHeight <
1893
+ 5;
1894
+
1895
+ // Now we update the ref for the *next* render cycle.
1886
1896
  previousTotalCountRef.current = totalCount;
1887
1897
 
1888
1898
  const handleScroll = () => {
1899
+ // ... (binary search logic to setRange is the same) ...
1889
1900
  const { scrollTop, clientHeight, scrollHeight } = container;
1890
- isAtBottomRef.current =
1891
- scrollHeight - scrollTop - clientHeight < 10;
1892
-
1893
1901
  let search = (list: number[], value: number) => {
1894
1902
  let low = 0;
1895
1903
  let high = list.length - 1;
@@ -1903,7 +1911,6 @@ function createProxyHandler<T>(
1903
1911
  }
1904
1912
  return low;
1905
1913
  };
1906
-
1907
1914
  let startIndex = search(positions, scrollTop);
1908
1915
  let endIndex = startIndex;
1909
1916
  while (
@@ -1912,10 +1919,8 @@ function createProxyHandler<T>(
1912
1919
  ) {
1913
1920
  endIndex++;
1914
1921
  }
1915
-
1916
1922
  startIndex = Math.max(0, startIndex - overscan);
1917
1923
  endIndex = Math.min(totalCount, endIndex + overscan);
1918
-
1919
1924
  setRange((prevRange) => {
1920
1925
  if (
1921
1926
  prevRange.startIndex !== startIndex ||
@@ -1930,23 +1935,24 @@ function createProxyHandler<T>(
1930
1935
  container.addEventListener("scroll", handleScroll, {
1931
1936
  passive: true,
1932
1937
  });
1938
+ handleScroll();
1933
1939
 
1934
- if (stickToBottom) {
1935
- if (isInitialMountRef.current) {
1936
- container.scrollTo({
1937
- top: container.scrollHeight,
1938
- behavior: "auto",
1939
- });
1940
- } else if (wasAtBottom && listGrew) {
1941
- // Use 'auto' for an instant jump to the bottom to prevent visual glitches.
1942
- container.scrollTo({
1943
- top: container.scrollHeight,
1944
- behavior: "auto",
1945
- });
1946
- }
1940
+ // This single block now handles all cases.
1941
+ if (
1942
+ stickToBottom &&
1943
+ (listGrew || isInitialMountRef.current) &&
1944
+ wasAtBottom
1945
+ ) {
1946
+ container.scrollTo({
1947
+ top: container.scrollHeight,
1948
+ behavior: "auto",
1949
+ });
1950
+ }
1951
+
1952
+ // We only set this to false after the first correct layout has been established.
1953
+ if (positions.length > 0) {
1954
+ isInitialMountRef.current = false;
1947
1955
  }
1948
- isInitialMountRef.current = false;
1949
- handleScroll();
1950
1956
 
1951
1957
  return () =>
1952
1958
  container.removeEventListener("scroll", handleScroll);