cogsbox-state 0.5.319 → 0.5.320
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 +541 -535
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +36 -31
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1809,16 +1809,22 @@ function createProxyHandler<T>(
|
|
|
1809
1809
|
} = options;
|
|
1810
1810
|
|
|
1811
1811
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
1812
|
+
|
|
1813
|
+
const sourceArray = getGlobalStore().getNestedState(
|
|
1814
|
+
stateKey,
|
|
1815
|
+
path
|
|
1816
|
+
) as any[];
|
|
1817
|
+
const totalCount = sourceArray.length;
|
|
1818
|
+
|
|
1819
|
+
// Start at top, will adjust once container is measured
|
|
1812
1820
|
const [range, setRange] = useState({
|
|
1813
1821
|
startIndex: 0,
|
|
1814
1822
|
endIndex: 10,
|
|
1815
1823
|
});
|
|
1816
1824
|
|
|
1817
|
-
// This ref tracks if the user is locked to the bottom.
|
|
1818
1825
|
const isLockedToBottomRef = useRef(stickToBottom);
|
|
1819
|
-
|
|
1820
|
-
// This state triggers a re-render when item heights change.
|
|
1821
1826
|
const [shadowUpdateTrigger, setShadowUpdateTrigger] = useState(0);
|
|
1827
|
+
const hasInitializedRef = useRef(false);
|
|
1822
1828
|
|
|
1823
1829
|
useEffect(() => {
|
|
1824
1830
|
const unsubscribe = getGlobalStore
|
|
@@ -1829,13 +1835,6 @@ function createProxyHandler<T>(
|
|
|
1829
1835
|
return unsubscribe;
|
|
1830
1836
|
}, [stateKey]);
|
|
1831
1837
|
|
|
1832
|
-
const sourceArray = getGlobalStore().getNestedState(
|
|
1833
|
-
stateKey,
|
|
1834
|
-
path
|
|
1835
|
-
) as any[];
|
|
1836
|
-
const totalCount = sourceArray.length;
|
|
1837
|
-
|
|
1838
|
-
// Calculate heights from shadow state. This runs when data or measurements change.
|
|
1839
1838
|
const { totalHeight, positions } = useMemo(() => {
|
|
1840
1839
|
const shadowArray =
|
|
1841
1840
|
getGlobalStore.getState().getShadowMetadata(stateKey, path) ||
|
|
@@ -1857,7 +1856,6 @@ function createProxyHandler<T>(
|
|
|
1857
1856
|
shadowUpdateTrigger,
|
|
1858
1857
|
]);
|
|
1859
1858
|
|
|
1860
|
-
// Memoize the virtualized slice of data.
|
|
1861
1859
|
const virtualState = useMemo(() => {
|
|
1862
1860
|
const start = Math.max(0, range.startIndex);
|
|
1863
1861
|
const end = Math.min(totalCount, range.endIndex);
|
|
@@ -1872,14 +1870,10 @@ function createProxyHandler<T>(
|
|
|
1872
1870
|
});
|
|
1873
1871
|
}, [range.startIndex, range.endIndex, sourceArray, totalCount]);
|
|
1874
1872
|
|
|
1875
|
-
// This is the main effect that handles all scrolling and updates.
|
|
1876
1873
|
useLayoutEffect(() => {
|
|
1877
1874
|
const container = containerRef.current;
|
|
1878
1875
|
if (!container) return;
|
|
1879
1876
|
|
|
1880
|
-
let scrollTimeoutId: NodeJS.Timeout;
|
|
1881
|
-
|
|
1882
|
-
// This function determines what's visible in the viewport.
|
|
1883
1877
|
const updateVirtualRange = () => {
|
|
1884
1878
|
if (!container) return;
|
|
1885
1879
|
const { scrollTop } = container;
|
|
@@ -1903,7 +1897,6 @@ function createProxyHandler<T>(
|
|
|
1903
1897
|
setRange({ startIndex, endIndex });
|
|
1904
1898
|
};
|
|
1905
1899
|
|
|
1906
|
-
// This function handles ONLY user-initiated scrolls.
|
|
1907
1900
|
const handleUserScroll = () => {
|
|
1908
1901
|
isLockedToBottomRef.current =
|
|
1909
1902
|
container.scrollHeight -
|
|
@@ -1917,28 +1910,40 @@ function createProxyHandler<T>(
|
|
|
1917
1910
|
passive: true,
|
|
1918
1911
|
});
|
|
1919
1912
|
|
|
1920
|
-
//
|
|
1921
|
-
if (
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1913
|
+
// Initialize at bottom if needed
|
|
1914
|
+
if (
|
|
1915
|
+
stickToBottom &&
|
|
1916
|
+
!hasInitializedRef.current &&
|
|
1917
|
+
totalCount > 0 &&
|
|
1918
|
+
container.clientHeight > 0
|
|
1919
|
+
) {
|
|
1920
|
+
hasInitializedRef.current = true;
|
|
1921
|
+
|
|
1922
|
+
// Now we have the actual container height, calculate visible items
|
|
1923
|
+
const visibleCount = Math.ceil(
|
|
1924
|
+
container.clientHeight / itemHeight
|
|
1925
|
+
);
|
|
1926
|
+
const startIdx = Math.max(
|
|
1927
|
+
0,
|
|
1928
|
+
totalCount - visibleCount - overscan
|
|
1929
|
+
);
|
|
1930
|
+
|
|
1931
|
+
// Set range to show bottom items
|
|
1932
|
+
setRange({
|
|
1933
|
+
startIndex: startIdx,
|
|
1934
|
+
endIndex: totalCount,
|
|
1935
|
+
});
|
|
1936
|
+
|
|
1937
|
+
// Scroll to bottom
|
|
1938
|
+
container.scrollTop = container.scrollHeight;
|
|
1930
1939
|
}
|
|
1931
1940
|
|
|
1932
|
-
// Update the visible range on initial load.
|
|
1933
1941
|
updateVirtualRange();
|
|
1934
1942
|
|
|
1935
|
-
// Cleanup function is vital to prevent memory leaks.
|
|
1936
1943
|
return () => {
|
|
1937
|
-
clearTimeout(scrollTimeoutId);
|
|
1938
1944
|
container.removeEventListener("scroll", handleUserScroll);
|
|
1939
1945
|
};
|
|
1940
|
-
|
|
1941
|
-
}, [totalCount, positions, stickToBottom]);
|
|
1946
|
+
}, [totalCount, positions, stickToBottom, itemHeight, overscan]);
|
|
1942
1947
|
|
|
1943
1948
|
const scrollToBottom = useCallback(
|
|
1944
1949
|
(behavior: ScrollBehavior = "smooth") => {
|