@jsenv/navi 0.29.57 → 0.29.59
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/jsenv_navi.js +104 -6
- package/dist/jsenv_navi.js.map +12 -5
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -56347,6 +56347,11 @@ const useListScrollSync = ({
|
|
|
56347
56347
|
virtual.holdPending = scrolledWanted !== "start" && scrolledWanted !== undefined;
|
|
56348
56348
|
const total = virtual.totalSignal.peek();
|
|
56349
56349
|
if (total <= renderBudget) {
|
|
56350
|
+
// The whole collection is what the list draws: wherever in it the list is
|
|
56351
|
+
// held, the window is already its place. Nowhere to move to means nothing
|
|
56352
|
+
// to wait for — a hold left standing here is a list that never asks for
|
|
56353
|
+
// anything again.
|
|
56354
|
+
virtual.holdPending = false;
|
|
56350
56355
|
return;
|
|
56351
56356
|
}
|
|
56352
56357
|
const half = Math.floor(renderBudget / 2);
|
|
@@ -56367,6 +56372,9 @@ const useListScrollSync = ({
|
|
|
56367
56372
|
}
|
|
56368
56373
|
}
|
|
56369
56374
|
if (wantedStart === null) {
|
|
56375
|
+
// Held on a row nobody can place yet: the window frames the start, which
|
|
56376
|
+
// is not where the list is going. The hold stands until the row comes
|
|
56377
|
+
// back — the run asks for it by name (see useRequestMissing).
|
|
56370
56378
|
return;
|
|
56371
56379
|
}
|
|
56372
56380
|
if (wantedStart < 0) {
|
|
@@ -58451,6 +58459,7 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
58451
58459
|
* memoryBudget?: number,
|
|
58452
58460
|
* renderSkeleton?: false | ((index: number) => import("ignore:preact").ComponentChildren),
|
|
58453
58461
|
* renderError?: (failure: {error: any, retry: () => void, start: number, end: number}) => import("ignore:preact").ComponentChildren,
|
|
58462
|
+
* onRequestStateChange?: (state: {busy: boolean, refreshing: boolean, range: {start: number, end: number}|null}) => void,
|
|
58454
58463
|
* }>}
|
|
58455
58464
|
* @param {(item: any, index: number, state: {refreshing: boolean}) => any} props.renderItem
|
|
58456
58465
|
* What one row is, given the item and where it sits. `state.refreshing` says
|
|
@@ -58488,6 +58497,14 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
58488
58497
|
* a `retry` to call, and the `start`/`end` of the range that failed. Defaults
|
|
58489
58498
|
* to an inline message with a retry button, drawn on the row the user is
|
|
58490
58499
|
* looking at.
|
|
58500
|
+
* @param {(state: {busy: boolean, refreshing: boolean, range: {start: number, end: number}|null}) => void} [props.onRequestStateChange]
|
|
58501
|
+
* Called when the run starts or stops asking for rows — for the screen around
|
|
58502
|
+
* the list to say that it is looking (the rows themselves have skeletons and
|
|
58503
|
+
* `refreshing` already). `busy` covers every ask, first slice and holes
|
|
58504
|
+
* opened by scrolling included; `refreshing` is the subset where rows already
|
|
58505
|
+
* held are being read again; `range` is what is being asked for, `null` once
|
|
58506
|
+
* nothing is. A range called off and asked again right away stays one `busy`,
|
|
58507
|
+
* and a list unmounted while asking says `busy: false` on its way out.
|
|
58491
58508
|
*/
|
|
58492
58509
|
const ListItems = ({
|
|
58493
58510
|
renderItem,
|
|
@@ -58499,7 +58516,8 @@ const ListItems = ({
|
|
|
58499
58516
|
renderGroupLabel,
|
|
58500
58517
|
groupLabelProps,
|
|
58501
58518
|
renderSkeleton,
|
|
58502
|
-
renderError
|
|
58519
|
+
renderError,
|
|
58520
|
+
onRequestStateChange
|
|
58503
58521
|
}) => {
|
|
58504
58522
|
const ownerId = useId();
|
|
58505
58523
|
const virtual = useContext(ListVirtualContext);
|
|
@@ -58508,7 +58526,8 @@ const ListItems = ({
|
|
|
58508
58526
|
const store = useItemStore({
|
|
58509
58527
|
count,
|
|
58510
58528
|
itemsAction,
|
|
58511
|
-
memoryBudget
|
|
58529
|
+
memoryBudget,
|
|
58530
|
+
onRequestStateChange
|
|
58512
58531
|
});
|
|
58513
58532
|
const renderRowSkeleton = renderSkeleton === undefined ? virtual.renderSkeleton : renderSkeleton;
|
|
58514
58533
|
// A row on its way takes the room the list reserves for it: anything else
|
|
@@ -58782,6 +58801,12 @@ const ListItemsFailure = ({
|
|
|
58782
58801
|
// hits the network again.
|
|
58783
58802
|
const ITEM_STORE_MAX_DEFAULT = 1000;
|
|
58784
58803
|
const ITEM_STORE_KEEP_AROUND = 250;
|
|
58804
|
+
const rangeIsSame = (a, b) => {
|
|
58805
|
+
if (!a || !b) {
|
|
58806
|
+
return a === b;
|
|
58807
|
+
}
|
|
58808
|
+
return a.start === b.start && a.end === b.end;
|
|
58809
|
+
};
|
|
58785
58810
|
|
|
58786
58811
|
// The rows a run has, and how it gets more. Two shapes behind one reader: the
|
|
58787
58812
|
// caller holds them (items/count/itemStart), or the run asked for them and
|
|
@@ -58791,12 +58816,17 @@ const ITEM_STORE_KEEP_AROUND = 250;
|
|
|
58791
58816
|
const useItemStore = ({
|
|
58792
58817
|
count,
|
|
58793
58818
|
itemsAction,
|
|
58794
|
-
memoryBudget
|
|
58819
|
+
memoryBudget,
|
|
58820
|
+
onRequestStateChange
|
|
58795
58821
|
}) => {
|
|
58796
58822
|
// What the source kept of the collection when the screen it was on went away
|
|
58797
58823
|
// (a range reader keeps the composition: see resource_range_reader.js). The
|
|
58798
58824
|
// rows are drawn from it right away and the window is asked for again — the
|
|
58799
58825
|
// revalidation below, entered from a fresh mount rather than from a write.
|
|
58826
|
+
// A reader is an interface, not just a function that answers a range: a list
|
|
58827
|
+
// handed something else keeps drawing rows and quietly gives up everything
|
|
58828
|
+
// the reader holds for it (see resource_range_reader.js).
|
|
58829
|
+
useRef(false);
|
|
58800
58830
|
const pagesRef = useRef(null);
|
|
58801
58831
|
let restored = false;
|
|
58802
58832
|
if (!pagesRef.current) {
|
|
@@ -58864,6 +58894,51 @@ const useItemStore = ({
|
|
|
58864
58894
|
virtual.refreshingSignal.value = virtual.refreshingSignal.peek() - 1;
|
|
58865
58895
|
};
|
|
58866
58896
|
}, [refreshing]);
|
|
58897
|
+
|
|
58898
|
+
// What the run is doing, for the screen around the list to draw: the list has
|
|
58899
|
+
// its own skeletons, what is around it has to be told. Read from the request
|
|
58900
|
+
// itself rather than pushed from each place that touches it, so a range
|
|
58901
|
+
// called off and asked again right away stays one uninterrupted ask.
|
|
58902
|
+
const requestStateRef = useRef({
|
|
58903
|
+
busy: false,
|
|
58904
|
+
refreshing: false,
|
|
58905
|
+
range: null
|
|
58906
|
+
});
|
|
58907
|
+
const onRequestStateChangeRef = useRef(onRequestStateChange);
|
|
58908
|
+
onRequestStateChangeRef.current = onRequestStateChange;
|
|
58909
|
+
const publishRequestState = () => {
|
|
58910
|
+
const request = requestRef.current;
|
|
58911
|
+
const busy = request.busy;
|
|
58912
|
+
const state = {
|
|
58913
|
+
busy,
|
|
58914
|
+
refreshing: busy && request.revalidating,
|
|
58915
|
+
range: busy ? {
|
|
58916
|
+
start: request.start,
|
|
58917
|
+
end: request.end
|
|
58918
|
+
} : null
|
|
58919
|
+
};
|
|
58920
|
+
const previous = requestStateRef.current;
|
|
58921
|
+
if (previous.busy === state.busy && previous.refreshing === state.refreshing && rangeIsSame(previous.range, state.range)) {
|
|
58922
|
+
return;
|
|
58923
|
+
}
|
|
58924
|
+
requestStateRef.current = state;
|
|
58925
|
+
if (onRequestStateChangeRef.current) {
|
|
58926
|
+
onRequestStateChangeRef.current(state);
|
|
58927
|
+
}
|
|
58928
|
+
};
|
|
58929
|
+
// A list taken off the screen while it was asking leaves nothing ringing
|
|
58930
|
+
// behind it: whoever is drawing "looking for rows" has to stop.
|
|
58931
|
+
useLayoutEffect(() => {
|
|
58932
|
+
return () => {
|
|
58933
|
+
if (requestStateRef.current.busy && onRequestStateChangeRef.current) {
|
|
58934
|
+
onRequestStateChangeRef.current({
|
|
58935
|
+
busy: false,
|
|
58936
|
+
refreshing: false,
|
|
58937
|
+
range: null
|
|
58938
|
+
});
|
|
58939
|
+
}
|
|
58940
|
+
};
|
|
58941
|
+
}, []);
|
|
58867
58942
|
const store = {
|
|
58868
58943
|
rowCount,
|
|
58869
58944
|
failure,
|
|
@@ -58917,7 +58992,22 @@ const useItemStore = ({
|
|
|
58917
58992
|
// anchored on the row at its top — a source paginating by cursor gets a
|
|
58918
58993
|
// row to count from, and the reading position is what must survive.
|
|
58919
58994
|
const revalidating = staleRef.current;
|
|
58920
|
-
|
|
58995
|
+
// The list is held on a row nothing on screen leads to: the rows it holds
|
|
58996
|
+
// do not contain it, so no window it could draw will ever bring it. Only
|
|
58997
|
+
// asking for it by name does.
|
|
58998
|
+
const wanted = virtual.scrolled;
|
|
58999
|
+
const askingAroundWantedRow = revalidating &&
|
|
59000
|
+
// Only while the hold stands: once the user has taken the list over,
|
|
59001
|
+
// the reading position is where they are, not where it opened.
|
|
59002
|
+
virtual.holdPending && wanted && typeof wanted === "object" && wanted.id !== undefined && virtual.locateRow(wanted.id) === null;
|
|
59003
|
+
if (askingAroundWantedRow) {
|
|
59004
|
+
around = wanted.id;
|
|
59005
|
+
// Where it stood when it was written down is enough to frame the ask;
|
|
59006
|
+
// the answer says where it really landed.
|
|
59007
|
+
const from = typeof wanted.index === "number" ? wanted.index - Math.floor(budget / 2) : 0;
|
|
59008
|
+
start = from < 0 ? 0 : from;
|
|
59009
|
+
end = start + budget - 1;
|
|
59010
|
+
} else if (revalidating) {
|
|
58921
59011
|
start = windowFrom;
|
|
58922
59012
|
end = windowTo - 1;
|
|
58923
59013
|
if (end < start) {
|
|
@@ -58954,11 +59044,13 @@ const useItemStore = ({
|
|
|
58954
59044
|
end = start + budget - 1;
|
|
58955
59045
|
}
|
|
58956
59046
|
}
|
|
58957
|
-
|
|
59047
|
+
const ask = () => {
|
|
58958
59048
|
if (start === -1) {
|
|
58959
59049
|
return;
|
|
58960
59050
|
}
|
|
58961
|
-
if (virtual.holdPending && pages.count !== undefined) {
|
|
59051
|
+
if (virtual.holdPending && pages.count !== undefined && !askingAroundWantedRow) {
|
|
59052
|
+
// The one ask a hold lets through: the row the list is held on is
|
|
59053
|
+
// what would lift the hold, and nothing else is going to bring it.
|
|
58962
59054
|
return;
|
|
58963
59055
|
}
|
|
58964
59056
|
const request = requestRef.current;
|
|
@@ -59027,6 +59119,7 @@ const useItemStore = ({
|
|
|
59027
59119
|
staleRef.current = false;
|
|
59028
59120
|
setRefreshing(false);
|
|
59029
59121
|
}
|
|
59122
|
+
publishRequestState();
|
|
59030
59123
|
}
|
|
59031
59124
|
if (revalidating && !current) {
|
|
59032
59125
|
// Rows of a composition already superseded by a newer ask: keeping
|
|
@@ -59073,6 +59166,7 @@ const useItemStore = ({
|
|
|
59073
59166
|
}
|
|
59074
59167
|
request.busy = false;
|
|
59075
59168
|
request.revalidating = false;
|
|
59169
|
+
publishRequestState();
|
|
59076
59170
|
if (revalidating) {
|
|
59077
59171
|
// The rows from before stay: a revalidation that failed has
|
|
59078
59172
|
// nothing better to put in their place.
|
|
@@ -59101,6 +59195,10 @@ const useItemStore = ({
|
|
|
59101
59195
|
} else {
|
|
59102
59196
|
done(result);
|
|
59103
59197
|
}
|
|
59198
|
+
};
|
|
59199
|
+
useLayoutEffect(() => {
|
|
59200
|
+
ask();
|
|
59201
|
+
publishRequestState();
|
|
59104
59202
|
});
|
|
59105
59203
|
}
|
|
59106
59204
|
};
|