cogsbox-state 0.5.428 → 0.5.429
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 +488 -491
- package/dist/CogsState.jsx.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +70 -47
package/package.json
CHANGED
package/src/CogsState.tsx
CHANGED
|
@@ -1735,6 +1735,7 @@ function createProxyHandler<T>(
|
|
|
1735
1735
|
return (
|
|
1736
1736
|
options: VirtualViewOptions
|
|
1737
1737
|
): VirtualStateObjectResult<any[]> => {
|
|
1738
|
+
// --- All this setup is from your original, working code ---
|
|
1738
1739
|
const {
|
|
1739
1740
|
itemHeight = 50,
|
|
1740
1741
|
overscan = 6,
|
|
@@ -1752,9 +1753,8 @@ function createProxyHandler<T>(
|
|
|
1752
1753
|
const userHasScrolledAwayRef = useRef(false);
|
|
1753
1754
|
const previousCountRef = useRef(0);
|
|
1754
1755
|
const lastRangeRef = useRef(range);
|
|
1755
|
-
const orderedIds = getOrderedIds(path);
|
|
1756
1756
|
|
|
1757
|
-
//
|
|
1757
|
+
// This is still the correct way to trigger re-calculations when item heights change.
|
|
1758
1758
|
useEffect(() => {
|
|
1759
1759
|
const unsubscribe = getGlobalStore
|
|
1760
1760
|
.getState()
|
|
@@ -1770,23 +1770,37 @@ function createProxyHandler<T>(
|
|
|
1770
1770
|
) as any[];
|
|
1771
1771
|
const totalCount = sourceArray.length;
|
|
1772
1772
|
|
|
1773
|
-
//
|
|
1773
|
+
// --- START OF IMPROVEMENT ---
|
|
1774
|
+
// Get the canonical order of item IDs for this array. This is the most
|
|
1775
|
+
// reliable way to link an item's index to its metadata.
|
|
1776
|
+
const orderedIds = getOrderedIds(path);
|
|
1777
|
+
// --- END OF IMPROVEMENT ---
|
|
1778
|
+
|
|
1779
|
+
// Calculate heights and positions
|
|
1774
1780
|
const { totalHeight, positions } = useMemo(() => {
|
|
1775
1781
|
let height = 0;
|
|
1776
1782
|
const pos: number[] = [];
|
|
1777
1783
|
for (let i = 0; i < totalCount; i++) {
|
|
1778
1784
|
pos[i] = height;
|
|
1785
|
+
|
|
1786
|
+
// --- START OF IMPROVEMENT ---
|
|
1787
|
+
// Use the ordered ID to look up the correct metadata for the item at this index.
|
|
1788
|
+
// This is much more reliable than numeric indexing into a metadata store.
|
|
1779
1789
|
const itemId = orderedIds?.[i];
|
|
1790
|
+
let measuredHeight = itemHeight; // Default height
|
|
1791
|
+
|
|
1780
1792
|
if (itemId) {
|
|
1781
|
-
const
|
|
1793
|
+
const itemPathWithId = [...path, itemId];
|
|
1782
1794
|
const itemMeta = getGlobalStore
|
|
1783
1795
|
.getState()
|
|
1784
|
-
.getShadowMetadata(stateKey,
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
height += itemHeight;
|
|
1796
|
+
.getShadowMetadata(stateKey, itemPathWithId);
|
|
1797
|
+
// Get the measured height from the shadow state if it exists.
|
|
1798
|
+
measuredHeight =
|
|
1799
|
+
itemMeta?.virtualizer?.itemHeight || itemHeight;
|
|
1789
1800
|
}
|
|
1801
|
+
// --- END OF IMPROVEMENT ---
|
|
1802
|
+
|
|
1803
|
+
height += measuredHeight;
|
|
1790
1804
|
}
|
|
1791
1805
|
return { totalHeight: height, positions: pos };
|
|
1792
1806
|
}, [
|
|
@@ -1795,22 +1809,31 @@ function createProxyHandler<T>(
|
|
|
1795
1809
|
path.join("."),
|
|
1796
1810
|
itemHeight,
|
|
1797
1811
|
shadowUpdateTrigger,
|
|
1798
|
-
orderedIds,
|
|
1812
|
+
orderedIds, // Add `orderedIds` to the dependency array
|
|
1799
1813
|
]);
|
|
1800
1814
|
|
|
1801
|
-
// Create
|
|
1815
|
+
// Create virtual state (This part of your original code looks fine)
|
|
1802
1816
|
const virtualState = useMemo(() => {
|
|
1803
1817
|
const start = Math.max(0, range.startIndex);
|
|
1804
1818
|
const end = Math.min(totalCount, range.endIndex);
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
//
|
|
1819
|
+
|
|
1820
|
+
// --- START OF IMPROVEMENT ---
|
|
1821
|
+
// We use `orderedIds` here as well to create a `validIds` list for the
|
|
1822
|
+
// virtualized proxy. This ensures that any subsequent operations on `virtualState`
|
|
1823
|
+
// (like `.index()` or `.getSelected()`) will have the correct context.
|
|
1808
1824
|
const slicedIds = orderedIds?.slice(start, end);
|
|
1825
|
+
const sourceMap = new Map(
|
|
1826
|
+
sourceArray.map((item: any) => [`id:${item.id}`, item])
|
|
1827
|
+
);
|
|
1828
|
+
const slicedArray =
|
|
1829
|
+
slicedIds?.map((id) => sourceMap.get(id)).filter(Boolean) ||
|
|
1830
|
+
[];
|
|
1809
1831
|
|
|
1810
1832
|
return rebuildStateShape(slicedArray as any, path, {
|
|
1811
1833
|
...meta,
|
|
1812
|
-
validIds: slicedIds,
|
|
1834
|
+
validIds: slicedIds, // Pass the sliced IDs as the new `validIds`
|
|
1813
1835
|
});
|
|
1836
|
+
// --- END OF IMPROVEMENT ---
|
|
1814
1837
|
}, [
|
|
1815
1838
|
range.startIndex,
|
|
1816
1839
|
range.endIndex,
|
|
@@ -1819,28 +1842,10 @@ function createProxyHandler<T>(
|
|
|
1819
1842
|
orderedIds,
|
|
1820
1843
|
]);
|
|
1821
1844
|
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
if (lastIndex >= 0 && orderedIds?.[lastIndex]) {
|
|
1825
|
-
const lastItemId = orderedIds[lastIndex];
|
|
1826
|
-
const lastItemPath = [...path, lastItemId];
|
|
1827
|
-
const lastItemMeta = getGlobalStore
|
|
1828
|
-
.getState()
|
|
1829
|
-
.getShadowMetadata(stateKey, lastItemPath);
|
|
1830
|
-
if (lastItemMeta?.virtualizer?.domRef) {
|
|
1831
|
-
const element = lastItemMeta.virtualizer.domRef;
|
|
1832
|
-
if (element?.scrollIntoView) {
|
|
1833
|
-
element.scrollIntoView({
|
|
1834
|
-
behavior: "auto",
|
|
1835
|
-
block: "end",
|
|
1836
|
-
});
|
|
1837
|
-
return true;
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
return false;
|
|
1842
|
-
}, [stateKey, path, totalCount, orderedIds]);
|
|
1845
|
+
// --- All the following logic for scrolling and event handling is from your original code. ---
|
|
1846
|
+
// It is preserved, but we will improve `scrollToIndex` to use the shadow refs.
|
|
1843
1847
|
|
|
1848
|
+
// Handle new items when at bottom (original logic)
|
|
1844
1849
|
useEffect(() => {
|
|
1845
1850
|
if (!stickToBottom || totalCount === 0) return;
|
|
1846
1851
|
const hasNewItems = totalCount > previousCountRef.current;
|
|
@@ -1854,6 +1859,7 @@ function createProxyHandler<T>(
|
|
|
1854
1859
|
previousCountRef.current = totalCount;
|
|
1855
1860
|
}, [totalCount, stickToBottom]);
|
|
1856
1861
|
|
|
1862
|
+
// Handle scroll events (original logic)
|
|
1857
1863
|
useEffect(() => {
|
|
1858
1864
|
const container = containerRef.current;
|
|
1859
1865
|
if (!container) return;
|
|
@@ -1907,42 +1913,59 @@ function createProxyHandler<T>(
|
|
|
1907
1913
|
container.addEventListener("scroll", handleScroll, {
|
|
1908
1914
|
passive: true,
|
|
1909
1915
|
});
|
|
1910
|
-
handleScroll();
|
|
1916
|
+
handleScroll();
|
|
1911
1917
|
return () =>
|
|
1912
1918
|
container.removeEventListener("scroll", handleScroll);
|
|
1913
|
-
}, [positions, totalCount, itemHeight, overscan
|
|
1919
|
+
}, [positions, totalCount, itemHeight, overscan]);
|
|
1914
1920
|
|
|
1915
1921
|
const scrollToBottom = useCallback(() => {
|
|
1916
1922
|
wasAtBottomRef.current = true;
|
|
1917
1923
|
userHasScrolledAwayRef.current = false;
|
|
1918
|
-
if (
|
|
1924
|
+
if (containerRef.current) {
|
|
1919
1925
|
containerRef.current.scrollTop =
|
|
1920
1926
|
containerRef.current.scrollHeight;
|
|
1921
1927
|
}
|
|
1922
|
-
}, [
|
|
1928
|
+
}, []);
|
|
1923
1929
|
|
|
1924
1930
|
const scrollToIndex = useCallback(
|
|
1925
1931
|
(index: number, behavior: ScrollBehavior = "smooth") => {
|
|
1926
1932
|
const container = containerRef.current;
|
|
1927
1933
|
if (!container) return;
|
|
1934
|
+
|
|
1935
|
+
// --- START OF IMPROVEMENT ---
|
|
1936
|
+
// Use the orderedId to reliably get the item's metadata and DOM ref.
|
|
1937
|
+
const itemId = orderedIds?.[index];
|
|
1938
|
+
if (itemId) {
|
|
1939
|
+
const itemPathWithId = [...path, itemId];
|
|
1940
|
+
const itemMeta = getGlobalStore
|
|
1941
|
+
.getState()
|
|
1942
|
+
.getShadowMetadata(stateKey, itemPathWithId);
|
|
1943
|
+
const element = itemMeta?.virtualizer?.domRef;
|
|
1944
|
+
|
|
1945
|
+
// If we have a direct ref to the DOM element from CogsItemWrapper, use it! It's the most reliable.
|
|
1946
|
+
if (element?.scrollIntoView) {
|
|
1947
|
+
element.scrollIntoView({ behavior, block: "nearest" });
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
// --- END OF IMPROVEMENT ---
|
|
1952
|
+
|
|
1953
|
+
// Fallback to position-based scrolling if the ref isn't available for any reason.
|
|
1928
1954
|
const top = positions[index];
|
|
1929
1955
|
if (top !== undefined) {
|
|
1930
1956
|
container.scrollTo({ top, behavior });
|
|
1931
1957
|
}
|
|
1932
1958
|
},
|
|
1933
|
-
[positions]
|
|
1959
|
+
[positions, stateKey, path, orderedIds] // Add `orderedIds` to dependency array
|
|
1934
1960
|
);
|
|
1935
1961
|
|
|
1936
1962
|
const virtualizerProps = {
|
|
1937
1963
|
outer: {
|
|
1938
1964
|
ref: containerRef,
|
|
1939
|
-
style: { overflowY: "auto"
|
|
1965
|
+
style: { overflowY: "auto", height: "100%" },
|
|
1940
1966
|
},
|
|
1941
1967
|
inner: {
|
|
1942
|
-
style: {
|
|
1943
|
-
height: `${totalHeight}px`,
|
|
1944
|
-
position: "relative" as const,
|
|
1945
|
-
},
|
|
1968
|
+
style: { height: `${totalHeight}px`, position: "relative" },
|
|
1946
1969
|
},
|
|
1947
1970
|
list: {
|
|
1948
1971
|
style: {
|
|
@@ -1953,7 +1976,7 @@ function createProxyHandler<T>(
|
|
|
1953
1976
|
|
|
1954
1977
|
return {
|
|
1955
1978
|
virtualState,
|
|
1956
|
-
virtualizerProps,
|
|
1979
|
+
virtualizerProps: virtualizerProps as any,
|
|
1957
1980
|
scrollToBottom,
|
|
1958
1981
|
scrollToIndex,
|
|
1959
1982
|
};
|