@jsenv/navi 0.29.427 → 0.29.428
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 +144 -46
- package/dist/dev/jsenv_navi.js.map +4 -4
- package/dist/jsenv_navi.js +144 -46
- package/dist/jsenv_navi.js.map +4 -4
- package/docs/list_refresh.md +5 -4
- package/package.json +2 -2
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -26867,10 +26867,11 @@ const createRangeReader = (
|
|
|
26867
26867
|
});
|
|
26868
26868
|
return { byIndex, count: composition.count };
|
|
26869
26869
|
};
|
|
26870
|
-
// `replace`
|
|
26871
|
-
//
|
|
26872
|
-
// so two lists reading the same
|
|
26873
|
-
// to one composition instead of
|
|
26870
|
+
// `replace` says the list dropped ranks it held (an item the collection moved
|
|
26871
|
+
// elsewhere, ranks past its end): kept here, they would come back at the next
|
|
26872
|
+
// mount. Otherwise the ranks are merged, so two lists reading the same
|
|
26873
|
+
// collection through their own windows add up to one composition instead of
|
|
26874
|
+
// taking turns erasing each other.
|
|
26874
26875
|
readRange.writeComposition = ({ byIndex, count, replace }) => {
|
|
26875
26876
|
const params = currentParams();
|
|
26876
26877
|
let composition = findComposition(params);
|
|
@@ -77673,19 +77674,57 @@ const useRunItems = (store, {
|
|
|
77673
77674
|
// rebuilt as the window slides — a group holds the items of its day that are
|
|
77674
77675
|
// currently drawn, which is exactly the span its label has to survive.
|
|
77675
77676
|
let group = null;
|
|
77677
|
+
// Two groups can still share a key (a failure band standing mid-group, data
|
|
77678
|
+
// not sorted by group): the later ones are told apart by their rank among
|
|
77679
|
+
// them, so the first keeps its element. A group keyed by where it starts
|
|
77680
|
+
// would lose its element each time the window slides past its first item.
|
|
77681
|
+
const groupCountByKey = new Map();
|
|
77676
77682
|
const closeGroup = () => {
|
|
77677
77683
|
if (!group) {
|
|
77678
77684
|
return;
|
|
77679
77685
|
}
|
|
77686
|
+
const groupCount = (groupCountByKey.get(group.key) || 0) + 1;
|
|
77687
|
+
groupCountByKey.set(group.key, groupCount);
|
|
77680
77688
|
nodes.push(jsx(ListItemGroup, {
|
|
77681
77689
|
label: group.label,
|
|
77682
77690
|
labelProps: group.labelProps,
|
|
77683
77691
|
children: group.children
|
|
77684
|
-
}, `${ownerId}_group_${group.key}`));
|
|
77692
|
+
}, groupCount === 1 ? `${ownerId}_group_${group.key}` : `${ownerId}_group_${group.key}_${groupCount}`));
|
|
77685
77693
|
group = null;
|
|
77686
77694
|
};
|
|
77695
|
+
// An item not held has no group of its own. Between two items of the open
|
|
77696
|
+
// group it is a line of that group whose content has not arrived: drawn
|
|
77697
|
+
// outside, it would cut the group in two and show its label twice. A hole at
|
|
77698
|
+
// a group's edge stays outside — nothing says which side it belongs to.
|
|
77699
|
+
let holeTo = -1;
|
|
77700
|
+
let holeGroupKey;
|
|
77701
|
+
const groupKeyOfHole = itemIndex => {
|
|
77702
|
+
if (itemIndex < holeTo) {
|
|
77703
|
+
return holeGroupKey;
|
|
77704
|
+
}
|
|
77705
|
+
holeTo = itemIndex + 1;
|
|
77706
|
+
while (holeTo < windowTo && holeTo !== failureFrom && getItemAt(holeTo) === undefined) {
|
|
77707
|
+
holeTo++;
|
|
77708
|
+
}
|
|
77709
|
+
holeGroupKey = undefined;
|
|
77710
|
+
if (group && holeTo < windowTo && holeTo !== failureFrom) {
|
|
77711
|
+
const keyAfterHole = groupBy(getItemAt(holeTo), holeTo);
|
|
77712
|
+
if (keyAfterHole === group.key) {
|
|
77713
|
+
holeGroupKey = keyAfterHole;
|
|
77714
|
+
}
|
|
77715
|
+
}
|
|
77716
|
+
return holeGroupKey;
|
|
77717
|
+
};
|
|
77687
77718
|
// Which group an item belongs to, or undefined when it belongs to none.
|
|
77688
|
-
const groupKeyOf = (item, itemIndex) =>
|
|
77719
|
+
const groupKeyOf = (item, itemIndex) => {
|
|
77720
|
+
if (!groupBy) {
|
|
77721
|
+
return undefined;
|
|
77722
|
+
}
|
|
77723
|
+
if (item === undefined) {
|
|
77724
|
+
return groupKeyOfHole(itemIndex);
|
|
77725
|
+
}
|
|
77726
|
+
return groupBy(item, itemIndex);
|
|
77727
|
+
};
|
|
77689
77728
|
const pushItem = (itemNode, item, itemIndex, groupKey) => {
|
|
77690
77729
|
if (groupKey === undefined) {
|
|
77691
77730
|
closeGroup();
|
|
@@ -78022,10 +78061,15 @@ const useItemStore = ({
|
|
|
78022
78061
|
}
|
|
78023
78062
|
const pages = pagesRef.current;
|
|
78024
78063
|
const [, setPageVersion] = useState(0);
|
|
78025
|
-
// The
|
|
78026
|
-
//
|
|
78027
|
-
//
|
|
78028
|
-
|
|
78064
|
+
// The ranks whose item is from before: the run came back to the screen, or
|
|
78065
|
+
// the source said the collection moved. They stay drawn until a page confirms
|
|
78066
|
+
// or replaces them, rank by rank. A page covers what the window framed when it
|
|
78067
|
+
// was asked for, and the window keeps growing meanwhile: dropping what the
|
|
78068
|
+
// page did not cover empties items on screen.
|
|
78069
|
+
const staleRanksRef = useRef(null);
|
|
78070
|
+
if (staleRanksRef.current === null) {
|
|
78071
|
+
staleRanksRef.current = restored ? new Set(pages.byIndex.keys()) : new Set();
|
|
78072
|
+
}
|
|
78029
78073
|
const [refreshing, setRefreshing] = useState(false);
|
|
78030
78074
|
// A source that says when what it reads has moved (a resource range reader
|
|
78031
78075
|
// does: see rerunOn.GET_RANGE) is heard here — a write deciding who belongs
|
|
@@ -78036,7 +78080,7 @@ const useItemStore = ({
|
|
|
78036
78080
|
const invalidationRef = useRef(invalidation);
|
|
78037
78081
|
if (invalidationRef.current !== invalidation) {
|
|
78038
78082
|
invalidationRef.current = invalidation;
|
|
78039
|
-
|
|
78083
|
+
staleRanksRef.current = new Set(pages.byIndex.keys());
|
|
78040
78084
|
}
|
|
78041
78085
|
// The one request in flight, with the means to call it off: a page asked for
|
|
78042
78086
|
// a window the list has left is work the server and the browser are doing for
|
|
@@ -78069,11 +78113,6 @@ const useItemStore = ({
|
|
|
78069
78113
|
// It stands for a page of them: a list that is about to be filled looks
|
|
78070
78114
|
// like items on their way, not like an empty list.
|
|
78071
78115
|
const itemCount = pages.count ?? count ?? listItems.pageSize;
|
|
78072
|
-
// A run that never received anything has nothing to keep on screen: asking
|
|
78073
|
-
// again is its first ask, not a refresh.
|
|
78074
|
-
if (staleRef.current && pages.count === undefined) {
|
|
78075
|
-
staleRef.current = false;
|
|
78076
|
-
}
|
|
78077
78116
|
useLayoutEffect(() => {
|
|
78078
78117
|
if (!refreshing) {
|
|
78079
78118
|
return null;
|
|
@@ -78146,9 +78185,11 @@ const useItemStore = ({
|
|
|
78146
78185
|
const keepFrom = windowFrom - ITEM_STORE_KEEP_AROUND;
|
|
78147
78186
|
const keepTo = windowTo + ITEM_STORE_KEEP_AROUND;
|
|
78148
78187
|
if (pages.byIndex.size > budget) {
|
|
78188
|
+
const staleRanks = staleRanksRef.current;
|
|
78149
78189
|
for (const index of pages.byIndex.keys()) {
|
|
78150
78190
|
if (index < keepFrom || index > keepTo) {
|
|
78151
78191
|
pages.byIndex.delete(index);
|
|
78192
|
+
staleRanks.delete(index);
|
|
78152
78193
|
}
|
|
78153
78194
|
}
|
|
78154
78195
|
}
|
|
@@ -78183,10 +78224,24 @@ const useItemStore = ({
|
|
|
78183
78224
|
let start = missingStart;
|
|
78184
78225
|
let end = missingEnd;
|
|
78185
78226
|
let around;
|
|
78186
|
-
//
|
|
78187
|
-
//
|
|
78188
|
-
|
|
78189
|
-
|
|
78227
|
+
// The window draws items from before: they are asked for again, and stay
|
|
78228
|
+
// drawn meanwhile.
|
|
78229
|
+
const staleRanks = staleRanksRef.current;
|
|
78230
|
+
let staleFrom = -1;
|
|
78231
|
+
let staleTo = -1;
|
|
78232
|
+
if (staleRanks.size > 0) {
|
|
78233
|
+
let rank = windowFrom;
|
|
78234
|
+
while (rank < windowTo) {
|
|
78235
|
+
if (staleRanks.has(rank)) {
|
|
78236
|
+
if (staleFrom === -1) {
|
|
78237
|
+
staleFrom = rank;
|
|
78238
|
+
}
|
|
78239
|
+
staleTo = rank;
|
|
78240
|
+
}
|
|
78241
|
+
rank++;
|
|
78242
|
+
}
|
|
78243
|
+
}
|
|
78244
|
+
const revalidating = staleFrom !== -1;
|
|
78190
78245
|
// The list is held on an item nothing on screen leads to: the items it holds
|
|
78191
78246
|
// do not contain it, so no window it could draw will ever bring it. Only
|
|
78192
78247
|
// asking for it by name does.
|
|
@@ -78203,18 +78258,36 @@ const useItemStore = ({
|
|
|
78203
78258
|
start = from < 0 ? 0 : from;
|
|
78204
78259
|
end = start + budget - 1;
|
|
78205
78260
|
} else if (revalidating) {
|
|
78206
|
-
|
|
78207
|
-
|
|
78208
|
-
if (
|
|
78209
|
-
|
|
78210
|
-
|
|
78211
|
-
|
|
78212
|
-
|
|
78213
|
-
|
|
78214
|
-
|
|
78215
|
-
|
|
78216
|
-
|
|
78217
|
-
|
|
78261
|
+
// The items from before that the window draws, and the missing ones
|
|
78262
|
+
// with them: one ask.
|
|
78263
|
+
if (start === -1 || staleFrom < start) {
|
|
78264
|
+
start = staleFrom;
|
|
78265
|
+
}
|
|
78266
|
+
if (staleTo > end) {
|
|
78267
|
+
end = staleTo;
|
|
78268
|
+
}
|
|
78269
|
+
// Grown over the items from before on either side, up to a page: the
|
|
78270
|
+
// window grows past its first picture right after it is painted, and
|
|
78271
|
+
// what it grows onto would otherwise be asked for once more.
|
|
78272
|
+
while (end - start + 1 < budget) {
|
|
78273
|
+
const staleBefore = staleRanks.has(start - 1);
|
|
78274
|
+
const staleAfter = staleRanks.has(end + 1);
|
|
78275
|
+
if (!staleBefore && !staleAfter) {
|
|
78276
|
+
break;
|
|
78277
|
+
}
|
|
78278
|
+
if (staleBefore) {
|
|
78279
|
+
start--;
|
|
78280
|
+
}
|
|
78281
|
+
if (staleAfter && end - start + 1 < budget) {
|
|
78282
|
+
end++;
|
|
78283
|
+
}
|
|
78284
|
+
}
|
|
78285
|
+
// Anchored on the first item from before on screen: a source
|
|
78286
|
+
// paginating by cursor gets an item to count from, and the reading
|
|
78287
|
+
// position is what must survive.
|
|
78288
|
+
const firstStale = pages.byIndex.get(staleFrom);
|
|
78289
|
+
if (firstStale && firstStale.id !== undefined) {
|
|
78290
|
+
around = firstStale.id;
|
|
78218
78291
|
}
|
|
78219
78292
|
} else if (pages.count === undefined) {
|
|
78220
78293
|
const scrolled = listItems.scrolled;
|
|
@@ -78268,7 +78341,8 @@ const useItemStore = ({
|
|
|
78268
78341
|
debugAsk("already revalidating");
|
|
78269
78342
|
return;
|
|
78270
78343
|
}
|
|
78271
|
-
// A page for
|
|
78344
|
+
// A page asked for before the items went stale answers for the
|
|
78345
|
+
// collection as it was.
|
|
78272
78346
|
request.controller?.abort();
|
|
78273
78347
|
request.busy = false;
|
|
78274
78348
|
}
|
|
@@ -78289,11 +78363,11 @@ const useItemStore = ({
|
|
|
78289
78363
|
request.controller?.abort();
|
|
78290
78364
|
request.busy = false;
|
|
78291
78365
|
}
|
|
78292
|
-
const held = pages.byIndex.size;
|
|
78293
78366
|
// Asking again for a range that was already asked for, having received
|
|
78294
|
-
// nothing since, can only produce the same answer
|
|
78295
|
-
//
|
|
78296
|
-
|
|
78367
|
+
// nothing since, can only produce the same answer — unless the
|
|
78368
|
+
// collection moved since, which is what an invalidation says.
|
|
78369
|
+
const held = `${pages.byIndex.size}/${staleRanks.size}/${invalidation}`;
|
|
78370
|
+
if (request.start === start && request.end === end && request.held === held) {
|
|
78297
78371
|
debugAsk("this range was asked for already");
|
|
78298
78372
|
return;
|
|
78299
78373
|
}
|
|
@@ -78329,7 +78403,6 @@ const useItemStore = ({
|
|
|
78329
78403
|
request.revalidating = false;
|
|
78330
78404
|
setFailure(null);
|
|
78331
78405
|
if (revalidating) {
|
|
78332
|
-
staleRef.current = false;
|
|
78333
78406
|
setRefreshing(false);
|
|
78334
78407
|
}
|
|
78335
78408
|
publishRequestState();
|
|
@@ -78348,15 +78421,35 @@ const useItemStore = ({
|
|
|
78348
78421
|
// Before the items land: what is on screen has to stay where it is,
|
|
78349
78422
|
// and the DOM still shows the state to hold onto.
|
|
78350
78423
|
listItems.captureAnchor();
|
|
78351
|
-
|
|
78352
|
-
|
|
78353
|
-
|
|
78354
|
-
|
|
78355
|
-
|
|
78424
|
+
// An item from before is gone from where it stood when the page puts
|
|
78425
|
+
// it at another rank (it would be drawn twice), or when its rank is
|
|
78426
|
+
// past the end of the collection.
|
|
78427
|
+
const staleRanksNow = staleRanksRef.current;
|
|
78428
|
+
const pageEnd = pageStart + pageItems.length;
|
|
78429
|
+
let dropped = false;
|
|
78430
|
+
if (staleRanksNow.size > 0) {
|
|
78431
|
+
const pageIds = new Set();
|
|
78432
|
+
for (const pageItem of pageItems) {
|
|
78433
|
+
if (pageItem && pageItem.id !== undefined) {
|
|
78434
|
+
pageIds.add(pageItem.id);
|
|
78435
|
+
}
|
|
78436
|
+
}
|
|
78437
|
+
for (const rank of staleRanksNow) {
|
|
78438
|
+
if (rank >= pageStart && rank < pageEnd) {
|
|
78439
|
+
continue;
|
|
78440
|
+
}
|
|
78441
|
+
const staleItem = pages.byIndex.get(rank);
|
|
78442
|
+
if (rank >= pageCount || staleItem && pageIds.has(staleItem.id)) {
|
|
78443
|
+
staleRanksNow.delete(rank);
|
|
78444
|
+
pages.byIndex.delete(rank);
|
|
78445
|
+
dropped = true;
|
|
78446
|
+
}
|
|
78447
|
+
}
|
|
78356
78448
|
}
|
|
78357
78449
|
let i = 0;
|
|
78358
78450
|
while (i < pageItems.length) {
|
|
78359
78451
|
pages.byIndex.set(pageStart + i, pageItems[i]);
|
|
78452
|
+
staleRanksNow.delete(pageStart + i);
|
|
78360
78453
|
i++;
|
|
78361
78454
|
}
|
|
78362
78455
|
pages.count = pageCount;
|
|
@@ -78366,7 +78459,7 @@ const useItemStore = ({
|
|
|
78366
78459
|
itemsAction.writeComposition({
|
|
78367
78460
|
byIndex: pages.byIndex,
|
|
78368
78461
|
count: pageCount,
|
|
78369
|
-
replace:
|
|
78462
|
+
replace: dropped
|
|
78370
78463
|
});
|
|
78371
78464
|
}
|
|
78372
78465
|
listItems.pagesSignal.value = listItems.pagesSignal.peek() + 1;
|
|
@@ -78381,9 +78474,14 @@ const useItemStore = ({
|
|
|
78381
78474
|
request.revalidating = false;
|
|
78382
78475
|
publishRequestState();
|
|
78383
78476
|
if (revalidating) {
|
|
78384
|
-
// The items from before stay
|
|
78477
|
+
// The items from before stay, and are not asked for again until the
|
|
78478
|
+
// source says the collection moved: a revalidation that failed has
|
|
78385
78479
|
// nothing better to put in their place.
|
|
78386
|
-
|
|
78480
|
+
let rank = start;
|
|
78481
|
+
while (rank <= end) {
|
|
78482
|
+
staleRanksRef.current.delete(rank);
|
|
78483
|
+
rank++;
|
|
78484
|
+
}
|
|
78387
78485
|
setRefreshing(false);
|
|
78388
78486
|
return;
|
|
78389
78487
|
}
|