cogsbox-state 0.5.375 → 0.5.377

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.375",
3
+ "version": "0.5.377",
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
@@ -1827,8 +1827,7 @@ function createProxyHandler<T>(
1827
1827
  const isProgrammaticScroll = useRef(false);
1828
1828
  const prevTotalCountRef = useRef(0);
1829
1829
  const prevDepsRef = useRef(dependencies);
1830
- const lastScrollTopRef = useRef(0);
1831
-
1830
+ const lastUpdateAtScrollTop = useRef(0);
1832
1831
  const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
1833
1832
 
1834
1833
  useEffect(() => {
@@ -2001,71 +2000,49 @@ function createProxyHandler<T>(
2001
2000
  const container = containerRef.current;
2002
2001
  if (!container) return;
2003
2002
 
2004
- // Define our threshold. Updating every half-item feels very smooth.
2005
- // You can adjust this value. Using a full itemHeight also works well.
2006
- const scrollThreshold = itemHeight / 2;
2003
+ // The scroll distance threshold. One item's height is a great default.
2004
+ const scrollThreshold = itemHeight;
2007
2005
 
2008
2006
  const handleUserScroll = () => {
2009
- // Exit early for programmatic scrolls. This is still essential.
2007
+ // Essential guard for our own programmatic scrolls.
2010
2008
  if (isProgrammaticScroll.current) {
2011
2009
  return;
2012
2010
  }
2013
2011
 
2014
2012
  const scrollTop = container.scrollTop;
2015
2013
 
2016
- // --- Part 1: Handle state changes immediately (this is cheap) ---
2017
- const isAtBottom =
2018
- container.scrollHeight -
2019
- scrollTop -
2020
- container.clientHeight <
2021
- 1;
2022
-
2023
- if (!isAtBottom) {
2024
- if (status !== "IDLE_NOT_AT_BOTTOM") {
2025
- console.log(
2026
- "USER ACTION: Scrolled up -> IDLE_NOT_AT_BOTTOM"
2027
- );
2028
- setStatus("IDLE_NOT_AT_BOTTOM");
2029
- }
2030
- shouldNotScroll.current = true;
2031
- } else {
2032
- if (status === "IDLE_NOT_AT_BOTTOM") {
2033
- console.log(
2034
- "USER ACTION: Scrolled back to bottom -> LOCKED_AT_BOTTOM"
2035
- );
2036
- setStatus("LOCKED_AT_BOTTOM");
2037
- }
2038
- shouldNotScroll.current = false;
2039
- }
2040
-
2041
- // --- Part 2: The "Smarter" Threshold Check ---
2042
-
2043
- // Check if the scroll distance is greater than our threshold.
2044
- // Math.abs() handles both scrolling up and down.
2014
+ // --- THE CORE LOGIC YOU REQUESTED ---
2015
+ // Is the user just wiggling the scrollbar? If so, exit.
2016
+ // This is a very cheap check that runs on every scroll event.
2045
2017
  if (
2046
- Math.abs(scrollTop - lastScrollTopRef.current) <
2018
+ Math.abs(scrollTop - lastUpdateAtScrollTop.current) <
2047
2019
  scrollThreshold
2048
2020
  ) {
2049
- // Not scrolled far enough, do nothing.
2050
2021
  return;
2051
2022
  }
2052
2023
 
2053
- // If we've passed the threshold, update our reference for the next check.
2054
- lastScrollTopRef.current = scrollTop;
2024
+ // --- IF WE ARE HERE, WE HAVE SCROLLED A "DECENT AMOUNT" ---
2055
2025
 
2056
- console.log("Threshold passed: Updating virtual range."); // For debugging
2026
+ console.log(
2027
+ `Threshold passed at ${scrollTop}px. Recalculating range...`
2028
+ );
2057
2029
 
2058
- // --- Part 3: Run the expensive calculation ---
2059
- // This code now only runs when it's actually needed.
2030
+ // NOW we do the expensive work.
2060
2031
  const { clientHeight } = container;
2061
- let low = 0,
2062
- high = totalCount - 1;
2032
+ let high = totalCount - 1;
2033
+ let low = 0;
2034
+ let topItemIndex = 0;
2063
2035
  while (low <= high) {
2064
2036
  const mid = Math.floor((low + high) / 2);
2065
- if (positions[mid]! < scrollTop) low = mid + 1;
2066
- else high = mid - 1;
2037
+ if (positions[mid]! < scrollTop) {
2038
+ topItemIndex = mid;
2039
+ low = mid + 1;
2040
+ } else {
2041
+ high = mid - 1;
2042
+ }
2067
2043
  }
2068
- const startIndex = Math.max(0, high - overscan);
2044
+
2045
+ const startIndex = Math.max(0, topItemIndex - overscan);
2069
2046
  let endIndex = startIndex;
2070
2047
  const visibleEnd = scrollTop + clientHeight;
2071
2048
  while (
@@ -2074,10 +2051,14 @@ function createProxyHandler<T>(
2074
2051
  ) {
2075
2052
  endIndex++;
2076
2053
  }
2054
+
2077
2055
  setRange({
2078
2056
  startIndex,
2079
2057
  endIndex: Math.min(totalCount, endIndex + overscan),
2080
2058
  });
2059
+
2060
+ // Finally, we record that we did the work at THIS scroll position.
2061
+ lastUpdateAtScrollTop.current = scrollTop;
2081
2062
  };
2082
2063
 
2083
2064
  container.addEventListener("scroll", handleUserScroll, {
@@ -2085,7 +2066,7 @@ function createProxyHandler<T>(
2085
2066
  });
2086
2067
  return () =>
2087
2068
  container.removeEventListener("scroll", handleUserScroll);
2088
- }, [totalCount, positions, status, itemHeight]); // Added itemHeight to deps
2069
+ }, [totalCount, positions, itemHeight, overscan, status]);
2089
2070
 
2090
2071
  const scrollToBottom = useCallback(() => {
2091
2072
  console.log(