cogsbox-state 0.5.283 → 0.5.285
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 +470 -452
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +75 -38
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1802,7 +1802,7 @@ function createProxyHandler<T>(
|
|
|
1802
1802
|
options: VirtualViewOptions
|
|
1803
1803
|
): VirtualStateObjectResult<any[]> => {
|
|
1804
1804
|
const {
|
|
1805
|
-
itemHeight,
|
|
1805
|
+
itemHeight = 50, // Now optional with default
|
|
1806
1806
|
overscan = 5,
|
|
1807
1807
|
stickToBottom = false,
|
|
1808
1808
|
} = options;
|
|
@@ -1812,16 +1812,37 @@ function createProxyHandler<T>(
|
|
|
1812
1812
|
startIndex: 0,
|
|
1813
1813
|
endIndex: 10,
|
|
1814
1814
|
});
|
|
1815
|
-
|
|
1816
|
-
|
|
1815
|
+
|
|
1816
|
+
// Get item height from shadow state or fall back to default
|
|
1817
|
+
const getItemHeight = useCallback(
|
|
1818
|
+
(index: number) => {
|
|
1819
|
+
const metadata = getGlobalStore
|
|
1820
|
+
.getState()
|
|
1821
|
+
.getShadowMetadata(stateKey, [...path, index.toString()]);
|
|
1822
|
+
return metadata?.virtualizer?.itemHeight || itemHeight;
|
|
1823
|
+
},
|
|
1824
|
+
[itemHeight]
|
|
1825
|
+
);
|
|
1826
|
+
|
|
1827
|
+
// Calculate total height and item positions
|
|
1828
|
+
const calculateHeights = useCallback(() => {
|
|
1829
|
+
const sourceArray = getGlobalStore
|
|
1817
1830
|
.getState()
|
|
1818
|
-
.
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1831
|
+
.getNestedState(stateKey, path) as any[];
|
|
1832
|
+
|
|
1833
|
+
let totalHeight = 0;
|
|
1834
|
+
const positions: number[] = [];
|
|
1835
|
+
|
|
1836
|
+
for (let i = 0; i < sourceArray.length; i++) {
|
|
1837
|
+
positions[i] = totalHeight;
|
|
1838
|
+
totalHeight += getItemHeight(i);
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
return { totalHeight, positions };
|
|
1842
|
+
}, [getItemHeight]);
|
|
1843
|
+
|
|
1822
1844
|
const isAtBottomRef = useRef(stickToBottom);
|
|
1823
1845
|
const previousTotalCountRef = useRef(0);
|
|
1824
|
-
// NEW: Ref to explicitly track if this is the component's first render cycle.
|
|
1825
1846
|
const isInitialMountRef = useRef(true);
|
|
1826
1847
|
|
|
1827
1848
|
const sourceArray = getGlobalStore().getNestedState(
|
|
@@ -1852,25 +1873,43 @@ function createProxyHandler<T>(
|
|
|
1852
1873
|
const listGrew = totalCount > previousTotalCountRef.current;
|
|
1853
1874
|
previousTotalCountRef.current = totalCount;
|
|
1854
1875
|
|
|
1876
|
+
const { totalHeight, positions } = calculateHeights();
|
|
1877
|
+
|
|
1855
1878
|
const handleScroll = () => {
|
|
1856
1879
|
const { scrollTop, clientHeight, scrollHeight } = container;
|
|
1857
1880
|
isAtBottomRef.current =
|
|
1858
1881
|
scrollHeight - scrollTop - clientHeight < 10;
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1882
|
+
|
|
1883
|
+
// Find start index using binary search
|
|
1884
|
+
let start = 0;
|
|
1885
|
+
let end = positions.length - 1;
|
|
1886
|
+
while (start < end) {
|
|
1887
|
+
const mid = Math.floor((start + end) / 2);
|
|
1888
|
+
if (positions[mid]! < scrollTop) {
|
|
1889
|
+
start = mid + 1;
|
|
1890
|
+
} else {
|
|
1891
|
+
end = mid;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
start = Math.max(0, start - overscan);
|
|
1895
|
+
|
|
1896
|
+
// Find end index
|
|
1897
|
+
const visibleEnd = scrollTop + clientHeight;
|
|
1898
|
+
let endIndex = start;
|
|
1899
|
+
while (
|
|
1900
|
+
endIndex < positions.length &&
|
|
1901
|
+
positions[endIndex]! < visibleEnd
|
|
1902
|
+
) {
|
|
1903
|
+
endIndex++;
|
|
1904
|
+
}
|
|
1905
|
+
endIndex = Math.min(totalCount, endIndex + overscan);
|
|
1906
|
+
|
|
1868
1907
|
setRange((prevRange) => {
|
|
1869
1908
|
if (
|
|
1870
1909
|
prevRange.startIndex !== start ||
|
|
1871
|
-
prevRange.endIndex !==
|
|
1910
|
+
prevRange.endIndex !== endIndex
|
|
1872
1911
|
) {
|
|
1873
|
-
return { startIndex: start, endIndex:
|
|
1912
|
+
return { startIndex: start, endIndex: endIndex };
|
|
1874
1913
|
}
|
|
1875
1914
|
return prevRange;
|
|
1876
1915
|
});
|
|
@@ -1880,19 +1919,13 @@ function createProxyHandler<T>(
|
|
|
1880
1919
|
passive: true,
|
|
1881
1920
|
});
|
|
1882
1921
|
|
|
1883
|
-
// --- THE CORRECTED DECISION LOGIC ---
|
|
1884
1922
|
if (stickToBottom) {
|
|
1885
1923
|
if (isInitialMountRef.current) {
|
|
1886
|
-
// SCENARIO 1: First render of the component.
|
|
1887
|
-
// Go to the bottom unconditionally. Use `auto` scroll for an instant jump.
|
|
1888
1924
|
container.scrollTo({
|
|
1889
1925
|
top: container.scrollHeight,
|
|
1890
1926
|
behavior: "auto",
|
|
1891
1927
|
});
|
|
1892
1928
|
} else if (wasAtBottom && listGrew) {
|
|
1893
|
-
// SCENARIO 2: Subsequent renders (new messages arrive).
|
|
1894
|
-
// Only scroll if the user was already at the bottom.
|
|
1895
|
-
// Use `smooth` for a nice animated scroll for new messages.
|
|
1896
1929
|
requestAnimationFrame(() => {
|
|
1897
1930
|
container.scrollTo({
|
|
1898
1931
|
top: container.scrollHeight,
|
|
@@ -1902,15 +1935,12 @@ function createProxyHandler<T>(
|
|
|
1902
1935
|
}
|
|
1903
1936
|
}
|
|
1904
1937
|
|
|
1905
|
-
// After the logic runs, it's no longer the initial mount.
|
|
1906
1938
|
isInitialMountRef.current = false;
|
|
1907
|
-
|
|
1908
|
-
// Always run handleScroll once to set the initial visible window.
|
|
1909
1939
|
handleScroll();
|
|
1910
1940
|
|
|
1911
1941
|
return () =>
|
|
1912
1942
|
container.removeEventListener("scroll", handleScroll);
|
|
1913
|
-
}, [totalCount,
|
|
1943
|
+
}, [totalCount, calculateHeights, overscan, stickToBottom]);
|
|
1914
1944
|
|
|
1915
1945
|
const scrollToBottom = useCallback(
|
|
1916
1946
|
(behavior: ScrollBehavior = "smooth") => {
|
|
@@ -1927,37 +1957,44 @@ function createProxyHandler<T>(
|
|
|
1927
1957
|
const scrollToIndex = useCallback(
|
|
1928
1958
|
(index: number, behavior: ScrollBehavior = "smooth") => {
|
|
1929
1959
|
if (containerRef.current) {
|
|
1960
|
+
const { positions } = calculateHeights();
|
|
1930
1961
|
containerRef.current.scrollTo({
|
|
1931
|
-
top: index
|
|
1962
|
+
top: positions[index] || 0,
|
|
1932
1963
|
behavior,
|
|
1933
1964
|
});
|
|
1934
1965
|
}
|
|
1935
1966
|
},
|
|
1936
|
-
[
|
|
1967
|
+
[calculateHeights]
|
|
1937
1968
|
);
|
|
1938
1969
|
|
|
1939
|
-
//
|
|
1970
|
+
// Calculate actual heights for rendering
|
|
1971
|
+
const {
|
|
1972
|
+
totalHeight: totalHeightForRender,
|
|
1973
|
+
positions: positionsForRender,
|
|
1974
|
+
} = calculateHeights();
|
|
1975
|
+
const offsetY = positionsForRender[range.startIndex] || 0;
|
|
1976
|
+
|
|
1940
1977
|
const virtualizerProps = {
|
|
1941
1978
|
outer: {
|
|
1942
1979
|
ref: containerRef,
|
|
1943
|
-
style: { overflowY: "auto", height: "100%" },
|
|
1980
|
+
style: { overflowY: "auto", height: "100%" } as CSSProperties,
|
|
1944
1981
|
},
|
|
1945
1982
|
inner: {
|
|
1946
1983
|
style: {
|
|
1947
|
-
height: `${
|
|
1984
|
+
height: `${totalHeightForRender}px`,
|
|
1948
1985
|
position: "relative",
|
|
1949
|
-
},
|
|
1986
|
+
} as CSSProperties,
|
|
1950
1987
|
},
|
|
1951
1988
|
list: {
|
|
1952
1989
|
style: {
|
|
1953
|
-
transform: `translateY(${
|
|
1954
|
-
},
|
|
1990
|
+
transform: `translateY(${offsetY}px)`,
|
|
1991
|
+
} as CSSProperties,
|
|
1955
1992
|
},
|
|
1956
1993
|
};
|
|
1957
1994
|
|
|
1958
1995
|
return {
|
|
1959
1996
|
virtualState,
|
|
1960
|
-
virtualizerProps
|
|
1997
|
+
virtualizerProps,
|
|
1961
1998
|
scrollToBottom,
|
|
1962
1999
|
scrollToIndex,
|
|
1963
2000
|
};
|