@jsenv/navi 0.29.446 → 0.29.448
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 +248 -32
- package/dist/dev/jsenv_navi.js.map +3 -3
- package/dist/jsenv_navi.js +228 -28
- package/dist/jsenv_navi.js.map +3 -3
- package/docs/AI_INSTRUCTIONS.md +6 -3
- package/docs/resource.md +38 -7
- package/docs/scroll.md +45 -3
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -73595,6 +73595,7 @@ const css$x = /* css */`@property --list-group-label-height {
|
|
|
73595
73595
|
}
|
|
73596
73596
|
|
|
73597
73597
|
.navi_list {
|
|
73598
|
+
--x-list-item-between: 0px;
|
|
73598
73599
|
box-sizing: border-box;
|
|
73599
73600
|
outline: none;
|
|
73600
73601
|
margin: 0;
|
|
@@ -74568,6 +74569,32 @@ const useListScrollSync = ({
|
|
|
74568
74569
|
}
|
|
74569
74570
|
});
|
|
74570
74571
|
|
|
74572
|
+
// What stands between two items along the axis — the gap, a separator and
|
|
74573
|
+
// the gaps around it — which an item on its way takes out of the room it is
|
|
74574
|
+
// given (see getSkeletonItem): virtualItemSize is an item's room, from the
|
|
74575
|
+
// end of the item before to its own end, and a skeleton whose box took all
|
|
74576
|
+
// of it would be taller than the item replacing it, moving everything below
|
|
74577
|
+
// by the difference. Read before the anchoring of this commit runs, and
|
|
74578
|
+
// written to the list's own box so the skeletons follow without rendering.
|
|
74579
|
+
// Items side by side in a grid share a line: none stands between them.
|
|
74580
|
+
useLayoutEffect(() => {
|
|
74581
|
+
if (columns || !ref.current || !listItems.hasRuns()) {
|
|
74582
|
+
return;
|
|
74583
|
+
}
|
|
74584
|
+
const listEl = getListEl();
|
|
74585
|
+
if (!listEl) {
|
|
74586
|
+
return;
|
|
74587
|
+
}
|
|
74588
|
+
const spaceBetween = readSpaceBetweenItems(listEl, horizontal);
|
|
74589
|
+
if (spaceBetween === null) {
|
|
74590
|
+
return;
|
|
74591
|
+
}
|
|
74592
|
+
const value = `${spaceBetween}px`;
|
|
74593
|
+
if (listEl.style.getPropertyValue("--x-list-item-between") !== value) {
|
|
74594
|
+
listEl.style.setProperty("--x-list-item-between", value);
|
|
74595
|
+
}
|
|
74596
|
+
});
|
|
74597
|
+
|
|
74571
74598
|
// What the window holds goes through three stages (see settleWindow):
|
|
74572
74599
|
// - "first": the first commit, a count of items since nothing is laid out
|
|
74573
74600
|
// yet to measure a size with — `initial` or the budget when they are one,
|
|
@@ -76011,14 +76038,16 @@ const canScrollerScroll = (scrollerEl, axis) => {
|
|
|
76011
76038
|
return scrollSize - clientSize > 1;
|
|
76012
76039
|
};
|
|
76013
76040
|
// What a sticky part of the list sticks to is the nearest scroll container in
|
|
76014
|
-
// the DOM; `scroller` has no say in it. A list
|
|
76015
|
-
// therefore have its group labels and its header stuck to a wrapper
|
|
76016
|
-
//
|
|
76017
|
-
//
|
|
76018
|
-
//
|
|
76019
|
-
//
|
|
76041
|
+
// the DOM; `scroller` has no say in it. A list scrolled by a box around it can
|
|
76042
|
+
// therefore have its group labels and its header stuck to a wrapper between
|
|
76043
|
+
// the two that never scrolls along that axis — and pushed down by that
|
|
76044
|
+
// wrapper's scroll-padding on top of it. The usual culprit is a wrapper
|
|
76045
|
+
// carrying `overflow-x: auto`: to keep the document from overflowing
|
|
76046
|
+
// horizontally on mobile, where `overflow-x: clip` keeps that guarantee without
|
|
76047
|
+
// making a scroll container, or to let a wide table scroll sideways, where the
|
|
76048
|
+
// header cannot stick to both boxes.
|
|
76020
76049
|
const STICKY_LIST_PART_SELECTOR = `.navi_list_item_header, .navi_list_item_footer, .navi_list_item_group_label`;
|
|
76021
|
-
const useStickyScrollportWarning = (ref, scroller) => {
|
|
76050
|
+
const useStickyScrollportWarning = (ref, scroller, getScroller, horizontal) => {
|
|
76022
76051
|
useRef(false);
|
|
76023
76052
|
useLayoutEffect(() => {
|
|
76024
76053
|
{
|
|
@@ -76492,6 +76521,32 @@ const findItemsFrom = (listEl, from, horizontal) => {
|
|
|
76492
76521
|
// items (a card holding a list of its own): both carry the same attributes.
|
|
76493
76522
|
// Groups nest the items in a list of their own class, not in another list.
|
|
76494
76523
|
const isOwnItem = (itemEl, listEl) => itemEl.closest(".navi_list") === listEl;
|
|
76524
|
+
// From where an item ends to where the item after it starts, read on the first
|
|
76525
|
+
// two that follow each other in the same container (a group's label stands
|
|
76526
|
+
// between two items of different groups). Null when no two items do.
|
|
76527
|
+
const readSpaceBetweenItems = (listEl, horizontal) => {
|
|
76528
|
+
let previous = null;
|
|
76529
|
+
for (const itemEl of listEl.querySelectorAll(`[${LIST_ITEM_INDEX_ATTRIBUTE}]`)) {
|
|
76530
|
+
if (!isOwnItem(itemEl, listEl)) {
|
|
76531
|
+
continue;
|
|
76532
|
+
}
|
|
76533
|
+
const rect = itemEl.getBoundingClientRect();
|
|
76534
|
+
if (rect.width === 0 && rect.height === 0) {
|
|
76535
|
+
previous = null;
|
|
76536
|
+
continue;
|
|
76537
|
+
}
|
|
76538
|
+
const index = Number(itemEl.getAttribute(LIST_ITEM_INDEX_ATTRIBUTE));
|
|
76539
|
+
if (previous && previous.index === index - 1 && previous.containerEl === itemEl.parentElement) {
|
|
76540
|
+
return (horizontal ? rect.left : rect.top) - previous.to;
|
|
76541
|
+
}
|
|
76542
|
+
previous = {
|
|
76543
|
+
index,
|
|
76544
|
+
containerEl: itemEl.parentElement,
|
|
76545
|
+
to: horizontal ? rect.right : rect.bottom
|
|
76546
|
+
};
|
|
76547
|
+
}
|
|
76548
|
+
return null;
|
|
76549
|
+
};
|
|
76495
76550
|
// The item drawn at an index of the list, a stand-in or a real one.
|
|
76496
76551
|
const findItemElementAt = (listEl, index) => {
|
|
76497
76552
|
for (const itemEl of listEl.querySelectorAll(`[${LIST_ITEM_INDEX_ATTRIBUTE}="${index}"]`)) {
|
|
@@ -76607,7 +76662,10 @@ const readItemRooms = (listEl, horizontal, onRoom) => {
|
|
|
76607
76662
|
// Where what stands before an item in the list ends: the element before the
|
|
76608
76663
|
// item, or before its group when it is the first of it — or the start of the
|
|
76609
76664
|
// list's content when nothing does. Null when the element before is not laid
|
|
76610
|
-
// out.
|
|
76665
|
+
// out. It is where that element ends in the flow: where the item (or its
|
|
76666
|
+
// group) starts, less the gap and the margins between the two. Its own box is
|
|
76667
|
+
// where it is painted, which a sticky header stuck to the top of the screen
|
|
76668
|
+
// puts thousands of pixels away from its place in the list.
|
|
76611
76669
|
const readEndBefore = (itemEl, listEl, horizontal) => {
|
|
76612
76670
|
let slotEl = itemEl;
|
|
76613
76671
|
const groupListEl = itemEl.parentElement;
|
|
@@ -76616,11 +76674,20 @@ const readEndBefore = (itemEl, listEl, horizontal) => {
|
|
|
76616
76674
|
}
|
|
76617
76675
|
const beforeEl = slotEl.previousElementSibling;
|
|
76618
76676
|
if (beforeEl) {
|
|
76619
|
-
const
|
|
76620
|
-
if (
|
|
76677
|
+
const beforeRect = beforeEl.getBoundingClientRect();
|
|
76678
|
+
if (beforeRect.width === 0 && beforeRect.height === 0) {
|
|
76621
76679
|
return null;
|
|
76622
76680
|
}
|
|
76623
|
-
|
|
76681
|
+
const slotRect = slotEl.getBoundingClientRect();
|
|
76682
|
+
const containerStyle = window.getComputedStyle(slotEl.parentElement);
|
|
76683
|
+
const slotStyle = window.getComputedStyle(slotEl);
|
|
76684
|
+
const beforeStyle = window.getComputedStyle(beforeEl);
|
|
76685
|
+
// A gap the browser computes as "normal" is none in a flex or grid list.
|
|
76686
|
+
const lengthOf = value => parseFloat(value) || 0;
|
|
76687
|
+
if (horizontal) {
|
|
76688
|
+
return slotRect.left - lengthOf(containerStyle.columnGap) - lengthOf(slotStyle.marginLeft) - lengthOf(beforeStyle.marginRight);
|
|
76689
|
+
}
|
|
76690
|
+
return slotRect.top - lengthOf(containerStyle.rowGap) - lengthOf(slotStyle.marginTop) - lengthOf(beforeStyle.marginBottom);
|
|
76624
76691
|
}
|
|
76625
76692
|
if (slotEl.parentElement !== listEl) {
|
|
76626
76693
|
return null;
|
|
@@ -77947,10 +78014,12 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
77947
78014
|
* A collection read a slice at a time comes from `itemsAction(range)`: the run
|
|
77948
78015
|
* asks for what it is about to draw and keeps what it gets. The range says the
|
|
77949
78016
|
* same thing three ways, so a source can read it however it paginates —
|
|
77950
|
-
* `{ start, end }` (places in the collection,
|
|
77951
|
-
*
|
|
77952
|
-
*
|
|
77953
|
-
*
|
|
78017
|
+
* `{ start, end }` (places in the collection, `end` included as in
|
|
78018
|
+
* `Range: items=0-99`; a negative `start` counting back from the end like
|
|
78019
|
+
* `Range: items=-25`, which is what a list opening on its last items asks for
|
|
78020
|
+
* before it knows how many there are), `limit` (how many items:
|
|
78021
|
+
* `end - start + 1` — an API whose end is excluded is called with
|
|
78022
|
+
* `start + limit`), and
|
|
77954
78023
|
* `before`/`after`/`around` (the id of an item to count from, for a source
|
|
77955
78024
|
* paginating by cursor). Answer with the items (an array — that is all of
|
|
77956
78025
|
* them), or with a range the way a Content-Range does: `{ items, start, count }`
|
|
@@ -77965,10 +78034,11 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
77965
78034
|
* (see docs/resource.md).
|
|
77966
78035
|
*
|
|
77967
78036
|
* A collection that changes as a whole (a search reordering it) is a different
|
|
77968
|
-
* collection
|
|
77969
|
-
*
|
|
77970
|
-
*
|
|
77971
|
-
*
|
|
78037
|
+
* collection, and the run draws it from its first item: with `items`, another
|
|
78038
|
+
* array is another collection; with `itemsAction`, another reader is — a
|
|
78039
|
+
* reader bound to other params (`bindParams({ q })` with another `q`). A param
|
|
78040
|
+
* held in a signal changes what the reader reads without changing the reader:
|
|
78041
|
+
* give the run a `key` that follows it.
|
|
77972
78042
|
*
|
|
77973
78043
|
* An item says what it is where it is drawn: `renderItem` returns a
|
|
77974
78044
|
* `<List.Item>` carrying its own props (`selectable`, `value`, `selected`…),
|
|
@@ -77983,6 +78053,7 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
77983
78053
|
* findText?: (item: any, index: number) => string,
|
|
77984
78054
|
* items?: any[],
|
|
77985
78055
|
* itemsAction?: (range: {start: number, end: number, limit: number, before?: string, after?: string, around?: string, count?: number, signal: AbortSignal}) => any,
|
|
78056
|
+
* debounce?: number,
|
|
77986
78057
|
* count?: number,
|
|
77987
78058
|
* groupBy?: (item: any, index: number) => any,
|
|
77988
78059
|
* renderGroupLabel?: (item: any, index: number) => import("ignore:preact").ComponentChildren,
|
|
@@ -77993,6 +78064,7 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
77993
78064
|
* itemSize?: (index: number) => number,
|
|
77994
78065
|
* renderError?: (failure: {error: any, retry: () => void, start: number, end: number}) => import("ignore:preact").ComponentChildren,
|
|
77995
78066
|
* onRequestStateChange?: (state: {busy: boolean, refreshing: boolean, range: {start: number, end: number}|null}) => void,
|
|
78067
|
+
* onCountChange?: (count: number|undefined) => void,
|
|
77996
78068
|
* }>}
|
|
77997
78069
|
* @param {(item: any, index: number, state: {refreshing: boolean}) => any} props.renderItem
|
|
77998
78070
|
* What is drawn for one item, given its data and where it sits — its place in the list,
|
|
@@ -78017,6 +78089,12 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
78017
78089
|
* @param {(range: object) => any} [props.itemsAction]
|
|
78018
78090
|
* Where the items come from when the collection is read a slice at a time:
|
|
78019
78091
|
* a resource's range reader (`RESOURCE.GET_RANGE.bindParams(...)`).
|
|
78092
|
+
* @param {number} [props.debounce]
|
|
78093
|
+
* Milliseconds the reader must hold still before the run draws the
|
|
78094
|
+
* collection it reads: params following a field as the user types
|
|
78095
|
+
* (`bindParams({ q })`) ask once typing stops, not once per key. Meanwhile
|
|
78096
|
+
* the run keeps drawing the collection from before, `refreshing`. The
|
|
78097
|
+
* first collection is drawn at once.
|
|
78020
78098
|
* @param {(item: any, index: number) => any} [props.groupBy]
|
|
78021
78099
|
* What tells items that belong together apart from the others — the day of a
|
|
78022
78100
|
* message, the month of a game. Consecutive items sharing it are wrapped in a
|
|
@@ -78080,24 +78158,101 @@ const VISIBILITY_HIDDEN_STYLE = {
|
|
|
78080
78158
|
* collection's own ranks as `itemsAction` sees them, `null` once nothing is.
|
|
78081
78159
|
* A range called off and asked again right away stays one `busy`, and a list
|
|
78082
78160
|
* unmounted while asking says `busy: false` on its way out.
|
|
78161
|
+
* @param {(count: number|undefined) => void} [props.onCountChange]
|
|
78162
|
+
* Called with how many items the collection holds when that changes — for
|
|
78163
|
+
* the screen around the list to say it ("5 of 83 books"): the `count` the
|
|
78164
|
+
* source answers with each slice, or the one given to the run.
|
|
78165
|
+
* `undefined` until it is known; a run drawing another collection says it
|
|
78166
|
+
* again, so the number always belongs to the collection on screen.
|
|
78083
78167
|
*/
|
|
78084
78168
|
const ListItems = ({
|
|
78169
|
+
itemsAction,
|
|
78170
|
+
debounce,
|
|
78171
|
+
...props
|
|
78172
|
+
}) => {
|
|
78173
|
+
// Read so that this component renders in the pass of the List moving its
|
|
78174
|
+
// window, and the run with it: the List frames its window on the items its
|
|
78175
|
+
// runs drew in that same commit (see settleWindow). Skipped as an unchanged
|
|
78176
|
+
// child, it would leave the run to a render of its own, after that commit.
|
|
78177
|
+
useContext(RenderWindowContext);
|
|
78178
|
+
const {
|
|
78179
|
+
reader,
|
|
78180
|
+
settling
|
|
78181
|
+
} = useSettledReader(itemsAction, debounce);
|
|
78182
|
+
return jsx(ListItemsRun
|
|
78183
|
+
// Another reader is another collection — bindParams gives back the
|
|
78184
|
+
// reader it made for equal params — and the run holds the ranks, the
|
|
78185
|
+
// count and the asks of the one it draws.
|
|
78186
|
+
, {
|
|
78187
|
+
itemsAction: reader,
|
|
78188
|
+
settling: settling,
|
|
78189
|
+
...props
|
|
78190
|
+
}, reader && reader.isRangeReader ? readerKeyOf(reader) : undefined);
|
|
78191
|
+
};
|
|
78192
|
+
const ListItemsRun = ({
|
|
78085
78193
|
items,
|
|
78086
78194
|
itemsAction,
|
|
78195
|
+
settling,
|
|
78087
78196
|
count,
|
|
78088
78197
|
memoryBudget,
|
|
78089
78198
|
onRequestStateChange,
|
|
78199
|
+
onCountChange,
|
|
78090
78200
|
...runProps
|
|
78091
78201
|
}) => {
|
|
78092
78202
|
const store = useItemStore({
|
|
78093
78203
|
items,
|
|
78094
78204
|
count,
|
|
78095
78205
|
itemsAction,
|
|
78206
|
+
settling,
|
|
78096
78207
|
memoryBudget,
|
|
78097
|
-
onRequestStateChange
|
|
78208
|
+
onRequestStateChange,
|
|
78209
|
+
onCountChange
|
|
78098
78210
|
});
|
|
78099
78211
|
return useRunItems(store, runProps);
|
|
78100
78212
|
};
|
|
78213
|
+
const readerKeyByReader = new WeakMap();
|
|
78214
|
+
let readerKeyPrevious = 0;
|
|
78215
|
+
const readerKeyOf = reader => {
|
|
78216
|
+
let key = readerKeyByReader.get(reader);
|
|
78217
|
+
if (key === undefined) {
|
|
78218
|
+
readerKeyPrevious++;
|
|
78219
|
+
key = readerKeyPrevious;
|
|
78220
|
+
readerKeyByReader.set(reader, key);
|
|
78221
|
+
}
|
|
78222
|
+
return key;
|
|
78223
|
+
};
|
|
78224
|
+
// The reader the run draws: the one it is given, or under `debounce` the one
|
|
78225
|
+
// it was drawing until the one given has held still that long. Only between
|
|
78226
|
+
// two range readers — the first collection is drawn at once, and a collection
|
|
78227
|
+
// held in memory costs no request to follow.
|
|
78228
|
+
const useSettledReader = (itemsAction, debounce) => {
|
|
78229
|
+
const settledRef = useRef(itemsAction);
|
|
78230
|
+
const [, setSettleCount] = useState(0);
|
|
78231
|
+
const settled = settledRef.current;
|
|
78232
|
+
const waits = Boolean(debounce) && itemsAction !== settled && Boolean(itemsAction && itemsAction.isRangeReader) && Boolean(settled && settled.isRangeReader);
|
|
78233
|
+
if (!waits) {
|
|
78234
|
+
settledRef.current = itemsAction;
|
|
78235
|
+
}
|
|
78236
|
+
useLayoutEffect(() => {
|
|
78237
|
+
if (!waits) {
|
|
78238
|
+
return undefined;
|
|
78239
|
+
}
|
|
78240
|
+
const timeout = setTimeout(() => {
|
|
78241
|
+
settledRef.current = itemsAction;
|
|
78242
|
+
setSettleCount(settleCount => settleCount + 1);
|
|
78243
|
+
}, debounce);
|
|
78244
|
+
return () => {
|
|
78245
|
+
clearTimeout(timeout);
|
|
78246
|
+
};
|
|
78247
|
+
}, [waits, itemsAction, debounce]);
|
|
78248
|
+
return waits ? {
|
|
78249
|
+
reader: settled,
|
|
78250
|
+
settling: true
|
|
78251
|
+
} : {
|
|
78252
|
+
reader: itemsAction,
|
|
78253
|
+
settling: false
|
|
78254
|
+
};
|
|
78255
|
+
};
|
|
78101
78256
|
|
|
78102
78257
|
// The items a `loading` list is told to expect (loadingSkeletonCount): a run
|
|
78103
78258
|
// holding none of them, and asking for none — they arrive through the app.
|
|
@@ -78178,10 +78333,13 @@ const useRunItems = (store, {
|
|
|
78178
78333
|
skeletonItem = {};
|
|
78179
78334
|
const virtualItemSize = listItems.virtualItemSizeSignal.value;
|
|
78180
78335
|
if (virtualItemSize) {
|
|
78336
|
+
// The room is the item's and what stands before it (see
|
|
78337
|
+
// readSpaceBetweenItems): the box takes what is left of it.
|
|
78338
|
+
const minSize = `calc(${virtualItemSize}px - var(--x-list-item-between, 0px))`;
|
|
78181
78339
|
if (listItems.horizontal) {
|
|
78182
|
-
skeletonItem.itemMinWidth =
|
|
78340
|
+
skeletonItem.itemMinWidth = minSize;
|
|
78183
78341
|
} else {
|
|
78184
|
-
skeletonItem.itemMinHeight =
|
|
78342
|
+
skeletonItem.itemMinHeight = minSize;
|
|
78185
78343
|
}
|
|
78186
78344
|
}
|
|
78187
78345
|
return skeletonItem;
|
|
@@ -78715,6 +78873,7 @@ const ListItemsFailure = ({
|
|
|
78715
78873
|
// hits the network again.
|
|
78716
78874
|
const ITEM_STORE_MAX_DEFAULT = 1000;
|
|
78717
78875
|
const ITEM_STORE_KEEP_AROUND = 250;
|
|
78876
|
+
const COUNT_NOT_SAID = {};
|
|
78718
78877
|
const rangeIsSame = (a, b) => {
|
|
78719
78878
|
if (!a || !b) {
|
|
78720
78879
|
return a === b;
|
|
@@ -78731,8 +78890,10 @@ const useItemStore = ({
|
|
|
78731
78890
|
items,
|
|
78732
78891
|
count,
|
|
78733
78892
|
itemsAction,
|
|
78893
|
+
settling,
|
|
78734
78894
|
memoryBudget,
|
|
78735
|
-
onRequestStateChange
|
|
78895
|
+
onRequestStateChange,
|
|
78896
|
+
onCountChange
|
|
78736
78897
|
}) => {
|
|
78737
78898
|
// A collection given whole (`items`) is held from the first render: nothing
|
|
78738
78899
|
// to ask for, nothing to keep across mounts, nothing to invalidate. The rest
|
|
@@ -78858,15 +79019,37 @@ const useItemStore = ({
|
|
|
78858
79019
|
// It stands for a page of them: a list that is about to be filled looks
|
|
78859
79020
|
// like items on their way, not like an empty list.
|
|
78860
79021
|
const itemCount = pages.count ?? count ?? listItems.pageSize;
|
|
79022
|
+
// The items drawn are from before while they are read again, and while the
|
|
79023
|
+
// collection that replaces them waits for its params to hold still (see
|
|
79024
|
+
// useSettledReader).
|
|
79025
|
+
const refreshingShown = refreshing || Boolean(settling);
|
|
78861
79026
|
useLayoutEffect(() => {
|
|
78862
|
-
if (!
|
|
79027
|
+
if (!refreshingShown) {
|
|
78863
79028
|
return null;
|
|
78864
79029
|
}
|
|
78865
79030
|
listItems.refreshingSignal.value = listItems.refreshingSignal.peek() + 1;
|
|
78866
79031
|
return () => {
|
|
78867
79032
|
listItems.refreshingSignal.value = listItems.refreshingSignal.peek() - 1;
|
|
78868
79033
|
};
|
|
78869
|
-
}, [
|
|
79034
|
+
}, [refreshingShown]);
|
|
79035
|
+
|
|
79036
|
+
// How many items the collection holds, for the screen around the list to
|
|
79037
|
+
// say: the count the source answered or the caller gave, never the page the
|
|
79038
|
+
// run stands for before it knows. Said by each run on its first commit, so a
|
|
79039
|
+
// run drawing another collection takes back what the one before said.
|
|
79040
|
+
const countKnown = pages.count ?? count;
|
|
79041
|
+
const onCountChangeRef = useRef(onCountChange);
|
|
79042
|
+
onCountChangeRef.current = onCountChange;
|
|
79043
|
+
const countSaidRef = useRef(COUNT_NOT_SAID);
|
|
79044
|
+
useLayoutEffect(() => {
|
|
79045
|
+
if (countSaidRef.current === countKnown) {
|
|
79046
|
+
return;
|
|
79047
|
+
}
|
|
79048
|
+
countSaidRef.current = countKnown;
|
|
79049
|
+
if (onCountChangeRef.current) {
|
|
79050
|
+
onCountChangeRef.current(countKnown);
|
|
79051
|
+
}
|
|
79052
|
+
});
|
|
78870
79053
|
|
|
78871
79054
|
// What the run is doing, for the screen around the list to draw: the list has
|
|
78872
79055
|
// its own skeletons, what is around it has to be told. Read from the request
|
|
@@ -78915,7 +79098,7 @@ const useItemStore = ({
|
|
|
78915
79098
|
const store = {
|
|
78916
79099
|
itemCount,
|
|
78917
79100
|
failure,
|
|
78918
|
-
refreshing,
|
|
79101
|
+
refreshing: refreshingShown,
|
|
78919
79102
|
// JS memory is cheap next to the DOM, but a long enough scroll accumulates
|
|
78920
79103
|
// everything it ever went through. Items far from what is on screen are
|
|
78921
79104
|
// dropped and simply asked for again if the user goes back — the same
|
|
@@ -79572,8 +79755,9 @@ const ListResolved = /*#__PURE__*/createComponentResolver([ListFirstResolver, Li
|
|
|
79572
79755
|
* @param {number} [props.virtualItemSize]
|
|
79573
79756
|
* The room an item never drawn is held at, in px along the scroll axis: what
|
|
79574
79757
|
* the fillers hold for it outside the render window, what a scroll position
|
|
79575
|
-
* inside them is read with, and the least an item on its way takes
|
|
79576
|
-
* `renderSkeleton`)
|
|
79758
|
+
* inside them is read with, and the least room an item on its way takes
|
|
79759
|
+
* (see `renderSkeleton`) — a room counts what stands before the item, a
|
|
79760
|
+
* gap or a separator, so the item's own box takes the rest of it. An item the list has drawn is held at the room it took
|
|
79577
79761
|
* then, and an item whose run says its room (`<List.Items itemSize>`) at
|
|
79578
79762
|
* that room. Left out, it is the average of the items measured so far — once when
|
|
79579
79763
|
* the list mounts, again when a popup around it opens, and after each commit
|
|
@@ -93477,6 +93661,12 @@ const DEFAULT_PLACEHOLDER_LIGHT = "#d4d8dd";
|
|
|
93477
93661
|
const DEFAULT_PLACEHOLDER_DARK = "#374151";
|
|
93478
93662
|
|
|
93479
93663
|
/**
|
|
93664
|
+
* The props may come in any order: `src` and `srcset` reach the element after
|
|
93665
|
+
* `loading` and the other hints. A plain `<img>` (or `<Box as="img">`) written
|
|
93666
|
+
* in JSX must put `loading` before `src`: WebKit, so every browser on iOS,
|
|
93667
|
+
* decides whether to load when `src` is set, and an image whose `src` came
|
|
93668
|
+
* first loads, lazy or not.
|
|
93669
|
+
*
|
|
93480
93670
|
* @param {string|false} [props.placeholderColor] - Background color shown while the image loads.
|
|
93481
93671
|
* Defaults to a light gray. Pass `false` to disable.
|
|
93482
93672
|
* @param {boolean} [props.placeholderDark] - Use a dark default placeholder color,
|
|
@@ -93486,6 +93676,9 @@ const DEFAULT_PLACEHOLDER_DARK = "#374151";
|
|
|
93486
93676
|
const Image = ({
|
|
93487
93677
|
placeholderColor,
|
|
93488
93678
|
placeholderDark = false,
|
|
93679
|
+
srcset,
|
|
93680
|
+
srcSet,
|
|
93681
|
+
src,
|
|
93489
93682
|
...rest
|
|
93490
93683
|
}) => {
|
|
93491
93684
|
import.meta.css = [css$5, "@jsenv/navi/src/graphic/image.jsx"];
|
|
@@ -93510,6 +93703,13 @@ const Image = ({
|
|
|
93510
93703
|
imageEl.setAttribute("navi-loaded", "");
|
|
93511
93704
|
rest.onLoad?.(e);
|
|
93512
93705
|
}
|
|
93706
|
+
// Last, srcset before src: an <img> decides its request when they are
|
|
93707
|
+
// set, with the attributes it has at that moment. WebKit loads an image
|
|
93708
|
+
// whose src arrives before loading="lazy", and does not take it back.
|
|
93709
|
+
,
|
|
93710
|
+
srcset: srcset,
|
|
93711
|
+
srcSet: srcSet,
|
|
93712
|
+
src: src
|
|
93513
93713
|
});
|
|
93514
93714
|
};
|
|
93515
93715
|
|