@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/docs/AI_INSTRUCTIONS.md
CHANGED
|
@@ -83,7 +83,8 @@ start when unsure which export solves a problem.
|
|
|
83
83
|
running (`{ run: true }` is the fallback), `action` versus `uiAction`, an
|
|
84
84
|
action and a command on one press. Before running an action from a component.
|
|
85
85
|
- `resource.md` — `resource()` and its relations (never an `op` discriminator),
|
|
86
|
-
`GET_RANGE`,
|
|
86
|
+
`GET_RANGE` (its inclusive `end`, the count for the screen around the list, a
|
|
87
|
+
question following a search field), a search as the same `GET_MANY`, `withParams()` scopes and
|
|
87
88
|
`dependencies`, `persist` (and `keepPageOnScreen` for the page on screen), a
|
|
88
89
|
function versus the verb's instance. Before writing a resource, and before
|
|
89
90
|
caching a response yourself.
|
|
@@ -186,11 +187,13 @@ start when unsure which export solves a problem.
|
|
|
186
187
|
`scroller`, where a list opens (a position handed back whole, `visibleCount`
|
|
187
188
|
included), a list that comes back (its `id` names one list of the app), a
|
|
188
189
|
popup that scrolls, many rows (`<List.Items>`, the render window and its first
|
|
189
|
-
picture, skeletons at the size of their item, `itemSize`, `findText
|
|
190
|
+
picture, skeletons at the size of their item, `itemSize`, `findText`, how far
|
|
191
|
+
ahead its images load and `loading` before `src`), many
|
|
190
192
|
sections (`<Box mount="after-paint">` and what it leaves out of reach), hover
|
|
191
193
|
while scrolling. Before writing CSS to make something scroll, before
|
|
192
194
|
rendering a collection as `<List.Item>` children, before writing a
|
|
193
|
-
`renderSkeleton`, and before deferring part
|
|
195
|
+
`renderSkeleton`, before putting images in a run, and before deferring part
|
|
196
|
+
of a page.
|
|
194
197
|
- `z_index.md` — DOM order first; a `z-index` without `isolation: isolate`
|
|
195
198
|
competes with the page; navi's bands. Before writing a `z-index`.
|
|
196
199
|
- `typography.md` — text is a component; `maxLines` is the one truncation; one
|
package/docs/resource.md
CHANGED
|
@@ -269,13 +269,20 @@ const GAME = resource("game", {
|
|
|
269
269
|
|
|
270
270
|
The callback receives the bound params merged with the range the list asks for
|
|
271
271
|
(`start`, `end`, `limit`, `before`, `after`, `around`), and `{ signal }`,
|
|
272
|
-
aborted when the list stops wanting those rows.
|
|
273
|
-
`
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
272
|
+
aborted when the list stops wanting those rows. `end` is the last place asked
|
|
273
|
+
for, included, as in `Range: items=0-99`: `limit` is `end - start + 1`, and an
|
|
274
|
+
API whose end is excluded is called with `start + limit`. It returns a range the
|
|
275
|
+
way a `Content-Range` does: **`{ items, start, count }`** — these rows, at this
|
|
276
|
+
place, out of that many. `start` may be omitted when the list asked for one at
|
|
277
|
+
or after `0` (a negative `start` counts back from the end, and the source must
|
|
278
|
+
then say where the slice landed); `count` defaults to `start + items.length`.
|
|
279
|
+
The items are upserted on their way in, so the list draws store items, never
|
|
280
|
+
copies of the JSON.
|
|
281
|
+
|
|
282
|
+
The count is also what the screen around the list says — "5 of 83 books". The
|
|
283
|
+
run hands it out with `onCountChange`: `undefined` until a slice has answered,
|
|
284
|
+
then each count a slice brings, and again for each collection the run draws, so
|
|
285
|
+
the number always belongs to the rows on screen.
|
|
279
286
|
|
|
280
287
|
But the list keeps the object it was handed, and an update replaces the item
|
|
281
288
|
object (the store holds values, which is what makes a change detectable). So a
|
|
@@ -304,6 +311,30 @@ rows staying on screen
|
|
|
304
311
|
reads a collection, so it lives on the resource (or on a `withParams()` of it),
|
|
305
312
|
not on a relation.
|
|
306
313
|
|
|
314
|
+
### A question that follows a search field
|
|
315
|
+
|
|
316
|
+
A reader bound to other params is another collection, and the run draws it
|
|
317
|
+
from its first item — it needs no `key` for that. A param following what is
|
|
318
|
+
typed then makes one collection per key, and one request each, the server
|
|
319
|
+
receiving every one even when the list calls it off. `debounce` on the run
|
|
320
|
+
waits for the reader to hold still, and keeps the collection from before drawn
|
|
321
|
+
meanwhile, `refreshing`:
|
|
322
|
+
|
|
323
|
+
```jsx
|
|
324
|
+
<List.Items
|
|
325
|
+
itemsAction={BOOK.GET_RANGE.bindParams({ q: searchSignal.value })}
|
|
326
|
+
debounce={300}
|
|
327
|
+
onCountChange={(count) => {
|
|
328
|
+
bookCountSignal.value = count;
|
|
329
|
+
}}
|
|
330
|
+
renderItem={renderBook}
|
|
331
|
+
/>
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
A `key` that follows the field defeats it: the run remounts at each key, and
|
|
335
|
+
its wait with it. Demo: `src/control/demos/integration/1_list_loaded_by_scroll_demo.html`
|
|
336
|
+
("Une recherche qui suit la frappe").
|
|
337
|
+
|
|
307
338
|
## Searching the same collection
|
|
308
339
|
|
|
309
340
|
A screen showing a collection soon asks a second question about it: the list
|
package/docs/scroll.md
CHANGED
|
@@ -482,6 +482,44 @@ is never revealed. navi's own does.
|
|
|
482
482
|
|
|
483
483
|
Reference: `src/control/demos/19_list_find_in_page_demo.html`.
|
|
484
484
|
|
|
485
|
+
### Images in a run
|
|
486
|
+
|
|
487
|
+
An `<img>` asks for its file once it is in the DOM, and an item outside the
|
|
488
|
+
render window is not. So in a run, two things decide how far ahead of the screen
|
|
489
|
+
images load, the window and the browser, and the nearer one wins:
|
|
490
|
+
|
|
491
|
+
- **Without `loading="lazy"`**, the window decides. Every item it draws loads
|
|
492
|
+
its images, so the lookahead that keeps a fling covered (three quarters of
|
|
493
|
+
what the screen leaves of `renderBudget`, which is dozens of items with the
|
|
494
|
+
default) is downloaded when the list opens, and again each time the window
|
|
495
|
+
slides.
|
|
496
|
+
- **With `loading="lazy"`**, the browser decides inside the window, and each
|
|
497
|
+
engine decides differently. Measured in October 2026, this is how far below
|
|
498
|
+
the screen an image's top is when its request starts:
|
|
499
|
+
|
|
500
|
+
| engine | distance |
|
|
501
|
+
| ----------------------------- | ------------------ |
|
|
502
|
+
| Chromium | ~3000 px |
|
|
503
|
+
| WebKit (every browser on iOS) | ~1 viewport height |
|
|
504
|
+
| Firefox | ~600 px |
|
|
505
|
+
|
|
506
|
+
Chromium keeps the same distance on 3G and on 4G. When the window's lookahead
|
|
507
|
+
is shorter than the engine's distance, the window decides again.
|
|
508
|
+
|
|
509
|
+
It is a trade between bytes and images that are ready. Lazy images follow the
|
|
510
|
+
screen, and nothing the user never reaches is downloaded. Eager ones are
|
|
511
|
+
already there when a fling arrives, at the cost of a whole window of downloads.
|
|
512
|
+
How far ahead is enough depends on how fast the screen is crossed and how fast
|
|
513
|
+
a file arrives. Like the window's own lookahead, it is measured on the slowest
|
|
514
|
+
device and connection the list serves. Whichever you choose, give each image
|
|
515
|
+
its dimensions (see
|
|
516
|
+
[What the list knows, and what it guesses](#what-the-list-knows-and-what-it-guesses)).
|
|
517
|
+
|
|
518
|
+
`loading` only holds if it is set before `src`. `Image` does this whatever the
|
|
519
|
+
order of its props. A plain `<img>` written in JSX must put `loading` first:
|
|
520
|
+
WebKit decides when `src` is set, and an image whose `src` came first loads
|
|
521
|
+
whatever `loading` says afterwards.
|
|
522
|
+
|
|
485
523
|
### Doing it well
|
|
486
524
|
|
|
487
525
|
- **Skeletons at the size of their item**, and `itemSize` when the items above
|
|
@@ -498,10 +536,14 @@ Reference: `src/control/demos/19_list_find_in_page_demo.html`.
|
|
|
498
536
|
item and the index it is given rather than closing over state.
|
|
499
537
|
|
|
500
538
|
The rest — `virtualItemSize`, the room an item not drawn is held at (uniform
|
|
501
|
-
items, or the smallest one of a mixed list — the worst case, see above), a
|
|
502
|
-
|
|
539
|
+
items, or the smallest one of a mixed list — the worst case, see above), a
|
|
540
|
+
collection that changes as a whole (another array, another reader — drawn from
|
|
541
|
+
its first item; never a `key` to refresh it, see
|
|
503
542
|
[list_refresh.md](./list_refresh.md#a-paginated-list-stays-on-screen-too)),
|
|
504
|
-
`
|
|
543
|
+
`debounce` for a question following a search field
|
|
544
|
+
([resource.md](./resource.md#a-question-that-follows-a-search-field)),
|
|
545
|
+
`onCountChange` for the screen around the list to say how many items there
|
|
546
|
+
are, `groupBy` for sections — is in the JSDoc of `List` and `List.Items`
|
|
505
547
|
(`src/control/list/list.jsx`). Demos:
|
|
506
548
|
`src/control/demos/17_virtual_scroll_and_filter_demo.html` (a run in memory,
|
|
507
549
|
searched), `src/control/demos/integration/1_list_loaded_by_scroll_demo.html` (a
|