cogsbox-state 0.5.296 → 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 +415 -404
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +36 -19
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1814,16 +1814,26 @@ function createProxyHandler<T>(
|
|
|
1814
1814
|
endIndex: 10,
|
|
1815
1815
|
});
|
|
1816
1816
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
[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
|
+
[]
|
|
1825
1824
|
);
|
|
1826
1825
|
|
|
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
|
+
|
|
1827
1837
|
const isAtBottomRef = useRef(stickToBottom);
|
|
1828
1838
|
const previousTotalCountRef = useRef(0);
|
|
1829
1839
|
const isInitialMountRef = useRef(true);
|
|
@@ -1834,18 +1844,27 @@ function createProxyHandler<T>(
|
|
|
1834
1844
|
) as any[];
|
|
1835
1845
|
const totalCount = sourceArray.length;
|
|
1836
1846
|
|
|
1847
|
+
// --- EFFICIENT HEIGHT & POSITION CALCULATION ---
|
|
1837
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
|
+
|
|
1838
1854
|
let height = 0;
|
|
1839
1855
|
const pos: number[] = [];
|
|
1840
1856
|
for (let i = 0; i < totalCount; i++) {
|
|
1841
1857
|
pos[i] = height;
|
|
1842
|
-
height
|
|
1843
|
-
|
|
1858
|
+
// Access the height from the local shadowArray. No repeated deep lookups.
|
|
1859
|
+
const measuredHeight =
|
|
1860
|
+
shadowArray[i]?.virtualizer?.itemHeight;
|
|
1861
|
+
height += measuredHeight || itemHeight;
|
|
1844
1862
|
}
|
|
1845
1863
|
return { totalHeight: height, positions: pos };
|
|
1846
|
-
|
|
1864
|
+
// This now depends on `heightsVersion`, so it re-runs when we force it.
|
|
1865
|
+
}, [totalCount, stateKey, path, itemHeight, heightsVersion]);
|
|
1847
1866
|
|
|
1848
|
-
// This logic is
|
|
1867
|
+
// This logic is from your original working code.
|
|
1849
1868
|
const virtualState = useMemo(() => {
|
|
1850
1869
|
const start = Math.max(0, range.startIndex);
|
|
1851
1870
|
const end = Math.min(totalCount, range.endIndex);
|
|
@@ -1860,7 +1879,7 @@ function createProxyHandler<T>(
|
|
|
1860
1879
|
});
|
|
1861
1880
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1862
1881
|
|
|
1863
|
-
// This
|
|
1882
|
+
// This is your original useLayoutEffect with the robust index calculation.
|
|
1864
1883
|
useLayoutEffect(() => {
|
|
1865
1884
|
const container = containerRef.current;
|
|
1866
1885
|
if (!container) return;
|
|
@@ -1874,15 +1893,13 @@ function createProxyHandler<T>(
|
|
|
1874
1893
|
isAtBottomRef.current =
|
|
1875
1894
|
scrollHeight - scrollTop - clientHeight < 10;
|
|
1876
1895
|
|
|
1877
|
-
//
|
|
1878
|
-
// This is extremely fast and correctly handles all scroll positions.
|
|
1896
|
+
// ROBUST: Binary search to find the start index. Prevents errors.
|
|
1879
1897
|
let search = (list: number[], value: number) => {
|
|
1880
1898
|
let low = 0;
|
|
1881
1899
|
let high = list.length - 1;
|
|
1882
1900
|
while (low <= high) {
|
|
1883
1901
|
const mid = Math.floor((low + high) / 2);
|
|
1884
|
-
|
|
1885
|
-
if (midValue < value) {
|
|
1902
|
+
if (list[mid]! < value) {
|
|
1886
1903
|
low = mid + 1;
|
|
1887
1904
|
} else {
|
|
1888
1905
|
high = mid - 1;
|
|
@@ -1903,7 +1920,7 @@ function createProxyHandler<T>(
|
|
|
1903
1920
|
|
|
1904
1921
|
startIndex = Math.max(0, startIndex - overscan);
|
|
1905
1922
|
endIndex = Math.min(totalCount, endIndex + overscan);
|
|
1906
|
-
|
|
1923
|
+
|
|
1907
1924
|
setRange((prevRange) => {
|
|
1908
1925
|
if (
|
|
1909
1926
|
prevRange.startIndex !== startIndex ||
|
|
@@ -1919,7 +1936,7 @@ function createProxyHandler<T>(
|
|
|
1919
1936
|
passive: true,
|
|
1920
1937
|
});
|
|
1921
1938
|
|
|
1922
|
-
// This stickToBottom logic is
|
|
1939
|
+
// This stickToBottom logic is from your original working code.
|
|
1923
1940
|
if (stickToBottom) {
|
|
1924
1941
|
if (isInitialMountRef.current) {
|
|
1925
1942
|
container.scrollTo({
|