cogsbox-state 0.5.297 → 0.5.299
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 +307 -309
- package/dist/CogsState.jsx.map +1 -1
- package/dist/store.d.ts +26 -24
- package/dist/store.js +109 -95
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
- package/src/CogsState.tsx +45 -40
- package/src/store.ts +96 -57
package/src/CogsState.tsx
CHANGED
|
@@ -1814,25 +1814,29 @@ function createProxyHandler<T>(
|
|
|
1814
1814
|
endIndex: 10,
|
|
1815
1815
|
});
|
|
1816
1816
|
|
|
1817
|
-
// --- STATE AND CALLBACKS FOR HEIGHTS ---
|
|
1818
|
-
// This state value is the key. We increment it to force a re-calculation.
|
|
1819
1817
|
const [heightsVersion, setHeightsVersion] = useState(0);
|
|
1820
|
-
// This callback is stable and won't cause re-renders itself.
|
|
1821
1818
|
const forceRecalculate = useCallback(
|
|
1822
1819
|
() => setHeightsVersion((v) => v + 1),
|
|
1823
1820
|
[]
|
|
1824
1821
|
);
|
|
1825
1822
|
|
|
1826
|
-
// ---
|
|
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.
|
|
1823
|
+
// --- This useEffect now cleanly subscribes to height changes ---
|
|
1830
1824
|
useEffect(() => {
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1825
|
+
// Subscribe to shadow state changes for this specific key.
|
|
1826
|
+
const unsubscribe = getGlobalStore
|
|
1827
|
+
.getState()
|
|
1828
|
+
.subscribeToShadowState(stateKey, forceRecalculate);
|
|
1829
|
+
|
|
1830
|
+
// On initial mount, we still need to trigger one recalculation
|
|
1831
|
+
// to capture heights from the very first render.
|
|
1832
|
+
const timer = setTimeout(forceRecalculate, 50);
|
|
1833
|
+
|
|
1834
|
+
// Cleanup function to unsubscribe when the component unmounts.
|
|
1835
|
+
return () => {
|
|
1836
|
+
unsubscribe();
|
|
1837
|
+
clearTimeout(timer);
|
|
1838
|
+
};
|
|
1839
|
+
}, [stateKey, forceRecalculate]); // Runs only once on mount.
|
|
1836
1840
|
|
|
1837
1841
|
const isAtBottomRef = useRef(stickToBottom);
|
|
1838
1842
|
const previousTotalCountRef = useRef(0);
|
|
@@ -1844,27 +1848,21 @@ function createProxyHandler<T>(
|
|
|
1844
1848
|
) as any[];
|
|
1845
1849
|
const totalCount = sourceArray.length;
|
|
1846
1850
|
|
|
1847
|
-
// --- EFFICIENT HEIGHT & POSITION CALCULATION ---
|
|
1848
1851
|
const { totalHeight, positions } = useMemo(() => {
|
|
1849
|
-
// Get the shadow object for the whole array ONCE. This is fast.
|
|
1850
1852
|
const shadowArray =
|
|
1851
1853
|
getGlobalStore.getState().getShadowMetadata(stateKey, path) ||
|
|
1852
1854
|
[];
|
|
1853
|
-
|
|
1854
1855
|
let height = 0;
|
|
1855
1856
|
const pos: number[] = [];
|
|
1856
1857
|
for (let i = 0; i < totalCount; i++) {
|
|
1857
1858
|
pos[i] = height;
|
|
1858
|
-
// Access the height from the local shadowArray. No repeated deep lookups.
|
|
1859
1859
|
const measuredHeight =
|
|
1860
1860
|
shadowArray[i]?.virtualizer?.itemHeight;
|
|
1861
1861
|
height += measuredHeight || itemHeight;
|
|
1862
1862
|
}
|
|
1863
1863
|
return { totalHeight: height, positions: pos };
|
|
1864
|
-
// This now depends on `heightsVersion`, so it re-runs when we force it.
|
|
1865
1864
|
}, [totalCount, stateKey, path, itemHeight, heightsVersion]);
|
|
1866
1865
|
|
|
1867
|
-
// This logic is from your original working code.
|
|
1868
1866
|
const virtualState = useMemo(() => {
|
|
1869
1867
|
const start = Math.max(0, range.startIndex);
|
|
1870
1868
|
const end = Math.min(totalCount, range.endIndex);
|
|
@@ -1877,9 +1875,7 @@ function createProxyHandler<T>(
|
|
|
1877
1875
|
...meta,
|
|
1878
1876
|
validIndices,
|
|
1879
1877
|
});
|
|
1880
|
-
}, [range.startIndex, range.endIndex, sourceArray
|
|
1881
|
-
|
|
1882
|
-
// This is your original useLayoutEffect with the robust index calculation.
|
|
1878
|
+
}, [range.startIndex, range.endIndex, sourceArray]);
|
|
1883
1879
|
useLayoutEffect(() => {
|
|
1884
1880
|
const container = containerRef.current;
|
|
1885
1881
|
if (!container) return;
|
|
@@ -1891,9 +1887,9 @@ function createProxyHandler<T>(
|
|
|
1891
1887
|
const handleScroll = () => {
|
|
1892
1888
|
const { scrollTop, clientHeight, scrollHeight } = container;
|
|
1893
1889
|
isAtBottomRef.current =
|
|
1894
|
-
scrollHeight - scrollTop - clientHeight <
|
|
1890
|
+
scrollHeight - scrollTop - clientHeight < 5; // Use a small tolerance
|
|
1895
1891
|
|
|
1896
|
-
//
|
|
1892
|
+
// ... (binary search logic to setRange) ...
|
|
1897
1893
|
let search = (list: number[], value: number) => {
|
|
1898
1894
|
let low = 0;
|
|
1899
1895
|
let high = list.length - 1;
|
|
@@ -1907,9 +1903,7 @@ function createProxyHandler<T>(
|
|
|
1907
1903
|
}
|
|
1908
1904
|
return low;
|
|
1909
1905
|
};
|
|
1910
|
-
|
|
1911
1906
|
let startIndex = search(positions, scrollTop);
|
|
1912
|
-
|
|
1913
1907
|
let endIndex = startIndex;
|
|
1914
1908
|
while (
|
|
1915
1909
|
endIndex < totalCount &&
|
|
@@ -1917,10 +1911,8 @@ function createProxyHandler<T>(
|
|
|
1917
1911
|
) {
|
|
1918
1912
|
endIndex++;
|
|
1919
1913
|
}
|
|
1920
|
-
|
|
1921
1914
|
startIndex = Math.max(0, startIndex - overscan);
|
|
1922
1915
|
endIndex = Math.min(totalCount, endIndex + overscan);
|
|
1923
|
-
|
|
1924
1916
|
setRange((prevRange) => {
|
|
1925
1917
|
if (
|
|
1926
1918
|
prevRange.startIndex !== startIndex ||
|
|
@@ -1935,27 +1927,28 @@ function createProxyHandler<T>(
|
|
|
1935
1927
|
container.addEventListener("scroll", handleScroll, {
|
|
1936
1928
|
passive: true,
|
|
1937
1929
|
});
|
|
1930
|
+
handleScroll(); // Run once to set initial view
|
|
1938
1931
|
|
|
1939
|
-
//
|
|
1932
|
+
// --- THE SIMPLE FIX ---
|
|
1933
|
+
// We check the flags *after* handleScroll has updated them.
|
|
1940
1934
|
if (stickToBottom) {
|
|
1941
1935
|
if (isInitialMountRef.current) {
|
|
1936
|
+
// On first load, always go to the bottom.
|
|
1942
1937
|
container.scrollTo({
|
|
1943
1938
|
top: container.scrollHeight,
|
|
1944
1939
|
behavior: "auto",
|
|
1945
1940
|
});
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1941
|
+
isInitialMountRef.current = false;
|
|
1942
|
+
} else if (listGrew && wasAtBottom) {
|
|
1943
|
+
// If a new item was added AND we were already at the bottom,
|
|
1944
|
+
// scroll to the new bottom.
|
|
1945
|
+
container.scrollTo({
|
|
1946
|
+
top: container.scrollHeight,
|
|
1947
|
+
behavior: "auto",
|
|
1952
1948
|
});
|
|
1953
1949
|
}
|
|
1954
1950
|
}
|
|
1955
1951
|
|
|
1956
|
-
isInitialMountRef.current = false;
|
|
1957
|
-
handleScroll();
|
|
1958
|
-
|
|
1959
1952
|
return () =>
|
|
1960
1953
|
container.removeEventListener("scroll", handleScroll);
|
|
1961
1954
|
}, [totalCount, overscan, stickToBottom, positions]);
|
|
@@ -2950,7 +2943,6 @@ export function $cogsSignalStore(proxy: {
|
|
|
2950
2943
|
);
|
|
2951
2944
|
return createElement("text", {}, String(value));
|
|
2952
2945
|
}
|
|
2953
|
-
|
|
2954
2946
|
function CogsItemWrapper({
|
|
2955
2947
|
stateKey,
|
|
2956
2948
|
itemComponentId,
|
|
@@ -2962,19 +2954,31 @@ function CogsItemWrapper({
|
|
|
2962
2954
|
itemPath: string[];
|
|
2963
2955
|
children: React.ReactNode;
|
|
2964
2956
|
}) {
|
|
2957
|
+
// This hook handles the re-rendering when the item's own data changes.
|
|
2965
2958
|
const [, forceUpdate] = useState({});
|
|
2959
|
+
// This hook measures the element.
|
|
2966
2960
|
const [ref, bounds] = useMeasure();
|
|
2961
|
+
// This ref prevents sending the same height update repeatedly.
|
|
2962
|
+
const lastReportedHeight = useRef<number | null>(null);
|
|
2967
2963
|
|
|
2964
|
+
// This is the primary effect for this component.
|
|
2968
2965
|
useEffect(() => {
|
|
2969
|
-
|
|
2966
|
+
// We only report a height if it's a valid number AND it's different
|
|
2967
|
+
// from the last height we reported. This prevents infinite loops.
|
|
2968
|
+
if (bounds.height > 0 && bounds.height !== lastReportedHeight.current) {
|
|
2969
|
+
// Store the new height so we don't report it again.
|
|
2970
|
+
lastReportedHeight.current = bounds.height;
|
|
2971
|
+
|
|
2972
|
+
// Call the store function to save the height and notify listeners.
|
|
2970
2973
|
getGlobalStore.getState().setShadowMetadata(stateKey, itemPath, {
|
|
2971
2974
|
virtualizer: {
|
|
2972
2975
|
itemHeight: bounds.height,
|
|
2973
2976
|
},
|
|
2974
2977
|
});
|
|
2975
2978
|
}
|
|
2976
|
-
}, [bounds.height]);
|
|
2979
|
+
}, [bounds.height, stateKey, itemPath]); // Reruns whenever the measured height changes.
|
|
2977
2980
|
|
|
2981
|
+
// This effect handles subscribing the item to its own data path for updates.
|
|
2978
2982
|
useLayoutEffect(() => {
|
|
2979
2983
|
const fullComponentId = `${stateKey}////${itemComponentId}`;
|
|
2980
2984
|
const stateEntry = getGlobalStore
|
|
@@ -3000,5 +3004,6 @@ function CogsItemWrapper({
|
|
|
3000
3004
|
};
|
|
3001
3005
|
}, [stateKey, itemComponentId, itemPath.join(".")]);
|
|
3002
3006
|
|
|
3007
|
+
// The rendered output is a simple div that gets measured.
|
|
3003
3008
|
return <div ref={ref}>{children}</div>;
|
|
3004
3009
|
}
|
package/src/store.ts
CHANGED
|
@@ -98,8 +98,12 @@ type ShadowState<T> =
|
|
|
98
98
|
: T extends object
|
|
99
99
|
? { [K in keyof T]: ShadowState<T[K]> } & ShadowMetadata
|
|
100
100
|
: ShadowMetadata;
|
|
101
|
+
|
|
101
102
|
export type CogsGlobalState = {
|
|
103
|
+
// --- Shadow State and Subscription System ---
|
|
102
104
|
shadowStateStore: { [key: string]: any };
|
|
105
|
+
shadowStateSubscribers: Map<string, Set<() => void>>; // Stores subscribers for shadow state updates
|
|
106
|
+
subscribeToShadowState: (key: string, callback: () => void) => () => void; // Subscribes a listener, returns an unsubscribe function
|
|
103
107
|
initializeShadowState: (key: string, initialState: any) => void;
|
|
104
108
|
updateShadowAtPath: (key: string, path: string[], newValue: any) => void;
|
|
105
109
|
insertShadowArrayElement: (
|
|
@@ -115,9 +119,8 @@ export type CogsGlobalState = {
|
|
|
115
119
|
getShadowMetadata: (key: string, path: string[]) => any;
|
|
116
120
|
setShadowMetadata: (key: string, path: string[], metadata: any) => void;
|
|
117
121
|
|
|
122
|
+
// --- Selected Item State ---
|
|
118
123
|
selectedIndicesMap: Map<string, Map<string, number>>; // stateKey -> (parentPath -> selectedIndex)
|
|
119
|
-
|
|
120
|
-
// Add these new methods
|
|
121
124
|
getSelectedIndex: (
|
|
122
125
|
stateKey: string,
|
|
123
126
|
parentPath: string
|
|
@@ -135,36 +138,16 @@ export type CogsGlobalState = {
|
|
|
135
138
|
path: string[];
|
|
136
139
|
}) => void;
|
|
137
140
|
clearSelectedIndexesForState: (stateKey: string) => void;
|
|
141
|
+
|
|
142
|
+
// --- Core State and Updaters ---
|
|
138
143
|
updaterState: { [key: string]: any };
|
|
139
144
|
initialStateOptions: { [key: string]: OptionsType };
|
|
140
145
|
cogsStateStore: { [key: string]: StateValue };
|
|
141
146
|
isLoadingGlobal: { [key: string]: boolean };
|
|
142
|
-
|
|
143
147
|
initialStateGlobal: { [key: string]: StateValue };
|
|
144
148
|
iniitialCreatedState: { [key: string]: StateValue };
|
|
145
|
-
validationErrors: Map<string, string[]>;
|
|
146
|
-
|
|
147
149
|
serverState: { [key: string]: StateValue };
|
|
148
|
-
serverSyncActions: { [key: string]: SyncActionsType<any> };
|
|
149
|
-
|
|
150
|
-
serverSyncLog: { [key: string]: SyncLogType[] };
|
|
151
|
-
serverSideOrNot: { [key: string]: boolean };
|
|
152
|
-
setServerSyncLog: (key: string, newValue: SyncLogType) => void;
|
|
153
|
-
|
|
154
|
-
setServerSideOrNot: (key: string, value: boolean) => void;
|
|
155
|
-
getServerSideOrNot: (key: string) => boolean | undefined;
|
|
156
|
-
setServerState: <StateKey extends StateKeys>(
|
|
157
|
-
key: StateKey,
|
|
158
|
-
value: StateValue
|
|
159
|
-
) => void;
|
|
160
150
|
|
|
161
|
-
getThisLocalUpdate: (key: string) => UpdateTypeDetail[] | undefined;
|
|
162
|
-
setServerSyncActions: (key: string, value: SyncActionsType<any>) => void;
|
|
163
|
-
addValidationError: (path: string, message: string) => void;
|
|
164
|
-
getValidationErrors: (path: string) => string[];
|
|
165
|
-
updateInitialStateGlobal: (key: string, newState: StateValue) => void;
|
|
166
|
-
updateInitialCreatedState: (key: string, newState: StateValue) => void;
|
|
167
|
-
getInitialOptions: (key: string) => OptionsType | undefined;
|
|
168
151
|
getUpdaterState: (key: string) => StateUpdater<StateValue>;
|
|
169
152
|
setUpdaterState: (key: string, newUpdater: any) => void;
|
|
170
153
|
getKeyState: <StateKey extends StateKeys>(key: StateKey) => StateValue;
|
|
@@ -178,15 +161,41 @@ export type CogsGlobalState = {
|
|
|
178
161
|
) => void;
|
|
179
162
|
setInitialStates: (initialState: StateValue) => void;
|
|
180
163
|
setCreatedState: (initialState: StateValue) => void;
|
|
164
|
+
updateInitialStateGlobal: (key: string, newState: StateValue) => void;
|
|
165
|
+
updateInitialCreatedState: (key: string, newState: StateValue) => void;
|
|
166
|
+
setIsLoadingGlobal: (key: string, value: boolean) => void;
|
|
167
|
+
setServerState: <StateKey extends StateKeys>(
|
|
168
|
+
key: StateKey,
|
|
169
|
+
value: StateValue
|
|
170
|
+
) => void;
|
|
171
|
+
getInitialOptions: (key: string) => OptionsType | undefined;
|
|
172
|
+
setInitialStateOptions: (key: string, value: OptionsType) => void;
|
|
173
|
+
|
|
174
|
+
// --- Validation ---
|
|
175
|
+
validationErrors: Map<string, string[]>;
|
|
176
|
+
addValidationError: (path: string, message: string) => void;
|
|
177
|
+
getValidationErrors: (path: string) => string[];
|
|
178
|
+
removeValidationError: (path: string) => void;
|
|
179
|
+
|
|
180
|
+
// --- Server Sync and Logging ---
|
|
181
|
+
serverSyncActions: { [key: string]: SyncActionsType<any> };
|
|
182
|
+
serverSyncLog: { [key: string]: SyncLogType[] };
|
|
181
183
|
stateLog: { [key: string]: UpdateTypeDetail[] };
|
|
184
|
+
syncInfoStore: Map<string, SyncInfo>;
|
|
185
|
+
serverSideOrNot: { [key: string]: boolean };
|
|
186
|
+
setServerSyncLog: (key: string, newValue: SyncLogType) => void;
|
|
187
|
+
setServerSideOrNot: (key: string, value: boolean) => void;
|
|
188
|
+
getServerSideOrNot: (key: string) => boolean | undefined;
|
|
189
|
+
getThisLocalUpdate: (key: string) => UpdateTypeDetail[] | undefined;
|
|
190
|
+
setServerSyncActions: (key: string, value: SyncActionsType<any>) => void;
|
|
182
191
|
setStateLog: (
|
|
183
192
|
key: string,
|
|
184
193
|
updater: (prevUpdates: UpdateTypeDetail[]) => UpdateTypeDetail[]
|
|
185
194
|
) => void;
|
|
186
|
-
|
|
195
|
+
setSyncInfo: (key: string, syncInfo: SyncInfo) => void;
|
|
196
|
+
getSyncInfo: (key: string) => SyncInfo | null;
|
|
187
197
|
|
|
188
|
-
|
|
189
|
-
removeValidationError: (path: string) => void;
|
|
198
|
+
// --- Component and DOM Integration ---
|
|
190
199
|
signalDomElements: Map<
|
|
191
200
|
string,
|
|
192
201
|
Set<{
|
|
@@ -208,8 +217,10 @@ export type CogsGlobalState = {
|
|
|
208
217
|
}
|
|
209
218
|
) => void;
|
|
210
219
|
removeSignalElement: (signalId: string, instanceId: string) => void;
|
|
211
|
-
|
|
220
|
+
stateComponents: Map<string, ComponentsType>;
|
|
212
221
|
|
|
222
|
+
// --- Deprecated/Legacy (Review for removal) ---
|
|
223
|
+
reRenderTriggerPrevValue: Record<string, any>;
|
|
213
224
|
reactiveDeps: Record<
|
|
214
225
|
string,
|
|
215
226
|
{
|
|
@@ -228,11 +239,6 @@ export type CogsGlobalState = {
|
|
|
228
239
|
) => void;
|
|
229
240
|
deleteReactiveDeps: (key: string) => void;
|
|
230
241
|
subscribe: (listener: () => void) => () => void;
|
|
231
|
-
|
|
232
|
-
stateComponents: Map<string, ComponentsType>;
|
|
233
|
-
syncInfoStore: Map<string, SyncInfo>;
|
|
234
|
-
setSyncInfo: (key: string, syncInfo: SyncInfo) => void;
|
|
235
|
-
getSyncInfo: (key: string) => SyncInfo | null;
|
|
236
242
|
};
|
|
237
243
|
|
|
238
244
|
export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
@@ -250,30 +256,6 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
250
256
|
return current;
|
|
251
257
|
},
|
|
252
258
|
|
|
253
|
-
setShadowMetadata: (key: string, path: string[], metadata: any) => {
|
|
254
|
-
set((state) => {
|
|
255
|
-
const newShadow = { ...state.shadowStateStore };
|
|
256
|
-
if (!newShadow[key]) return state;
|
|
257
|
-
|
|
258
|
-
newShadow[key] = JSON.parse(JSON.stringify(newShadow[key]));
|
|
259
|
-
|
|
260
|
-
let current: any = newShadow[key];
|
|
261
|
-
for (const segment of path) {
|
|
262
|
-
if (!current[segment]) current[segment] = {};
|
|
263
|
-
current = current[segment];
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Merge the metadata into the existing structure
|
|
267
|
-
Object.keys(metadata).forEach((category) => {
|
|
268
|
-
if (!current[category]) {
|
|
269
|
-
current[category] = {};
|
|
270
|
-
}
|
|
271
|
-
Object.assign(current[category], metadata[category]);
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
return { shadowStateStore: newShadow };
|
|
275
|
-
});
|
|
276
|
-
},
|
|
277
259
|
initializeShadowState: (key: string, initialState: any) => {
|
|
278
260
|
const createShadowStructure = (obj: any): any => {
|
|
279
261
|
if (Array.isArray(obj)) {
|
|
@@ -389,6 +371,63 @@ export const getGlobalStore = create<CogsGlobalState>((set, get) => ({
|
|
|
389
371
|
return { shadowStateStore: newShadow };
|
|
390
372
|
});
|
|
391
373
|
},
|
|
374
|
+
shadowStateSubscribers: new Map<string, Set<() => void>>(), // key -> Set of callbacks
|
|
375
|
+
|
|
376
|
+
subscribeToShadowState: (key: string, callback: () => void) => {
|
|
377
|
+
set((state) => {
|
|
378
|
+
const newSubs = new Map(state.shadowStateSubscribers);
|
|
379
|
+
const subsForKey = newSubs.get(key) || new Set();
|
|
380
|
+
subsForKey.add(callback);
|
|
381
|
+
newSubs.set(key, subsForKey);
|
|
382
|
+
return { shadowStateSubscribers: newSubs };
|
|
383
|
+
});
|
|
384
|
+
// Return an unsubscribe function
|
|
385
|
+
return () => {
|
|
386
|
+
set((state) => {
|
|
387
|
+
const newSubs = new Map(state.shadowStateSubscribers);
|
|
388
|
+
const subsForKey = newSubs.get(key);
|
|
389
|
+
if (subsForKey) {
|
|
390
|
+
subsForKey.delete(callback);
|
|
391
|
+
}
|
|
392
|
+
return { shadowStateSubscribers: newSubs };
|
|
393
|
+
});
|
|
394
|
+
};
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
setShadowMetadata: (key: string, path: string[], metadata: any) => {
|
|
398
|
+
let hasChanged = false;
|
|
399
|
+
set((state) => {
|
|
400
|
+
const newShadow = { ...state.shadowStateStore };
|
|
401
|
+
if (!newShadow[key]) return state;
|
|
402
|
+
|
|
403
|
+
newShadow[key] = JSON.parse(JSON.stringify(newShadow[key]));
|
|
404
|
+
|
|
405
|
+
let current: any = newShadow[key];
|
|
406
|
+
for (const segment of path) {
|
|
407
|
+
if (!current[segment]) current[segment] = {};
|
|
408
|
+
current = current[segment];
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const oldHeight = current.virtualizer?.itemHeight;
|
|
412
|
+
const newHeight = metadata.virtualizer?.itemHeight;
|
|
413
|
+
|
|
414
|
+
if (newHeight && oldHeight !== newHeight) {
|
|
415
|
+
hasChanged = true;
|
|
416
|
+
if (!current.virtualizer) current.virtualizer = {};
|
|
417
|
+
current.virtualizer.itemHeight = newHeight;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return { shadowStateStore: newShadow };
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// If a height value was actually changed, notify the specific subscribers.
|
|
424
|
+
if (hasChanged) {
|
|
425
|
+
const subscribers = get().shadowStateSubscribers.get(key);
|
|
426
|
+
if (subscribers) {
|
|
427
|
+
subscribers.forEach((callback) => callback());
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
},
|
|
392
431
|
selectedIndicesMap: new Map<string, Map<string, number>>(),
|
|
393
432
|
|
|
394
433
|
// Add the new methods
|