cogsbox-state 0.5.303 → 0.5.304

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.303",
3
+ "version": "0.5.304",
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
@@ -1814,28 +1814,9 @@ function createProxyHandler<T>(
1814
1814
  endIndex: 10,
1815
1815
  });
1816
1816
 
1817
- const [heightsVersion, setHeightsVersion] = useState(0);
1818
- const forceRecalculate = useCallback(
1819
- () => setHeightsVersion((v) => v + 1),
1820
- []
1821
- );
1822
-
1823
- // Track scroll position
1824
1817
  const isAtBottomRef = useRef(stickToBottom);
1825
1818
  const previousTotalCountRef = useRef(0);
1826
1819
  const isInitialMountRef = useRef(true);
1827
- const hasScrolledToBottomRef = useRef(false); // Track if we've done initial scroll
1828
-
1829
- useEffect(() => {
1830
- const unsubscribe = getGlobalStore
1831
- .getState()
1832
- .subscribeToShadowState(stateKey, forceRecalculate);
1833
- const timer = setTimeout(forceRecalculate, 50);
1834
- return () => {
1835
- unsubscribe();
1836
- clearTimeout(timer);
1837
- };
1838
- }, [stateKey, forceRecalculate]);
1839
1820
 
1840
1821
  const sourceArray = getGlobalStore().getNestedState(
1841
1822
  stateKey,
@@ -1843,32 +1824,23 @@ function createProxyHandler<T>(
1843
1824
  ) as any[];
1844
1825
  const totalCount = sourceArray.length;
1845
1826
 
1846
- const { totalHeight, positions, allItemsMeasured } =
1847
- useMemo(() => {
1848
- const shadowArray =
1849
- getGlobalStore
1850
- .getState()
1851
- .getShadowMetadata(stateKey, path) || [];
1852
- let height = 0;
1853
- const pos: number[] = [];
1854
- let measured = true;
1855
-
1856
- for (let i = 0; i < totalCount; i++) {
1857
- pos[i] = height;
1858
- const measuredHeight =
1859
- shadowArray[i]?.virtualizer?.itemHeight;
1860
- if (!measuredHeight && totalCount > 0) {
1861
- measured = false;
1862
- }
1863
- height += measuredHeight || itemHeight;
1864
- }
1827
+ // Calculate heights from shadow state
1828
+ const { totalHeight, positions } = useMemo(() => {
1829
+ const shadowArray =
1830
+ getGlobalStore.getState().getShadowMetadata(stateKey, path) ||
1831
+ [];
1832
+ let height = 0;
1833
+ const pos: number[] = [];
1834
+
1835
+ for (let i = 0; i < totalCount; i++) {
1836
+ pos[i] = height;
1837
+ const measuredHeight =
1838
+ shadowArray[i]?.virtualizer?.itemHeight;
1839
+ height += measuredHeight || itemHeight;
1840
+ }
1865
1841
 
1866
- return {
1867
- totalHeight: height,
1868
- positions: pos,
1869
- allItemsMeasured: measured,
1870
- };
1871
- }, [totalCount, stateKey, path, itemHeight, heightsVersion]);
1842
+ return { totalHeight: height, positions: pos };
1843
+ }, [totalCount, stateKey, path.join("."), itemHeight]);
1872
1844
 
1873
1845
  const virtualState = useMemo(() => {
1874
1846
  const start = Math.max(0, range.startIndex);
@@ -1894,7 +1866,6 @@ function createProxyHandler<T>(
1894
1866
 
1895
1867
  const handleScroll = () => {
1896
1868
  const { scrollTop, clientHeight, scrollHeight } = container;
1897
- // Consider "at bottom" if within 10px
1898
1869
  isAtBottomRef.current =
1899
1870
  scrollHeight - scrollTop - clientHeight < 10;
1900
1871
 
@@ -1939,37 +1910,18 @@ function createProxyHandler<T>(
1939
1910
 
1940
1911
  // Handle stick to bottom
1941
1912
  if (stickToBottom) {
1942
- if (
1943
- isInitialMountRef.current &&
1944
- !hasScrolledToBottomRef.current
1945
- ) {
1946
- // For initial mount, wait for items to be measured
1947
- if (allItemsMeasured && totalCount > 0) {
1948
- container.scrollTo({
1949
- top: container.scrollHeight,
1950
- behavior: "auto",
1951
- });
1952
- hasScrolledToBottomRef.current = true;
1953
- isInitialMountRef.current = false;
1954
- } else if (totalCount > 0) {
1955
- // If not all measured yet, try again soon
1956
- const retryTimer = setTimeout(() => {
1957
- if (containerRef.current && isInitialMountRef.current) {
1958
- containerRef.current.scrollTo({
1959
- top: containerRef.current.scrollHeight,
1960
- behavior: "auto",
1961
- });
1962
- hasScrolledToBottomRef.current = true;
1963
- isInitialMountRef.current = false;
1964
- }
1965
- }, 100);
1966
- return () => clearTimeout(retryTimer);
1967
- }
1968
- } else if (
1969
- !isInitialMountRef.current &&
1970
- wasAtBottom &&
1971
- listGrew
1972
- ) {
1913
+ if (isInitialMountRef.current && totalCount > 0) {
1914
+ // Delay initial scroll to ensure items are rendered
1915
+ setTimeout(() => {
1916
+ if (containerRef.current) {
1917
+ containerRef.current.scrollTo({
1918
+ top: containerRef.current.scrollHeight,
1919
+ behavior: "auto",
1920
+ });
1921
+ }
1922
+ }, 0);
1923
+ isInitialMountRef.current = false;
1924
+ } else if (wasAtBottom && listGrew) {
1973
1925
  // New items added and we were at bottom - stay at bottom
1974
1926
  requestAnimationFrame(() => {
1975
1927
  container.scrollTo({
@@ -1987,13 +1939,7 @@ function createProxyHandler<T>(
1987
1939
 
1988
1940
  return () =>
1989
1941
  container.removeEventListener("scroll", handleScroll);
1990
- }, [
1991
- totalCount,
1992
- positions,
1993
- overscan,
1994
- stickToBottom,
1995
- allItemsMeasured,
1996
- ]);
1942
+ }, [totalCount, positions, overscan, stickToBottom]);
1997
1943
 
1998
1944
  const scrollToBottom = useCallback(
1999
1945
  (behavior: ScrollBehavior = "smooth") => {