cogsbox-state 0.5.311 → 0.5.313
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 +204 -206
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +18 -33
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1816,20 +1816,18 @@ function createProxyHandler<T>(
|
|
|
1816
1816
|
|
|
1817
1817
|
// --- State and Lock Management Refs ---
|
|
1818
1818
|
const isLockedToBottomRef = useRef(stickToBottom);
|
|
1819
|
-
|
|
1819
|
+
// This ref tracks the item count to determine when to scroll smoothly vs instantly.
|
|
1820
|
+
const previousTotalCountRef = useRef(0);
|
|
1820
1821
|
|
|
1821
1822
|
// Subscribe to shadow state changes for height updates
|
|
1822
1823
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1823
1824
|
|
|
1824
1825
|
useEffect(() => {
|
|
1825
|
-
// Subscribe to shadow state updates for this stateKey
|
|
1826
1826
|
const unsubscribe = getGlobalStore
|
|
1827
1827
|
.getState()
|
|
1828
1828
|
.subscribeToShadowState(stateKey, () => {
|
|
1829
|
-
// Force recalculation when shadow state updates
|
|
1830
1829
|
setShadowUpdateTrigger((prev) => prev + 1);
|
|
1831
1830
|
});
|
|
1832
|
-
|
|
1833
1831
|
return unsubscribe;
|
|
1834
1832
|
}, [stateKey]);
|
|
1835
1833
|
|
|
@@ -1839,21 +1837,19 @@ function createProxyHandler<T>(
|
|
|
1839
1837
|
) as any[];
|
|
1840
1838
|
const totalCount = sourceArray.length;
|
|
1841
1839
|
|
|
1842
|
-
// Calculate heights from shadow state
|
|
1840
|
+
// Calculate heights and positions from shadow state
|
|
1843
1841
|
const { totalHeight, positions } = useMemo(() => {
|
|
1844
1842
|
const shadowArray =
|
|
1845
1843
|
getGlobalStore.getState().getShadowMetadata(stateKey, path) ||
|
|
1846
1844
|
[];
|
|
1847
1845
|
let height = 0;
|
|
1848
1846
|
const pos: number[] = [];
|
|
1849
|
-
|
|
1850
1847
|
for (let i = 0; i < totalCount; i++) {
|
|
1851
1848
|
pos[i] = height;
|
|
1852
1849
|
const measuredHeight =
|
|
1853
1850
|
shadowArray[i]?.virtualizer?.itemHeight;
|
|
1854
1851
|
height += measuredHeight || itemHeight;
|
|
1855
1852
|
}
|
|
1856
|
-
|
|
1857
1853
|
return { totalHeight: height, positions: pos };
|
|
1858
1854
|
}, [
|
|
1859
1855
|
totalCount,
|
|
@@ -1881,30 +1877,23 @@ function createProxyHandler<T>(
|
|
|
1881
1877
|
const container = containerRef.current;
|
|
1882
1878
|
if (!container) return;
|
|
1883
1879
|
|
|
1880
|
+
const listGrew = totalCount > previousTotalCountRef.current;
|
|
1881
|
+
|
|
1884
1882
|
const handleScroll = () => {
|
|
1885
1883
|
const { scrollTop, clientHeight, scrollHeight } = container;
|
|
1886
|
-
|
|
1887
|
-
// Determine if the user is at the bottom
|
|
1888
1884
|
const isNowAtBottom =
|
|
1889
1885
|
scrollHeight - scrollTop - clientHeight < 1;
|
|
1890
|
-
|
|
1891
|
-
// If the user scrolls up, unlock. If they scroll back down, re-lock.
|
|
1892
1886
|
isLockedToBottomRef.current = isNowAtBottom;
|
|
1893
1887
|
|
|
1894
|
-
//
|
|
1888
|
+
// ... (virtualization range calculation logic is unchanged)
|
|
1895
1889
|
let low = 0,
|
|
1896
1890
|
high = totalCount - 1;
|
|
1897
1891
|
while (low <= high) {
|
|
1898
1892
|
const mid = Math.floor((low + high) / 2);
|
|
1899
|
-
if (positions[mid]! < scrollTop)
|
|
1900
|
-
|
|
1901
|
-
} else {
|
|
1902
|
-
high = mid - 1;
|
|
1903
|
-
}
|
|
1893
|
+
if (positions[mid]! < scrollTop) low = mid + 1;
|
|
1894
|
+
else high = mid - 1;
|
|
1904
1895
|
}
|
|
1905
1896
|
const startIndex = Math.max(0, high - overscan);
|
|
1906
|
-
|
|
1907
|
-
// Find end index
|
|
1908
1897
|
let endIndex = startIndex;
|
|
1909
1898
|
const visibleEnd = scrollTop + clientHeight;
|
|
1910
1899
|
while (
|
|
@@ -1914,7 +1903,6 @@ function createProxyHandler<T>(
|
|
|
1914
1903
|
endIndex++;
|
|
1915
1904
|
}
|
|
1916
1905
|
endIndex = Math.min(totalCount, endIndex + overscan);
|
|
1917
|
-
|
|
1918
1906
|
setRange((prevRange) => {
|
|
1919
1907
|
if (
|
|
1920
1908
|
prevRange.startIndex !== startIndex ||
|
|
@@ -1930,12 +1918,15 @@ function createProxyHandler<T>(
|
|
|
1930
1918
|
passive: true,
|
|
1931
1919
|
});
|
|
1932
1920
|
|
|
1933
|
-
// ---
|
|
1921
|
+
// --- ROBUST STICK-TO-BOTTOM LOGIC ---
|
|
1934
1922
|
if (stickToBottom && isLockedToBottomRef.current) {
|
|
1935
|
-
//
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1923
|
+
// If the list grew (a new message was added), we want a smooth scroll.
|
|
1924
|
+
// For all other cases (initial load, height recalculation), we MUST
|
|
1925
|
+
// use 'auto' to instantly snap to the bottom and prevent the "jump up".
|
|
1926
|
+
const behavior =
|
|
1927
|
+
listGrew && previousTotalCountRef.current > 0
|
|
1928
|
+
? "smooth"
|
|
1929
|
+
: "auto";
|
|
1939
1930
|
|
|
1940
1931
|
container.scrollTo({
|
|
1941
1932
|
top: container.scrollHeight,
|
|
@@ -1943,15 +1934,9 @@ function createProxyHandler<T>(
|
|
|
1943
1934
|
});
|
|
1944
1935
|
}
|
|
1945
1936
|
|
|
1946
|
-
//
|
|
1947
|
-
|
|
1948
|
-
queueMicrotask(() => {
|
|
1949
|
-
if (isInitialMountRef.current) {
|
|
1950
|
-
isInitialMountRef.current = false;
|
|
1951
|
-
}
|
|
1952
|
-
});
|
|
1937
|
+
// Update the count for the next run AFTER the scroll logic.
|
|
1938
|
+
previousTotalCountRef.current = totalCount;
|
|
1953
1939
|
|
|
1954
|
-
// Run handleScroll once on setup to set initial range and lock status
|
|
1955
1940
|
handleScroll();
|
|
1956
1941
|
|
|
1957
1942
|
return () =>
|