@jsenv/navi 0.30.3 → 0.30.5
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 +205 -36
- package/dist/dev/jsenv_navi.js.map +12 -12
- package/dist/jsenv_navi.js +205 -36
- package/dist/jsenv_navi.js.map +12 -12
- package/docs/drag_to_travel.md +3 -1
- package/docs/navigation.md +50 -0
- package/docs/scroll.md +8 -0
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -11751,7 +11751,7 @@ const getMessageString = (message) => {
|
|
|
11751
11751
|
if (typeof message === "string") {
|
|
11752
11752
|
return message;
|
|
11753
11753
|
}
|
|
11754
|
-
if (Error
|
|
11754
|
+
if (message instanceof Error) {
|
|
11755
11755
|
return message.message;
|
|
11756
11756
|
}
|
|
11757
11757
|
return undefined;
|
|
@@ -20281,7 +20281,7 @@ const openCallout = (
|
|
|
20281
20281
|
element: calloutElement,
|
|
20282
20282
|
});
|
|
20283
20283
|
} else {
|
|
20284
|
-
if (Error
|
|
20284
|
+
if (newMessage instanceof Error) {
|
|
20285
20285
|
const error = newMessage;
|
|
20286
20286
|
newMessage = error.message;
|
|
20287
20287
|
if (showErrorStack && error.stack) {
|
|
@@ -23931,7 +23931,7 @@ const sayRefusal = (element, error) => {
|
|
|
23931
23931
|
let anchorElement = element;
|
|
23932
23932
|
if (
|
|
23933
23933
|
typeof error === "object" &&
|
|
23934
|
-
!
|
|
23934
|
+
!(error instanceof Error) &&
|
|
23935
23935
|
!isValidElement(error)
|
|
23936
23936
|
) {
|
|
23937
23937
|
message = error.message;
|
|
@@ -26739,7 +26739,7 @@ const useExecuteAction = (
|
|
|
26739
26739
|
// and it is then shown exactly as if there were no mapping at all.
|
|
26740
26740
|
if (typeof errorMappingResult === "string") {
|
|
26741
26741
|
message = errorMappingResult;
|
|
26742
|
-
} else if (Error
|
|
26742
|
+
} else if (errorMappingResult instanceof Error) {
|
|
26743
26743
|
message = errorMappingResult;
|
|
26744
26744
|
} else if (isValidElement(errorMappingResult)) {
|
|
26745
26745
|
message = errorMappingResult;
|
|
@@ -37756,9 +37756,23 @@ const collectRoutePages = children => {
|
|
|
37756
37756
|
* Whether the next container down is a row a hand scrolls: every page has a
|
|
37757
37757
|
* place on it from the start, and the browser moves between them (see
|
|
37758
37758
|
* RouteTravel's `nativeScroll`). Told to one container, not to the pages it holds.
|
|
37759
|
+
* False, or `{ renderNeighbour }`.
|
|
37759
37760
|
*/
|
|
37760
37761
|
const RouteRowContext = createContext(false);
|
|
37761
37762
|
|
|
37763
|
+
/**
|
|
37764
|
+
* What stands in the pane of a neighbour until its page does. A component of its
|
|
37765
|
+
* own: what the application calls in there (a hook, a signal) answers to it, however
|
|
37766
|
+
* many neighbours the row has at that moment.
|
|
37767
|
+
*/
|
|
37768
|
+
const RouteRowNeighbour = ({
|
|
37769
|
+
renderNeighbour,
|
|
37770
|
+
page
|
|
37771
|
+
}) => jsx("div", {
|
|
37772
|
+
"data-route-row-neighbour": "",
|
|
37773
|
+
children: renderNeighbour(page)
|
|
37774
|
+
});
|
|
37775
|
+
|
|
37762
37776
|
// A container as a row: one pane per leaf, in the order they are written. A page
|
|
37763
37777
|
// still builds when its route first matches, since a route's actions only ask
|
|
37764
37778
|
// while it does: before that its pane is empty. Once built it stays, with what
|
|
@@ -37771,6 +37785,9 @@ const RouteRowContext = createContext(false);
|
|
|
37771
37785
|
const RouteRowContainer = ({
|
|
37772
37786
|
children
|
|
37773
37787
|
}) => {
|
|
37788
|
+
const {
|
|
37789
|
+
renderNeighbour
|
|
37790
|
+
} = useContext(RouteRowContext);
|
|
37774
37791
|
const {
|
|
37775
37792
|
activeBranch,
|
|
37776
37793
|
leaves
|
|
@@ -37819,16 +37836,19 @@ const RouteRowContainer = ({
|
|
|
37819
37836
|
shown: true
|
|
37820
37837
|
}, "fallback");
|
|
37821
37838
|
}
|
|
37822
|
-
|
|
37839
|
+
const shownIndex = activeBranch ? leaves.findIndex(leaf => leaf.id === activeBranch.id) : -1;
|
|
37840
|
+
return leaves.map((leaf, index) => jsx(RouteRowPane, {
|
|
37823
37841
|
branch: leaf,
|
|
37824
37842
|
page: pageOf(leaf),
|
|
37825
|
-
shown:
|
|
37843
|
+
shown: index === shownIndex,
|
|
37844
|
+
renderNeighbour: shownIndex !== -1 && (index === shownIndex - 1 || index === shownIndex + 1) ? renderNeighbour : undefined
|
|
37826
37845
|
}, leaf.id));
|
|
37827
37846
|
};
|
|
37828
37847
|
const RouteRowPane = ({
|
|
37829
37848
|
branch,
|
|
37830
37849
|
page,
|
|
37831
|
-
shown
|
|
37850
|
+
shown,
|
|
37851
|
+
renderNeighbour
|
|
37832
37852
|
}) => {
|
|
37833
37853
|
// The very vnode rendered last, while not on screen: Preact does not look into
|
|
37834
37854
|
// it, and a page nobody can see costs nothing when the address moves.
|
|
@@ -37847,7 +37867,10 @@ const RouteRowPane = ({
|
|
|
37847
37867
|
"data-route-row-pane": "",
|
|
37848
37868
|
"data-built": contentRef.current ? "" : undefined,
|
|
37849
37869
|
inert: !shown,
|
|
37850
|
-
children: contentRef.current
|
|
37870
|
+
children: contentRef.current || renderNeighbour && jsx(RouteRowNeighbour, {
|
|
37871
|
+
renderNeighbour: renderNeighbour,
|
|
37872
|
+
page: branchRoutePage(branch)
|
|
37873
|
+
})
|
|
37851
37874
|
});
|
|
37852
37875
|
};
|
|
37853
37876
|
|
|
@@ -41703,7 +41726,9 @@ const readRowStretch = (scroller, pages, page) => {
|
|
|
41703
41726
|
/**
|
|
41704
41727
|
* @param {Element} scroller
|
|
41705
41728
|
* @param {object} options
|
|
41706
|
-
* @param {() => void} options.onScroll - the row moved.
|
|
41729
|
+
* @param {(move: {finger: boolean}) => void} options.onScroll - the row moved.
|
|
41730
|
+
* `finger`: a touch has come since the row last stopped, so a lift will say where
|
|
41731
|
+
* it goes (`onLeftToSnap`). Without one (a trackpad, a wheel) nothing will.
|
|
41707
41732
|
* @param {(event: Event|null) => void} options.onLand - the row may have stopped.
|
|
41708
41733
|
* Read `pageAtRest` to know whether it stopped on a page. Heard more than once
|
|
41709
41734
|
* for one landing, so what it does must find nothing to do the second time.
|
|
@@ -41719,11 +41744,13 @@ const watchRowScroll = (
|
|
|
41719
41744
|
) => {
|
|
41720
41745
|
let stoppedTimeout = null;
|
|
41721
41746
|
let touching = false;
|
|
41747
|
+
let touchedSinceStop = false;
|
|
41722
41748
|
let liftedAt = null;
|
|
41723
41749
|
const landOnSilence = () => {
|
|
41724
41750
|
liftedAt = null;
|
|
41725
41751
|
// A finger holding the row still: nothing has stopped.
|
|
41726
41752
|
if (!touching) {
|
|
41753
|
+
touchedSinceStop = false;
|
|
41727
41754
|
onLand(null);
|
|
41728
41755
|
}
|
|
41729
41756
|
};
|
|
@@ -41732,7 +41759,7 @@ const watchRowScroll = (
|
|
|
41732
41759
|
stoppedTimeout = setTimeout(landOnSilence, STOPPED_SILENCE);
|
|
41733
41760
|
};
|
|
41734
41761
|
const onScrollEvent = () => {
|
|
41735
|
-
onScroll();
|
|
41762
|
+
onScroll({ finger: touchedSinceStop });
|
|
41736
41763
|
armSilence();
|
|
41737
41764
|
if (!liftedAt) {
|
|
41738
41765
|
return;
|
|
@@ -41748,6 +41775,7 @@ const watchRowScroll = (
|
|
|
41748
41775
|
};
|
|
41749
41776
|
const onTouchStart = () => {
|
|
41750
41777
|
touching = true;
|
|
41778
|
+
touchedSinceStop = true;
|
|
41751
41779
|
liftedAt = null;
|
|
41752
41780
|
clearTimeout(stoppedTimeout);
|
|
41753
41781
|
};
|
|
@@ -41775,6 +41803,8 @@ const watchRowScroll = (
|
|
|
41775
41803
|
|
|
41776
41804
|
installImportMetaCssBuild(import.meta);
|
|
41777
41805
|
const css$16 = /* css */`.navi_route_travel {
|
|
41806
|
+
flex-direction: column;
|
|
41807
|
+
display: flex;
|
|
41778
41808
|
position: relative;
|
|
41779
41809
|
}
|
|
41780
41810
|
|
|
@@ -41826,6 +41856,15 @@ const css$16 = /* css */`.navi_route_travel {
|
|
|
41826
41856
|
overflow: clip;
|
|
41827
41857
|
}
|
|
41828
41858
|
|
|
41859
|
+
& > [data-route-row-pane] > [data-route-row-neighbour] {
|
|
41860
|
+
contain: layout paint;
|
|
41861
|
+
visibility: visible;
|
|
41862
|
+
flex-direction: column;
|
|
41863
|
+
display: flex;
|
|
41864
|
+
position: absolute;
|
|
41865
|
+
inset: 0;
|
|
41866
|
+
}
|
|
41867
|
+
|
|
41829
41868
|
& > [data-route-row-live] {
|
|
41830
41869
|
flex-direction: column;
|
|
41831
41870
|
grid-row: 1;
|
|
@@ -41858,6 +41897,7 @@ const SET_OFF_PULL = 16;
|
|
|
41858
41897
|
* routes?: Array<object|{route: object, params?: object}>,
|
|
41859
41898
|
* travelByDrag?: boolean,
|
|
41860
41899
|
* onTravel?: (detail: {route: object, params: object|undefined, cause: string}) => void|Promise<void>,
|
|
41900
|
+
* renderNeighbour?: (page: {route: object, params: object|undefined}) => import("preact").ComponentChildren,
|
|
41861
41901
|
* }>}
|
|
41862
41902
|
* @param {Array<object|{route: object, params?: object}>} [props.routes] - a window
|
|
41863
41903
|
* over something longer, in order. Read from the <Route> children by default,
|
|
@@ -41874,6 +41914,13 @@ const SET_OFF_PULL = 16;
|
|
|
41874
41914
|
* of the page under six entries. A tab pressed goes the way its <Link> says —
|
|
41875
41915
|
* `<Link replace>` for a row of tabs, so a press and a swipe towards the same
|
|
41876
41916
|
* neighbour write the same history.
|
|
41917
|
+
* @param {(page: {route: object, params: object|undefined}) => import("preact").ComponentChildren} [props.renderNeighbour]
|
|
41918
|
+
* - what stands in the pane of a page next to the one on screen, until the hand
|
|
41919
|
+
* has pulled far enough to bring that page: its background, its skeleton, what the
|
|
41920
|
+
* list already knows. A `<Route>` page already built shows itself. Receives
|
|
41921
|
+
* `{ route, params }`, or the entry of `routes` as it was given, and is a column
|
|
41922
|
+
* the height of the row, as the page is. Its route does not match while it stands
|
|
41923
|
+
* there: what it reads is not asked for.
|
|
41877
41924
|
*
|
|
41878
41925
|
* Every other prop lands on the box itself (`id`, `data-testid`, `className`, …).
|
|
41879
41926
|
* The box has to outlive every page of its row: around those <Route>s, or around
|
|
@@ -41889,6 +41936,7 @@ const RouteTravel = ({
|
|
|
41889
41936
|
replace: true,
|
|
41890
41937
|
routeTransition: "none"
|
|
41891
41938
|
}),
|
|
41939
|
+
renderNeighbour,
|
|
41892
41940
|
className,
|
|
41893
41941
|
children,
|
|
41894
41942
|
...rest
|
|
@@ -41949,9 +41997,7 @@ const RouteTravel = ({
|
|
|
41949
41997
|
travelling: false,
|
|
41950
41998
|
pictures: new Map(),
|
|
41951
41999
|
resumeScrollRecording: null,
|
|
41952
|
-
scrollsDocument:
|
|
41953
|
-
includeHidden: true
|
|
41954
|
-
}) === document.documentElement,
|
|
42000
|
+
scrollsDocument: rowFollowsDocument(row),
|
|
41955
42001
|
...fields
|
|
41956
42002
|
};
|
|
41957
42003
|
movementRef.current = movement;
|
|
@@ -42287,6 +42333,30 @@ const RouteTravel = ({
|
|
|
42287
42333
|
Promise.resolve().then(endMovement);
|
|
42288
42334
|
}
|
|
42289
42335
|
}, [currentIndex]);
|
|
42336
|
+
|
|
42337
|
+
// A neighbour shows from the first frame the compositor moves the row, before
|
|
42338
|
+
// any scroll event: a finger landing is the last word before that.
|
|
42339
|
+
const paintsNeighbours = Boolean(renderNeighbour);
|
|
42340
|
+
useLayoutEffect(() => {
|
|
42341
|
+
if (!paintsNeighbours) {
|
|
42342
|
+
return undefined;
|
|
42343
|
+
}
|
|
42344
|
+
const row = rowRef.current;
|
|
42345
|
+
const onTouchStart = () => {
|
|
42346
|
+
if (!movementRef.current && rowFollowsDocument(row)) {
|
|
42347
|
+
row.style.setProperty("--navi-route-row-pin", `${pinOf(row)}px`);
|
|
42348
|
+
}
|
|
42349
|
+
};
|
|
42350
|
+
row.addEventListener("touchstart", onTouchStart, {
|
|
42351
|
+
passive: true
|
|
42352
|
+
});
|
|
42353
|
+
return () => {
|
|
42354
|
+
row.removeEventListener("touchstart", onTouchStart);
|
|
42355
|
+
};
|
|
42356
|
+
}, [paintsNeighbours]);
|
|
42357
|
+
const rowContext = useMemo(() => ({
|
|
42358
|
+
renderNeighbour
|
|
42359
|
+
}), [renderNeighbour]);
|
|
42290
42360
|
const rowKind = pages.length < 2 && windowed ? "still" : travelByDrag ? "" : "code";
|
|
42291
42361
|
return jsx("div", {
|
|
42292
42362
|
...rest,
|
|
@@ -42299,12 +42369,20 @@ const RouteTravel = ({
|
|
|
42299
42369
|
,
|
|
42300
42370
|
"data-travel-by-drag": travelByDrag && rowKind !== "still" ? "x" : undefined,
|
|
42301
42371
|
children: windowed ? jsxs(Fragment, {
|
|
42302
|
-
children: [pages.map((page, index) =>
|
|
42303
|
-
|
|
42304
|
-
|
|
42305
|
-
|
|
42306
|
-
|
|
42307
|
-
|
|
42372
|
+
children: [pages.map((page, index) => {
|
|
42373
|
+
const holdsNeighbour = paintsNeighbours && isNeighbourPane(index, liveIndex, movementRef.current);
|
|
42374
|
+
return jsx("div", {
|
|
42375
|
+
"data-route-row-pane": "",
|
|
42376
|
+
inert: holdsNeighbour,
|
|
42377
|
+
style: {
|
|
42378
|
+
gridColumn: index + 1
|
|
42379
|
+
},
|
|
42380
|
+
children: holdsNeighbour && jsx(RouteRowNeighbour, {
|
|
42381
|
+
renderNeighbour: renderNeighbour,
|
|
42382
|
+
page: page
|
|
42383
|
+
})
|
|
42384
|
+
}, index);
|
|
42385
|
+
}), jsx("div", {
|
|
42308
42386
|
ref: liveRef,
|
|
42309
42387
|
"data-route-row-live": "",
|
|
42310
42388
|
style: {
|
|
@@ -42316,13 +42394,25 @@ const RouteTravel = ({
|
|
|
42316
42394
|
"data-route-row-pictures": ""
|
|
42317
42395
|
})]
|
|
42318
42396
|
}) : jsx(RouteRowContext.Provider, {
|
|
42319
|
-
value:
|
|
42397
|
+
value: rowContext,
|
|
42320
42398
|
children: children
|
|
42321
42399
|
})
|
|
42322
42400
|
})
|
|
42323
42401
|
});
|
|
42324
42402
|
};
|
|
42325
42403
|
|
|
42404
|
+
// The panes on each side of the live page. Not one holding a picture of the page
|
|
42405
|
+
// left there: a page with no background of its own would show it through.
|
|
42406
|
+
const isNeighbourPane = (index, liveIndex, movement) => {
|
|
42407
|
+
if (index !== liveIndex - 1 && index !== liveIndex + 1) {
|
|
42408
|
+
return false;
|
|
42409
|
+
}
|
|
42410
|
+
return !movement || !movement.pictures.has(index);
|
|
42411
|
+
};
|
|
42412
|
+
const rowFollowsDocument = row => getScrollContainer(row.parentElement, {
|
|
42413
|
+
includeHidden: true
|
|
42414
|
+
}) === document.documentElement;
|
|
42415
|
+
|
|
42326
42416
|
// How far down the row the reader is looking, for a page brought in: a page on
|
|
42327
42417
|
// screen scrolls with the document, and one arriving has to start from there.
|
|
42328
42418
|
const pinOf = row => {
|
|
@@ -58059,6 +58149,10 @@ const SLIDE_TOWARD_ATTRIBUTE = "data-slide-travel-toward";
|
|
|
58059
58149
|
// one: a hand on a row the browser scrolls can carry it past several slides, and
|
|
58060
58150
|
// what follows it goes on between the two it is standing between.
|
|
58061
58151
|
const SLIDE_BASE_ATTRIBUTE = "data-slide-travel-base";
|
|
58152
|
+
// The slide the row is on its way to while the current one has not changed yet,
|
|
58153
|
+
// because that only happens at rest: nothing is rendered and no address is written
|
|
58154
|
+
// under a snap, and what says where one is should not wait for it.
|
|
58155
|
+
const SLIDE_HEADING_ATTRIBUTE = "data-slide-heading";
|
|
58062
58156
|
// Every way out that would DO something right now, in the words the commands
|
|
58063
58157
|
// use: a direction ("left", "right", "up", "down") when there is a slide that
|
|
58064
58158
|
// way, plus "first" and "last" when one is not already standing at that end of
|
|
@@ -58093,9 +58187,16 @@ const wordsOf = (element, attribute) => {
|
|
|
58093
58187
|
return value ? value.split(" ") : NO_WAYS;
|
|
58094
58188
|
};
|
|
58095
58189
|
|
|
58190
|
+
// The slide to say one is on: for whatever tells the reader where they are, as
|
|
58191
|
+
// opposed to data-slide-current, which is what a travel departs from.
|
|
58192
|
+
const readSlideOnScreen = (element) =>
|
|
58193
|
+
element.getAttribute(SLIDE_HEADING_ATTRIBUTE) ??
|
|
58194
|
+
element.getAttribute(SLIDE_CURRENT_ATTRIBUTE) ??
|
|
58195
|
+
undefined;
|
|
58196
|
+
|
|
58096
58197
|
const readSlideContainerState = (element) => ({
|
|
58097
58198
|
known: true,
|
|
58098
|
-
current: element
|
|
58199
|
+
current: readSlideOnScreen(element),
|
|
58099
58200
|
toward: element.getAttribute(SLIDE_TOWARD_ATTRIBUTE) ?? undefined,
|
|
58100
58201
|
// In DOM order — which is the order of the WALK for a line, and not
|
|
58101
58202
|
// necessarily for a map: there the order is the one the areas are written in
|
|
@@ -58133,11 +58234,14 @@ const sameSlideContainerState = (a, b) =>
|
|
|
58133
58234
|
* can: (wayOut: "left"|"right"|"up"|"down"|"first"|"last") => boolean,
|
|
58134
58235
|
* held: (wayOut: "left"|"right"|"up"|"down"|"first"|"last") => boolean,
|
|
58135
58236
|
* }} where the box stands. `current` is the slide on screen — the one being
|
|
58136
|
-
* travelled TO while a travel plays,
|
|
58237
|
+
* travelled TO while a travel plays, and the one the row is going to once a hand
|
|
58238
|
+
* has let go, because that is what one is looking at. It can come before the
|
|
58239
|
+
* slide's own signal and `onCurrentChange`, which wait for the row to rest.
|
|
58137
58240
|
* `toward` is the other slide in the frame while the picture is between two,
|
|
58138
|
-
* and nothing at rest. `can` is "asking for it would do something",
|
|
58139
|
-
*
|
|
58140
|
-
* only the second is worth a word to
|
|
58241
|
+
* and nothing at rest. `can` is "asking for it would do something", from the
|
|
58242
|
+
* slide a travel would depart from, `held` is "it is there and this slide says
|
|
58243
|
+
* no" — a way out is dead in both cases, and only the second is worth a word to
|
|
58244
|
+
* the reader.
|
|
58141
58245
|
* `known` is false until the box has been read: no box was named and none is
|
|
58142
58246
|
* above, the id names nothing, or — for one commit — this mounted before the
|
|
58143
58247
|
* box had painted. Until then `can` answers YES, because it is the answer that
|
|
@@ -58991,7 +59095,7 @@ const Nav = ({
|
|
|
58991
59095
|
}
|
|
58992
59096
|
slideContainerElementRef.current = containerElement;
|
|
58993
59097
|
const readContainer = () => {
|
|
58994
|
-
setCurrentSlideArea(containerElement
|
|
59098
|
+
setCurrentSlideArea(readSlideOnScreen(containerElement));
|
|
58995
59099
|
paintIndicatorGeometryRef.current();
|
|
58996
59100
|
scheduleTabScrollSyncRef.current();
|
|
58997
59101
|
};
|
|
@@ -70051,6 +70155,20 @@ const SlideContainer = ({
|
|
|
70051
70155
|
const paintCurrentArea = area => {
|
|
70052
70156
|
containerRef.current?.setAttribute(SLIDE_CURRENT_ATTRIBUTE, area);
|
|
70053
70157
|
};
|
|
70158
|
+
|
|
70159
|
+
// Where the row is going, for as long as the current slide has not changed:
|
|
70160
|
+
// anything saying where one is reads this first (see readSlideOnScreen). Left to
|
|
70161
|
+
// the caller to announce, a landing having more to say in the same breath.
|
|
70162
|
+
const writeHeading = headingElement => {
|
|
70163
|
+
const containerEl = containerRef.current;
|
|
70164
|
+
const area = headingElement ? readArea(headingElement) : null;
|
|
70165
|
+
// A window does not change slide, it rolls: it has nowhere to be heading.
|
|
70166
|
+
if (loop || area === null || area === containerEl.getAttribute(SLIDE_CURRENT_ATTRIBUTE)) {
|
|
70167
|
+
containerEl.removeAttribute(SLIDE_HEADING_ATTRIBUTE);
|
|
70168
|
+
return;
|
|
70169
|
+
}
|
|
70170
|
+
containerEl.setAttribute(SLIDE_HEADING_ATTRIBUTE, area);
|
|
70171
|
+
};
|
|
70054
70172
|
const markAnswered = area => {
|
|
70055
70173
|
const order = readMap().slideElements.map(readArea);
|
|
70056
70174
|
const rank = order.indexOf(area);
|
|
@@ -70256,6 +70374,10 @@ const SlideContainer = ({
|
|
|
70256
70374
|
slideElements[0];
|
|
70257
70375
|
const currentArea = readArea(currentElement);
|
|
70258
70376
|
paintCurrentArea(currentArea);
|
|
70377
|
+
// In the commit the slide changes in, so nothing reads the slide left in between.
|
|
70378
|
+
if (!handMovingRef.current) {
|
|
70379
|
+
writeHeading(null);
|
|
70380
|
+
}
|
|
70259
70381
|
const realPlaceOf = area => placeOf.get(area) || {
|
|
70260
70382
|
x: 0,
|
|
70261
70383
|
y: 0
|
|
@@ -70288,6 +70410,8 @@ const SlideContainer = ({
|
|
|
70288
70410
|
const drawnArea = stage ? stage.area : drawnAreaRef.current;
|
|
70289
70411
|
const travelStarts = !still && durationMs > 0 && drawnArea !== undefined && drawnArea !== currentArea && slideElements.some(slideElement => readArea(slideElement) === drawnArea);
|
|
70290
70412
|
if (travelStarts) {
|
|
70413
|
+
// Asked for over a row still snapping: the travel is what one will see.
|
|
70414
|
+
writeHeading(null);
|
|
70291
70415
|
// Where the slide being left IS — the place the stage gave it if a travel
|
|
70292
70416
|
// was already playing (a press landing mid-travel departs from where the
|
|
70293
70417
|
// eye is, not from the map), its own place otherwise.
|
|
@@ -71054,7 +71178,9 @@ const SlideContainer = ({
|
|
|
71054
71178
|
// Where a hand has the row, in the terms of --slide-travel-progress: from the
|
|
71055
71179
|
// current slide while it stands next to it, and past that between the two it
|
|
71056
71180
|
// stands between, as far as the hand carries it.
|
|
71057
|
-
const paintNativeRow = (
|
|
71181
|
+
const paintNativeRow = ({
|
|
71182
|
+
finger
|
|
71183
|
+
}) => {
|
|
71058
71184
|
if (trackAnimationRef.current?.playState === "running") {
|
|
71059
71185
|
return;
|
|
71060
71186
|
}
|
|
@@ -71066,6 +71192,9 @@ const SlideContainer = ({
|
|
|
71066
71192
|
}
|
|
71067
71193
|
if (restsOn(containerEl, currentElement)) {
|
|
71068
71194
|
if (handMovingRef.current) {
|
|
71195
|
+
if (!finger) {
|
|
71196
|
+
writeHeading(null);
|
|
71197
|
+
}
|
|
71069
71198
|
paintTravelProgress();
|
|
71070
71199
|
}
|
|
71071
71200
|
return;
|
|
@@ -71086,6 +71215,12 @@ const SlideContainer = ({
|
|
|
71086
71215
|
}
|
|
71087
71216
|
element.style.setProperty("--slide-travel-progress", forward ? -fraction : fraction);
|
|
71088
71217
|
}
|
|
71218
|
+
// Nothing will say when a trackpad's fingers leave, and a long stroke would
|
|
71219
|
+
// keep the first tab lit for the whole trip: the nearest slide answers. A finger
|
|
71220
|
+
// has a lift to wait for (headNativeRow), and until then the slide held stands.
|
|
71221
|
+
if (!finger) {
|
|
71222
|
+
writeHeading(fraction >= 0.5 && toward ? toward : base);
|
|
71223
|
+
}
|
|
71089
71224
|
paintTravelToward(toward ? readArea(toward) : null);
|
|
71090
71225
|
// What the hand reaches ahead of the neighbours built at rest is asked for on
|
|
71091
71226
|
// the way: an empty slide goes by otherwise.
|
|
@@ -71093,6 +71228,28 @@ const SlideContainer = ({
|
|
|
71093
71228
|
alongside: true
|
|
71094
71229
|
});
|
|
71095
71230
|
};
|
|
71231
|
+
|
|
71232
|
+
// A finger has lifted and the row moves: on past the slide it stands after, or
|
|
71233
|
+
// back to it. Already standing on one, it has arrived, whichever way it came.
|
|
71234
|
+
const headNativeRow = movedForward => {
|
|
71235
|
+
if (!handMovingRef.current || trackAnimationRef.current?.playState === "running") {
|
|
71236
|
+
return;
|
|
71237
|
+
}
|
|
71238
|
+
const slideElements = Array.from(trackRef.current.children);
|
|
71239
|
+
const currentElement = slideElements.find(slideElement => slideElement.hasAttribute("data-current"));
|
|
71240
|
+
if (!currentElement) {
|
|
71241
|
+
return;
|
|
71242
|
+
}
|
|
71243
|
+
const {
|
|
71244
|
+
base,
|
|
71245
|
+
toward,
|
|
71246
|
+
fraction,
|
|
71247
|
+
forward
|
|
71248
|
+
} = readRowStretch(containerRef.current, slideElements, currentElement);
|
|
71249
|
+
const goesOn = fraction > 0 && movedForward === forward;
|
|
71250
|
+
writeHeading(goesOn && toward ? toward : base);
|
|
71251
|
+
announceState();
|
|
71252
|
+
};
|
|
71096
71253
|
const landNativeRow = scrollEndEvent => {
|
|
71097
71254
|
if (!handMovingRef.current) {
|
|
71098
71255
|
return;
|
|
@@ -71107,13 +71264,15 @@ const SlideContainer = ({
|
|
|
71107
71264
|
return;
|
|
71108
71265
|
}
|
|
71109
71266
|
handMovingRef.current = false;
|
|
71110
|
-
paintTravelProgress();
|
|
71111
71267
|
const area = readArea(landedElement);
|
|
71112
71268
|
const currentArea = containerEl.getAttribute(SLIDE_CURRENT_ATTRIBUTE);
|
|
71113
71269
|
if (area === currentArea) {
|
|
71270
|
+
writeHeading(null);
|
|
71271
|
+
paintTravelProgress();
|
|
71114
71272
|
settleTravel();
|
|
71115
71273
|
return;
|
|
71116
71274
|
}
|
|
71275
|
+
paintTravelProgress();
|
|
71117
71276
|
const event = scrollEndEvent ?? new Event("scrollend");
|
|
71118
71277
|
if (loop) {
|
|
71119
71278
|
// A window does not change slide, it rolls: back at rest in the render the
|
|
@@ -71144,6 +71303,8 @@ const SlideContainer = ({
|
|
|
71144
71303
|
}
|
|
71145
71304
|
// Refused: the row is put back in view of the slide that stays.
|
|
71146
71305
|
handLandedRef.current = null;
|
|
71306
|
+
writeHeading(null);
|
|
71307
|
+
announceState();
|
|
71147
71308
|
const currentElement = slideElements.find(slideElement => slideElement.hasAttribute("data-current"));
|
|
71148
71309
|
containerEl.scrollTo({
|
|
71149
71310
|
left: currentElement.offsetLeft,
|
|
@@ -71157,11 +71318,13 @@ const SlideContainer = ({
|
|
|
71157
71318
|
const nativeRowHandlersRef = useRef(null);
|
|
71158
71319
|
nativeRowHandlersRef.current = {
|
|
71159
71320
|
paintNativeRow,
|
|
71321
|
+
headNativeRow,
|
|
71160
71322
|
landNativeRow
|
|
71161
71323
|
};
|
|
71162
71324
|
useLayoutEffect(() => {
|
|
71163
71325
|
return watchRowScroll(containerRef.current, {
|
|
71164
|
-
onScroll:
|
|
71326
|
+
onScroll: move => nativeRowHandlersRef.current.paintNativeRow(move),
|
|
71327
|
+
onLeftToSnap: forward => nativeRowHandlersRef.current.headNativeRow(forward),
|
|
71165
71328
|
onLand: event => nativeRowHandlersRef.current.landNativeRow(event)
|
|
71166
71329
|
});
|
|
71167
71330
|
}, []);
|
|
@@ -84981,7 +85144,7 @@ const css$w = /* css */`@property --list-group-label-height {
|
|
|
84981
85144
|
overflow: clip;
|
|
84982
85145
|
}
|
|
84983
85146
|
|
|
84984
|
-
.navi_list_container[data-horizontal]:not([data-scroller], [data-overflow-visible]) > .navi_list_scroll_container > .navi_list:not([navi-box-flow="grid"]) {
|
|
85147
|
+
.navi_list_container[data-horizontal]:not([data-scroller], [data-overflow-visible], [data-flex-wrap]) > .navi_list_scroll_container > .navi_list:not([navi-box-flow="grid"]) {
|
|
84985
85148
|
width: min-content;
|
|
84986
85149
|
min-width: 100%;
|
|
84987
85150
|
}
|
|
@@ -85542,7 +85705,7 @@ const ListUI = props => {
|
|
|
85542
85705
|
// rule (min-content, never narrower than its box — see the css), which
|
|
85543
85706
|
// already gives it what expandX asks. An inline width from expandX would beat
|
|
85544
85707
|
// that rule and lay the end room among the items again.
|
|
85545
|
-
const trackSizedByItsRule = horizontal && !scrollerAttribute && !overflowVisibleAttribute && !(columns || itemColumns);
|
|
85708
|
+
const trackSizedByItsRule = horizontal && !scrollerAttribute && !overflowVisibleAttribute && !rest.flexWrap && !(columns || itemColumns);
|
|
85546
85709
|
return jsx(Box, {
|
|
85547
85710
|
...rest,
|
|
85548
85711
|
ref: ref,
|
|
@@ -85553,6 +85716,7 @@ const ListUI = props => {
|
|
|
85553
85716
|
"data-borderless": isBorderless(rest) ? "" : undefined,
|
|
85554
85717
|
"data-scroller": scrollerAttribute,
|
|
85555
85718
|
"data-overflow-visible": overflowVisibleAttribute,
|
|
85719
|
+
"data-flex-wrap": rest.flexWrap ? "" : undefined,
|
|
85556
85720
|
"navi-hover-while-scrolling": hoverWhileScrolling ? "" : undefined,
|
|
85557
85721
|
"data-expand-x": expandX || expand ? "" : undefined,
|
|
85558
85722
|
"data-expand-y": expandY || expand ? "" : undefined,
|
|
@@ -86425,6 +86589,12 @@ const useListScrollSync = ({
|
|
|
86425
86589
|
// (pour l'instant pas grave car on travaille pour le mode select qui fermera le dialog au select)
|
|
86426
86590
|
const topMatchScoresKeyRef = useRef("");
|
|
86427
86591
|
const restoreScrollRafRef = useRef(null);
|
|
86592
|
+
// The frame reads the list's ref, which an unmount empties.
|
|
86593
|
+
useLayoutEffect(() => {
|
|
86594
|
+
return () => {
|
|
86595
|
+
cancelAnimationFrame(restoreScrollRafRef.current);
|
|
86596
|
+
};
|
|
86597
|
+
}, []);
|
|
86428
86598
|
useLayoutEffect(() => {
|
|
86429
86599
|
const listScrollContainerEl = ref.current ? getScroller() : null;
|
|
86430
86600
|
if (!listScrollContainerEl) {
|
|
@@ -86463,10 +86633,9 @@ const useListScrollSync = ({
|
|
|
86463
86633
|
// based on virtual item height which can wrongly restore the scroll.
|
|
86464
86634
|
// However we have a contract with outside to inside which item is scrolled
|
|
86465
86635
|
// (used by keyboard nav to enable anchoring the item for list item nav with arrow keys)
|
|
86466
|
-
// so we do our best to give that item back
|
|
86467
|
-
|
|
86468
|
-
|
|
86469
|
-
} = getScrollInfo({
|
|
86636
|
+
// so we do our best to give that item back: there is none to give when
|
|
86637
|
+
// the list has no visible part, and the restore happens all the same.
|
|
86638
|
+
const scrollInfo = getScrollInfo({
|
|
86470
86639
|
scrollValues: savedScroll,
|
|
86471
86640
|
scrollerEl: listScrollContainerEl,
|
|
86472
86641
|
listEl: getListEl(),
|
|
@@ -86482,7 +86651,7 @@ const useListScrollSync = ({
|
|
|
86482
86651
|
});
|
|
86483
86652
|
const listEl = getListEl();
|
|
86484
86653
|
dispatchPublicCustomEvent(listEl, "navi_scroll", {
|
|
86485
|
-
item,
|
|
86654
|
+
item: scrollInfo?.item,
|
|
86486
86655
|
event: new CustomEvent("navi_scroll_restore")
|
|
86487
86656
|
});
|
|
86488
86657
|
});
|