@jsenv/navi 0.29.64 → 0.29.66
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 +829 -97
- package/dist/jsenv_navi.js.map +17 -16
- package/docs/AI_INSTRUCTIONS.md +6 -0
- package/docs/navigation.md +6 -0
- package/docs/route_transitions.md +129 -0
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -38,7 +38,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
38
38
|
* any of these, and a number is the last resort, not the first tool.
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
const css$
|
|
41
|
+
const css$12 = /* css */`
|
|
42
42
|
@layer navi {
|
|
43
43
|
:root {
|
|
44
44
|
/* A control that overlaps its neighbours (the members of a Group share
|
|
@@ -90,7 +90,7 @@ const css$11 = /* css */`
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
`;
|
|
93
|
-
import.meta.css = [css$
|
|
93
|
+
import.meta.css = [css$12, "@jsenv/navi/src/navi_z_indexes.js"];
|
|
94
94
|
|
|
95
95
|
const addIntoArray = (array, ...valuesToAdd) => {
|
|
96
96
|
if (valuesToAdd.length === 1) {
|
|
@@ -359,7 +359,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
359
359
|
* the very first render and the browser does everything on its own.
|
|
360
360
|
*/
|
|
361
361
|
const URL_TARGET_ATTRIBUTE = "data-url-target";
|
|
362
|
-
const css$
|
|
362
|
+
const css$11 = /* css */`
|
|
363
363
|
@layer navi {
|
|
364
364
|
[${URL_TARGET_ATTRIBUTE}] {
|
|
365
365
|
animation: navi_url_target var(--navi-url-target-duration, 2000ms)
|
|
@@ -377,7 +377,7 @@ const css$10 = /* css */`
|
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
`;
|
|
380
|
-
import.meta.css = [css$
|
|
380
|
+
import.meta.css = [css$11, "@jsenv/navi/src/nav/url_target/url_target.js"];
|
|
381
381
|
let urlTargetOptions = {
|
|
382
382
|
block: "center",
|
|
383
383
|
behavior: "smooth",
|
|
@@ -7753,7 +7753,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
7753
7753
|
* - Arrow automatically shows when pointing at a valid anchor element
|
|
7754
7754
|
* - Centers in viewport when no anchor element provided or anchor is too big
|
|
7755
7755
|
*/
|
|
7756
|
-
const css
|
|
7756
|
+
const css$10 = /* css */`
|
|
7757
7757
|
@layer navi {
|
|
7758
7758
|
.navi_callout {
|
|
7759
7759
|
/* A callout is parented to what it explains, so it inherits from it — and
|
|
@@ -7996,7 +7996,7 @@ const openCallout = (message, {
|
|
|
7996
7996
|
skipFocus = false,
|
|
7997
7997
|
debug = () => {}
|
|
7998
7998
|
} = {}) => {
|
|
7999
|
-
import.meta.css = [css
|
|
7999
|
+
import.meta.css = [css$10, "@jsenv/navi/src/control/rules/callout/callout.js"];
|
|
8000
8000
|
if (debug === true) {
|
|
8001
8001
|
debug = (e, ...args) => console.debug(`"${e.type}" -> `, ...args);
|
|
8002
8002
|
}
|
|
@@ -20118,7 +20118,7 @@ const setupNetworkMonitoring = () => {
|
|
|
20118
20118
|
};
|
|
20119
20119
|
setupNetworkMonitoring();
|
|
20120
20120
|
|
|
20121
|
-
installImportMetaCssBuild(import.meta);const css
|
|
20121
|
+
installImportMetaCssBuild(import.meta);const css$$ = /* css */`
|
|
20122
20122
|
.navi_loading_indicator_fluid_container {
|
|
20123
20123
|
position: relative;
|
|
20124
20124
|
display: flex;
|
|
@@ -20150,7 +20150,7 @@ const LoadingIndicatorFluid = ({
|
|
|
20150
20150
|
visuallyHidden,
|
|
20151
20151
|
...rest
|
|
20152
20152
|
}) => {
|
|
20153
|
-
import.meta.css = [css
|
|
20153
|
+
import.meta.css = [css$$, "@jsenv/navi/src/graphic/loading/loading_indicator_fluid.jsx"];
|
|
20154
20154
|
const ref = useRef(null);
|
|
20155
20155
|
// The container dimensions can be deduced from the ref itself as the indicator is absolute inset 0
|
|
20156
20156
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
@@ -20355,7 +20355,7 @@ const LoadingRectangleSvg = ({
|
|
|
20355
20355
|
});
|
|
20356
20356
|
};
|
|
20357
20357
|
|
|
20358
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
20358
|
+
installImportMetaCssBuild(import.meta);const css$_ = /* css */`
|
|
20359
20359
|
.navi_loading_outline_wrapper {
|
|
20360
20360
|
position: absolute;
|
|
20361
20361
|
/* Controls place the outline slightly outside their box, right on top of
|
|
@@ -20392,7 +20392,7 @@ installImportMetaCssBuild(import.meta);const css$Z = /* css */`
|
|
|
20392
20392
|
}
|
|
20393
20393
|
`;
|
|
20394
20394
|
const LoadingOutline = props => {
|
|
20395
|
-
import.meta.css = [css$
|
|
20395
|
+
import.meta.css = [css$_, "@jsenv/navi/src/graphic/loading/loading_outline.jsx"];
|
|
20396
20396
|
if (props.containerRef) {
|
|
20397
20397
|
const container = props.containerRef.current;
|
|
20398
20398
|
if (!container) {
|
|
@@ -20682,7 +20682,7 @@ const selectByTextStrings = (element, range, startText, endText) => {
|
|
|
20682
20682
|
};
|
|
20683
20683
|
|
|
20684
20684
|
installImportMetaCssBuild(import.meta);// https://jsfiddle.net/v5xzJ/4/
|
|
20685
|
-
const css$
|
|
20685
|
+
const css$Z = /* css */`
|
|
20686
20686
|
@layer navi {
|
|
20687
20687
|
.navi_text {
|
|
20688
20688
|
&[data-skeleton] {
|
|
@@ -21188,7 +21188,7 @@ const TextShrinkWrap = props => {
|
|
|
21188
21188
|
});
|
|
21189
21189
|
};
|
|
21190
21190
|
const TextUI = props => {
|
|
21191
|
-
import.meta.css = [css$
|
|
21191
|
+
import.meta.css = [css$Z, "@jsenv/navi/src/text/text.jsx"];
|
|
21192
21192
|
let {
|
|
21193
21193
|
ref,
|
|
21194
21194
|
spacing,
|
|
@@ -27266,7 +27266,7 @@ const getAssociatedLabels = element => {
|
|
|
27266
27266
|
return Array.from(element.labels);
|
|
27267
27267
|
};
|
|
27268
27268
|
|
|
27269
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
27269
|
+
installImportMetaCssBuild(import.meta);const css$Y = /* css */`
|
|
27270
27270
|
@layer navi {
|
|
27271
27271
|
.navi_button {
|
|
27272
27272
|
--button-border-radius: var(--navi-control-border-radius);
|
|
@@ -27697,7 +27697,7 @@ installImportMetaCssBuild(import.meta);const css$X = /* css */`
|
|
|
27697
27697
|
}
|
|
27698
27698
|
`;
|
|
27699
27699
|
const ButtonUI = props => {
|
|
27700
|
-
import.meta.css = [css$
|
|
27700
|
+
import.meta.css = [css$Y, "@jsenv/navi/src/control/input/button_ui.jsx"];
|
|
27701
27701
|
const {
|
|
27702
27702
|
ref,
|
|
27703
27703
|
// href/link
|
|
@@ -29551,7 +29551,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
29551
29551
|
* reaches the real container.
|
|
29552
29552
|
*/
|
|
29553
29553
|
let openLocalDialogCount = 0;
|
|
29554
|
-
const css$
|
|
29554
|
+
const css$X = /* css */`
|
|
29555
29555
|
@layer navi {
|
|
29556
29556
|
.navi_dialog {
|
|
29557
29557
|
/* Min gap between the dialog and the edges of its container. Written
|
|
@@ -29897,9 +29897,12 @@ const css$W = /* css */`
|
|
|
29897
29897
|
backdrop-filter: none;
|
|
29898
29898
|
}
|
|
29899
29899
|
|
|
29900
|
+
/* overlay is a no-op here (this backdrop is a plain div, never a
|
|
29901
|
+
top-layer element) but stays in the list so all four transition lists in
|
|
29902
|
+
these files agree — display and overlay always travel together. */
|
|
29900
29903
|
&[navi-animation] {
|
|
29901
29904
|
opacity: 1;
|
|
29902
|
-
transition-property: display, opacity;
|
|
29905
|
+
transition-property: display, overlay, opacity;
|
|
29903
29906
|
transition-duration: var(--popup-animation-duration);
|
|
29904
29907
|
transition-timing-function: ease;
|
|
29905
29908
|
transition-behavior: allow-discrete;
|
|
@@ -30071,7 +30074,7 @@ const css$W = /* css */`
|
|
|
30071
30074
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
30072
30075
|
*/
|
|
30073
30076
|
const Dialog = props => {
|
|
30074
|
-
import.meta.css = [css$
|
|
30077
|
+
import.meta.css = [css$X, "@jsenv/navi/src/layout/dialog.jsx"];
|
|
30075
30078
|
if (props.openController) {
|
|
30076
30079
|
return jsx(ControlledDialog, {
|
|
30077
30080
|
...props
|
|
@@ -31027,7 +31030,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
31027
31030
|
* and applied.
|
|
31028
31031
|
*/
|
|
31029
31032
|
let openLocalPopoverCount = 0;
|
|
31030
|
-
const css$
|
|
31033
|
+
const css$W = /* css */`
|
|
31031
31034
|
@layer navi {
|
|
31032
31035
|
.navi_popover {
|
|
31033
31036
|
/* soft: user-configurable preferred max-height. Kept as a *default*
|
|
@@ -31305,12 +31308,16 @@ const css$V = /* css */`
|
|
|
31305
31308
|
/* navi-animation mirrors the content popover's own resolved value (set
|
|
31306
31309
|
imperatively in openEffect) — the backdrop only ever fades, regardless
|
|
31307
31310
|
of which kind it is (translate/scale wouldn't mean anything on it).
|
|
31308
|
-
display
|
|
31309
|
-
reason popup_css.js's own .navi_popover rule includes
|
|
31310
|
-
file's top comment.
|
|
31311
|
+
display and overlay are included alongside opacity (+ allow-discrete)
|
|
31312
|
+
for the same reason popup_css.js's own .navi_popover rule includes them
|
|
31313
|
+
— see this file's top comment. They go together: display keeps the
|
|
31314
|
+
backdrop rendered during the exit, overlay keeps it in the top layer
|
|
31315
|
+
(hidePopover() is called synchronously, so without it the backdrop is
|
|
31316
|
+
evicted immediately and, being z-index: unset, loses to FixedBar and to
|
|
31317
|
+
any positioned element later in DOM order for the whole fade). */
|
|
31311
31318
|
&[navi-animation] {
|
|
31312
31319
|
opacity: 1;
|
|
31313
|
-
transition-property: display, opacity;
|
|
31320
|
+
transition-property: display, overlay, opacity;
|
|
31314
31321
|
transition-duration: var(--popup-animation-duration);
|
|
31315
31322
|
transition-timing-function: ease;
|
|
31316
31323
|
transition-behavior: allow-discrete;
|
|
@@ -31460,7 +31467,7 @@ const css$V = /* css */`
|
|
|
31460
31467
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
31461
31468
|
*/
|
|
31462
31469
|
const Popover = props => {
|
|
31463
|
-
import.meta.css = [css$
|
|
31470
|
+
import.meta.css = [css$W, "@jsenv/navi/src/layout/popover.jsx"];
|
|
31464
31471
|
if (props.openController) {
|
|
31465
31472
|
return jsx(ControlledPopover, {
|
|
31466
31473
|
...props
|
|
@@ -32479,7 +32486,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
32479
32486
|
* event, and a caller replacing the body entirely then has one protocol to
|
|
32480
32487
|
* follow — `--navi-confirm` for yes, anything that closes for no.
|
|
32481
32488
|
*/
|
|
32482
|
-
const css$
|
|
32489
|
+
const css$V = /* css */`
|
|
32483
32490
|
/* The width lives on the body rather than on the popup, so that custom
|
|
32484
32491
|
content (which replaces this body entirely) sizes itself instead of
|
|
32485
32492
|
inheriting a ceiling meant for a sentence-long question. */
|
|
@@ -32616,7 +32623,7 @@ const ConfirmPopup = ({
|
|
|
32616
32623
|
onAnswer,
|
|
32617
32624
|
onClosed
|
|
32618
32625
|
}) => {
|
|
32619
|
-
import.meta.css = [css$
|
|
32626
|
+
import.meta.css = [css$V, "@jsenv/navi/src/action/confirm_popup.jsx"];
|
|
32620
32627
|
const {
|
|
32621
32628
|
mode,
|
|
32622
32629
|
confirmLabel,
|
|
@@ -32700,7 +32707,7 @@ const defaultBody = (message, {
|
|
|
32700
32707
|
});
|
|
32701
32708
|
};
|
|
32702
32709
|
|
|
32703
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
32710
|
+
installImportMetaCssBuild(import.meta);const css$U = /* css */`
|
|
32704
32711
|
.action_error {
|
|
32705
32712
|
margin-top: 0;
|
|
32706
32713
|
margin-bottom: 20px;
|
|
@@ -32725,7 +32732,7 @@ const ActionRenderer = ({
|
|
|
32725
32732
|
children,
|
|
32726
32733
|
disabled
|
|
32727
32734
|
}) => {
|
|
32728
|
-
import.meta.css = [css$
|
|
32735
|
+
import.meta.css = [css$U, "@jsenv/navi/src/action/action_renderer.jsx"];
|
|
32729
32736
|
if (action === undefined) {
|
|
32730
32737
|
throw new Error("ActionRenderer requires an action to render, but none was provided.");
|
|
32731
32738
|
}
|
|
@@ -36799,7 +36806,7 @@ const ensureDocumentStartViewTransition = () => {
|
|
|
36799
36806
|
startViewTransitionPolyfill.isPolyfill = true;
|
|
36800
36807
|
document.startViewTransition = startViewTransitionPolyfill;
|
|
36801
36808
|
}
|
|
36802
|
-
return startViewTransition$
|
|
36809
|
+
return startViewTransition$2;
|
|
36803
36810
|
};
|
|
36804
36811
|
|
|
36805
36812
|
// A transition a finger is holding still (see route_travel.jsx): it has to be
|
|
@@ -36821,7 +36828,7 @@ const holdViewTransition = (release) => {
|
|
|
36821
36828
|
};
|
|
36822
36829
|
};
|
|
36823
36830
|
|
|
36824
|
-
const startViewTransition$
|
|
36831
|
+
const startViewTransition$2 = (updateCallback) => {
|
|
36825
36832
|
if (releaseHeldViewTransition) {
|
|
36826
36833
|
const release = releaseHeldViewTransition;
|
|
36827
36834
|
releaseHeldViewTransition = null;
|
|
@@ -38309,6 +38316,787 @@ const RouteUI = ({
|
|
|
38309
38316
|
return element;
|
|
38310
38317
|
};
|
|
38311
38318
|
|
|
38319
|
+
/**
|
|
38320
|
+
* The document's rendering, held for the one frame a view transition needs.
|
|
38321
|
+
*
|
|
38322
|
+
* The browser does not take the picture of the page being left when a
|
|
38323
|
+
* transition is ASKED for — it takes it at the next frame, just before running
|
|
38324
|
+
* the update callback. Preact renders sooner than that, in a microtask: so a
|
|
38325
|
+
* change nobody asked for (a tab pressed, the back button) has already reached
|
|
38326
|
+
* the DOM when the picture is taken, and the picture is of the page ARRIVING.
|
|
38327
|
+
* Both sides of the animation then show it, and one watches a page slide onto
|
|
38328
|
+
* itself.
|
|
38329
|
+
*
|
|
38330
|
+
* So what Preact has queued waits until the update callback, which is the
|
|
38331
|
+
* moment the API is built around — the change belongs inside it. The whole
|
|
38332
|
+
* document is held: it is about to be frozen under a picture anyway.
|
|
38333
|
+
*
|
|
38334
|
+
* ONE hold for the whole document, whoever animates. The hold is a wrapper
|
|
38335
|
+
* around Preact's `options.debounceRendering`, and two of them installed
|
|
38336
|
+
* independently restore each other in the wrong order when they let go — every
|
|
38337
|
+
* render queued in between is then handed to a wrapper nobody will ever
|
|
38338
|
+
* release. Everything that photographs a navigation (RouteTravel's box, a
|
|
38339
|
+
* route transition) must therefore hold through this module, never through a
|
|
38340
|
+
* wrapper of its own.
|
|
38341
|
+
*/
|
|
38342
|
+
|
|
38343
|
+
|
|
38344
|
+
let renderingHold = null;
|
|
38345
|
+
const holdRendering = () => {
|
|
38346
|
+
if (renderingHold) {
|
|
38347
|
+
return renderingHold.release;
|
|
38348
|
+
}
|
|
38349
|
+
const debounceRenderingBefore = options.debounceRendering;
|
|
38350
|
+
const hold = {
|
|
38351
|
+
render: null,
|
|
38352
|
+
release: () => {
|
|
38353
|
+
// Only the hold that is still standing may be given back: a holder
|
|
38354
|
+
// releasing after another has taken over must not let go of what it
|
|
38355
|
+
// does not hold.
|
|
38356
|
+
if (renderingHold !== hold) {
|
|
38357
|
+
return;
|
|
38358
|
+
}
|
|
38359
|
+
renderingHold = null;
|
|
38360
|
+
options.debounceRendering = debounceRenderingBefore;
|
|
38361
|
+
const { render } = hold;
|
|
38362
|
+
hold.render = null;
|
|
38363
|
+
if (render) {
|
|
38364
|
+
render();
|
|
38365
|
+
}
|
|
38366
|
+
},
|
|
38367
|
+
};
|
|
38368
|
+
renderingHold = hold;
|
|
38369
|
+
options.debounceRendering = (render) => {
|
|
38370
|
+
hold.render = render;
|
|
38371
|
+
};
|
|
38372
|
+
return hold.release;
|
|
38373
|
+
};
|
|
38374
|
+
|
|
38375
|
+
// The hold a navigation takes on its way in — from before its first write,
|
|
38376
|
+
// because by the time a route announces that it matches, Preact has already
|
|
38377
|
+
// been told and the render is queued; a hold taken then is a hold taken too
|
|
38378
|
+
// late. Kept here until whoever animates the change takes it over, or the
|
|
38379
|
+
// navigation turns out to be one nobody animates.
|
|
38380
|
+
let routingRenderingHold = null;
|
|
38381
|
+
const holdRenderingForRouting = () => {
|
|
38382
|
+
routingRenderingHold = holdRendering();
|
|
38383
|
+
};
|
|
38384
|
+
// Nobody had a picture to take: a page held for a change it does not animate
|
|
38385
|
+
// is a page that stutters for nothing.
|
|
38386
|
+
const releaseRoutingRenderingHold = () => {
|
|
38387
|
+
const release = routingRenderingHold;
|
|
38388
|
+
routingRenderingHold = null;
|
|
38389
|
+
if (release) {
|
|
38390
|
+
release();
|
|
38391
|
+
}
|
|
38392
|
+
};
|
|
38393
|
+
// An animator takes the navigation's hold as its own — taking another would be
|
|
38394
|
+
// taking a hold on a page that is holding still — or takes a fresh one when
|
|
38395
|
+
// the change it animates is not a navigation.
|
|
38396
|
+
const takeoverRoutingRenderingHold = () => {
|
|
38397
|
+
const release = routingRenderingHold || holdRendering();
|
|
38398
|
+
routingRenderingHold = null;
|
|
38399
|
+
return release;
|
|
38400
|
+
};
|
|
38401
|
+
|
|
38402
|
+
installImportMetaCssBuild(import.meta);/**
|
|
38403
|
+
* How two routes move against each other, said one relation at a time —
|
|
38404
|
+
* without putting them in a row, and without a box in the tree.
|
|
38405
|
+
*
|
|
38406
|
+
* A page one goes INTO (a game, a profile, a place) is entered from wherever
|
|
38407
|
+
* one opened it, and left back out the same way. That is a fact about a PAIR
|
|
38408
|
+
* of pages, and only about the pairs it is written for:
|
|
38409
|
+
*
|
|
38410
|
+
* defineRouteTransition(MY_GAMES_PAGE, GAME_PAGE, "slide-x");
|
|
38411
|
+
* defineRouteTransition(RADAR_PAGE, GAME_PAGE, "slide-x");
|
|
38412
|
+
*
|
|
38413
|
+
* Going from the first page to the second plays forward, the reverse plays
|
|
38414
|
+
* back, and two pages never written in the same relation play nothing between
|
|
38415
|
+
* each other — two tabs of a bottom bar are side by side, neither is before
|
|
38416
|
+
* the other, and being animated by the same mechanism does not order them.
|
|
38417
|
+
* This is what tells this apart from <RouteTravel>: a travel box is a ROW — a
|
|
38418
|
+
* total order, plus a drag gesture that walks it — while this declares
|
|
38419
|
+
* individual relations and nothing else.
|
|
38420
|
+
*
|
|
38421
|
+
* A relation is reciprocal by DEFAULT, not by decree: the way back is the same
|
|
38422
|
+
* movement run the other way, because that is what lets a user build a map of
|
|
38423
|
+
* the app — but a relation written for the exact way travelled wins over being
|
|
38424
|
+
* the reverse of another, so B → A can be given a movement of its own, or
|
|
38425
|
+
* silenced with "none", by writing it (see findRelation).
|
|
38426
|
+
*
|
|
38427
|
+
* The relation says WHEN something plays and which way; the transition says
|
|
38428
|
+
* WHAT plays — a movement navi ships, or a name the application defines in its
|
|
38429
|
+
* own CSS (see the JSDoc below). Said without one, the relation plays the
|
|
38430
|
+
* browser's cross-fade.
|
|
38431
|
+
*
|
|
38432
|
+
* There is no box in the tree: by default what animates is the document itself
|
|
38433
|
+
* (its `root` view transition group), which is right for pages that ARE the
|
|
38434
|
+
* whole viewport. An application whose pages live between fixed bars marks the
|
|
38435
|
+
* region they live in with `data-navi-route-transition-area` — one attribute
|
|
38436
|
+
* on an element it already has — and the movement then plays on that region's
|
|
38437
|
+
* own pictures, clipped at its bounds, while the bars simply never move (see
|
|
38438
|
+
* TRANSITION_AREA_ATTRIBUTE for why the root pictures cannot do this job).
|
|
38439
|
+
*
|
|
38440
|
+
* The URL leads and the picture follows, as everywhere in navi: the change is
|
|
38441
|
+
* a navigation somebody else started (a <Link>, the back button), this only
|
|
38442
|
+
* watches it land and photographs the page being left in time (see
|
|
38443
|
+
* rendering_hold.js for how the picture is kept honest). A browser without
|
|
38444
|
+
* view transitions navigates without the movement.
|
|
38445
|
+
*
|
|
38446
|
+
* However many relations are defined, there is ONE watcher: every definition
|
|
38447
|
+
* lands in a shared registry, and the watcher is rebuilt over the whole of it
|
|
38448
|
+
* — a navigation is a single fact about the document, and the first relation
|
|
38449
|
+
* that speaks about it answers for it.
|
|
38450
|
+
*/
|
|
38451
|
+
const startViewTransition$1 = ensureDocumentStartViewTransition();
|
|
38452
|
+
const TRANSITION_ATTRIBUTE = "data-navi-route-transition";
|
|
38453
|
+
const TRANSITION_TYPE_ATTRIBUTE = "data-navi-route-transition-type";
|
|
38454
|
+
const TRANSITION_DURATION_PROPERTY = "--navi-route-transition-duration";
|
|
38455
|
+
// What the movement is played on. The root snapshot spans the viewport, and
|
|
38456
|
+
// the regions of elements captured on their own (a named bar) are BLANK in it
|
|
38457
|
+
// — a page sliding vertically then drags a blank band across the screen where
|
|
38458
|
+
// the top bar was. An application with fixed bars therefore marks the region
|
|
38459
|
+
// its pages live in with this attribute: the marked element is captured on its
|
|
38460
|
+
// own, the movement plays on ITS pictures, clipped at its bounds, and the bars
|
|
38461
|
+
// simply never move. Without the mark the document itself travels, which is
|
|
38462
|
+
// right for a page that IS the whole viewport.
|
|
38463
|
+
const TRANSITION_AREA_ATTRIBUTE = "data-navi-route-transition-area";
|
|
38464
|
+
const TRANSITION_TARGET_ATTRIBUTE = "data-navi-route-transition-target";
|
|
38465
|
+
const AREA_NAME = "navi-route-transition";
|
|
38466
|
+
// route_travel.jsx wears this on the root for the length of one of its
|
|
38467
|
+
// travels (its TRAVEL_ATTRIBUTE — a comment there mirrors this one). Read by
|
|
38468
|
+
// name rather than imported: importing route_travel.jsx would pull the whole
|
|
38469
|
+
// travel machinery into an application that only defines transitions.
|
|
38470
|
+
const ROUTE_TRAVEL_ATTRIBUTE = "data-navi-route-travel";
|
|
38471
|
+
|
|
38472
|
+
// The same movements, written once and played on either target: the document,
|
|
38473
|
+
// or the marked area. The guard keeps the two exclusive — with an area marked,
|
|
38474
|
+
// the root pictures must NOT move (they carry the whole viewport, blank bands
|
|
38475
|
+
// included).
|
|
38476
|
+
const movementsCSS = (name, guard) => /* css */`
|
|
38477
|
+
:root${guard} {
|
|
38478
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="slide-x"],
|
|
38479
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="slide-y"],
|
|
38480
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="cover-x"],
|
|
38481
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="cover-y"] {
|
|
38482
|
+
&::view-transition-old(${name}),
|
|
38483
|
+
&::view-transition-new(${name}) {
|
|
38484
|
+
/* The default cross-fade, dropped: two pages sliding past each other
|
|
38485
|
+
are two solid things, and seeing through one to the other says they
|
|
38486
|
+
are the same page changing its mind. */
|
|
38487
|
+
mix-blend-mode: normal;
|
|
38488
|
+
animation-timing-function: ease;
|
|
38489
|
+
animation-fill-mode: both;
|
|
38490
|
+
}
|
|
38491
|
+
}
|
|
38492
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="slide-x"] {
|
|
38493
|
+
&[${TRANSITION_ATTRIBUTE}="forward"] {
|
|
38494
|
+
&::view-transition-old(${name}) {
|
|
38495
|
+
animation-name: navi-route-transition-leave-towards-start;
|
|
38496
|
+
}
|
|
38497
|
+
&::view-transition-new(${name}) {
|
|
38498
|
+
animation-name: navi-route-transition-enter-from-end;
|
|
38499
|
+
}
|
|
38500
|
+
}
|
|
38501
|
+
&[${TRANSITION_ATTRIBUTE}="back"] {
|
|
38502
|
+
&::view-transition-old(${name}) {
|
|
38503
|
+
animation-name: navi-route-transition-leave-towards-end;
|
|
38504
|
+
}
|
|
38505
|
+
&::view-transition-new(${name}) {
|
|
38506
|
+
animation-name: navi-route-transition-enter-from-start;
|
|
38507
|
+
}
|
|
38508
|
+
}
|
|
38509
|
+
}
|
|
38510
|
+
/* The same four movements, along the other axis: the start of a column is
|
|
38511
|
+
its top, so going forward there is the page rising and the next one
|
|
38512
|
+
coming up from below. */
|
|
38513
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="slide-y"] {
|
|
38514
|
+
&[${TRANSITION_ATTRIBUTE}="forward"] {
|
|
38515
|
+
&::view-transition-old(${name}) {
|
|
38516
|
+
animation-name: navi-route-transition-leave-towards-top;
|
|
38517
|
+
}
|
|
38518
|
+
&::view-transition-new(${name}) {
|
|
38519
|
+
animation-name: navi-route-transition-enter-from-bottom;
|
|
38520
|
+
}
|
|
38521
|
+
}
|
|
38522
|
+
&[${TRANSITION_ATTRIBUTE}="back"] {
|
|
38523
|
+
&::view-transition-old(${name}) {
|
|
38524
|
+
animation-name: navi-route-transition-leave-towards-bottom;
|
|
38525
|
+
}
|
|
38526
|
+
&::view-transition-new(${name}) {
|
|
38527
|
+
animation-name: navi-route-transition-enter-from-top;
|
|
38528
|
+
}
|
|
38529
|
+
}
|
|
38530
|
+
}
|
|
38531
|
+
/* One page over the other, the way a sheet covers a desk: the page
|
|
38532
|
+
arriving slides in ON TOP of one that does not move, and going back it
|
|
38533
|
+
slides off, uncovering it. The still page is animated all the same — to
|
|
38534
|
+
a keyframe that goes nowhere — because left to the browser it would
|
|
38535
|
+
fade. */
|
|
38536
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="cover-x"] {
|
|
38537
|
+
&[${TRANSITION_ATTRIBUTE}="forward"] {
|
|
38538
|
+
&::view-transition-old(${name}) {
|
|
38539
|
+
animation-name: navi-route-transition-still;
|
|
38540
|
+
}
|
|
38541
|
+
&::view-transition-new(${name}) {
|
|
38542
|
+
animation-name: navi-route-transition-enter-from-end;
|
|
38543
|
+
}
|
|
38544
|
+
}
|
|
38545
|
+
&[${TRANSITION_ATTRIBUTE}="back"] {
|
|
38546
|
+
&::view-transition-old(${name}) {
|
|
38547
|
+
/* The page leaving is the cover: it must slide off ABOVE the one it
|
|
38548
|
+
uncovers, against the browser's default of drawing the new page
|
|
38549
|
+
on top. */
|
|
38550
|
+
z-index: 1;
|
|
38551
|
+
animation-name: navi-route-transition-leave-towards-end;
|
|
38552
|
+
}
|
|
38553
|
+
&::view-transition-new(${name}) {
|
|
38554
|
+
animation-name: navi-route-transition-still;
|
|
38555
|
+
}
|
|
38556
|
+
}
|
|
38557
|
+
}
|
|
38558
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="cover-y"] {
|
|
38559
|
+
&[${TRANSITION_ATTRIBUTE}="forward"] {
|
|
38560
|
+
&::view-transition-old(${name}) {
|
|
38561
|
+
animation-name: navi-route-transition-still;
|
|
38562
|
+
}
|
|
38563
|
+
&::view-transition-new(${name}) {
|
|
38564
|
+
animation-name: navi-route-transition-enter-from-bottom;
|
|
38565
|
+
}
|
|
38566
|
+
}
|
|
38567
|
+
&[${TRANSITION_ATTRIBUTE}="back"] {
|
|
38568
|
+
&::view-transition-old(${name}) {
|
|
38569
|
+
z-index: 1;
|
|
38570
|
+
animation-name: navi-route-transition-leave-towards-bottom;
|
|
38571
|
+
}
|
|
38572
|
+
&::view-transition-new(${name}) {
|
|
38573
|
+
animation-name: navi-route-transition-still;
|
|
38574
|
+
}
|
|
38575
|
+
}
|
|
38576
|
+
}
|
|
38577
|
+
/* Going deeper is coming closer: the page arriving lands from slightly too
|
|
38578
|
+
big, and going back it is the page leaving that grows away. The other
|
|
38579
|
+
side keeps the browser's own fade under it. */
|
|
38580
|
+
&[${TRANSITION_TYPE_ATTRIBUTE}="zoom"] {
|
|
38581
|
+
&::view-transition-old(${name}),
|
|
38582
|
+
&::view-transition-new(${name}) {
|
|
38583
|
+
animation-fill-mode: both;
|
|
38584
|
+
}
|
|
38585
|
+
&[${TRANSITION_ATTRIBUTE}="forward"] {
|
|
38586
|
+
&::view-transition-new(${name}) {
|
|
38587
|
+
animation-name: navi-route-transition-zoom-in;
|
|
38588
|
+
}
|
|
38589
|
+
}
|
|
38590
|
+
&[${TRANSITION_ATTRIBUTE}="back"] {
|
|
38591
|
+
&::view-transition-old(${name}) {
|
|
38592
|
+
animation-name: navi-route-transition-zoom-out;
|
|
38593
|
+
}
|
|
38594
|
+
}
|
|
38595
|
+
}
|
|
38596
|
+
}
|
|
38597
|
+
`;
|
|
38598
|
+
const css$T = /* css */`
|
|
38599
|
+
/* The marked region is a picture of its own during every view transition of
|
|
38600
|
+
the document — which is what keeps it out of the root snapshot, where its
|
|
38601
|
+
place would be blank. */
|
|
38602
|
+
[${TRANSITION_AREA_ATTRIBUTE}] {
|
|
38603
|
+
view-transition-name: ${AREA_NAME};
|
|
38604
|
+
}
|
|
38605
|
+
|
|
38606
|
+
/* Only while a transition of OURS is playing: everything below changes how
|
|
38607
|
+
the document animates, and the document belongs to the application the
|
|
38608
|
+
rest of the time. The duration is written here, on the direction alone, so
|
|
38609
|
+
a relation with no type — the browser's cross-fade — answers to
|
|
38610
|
+
--navi-route-transition-duration like every other. */
|
|
38611
|
+
:root[${TRANSITION_ATTRIBUTE}] {
|
|
38612
|
+
&::view-transition-old(root),
|
|
38613
|
+
&::view-transition-new(root),
|
|
38614
|
+
&::view-transition-old(${AREA_NAME}),
|
|
38615
|
+
&::view-transition-new(${AREA_NAME}) {
|
|
38616
|
+
animation-duration: var(${TRANSITION_DURATION_PROPERTY}, 300ms);
|
|
38617
|
+
}
|
|
38618
|
+
|
|
38619
|
+
/* The pages are cut at the edge of the area they move in: its pictures are
|
|
38620
|
+
drawn in the top layer, above the bars, and a page sliding in would
|
|
38621
|
+
otherwise be seen crossing them. */
|
|
38622
|
+
&::view-transition-group(${AREA_NAME}),
|
|
38623
|
+
&::view-transition-image-pair(${AREA_NAME}) {
|
|
38624
|
+
overflow: clip;
|
|
38625
|
+
}
|
|
38626
|
+
}
|
|
38627
|
+
|
|
38628
|
+
${movementsCSS("root", `:not([${TRANSITION_TARGET_ATTRIBUTE}])`)}
|
|
38629
|
+
${movementsCSS(AREA_NAME, `[${TRANSITION_TARGET_ATTRIBUTE}="area"]`)}
|
|
38630
|
+
|
|
38631
|
+
@keyframes navi-route-transition-leave-towards-start {
|
|
38632
|
+
to {
|
|
38633
|
+
translate: -100% 0;
|
|
38634
|
+
}
|
|
38635
|
+
}
|
|
38636
|
+
@keyframes navi-route-transition-enter-from-end {
|
|
38637
|
+
from {
|
|
38638
|
+
translate: 100% 0;
|
|
38639
|
+
}
|
|
38640
|
+
}
|
|
38641
|
+
@keyframes navi-route-transition-leave-towards-end {
|
|
38642
|
+
to {
|
|
38643
|
+
translate: 100% 0;
|
|
38644
|
+
}
|
|
38645
|
+
}
|
|
38646
|
+
@keyframes navi-route-transition-enter-from-start {
|
|
38647
|
+
from {
|
|
38648
|
+
translate: -100% 0;
|
|
38649
|
+
}
|
|
38650
|
+
}
|
|
38651
|
+
@keyframes navi-route-transition-leave-towards-top {
|
|
38652
|
+
to {
|
|
38653
|
+
translate: 0 -100%;
|
|
38654
|
+
}
|
|
38655
|
+
}
|
|
38656
|
+
@keyframes navi-route-transition-enter-from-bottom {
|
|
38657
|
+
from {
|
|
38658
|
+
translate: 0 100%;
|
|
38659
|
+
}
|
|
38660
|
+
}
|
|
38661
|
+
@keyframes navi-route-transition-leave-towards-bottom {
|
|
38662
|
+
to {
|
|
38663
|
+
translate: 0 100%;
|
|
38664
|
+
}
|
|
38665
|
+
}
|
|
38666
|
+
@keyframes navi-route-transition-enter-from-top {
|
|
38667
|
+
from {
|
|
38668
|
+
translate: 0 -100%;
|
|
38669
|
+
}
|
|
38670
|
+
}
|
|
38671
|
+
@keyframes navi-route-transition-zoom-in {
|
|
38672
|
+
from {
|
|
38673
|
+
opacity: 0;
|
|
38674
|
+
scale: 1.1;
|
|
38675
|
+
}
|
|
38676
|
+
}
|
|
38677
|
+
@keyframes navi-route-transition-zoom-out {
|
|
38678
|
+
to {
|
|
38679
|
+
opacity: 0;
|
|
38680
|
+
scale: 1.1;
|
|
38681
|
+
}
|
|
38682
|
+
}
|
|
38683
|
+
/* Standing still, said as an animation: naming it replaces the browser's own
|
|
38684
|
+
fade on that side, which is the whole point. */
|
|
38685
|
+
@keyframes navi-route-transition-still {
|
|
38686
|
+
to {
|
|
38687
|
+
translate: 0 0;
|
|
38688
|
+
}
|
|
38689
|
+
}
|
|
38690
|
+
`;
|
|
38691
|
+
|
|
38692
|
+
/**
|
|
38693
|
+
* Declare how a pair of routes moves against each other.
|
|
38694
|
+
*
|
|
38695
|
+
* @param {object} from - a route, or `{ route, params }` when the page is a
|
|
38696
|
+
* param of a route rather than a route of its own.
|
|
38697
|
+
* @param {object} to - same forms. Going from `from` to `to` plays forward,
|
|
38698
|
+
* the reverse plays back — unless the reverse is written as a relation of
|
|
38699
|
+
* its own, which then owns that way (a movement of its own, or `"none"` for
|
|
38700
|
+
* a plain cut). A change between two pages no relation was written for plays
|
|
38701
|
+
* nothing.
|
|
38702
|
+
* @param {string|{type?: string, duration?: number|string}} [transition] -
|
|
38703
|
+
* what plays: a type name, or `{ type, duration }` to also say how long
|
|
38704
|
+
* (`--navi-route-transition-duration` says it for everyone otherwise).
|
|
38705
|
+
* Omitted, the browser's own cross-fade. Shipped with navi:
|
|
38706
|
+
* - `"slide-x"`, `"slide-y"`: the two pages slide past each other, forward
|
|
38707
|
+
* towards the start of the axis;
|
|
38708
|
+
* - `"cover-x"`, `"cover-y"`: the page arriving slides in OVER one that does
|
|
38709
|
+
* not move, and slides off it on the way back;
|
|
38710
|
+
* - `"zoom"`: the deeper page is the closer one — it lands from slightly too
|
|
38711
|
+
* big, and grows away when left;
|
|
38712
|
+
* - `"none"`: nothing, said out loud — written on one way of a pair, it cuts
|
|
38713
|
+
* where the reverse of the other way (or the default) would have played;
|
|
38714
|
+
* - `"cross-fade"`: the omitted case, nameable — so one way of a pair can
|
|
38715
|
+
* fade while the other way moves.
|
|
38716
|
+
* Every type plays on the document, or on the element marked
|
|
38717
|
+
* `data-navi-route-transition-area` when the application has one (see the
|
|
38718
|
+
* top of this file). Any other name belongs to the application: for the
|
|
38719
|
+
* length of the transition the root carries
|
|
38720
|
+
* `data-navi-route-transition-type="<type>"` next to
|
|
38721
|
+
* `data-navi-route-transition="forward"|"back"`, and the application's CSS
|
|
38722
|
+
* defines the movement against the view transition pseudo-elements:
|
|
38723
|
+
*
|
|
38724
|
+
* :root[data-navi-route-transition-type="spin"][data-navi-route-transition="forward"] {
|
|
38725
|
+
* &::view-transition-new(root) {
|
|
38726
|
+
* animation-name: my-spin-in;
|
|
38727
|
+
* }
|
|
38728
|
+
* }
|
|
38729
|
+
* @returns {() => void} remove this relation.
|
|
38730
|
+
*/
|
|
38731
|
+
const defineRouteTransition = (from, to, transition) => {
|
|
38732
|
+
import.meta.css = [css$T, "@jsenv/navi/src/nav/route_transition.js"];
|
|
38733
|
+
const {
|
|
38734
|
+
type,
|
|
38735
|
+
duration
|
|
38736
|
+
} = normalizeTransition(transition);
|
|
38737
|
+
const relation = {
|
|
38738
|
+
from: normalizePage$1(from),
|
|
38739
|
+
to: normalizePage$1(to),
|
|
38740
|
+
type,
|
|
38741
|
+
duration
|
|
38742
|
+
};
|
|
38743
|
+
relations.push(relation);
|
|
38744
|
+
rebuildWatcher();
|
|
38745
|
+
updateRoutingObservers();
|
|
38746
|
+
return () => {
|
|
38747
|
+
const index = relations.indexOf(relation);
|
|
38748
|
+
if (index > -1) {
|
|
38749
|
+
relations.splice(index, 1);
|
|
38750
|
+
rebuildWatcher();
|
|
38751
|
+
updateRoutingObservers();
|
|
38752
|
+
}
|
|
38753
|
+
};
|
|
38754
|
+
};
|
|
38755
|
+
|
|
38756
|
+
/**
|
|
38757
|
+
* What plays on a navigation no relation was written for: every route change
|
|
38758
|
+
* then plays this transition, and the written relations keep their own.
|
|
38759
|
+
*
|
|
38760
|
+
* A default has no direction — nothing says which of two arbitrary pages is
|
|
38761
|
+
* "before" the other — so give it a movement that does not need one:
|
|
38762
|
+
* `"cross-fade"`, or a custom type whose CSS is keyed on the type alone.
|
|
38763
|
+
*
|
|
38764
|
+
* @param {string|{type?: string, duration?: number|string}} transition - same
|
|
38765
|
+
* forms as defineRouteTransition's. `"none"` (or removing the default) puts
|
|
38766
|
+
* the silence back.
|
|
38767
|
+
* @returns {() => void} remove this default.
|
|
38768
|
+
*/
|
|
38769
|
+
const defineRouteDefaultTransition = transition => {
|
|
38770
|
+
import.meta.css = [css$T, "@jsenv/navi/src/nav/route_transition.js"];
|
|
38771
|
+
const value = normalizeTransition(transition);
|
|
38772
|
+
defaultTransition = value;
|
|
38773
|
+
updateRoutingObservers();
|
|
38774
|
+
return () => {
|
|
38775
|
+
if (defaultTransition === value) {
|
|
38776
|
+
defaultTransition = null;
|
|
38777
|
+
updateRoutingObservers();
|
|
38778
|
+
}
|
|
38779
|
+
};
|
|
38780
|
+
};
|
|
38781
|
+
|
|
38782
|
+
// "cross-fade" is a name for what plays when nothing is asked for — the
|
|
38783
|
+
// browser's own animation — so it normalizes to asking for nothing. Having the
|
|
38784
|
+
// name lets one way of a pair say it out loud while the other way slides.
|
|
38785
|
+
const normalizeTransition = transition => {
|
|
38786
|
+
const {
|
|
38787
|
+
type,
|
|
38788
|
+
duration
|
|
38789
|
+
} = typeof transition === "string" ? {
|
|
38790
|
+
type: transition
|
|
38791
|
+
} : transition || {};
|
|
38792
|
+
return {
|
|
38793
|
+
type: type === "cross-fade" ? undefined : type,
|
|
38794
|
+
duration
|
|
38795
|
+
};
|
|
38796
|
+
};
|
|
38797
|
+
|
|
38798
|
+
// Every relation defined, and the single watcher standing over all of them.
|
|
38799
|
+
const relations = [];
|
|
38800
|
+
let watcher = null;
|
|
38801
|
+
const rebuildWatcher = () => {
|
|
38802
|
+
if (watcher) {
|
|
38803
|
+
watcher.stop();
|
|
38804
|
+
watcher = null;
|
|
38805
|
+
}
|
|
38806
|
+
if (relations.length === 0) {
|
|
38807
|
+
return;
|
|
38808
|
+
}
|
|
38809
|
+
// Every page any relation mentions, each once: the position of the current
|
|
38810
|
+
// page in this list is what turns "some signal moved" into "the document
|
|
38811
|
+
// went from page A to page B".
|
|
38812
|
+
const pages = [];
|
|
38813
|
+
for (const {
|
|
38814
|
+
from,
|
|
38815
|
+
to
|
|
38816
|
+
} of relations) {
|
|
38817
|
+
if (pageIndexOf$1(pages, from) === -1) {
|
|
38818
|
+
pages.push(from);
|
|
38819
|
+
}
|
|
38820
|
+
if (pageIndexOf$1(pages, to) === -1) {
|
|
38821
|
+
pages.push(to);
|
|
38822
|
+
}
|
|
38823
|
+
}
|
|
38824
|
+
const currentIndexSignal = computed(() => currentPageIndex$1(pages));
|
|
38825
|
+
let currentIndex;
|
|
38826
|
+
let firstReading = true;
|
|
38827
|
+
const onMove = index => {
|
|
38828
|
+
const fromIndex = currentIndex;
|
|
38829
|
+
currentIndex = index;
|
|
38830
|
+
if (firstReading) {
|
|
38831
|
+
// Where the document already is — nothing changed, there is nothing to
|
|
38832
|
+
// animate. Also the first reading after a definition landed mid-life:
|
|
38833
|
+
// the watcher is standing again on whatever page is current.
|
|
38834
|
+
firstReading = false;
|
|
38835
|
+
return;
|
|
38836
|
+
}
|
|
38837
|
+
if (index === -1 || fromIndex === -1 || fromIndex === index) {
|
|
38838
|
+
return;
|
|
38839
|
+
}
|
|
38840
|
+
const found = findRelation(pages[fromIndex], pages[index]);
|
|
38841
|
+
if (!found) {
|
|
38842
|
+
// No relation says anything about these two: they are side by side, and
|
|
38843
|
+
// silence is the fact — not a missing case.
|
|
38844
|
+
return;
|
|
38845
|
+
}
|
|
38846
|
+
const {
|
|
38847
|
+
direction,
|
|
38848
|
+
relation
|
|
38849
|
+
} = found;
|
|
38850
|
+
if (relation.type === "none") {
|
|
38851
|
+
// Silence said out loud: this way of the pair was written to play
|
|
38852
|
+
// nothing, where the reverse of the other way — or the default — would
|
|
38853
|
+
// have played.
|
|
38854
|
+
navigationAnimated = true;
|
|
38855
|
+
return;
|
|
38856
|
+
}
|
|
38857
|
+
beginTransition({
|
|
38858
|
+
page: pages[index],
|
|
38859
|
+
direction,
|
|
38860
|
+
type: relation.type,
|
|
38861
|
+
duration: relation.duration
|
|
38862
|
+
});
|
|
38863
|
+
};
|
|
38864
|
+
// `subscribe` rather than `effect`: it hands the value to a callback that is
|
|
38865
|
+
// not being tracked, and starting a view transition releases holds that make
|
|
38866
|
+
// the very signals this is watched through move again.
|
|
38867
|
+
const unsubscribe = currentIndexSignal.subscribe(onMove);
|
|
38868
|
+
watcher = {
|
|
38869
|
+
stop: unsubscribe
|
|
38870
|
+
};
|
|
38871
|
+
};
|
|
38872
|
+
|
|
38873
|
+
// What plays when no relation matched (see defineRouteDefaultTransition), and
|
|
38874
|
+
// whether the navigation now landing found an answer already — a relation's
|
|
38875
|
+
// transition, a "none", a RouteTravel travel. The flag is reset when a
|
|
38876
|
+
// navigation begins, so it is always about the latest one.
|
|
38877
|
+
let defaultTransition = null;
|
|
38878
|
+
let navigationAnimated = false;
|
|
38879
|
+
|
|
38880
|
+
// The two ends of a navigation, watched while there is anyone to animate it.
|
|
38881
|
+
// The picture of the page being left has to be honest, so rendering is held
|
|
38882
|
+
// from before the navigation's first write (see rendering_hold.js) — and given
|
|
38883
|
+
// back at the far end when the change turns out to be one nobody animates,
|
|
38884
|
+
// which is also the one moment the DEFAULT can decide: every relation has had
|
|
38885
|
+
// its say by then.
|
|
38886
|
+
let stopRoutingObservers = null;
|
|
38887
|
+
const updateRoutingObservers = () => {
|
|
38888
|
+
const wanted = relations.length > 0 || defaultTransition !== null;
|
|
38889
|
+
if (wanted && !stopRoutingObservers) {
|
|
38890
|
+
const stopWatchingStart = observeBeforeRouting(() => {
|
|
38891
|
+
navigationAnimated = false;
|
|
38892
|
+
holdRenderingForRouting();
|
|
38893
|
+
});
|
|
38894
|
+
const stopWatchingEnd = observeAfterRouting(() => {
|
|
38895
|
+
if (defaultTransition && defaultTransition.type !== "none" && !navigationAnimated) {
|
|
38896
|
+
beginTransition({
|
|
38897
|
+
page: null,
|
|
38898
|
+
// A default has no direction: nothing says which of two arbitrary
|
|
38899
|
+
// pages is before the other. The attribute is worn empty — present
|
|
38900
|
+
// for whoever keys on "one of ours is playing", silent on the way.
|
|
38901
|
+
direction: "",
|
|
38902
|
+
type: defaultTransition.type,
|
|
38903
|
+
duration: defaultTransition.duration
|
|
38904
|
+
});
|
|
38905
|
+
}
|
|
38906
|
+
releaseRoutingRenderingHold();
|
|
38907
|
+
});
|
|
38908
|
+
stopRoutingObservers = () => {
|
|
38909
|
+
stopWatchingStart();
|
|
38910
|
+
stopWatchingEnd();
|
|
38911
|
+
};
|
|
38912
|
+
return;
|
|
38913
|
+
}
|
|
38914
|
+
if (!wanted && stopRoutingObservers) {
|
|
38915
|
+
stopRoutingObservers();
|
|
38916
|
+
stopRoutingObservers = null;
|
|
38917
|
+
}
|
|
38918
|
+
};
|
|
38919
|
+
|
|
38920
|
+
// The exact way travelled first, over the whole registry, and only then the
|
|
38921
|
+
// reverses: a relation written B → A owns that way, and being the reverse of
|
|
38922
|
+
// one written A → B never outranks it. This is what makes reciprocity a
|
|
38923
|
+
// default rather than a decree — write the way back to give it a movement of
|
|
38924
|
+
// its own, or "none" to silence it.
|
|
38925
|
+
const findRelation = (fromPage, toPage) => {
|
|
38926
|
+
for (const relation of relations) {
|
|
38927
|
+
if (samePage$1(relation.from, fromPage) && samePage$1(relation.to, toPage)) {
|
|
38928
|
+
return {
|
|
38929
|
+
direction: "forward",
|
|
38930
|
+
relation
|
|
38931
|
+
};
|
|
38932
|
+
}
|
|
38933
|
+
}
|
|
38934
|
+
for (const relation of relations) {
|
|
38935
|
+
if (samePage$1(relation.from, toPage) && samePage$1(relation.to, fromPage)) {
|
|
38936
|
+
return {
|
|
38937
|
+
direction: "back",
|
|
38938
|
+
relation
|
|
38939
|
+
};
|
|
38940
|
+
}
|
|
38941
|
+
}
|
|
38942
|
+
return null;
|
|
38943
|
+
};
|
|
38944
|
+
|
|
38945
|
+
// The transition whose direction the document is currently wearing. One per
|
|
38946
|
+
// document, as with view transitions themselves: a new one starting takes the
|
|
38947
|
+
// attributes over, and only their owner may take them off.
|
|
38948
|
+
let currentTransition = null;
|
|
38949
|
+
const beginTransition = ({
|
|
38950
|
+
page,
|
|
38951
|
+
direction,
|
|
38952
|
+
type,
|
|
38953
|
+
duration
|
|
38954
|
+
}) => {
|
|
38955
|
+
navigationAnimated = true;
|
|
38956
|
+
const documentElement = document.documentElement;
|
|
38957
|
+
// One navigation, one animator. A RouteTravel box already travelling this
|
|
38958
|
+
// change owns the document's transition — and possibly a finger; starting
|
|
38959
|
+
// one here on top would skip its pictures mid-slide. A pair of routes must
|
|
38960
|
+
// be animated by RouteTravel or by a route transition, never both.
|
|
38961
|
+
if (documentElement.hasAttribute(ROUTE_TRAVEL_ATTRIBUTE)) {
|
|
38962
|
+
console.warn("A RouteTravel is animating this navigation; the route transition defined between these routes is skipped. Animate a pair of routes with RouteTravel or defineRouteTransition, not both.");
|
|
38963
|
+
return;
|
|
38964
|
+
}
|
|
38965
|
+
const transition = {};
|
|
38966
|
+
currentTransition = transition;
|
|
38967
|
+
documentElement.setAttribute(TRANSITION_ATTRIBUTE, direction);
|
|
38968
|
+
if (type) {
|
|
38969
|
+
documentElement.setAttribute(TRANSITION_TYPE_ATTRIBUTE, type);
|
|
38970
|
+
}
|
|
38971
|
+
// Looked up per transition, not once: the area is the application's own
|
|
38972
|
+
// element and follows its lifecycle — a page layout without bars has none,
|
|
38973
|
+
// and the movement then plays on the document itself.
|
|
38974
|
+
if (document.querySelector(`[${TRANSITION_AREA_ATTRIBUTE}]`)) {
|
|
38975
|
+
documentElement.setAttribute(TRANSITION_TARGET_ATTRIBUTE, "area");
|
|
38976
|
+
}
|
|
38977
|
+
// A duration of this relation's own, worn for the length of the transition —
|
|
38978
|
+
// and whatever the application had written inline put back afterwards, not
|
|
38979
|
+
// erased.
|
|
38980
|
+
let restoreDuration = null;
|
|
38981
|
+
if (duration !== undefined) {
|
|
38982
|
+
const durationBefore = documentElement.style.getPropertyValue(TRANSITION_DURATION_PROPERTY);
|
|
38983
|
+
documentElement.style.setProperty(TRANSITION_DURATION_PROPERTY, typeof duration === "number" ? `${duration}ms` : duration);
|
|
38984
|
+
restoreDuration = () => {
|
|
38985
|
+
if (durationBefore) {
|
|
38986
|
+
documentElement.style.setProperty(TRANSITION_DURATION_PROPERTY, durationBefore);
|
|
38987
|
+
} else {
|
|
38988
|
+
documentElement.style.removeProperty(TRANSITION_DURATION_PROPERTY);
|
|
38989
|
+
}
|
|
38990
|
+
};
|
|
38991
|
+
}
|
|
38992
|
+
const releaseRendering = takeoverRoutingRenderingHold();
|
|
38993
|
+
// Armed from here rather than from inside the callback below: the browser
|
|
38994
|
+
// calls that callback a frame later, and a navigation that has already
|
|
38995
|
+
// been decided renders its page in between — a wait armed then waits for
|
|
38996
|
+
// something that has already happened.
|
|
38997
|
+
const renderWait = armRouteRenderWait$1();
|
|
38998
|
+
const viewTransition = startViewTransition$1(async () => {
|
|
38999
|
+
// The picture the browser is about to take must be of the page that was
|
|
39000
|
+
// asked for, and a route matching is not yet a page rendered. Whatever
|
|
39001
|
+
// is awaited here must be able to resolve without a frame: the document
|
|
39002
|
+
// is frozen for the whole of this callback.
|
|
39003
|
+
try {
|
|
39004
|
+
// Releasing flushes the held render synchronously, so a route that
|
|
39005
|
+
// rendered has already resolved the wait by the next line.
|
|
39006
|
+
releaseRendering();
|
|
39007
|
+
if (page === null) {
|
|
39008
|
+
// A default transition: which page is arriving is unknown, and some
|
|
39009
|
+
// navigations render no route at all (a search param bound to a
|
|
39010
|
+
// signal) — waited on, those would freeze the page until the browser
|
|
39011
|
+
// gives up. The wait is raced with a short timer instead.
|
|
39012
|
+
await Promise.race([renderWait.rendered, waitMs(50)]);
|
|
39013
|
+
} else if (pageIsCurrent$1(page)) {
|
|
39014
|
+
await renderWait.rendered;
|
|
39015
|
+
}
|
|
39016
|
+
} finally {
|
|
39017
|
+
renderWait.stop();
|
|
39018
|
+
}
|
|
39019
|
+
});
|
|
39020
|
+
const end = () => {
|
|
39021
|
+
// Whatever ends it — played out, skipped by another transition starting,
|
|
39022
|
+
// failed before its callback ever ran — the hold is given back and the
|
|
39023
|
+
// document is handed back to the application. Both are idempotent, and
|
|
39024
|
+
// the attributes belong to the LAST transition begun: an earlier one
|
|
39025
|
+
// ending late must not strip what a later one is wearing.
|
|
39026
|
+
renderWait.stop();
|
|
39027
|
+
releaseRendering();
|
|
39028
|
+
if (currentTransition === transition) {
|
|
39029
|
+
currentTransition = null;
|
|
39030
|
+
documentElement.removeAttribute(TRANSITION_ATTRIBUTE);
|
|
39031
|
+
documentElement.removeAttribute(TRANSITION_TYPE_ATTRIBUTE);
|
|
39032
|
+
documentElement.removeAttribute(TRANSITION_TARGET_ATTRIBUTE);
|
|
39033
|
+
if (restoreDuration) {
|
|
39034
|
+
restoreDuration();
|
|
39035
|
+
}
|
|
39036
|
+
}
|
|
39037
|
+
};
|
|
39038
|
+
viewTransition.finished.then(end, end);
|
|
39039
|
+
};
|
|
39040
|
+
|
|
39041
|
+
// A route matching is a signal changing; how many passes Preact takes to
|
|
39042
|
+
// answer it is its own business, and the render is the moment the picture can
|
|
39043
|
+
// be taken. Listening starts before the change, or a render landing while the
|
|
39044
|
+
// change settles is a render nobody heard.
|
|
39045
|
+
const armRouteRenderWait$1 = () => {
|
|
39046
|
+
let stopListening;
|
|
39047
|
+
const rendered = new Promise(resolve => {
|
|
39048
|
+
stopListening = observeRouteRender(resolve);
|
|
39049
|
+
});
|
|
39050
|
+
return {
|
|
39051
|
+
rendered,
|
|
39052
|
+
stop: () => stopListening()
|
|
39053
|
+
};
|
|
39054
|
+
};
|
|
39055
|
+
const waitMs = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
39056
|
+
const normalizePage$1 = page => page.isRoute ? {
|
|
39057
|
+
route: page,
|
|
39058
|
+
params: undefined
|
|
39059
|
+
} : page;
|
|
39060
|
+
|
|
39061
|
+
// Two pages are the same page when they select the same thing, not when they
|
|
39062
|
+
// were written by the same hand.
|
|
39063
|
+
const samePage$1 = (a, b) => {
|
|
39064
|
+
if (a === b) {
|
|
39065
|
+
return true;
|
|
39066
|
+
}
|
|
39067
|
+
if (!a || !b) {
|
|
39068
|
+
return false;
|
|
39069
|
+
}
|
|
39070
|
+
return a.route === b.route && compareTwoJsValues(a.params, b.params);
|
|
39071
|
+
};
|
|
39072
|
+
const pageIndexOf$1 = (pages, page) => pages.findIndex(candidate => samePage$1(candidate, page));
|
|
39073
|
+
|
|
39074
|
+
// Whether this page is the one on screen — same reading as route_travel.jsx's
|
|
39075
|
+
// own: matchingSignal is the necessary condition and is read whatever happens,
|
|
39076
|
+
// params only for a route that matches (the params of a route that does not
|
|
39077
|
+
// match are not params).
|
|
39078
|
+
const pageIsCurrent$1 = ({
|
|
39079
|
+
route,
|
|
39080
|
+
params
|
|
39081
|
+
}) => {
|
|
39082
|
+
if (!route.matchingSignal.value) {
|
|
39083
|
+
return false;
|
|
39084
|
+
}
|
|
39085
|
+
return params ? route.matchesParams(params) : true;
|
|
39086
|
+
};
|
|
39087
|
+
// The FIRST page that answers, and every page read all the same: a page that
|
|
39088
|
+
// is not the current one today is the one that must wake the reader tomorrow.
|
|
39089
|
+
const currentPageIndex$1 = pages => {
|
|
39090
|
+
let currentIndex = -1;
|
|
39091
|
+
for (let i = 0; i < pages.length; i++) {
|
|
39092
|
+
const isCurrent = pageIsCurrent$1(pages[i]);
|
|
39093
|
+
if (isCurrent && currentIndex === -1) {
|
|
39094
|
+
currentIndex = i;
|
|
39095
|
+
}
|
|
39096
|
+
}
|
|
39097
|
+
return currentIndex;
|
|
39098
|
+
};
|
|
39099
|
+
|
|
38312
39100
|
installImportMetaCssBuild(import.meta);/**
|
|
38313
39101
|
* Dragging from one route to the next, when the tabs of a page are URLs.
|
|
38314
39102
|
*
|
|
@@ -38348,6 +39136,10 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
38348
39136
|
*/
|
|
38349
39137
|
const CAN_KEEP_PICTURE = Boolean(document.startViewTransition && !document.startViewTransition.isPolyfill);
|
|
38350
39138
|
const startViewTransition = ensureDocumentStartViewTransition();
|
|
39139
|
+
|
|
39140
|
+
// route_transition.js reads this attribute by name (not imported, see its
|
|
39141
|
+
// ROUTE_TRAVEL_ATTRIBUTE) to refuse animating a navigation a travel already
|
|
39142
|
+
// animates — keep the two in sync.
|
|
38351
39143
|
const TRAVEL_ATTRIBUTE = "data-navi-route-travel";
|
|
38352
39144
|
// Which way the pages move, said on the document: the pictures of a transition
|
|
38353
39145
|
// hang off the root, not off the box that travels, so the box's own `axis` has
|
|
@@ -38847,8 +39639,7 @@ const RouteTravel = ({
|
|
|
38847
39639
|
const rectBefore = elementRef.current.getBoundingClientRect();
|
|
38848
39640
|
// The hold a navigation already took, if this travel is the answer to one:
|
|
38849
39641
|
// taking another would be taking a hold on a page that is holding still.
|
|
38850
|
-
const releaseRendering =
|
|
38851
|
-
renderingHeldForRouting = null;
|
|
39642
|
+
const releaseRendering = takeoverRoutingRenderingHold();
|
|
38852
39643
|
// The picture the browser is about to take must be of the page that was
|
|
38853
39644
|
// asked for, and a route matching is not yet a page rendered. Watched from
|
|
38854
39645
|
// here rather than from inside the callback below: the browser calls that
|
|
@@ -38991,25 +39782,14 @@ const RouteTravel = ({
|
|
|
38991
39782
|
}, [pages]);
|
|
38992
39783
|
|
|
38993
39784
|
// Rendering is held for the length of a navigation, so that whatever picture
|
|
38994
|
-
// this box is about to take is of the page being LEFT (see
|
|
38995
|
-
//
|
|
38996
|
-
// announces that it matches, Preact has already been told and the render is
|
|
38997
|
-
// queued — a hold taken then is a hold taken too late.
|
|
39785
|
+
// this box is about to take is of the page being LEFT (see
|
|
39786
|
+
// rendering_hold.js).
|
|
38998
39787
|
useLayoutEffect(() => {
|
|
38999
|
-
const stopWatchingStart = observeBeforeRouting(
|
|
39000
|
-
renderingHeldForRouting = holdRendering();
|
|
39001
|
-
});
|
|
39788
|
+
const stopWatchingStart = observeBeforeRouting(holdRenderingForRouting);
|
|
39002
39789
|
// Nobody may have had a picture to take: this navigation is not always one
|
|
39003
|
-
// this box travels
|
|
39004
|
-
//
|
|
39005
|
-
|
|
39006
|
-
const stopWatchingEnd = observeAfterRouting(() => {
|
|
39007
|
-
const release = renderingHeldForRouting;
|
|
39008
|
-
renderingHeldForRouting = null;
|
|
39009
|
-
if (release) {
|
|
39010
|
-
release();
|
|
39011
|
-
}
|
|
39012
|
-
});
|
|
39790
|
+
// this box travels. Whoever wanted the hold took it over (beginTravel)
|
|
39791
|
+
// while the change was being applied, and left nothing here.
|
|
39792
|
+
const stopWatchingEnd = observeAfterRouting(releaseRoutingRenderingHold);
|
|
39013
39793
|
return () => {
|
|
39014
39794
|
stopWatchingStart();
|
|
39015
39795
|
stopWatchingEnd();
|
|
@@ -39622,54 +40402,6 @@ const releaseTravelGeometry = () => {
|
|
|
39622
40402
|
}
|
|
39623
40403
|
};
|
|
39624
40404
|
|
|
39625
|
-
// The browser does not take the picture of the page being left when a
|
|
39626
|
-
// transition is ASKED for — it takes it at the next frame, just before running
|
|
39627
|
-
// the update callback. Preact renders sooner than that, in a microtask: so a
|
|
39628
|
-
// change nobody here asked for (a tab pressed, the back button) has already
|
|
39629
|
-
// reached the DOM when the picture is taken, and the picture is of the page
|
|
39630
|
-
// ARRIVING. Both sides of the travel then show it, and one watches a page slide
|
|
39631
|
-
// onto itself.
|
|
39632
|
-
//
|
|
39633
|
-
// So what Preact has queued waits until the update callback, which is the
|
|
39634
|
-
// moment the API is built around — the change belongs inside it. The whole
|
|
39635
|
-
// document is held, for the one frame the browser needs: it is about to be
|
|
39636
|
-
// frozen under a picture anyway.
|
|
39637
|
-
let renderingHold = null;
|
|
39638
|
-
// The hold a navigation took on its way in, until a travel takes it over or the
|
|
39639
|
-
// navigation turns out to be one nobody here animates.
|
|
39640
|
-
let renderingHeldForRouting = null;
|
|
39641
|
-
const holdRendering = () => {
|
|
39642
|
-
if (renderingHold) {
|
|
39643
|
-
return renderingHold.release;
|
|
39644
|
-
}
|
|
39645
|
-
const debounceRenderingBefore = options.debounceRendering;
|
|
39646
|
-
const hold = {
|
|
39647
|
-
render: null,
|
|
39648
|
-
release: () => {
|
|
39649
|
-
// Only the hold that is still standing may be given back: a travel
|
|
39650
|
-
// ending after another has taken over must not let go of what it does
|
|
39651
|
-
// not hold.
|
|
39652
|
-
if (renderingHold !== hold) {
|
|
39653
|
-
return;
|
|
39654
|
-
}
|
|
39655
|
-
renderingHold = null;
|
|
39656
|
-
options.debounceRendering = debounceRenderingBefore;
|
|
39657
|
-
const {
|
|
39658
|
-
render
|
|
39659
|
-
} = hold;
|
|
39660
|
-
hold.render = null;
|
|
39661
|
-
if (render) {
|
|
39662
|
-
render();
|
|
39663
|
-
}
|
|
39664
|
-
}
|
|
39665
|
-
};
|
|
39666
|
-
renderingHold = hold;
|
|
39667
|
-
options.debounceRendering = render => {
|
|
39668
|
-
hold.render = render;
|
|
39669
|
-
};
|
|
39670
|
-
return hold.release;
|
|
39671
|
-
};
|
|
39672
|
-
|
|
39673
40405
|
// The animations of the pictures, asked for again until there are some: they
|
|
39674
40406
|
// come into existence with the transition, several frames after it was asked
|
|
39675
40407
|
// for, and the gesture has already begun by then. Kept once found — the set
|
|
@@ -73006,5 +73738,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
73006
73738
|
})
|
|
73007
73739
|
});
|
|
73008
73740
|
|
|
73009
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeSpin, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
73741
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeSpin, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
73010
73742
|
//# sourceMappingURL=jsenv_navi.js.map
|