cogsbox-state 0.5.422 → 0.5.424

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.422",
3
+ "version": "0.5.424",
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
@@ -1824,7 +1824,7 @@ function createProxyHandler<T>(
1824
1824
  const wasAtBottomRef = useRef(true);
1825
1825
  const userHasScrolledAwayRef = useRef(false);
1826
1826
  const previousCountRef = useRef(0);
1827
-
1827
+ const lastRangeRef = useRef(range);
1828
1828
  // Subscribe to shadow state updates
1829
1829
  useEffect(() => {
1830
1830
  const unsubscribe = getGlobalStore
@@ -1930,12 +1930,8 @@ function createProxyHandler<T>(
1930
1930
  setRange(newRange);
1931
1931
 
1932
1932
  const timeoutId = setTimeout(() => {
1933
- if (containerRef.current) {
1934
- containerRef.current.scrollTop =
1935
- containerRef.current.scrollHeight;
1936
- }
1933
+ scrollToIndex(totalCount - 1, "smooth");
1937
1934
  }, 50);
1938
-
1939
1935
  return () => clearTimeout(timeoutId);
1940
1936
  }
1941
1937
 
@@ -1960,7 +1956,7 @@ function createProxyHandler<T>(
1960
1956
  userHasScrolledAwayRef.current = true;
1961
1957
  }
1962
1958
 
1963
- // If user scrolls back to bottom, clear flag
1959
+ // If user scrolls back to bottom, cle
1964
1960
  if (distanceFromBottom < 5) {
1965
1961
  userHasScrolledAwayRef.current = false;
1966
1962
  }
@@ -1983,10 +1979,26 @@ function createProxyHandler<T>(
1983
1979
  endIndex = i;
1984
1980
  }
1985
1981
 
1986
- setRange({
1987
- startIndex: Math.max(0, startIndex),
1988
- endIndex: Math.min(totalCount, endIndex + 1 + overscan),
1989
- });
1982
+ const newStartIndex = Math.max(0, startIndex);
1983
+ const newEndIndex = Math.min(
1984
+ totalCount,
1985
+ endIndex + 1 + overscan
1986
+ );
1987
+
1988
+ // THE FIX: Only update state if the visible range of items has changed.
1989
+ if (
1990
+ newStartIndex !== lastRangeRef.current.startIndex ||
1991
+ newEndIndex !== lastRangeRef.current.endIndex
1992
+ ) {
1993
+ lastRangeRef.current = {
1994
+ startIndex: newStartIndex,
1995
+ endIndex: newEndIndex,
1996
+ };
1997
+ setRange({
1998
+ startIndex: newStartIndex,
1999
+ endIndex: newEndIndex,
2000
+ });
2001
+ }
1990
2002
  };
1991
2003
 
1992
2004
  container.addEventListener("scroll", handleScroll, {
@@ -2023,32 +2035,48 @@ function createProxyHandler<T>(
2023
2035
  containerRef.current.scrollHeight;
2024
2036
  }
2025
2037
  }, [scrollToLastItem]);
2026
-
2027
2038
  const scrollToIndex = useCallback(
2028
2039
  (index: number, behavior: ScrollBehavior = "smooth") => {
2040
+ const container = containerRef.current;
2041
+ if (!container) return;
2042
+
2043
+ const isLastItem = index === totalCount - 1;
2044
+
2045
+ // --- Special Case: The Last Item ---
2046
+ if (isLastItem) {
2047
+ // For the last item, scrollIntoView can fail. The most reliable method
2048
+ // is to scroll the parent container to its maximum scroll height.
2049
+ container.scrollTo({
2050
+ top: container.scrollHeight,
2051
+ behavior: behavior,
2052
+ });
2053
+ return; // We're done.
2054
+ }
2055
+
2056
+ // --- Standard Case: All Other Items ---
2057
+ // For all other items, we find the ref and use scrollIntoView.
2029
2058
  const shadowArray =
2030
2059
  getGlobalStore
2031
2060
  .getState()
2032
2061
  .getShadowMetadata(stateKey, path) || [];
2033
2062
  const itemData = shadowArray[index];
2063
+ const element = itemData?.virtualizer?.domRef;
2034
2064
 
2035
- if (itemData?.virtualizer?.domRef) {
2036
- const element = itemData.virtualizer.domRef;
2037
- if (element && element.scrollIntoView) {
2038
- element.scrollIntoView({ behavior, block: "end" });
2039
- return;
2040
- }
2041
- }
2042
-
2043
- // Fallback to position-based scrolling
2044
- if (containerRef.current && positions[index] !== undefined) {
2045
- containerRef.current.scrollTo({
2065
+ if (element) {
2066
+ // 'center' gives a better user experience for items in the middle of the list.
2067
+ element.scrollIntoView({
2068
+ behavior: behavior,
2069
+ block: "center",
2070
+ });
2071
+ } else if (positions[index] !== undefined) {
2072
+ // Fallback if the ref isn't available for some reason.
2073
+ container.scrollTo({
2046
2074
  top: positions[index],
2047
2075
  behavior,
2048
2076
  });
2049
2077
  }
2050
2078
  },
2051
- [positions, stateKey, path]
2079
+ [positions, stateKey, path, totalCount] // Add totalCount to the dependencies
2052
2080
  );
2053
2081
 
2054
2082
  const virtualizerProps = {