cogsbox-state 0.5.374 → 0.5.375

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.374",
3
+ "version": "0.5.375",
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,6 +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);
1830
1831
 
1831
1832
  const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
1832
1833
 
@@ -2000,30 +2001,63 @@ function createProxyHandler<T>(
2000
2001
  const container = containerRef.current;
2001
2002
  if (!container) return;
2002
2003
 
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;
2007
+
2003
2008
  const handleUserScroll = () => {
2004
- // This is the core logic you wanted.
2009
+ // Exit early for programmatic scrolls. This is still essential.
2005
2010
  if (isProgrammaticScroll.current) {
2006
2011
  return;
2007
2012
  }
2013
+
2014
+ const scrollTop = container.scrollTop;
2015
+
2016
+ // --- Part 1: Handle state changes immediately (this is cheap) ---
2008
2017
  const isAtBottom =
2009
2018
  container.scrollHeight -
2010
- container.scrollTop -
2019
+ scrollTop -
2011
2020
  container.clientHeight <
2012
2021
  1;
2013
2022
 
2014
2023
  if (!isAtBottom) {
2015
- console.log(
2016
- "USER ACTION: Scrolled up -> IDLE_NOT_AT_BOTTOM"
2017
- );
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
+ }
2018
2030
  shouldNotScroll.current = true;
2019
- setStatus("IDLE_NOT_AT_BOTTOM");
2020
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
+ }
2021
2038
  shouldNotScroll.current = false;
2022
2039
  }
2023
2040
 
2024
- // We always update the range, regardless of state.
2025
- // This is the full, non-placeholder function.
2026
- const { scrollTop, clientHeight } = container;
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.
2045
+ if (
2046
+ Math.abs(scrollTop - lastScrollTopRef.current) <
2047
+ scrollThreshold
2048
+ ) {
2049
+ // Not scrolled far enough, do nothing.
2050
+ return;
2051
+ }
2052
+
2053
+ // If we've passed the threshold, update our reference for the next check.
2054
+ lastScrollTopRef.current = scrollTop;
2055
+
2056
+ console.log("Threshold passed: Updating virtual range."); // For debugging
2057
+
2058
+ // --- Part 3: Run the expensive calculation ---
2059
+ // This code now only runs when it's actually needed.
2060
+ const { clientHeight } = container;
2027
2061
  let low = 0,
2028
2062
  high = totalCount - 1;
2029
2063
  while (low <= high) {
@@ -2051,7 +2085,7 @@ function createProxyHandler<T>(
2051
2085
  });
2052
2086
  return () =>
2053
2087
  container.removeEventListener("scroll", handleUserScroll);
2054
- }, [totalCount, positions, status]); // Depends on status to know if it should break the lock
2088
+ }, [totalCount, positions, status, itemHeight]); // Added itemHeight to deps
2055
2089
 
2056
2090
  const scrollToBottom = useCallback(() => {
2057
2091
  console.log(