@jsenv/navi 0.29.422 → 0.29.424
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 +141 -15
- package/dist/dev/jsenv_navi.js.map +3 -3
- package/dist/jsenv_navi.js +141 -15
- package/dist/jsenv_navi.js.map +3 -3
- package/docs/scroll.md +40 -5
- package/package.json +2 -2
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -60814,6 +60814,20 @@ const readArea = slideElement => slideElement.getAttribute("data-slide-area") ||
|
|
|
60814
60814
|
* `sizing={loading ? "largest" : "frozen"}` and is measured once the real
|
|
60815
60815
|
* content is there. The freeze holds against what happens INSIDE the box, not
|
|
60816
60816
|
* against the room it is given: a window resize measures again.
|
|
60817
|
+
* @param {"always"|"near"} [props.mount="always"] - when a slide's CONTENT is
|
|
60818
|
+
* rendered. The <Slide> element always is, so areas, tabs following the box
|
|
60819
|
+
* and `aria-labelledby` are the same either way. "always": every slide's,
|
|
60820
|
+
* from the start. "near": once a travel can show it — the slide on screen,
|
|
60821
|
+
* the one a travel is going to, and at rest the ones a hand dragging the box
|
|
60822
|
+
* would bring alongside (neighbours on the map, along the axes
|
|
60823
|
+
* `travelByDrag` opens, the other end of a `loop` included) — and kept from
|
|
60824
|
+
* then on. For slides that are costly to build (a grid of a few hundred
|
|
60825
|
+
* controls each): opening builds the slide shown and its neighbours rather
|
|
60826
|
+
* than all of them, and a jump to a far slide builds that one and none of
|
|
60827
|
+
* those in between, which a travel never shows. The box is then as large as
|
|
60828
|
+
* the largest slide BUILT so far (see `sizing`), so it grows as a larger one
|
|
60829
|
+
* is reached: give it a size of its own when the slides differ.
|
|
60830
|
+
* `<Slide mount>` says it for one slide — a heavy one among light ones.
|
|
60817
60831
|
*/
|
|
60818
60832
|
const SlideContainer = ({
|
|
60819
60833
|
layout = "row",
|
|
@@ -60829,6 +60843,7 @@ const SlideContainer = ({
|
|
|
60829
60843
|
travelByScroll = "x",
|
|
60830
60844
|
duration = "300ms",
|
|
60831
60845
|
sizing = "largest",
|
|
60846
|
+
mount = "always",
|
|
60832
60847
|
children,
|
|
60833
60848
|
...rest
|
|
60834
60849
|
}) => {
|
|
@@ -60948,6 +60963,15 @@ const SlideContainer = ({
|
|
|
60948
60963
|
// Undefined at mount on purpose: the first area held outside is news like any
|
|
60949
60964
|
// other, and it is walked to rather than opened on.
|
|
60950
60965
|
const areaAskedSeenRef = useRef(undefined);
|
|
60966
|
+
// An area held outside that this container has not answered yet: the effect
|
|
60967
|
+
// reading currentFromCaller walks to it, after the render that brings it.
|
|
60968
|
+
const requestIsNews = () => currentFromCaller !== undefined && currentFromCaller !== areaAskedSeenRef.current;
|
|
60969
|
+
// The slide about to be on screen, as far as a render can tell: the area
|
|
60970
|
+
// asked from outside while it is news — the picture is walked there before
|
|
60971
|
+
// it is painted, the first request included — and the container's own answer
|
|
60972
|
+
// otherwise. What a slide waiting for a travel reads to have its content in
|
|
60973
|
+
// the very render that shows it (see Slide's `mount`).
|
|
60974
|
+
const areaShownNext = requestIsNews() ? currentFromCaller : current;
|
|
60951
60975
|
// Where the container stands, said where the caller holds it.
|
|
60952
60976
|
//
|
|
60953
60977
|
// Whether a slide is a place one came from is the STATE's own business (see
|
|
@@ -61002,6 +61026,22 @@ const SlideContainer = ({
|
|
|
61002
61026
|
// state: nothing on screen depends on it, and a travel must read what the
|
|
61003
61027
|
// one before it wrote, not what the last render saw.
|
|
61004
61028
|
const cameFromRef = useRef({});
|
|
61029
|
+
// The slides a travel has come near while their content was not rendered
|
|
61030
|
+
// (mount="near", see renderNear): only ever grows, and only for a slide that
|
|
61031
|
+
// was waiting — a container whose slides all render never re-renders for it.
|
|
61032
|
+
const [nearAreas, setNearAreas] = useState([]);
|
|
61033
|
+
// Nothing names the slide on screen (no area held outside, no default): it
|
|
61034
|
+
// is the first one in the DOM, which the first render cannot read yet. The
|
|
61035
|
+
// first Slide to render is that one, so it claims it — the slide on screen
|
|
61036
|
+
// then has its content from the first commit (a size frozen at mount, a
|
|
61037
|
+
// focus landing in it) rather than one render late.
|
|
61038
|
+
const openingClaimRef = useRef(null);
|
|
61039
|
+
const claimOpening = area => {
|
|
61040
|
+
if (openingClaimRef.current === null) {
|
|
61041
|
+
openingClaimRef.current = area;
|
|
61042
|
+
}
|
|
61043
|
+
return openingClaimRef.current === area;
|
|
61044
|
+
};
|
|
61005
61045
|
|
|
61006
61046
|
// The controller has caught up with the slide the container went to on its
|
|
61007
61047
|
// own (commit="rest"): there are no longer two answers to give, so the
|
|
@@ -61142,6 +61182,44 @@ const SlideContainer = ({
|
|
|
61142
61182
|
}
|
|
61143
61183
|
};
|
|
61144
61184
|
|
|
61185
|
+
// The slides a hand dragging the box from this area would bring alongside:
|
|
61186
|
+
// the map's neighbours on the axes it drags, read the way the drag reads them
|
|
61187
|
+
// (areaTowards knows the holes and a loop's two ends).
|
|
61188
|
+
const areasAlongside = area => {
|
|
61189
|
+
const alongside = [];
|
|
61190
|
+
if (dragAxes?.includes("x")) {
|
|
61191
|
+
alongside.push(areaTowards(-1, 0, area), areaTowards(1, 0, area));
|
|
61192
|
+
}
|
|
61193
|
+
if (dragAxes?.includes("y")) {
|
|
61194
|
+
alongside.push(areaTowards(0, -1, area), areaTowards(0, 1, area));
|
|
61195
|
+
}
|
|
61196
|
+
return alongside;
|
|
61197
|
+
};
|
|
61198
|
+
|
|
61199
|
+
// mount="near": the content of a slide is asked for before a travel shows
|
|
61200
|
+
// it. The neighbours are asked for AT REST, never when a travel sets off: the
|
|
61201
|
+
// travel shows the slide it goes to and nothing past it, and a slide built in
|
|
61202
|
+
// the render that starts it is a frame the travel waits for. At rest nothing
|
|
61203
|
+
// moves, and a hand landing next is still answered after the build.
|
|
61204
|
+
const renderNear = (area, {
|
|
61205
|
+
alongside
|
|
61206
|
+
}) => {
|
|
61207
|
+
// Asked on every render: a container with nothing waiting stops here.
|
|
61208
|
+
if (!trackRef.current?.querySelector(":scope > [data-slide-unrendered]")) {
|
|
61209
|
+
return;
|
|
61210
|
+
}
|
|
61211
|
+
const unrendered = readMap().slideElements.filter(slideElement => slideElement.hasAttribute("data-slide-unrendered")).map(readArea);
|
|
61212
|
+
const near = alongside ? [area, ...areasAlongside(area)] : [area];
|
|
61213
|
+
const toRender = near.filter(nearArea => unrendered.includes(nearArea));
|
|
61214
|
+
if (!toRender.length) {
|
|
61215
|
+
return;
|
|
61216
|
+
}
|
|
61217
|
+
setNearAreas(previous => {
|
|
61218
|
+
const added = toRender.filter(nearArea => !previous.includes(nearArea));
|
|
61219
|
+
return added.length ? [...previous, ...added] : previous;
|
|
61220
|
+
});
|
|
61221
|
+
};
|
|
61222
|
+
|
|
61145
61223
|
// The travel is over: the stage is struck and every slide goes back where the
|
|
61146
61224
|
// map says it is. Nothing is seen moving for it — the slide on screen sits at
|
|
61147
61225
|
// the same place whatever the arrangement (its own offset and the track's are
|
|
@@ -61190,6 +61268,9 @@ const SlideContainer = ({
|
|
|
61190
61268
|
const offset = `${-x * 100}% ${-y * 100}%`;
|
|
61191
61269
|
offsetRef.current = offset;
|
|
61192
61270
|
track.style.setProperty("--slide-container-offset", offset);
|
|
61271
|
+
renderNear(currentArea, {
|
|
61272
|
+
alongside: true
|
|
61273
|
+
});
|
|
61193
61274
|
// Arrived, so the change can be told (commit="rest"): the picture is at
|
|
61194
61275
|
// rest and whatever the caller does with it — write the URL, ask a server —
|
|
61195
61276
|
// costs the gesture nothing anymore.
|
|
@@ -61467,6 +61548,15 @@ const SlideContainer = ({
|
|
|
61467
61548
|
if (!stageRef.current) {
|
|
61468
61549
|
drawnAreaRef.current = currentArea;
|
|
61469
61550
|
}
|
|
61551
|
+
// What a travel can show next (mount="near"), around where the picture
|
|
61552
|
+
// SETTLES: a request from outside is walked to by an effect running after
|
|
61553
|
+
// this one, in the same commit, and the slides around a picture about to be
|
|
61554
|
+
// walked away from would be built for nothing. The neighbours only at
|
|
61555
|
+
// rest, see renderNear.
|
|
61556
|
+
const settlingArea = requestIsNews() && reachableTowards(currentArea, currentFromCaller) || currentArea;
|
|
61557
|
+
renderNear(settlingArea, {
|
|
61558
|
+
alongside: !stageRef.current
|
|
61559
|
+
});
|
|
61470
61560
|
// Said last, and after data-current has been written: what a travel would do
|
|
61471
61561
|
// is read off the map from the slide that is now current, and off the locks
|
|
61472
61562
|
// that slide is wearing in this very commit.
|
|
@@ -61704,12 +61794,9 @@ const SlideContainer = ({
|
|
|
61704
61794
|
// request later), and what nothing has answered yet must still be answered
|
|
61705
61795
|
// once it can be.
|
|
61706
61796
|
useLayoutEffect(() => {
|
|
61707
|
-
if (
|
|
61708
|
-
|
|
61709
|
-
|
|
61710
|
-
if (currentFromCaller === areaAskedSeenRef.current) {
|
|
61711
|
-
// Not news: either nothing moved, or this container is reading back what
|
|
61712
|
-
// it wrote itself.
|
|
61797
|
+
if (!requestIsNews()) {
|
|
61798
|
+
// Not news: nothing held outside, nothing moved, or this container
|
|
61799
|
+
// reading back what it wrote itself.
|
|
61713
61800
|
return;
|
|
61714
61801
|
}
|
|
61715
61802
|
// The slide asked for is not rendered yet — no slides at all, or one whose
|
|
@@ -62539,6 +62626,11 @@ const SlideContainer = ({
|
|
|
62539
62626
|
if (!past) {
|
|
62540
62627
|
return false;
|
|
62541
62628
|
}
|
|
62629
|
+
// Two slides from the one at rest, so possibly never rendered: asked
|
|
62630
|
+
// for now, and built before the frame that brings it in is painted.
|
|
62631
|
+
renderNear(past, {
|
|
62632
|
+
alongside: false
|
|
62633
|
+
});
|
|
62542
62634
|
const currentElement = slideElements.find(slideElement => slideElement.hasAttribute("data-current")) || slideElements[0];
|
|
62543
62635
|
const basePlace = stageRef.current?.placeByArea.get(reached) || placeOf.get(reached) || {
|
|
62544
62636
|
x: 0,
|
|
@@ -62997,6 +63089,12 @@ const SlideContainer = ({
|
|
|
62997
63089
|
done,
|
|
62998
63090
|
valueByArea,
|
|
62999
63091
|
settleFocus,
|
|
63092
|
+
// What a slide reads to know whether its content is rendered yet
|
|
63093
|
+
// (see Slide's `mount`).
|
|
63094
|
+
mount,
|
|
63095
|
+
areaShownNext,
|
|
63096
|
+
nearAreas,
|
|
63097
|
+
claimOpening: areaShownNext === undefined ? claimOpening : null,
|
|
63000
63098
|
// The box itself, for what is written INSIDE it to read the same
|
|
63001
63099
|
// facts what is written outside reads by id (useSlideContainer):
|
|
63002
63100
|
// a way out is a way out on either side of the box.
|
|
@@ -63053,9 +63151,12 @@ const warnOnNonStringArea = area => {
|
|
|
63053
63151
|
* try to leave.
|
|
63054
63152
|
* @param {boolean} [props.preventNavNext] - hold them from going right or down.
|
|
63055
63153
|
* @param {boolean} [props.preventNavPrevious] - …left or up.
|
|
63154
|
+
* @param {"always"|"near"} [props.mount] - when this slide's content is
|
|
63155
|
+
* rendered; the container's `mount` when not said (see there).
|
|
63056
63156
|
*/
|
|
63057
63157
|
const Slide = ({
|
|
63058
63158
|
area,
|
|
63159
|
+
mount,
|
|
63059
63160
|
required,
|
|
63060
63161
|
preventNav,
|
|
63061
63162
|
preventNavNext = preventNav,
|
|
@@ -63068,6 +63169,17 @@ const Slide = ({
|
|
|
63068
63169
|
{
|
|
63069
63170
|
warnOnNonStringArea(slideArea);
|
|
63070
63171
|
}
|
|
63172
|
+
// Asked by every slide, whatever its own mode: the claim goes to the first
|
|
63173
|
+
// slide to RENDER, and a slide that skipped asking would hand it to the one
|
|
63174
|
+
// after it.
|
|
63175
|
+
const opening = container?.claimOpening?.(slideArea);
|
|
63176
|
+
// Kept once rendered (mount="near"): going back builds nothing again, and a
|
|
63177
|
+
// slide being left keeps its content for as long as it is still in the frame.
|
|
63178
|
+
const renderedRef = useRef(false);
|
|
63179
|
+
if (!renderedRef.current && (!container || (mount ?? container.mount) !== "near" || opening || slideArea === container.areaShownNext || container.nearAreas.includes(slideArea))) {
|
|
63180
|
+
renderedRef.current = true;
|
|
63181
|
+
}
|
|
63182
|
+
const rendered = renderedRef.current;
|
|
63071
63183
|
const answered = Boolean(container?.answeredAreas.includes(slideArea));
|
|
63072
63184
|
const holdsUntilAnswered = Boolean(required) && !answered;
|
|
63073
63185
|
const nextIsLocked = Boolean(preventNavNext) || holdsUntilAnswered;
|
|
@@ -63117,13 +63229,17 @@ const Slide = ({
|
|
|
63117
63229
|
"data-slide-area": slideArea,
|
|
63118
63230
|
"data-prevent-nav-next": nextIsLocked ? "" : undefined,
|
|
63119
63231
|
"data-prevent-nav-previous": preventNavPrevious ? "" : undefined
|
|
63232
|
+
// What the container reads to know a slide is waiting for a travel
|
|
63233
|
+
// to come near (see renderNear).
|
|
63234
|
+
,
|
|
63235
|
+
"data-slide-unrendered": rendered ? undefined : ""
|
|
63120
63236
|
// A surface one interacts with says what state it is in, the way every
|
|
63121
63237
|
// other surface does — a dialog carries the very same set.
|
|
63122
63238
|
// :focus-within is the one a slide is really about: it is what tells
|
|
63123
63239
|
// the slide holding the keyboard from the ones waiting.
|
|
63124
63240
|
,
|
|
63125
63241
|
pseudoClasses: SLIDE_PSEUDO_CLASSES,
|
|
63126
|
-
children: children
|
|
63242
|
+
children: rendered ? children : null
|
|
63127
63243
|
})
|
|
63128
63244
|
})
|
|
63129
63245
|
});
|
|
@@ -75640,9 +75756,12 @@ const readRoomAround = ({
|
|
|
75640
75756
|
// too — and an item not drawn is taken to weigh what the drawn items at that
|
|
75641
75757
|
// edge of the window weigh. Items of one kind come together (the one-line
|
|
75642
75758
|
// items of the past, the cards ahead), and an item misjudged is weighed again
|
|
75643
|
-
// once it is drawn (see "after slide"):
|
|
75644
|
-
//
|
|
75645
|
-
//
|
|
75759
|
+
// once it is drawn (see "after slide"): a window that came up short is
|
|
75760
|
+
// extended on the next frame, from what it measured. Weighing an item not drawn
|
|
75761
|
+
// at the average of all items, or at the smallest an item can be so that the
|
|
75762
|
+
// window never comes up short, walks into the cards at the one-line size,
|
|
75763
|
+
// several at a time — the latter measured in wematch: no blank spared, 50–65 ms
|
|
75764
|
+
// tasks while reading down through the cards.
|
|
75646
75765
|
const EDGE_SAMPLE_ITEM_COUNT = 8;
|
|
75647
75766
|
const createItemSizeReader = (items, start, end, itemSize) => {
|
|
75648
75767
|
const sizeByIndex = new Map();
|
|
@@ -78127,11 +78246,18 @@ const ListResolved = /*#__PURE__*/createComponentResolver([ListFirstResolver, Li
|
|
|
78127
78246
|
* source for is a page (see `<List.Items pageSize>`), whatever either says,
|
|
78128
78247
|
* so the first picture costs no second request.
|
|
78129
78248
|
* @param {number} [props.virtualItemSize]
|
|
78130
|
-
* The
|
|
78131
|
-
*
|
|
78132
|
-
*
|
|
78133
|
-
*
|
|
78134
|
-
*
|
|
78249
|
+
* The room an item not drawn is held at, in px along the scroll axis: what
|
|
78250
|
+
* the fillers hold for each item outside the render window, what a scroll
|
|
78251
|
+
* position inside them is read with, and the least an item on its way takes
|
|
78252
|
+
* (see `renderSkeleton`). Left out, it is the average of the items measured
|
|
78253
|
+
* so far — once when the list mounts, again when a popup around it opens,
|
|
78254
|
+
* and after each commit while items are held off screen. Given, it is the
|
|
78255
|
+
* worst case: the size every item has, or, in a list whose items differ, the
|
|
78256
|
+
* smallest an item can be (a thread of one-line items and cards: the
|
|
78257
|
+
* one-line size) — an item guessed too small builds one more, an item
|
|
78258
|
+
* guessed too big leaves a blank (see docs/scroll.md, "What the list knows,
|
|
78259
|
+
* and what it guesses"). The items drawn are measured either way: the render
|
|
78260
|
+
* window is sized on them.
|
|
78135
78261
|
* @param {"self"|"parent"|"document"|Element|{current: Element}} [props.scroller="self"]
|
|
78136
78262
|
* Which box scrolls — and with it, which box the render window follows and
|
|
78137
78263
|
* which box a scroll position is read from (`onScrolledChange`). `"self"`
|