cogsbox-state 0.5.318 → 0.5.320

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.318",
3
+ "version": "0.5.320",
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
@@ -1809,6 +1809,14 @@ function createProxyHandler<T>(
1809
1809
  } = options;
1810
1810
 
1811
1811
  const containerRef = useRef<HTMLDivElement | null>(null);
1812
+
1813
+ const sourceArray = getGlobalStore().getNestedState(
1814
+ stateKey,
1815
+ path
1816
+ ) as any[];
1817
+ const totalCount = sourceArray.length;
1818
+
1819
+ // Start at top, will adjust once container is measured
1812
1820
  const [range, setRange] = useState({
1813
1821
  startIndex: 0,
1814
1822
  endIndex: 10,
@@ -1816,104 +1824,41 @@ function createProxyHandler<T>(
1816
1824
 
1817
1825
  const isLockedToBottomRef = useRef(stickToBottom);
1818
1826
  const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
1819
-
1820
- // Track if we've scrolled to bottom after initial load
1821
- const hasScrolledToBottomRef = useRef(false);
1822
- const lastTotalCountRef = useRef(0);
1827
+ const hasInitializedRef = useRef(false);
1823
1828
 
1824
1829
  useEffect(() => {
1825
- let updateCount = 0;
1826
1830
  const unsubscribe = getGlobalStore
1827
1831
  .getState()
1828
1832
  .subscribeToShadowState(stateKey, () => {
1829
- updateCount++;
1830
- if (updateCount <= 5) {
1831
- console.log(
1832
- `[VirtualView] Shadow update #${updateCount}`
1833
- );
1834
- }
1835
1833
  setShadowUpdateTrigger((prev) => prev + 1);
1836
1834
  });
1837
1835
  return unsubscribe;
1838
1836
  }, [stateKey]);
1839
1837
 
1840
- const sourceArray = getGlobalStore().getNestedState(
1838
+ const { totalHeight, positions } = useMemo(() => {
1839
+ const shadowArray =
1840
+ getGlobalStore.getState().getShadowMetadata(stateKey, path) ||
1841
+ [];
1842
+ let height = 0;
1843
+ const pos: number[] = [];
1844
+ for (let i = 0; i < totalCount; i++) {
1845
+ pos[i] = height;
1846
+ const measuredHeight =
1847
+ shadowArray[i]?.virtualizer?.itemHeight;
1848
+ height += measuredHeight || itemHeight;
1849
+ }
1850
+ return { totalHeight: height, positions: pos };
1851
+ }, [
1852
+ totalCount,
1841
1853
  stateKey,
1842
- path
1843
- ) as any[];
1844
- const totalCount = sourceArray.length;
1845
-
1846
- console.log(
1847
- `[VirtualView] Initial setup - totalCount: ${totalCount}, itemHeight: ${itemHeight}, stickToBottom: ${stickToBottom}`
1848
- );
1854
+ path.join("."),
1855
+ itemHeight,
1856
+ shadowUpdateTrigger,
1857
+ ]);
1849
1858
 
1850
- // Reset when array size changes significantly
1851
- if (totalCount !== lastTotalCountRef.current) {
1852
- console.log(
1853
- `[VirtualView] Array size changed from ${lastTotalCountRef.current} to ${totalCount}`
1854
- );
1855
- hasScrolledToBottomRef.current = false;
1856
- lastTotalCountRef.current = totalCount;
1857
- }
1858
-
1859
- // Calculate heights from shadow state
1860
- const { totalHeight, positions, visibleMeasured } =
1861
- useMemo(() => {
1862
- const shadowArray =
1863
- getGlobalStore
1864
- .getState()
1865
- .getShadowMetadata(stateKey, path) || [];
1866
- let height = 0;
1867
- const pos: number[] = [];
1868
- let measuredCount = 0;
1869
- let visibleMeasuredCount = 0;
1870
-
1871
- for (let i = 0; i < totalCount; i++) {
1872
- pos[i] = height;
1873
- const measuredHeight =
1874
- shadowArray[i]?.virtualizer?.itemHeight;
1875
- if (measuredHeight) {
1876
- measuredCount++;
1877
- // Count measured items in current visible range
1878
- if (i >= range.startIndex && i < range.endIndex) {
1879
- visibleMeasuredCount++;
1880
- }
1881
- }
1882
- height += measuredHeight || itemHeight;
1883
- }
1884
-
1885
- // Check if all VISIBLE items are measured
1886
- const visibleCount = range.endIndex - range.startIndex;
1887
- const allVisibleMeasured =
1888
- visibleMeasuredCount === visibleCount && visibleCount > 0;
1889
-
1890
- console.log(
1891
- `[VirtualView] Heights calc - measured: ${measuredCount}/${totalCount}, visible measured: ${visibleMeasuredCount}/${visibleCount}, totalHeight: ${height}`
1892
- );
1893
-
1894
- return {
1895
- totalHeight: height,
1896
- positions: pos,
1897
- visibleMeasured: allVisibleMeasured,
1898
- };
1899
- }, [
1900
- totalCount,
1901
- stateKey,
1902
- path.join("."),
1903
- itemHeight,
1904
- shadowUpdateTrigger,
1905
- range, // Add range dependency
1906
- ]);
1907
-
1908
- // Memoize the virtualized slice
1909
1859
  const virtualState = useMemo(() => {
1910
1860
  const start = Math.max(0, range.startIndex);
1911
1861
  const end = Math.min(totalCount, range.endIndex);
1912
-
1913
- console.log(
1914
- `[VirtualView] Creating virtual slice - range: ${start}-${end} (${end - start} items)`
1915
- );
1916
-
1917
1862
  const validIndices = Array.from(
1918
1863
  { length: end - start },
1919
1864
  (_, i) => start + i
@@ -1925,7 +1870,6 @@ function createProxyHandler<T>(
1925
1870
  });
1926
1871
  }, [range.startIndex, range.endIndex, sourceArray, totalCount]);
1927
1872
 
1928
- // Main layout effect
1929
1873
  useLayoutEffect(() => {
1930
1874
  const container = containerRef.current;
1931
1875
  if (!container) return;
@@ -1966,44 +1910,32 @@ function createProxyHandler<T>(
1966
1910
  passive: true,
1967
1911
  });
1968
1912
 
1969
- // For stick to bottom: check conditions without triggering re-renders
1913
+ // Initialize at bottom if needed
1970
1914
  if (
1971
1915
  stickToBottom &&
1972
- !hasScrolledToBottomRef.current &&
1973
- totalCount > 0
1916
+ !hasInitializedRef.current &&
1917
+ totalCount > 0 &&
1918
+ container.clientHeight > 0
1974
1919
  ) {
1975
- // Check current range without dependency
1976
- const currentRange = range;
1977
- const atEnd = currentRange.endIndex >= totalCount - 5; // Close to end
1920
+ hasInitializedRef.current = true;
1978
1921
 
1979
- if (atEnd) {
1980
- console.log(
1981
- `[VirtualView] At end of list, scrolling to bottom`
1982
- );
1983
- hasScrolledToBottomRef.current = true;
1984
-
1985
- setTimeout(() => {
1986
- const scrollTarget = container.scrollHeight + 1000;
1987
- container.scrollTo({
1988
- top: scrollTarget,
1989
- behavior: "auto",
1990
- });
1991
- isLockedToBottomRef.current = true;
1992
- }, 50);
1993
- } else {
1994
- // Jump close to the bottom
1995
- console.log(
1996
- `[VirtualView] Jumping near bottom to trigger measurements`
1997
- );
1998
- const estimatedScrollPosition = Math.max(
1999
- 0,
2000
- (totalCount - 20) * itemHeight
2001
- );
2002
- container.scrollTo({
2003
- top: estimatedScrollPosition,
2004
- behavior: "auto",
2005
- });
2006
- }
1922
+ // Now we have the actual container height, calculate visible items
1923
+ const visibleCount = Math.ceil(
1924
+ container.clientHeight / itemHeight
1925
+ );
1926
+ const startIdx = Math.max(
1927
+ 0,
1928
+ totalCount - visibleCount - overscan
1929
+ );
1930
+
1931
+ // Set range to show bottom items
1932
+ setRange({
1933
+ startIndex: startIdx,
1934
+ endIndex: totalCount,
1935
+ });
1936
+
1937
+ // Scroll to bottom
1938
+ container.scrollTop = container.scrollHeight;
2007
1939
  }
2008
1940
 
2009
1941
  updateVirtualRange();
@@ -2011,7 +1943,7 @@ function createProxyHandler<T>(
2011
1943
  return () => {
2012
1944
  container.removeEventListener("scroll", handleUserScroll);
2013
1945
  };
2014
- }, [totalCount, positions, stickToBottom]); // Removed visibleMeasured and range.endIndex
1946
+ }, [totalCount, positions, stickToBottom, itemHeight, overscan]);
2015
1947
 
2016
1948
  const scrollToBottom = useCallback(
2017
1949
  (behavior: ScrollBehavior = "smooth") => {