cogsbox-state 0.5.295 → 0.5.297
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/dist/CogsState.jsx +365 -367
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +54 -49
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1802,7 +1802,6 @@ function createProxyHandler<T>(
|
|
|
1802
1802
|
return (
|
|
1803
1803
|
options: VirtualViewOptions
|
|
1804
1804
|
): VirtualStateObjectResult<any[]> => {
|
|
1805
|
-
// --- CHANGE 1: itemHeight is now optional, with a default fallback.
|
|
1806
1805
|
const {
|
|
1807
1806
|
itemHeight = 50, // Default/estimated height
|
|
1808
1807
|
overscan = 5,
|
|
@@ -1815,18 +1814,26 @@ function createProxyHandler<T>(
|
|
|
1815
1814
|
endIndex: 10,
|
|
1816
1815
|
});
|
|
1817
1816
|
|
|
1818
|
-
// ---
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
},
|
|
1826
|
-
[itemHeight, stateKey, path]
|
|
1817
|
+
// --- STATE AND CALLBACKS FOR HEIGHTS ---
|
|
1818
|
+
// This state value is the key. We increment it to force a re-calculation.
|
|
1819
|
+
const [heightsVersion, setHeightsVersion] = useState(0);
|
|
1820
|
+
// This callback is stable and won't cause re-renders itself.
|
|
1821
|
+
const forceRecalculate = useCallback(
|
|
1822
|
+
() => setHeightsVersion((v) => v + 1),
|
|
1823
|
+
[]
|
|
1827
1824
|
);
|
|
1828
1825
|
|
|
1829
|
-
// ---
|
|
1826
|
+
// --- ON MOUNT: SCHEDULE A RECALCULATION ---
|
|
1827
|
+
// This solves the "initial load" problem. It ensures that after the first
|
|
1828
|
+
// items render and measure themselves, we run the calculations again
|
|
1829
|
+
// with the new, correct height data.
|
|
1830
|
+
useEffect(() => {
|
|
1831
|
+
const timer = setTimeout(() => {
|
|
1832
|
+
forceRecalculate();
|
|
1833
|
+
}, 50); // A small delay helps batch initial measurements.
|
|
1834
|
+
return () => clearTimeout(timer);
|
|
1835
|
+
}, [forceRecalculate]);
|
|
1836
|
+
|
|
1830
1837
|
const isAtBottomRef = useRef(stickToBottom);
|
|
1831
1838
|
const previousTotalCountRef = useRef(0);
|
|
1832
1839
|
const isInitialMountRef = useRef(true);
|
|
@@ -1837,19 +1844,27 @@ function createProxyHandler<T>(
|
|
|
1837
1844
|
) as any[];
|
|
1838
1845
|
const totalCount = sourceArray.length;
|
|
1839
1846
|
|
|
1840
|
-
// ---
|
|
1841
|
-
// This is the only new block of logic required.
|
|
1847
|
+
// --- EFFICIENT HEIGHT & POSITION CALCULATION ---
|
|
1842
1848
|
const { totalHeight, positions } = useMemo(() => {
|
|
1849
|
+
// Get the shadow object for the whole array ONCE. This is fast.
|
|
1850
|
+
const shadowArray =
|
|
1851
|
+
getGlobalStore.getState().getShadowMetadata(stateKey, path) ||
|
|
1852
|
+
[];
|
|
1853
|
+
|
|
1843
1854
|
let height = 0;
|
|
1844
1855
|
const pos: number[] = [];
|
|
1845
1856
|
for (let i = 0; i < totalCount; i++) {
|
|
1846
1857
|
pos[i] = height;
|
|
1847
|
-
height
|
|
1858
|
+
// Access the height from the local shadowArray. No repeated deep lookups.
|
|
1859
|
+
const measuredHeight =
|
|
1860
|
+
shadowArray[i]?.virtualizer?.itemHeight;
|
|
1861
|
+
height += measuredHeight || itemHeight;
|
|
1848
1862
|
}
|
|
1849
1863
|
return { totalHeight: height, positions: pos };
|
|
1850
|
-
|
|
1864
|
+
// This now depends on `heightsVersion`, so it re-runs when we force it.
|
|
1865
|
+
}, [totalCount, stateKey, path, itemHeight, heightsVersion]);
|
|
1851
1866
|
|
|
1852
|
-
//
|
|
1867
|
+
// This logic is from your original working code.
|
|
1853
1868
|
const virtualState = useMemo(() => {
|
|
1854
1869
|
const start = Math.max(0, range.startIndex);
|
|
1855
1870
|
const end = Math.min(totalCount, range.endIndex);
|
|
@@ -1864,8 +1879,7 @@ function createProxyHandler<T>(
|
|
|
1864
1879
|
});
|
|
1865
1880
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1866
1881
|
|
|
1867
|
-
//
|
|
1868
|
-
// --- We only change the math inside handleScroll. ---
|
|
1882
|
+
// This is your original useLayoutEffect with the robust index calculation.
|
|
1869
1883
|
useLayoutEffect(() => {
|
|
1870
1884
|
const container = containerRef.current;
|
|
1871
1885
|
if (!container) return;
|
|
@@ -1879,19 +1893,24 @@ function createProxyHandler<T>(
|
|
|
1879
1893
|
isAtBottomRef.current =
|
|
1880
1894
|
scrollHeight - scrollTop - clientHeight < 10;
|
|
1881
1895
|
|
|
1882
|
-
//
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1896
|
+
// ROBUST: Binary search to find the start index. Prevents errors.
|
|
1897
|
+
let search = (list: number[], value: number) => {
|
|
1898
|
+
let low = 0;
|
|
1899
|
+
let high = list.length - 1;
|
|
1900
|
+
while (low <= high) {
|
|
1901
|
+
const mid = Math.floor((low + high) / 2);
|
|
1902
|
+
if (list[mid]! < value) {
|
|
1903
|
+
low = mid + 1;
|
|
1904
|
+
} else {
|
|
1905
|
+
high = mid - 1;
|
|
1906
|
+
}
|
|
1890
1907
|
}
|
|
1891
|
-
|
|
1908
|
+
return low;
|
|
1909
|
+
};
|
|
1910
|
+
|
|
1911
|
+
let startIndex = search(positions, scrollTop);
|
|
1892
1912
|
|
|
1893
1913
|
let endIndex = startIndex;
|
|
1894
|
-
// Find the first item whose top position is past the bottom of the viewport.
|
|
1895
1914
|
while (
|
|
1896
1915
|
endIndex < totalCount &&
|
|
1897
1916
|
positions[endIndex]! < scrollTop + clientHeight
|
|
@@ -1899,23 +1918,15 @@ function createProxyHandler<T>(
|
|
|
1899
1918
|
endIndex++;
|
|
1900
1919
|
}
|
|
1901
1920
|
|
|
1902
|
-
// Apply overscan, identical to your original code.
|
|
1903
1921
|
startIndex = Math.max(0, startIndex - overscan);
|
|
1904
1922
|
endIndex = Math.min(totalCount, endIndex + overscan);
|
|
1905
|
-
|
|
1906
|
-
"startIndex",
|
|
1907
|
-
startIndex,
|
|
1908
|
-
"endIndex",
|
|
1909
|
-
endIndex,
|
|
1910
|
-
"totalHeight",
|
|
1911
|
-
totalHeight
|
|
1912
|
-
);
|
|
1923
|
+
|
|
1913
1924
|
setRange((prevRange) => {
|
|
1914
1925
|
if (
|
|
1915
1926
|
prevRange.startIndex !== startIndex ||
|
|
1916
1927
|
prevRange.endIndex !== endIndex
|
|
1917
1928
|
) {
|
|
1918
|
-
return { startIndex
|
|
1929
|
+
return { startIndex, endIndex };
|
|
1919
1930
|
}
|
|
1920
1931
|
return prevRange;
|
|
1921
1932
|
});
|
|
@@ -1925,7 +1936,7 @@ function createProxyHandler<T>(
|
|
|
1925
1936
|
passive: true,
|
|
1926
1937
|
});
|
|
1927
1938
|
|
|
1928
|
-
//
|
|
1939
|
+
// This stickToBottom logic is from your original working code.
|
|
1929
1940
|
if (stickToBottom) {
|
|
1930
1941
|
if (isInitialMountRef.current) {
|
|
1931
1942
|
container.scrollTo({
|
|
@@ -1947,7 +1958,6 @@ function createProxyHandler<T>(
|
|
|
1947
1958
|
|
|
1948
1959
|
return () =>
|
|
1949
1960
|
container.removeEventListener("scroll", handleScroll);
|
|
1950
|
-
// --- We swap `itemHeight` for `positions` in the dependency array. ---
|
|
1951
1961
|
}, [totalCount, overscan, stickToBottom, positions]);
|
|
1952
1962
|
|
|
1953
1963
|
const scrollToBottom = useCallback(
|
|
@@ -1962,34 +1972,29 @@ function createProxyHandler<T>(
|
|
|
1962
1972
|
[]
|
|
1963
1973
|
);
|
|
1964
1974
|
|
|
1965
|
-
// --- CHANGE 5: Update scrollToIndex to use the positions array. ---
|
|
1966
1975
|
const scrollToIndex = useCallback(
|
|
1967
1976
|
(index: number, behavior: ScrollBehavior = "smooth") => {
|
|
1968
1977
|
if (containerRef.current) {
|
|
1969
1978
|
containerRef.current.scrollTo({
|
|
1970
|
-
top: positions[index] || 0,
|
|
1979
|
+
top: positions[index] || 0,
|
|
1971
1980
|
behavior,
|
|
1972
1981
|
});
|
|
1973
1982
|
}
|
|
1974
1983
|
},
|
|
1975
|
-
[positions]
|
|
1984
|
+
[positions]
|
|
1976
1985
|
);
|
|
1977
1986
|
|
|
1978
|
-
// --- CHANGE 6: Update virtualizer props to use dynamic values. ---
|
|
1979
1987
|
const virtualizerProps = {
|
|
1980
1988
|
outer: {
|
|
1981
1989
|
ref: containerRef,
|
|
1982
1990
|
style: { overflowY: "auto", height: "100%" },
|
|
1983
1991
|
},
|
|
1984
1992
|
inner: {
|
|
1985
|
-
style: {
|
|
1986
|
-
height: `${totalHeight}px`, // Use calculated dynamic height
|
|
1987
|
-
position: "relative",
|
|
1988
|
-
},
|
|
1993
|
+
style: { height: `${totalHeight}px`, position: "relative" },
|
|
1989
1994
|
},
|
|
1990
1995
|
list: {
|
|
1991
1996
|
style: {
|
|
1992
|
-
transform: `translateY(${positions[range.startIndex] || 0}px)`,
|
|
1997
|
+
transform: `translateY(${positions[range.startIndex] || 0}px)`,
|
|
1993
1998
|
},
|
|
1994
1999
|
},
|
|
1995
2000
|
};
|