@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/jsenv_navi.js
CHANGED
|
@@ -25978,10 +25978,11 @@ const createRangeReader = (
|
|
|
25978
25978
|
});
|
|
25979
25979
|
return { byIndex, count: composition.count };
|
|
25980
25980
|
};
|
|
25981
|
-
// `replace`
|
|
25982
|
-
//
|
|
25983
|
-
// so two lists reading the same
|
|
25984
|
-
// to one composition instead of
|
|
25981
|
+
// `replace` says the list dropped ranks it held (an item the collection moved
|
|
25982
|
+
// elsewhere, ranks past its end): kept here, they would come back at the next
|
|
25983
|
+
// mount. Otherwise the ranks are merged, so two lists reading the same
|
|
25984
|
+
// collection through their own windows add up to one composition instead of
|
|
25985
|
+
// taking turns erasing each other.
|
|
25985
25986
|
readRange.writeComposition = ({ byIndex, count, replace }) => {
|
|
25986
25987
|
const params = currentParams();
|
|
25987
25988
|
let composition = findComposition(params);
|
|
@@ -76192,19 +76193,57 @@ const useRunItems = (store, {
|
|
|
76192
76193
|
// rebuilt as the window slides — a group holds the items of its day that are
|
|
76193
76194
|
// currently drawn, which is exactly the span its label has to survive.
|
|
76194
76195
|
let group = null;
|
|
76196
|
+
// Two groups can still share a key (a failure band standing mid-group, data
|
|
76197
|
+
// not sorted by group): the later ones are told apart by their rank among
|
|
76198
|
+
// them, so the first keeps its element. A group keyed by where it starts
|
|
76199
|
+
// would lose its element each time the window slides past its first item.
|
|
76200
|
+
const groupCountByKey = new Map();
|
|
76195
76201
|
const closeGroup = () => {
|
|
76196
76202
|
if (!group) {
|
|
76197
76203
|
return;
|
|
76198
76204
|
}
|
|
76205
|
+
const groupCount = (groupCountByKey.get(group.key) || 0) + 1;
|
|
76206
|
+
groupCountByKey.set(group.key, groupCount);
|
|
76199
76207
|
nodes.push(jsx(ListItemGroup, {
|
|
76200
76208
|
label: group.label,
|
|
76201
76209
|
labelProps: group.labelProps,
|
|
76202
76210
|
children: group.children
|
|
76203
|
-
}, `${ownerId}_group_${group.key}`));
|
|
76211
|
+
}, groupCount === 1 ? `${ownerId}_group_${group.key}` : `${ownerId}_group_${group.key}_${groupCount}`));
|
|
76204
76212
|
group = null;
|
|
76205
76213
|
};
|
|
76214
|
+
// An item not held has no group of its own. Between two items of the open
|
|
76215
|
+
// group it is a line of that group whose content has not arrived: drawn
|
|
76216
|
+
// outside, it would cut the group in two and show its label twice. A hole at
|
|
76217
|
+
// a group's edge stays outside — nothing says which side it belongs to.
|
|
76218
|
+
let holeTo = -1;
|
|
76219
|
+
let holeGroupKey;
|
|
76220
|
+
const groupKeyOfHole = itemIndex => {
|
|
76221
|
+
if (itemIndex < holeTo) {
|
|
76222
|
+
return holeGroupKey;
|
|
76223
|
+
}
|
|
76224
|
+
holeTo = itemIndex + 1;
|
|
76225
|
+
while (holeTo < windowTo && holeTo !== failureFrom && getItemAt(holeTo) === undefined) {
|
|
76226
|
+
holeTo++;
|
|
76227
|
+
}
|
|
76228
|
+
holeGroupKey = undefined;
|
|
76229
|
+
if (group && holeTo < windowTo && holeTo !== failureFrom) {
|
|
76230
|
+
const keyAfterHole = groupBy(getItemAt(holeTo), holeTo);
|
|
76231
|
+
if (keyAfterHole === group.key) {
|
|
76232
|
+
holeGroupKey = keyAfterHole;
|
|
76233
|
+
}
|
|
76234
|
+
}
|
|
76235
|
+
return holeGroupKey;
|
|
76236
|
+
};
|
|
76206
76237
|
// Which group an item belongs to, or undefined when it belongs to none.
|
|
76207
|
-
const groupKeyOf = (item, itemIndex) =>
|
|
76238
|
+
const groupKeyOf = (item, itemIndex) => {
|
|
76239
|
+
if (!groupBy) {
|
|
76240
|
+
return undefined;
|
|
76241
|
+
}
|
|
76242
|
+
if (item === undefined) {
|
|
76243
|
+
return groupKeyOfHole(itemIndex);
|
|
76244
|
+
}
|
|
76245
|
+
return groupBy(item, itemIndex);
|
|
76246
|
+
};
|
|
76208
76247
|
const pushItem = (itemNode, item, itemIndex, groupKey) => {
|
|
76209
76248
|
if (groupKey === undefined) {
|
|
76210
76249
|
closeGroup();
|
|
@@ -76532,10 +76571,15 @@ const useItemStore = ({
|
|
|
76532
76571
|
}
|
|
76533
76572
|
const pages = pagesRef.current;
|
|
76534
76573
|
const [, setPageVersion] = useState(0);
|
|
76535
|
-
// The
|
|
76536
|
-
//
|
|
76537
|
-
//
|
|
76538
|
-
|
|
76574
|
+
// The ranks whose item is from before: the run came back to the screen, or
|
|
76575
|
+
// the source said the collection moved. They stay drawn until a page confirms
|
|
76576
|
+
// or replaces them, rank by rank. A page covers what the window framed when it
|
|
76577
|
+
// was asked for, and the window keeps growing meanwhile: dropping what the
|
|
76578
|
+
// page did not cover empties items on screen.
|
|
76579
|
+
const staleRanksRef = useRef(null);
|
|
76580
|
+
if (staleRanksRef.current === null) {
|
|
76581
|
+
staleRanksRef.current = restored ? new Set(pages.byIndex.keys()) : new Set();
|
|
76582
|
+
}
|
|
76539
76583
|
const [refreshing, setRefreshing] = useState(false);
|
|
76540
76584
|
// A source that says when what it reads has moved (a resource range reader
|
|
76541
76585
|
// does: see rerunOn.GET_RANGE) is heard here — a write deciding who belongs
|
|
@@ -76546,7 +76590,7 @@ const useItemStore = ({
|
|
|
76546
76590
|
const invalidationRef = useRef(invalidation);
|
|
76547
76591
|
if (invalidationRef.current !== invalidation) {
|
|
76548
76592
|
invalidationRef.current = invalidation;
|
|
76549
|
-
|
|
76593
|
+
staleRanksRef.current = new Set(pages.byIndex.keys());
|
|
76550
76594
|
}
|
|
76551
76595
|
// The one request in flight, with the means to call it off: a page asked for
|
|
76552
76596
|
// a window the list has left is work the server and the browser are doing for
|
|
@@ -76579,11 +76623,6 @@ const useItemStore = ({
|
|
|
76579
76623
|
// It stands for a page of them: a list that is about to be filled looks
|
|
76580
76624
|
// like items on their way, not like an empty list.
|
|
76581
76625
|
const itemCount = pages.count ?? count ?? listItems.pageSize;
|
|
76582
|
-
// A run that never received anything has nothing to keep on screen: asking
|
|
76583
|
-
// again is its first ask, not a refresh.
|
|
76584
|
-
if (staleRef.current && pages.count === undefined) {
|
|
76585
|
-
staleRef.current = false;
|
|
76586
|
-
}
|
|
76587
76626
|
useLayoutEffect(() => {
|
|
76588
76627
|
if (!refreshing) {
|
|
76589
76628
|
return null;
|
|
@@ -76656,9 +76695,11 @@ const useItemStore = ({
|
|
|
76656
76695
|
const keepFrom = windowFrom - ITEM_STORE_KEEP_AROUND;
|
|
76657
76696
|
const keepTo = windowTo + ITEM_STORE_KEEP_AROUND;
|
|
76658
76697
|
if (pages.byIndex.size > budget) {
|
|
76698
|
+
const staleRanks = staleRanksRef.current;
|
|
76659
76699
|
for (const index of pages.byIndex.keys()) {
|
|
76660
76700
|
if (index < keepFrom || index > keepTo) {
|
|
76661
76701
|
pages.byIndex.delete(index);
|
|
76702
|
+
staleRanks.delete(index);
|
|
76662
76703
|
}
|
|
76663
76704
|
}
|
|
76664
76705
|
}
|
|
@@ -76693,10 +76734,24 @@ const useItemStore = ({
|
|
|
76693
76734
|
let start = missingStart;
|
|
76694
76735
|
let end = missingEnd;
|
|
76695
76736
|
let around;
|
|
76696
|
-
//
|
|
76697
|
-
//
|
|
76698
|
-
|
|
76699
|
-
|
|
76737
|
+
// The window draws items from before: they are asked for again, and stay
|
|
76738
|
+
// drawn meanwhile.
|
|
76739
|
+
const staleRanks = staleRanksRef.current;
|
|
76740
|
+
let staleFrom = -1;
|
|
76741
|
+
let staleTo = -1;
|
|
76742
|
+
if (staleRanks.size > 0) {
|
|
76743
|
+
let rank = windowFrom;
|
|
76744
|
+
while (rank < windowTo) {
|
|
76745
|
+
if (staleRanks.has(rank)) {
|
|
76746
|
+
if (staleFrom === -1) {
|
|
76747
|
+
staleFrom = rank;
|
|
76748
|
+
}
|
|
76749
|
+
staleTo = rank;
|
|
76750
|
+
}
|
|
76751
|
+
rank++;
|
|
76752
|
+
}
|
|
76753
|
+
}
|
|
76754
|
+
const revalidating = staleFrom !== -1;
|
|
76700
76755
|
// The list is held on an item nothing on screen leads to: the items it holds
|
|
76701
76756
|
// do not contain it, so no window it could draw will ever bring it. Only
|
|
76702
76757
|
// asking for it by name does.
|
|
@@ -76713,18 +76768,36 @@ const useItemStore = ({
|
|
|
76713
76768
|
start = from < 0 ? 0 : from;
|
|
76714
76769
|
end = start + budget - 1;
|
|
76715
76770
|
} else if (revalidating) {
|
|
76716
|
-
|
|
76717
|
-
|
|
76718
|
-
if (
|
|
76719
|
-
|
|
76720
|
-
|
|
76721
|
-
|
|
76722
|
-
|
|
76723
|
-
|
|
76724
|
-
|
|
76725
|
-
|
|
76726
|
-
|
|
76727
|
-
|
|
76771
|
+
// The items from before that the window draws, and the missing ones
|
|
76772
|
+
// with them: one ask.
|
|
76773
|
+
if (start === -1 || staleFrom < start) {
|
|
76774
|
+
start = staleFrom;
|
|
76775
|
+
}
|
|
76776
|
+
if (staleTo > end) {
|
|
76777
|
+
end = staleTo;
|
|
76778
|
+
}
|
|
76779
|
+
// Grown over the items from before on either side, up to a page: the
|
|
76780
|
+
// window grows past its first picture right after it is painted, and
|
|
76781
|
+
// what it grows onto would otherwise be asked for once more.
|
|
76782
|
+
while (end - start + 1 < budget) {
|
|
76783
|
+
const staleBefore = staleRanks.has(start - 1);
|
|
76784
|
+
const staleAfter = staleRanks.has(end + 1);
|
|
76785
|
+
if (!staleBefore && !staleAfter) {
|
|
76786
|
+
break;
|
|
76787
|
+
}
|
|
76788
|
+
if (staleBefore) {
|
|
76789
|
+
start--;
|
|
76790
|
+
}
|
|
76791
|
+
if (staleAfter && end - start + 1 < budget) {
|
|
76792
|
+
end++;
|
|
76793
|
+
}
|
|
76794
|
+
}
|
|
76795
|
+
// Anchored on the first item from before on screen: a source
|
|
76796
|
+
// paginating by cursor gets an item to count from, and the reading
|
|
76797
|
+
// position is what must survive.
|
|
76798
|
+
const firstStale = pages.byIndex.get(staleFrom);
|
|
76799
|
+
if (firstStale && firstStale.id !== undefined) {
|
|
76800
|
+
around = firstStale.id;
|
|
76728
76801
|
}
|
|
76729
76802
|
} else if (pages.count === undefined) {
|
|
76730
76803
|
const scrolled = listItems.scrolled;
|
|
@@ -76778,7 +76851,8 @@ const useItemStore = ({
|
|
|
76778
76851
|
debugAsk("already revalidating");
|
|
76779
76852
|
return;
|
|
76780
76853
|
}
|
|
76781
|
-
// A page for
|
|
76854
|
+
// A page asked for before the items went stale answers for the
|
|
76855
|
+
// collection as it was.
|
|
76782
76856
|
request.controller?.abort();
|
|
76783
76857
|
request.busy = false;
|
|
76784
76858
|
}
|
|
@@ -76799,11 +76873,11 @@ const useItemStore = ({
|
|
|
76799
76873
|
request.controller?.abort();
|
|
76800
76874
|
request.busy = false;
|
|
76801
76875
|
}
|
|
76802
|
-
const held = pages.byIndex.size;
|
|
76803
76876
|
// Asking again for a range that was already asked for, having received
|
|
76804
|
-
// nothing since, can only produce the same answer
|
|
76805
|
-
//
|
|
76806
|
-
|
|
76877
|
+
// nothing since, can only produce the same answer — unless the
|
|
76878
|
+
// collection moved since, which is what an invalidation says.
|
|
76879
|
+
const held = `${pages.byIndex.size}/${staleRanks.size}/${invalidation}`;
|
|
76880
|
+
if (request.start === start && request.end === end && request.held === held) {
|
|
76807
76881
|
debugAsk("this range was asked for already");
|
|
76808
76882
|
return;
|
|
76809
76883
|
}
|
|
@@ -76839,7 +76913,6 @@ const useItemStore = ({
|
|
|
76839
76913
|
request.revalidating = false;
|
|
76840
76914
|
setFailure(null);
|
|
76841
76915
|
if (revalidating) {
|
|
76842
|
-
staleRef.current = false;
|
|
76843
76916
|
setRefreshing(false);
|
|
76844
76917
|
}
|
|
76845
76918
|
publishRequestState();
|
|
@@ -76858,15 +76931,35 @@ const useItemStore = ({
|
|
|
76858
76931
|
// Before the items land: what is on screen has to stay where it is,
|
|
76859
76932
|
// and the DOM still shows the state to hold onto.
|
|
76860
76933
|
listItems.captureAnchor();
|
|
76861
|
-
|
|
76862
|
-
|
|
76863
|
-
|
|
76864
|
-
|
|
76865
|
-
|
|
76934
|
+
// An item from before is gone from where it stood when the page puts
|
|
76935
|
+
// it at another rank (it would be drawn twice), or when its rank is
|
|
76936
|
+
// past the end of the collection.
|
|
76937
|
+
const staleRanksNow = staleRanksRef.current;
|
|
76938
|
+
const pageEnd = pageStart + pageItems.length;
|
|
76939
|
+
let dropped = false;
|
|
76940
|
+
if (staleRanksNow.size > 0) {
|
|
76941
|
+
const pageIds = new Set();
|
|
76942
|
+
for (const pageItem of pageItems) {
|
|
76943
|
+
if (pageItem && pageItem.id !== undefined) {
|
|
76944
|
+
pageIds.add(pageItem.id);
|
|
76945
|
+
}
|
|
76946
|
+
}
|
|
76947
|
+
for (const rank of staleRanksNow) {
|
|
76948
|
+
if (rank >= pageStart && rank < pageEnd) {
|
|
76949
|
+
continue;
|
|
76950
|
+
}
|
|
76951
|
+
const staleItem = pages.byIndex.get(rank);
|
|
76952
|
+
if (rank >= pageCount || staleItem && pageIds.has(staleItem.id)) {
|
|
76953
|
+
staleRanksNow.delete(rank);
|
|
76954
|
+
pages.byIndex.delete(rank);
|
|
76955
|
+
dropped = true;
|
|
76956
|
+
}
|
|
76957
|
+
}
|
|
76866
76958
|
}
|
|
76867
76959
|
let i = 0;
|
|
76868
76960
|
while (i < pageItems.length) {
|
|
76869
76961
|
pages.byIndex.set(pageStart + i, pageItems[i]);
|
|
76962
|
+
staleRanksNow.delete(pageStart + i);
|
|
76870
76963
|
i++;
|
|
76871
76964
|
}
|
|
76872
76965
|
pages.count = pageCount;
|
|
@@ -76876,7 +76969,7 @@ const useItemStore = ({
|
|
|
76876
76969
|
itemsAction.writeComposition({
|
|
76877
76970
|
byIndex: pages.byIndex,
|
|
76878
76971
|
count: pageCount,
|
|
76879
|
-
replace:
|
|
76972
|
+
replace: dropped
|
|
76880
76973
|
});
|
|
76881
76974
|
}
|
|
76882
76975
|
listItems.pagesSignal.value = listItems.pagesSignal.peek() + 1;
|
|
@@ -76891,9 +76984,14 @@ const useItemStore = ({
|
|
|
76891
76984
|
request.revalidating = false;
|
|
76892
76985
|
publishRequestState();
|
|
76893
76986
|
if (revalidating) {
|
|
76894
|
-
// The items from before stay
|
|
76987
|
+
// The items from before stay, and are not asked for again until the
|
|
76988
|
+
// source says the collection moved: a revalidation that failed has
|
|
76895
76989
|
// nothing better to put in their place.
|
|
76896
|
-
|
|
76990
|
+
let rank = start;
|
|
76991
|
+
while (rank <= end) {
|
|
76992
|
+
staleRanksRef.current.delete(rank);
|
|
76993
|
+
rank++;
|
|
76994
|
+
}
|
|
76897
76995
|
setRefreshing(false);
|
|
76898
76996
|
return;
|
|
76899
76997
|
}
|