@jsenv/navi 0.29.448 → 0.29.450
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/dev/jsenv_navi.js +184 -85
- package/dist/dev/jsenv_navi.js.map +4 -4
- package/dist/jsenv_navi.js +184 -85
- package/dist/jsenv_navi.js.map +4 -4
- package/docs/AI_INSTRUCTIONS.md +6 -4
- package/docs/list_refresh.md +10 -4
- package/docs/scroll.md +36 -4
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -4827,9 +4827,11 @@ const actionRunEffect = (
|
|
|
4827
4827
|
return params;
|
|
4828
4828
|
});
|
|
4829
4829
|
// Whether the getter asks for a run is read off what it returned, never off
|
|
4830
|
-
// the
|
|
4831
|
-
//
|
|
4832
|
-
//
|
|
4830
|
+
// the instances it moves between: an action handed here holding params of
|
|
4831
|
+
// its own (an instance, a binding) keeps them when the getter returns
|
|
4832
|
+
// nothing — and nothing must still run nothing; an instance reset under the
|
|
4833
|
+
// effect (a same-resource DELETE) reads as never run — and the next params
|
|
4834
|
+
// the getter asks for must still run.
|
|
4833
4835
|
let asking = Boolean(actionParamsSignal.peek());
|
|
4834
4836
|
const actionRunnedByThisEffect = action.bindParams(actionParamsSignal, {
|
|
4835
4837
|
debounce,
|
|
@@ -4856,11 +4858,7 @@ const actionRunEffect = (
|
|
|
4856
4858
|
return;
|
|
4857
4859
|
}
|
|
4858
4860
|
|
|
4859
|
-
if (
|
|
4860
|
-
actionTargetPrevious &&
|
|
4861
|
-
!actionTargetPrevious.isPrerun &&
|
|
4862
|
-
actionTarget
|
|
4863
|
-
) {
|
|
4861
|
+
if (actionTargetPrevious && actionTarget) {
|
|
4864
4862
|
// params changed
|
|
4865
4863
|
if (!asking) {
|
|
4866
4864
|
// falsy params, don't run
|
|
@@ -72293,6 +72291,9 @@ const createListItems = () => {
|
|
|
72293
72291
|
// what puts the view back once they have (see VirtualFiller).
|
|
72294
72292
|
captureAnchor: () => {},
|
|
72295
72293
|
holdViewStill: () => {},
|
|
72294
|
+
// The list has asked for a window no render has drawn yet: a run holding
|
|
72295
|
+
// the one before has nothing to ask for it (see useRequestMissing).
|
|
72296
|
+
windowOnItsWay: () => false,
|
|
72296
72297
|
horizontal: false,
|
|
72297
72298
|
virtualItemSizeSignal: null,
|
|
72298
72299
|
roomById,
|
|
@@ -74462,6 +74463,7 @@ const useListScrollSync = ({
|
|
|
74462
74463
|
const renderWindowRef = useRef(null);
|
|
74463
74464
|
// A window was asked for that no render has drawn yet (see settleWindow).
|
|
74464
74465
|
const windowAskedRef = useRef(false);
|
|
74466
|
+
listItems.windowOnItsWay = () => windowAskedRef.current;
|
|
74465
74467
|
const windowLeavesItemsOut = () => {
|
|
74466
74468
|
const renderWindow = renderWindowRef.current;
|
|
74467
74469
|
if (!renderWindow) {
|
|
@@ -75933,6 +75935,7 @@ const useListScrollSync = ({
|
|
|
75933
75935
|
}, [scrollerElResolved]);
|
|
75934
75936
|
holdWindow();
|
|
75935
75937
|
// Whatever was asked for until now is what this render draws.
|
|
75938
|
+
const windowWasAsked = windowAskedRef.current;
|
|
75936
75939
|
windowAskedRef.current = false;
|
|
75937
75940
|
const {
|
|
75938
75941
|
start: windowStart,
|
|
@@ -75948,13 +75951,15 @@ const useListScrollSync = ({
|
|
|
75948
75951
|
// column — started anywhere but on a line, every item drawn would sit in the
|
|
75949
75952
|
// column of another. Started on one, an item is in the column its place says
|
|
75950
75953
|
// whatever the window frames. The same object while the numbers hold, so the
|
|
75951
|
-
// runs are not told about a window that did not move
|
|
75954
|
+
// runs are not told about a window that did not move — except after a window
|
|
75955
|
+
// was asked for: a run waiting for it to ask (see useRequestMissing) must be
|
|
75956
|
+
// told, even when the window framed comes back to the same numbers.
|
|
75952
75957
|
const windowDrawnRef = useRef(null);
|
|
75953
75958
|
const drawnStart = windowStart - windowStart % itemsPerLine;
|
|
75954
75959
|
const endPastLine = windowEnd % itemsPerLine;
|
|
75955
75960
|
const drawnEnd = endPastLine === 0 ? windowEnd : windowEnd + itemsPerLine - endPastLine;
|
|
75956
75961
|
let windowDrawn = windowDrawnRef.current;
|
|
75957
|
-
if (!windowDrawn || windowDrawn.start !== drawnStart || windowDrawn.end !== drawnEnd || windowDrawn.itemsPerLine !== itemsPerLine) {
|
|
75962
|
+
if (!windowDrawn || windowWasAsked || windowDrawn.start !== drawnStart || windowDrawn.end !== drawnEnd || windowDrawn.itemsPerLine !== itemsPerLine) {
|
|
75958
75963
|
windowDrawn = {
|
|
75959
75964
|
start: drawnStart,
|
|
75960
75965
|
end: drawnEnd,
|
|
@@ -78089,6 +78094,15 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
78089
78094
|
* @param {(range: object) => any} [props.itemsAction]
|
|
78090
78095
|
* Where the items come from when the collection is read a slice at a time:
|
|
78091
78096
|
* a resource's range reader (`RESOURCE.GET_RANGE.bindParams(...)`).
|
|
78097
|
+
* @param {number} [props.count]
|
|
78098
|
+
* How many items the collection holds, when the app knows it before the
|
|
78099
|
+
* first answer: a total shown elsewhere, a profile saying how many there are.
|
|
78100
|
+
* The list is then as long as the collection from its first frame: it opens
|
|
78101
|
+
* where it is held, the scrollbar right, and asks for that window. Without
|
|
78102
|
+
* it, the run stands for skeletons up to the item the list opens on and a
|
|
78103
|
+
* page past it, until the first answer says how many there are. Not worth a
|
|
78104
|
+
* request of its own, since the first answer gives it (see docs/scroll.md,
|
|
78105
|
+
* "What a run knows when it opens").
|
|
78092
78106
|
* @param {number} [props.debounce]
|
|
78093
78107
|
* Milliseconds the reader must hold still before the run draws the
|
|
78094
78108
|
* collection it reads: params following a field as the user types
|
|
@@ -78204,6 +78218,7 @@ const ListItemsRun = ({
|
|
|
78204
78218
|
count,
|
|
78205
78219
|
itemsAction,
|
|
78206
78220
|
settling,
|
|
78221
|
+
pageSize: runProps.pageSize,
|
|
78207
78222
|
memoryBudget,
|
|
78208
78223
|
onRequestStateChange,
|
|
78209
78224
|
onCountChange
|
|
@@ -78472,9 +78487,17 @@ const useRunItems = (store, {
|
|
|
78472
78487
|
// A hole with nothing on either side (the scrollbar was thrown into
|
|
78473
78488
|
// territory never visited): grow it both ways around what is on
|
|
78474
78489
|
// screen.
|
|
78475
|
-
|
|
78476
|
-
|
|
78477
|
-
|
|
78490
|
+
askStart = missingStart - Math.floor((itemsPerPage - holeSize) / 2);
|
|
78491
|
+
askEnd = askStart + itemsPerPage - 1;
|
|
78492
|
+
// Cut by an edge of the run (the first page, the last one), the page
|
|
78493
|
+
// takes the room on the other side.
|
|
78494
|
+
if (askStart < runStart) {
|
|
78495
|
+
askEnd += runStart - askStart;
|
|
78496
|
+
askStart = runStart;
|
|
78497
|
+
} else if (askEnd > runEnd - 1) {
|
|
78498
|
+
askStart -= askEnd - (runEnd - 1);
|
|
78499
|
+
askEnd = runEnd - 1;
|
|
78500
|
+
}
|
|
78478
78501
|
}
|
|
78479
78502
|
}
|
|
78480
78503
|
if (askStart < runStart) {
|
|
@@ -78874,6 +78897,18 @@ const ListItemsFailure = ({
|
|
|
78874
78897
|
const ITEM_STORE_MAX_DEFAULT = 1000;
|
|
78875
78898
|
const ITEM_STORE_KEEP_AROUND = 250;
|
|
78876
78899
|
const COUNT_NOT_SAID = {};
|
|
78900
|
+
|
|
78901
|
+
// The index of the item the list is held at, when the hold names one: a number,
|
|
78902
|
+
// or a position remembered with its index (see placeWhereHeld).
|
|
78903
|
+
const readHeldIndex = scrolled => {
|
|
78904
|
+
if (typeof scrolled === "number") {
|
|
78905
|
+
return scrolled;
|
|
78906
|
+
}
|
|
78907
|
+
if (scrolled && typeof scrolled === "object" && typeof scrolled.index === "number") {
|
|
78908
|
+
return scrolled.index;
|
|
78909
|
+
}
|
|
78910
|
+
return null;
|
|
78911
|
+
};
|
|
78877
78912
|
const rangeIsSame = (a, b) => {
|
|
78878
78913
|
if (!a || !b) {
|
|
78879
78914
|
return a === b;
|
|
@@ -78891,6 +78926,7 @@ const useItemStore = ({
|
|
|
78891
78926
|
count,
|
|
78892
78927
|
itemsAction,
|
|
78893
78928
|
settling,
|
|
78929
|
+
pageSize,
|
|
78894
78930
|
memoryBudget,
|
|
78895
78931
|
onRequestStateChange,
|
|
78896
78932
|
onCountChange
|
|
@@ -78976,6 +79012,68 @@ const useItemStore = ({
|
|
|
78976
79012
|
if (staleRanksRef.current === null) {
|
|
78977
79013
|
staleRanksRef.current = restored ? new Set(pages.byIndex.keys()) : new Set();
|
|
78978
79014
|
}
|
|
79015
|
+
const takeInPage = ({
|
|
79016
|
+
pageItems,
|
|
79017
|
+
pageStart,
|
|
79018
|
+
pageCount
|
|
79019
|
+
}) => {
|
|
79020
|
+
// An item from before is gone from where it stood when the page puts
|
|
79021
|
+
// it at another rank (it would be drawn twice), or when its rank is
|
|
79022
|
+
// past the end of the collection.
|
|
79023
|
+
const staleRanks = staleRanksRef.current;
|
|
79024
|
+
const pageEnd = pageStart + pageItems.length;
|
|
79025
|
+
let dropped = false;
|
|
79026
|
+
if (staleRanks.size > 0) {
|
|
79027
|
+
const pageIds = new Set();
|
|
79028
|
+
for (const pageItem of pageItems) {
|
|
79029
|
+
if (pageItem && pageItem.id !== undefined) {
|
|
79030
|
+
pageIds.add(pageItem.id);
|
|
79031
|
+
}
|
|
79032
|
+
}
|
|
79033
|
+
for (const rank of staleRanks) {
|
|
79034
|
+
if (rank >= pageStart && rank < pageEnd) {
|
|
79035
|
+
continue;
|
|
79036
|
+
}
|
|
79037
|
+
const staleItem = pages.byIndex.get(rank);
|
|
79038
|
+
if (rank >= pageCount || staleItem && pageIds.has(staleItem.id)) {
|
|
79039
|
+
staleRanks.delete(rank);
|
|
79040
|
+
pages.byIndex.delete(rank);
|
|
79041
|
+
dropped = true;
|
|
79042
|
+
}
|
|
79043
|
+
}
|
|
79044
|
+
}
|
|
79045
|
+
let i = 0;
|
|
79046
|
+
while (i < pageItems.length) {
|
|
79047
|
+
pages.byIndex.set(pageStart + i, pageItems[i]);
|
|
79048
|
+
staleRanks.delete(pageStart + i);
|
|
79049
|
+
i++;
|
|
79050
|
+
}
|
|
79051
|
+
pages.count = pageCount;
|
|
79052
|
+
// Which rank holds which id, kept by the source so a list drawing
|
|
79053
|
+
// this collection again finds it drawn (see readComposition above).
|
|
79054
|
+
if (itemsAction.writeComposition) {
|
|
79055
|
+
itemsAction.writeComposition({
|
|
79056
|
+
byIndex: pages.byIndex,
|
|
79057
|
+
count: pageCount,
|
|
79058
|
+
replace: dropped
|
|
79059
|
+
});
|
|
79060
|
+
}
|
|
79061
|
+
};
|
|
79062
|
+
// The pages answered since the last render, taken in by the render and not
|
|
79063
|
+
// as they land: what the list reads of the run — how many items it stands for
|
|
79064
|
+
// (see listItems.take), where an item sits (its locator) — then moves in one
|
|
79065
|
+
// step. Taken in on landing, an item could be located past the count the list
|
|
79066
|
+
// still holds, and a list held on it would aim its window there at every
|
|
79067
|
+
// render, framed back each time.
|
|
79068
|
+
const pagesLandedRef = useRef([]);
|
|
79069
|
+
const pagesLanded = pagesLandedRef.current;
|
|
79070
|
+
const pagesTakenIn = pagesLanded.length > 0;
|
|
79071
|
+
if (pagesTakenIn) {
|
|
79072
|
+
pagesLandedRef.current = [];
|
|
79073
|
+
for (const page of pagesLanded) {
|
|
79074
|
+
takeInPage(page);
|
|
79075
|
+
}
|
|
79076
|
+
}
|
|
78979
79077
|
const [refreshing, setRefreshing] = useState(false);
|
|
78980
79078
|
// A source that says when what it reads has moved (a resource range reader
|
|
78981
79079
|
// does: see rerunOn.GET_RANGE) is heard here — a write deciding who belongs
|
|
@@ -79006,19 +79104,33 @@ const useItemStore = ({
|
|
|
79006
79104
|
const [failure, setFailure] = useState(null);
|
|
79007
79105
|
const listItems = useContext(ListItemsContext);
|
|
79008
79106
|
// The items are there, which is what the list waits for to place itself on the
|
|
79009
|
-
// item it is held at (see placeWhereHeld). Said from an effect
|
|
79010
|
-
// during this very render must not be written
|
|
79107
|
+
// item it is held at (see placeWhereHeld). Said from an effect, once the run
|
|
79108
|
+
// has drawn them: a signal read during this very render must not be written
|
|
79109
|
+
// during it.
|
|
79011
79110
|
useLayoutEffect(() => {
|
|
79012
|
-
if (
|
|
79111
|
+
if (inMemory) {
|
|
79112
|
+
if (itemsHeldRef.current) {
|
|
79113
|
+
return;
|
|
79114
|
+
}
|
|
79115
|
+
itemsHeldRef.current = true;
|
|
79116
|
+
} else if (!pagesTakenIn) {
|
|
79013
79117
|
return;
|
|
79014
79118
|
}
|
|
79015
|
-
itemsHeldRef.current = true;
|
|
79016
79119
|
listItems.pagesSignal.value = listItems.pagesSignal.peek() + 1;
|
|
79017
79120
|
});
|
|
79018
79121
|
// Before the first answer a run does not know how many items it stands for.
|
|
79019
79122
|
// It stands for a page of them: a list that is about to be filled looks
|
|
79020
|
-
// like items on their way, not like an empty list.
|
|
79021
|
-
|
|
79123
|
+
// like items on their way, not like an empty list. A list held on an item
|
|
79124
|
+
// (see placeWhereHeld) is about to be filled there: the run stands for the
|
|
79125
|
+
// items up to that one and a page past it, so the window frames the item
|
|
79126
|
+
// before any answer, and what the run asks for first is that window.
|
|
79127
|
+
const itemsPerPage = pageSize || listItems.pageSize;
|
|
79128
|
+
const countKnown = pages.count ?? count;
|
|
79129
|
+
let itemCount = countKnown;
|
|
79130
|
+
if (itemCount === undefined) {
|
|
79131
|
+
const heldIndex = readHeldIndex(listItems.scrolled);
|
|
79132
|
+
itemCount = heldIndex === null ? itemsPerPage : heldIndex + itemsPerPage;
|
|
79133
|
+
}
|
|
79022
79134
|
// The items drawn are from before while they are read again, and while the
|
|
79023
79135
|
// collection that replaces them waits for its params to hold still (see
|
|
79024
79136
|
// useSettledReader).
|
|
@@ -79037,7 +79149,6 @@ const useItemStore = ({
|
|
|
79037
79149
|
// say: the count the source answered or the caller gave, never the page the
|
|
79038
79150
|
// run stands for before it knows. Said by each run on its first commit, so a
|
|
79039
79151
|
// run drawing another collection takes back what the one before said.
|
|
79040
|
-
const countKnown = pages.count ?? count;
|
|
79041
79152
|
const onCountChangeRef = useRef(onCountChange);
|
|
79042
79153
|
onCountChangeRef.current = onCountChange;
|
|
79043
79154
|
const countSaidRef = useRef(COUNT_NOT_SAID);
|
|
@@ -79084,8 +79195,13 @@ const useItemStore = ({
|
|
|
79084
79195
|
};
|
|
79085
79196
|
// A list taken off the screen while it was asking leaves nothing ringing
|
|
79086
79197
|
// behind it: whoever is drawing "looking for items" has to stop.
|
|
79198
|
+
const mountedRef = useRef(false);
|
|
79199
|
+
// Which render's ask is the one to send (see useRequestMissing).
|
|
79200
|
+
const askTurnRef = useRef(0);
|
|
79087
79201
|
useLayoutEffect(() => {
|
|
79202
|
+
mountedRef.current = true;
|
|
79088
79203
|
return () => {
|
|
79204
|
+
mountedRef.current = false;
|
|
79089
79205
|
if (requestStateRef.current.busy && onRequestStateChangeRef.current) {
|
|
79090
79206
|
onRequestStateChangeRef.current({
|
|
79091
79207
|
busy: false,
|
|
@@ -79145,11 +79261,7 @@ const useItemStore = ({
|
|
|
79145
79261
|
// what it hands over (see rankOf). The one thing read from the list
|
|
79146
79262
|
// itself is where it is being held, which is a list item.
|
|
79147
79263
|
const rankOfIndex = itemIndex => itemIndex - runStart;
|
|
79148
|
-
|
|
79149
|
-
// how many items there are, so it asks for the items the list would open
|
|
79150
|
-
// on — counting back from the end when that is where it opens, the way
|
|
79151
|
-
// an HTTP range does.
|
|
79152
|
-
const budget = listItems.pageSize;
|
|
79264
|
+
const budget = itemsPerPage;
|
|
79153
79265
|
let start = missingStart;
|
|
79154
79266
|
let end = missingEnd;
|
|
79155
79267
|
let around;
|
|
@@ -79219,26 +79331,26 @@ const useItemStore = ({
|
|
|
79219
79331
|
around = firstStale.id;
|
|
79220
79332
|
}
|
|
79221
79333
|
} else if (pages.count === undefined) {
|
|
79334
|
+
// The very first ask is what the window misses, like any other: the
|
|
79335
|
+
// run stands for the items up to where the list opens (see
|
|
79336
|
+
// itemCount), so the window frames that place already.
|
|
79222
79337
|
const scrolled = listItems.scrolled;
|
|
79223
|
-
if (scrolled === "end") {
|
|
79224
|
-
//
|
|
79225
|
-
//
|
|
79226
|
-
// there are.
|
|
79338
|
+
if (scrolled === "end" && countKnown === undefined) {
|
|
79339
|
+
// Except the end, which no window can frame before the count is
|
|
79340
|
+
// known: counted back from, the way an HTTP range does.
|
|
79227
79341
|
start = -budget;
|
|
79228
79342
|
end = -1;
|
|
79229
|
-
} else if (
|
|
79230
|
-
//
|
|
79231
|
-
//
|
|
79232
|
-
|
|
79233
|
-
|
|
79234
|
-
|
|
79235
|
-
|
|
79236
|
-
|
|
79343
|
+
} else if (start === -1) {
|
|
79344
|
+
// The window does not reach the run yet: its first page is asked
|
|
79345
|
+
// for all the same, which says how many items it stands for.
|
|
79346
|
+
start = 0;
|
|
79347
|
+
end = budget - 1;
|
|
79348
|
+
}
|
|
79349
|
+
if (scrolled && scrolled.id !== undefined) {
|
|
79350
|
+
// Asked for by name too, since a place can have changed hands since
|
|
79351
|
+
// it was written down: the answer says where it really landed (see
|
|
79352
|
+
// the page's own `start`).
|
|
79237
79353
|
around = scrolled.id;
|
|
79238
|
-
} else {
|
|
79239
|
-
const first = typeof scrolled === "number" ? rankOfIndex(scrolled) - Math.floor(budget / 2) : 0;
|
|
79240
|
-
start = first < 0 ? 0 : first;
|
|
79241
|
-
end = start + budget - 1;
|
|
79242
79354
|
}
|
|
79243
79355
|
}
|
|
79244
79356
|
const ask = () => {
|
|
@@ -79252,6 +79364,12 @@ const useItemStore = ({
|
|
|
79252
79364
|
const debugAsk = outcome => {
|
|
79253
79365
|
debugScroll(`ask ${start}-${end}: ${outcome}`, `(revalidating=${revalidating} holdPending=${listItems.holdPending} count=${pages.count})`);
|
|
79254
79366
|
};
|
|
79367
|
+
if (listItems.windowOnItsWay()) {
|
|
79368
|
+
// The list moved its window after this render drew the one it had:
|
|
79369
|
+
// the run draws the new one in the list's next pass, and asks then.
|
|
79370
|
+
debugAsk("the list is moving its window");
|
|
79371
|
+
return;
|
|
79372
|
+
}
|
|
79255
79373
|
if (start === -1) {
|
|
79256
79374
|
// Nothing missing and nothing to revalidate: the run has what it
|
|
79257
79375
|
// draws.
|
|
@@ -79347,51 +79465,21 @@ const useItemStore = ({
|
|
|
79347
79465
|
const pageItems = Array.isArray(page) ? page : page.items;
|
|
79348
79466
|
const pageStart = Array.isArray(page) ? 0 : page.start ?? 0;
|
|
79349
79467
|
const pageCount = Array.isArray(page) ? pageItems.length : page.count ?? pageStart + pageItems.length;
|
|
79468
|
+
const pageLanded = {
|
|
79469
|
+
pageItems,
|
|
79470
|
+
pageStart,
|
|
79471
|
+
pageCount
|
|
79472
|
+
};
|
|
79473
|
+
if (!mountedRef.current) {
|
|
79474
|
+
// No render is coming to take it in, and the source still keeps
|
|
79475
|
+
// what came back for the next list drawing this collection.
|
|
79476
|
+
takeInPage(pageLanded);
|
|
79477
|
+
return;
|
|
79478
|
+
}
|
|
79350
79479
|
// Before the items land: what is on screen has to stay where it is,
|
|
79351
79480
|
// and the DOM still shows the state to hold onto.
|
|
79352
79481
|
listItems.captureAnchor();
|
|
79353
|
-
|
|
79354
|
-
// it at another rank (it would be drawn twice), or when its rank is
|
|
79355
|
-
// past the end of the collection.
|
|
79356
|
-
const staleRanksNow = staleRanksRef.current;
|
|
79357
|
-
const pageEnd = pageStart + pageItems.length;
|
|
79358
|
-
let dropped = false;
|
|
79359
|
-
if (staleRanksNow.size > 0) {
|
|
79360
|
-
const pageIds = new Set();
|
|
79361
|
-
for (const pageItem of pageItems) {
|
|
79362
|
-
if (pageItem && pageItem.id !== undefined) {
|
|
79363
|
-
pageIds.add(pageItem.id);
|
|
79364
|
-
}
|
|
79365
|
-
}
|
|
79366
|
-
for (const rank of staleRanksNow) {
|
|
79367
|
-
if (rank >= pageStart && rank < pageEnd) {
|
|
79368
|
-
continue;
|
|
79369
|
-
}
|
|
79370
|
-
const staleItem = pages.byIndex.get(rank);
|
|
79371
|
-
if (rank >= pageCount || staleItem && pageIds.has(staleItem.id)) {
|
|
79372
|
-
staleRanksNow.delete(rank);
|
|
79373
|
-
pages.byIndex.delete(rank);
|
|
79374
|
-
dropped = true;
|
|
79375
|
-
}
|
|
79376
|
-
}
|
|
79377
|
-
}
|
|
79378
|
-
let i = 0;
|
|
79379
|
-
while (i < pageItems.length) {
|
|
79380
|
-
pages.byIndex.set(pageStart + i, pageItems[i]);
|
|
79381
|
-
staleRanksNow.delete(pageStart + i);
|
|
79382
|
-
i++;
|
|
79383
|
-
}
|
|
79384
|
-
pages.count = pageCount;
|
|
79385
|
-
// Which rank holds which id, kept by the source so a list drawing
|
|
79386
|
-
// this collection again finds it drawn (see readComposition above).
|
|
79387
|
-
if (itemsAction.writeComposition) {
|
|
79388
|
-
itemsAction.writeComposition({
|
|
79389
|
-
byIndex: pages.byIndex,
|
|
79390
|
-
count: pageCount,
|
|
79391
|
-
replace: dropped
|
|
79392
|
-
});
|
|
79393
|
-
}
|
|
79394
|
-
listItems.pagesSignal.value = listItems.pagesSignal.peek() + 1;
|
|
79482
|
+
pagesLandedRef.current.push(pageLanded);
|
|
79395
79483
|
setPageVersion(version => version + 1);
|
|
79396
79484
|
};
|
|
79397
79485
|
const failed = error => {
|
|
@@ -79436,9 +79524,20 @@ const useItemStore = ({
|
|
|
79436
79524
|
done(result);
|
|
79437
79525
|
}
|
|
79438
79526
|
};
|
|
79527
|
+
// Asked once the commit is over rather than from the effect: the list
|
|
79528
|
+
// frames its window after its runs, in that same commit — sized on the
|
|
79529
|
+
// screen, aimed at the item it is held on — and what the run asks for is
|
|
79530
|
+
// the window the list settles on. A render coming meanwhile asks instead.
|
|
79439
79531
|
useLayoutEffect(() => {
|
|
79440
|
-
|
|
79441
|
-
|
|
79532
|
+
askTurnRef.current++;
|
|
79533
|
+
const turn = askTurnRef.current;
|
|
79534
|
+
queueMicrotask(() => {
|
|
79535
|
+
if (turn !== askTurnRef.current || !mountedRef.current) {
|
|
79536
|
+
return;
|
|
79537
|
+
}
|
|
79538
|
+
ask();
|
|
79539
|
+
publishRequestState();
|
|
79540
|
+
});
|
|
79442
79541
|
});
|
|
79443
79542
|
}
|
|
79444
79543
|
};
|