@jsenv/navi 0.29.66 → 0.29.68
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 +692 -253
- package/dist/jsenv_navi.js.map +92 -55
- package/docs/AI_INSTRUCTIONS.md +8 -4
- package/docs/list_refresh.md +33 -2
- package/docs/navigation.md +26 -0
- package/docs/route_transitions.md +101 -13
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -21810,6 +21810,244 @@ const updateDocumentState = (value) => {
|
|
|
21810
21810
|
documentStateSignal.value = value;
|
|
21811
21811
|
};
|
|
21812
21812
|
|
|
21813
|
+
/**
|
|
21814
|
+
* The document's rendering, held for the one frame a view transition needs.
|
|
21815
|
+
*
|
|
21816
|
+
* The browser does not take the picture of the page being left when a
|
|
21817
|
+
* transition is ASKED for — it takes it at the next frame, just before running
|
|
21818
|
+
* the update callback. Preact renders sooner than that, in a microtask: so a
|
|
21819
|
+
* change nobody asked for (a tab pressed, the back button) has already reached
|
|
21820
|
+
* the DOM when the picture is taken, and the picture is of the page ARRIVING.
|
|
21821
|
+
* Both sides of the animation then show it, and one watches a page slide onto
|
|
21822
|
+
* itself.
|
|
21823
|
+
*
|
|
21824
|
+
* So what Preact has queued waits until the update callback, which is the
|
|
21825
|
+
* moment the API is built around — the change belongs inside it. The whole
|
|
21826
|
+
* document is held: it is about to be frozen under a picture anyway.
|
|
21827
|
+
*
|
|
21828
|
+
* ONE hold for the whole document, whoever animates. The hold is a wrapper
|
|
21829
|
+
* around Preact's `options.debounceRendering`, and two of them installed
|
|
21830
|
+
* independently restore each other in the wrong order when they let go — every
|
|
21831
|
+
* render queued in between is then handed to a wrapper nobody will ever
|
|
21832
|
+
* release. Everything that photographs a navigation (RouteTravel's box, a
|
|
21833
|
+
* route transition) must therefore hold through this module, never through a
|
|
21834
|
+
* wrapper of its own.
|
|
21835
|
+
*/
|
|
21836
|
+
|
|
21837
|
+
|
|
21838
|
+
let renderingHold = null;
|
|
21839
|
+
const holdRendering = () => {
|
|
21840
|
+
if (renderingHold) {
|
|
21841
|
+
return renderingHold.release;
|
|
21842
|
+
}
|
|
21843
|
+
const debounceRenderingBefore = options.debounceRendering;
|
|
21844
|
+
const hold = {
|
|
21845
|
+
render: null,
|
|
21846
|
+
waiting: [],
|
|
21847
|
+
release: () => {
|
|
21848
|
+
// Only the hold that is still standing may be given back: a holder
|
|
21849
|
+
// releasing after another has taken over must not let go of what it
|
|
21850
|
+
// does not hold.
|
|
21851
|
+
if (renderingHold !== hold) {
|
|
21852
|
+
return;
|
|
21853
|
+
}
|
|
21854
|
+
renderingHold = null;
|
|
21855
|
+
options.debounceRendering = debounceRenderingBefore;
|
|
21856
|
+
const { render, waiting } = hold;
|
|
21857
|
+
hold.render = null;
|
|
21858
|
+
hold.waiting = [];
|
|
21859
|
+
if (render) {
|
|
21860
|
+
render();
|
|
21861
|
+
}
|
|
21862
|
+
for (const wait of waiting) {
|
|
21863
|
+
wait();
|
|
21864
|
+
}
|
|
21865
|
+
},
|
|
21866
|
+
};
|
|
21867
|
+
renderingHold = hold;
|
|
21868
|
+
options.debounceRendering = (render) => {
|
|
21869
|
+
hold.render = render;
|
|
21870
|
+
};
|
|
21871
|
+
return hold.release;
|
|
21872
|
+
};
|
|
21873
|
+
|
|
21874
|
+
// Anything else that must not happen before the picture is taken, and the
|
|
21875
|
+
// scroll is the other one: a page one arrives at starts at its top, and the
|
|
21876
|
+
// document put back to its top while the page being left is still on screen is
|
|
21877
|
+
// a page that has ALREADY jumped when the picture is taken. Worse, the browser
|
|
21878
|
+
// paints what the new offset shows and nothing else, so the picture keeps only
|
|
21879
|
+
// the band it had already painted — the page being left is then seen in
|
|
21880
|
+
// fragments, whatever the movement does afterwards.
|
|
21881
|
+
//
|
|
21882
|
+
// Run at once when nobody is photographing anything, which is the common case
|
|
21883
|
+
// and must stay free.
|
|
21884
|
+
const whenRenderingResumes = (callback) => {
|
|
21885
|
+
if (!renderingHold) {
|
|
21886
|
+
callback();
|
|
21887
|
+
return;
|
|
21888
|
+
}
|
|
21889
|
+
renderingHold.waiting.push(callback);
|
|
21890
|
+
};
|
|
21891
|
+
|
|
21892
|
+
// The hold a navigation takes on its way in — from before its first write,
|
|
21893
|
+
// because by the time a route announces that it matches, Preact has already
|
|
21894
|
+
// been told and the render is queued; a hold taken then is a hold taken too
|
|
21895
|
+
// late. Kept here until whoever animates the change takes it over, or the
|
|
21896
|
+
// navigation turns out to be one nobody animates.
|
|
21897
|
+
let routingRenderingHold = null;
|
|
21898
|
+
const holdRenderingForRouting = () => {
|
|
21899
|
+
routingRenderingHold = holdRendering();
|
|
21900
|
+
};
|
|
21901
|
+
// Nobody had a picture to take: a page held for a change it does not animate
|
|
21902
|
+
// is a page that stutters for nothing.
|
|
21903
|
+
const releaseRoutingRenderingHold = () => {
|
|
21904
|
+
const release = routingRenderingHold;
|
|
21905
|
+
routingRenderingHold = null;
|
|
21906
|
+
if (release) {
|
|
21907
|
+
release();
|
|
21908
|
+
}
|
|
21909
|
+
};
|
|
21910
|
+
// An animator takes the navigation's hold as its own — taking another would be
|
|
21911
|
+
// taking a hold on a page that is holding still — or takes a fresh one when
|
|
21912
|
+
// the change it animates is not a navigation.
|
|
21913
|
+
const takeoverRoutingRenderingHold = () => {
|
|
21914
|
+
const release = routingRenderingHold || holdRendering();
|
|
21915
|
+
routingRenderingHold = null;
|
|
21916
|
+
return release;
|
|
21917
|
+
};
|
|
21918
|
+
|
|
21919
|
+
/**
|
|
21920
|
+
* A container has put its page on screen — or as much of it as it can.
|
|
21921
|
+
*
|
|
21922
|
+
* A route matching is a signal changing, and the page it selects reaches the
|
|
21923
|
+
* DOM only once Preact has rendered — an unknown number of passes later, in an
|
|
21924
|
+
* unknown number of microtasks. Anyone who needs the page as it IS rather than
|
|
21925
|
+
* as it has been decided (a travel about to have its picture taken by the
|
|
21926
|
+
* browser, see route_travel.jsx) waits for this instead of counting.
|
|
21927
|
+
*
|
|
21928
|
+
* A page waiting on data is announced too, by the boundary showing its loading
|
|
21929
|
+
* state (see Loading in use_async_data.jsx): what the container could put on
|
|
21930
|
+
* screen is what the browser is about to take a picture of, and a page that
|
|
21931
|
+
* cannot render yet would otherwise be waited on until the transition dies of
|
|
21932
|
+
* it. It lives in a module of its own for that: the async layer says it as much
|
|
21933
|
+
* as the router does, and neither can import the other.
|
|
21934
|
+
*/
|
|
21935
|
+
const [publishRouteRender, observeRouteRender] = createPubSub();
|
|
21936
|
+
|
|
21937
|
+
/**
|
|
21938
|
+
* Where a page was left, given back when one comes back to it.
|
|
21939
|
+
*
|
|
21940
|
+
* The browser does this on its own, and gets it wrong here for a reason that
|
|
21941
|
+
* has nothing to do with it: it puts the offset back at the instant the entry
|
|
21942
|
+
* changes, when the document still holds the page being LEFT. A position
|
|
21943
|
+
* further down than that page is tall is clamped to its bottom and lost — so
|
|
21944
|
+
* coming back to a long page from a short one lands short, and the deeper one
|
|
21945
|
+
* was, the more is missing.
|
|
21946
|
+
*
|
|
21947
|
+
* So the browser is told to stop (`scrollRestoration = "manual"`) and the
|
|
21948
|
+
* position is put back once the page one is coming back to is really there —
|
|
21949
|
+
* through the same wait as everything else that must not happen before the
|
|
21950
|
+
* picture of a transition is taken (see rendering_hold.js): restored after the
|
|
21951
|
+
* picture, the page arriving would be photographed at the top and seen jumping
|
|
21952
|
+
* from it.
|
|
21953
|
+
*
|
|
21954
|
+
* Kept per URL rather than per history entry: an entry has no name of its own
|
|
21955
|
+
* that survives a reload, and two entries on the same URL are the same place
|
|
21956
|
+
* to a reader. Kept in the session too, so a reload lands where the browser
|
|
21957
|
+
* would have landed — the flag above is a promise to do the whole job.
|
|
21958
|
+
*
|
|
21959
|
+
* What is NOT covered, and cannot be from here: a page whose height depends on
|
|
21960
|
+
* something still loading. Its content is not there at the moment it is put
|
|
21961
|
+
* back, so a position beyond what has arrived is clamped as before. Only the
|
|
21962
|
+
* page knows when it is whole.
|
|
21963
|
+
*/
|
|
21964
|
+
|
|
21965
|
+
|
|
21966
|
+
const STORAGE_KEY = "navi_scroll_positions";
|
|
21967
|
+
|
|
21968
|
+
const positionByUrl = new Map();
|
|
21969
|
+
const readStoredPositions = () => {
|
|
21970
|
+
let stored;
|
|
21971
|
+
try {
|
|
21972
|
+
stored = window.sessionStorage.getItem(STORAGE_KEY);
|
|
21973
|
+
} catch {
|
|
21974
|
+
// A session storage that refuses to answer (a private window, a policy) is
|
|
21975
|
+
// not a reason to lose the positions of THIS session.
|
|
21976
|
+
return;
|
|
21977
|
+
}
|
|
21978
|
+
if (!stored) {
|
|
21979
|
+
return;
|
|
21980
|
+
}
|
|
21981
|
+
try {
|
|
21982
|
+
for (const [url, position] of Object.entries(JSON.parse(stored))) {
|
|
21983
|
+
positionByUrl.set(url, position);
|
|
21984
|
+
}
|
|
21985
|
+
} catch {
|
|
21986
|
+
// Something else wrote there, or it was truncated.
|
|
21987
|
+
}
|
|
21988
|
+
};
|
|
21989
|
+
const storePositions = () => {
|
|
21990
|
+
try {
|
|
21991
|
+
window.sessionStorage.setItem(
|
|
21992
|
+
STORAGE_KEY,
|
|
21993
|
+
JSON.stringify(Object.fromEntries(positionByUrl)),
|
|
21994
|
+
);
|
|
21995
|
+
} catch {
|
|
21996
|
+
// Full, or refused: the session is the only thing lost.
|
|
21997
|
+
}
|
|
21998
|
+
};
|
|
21999
|
+
|
|
22000
|
+
let installed = false;
|
|
22001
|
+
const installScrollRestoration = () => {
|
|
22002
|
+
if (installed) {
|
|
22003
|
+
return;
|
|
22004
|
+
}
|
|
22005
|
+
installed = true;
|
|
22006
|
+
if (!("scrollRestoration" in window.history)) {
|
|
22007
|
+
return;
|
|
22008
|
+
}
|
|
22009
|
+
window.history.scrollRestoration = "manual";
|
|
22010
|
+
readStoredPositions();
|
|
22011
|
+
// Read as it happens rather than when leaving: a traverse changes the url
|
|
22012
|
+
// before anything here is told, so a position read then would be read for
|
|
22013
|
+
// the wrong page.
|
|
22014
|
+
window.addEventListener(
|
|
22015
|
+
"scroll",
|
|
22016
|
+
() => {
|
|
22017
|
+
positionByUrl.set(window.location.href, {
|
|
22018
|
+
x: window.scrollX,
|
|
22019
|
+
y: window.scrollY,
|
|
22020
|
+
});
|
|
22021
|
+
},
|
|
22022
|
+
{ passive: true },
|
|
22023
|
+
);
|
|
22024
|
+
window.addEventListener("pagehide", storePositions);
|
|
22025
|
+
// What a reload asks for, now that the browser has been told not to do it.
|
|
22026
|
+
// Once, and at the first render of a route: the position is only meaningful
|
|
22027
|
+
// once there is a page under it.
|
|
22028
|
+
const positionOnLoad = positionByUrl.get(window.location.href);
|
|
22029
|
+
if (positionOnLoad && (positionOnLoad.x || positionOnLoad.y)) {
|
|
22030
|
+
const stopListening = observeRouteRender(() => {
|
|
22031
|
+
stopListening();
|
|
22032
|
+
scrollTo(positionOnLoad);
|
|
22033
|
+
});
|
|
22034
|
+
}
|
|
22035
|
+
};
|
|
22036
|
+
|
|
22037
|
+
// Nothing to put back is not the same as putting back the top: a page arrived
|
|
22038
|
+
// at for the first time is startAtTop's business, and this must not step on it.
|
|
22039
|
+
const restoreScrollPosition = (url) => {
|
|
22040
|
+
const position = positionByUrl.get(new URL(url, window.location.href).href);
|
|
22041
|
+
if (!position) {
|
|
22042
|
+
return;
|
|
22043
|
+
}
|
|
22044
|
+
scrollTo(position);
|
|
22045
|
+
};
|
|
22046
|
+
|
|
22047
|
+
const scrollTo = ({ x, y }) => {
|
|
22048
|
+
window.scrollTo({ top: y, left: x, behavior: "instant" });
|
|
22049
|
+
};
|
|
22050
|
+
|
|
21813
22051
|
/**
|
|
21814
22052
|
* A navigation is ABOUT to be applied — said before its very first write.
|
|
21815
22053
|
*
|
|
@@ -21978,7 +22216,12 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
21978
22216
|
state,
|
|
21979
22217
|
});
|
|
21980
22218
|
if (navigationType === "push") {
|
|
21981
|
-
startAtTop(url);
|
|
22219
|
+
whenRenderingResumes(() => startAtTop(url));
|
|
22220
|
+
} else if (navigationType === "traverse") {
|
|
22221
|
+
// Where this entry was left. Waited for like the reset above, and for
|
|
22222
|
+
// the same two reasons: the page has to be there to be scrolled, and a
|
|
22223
|
+
// picture taken before it would be of a page at its top.
|
|
22224
|
+
whenRenderingResumes(() => restoreScrollPosition(url));
|
|
21982
22225
|
}
|
|
21983
22226
|
executeWithCleanup(
|
|
21984
22227
|
() => allResult,
|
|
@@ -22056,6 +22299,11 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
22056
22299
|
{ capture: true },
|
|
22057
22300
|
);
|
|
22058
22301
|
|
|
22302
|
+
// The browser's own scroll restoration is taken over here rather than left
|
|
22303
|
+
// to whoever navigates: it is a decision about the document, and the entry
|
|
22304
|
+
// being left must be recorded from the first pixel scrolled.
|
|
22305
|
+
installScrollRestoration();
|
|
22306
|
+
|
|
22059
22307
|
window.addEventListener("popstate", (popstateEvent) => {
|
|
22060
22308
|
const url = window.location.href;
|
|
22061
22309
|
const state = popstateEvent.state;
|
|
@@ -22140,13 +22388,16 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
22140
22388
|
// route_travel.jsx), and resetting there would throw the reader out of a page
|
|
22141
22389
|
// they never left.
|
|
22142
22390
|
//
|
|
22143
|
-
// After the routes have been told, and
|
|
22144
|
-
//
|
|
22145
|
-
//
|
|
22146
|
-
//
|
|
22147
|
-
//
|
|
22148
|
-
//
|
|
22149
|
-
// the
|
|
22391
|
+
// After the routes have been told, and after the picture of the page being
|
|
22392
|
+
// left has been taken — that ordering is the whole subtlety. The routes
|
|
22393
|
+
// changing is what sets a movement off, and a movement measures the box it is
|
|
22394
|
+
// leaving as it stands; put the document back to its top any earlier and the
|
|
22395
|
+
// picture is of a page at its first line, which the reader was not at. The
|
|
22396
|
+
// browser paints what the new offset shows and nothing else, so what is kept
|
|
22397
|
+
// of the page being left is the band it had already painted, and the movement
|
|
22398
|
+
// carries a fragment (see rendering_hold.js, which is where the waiting
|
|
22399
|
+
// happens). After pushState too, so the entry being left keeps the offset it
|
|
22400
|
+
// is at.
|
|
22150
22401
|
//
|
|
22151
22402
|
// The document, because the document is the scrollport in the common case. An
|
|
22152
22403
|
// app that scrolls an element of its own scrolls it itself.
|
|
@@ -36224,24 +36475,6 @@ const TYPE_CONVERTERS = {
|
|
|
36224
36475
|
},
|
|
36225
36476
|
};
|
|
36226
36477
|
|
|
36227
|
-
/**
|
|
36228
|
-
* A container has put its page on screen — or as much of it as it can.
|
|
36229
|
-
*
|
|
36230
|
-
* A route matching is a signal changing, and the page it selects reaches the
|
|
36231
|
-
* DOM only once Preact has rendered — an unknown number of passes later, in an
|
|
36232
|
-
* unknown number of microtasks. Anyone who needs the page as it IS rather than
|
|
36233
|
-
* as it has been decided (a travel about to have its picture taken by the
|
|
36234
|
-
* browser, see route_travel.jsx) waits for this instead of counting.
|
|
36235
|
-
*
|
|
36236
|
-
* A page waiting on data is announced too, by the boundary showing its loading
|
|
36237
|
-
* state (see Loading in use_async_data.jsx): what the container could put on
|
|
36238
|
-
* screen is what the browser is about to take a picture of, and a page that
|
|
36239
|
-
* cannot render yet would otherwise be waited on until the transition dies of
|
|
36240
|
-
* it. It lives in a module of its own for that: the async layer says it as much
|
|
36241
|
-
* as the router does, and neither can import the other.
|
|
36242
|
-
*/
|
|
36243
|
-
const [publishRouteRender, observeRouteRender] = createPubSub();
|
|
36244
|
-
|
|
36245
36478
|
const promiseStateWeakMap = new WeakMap();
|
|
36246
36479
|
const usePromiseAsyncData = (
|
|
36247
36480
|
promise,
|
|
@@ -38317,86 +38550,90 @@ const RouteUI = ({
|
|
|
38317
38550
|
};
|
|
38318
38551
|
|
|
38319
38552
|
/**
|
|
38320
|
-
* The
|
|
38321
|
-
*
|
|
38322
|
-
*
|
|
38323
|
-
*
|
|
38324
|
-
*
|
|
38325
|
-
*
|
|
38326
|
-
*
|
|
38327
|
-
*
|
|
38328
|
-
*
|
|
38329
|
-
*
|
|
38330
|
-
*
|
|
38331
|
-
*
|
|
38332
|
-
*
|
|
38333
|
-
*
|
|
38334
|
-
*
|
|
38335
|
-
*
|
|
38336
|
-
*
|
|
38337
|
-
*
|
|
38338
|
-
*
|
|
38339
|
-
*
|
|
38340
|
-
*
|
|
38553
|
+
* The window two pages are seen through while one replaces the other, measured
|
|
38554
|
+
* once and published for the length of the movement.
|
|
38555
|
+
*
|
|
38556
|
+
* Both ways of moving from one route to another need the same six numbers, so
|
|
38557
|
+
* they are written under the same names and read by the same CSS formulas —
|
|
38558
|
+
* `route_travel.jsx` for a row a finger pushes, `route_transition.jsx` for a
|
|
38559
|
+
* relation between two pages. Only one of them ever plays at a time (there is
|
|
38560
|
+
* one view transition per document), which is what lets them share the names.
|
|
38561
|
+
*
|
|
38562
|
+
* What the numbers are for:
|
|
38563
|
+
*
|
|
38564
|
+
* - **the box the movement happens in**, in the WINDOW's coordinates. The
|
|
38565
|
+
* pictures of a transition are drawn in the top layer, above everything, so
|
|
38566
|
+
* no overflow of the document reaches them: where to cut them can only be
|
|
38567
|
+
* said from outside the document, and this is where that outside is known.
|
|
38568
|
+
* - **the height it is held at**, the taller of the two states. Left to the
|
|
38569
|
+
* browser the window's height animates from one to the other, and a window
|
|
38570
|
+
* that changes size under the pictures cuts the page being left from the
|
|
38571
|
+
* bottom, progressively. It does end up at the arriving height, and that is
|
|
38572
|
+
* right; what must not happen is the user watching it get there.
|
|
38573
|
+
* - **where the page being left WAS**, which is not where the window stands:
|
|
38574
|
+
* the two states are at the same place in the layout without being at the
|
|
38575
|
+
* same place in the window — one page is scrolled and the other is not.
|
|
38576
|
+
* Drawn at the window's own corner, the page being left would be seen
|
|
38577
|
+
* jumping to its top before it begins to leave.
|
|
38578
|
+
*
|
|
38579
|
+
* Only the measuring needs JS, and only for the one moment both states exist:
|
|
38580
|
+
* the page arriving is in the DOM and the transition has not started playing.
|
|
38581
|
+
* Everything DERIVED from these numbers — the band a fixed bar covers, how far
|
|
38582
|
+
* a page travels — is derived in CSS, so the application's own numbers (the
|
|
38583
|
+
* room its bars give back, see layout/safe_area.js) take part in it.
|
|
38341
38584
|
*/
|
|
38342
38585
|
|
|
38586
|
+
const WINDOW_TOP_PROPERTY = "--navi-transition-window-top";
|
|
38587
|
+
const WINDOW_LEFT_PROPERTY = "--navi-transition-window-left";
|
|
38588
|
+
const WINDOW_WIDTH_PROPERTY = "--navi-transition-window-width";
|
|
38589
|
+
const WINDOW_HEIGHT_PROPERTY = "--navi-transition-window-height";
|
|
38590
|
+
const WINDOW_OLD_TOP_PROPERTY = "--navi-transition-window-old-top";
|
|
38591
|
+
const WINDOW_OLD_LEFT_PROPERTY = "--navi-transition-window-old-left";
|
|
38592
|
+
const WINDOW_PROPERTIES = [
|
|
38593
|
+
WINDOW_TOP_PROPERTY,
|
|
38594
|
+
WINDOW_LEFT_PROPERTY,
|
|
38595
|
+
WINDOW_WIDTH_PROPERTY,
|
|
38596
|
+
WINDOW_HEIGHT_PROPERTY,
|
|
38597
|
+
WINDOW_OLD_TOP_PROPERTY,
|
|
38598
|
+
WINDOW_OLD_LEFT_PROPERTY,
|
|
38599
|
+
];
|
|
38343
38600
|
|
|
38344
|
-
|
|
38345
|
-
|
|
38346
|
-
|
|
38347
|
-
|
|
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
|
-
};
|
|
38601
|
+
// Whose numbers are currently published. The window belongs to the movement
|
|
38602
|
+
// that measured it, and only that one may take it down: a movement ending
|
|
38603
|
+
// after another has replaced it must not wipe numbers the new one is standing
|
|
38604
|
+
// on.
|
|
38605
|
+
let windowOwner = null;
|
|
38374
38606
|
|
|
38375
|
-
|
|
38376
|
-
|
|
38377
|
-
//
|
|
38378
|
-
//
|
|
38379
|
-
//
|
|
38380
|
-
|
|
38381
|
-
|
|
38382
|
-
|
|
38607
|
+
const holdTransitionWindow = (owner, element, rectBefore) => {
|
|
38608
|
+
const rectAfter = element.getBoundingClientRect();
|
|
38609
|
+
// It cannot be measured from one side alone: a page arriving shorter than
|
|
38610
|
+
// the one it replaces would cut the one leaving, a page arriving taller
|
|
38611
|
+
// would be cut itself.
|
|
38612
|
+
const height =
|
|
38613
|
+
rectBefore.height > rectAfter.height ? rectBefore.height : rectAfter.height;
|
|
38614
|
+
windowOwner = owner;
|
|
38615
|
+
const { style } = document.documentElement;
|
|
38616
|
+
style.setProperty(WINDOW_TOP_PROPERTY, `${rectAfter.top}px`);
|
|
38617
|
+
style.setProperty(WINDOW_LEFT_PROPERTY, `${rectAfter.left}px`);
|
|
38618
|
+
style.setProperty(WINDOW_WIDTH_PROPERTY, `${rectAfter.width}px`);
|
|
38619
|
+
style.setProperty(WINDOW_HEIGHT_PROPERTY, `${height}px`);
|
|
38620
|
+
style.setProperty(WINDOW_OLD_TOP_PROPERTY, `${rectBefore.top}px`);
|
|
38621
|
+
style.setProperty(WINDOW_OLD_LEFT_PROPERTY, `${rectBefore.left}px`);
|
|
38383
38622
|
};
|
|
38384
|
-
|
|
38385
|
-
//
|
|
38386
|
-
|
|
38387
|
-
|
|
38388
|
-
|
|
38389
|
-
|
|
38390
|
-
|
|
38623
|
+
|
|
38624
|
+
// The live layout takes the box back. A discontinuity by construction — the
|
|
38625
|
+
// window stands at the held height, the box is at its own — and an invisible
|
|
38626
|
+
// one: the page arriving is fully in place, and the strip below it that the
|
|
38627
|
+
// window still covers shows the page leaving only while it is still on screen.
|
|
38628
|
+
const releaseTransitionWindow = (owner) => {
|
|
38629
|
+
if (owner !== windowOwner) {
|
|
38630
|
+
return;
|
|
38631
|
+
}
|
|
38632
|
+
windowOwner = null;
|
|
38633
|
+
const { style } = document.documentElement;
|
|
38634
|
+
for (const property of WINDOW_PROPERTIES) {
|
|
38635
|
+
style.removeProperty(property);
|
|
38391
38636
|
}
|
|
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
38637
|
};
|
|
38401
38638
|
|
|
38402
38639
|
installImportMetaCssBuild(import.meta);/**
|
|
@@ -38473,14 +38710,158 @@ const ROUTE_TRAVEL_ATTRIBUTE = "data-navi-route-travel";
|
|
|
38473
38710
|
// or the marked area. The guard keeps the two exclusive — with an area marked,
|
|
38474
38711
|
// the root pictures must NOT move (they carry the whole viewport, blank bands
|
|
38475
38712
|
// included).
|
|
38476
|
-
|
|
38477
|
-
|
|
38478
|
-
|
|
38479
|
-
|
|
38480
|
-
|
|
38481
|
-
|
|
38482
|
-
|
|
38483
|
-
|
|
38713
|
+
|
|
38714
|
+
const css$T = /* css */`
|
|
38715
|
+
/* The marked region is a picture of its own during every view transition of
|
|
38716
|
+
the document — which is what keeps it out of the root snapshot, where its
|
|
38717
|
+
place would otherwise be blank. */
|
|
38718
|
+
[data-navi-route-transition-area] {
|
|
38719
|
+
view-transition-name: navi-route-transition;
|
|
38720
|
+
}
|
|
38721
|
+
|
|
38722
|
+
/* Only while a transition of OURS is playing: everything below changes how
|
|
38723
|
+
the document animates, and the document belongs to the application the
|
|
38724
|
+
rest of the time. */
|
|
38725
|
+
:root[data-navi-route-transition] {
|
|
38726
|
+
/* With an area marked, the page AROUND it is not taken as a picture — so
|
|
38727
|
+
exactly one of the two names below exists at a time, and the movements
|
|
38728
|
+
can be written once for both. It is also what a fixed bar wants: a
|
|
38729
|
+
captured element is not painted where it stands and cannot be pointed
|
|
38730
|
+
at either, so a bar photographed with the document is dead for the
|
|
38731
|
+
length of every transition. Left live, it answers as it always did, and
|
|
38732
|
+
nothing shows through where the pages are — the two pictures cover the
|
|
38733
|
+
area's rectangle between them at every moment. Anything around that must
|
|
38734
|
+
ANIMATE rather than stand still gets a view-transition-name of its own,
|
|
38735
|
+
and the browser moves it on the same clock. */
|
|
38736
|
+
&[data-navi-route-transition-target="area"] {
|
|
38737
|
+
view-transition-name: none;
|
|
38738
|
+
}
|
|
38739
|
+
|
|
38740
|
+
&::view-transition-old(root),
|
|
38741
|
+
&::view-transition-new(root),
|
|
38742
|
+
&::view-transition-old(navi-route-transition),
|
|
38743
|
+
&::view-transition-new(navi-route-transition) {
|
|
38744
|
+
/* Written on the direction alone, so a relation with no type — the
|
|
38745
|
+
browser's cross-fade — answers to it like every other. */
|
|
38746
|
+
animation-duration: var(--navi-route-transition-duration, 300ms);
|
|
38747
|
+
}
|
|
38748
|
+
|
|
38749
|
+
/* The window the pages are seen through, when it is an area. Nothing here
|
|
38750
|
+
names \`root\`: the root picture IS the window when the whole document
|
|
38751
|
+
travels, already the size of the screen and already cut by it. */
|
|
38752
|
+
&::view-transition-group(navi-route-transition),
|
|
38753
|
+
&::view-transition-image-pair(navi-route-transition) {
|
|
38754
|
+
/* The pages are cut at the edge of the area they move in. Said HERE and
|
|
38755
|
+
nowhere else: these pictures are drawn in the top layer, so no
|
|
38756
|
+
overflow on any element of the document can reach them. */
|
|
38757
|
+
overflow: clip;
|
|
38758
|
+
}
|
|
38759
|
+
&::view-transition-group(navi-route-transition) {
|
|
38760
|
+
/* Held still for the whole transition, at the taller of the two states,
|
|
38761
|
+
and standing where the area stands (see transition_window.js). Held by
|
|
38762
|
+
dropping the group's animation rather than by winning against it with
|
|
38763
|
+
!important — which also drops its position animation, fine for an area
|
|
38764
|
+
that stays in the same place from one page to the next. */
|
|
38765
|
+
height: var(--navi-transition-window-height);
|
|
38766
|
+
animation-name: none;
|
|
38767
|
+
|
|
38768
|
+
/* Cut at the safe area, on top of being cut at the area's own box. The
|
|
38769
|
+
pictures are drawn in the top layer, so they cover a fixed bar as
|
|
38770
|
+
easily as anything else — and the area runs UNDER the bars by design:
|
|
38771
|
+
that is what a fixed bar is for, and what the room it gives back is
|
|
38772
|
+
for. An area taller than the screen therefore ends below the bottom
|
|
38773
|
+
bar, and a scrolled one starts above the top bar, so the movement
|
|
38774
|
+
would be watched painting over them for its whole length.
|
|
38775
|
+
|
|
38776
|
+
The band left free is the app's own safe area (see
|
|
38777
|
+
layout/safe_area.js) — every kind of furniture at once, not the bars
|
|
38778
|
+
alone, and read rather than asked for, so one that grows, shrinks or
|
|
38779
|
+
unmounts mid-transition is followed without anything being told. What
|
|
38780
|
+
the window cannot know is only where it itself stands, and that is the
|
|
38781
|
+
measured half. */
|
|
38782
|
+
--navi-route-transition-clip-top: max(
|
|
38783
|
+
0px,
|
|
38784
|
+
var(--navi-safe-area-inset-top) - var(--navi-transition-window-top)
|
|
38785
|
+
);
|
|
38786
|
+
--navi-route-transition-clip-left: max(
|
|
38787
|
+
0px,
|
|
38788
|
+
var(--navi-safe-area-inset-left) - var(--navi-transition-window-left)
|
|
38789
|
+
);
|
|
38790
|
+
--navi-route-transition-clip-bottom: max(
|
|
38791
|
+
0px,
|
|
38792
|
+
var(--navi-transition-window-top) +
|
|
38793
|
+
var(--navi-transition-window-height) +
|
|
38794
|
+
var(--navi-safe-area-inset-bottom) - 100dvh
|
|
38795
|
+
);
|
|
38796
|
+
--navi-route-transition-clip-right: max(
|
|
38797
|
+
0px,
|
|
38798
|
+
var(--navi-transition-window-left) +
|
|
38799
|
+
var(--navi-transition-window-width) +
|
|
38800
|
+
var(--navi-safe-area-inset-right) - 100dvw
|
|
38801
|
+
);
|
|
38802
|
+
clip-path: inset(
|
|
38803
|
+
var(--navi-route-transition-clip-top)
|
|
38804
|
+
var(--navi-route-transition-clip-right)
|
|
38805
|
+
var(--navi-route-transition-clip-bottom)
|
|
38806
|
+
var(--navi-route-transition-clip-left)
|
|
38807
|
+
);
|
|
38808
|
+
|
|
38809
|
+
/* How far a page travels: the WINDOW it is seen through, not its own
|
|
38810
|
+
size. A page is as tall as its content — several screens of it — and a
|
|
38811
|
+
movement measured on the picture would send it thousands of pixels
|
|
38812
|
+
away, off screen for most of the transition and flying past at the
|
|
38813
|
+
end. What one page crossing another means is one window's worth of
|
|
38814
|
+
movement, whatever the pages are made of. Inherited by the pictures,
|
|
38815
|
+
which is where it is used (see the keyframes). */
|
|
38816
|
+
--navi-route-transition-travel-x: calc(
|
|
38817
|
+
var(--navi-transition-window-width) - var(
|
|
38818
|
+
--navi-route-transition-clip-left
|
|
38819
|
+
) - var(--navi-route-transition-clip-right)
|
|
38820
|
+
);
|
|
38821
|
+
--navi-route-transition-travel-y: calc(
|
|
38822
|
+
var(--navi-transition-window-height) - var(
|
|
38823
|
+
--navi-route-transition-clip-top
|
|
38824
|
+
) - var(--navi-route-transition-clip-bottom)
|
|
38825
|
+
);
|
|
38826
|
+
}
|
|
38827
|
+
&::view-transition-old(navi-route-transition) {
|
|
38828
|
+
/* Where the area WAS on screen, which is not where the window stands
|
|
38829
|
+
(see transition_window.js). Offset here rather than by \`translate\`,
|
|
38830
|
+
which the movement itself uses. */
|
|
38831
|
+
top: calc(
|
|
38832
|
+
var(--navi-transition-window-old-top) - var(
|
|
38833
|
+
--navi-transition-window-top
|
|
38834
|
+
)
|
|
38835
|
+
);
|
|
38836
|
+
left: calc(
|
|
38837
|
+
var(--navi-transition-window-old-left) - var(
|
|
38838
|
+
--navi-transition-window-left
|
|
38839
|
+
)
|
|
38840
|
+
);
|
|
38841
|
+
}
|
|
38842
|
+
|
|
38843
|
+
/* ------------------------------------------------------------------
|
|
38844
|
+
The movements. One of \`root\` and \`navi-route-transition\` exists at a
|
|
38845
|
+
time (see the opt-out above), so each is written for both.
|
|
38846
|
+
------------------------------------------------------------------ */
|
|
38847
|
+
&[data-navi-route-transition-type="slide-x"],
|
|
38848
|
+
&[data-navi-route-transition-type="slide-y"],
|
|
38849
|
+
&[data-navi-route-transition-type="cover-x"],
|
|
38850
|
+
&[data-navi-route-transition-type="cover-y"] {
|
|
38851
|
+
&::view-transition-old(root),
|
|
38852
|
+
&::view-transition-new(root),
|
|
38853
|
+
&::view-transition-old(navi-route-transition),
|
|
38854
|
+
&::view-transition-new(navi-route-transition) {
|
|
38855
|
+
width: auto;
|
|
38856
|
+
/* Each picture at the size it was taken at: a page is not resized by
|
|
38857
|
+
the page it crosses. The picture is as wide as the box the browser
|
|
38858
|
+
gives it — the arriving one's — so a page leaving a narrower box (a
|
|
38859
|
+
scrollbar appeared, a side panel closed) would be seen zooming over
|
|
38860
|
+
the length of the movement. Left to the untyped cross-fade, where
|
|
38861
|
+
scaling one picture into the other is the whole idea. */
|
|
38862
|
+
height: auto;
|
|
38863
|
+
object-fit: none;
|
|
38864
|
+
object-position: top left;
|
|
38484
38865
|
/* The default cross-fade, dropped: two pages sliding past each other
|
|
38485
38866
|
are two solid things, and seeing through one to the other says they
|
|
38486
38867
|
are the same page changing its mind. */
|
|
@@ -38489,183 +38870,177 @@ const movementsCSS = (name, guard) => /* css */`
|
|
|
38489
38870
|
animation-fill-mode: both;
|
|
38490
38871
|
}
|
|
38491
38872
|
}
|
|
38492
|
-
|
|
38493
|
-
|
|
38494
|
-
|
|
38873
|
+
|
|
38874
|
+
&[data-navi-route-transition-type="slide-x"] {
|
|
38875
|
+
&[data-navi-route-transition="forward"] {
|
|
38876
|
+
&::view-transition-old(root),
|
|
38877
|
+
&::view-transition-old(navi-route-transition) {
|
|
38495
38878
|
animation-name: navi-route-transition-leave-towards-start;
|
|
38496
38879
|
}
|
|
38497
|
-
&::view-transition-new(
|
|
38880
|
+
&::view-transition-new(root),
|
|
38881
|
+
&::view-transition-new(navi-route-transition) {
|
|
38498
38882
|
animation-name: navi-route-transition-enter-from-end;
|
|
38499
38883
|
}
|
|
38500
38884
|
}
|
|
38501
|
-
&[
|
|
38502
|
-
&::view-transition-old(
|
|
38885
|
+
&[data-navi-route-transition="back"] {
|
|
38886
|
+
&::view-transition-old(root),
|
|
38887
|
+
&::view-transition-old(navi-route-transition) {
|
|
38503
38888
|
animation-name: navi-route-transition-leave-towards-end;
|
|
38504
38889
|
}
|
|
38505
|
-
&::view-transition-new(
|
|
38890
|
+
&::view-transition-new(root),
|
|
38891
|
+
&::view-transition-new(navi-route-transition) {
|
|
38506
38892
|
animation-name: navi-route-transition-enter-from-start;
|
|
38507
38893
|
}
|
|
38508
38894
|
}
|
|
38509
38895
|
}
|
|
38896
|
+
|
|
38510
38897
|
/* The same four movements, along the other axis: the start of a column is
|
|
38511
38898
|
its top, so going forward there is the page rising and the next one
|
|
38512
38899
|
coming up from below. */
|
|
38513
|
-
&[
|
|
38514
|
-
&[
|
|
38515
|
-
&::view-transition-old(
|
|
38900
|
+
&[data-navi-route-transition-type="slide-y"] {
|
|
38901
|
+
&[data-navi-route-transition="forward"] {
|
|
38902
|
+
&::view-transition-old(root),
|
|
38903
|
+
&::view-transition-old(navi-route-transition) {
|
|
38516
38904
|
animation-name: navi-route-transition-leave-towards-top;
|
|
38517
38905
|
}
|
|
38518
|
-
&::view-transition-new(
|
|
38906
|
+
&::view-transition-new(root),
|
|
38907
|
+
&::view-transition-new(navi-route-transition) {
|
|
38519
38908
|
animation-name: navi-route-transition-enter-from-bottom;
|
|
38520
38909
|
}
|
|
38521
38910
|
}
|
|
38522
|
-
&[
|
|
38523
|
-
&::view-transition-old(
|
|
38911
|
+
&[data-navi-route-transition="back"] {
|
|
38912
|
+
&::view-transition-old(root),
|
|
38913
|
+
&::view-transition-old(navi-route-transition) {
|
|
38524
38914
|
animation-name: navi-route-transition-leave-towards-bottom;
|
|
38525
38915
|
}
|
|
38526
|
-
&::view-transition-new(
|
|
38916
|
+
&::view-transition-new(root),
|
|
38917
|
+
&::view-transition-new(navi-route-transition) {
|
|
38527
38918
|
animation-name: navi-route-transition-enter-from-top;
|
|
38528
38919
|
}
|
|
38529
38920
|
}
|
|
38530
38921
|
}
|
|
38922
|
+
|
|
38531
38923
|
/* One page over the other, the way a sheet covers a desk: the page
|
|
38532
38924
|
arriving slides in ON TOP of one that does not move, and going back it
|
|
38533
38925
|
slides off, uncovering it. The still page is animated all the same — to
|
|
38534
38926
|
a keyframe that goes nowhere — because left to the browser it would
|
|
38535
38927
|
fade. */
|
|
38536
|
-
&[
|
|
38537
|
-
&[
|
|
38538
|
-
&::view-transition-old(
|
|
38928
|
+
&[data-navi-route-transition-type="cover-x"] {
|
|
38929
|
+
&[data-navi-route-transition="forward"] {
|
|
38930
|
+
&::view-transition-old(root),
|
|
38931
|
+
&::view-transition-old(navi-route-transition) {
|
|
38539
38932
|
animation-name: navi-route-transition-still;
|
|
38540
38933
|
}
|
|
38541
|
-
&::view-transition-new(
|
|
38934
|
+
&::view-transition-new(root),
|
|
38935
|
+
&::view-transition-new(navi-route-transition) {
|
|
38542
38936
|
animation-name: navi-route-transition-enter-from-end;
|
|
38543
38937
|
}
|
|
38544
38938
|
}
|
|
38545
|
-
&[
|
|
38546
|
-
&::view-transition-old(
|
|
38939
|
+
&[data-navi-route-transition="back"] {
|
|
38940
|
+
&::view-transition-old(root),
|
|
38941
|
+
&::view-transition-old(navi-route-transition) {
|
|
38547
38942
|
/* 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
|
-
|
|
38943
|
+
uncovers, against the browser's default of drawing the new page on
|
|
38944
|
+
top. */
|
|
38550
38945
|
z-index: 1;
|
|
38551
38946
|
animation-name: navi-route-transition-leave-towards-end;
|
|
38552
38947
|
}
|
|
38553
|
-
&::view-transition-new(
|
|
38948
|
+
&::view-transition-new(root),
|
|
38949
|
+
&::view-transition-new(navi-route-transition) {
|
|
38554
38950
|
animation-name: navi-route-transition-still;
|
|
38555
38951
|
}
|
|
38556
38952
|
}
|
|
38557
38953
|
}
|
|
38558
|
-
&[
|
|
38559
|
-
&[
|
|
38560
|
-
&::view-transition-old(
|
|
38954
|
+
&[data-navi-route-transition-type="cover-y"] {
|
|
38955
|
+
&[data-navi-route-transition="forward"] {
|
|
38956
|
+
&::view-transition-old(root),
|
|
38957
|
+
&::view-transition-old(navi-route-transition) {
|
|
38561
38958
|
animation-name: navi-route-transition-still;
|
|
38562
38959
|
}
|
|
38563
|
-
&::view-transition-new(
|
|
38960
|
+
&::view-transition-new(root),
|
|
38961
|
+
&::view-transition-new(navi-route-transition) {
|
|
38564
38962
|
animation-name: navi-route-transition-enter-from-bottom;
|
|
38565
38963
|
}
|
|
38566
38964
|
}
|
|
38567
|
-
&[
|
|
38568
|
-
&::view-transition-old(
|
|
38965
|
+
&[data-navi-route-transition="back"] {
|
|
38966
|
+
&::view-transition-old(root),
|
|
38967
|
+
&::view-transition-old(navi-route-transition) {
|
|
38569
38968
|
z-index: 1;
|
|
38570
38969
|
animation-name: navi-route-transition-leave-towards-bottom;
|
|
38571
38970
|
}
|
|
38572
|
-
&::view-transition-new(
|
|
38971
|
+
&::view-transition-new(root),
|
|
38972
|
+
&::view-transition-new(navi-route-transition) {
|
|
38573
38973
|
animation-name: navi-route-transition-still;
|
|
38574
38974
|
}
|
|
38575
38975
|
}
|
|
38576
38976
|
}
|
|
38977
|
+
|
|
38577
38978
|
/* Going deeper is coming closer: the page arriving lands from slightly too
|
|
38578
38979
|
big, and going back it is the page leaving that grows away. The other
|
|
38579
38980
|
side keeps the browser's own fade under it. */
|
|
38580
|
-
&[
|
|
38581
|
-
&::view-transition-old(
|
|
38582
|
-
&::view-transition-new(
|
|
38981
|
+
&[data-navi-route-transition-type="zoom"] {
|
|
38982
|
+
&::view-transition-old(root),
|
|
38983
|
+
&::view-transition-new(root),
|
|
38984
|
+
&::view-transition-old(navi-route-transition),
|
|
38985
|
+
&::view-transition-new(navi-route-transition) {
|
|
38583
38986
|
animation-fill-mode: both;
|
|
38584
38987
|
}
|
|
38585
|
-
&[
|
|
38586
|
-
&::view-transition-new(
|
|
38988
|
+
&[data-navi-route-transition="forward"] {
|
|
38989
|
+
&::view-transition-new(root),
|
|
38990
|
+
&::view-transition-new(navi-route-transition) {
|
|
38587
38991
|
animation-name: navi-route-transition-zoom-in;
|
|
38588
38992
|
}
|
|
38589
38993
|
}
|
|
38590
|
-
&[
|
|
38591
|
-
&::view-transition-old(
|
|
38994
|
+
&[data-navi-route-transition="back"] {
|
|
38995
|
+
&::view-transition-old(root),
|
|
38996
|
+
&::view-transition-old(navi-route-transition) {
|
|
38592
38997
|
animation-name: navi-route-transition-zoom-out;
|
|
38593
38998
|
}
|
|
38594
38999
|
}
|
|
38595
39000
|
}
|
|
38596
39001
|
}
|
|
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
39002
|
|
|
39003
|
+
/* One window's worth of movement. The fallback is the picture's own size,
|
|
39004
|
+
which is what the window is when the whole document travels: the root
|
|
39005
|
+
picture IS the viewport. */
|
|
38631
39006
|
@keyframes navi-route-transition-leave-towards-start {
|
|
38632
39007
|
to {
|
|
38633
|
-
translate: -100% 0;
|
|
39008
|
+
translate: calc(-1 * var(--navi-route-transition-travel-x, 100%)) 0;
|
|
38634
39009
|
}
|
|
38635
39010
|
}
|
|
38636
39011
|
@keyframes navi-route-transition-enter-from-end {
|
|
38637
39012
|
from {
|
|
38638
|
-
translate: 100% 0;
|
|
39013
|
+
translate: var(--navi-route-transition-travel-x, 100%) 0;
|
|
38639
39014
|
}
|
|
38640
39015
|
}
|
|
38641
39016
|
@keyframes navi-route-transition-leave-towards-end {
|
|
38642
39017
|
to {
|
|
38643
|
-
translate: 100% 0;
|
|
39018
|
+
translate: var(--navi-route-transition-travel-x, 100%) 0;
|
|
38644
39019
|
}
|
|
38645
39020
|
}
|
|
38646
39021
|
@keyframes navi-route-transition-enter-from-start {
|
|
38647
39022
|
from {
|
|
38648
|
-
translate: -100% 0;
|
|
39023
|
+
translate: calc(-1 * var(--navi-route-transition-travel-x, 100%)) 0;
|
|
38649
39024
|
}
|
|
38650
39025
|
}
|
|
38651
39026
|
@keyframes navi-route-transition-leave-towards-top {
|
|
38652
39027
|
to {
|
|
38653
|
-
translate: 0 -100
|
|
39028
|
+
translate: 0 calc(-1 * var(--navi-route-transition-travel-y, 100%));
|
|
38654
39029
|
}
|
|
38655
39030
|
}
|
|
38656
39031
|
@keyframes navi-route-transition-enter-from-bottom {
|
|
38657
39032
|
from {
|
|
38658
|
-
translate: 0 100
|
|
39033
|
+
translate: 0 var(--navi-route-transition-travel-y, 100%);
|
|
38659
39034
|
}
|
|
38660
39035
|
}
|
|
38661
39036
|
@keyframes navi-route-transition-leave-towards-bottom {
|
|
38662
39037
|
to {
|
|
38663
|
-
translate: 0 100
|
|
39038
|
+
translate: 0 var(--navi-route-transition-travel-y, 100%);
|
|
38664
39039
|
}
|
|
38665
39040
|
}
|
|
38666
39041
|
@keyframes navi-route-transition-enter-from-top {
|
|
38667
39042
|
from {
|
|
38668
|
-
translate: 0 -100
|
|
39043
|
+
translate: 0 calc(-1 * var(--navi-route-transition-travel-y, 100%));
|
|
38669
39044
|
}
|
|
38670
39045
|
}
|
|
38671
39046
|
@keyframes navi-route-transition-zoom-in {
|
|
@@ -38689,6 +39064,41 @@ const css$T = /* css */`
|
|
|
38689
39064
|
}
|
|
38690
39065
|
`;
|
|
38691
39066
|
|
|
39067
|
+
/**
|
|
39068
|
+
* The region the pages live in — where the movements play.
|
|
39069
|
+
*
|
|
39070
|
+
* Wrap the `<Route>` tree with it in an application that has fixed furniture
|
|
39071
|
+
* (a top bar, a tab bar): the movements then play on THIS element's pictures,
|
|
39072
|
+
* clipped at its bounds, and the bars never move. Without it the document
|
|
39073
|
+
* itself travels, which is right only when the pages are the whole viewport —
|
|
39074
|
+
* with bars around, the moving root picture drags a blank band across the
|
|
39075
|
+
* screen where they stand.
|
|
39076
|
+
*
|
|
39077
|
+
* It is a real box, and it must be: what is photographed and clipped IS its
|
|
39078
|
+
* rectangle. So `display: contents` cannot be used on it — an element with no
|
|
39079
|
+
* box is never captured, the movement plays on nothing and the browser aborts
|
|
39080
|
+
* the transition. Give it the layout the pages need instead — it is a `Box`,
|
|
39081
|
+
* so `flex`, `className`, `style` and the rest are there for that. An
|
|
39082
|
+
* application that already has an element holding its pages can mark that one
|
|
39083
|
+
* with `data-navi-route-transition-area` rather than nesting another.
|
|
39084
|
+
*
|
|
39085
|
+
* @type {import("ignore:preact").FunctionComponent<{ children?: any, [key: string]: any }>}
|
|
39086
|
+
*/
|
|
39087
|
+
const RouteTransitionArea = ({
|
|
39088
|
+
children,
|
|
39089
|
+
...rest
|
|
39090
|
+
}) => {
|
|
39091
|
+
import.meta.css = [css$T, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
39092
|
+
const props = {
|
|
39093
|
+
...rest,
|
|
39094
|
+
[TRANSITION_AREA_ATTRIBUTE]: ""
|
|
39095
|
+
};
|
|
39096
|
+
return jsx(Box, {
|
|
39097
|
+
...props,
|
|
39098
|
+
children: children
|
|
39099
|
+
});
|
|
39100
|
+
};
|
|
39101
|
+
|
|
38692
39102
|
/**
|
|
38693
39103
|
* Declare how a pair of routes moves against each other.
|
|
38694
39104
|
*
|
|
@@ -38729,7 +39139,7 @@ const css$T = /* css */`
|
|
|
38729
39139
|
* @returns {() => void} remove this relation.
|
|
38730
39140
|
*/
|
|
38731
39141
|
const defineRouteTransition = (from, to, transition) => {
|
|
38732
|
-
import.meta.css = [css$T, "@jsenv/navi/src/nav/route_transition.
|
|
39142
|
+
import.meta.css = [css$T, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
38733
39143
|
const {
|
|
38734
39144
|
type,
|
|
38735
39145
|
duration
|
|
@@ -38767,7 +39177,7 @@ const defineRouteTransition = (from, to, transition) => {
|
|
|
38767
39177
|
* @returns {() => void} remove this default.
|
|
38768
39178
|
*/
|
|
38769
39179
|
const defineRouteDefaultTransition = transition => {
|
|
38770
|
-
import.meta.css = [css$T, "@jsenv/navi/src/nav/route_transition.
|
|
39180
|
+
import.meta.css = [css$T, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
38771
39181
|
const value = normalizeTransition(transition);
|
|
38772
39182
|
defaultTransition = value;
|
|
38773
39183
|
updateRoutingObservers();
|
|
@@ -38971,8 +39381,17 @@ const beginTransition = ({
|
|
|
38971
39381
|
// Looked up per transition, not once: the area is the application's own
|
|
38972
39382
|
// element and follows its lifecycle — a page layout without bars has none,
|
|
38973
39383
|
// and the movement then plays on the document itself.
|
|
38974
|
-
|
|
39384
|
+
const areaElements = document.querySelectorAll(`[${TRANSITION_AREA_ATTRIBUTE}]`);
|
|
39385
|
+
if (areaElements.length > 1) {
|
|
39386
|
+
warnOnce("several-areas", `${areaElements.length} elements carry ${TRANSITION_AREA_ATTRIBUTE}. They all take the same view-transition-name, and a name belongs to one element at a time: the browser refuses EVERY view transition of the document while this holds. Mark the one element the pages live in.`);
|
|
39387
|
+
}
|
|
39388
|
+
const areaElement = areaElements.length > 0 ? areaElements[0] : null;
|
|
39389
|
+
// The area as it stands before anything moves: rendering is held, so this is
|
|
39390
|
+
// still the page being left (see holdAreaGeometry).
|
|
39391
|
+
let areaRectBefore = null;
|
|
39392
|
+
if (areaElement) {
|
|
38975
39393
|
documentElement.setAttribute(TRANSITION_TARGET_ATTRIBUTE, "area");
|
|
39394
|
+
areaRectBefore = areaElement.getBoundingClientRect();
|
|
38976
39395
|
}
|
|
38977
39396
|
// A duration of this relation's own, worn for the length of the transition —
|
|
38978
39397
|
// and whatever the application had written inline put back afterwards, not
|
|
@@ -38995,6 +39414,28 @@ const beginTransition = ({
|
|
|
38995
39414
|
// been decided renders its page in between — a wait armed then waits for
|
|
38996
39415
|
// something that has already happened.
|
|
38997
39416
|
const renderWait = armRouteRenderWait$1();
|
|
39417
|
+
// What the browser ACTUALLY captured, read once the pictures exist: it is
|
|
39418
|
+
// the only place the two silent misconfigurations show. Both are about the
|
|
39419
|
+
// same thing — a movement playing on pictures that are not the pages.
|
|
39420
|
+
const viewTransitionReady = () => {
|
|
39421
|
+
const capturedNames = capturedViewTransitionNames();
|
|
39422
|
+
if (areaElements.length > 0) {
|
|
39423
|
+
if (!capturedNames.has(AREA_NAME)) {
|
|
39424
|
+
warnOnce("area-not-captured", `The element marked ${TRANSITION_AREA_ATTRIBUTE} was not captured, so the movement plays on nothing. An element is captured only if it generates a box: \`display: contents\` (or an element not rendered) cannot be the area — its rectangle is what gets photographed and clipped.`);
|
|
39425
|
+
}
|
|
39426
|
+
return;
|
|
39427
|
+
}
|
|
39428
|
+
for (const name of capturedNames) {
|
|
39429
|
+
if (name === "root") {
|
|
39430
|
+
continue;
|
|
39431
|
+
}
|
|
39432
|
+
// Something stands still while the whole document travels under it. The
|
|
39433
|
+
// root picture spans the viewport and has a HOLE where that thing was
|
|
39434
|
+
// captured, so what crosses the screen is a blank band.
|
|
39435
|
+
warnOnce("pages-travel-under-named-elements", `The movement plays on the whole document while "${name}" is captured on its own, so a blank band travels where it stands. Wrap the pages in <RouteTransitionArea> (or mark their element with ${TRANSITION_AREA_ATTRIBUTE}) so the movement plays on them rather than on the document.`);
|
|
39436
|
+
break;
|
|
39437
|
+
}
|
|
39438
|
+
};
|
|
38998
39439
|
const viewTransition = startViewTransition$1(async () => {
|
|
38999
39440
|
// The picture the browser is about to take must be of the page that was
|
|
39000
39441
|
// asked for, and a route matching is not yet a page rendered. Whatever
|
|
@@ -39016,6 +39457,11 @@ const beginTransition = ({
|
|
|
39016
39457
|
} finally {
|
|
39017
39458
|
renderWait.stop();
|
|
39018
39459
|
}
|
|
39460
|
+
// The page arriving is in the DOM and the transition has not started
|
|
39461
|
+
// playing: the one moment both states of the area can be known.
|
|
39462
|
+
if (areaElement) {
|
|
39463
|
+
holdTransitionWindow(transition, areaElement, areaRectBefore);
|
|
39464
|
+
}
|
|
39019
39465
|
});
|
|
39020
39466
|
const end = () => {
|
|
39021
39467
|
// Whatever ends it — played out, skipped by another transition starting,
|
|
@@ -39030,14 +39476,50 @@ const beginTransition = ({
|
|
|
39030
39476
|
documentElement.removeAttribute(TRANSITION_ATTRIBUTE);
|
|
39031
39477
|
documentElement.removeAttribute(TRANSITION_TYPE_ATTRIBUTE);
|
|
39032
39478
|
documentElement.removeAttribute(TRANSITION_TARGET_ATTRIBUTE);
|
|
39479
|
+
releaseTransitionWindow(transition);
|
|
39033
39480
|
if (restoreDuration) {
|
|
39034
39481
|
restoreDuration();
|
|
39035
39482
|
}
|
|
39036
39483
|
}
|
|
39037
39484
|
};
|
|
39485
|
+
viewTransition.ready.then(viewTransitionReady, ignoreSkipped$1);
|
|
39038
39486
|
viewTransition.finished.then(end, end);
|
|
39039
39487
|
};
|
|
39040
39488
|
|
|
39489
|
+
// A transition skipped by another one starting is an outcome, not a failure.
|
|
39490
|
+
const ignoreSkipped$1 = () => {};
|
|
39491
|
+
|
|
39492
|
+
// The names the browser captured, read off the pictures themselves: what was
|
|
39493
|
+
// asked for in CSS and what was taken are not the same question (see
|
|
39494
|
+
// viewTransitionReady).
|
|
39495
|
+
const capturedViewTransitionNames = () => {
|
|
39496
|
+
const names = new Set();
|
|
39497
|
+
for (const animation of document.getAnimations()) {
|
|
39498
|
+
const pseudoElement = animation.effect?.pseudoElement;
|
|
39499
|
+
if (!pseudoElement || !pseudoElement.startsWith("::view-transition")) {
|
|
39500
|
+
continue;
|
|
39501
|
+
}
|
|
39502
|
+
const nameStart = pseudoElement.indexOf("(");
|
|
39503
|
+
if (nameStart === -1) {
|
|
39504
|
+
continue;
|
|
39505
|
+
}
|
|
39506
|
+
names.add(pseudoElement.slice(nameStart + 1, -1));
|
|
39507
|
+
}
|
|
39508
|
+
return names;
|
|
39509
|
+
};
|
|
39510
|
+
|
|
39511
|
+
// Said once per kind, whatever the number of navigations: a misconfiguration
|
|
39512
|
+
// is one fact about the application, and repeating it every time the user
|
|
39513
|
+
// moves would bury it.
|
|
39514
|
+
const warningsSaid = new Set();
|
|
39515
|
+
const warnOnce = (id, message) => {
|
|
39516
|
+
if (warningsSaid.has(id)) {
|
|
39517
|
+
return;
|
|
39518
|
+
}
|
|
39519
|
+
warningsSaid.add(id);
|
|
39520
|
+
console.warn(message);
|
|
39521
|
+
};
|
|
39522
|
+
|
|
39041
39523
|
// A route matching is a signal changing; how many passes Preact takes to
|
|
39042
39524
|
// answer it is its own business, and the render is the moment the picture can
|
|
39043
39525
|
// be taken. Listening starts before the change, or a render landing while the
|
|
@@ -39159,19 +39641,6 @@ const DRAGGED_ATTRIBUTE = "data-navi-route-travel-dragged";
|
|
|
39159
39641
|
const TURNED_ATTRIBUTE = "data-navi-route-travel-turned";
|
|
39160
39642
|
// The name the box wears while it travels, and only then (see nameForTravel).
|
|
39161
39643
|
const TRAVEL_NAME = "navi-route-travel";
|
|
39162
|
-
// Where the two boxes of a travel stand in the window, published for the
|
|
39163
|
-
// length of it. Measurements only: what is DERIVED from them — where a picture
|
|
39164
|
-
// goes, what a bar covers — is derived in the CSS below, so the app's own
|
|
39165
|
-
// numbers (the room its fixed bars take) can take part in it. Only the
|
|
39166
|
-
// measuring needs JS, and only for the one moment both boxes exist (see
|
|
39167
|
-
// holdTravelGeometry).
|
|
39168
|
-
const TRAVEL_TOP_PROPERTY = "--navi-route-travel-top";
|
|
39169
|
-
const TRAVEL_LEFT_PROPERTY = "--navi-route-travel-left";
|
|
39170
|
-
const TRAVEL_WIDTH_PROPERTY = "--navi-route-travel-width";
|
|
39171
|
-
const TRAVEL_HEIGHT_PROPERTY = "--navi-route-travel-height";
|
|
39172
|
-
const TRAVEL_OLD_TOP_PROPERTY = "--navi-route-travel-old-top";
|
|
39173
|
-
const TRAVEL_OLD_LEFT_PROPERTY = "--navi-route-travel-old-left";
|
|
39174
|
-
const TRAVEL_GEOMETRY_PROPERTIES = [TRAVEL_TOP_PROPERTY, TRAVEL_LEFT_PROPERTY, TRAVEL_WIDTH_PROPERTY, TRAVEL_HEIGHT_PROPERTY, TRAVEL_OLD_TOP_PROPERTY, TRAVEL_OLD_LEFT_PROPERTY];
|
|
39175
39644
|
const css$S = /* css */`
|
|
39176
39645
|
/* The name that makes the page inside this box a picture of its own during a
|
|
39177
39646
|
transition — rather than part of the one big picture the document takes, so
|
|
@@ -39254,10 +39723,16 @@ const css$S = /* css */`
|
|
|
39254
39723
|
would be seen jumping back to its top before it even begins to leave.
|
|
39255
39724
|
Offset here rather than by \`translate\`, which the movement itself uses,
|
|
39256
39725
|
and at its own size rather than the group's so that nothing is cut off
|
|
39257
|
-
the far side of the shift (see
|
|
39258
|
-
top: calc(
|
|
39726
|
+
the far side of the shift (see transition_window.js). */
|
|
39727
|
+
top: calc(
|
|
39728
|
+
var(--navi-transition-window-old-top) - var(
|
|
39729
|
+
--navi-transition-window-top
|
|
39730
|
+
)
|
|
39731
|
+
);
|
|
39259
39732
|
left: calc(
|
|
39260
|
-
var(
|
|
39733
|
+
var(--navi-transition-window-old-left) - var(
|
|
39734
|
+
--navi-transition-window-left
|
|
39735
|
+
)
|
|
39261
39736
|
);
|
|
39262
39737
|
width: auto;
|
|
39263
39738
|
}
|
|
@@ -39272,7 +39747,7 @@ const css$S = /* css */`
|
|
|
39272
39747
|
}
|
|
39273
39748
|
&::view-transition-group(navi-route-travel) {
|
|
39274
39749
|
/* The window the two pictures are seen through, held still for the whole
|
|
39275
|
-
travel at the taller of the two boxes (see
|
|
39750
|
+
travel at the taller of the two boxes (see transition_window.js): the group
|
|
39276
39751
|
is what CLIPS, and the browser animates its height from the box being
|
|
39277
39752
|
left to the box arriving — so the window shrinks under the pictures and
|
|
39278
39753
|
cuts the page leaving from the bottom, progressively. The box does end
|
|
@@ -39283,7 +39758,7 @@ const css$S = /* css */`
|
|
|
39283
39758
|
winning against it with !important — which also drops its position
|
|
39284
39759
|
animation, fine while a travel box stands in the same place from one
|
|
39285
39760
|
route to the next. */
|
|
39286
|
-
height: var(
|
|
39761
|
+
height: var(--navi-transition-window-height);
|
|
39287
39762
|
|
|
39288
39763
|
/* Cut at the safe area, on top of being cut at the box. The pictures are
|
|
39289
39764
|
drawn in the top layer, so they cover a fixed bar as easily as anything
|
|
@@ -39300,20 +39775,22 @@ const css$S = /* css */`
|
|
|
39300
39775
|
only where it itself stands, and that is the measured half. */
|
|
39301
39776
|
--navi-route-travel-clip-top: max(
|
|
39302
39777
|
0px,
|
|
39303
|
-
var(--navi-safe-area-inset-top) - var(
|
|
39778
|
+
var(--navi-safe-area-inset-top) - var(--navi-transition-window-top)
|
|
39304
39779
|
);
|
|
39305
39780
|
--navi-route-travel-clip-left: max(
|
|
39306
39781
|
0px,
|
|
39307
|
-
var(--navi-safe-area-inset-left) - var(
|
|
39782
|
+
var(--navi-safe-area-inset-left) - var(--navi-transition-window-left)
|
|
39308
39783
|
);
|
|
39309
39784
|
--navi-route-travel-clip-bottom: max(
|
|
39310
39785
|
0px,
|
|
39311
|
-
var(
|
|
39786
|
+
var(--navi-transition-window-top) +
|
|
39787
|
+
var(--navi-transition-window-height) +
|
|
39312
39788
|
var(--navi-safe-area-inset-bottom) - 100dvh
|
|
39313
39789
|
);
|
|
39314
39790
|
--navi-route-travel-clip-right: max(
|
|
39315
39791
|
0px,
|
|
39316
|
-
var(
|
|
39792
|
+
var(--navi-transition-window-left) +
|
|
39793
|
+
var(--navi-transition-window-width) +
|
|
39317
39794
|
var(--navi-safe-area-inset-right) - 100dvw
|
|
39318
39795
|
);
|
|
39319
39796
|
clip-path: inset(
|
|
@@ -39635,7 +40112,7 @@ const RouteTravel = ({
|
|
|
39635
40112
|
}
|
|
39636
40113
|
pageAskedForRef.current = page;
|
|
39637
40114
|
// The box as it stands before anything moves: rendering is held, so this is
|
|
39638
|
-
// still the page being left (see
|
|
40115
|
+
// still the page being left (see transition_window.js).
|
|
39639
40116
|
const rectBefore = elementRef.current.getBoundingClientRect();
|
|
39640
40117
|
// The hold a navigation already took, if this travel is the answer to one:
|
|
39641
40118
|
// taking another would be taking a hold on a page that is holding still.
|
|
@@ -39663,7 +40140,7 @@ const RouteTravel = ({
|
|
|
39663
40140
|
}, renderWait);
|
|
39664
40141
|
// The page arriving is in the DOM and the transition has not started
|
|
39665
40142
|
// playing: the one moment both boxes can be known.
|
|
39666
|
-
|
|
40143
|
+
holdTransitionWindow(travel, elementRef.current, rectBefore);
|
|
39667
40144
|
});
|
|
39668
40145
|
travel.viewTransition = viewTransition;
|
|
39669
40146
|
if (scrub) {
|
|
@@ -39981,7 +40458,7 @@ const RouteTravel = ({
|
|
|
39981
40458
|
document.documentElement.removeAttribute(TRAVEL_AXIS_ATTRIBUTE);
|
|
39982
40459
|
document.documentElement.removeAttribute(DRAGGED_ATTRIBUTE);
|
|
39983
40460
|
document.documentElement.removeAttribute(TURNED_ATTRIBUTE);
|
|
39984
|
-
|
|
40461
|
+
releaseTransitionWindow(travel);
|
|
39985
40462
|
}
|
|
39986
40463
|
};
|
|
39987
40464
|
|
|
@@ -40364,44 +40841,6 @@ const releaseHold = travel => {
|
|
|
40364
40841
|
document.documentElement.removeAttribute(HOLD_ATTRIBUTE);
|
|
40365
40842
|
};
|
|
40366
40843
|
|
|
40367
|
-
// The two boxes of a travel, measured at the one moment both exist: the
|
|
40368
|
-
// arriving page is in the DOM and the transition has not started playing.
|
|
40369
|
-
//
|
|
40370
|
-
// The group stands at the ARRIVING box — its own animation is dropped, so it
|
|
40371
|
-
// takes the geometry the browser declared for it and holds it for the whole
|
|
40372
|
-
// travel. That is why both rectangles have to be published: a group that does
|
|
40373
|
-
// not move says nothing about where the page being left was, and its rectangle
|
|
40374
|
-
// in the window is the only thing CSS cannot work out on its own.
|
|
40375
|
-
const holdTravelGeometry = (element, rectBefore) => {
|
|
40376
|
-
const rectAfter = element.getBoundingClientRect();
|
|
40377
|
-
// The height it is held at is the taller of the two boxes, so neither picture
|
|
40378
|
-
// is ever cut. It cannot be measured from one side alone: a page arriving
|
|
40379
|
-
// shorter than the one it replaces would cut the one leaving, a page arriving
|
|
40380
|
-
// taller would be cut itself.
|
|
40381
|
-
const height = rectBefore.height > rectAfter.height ? rectBefore.height : rectAfter.height;
|
|
40382
|
-
const {
|
|
40383
|
-
style
|
|
40384
|
-
} = document.documentElement;
|
|
40385
|
-
style.setProperty(TRAVEL_TOP_PROPERTY, `${rectAfter.top}px`);
|
|
40386
|
-
style.setProperty(TRAVEL_LEFT_PROPERTY, `${rectAfter.left}px`);
|
|
40387
|
-
style.setProperty(TRAVEL_WIDTH_PROPERTY, `${rectAfter.width}px`);
|
|
40388
|
-
style.setProperty(TRAVEL_HEIGHT_PROPERTY, `${height}px`);
|
|
40389
|
-
style.setProperty(TRAVEL_OLD_TOP_PROPERTY, `${rectBefore.top}px`);
|
|
40390
|
-
style.setProperty(TRAVEL_OLD_LEFT_PROPERTY, `${rectBefore.left}px`);
|
|
40391
|
-
};
|
|
40392
|
-
// The live layout takes the box back. A discontinuity by construction — the
|
|
40393
|
-
// group stands at the held height, the box is at the new one — and an invisible
|
|
40394
|
-
// one: the page arriving is fully in place, and the strip below it that the
|
|
40395
|
-
// group still covers shows the page leaving only while it is still on screen.
|
|
40396
|
-
const releaseTravelGeometry = () => {
|
|
40397
|
-
const {
|
|
40398
|
-
style
|
|
40399
|
-
} = document.documentElement;
|
|
40400
|
-
for (const property of TRAVEL_GEOMETRY_PROPERTIES) {
|
|
40401
|
-
style.removeProperty(property);
|
|
40402
|
-
}
|
|
40403
|
-
};
|
|
40404
|
-
|
|
40405
40844
|
// The animations of the pictures, asked for again until there are some: they
|
|
40406
40845
|
// come into existence with the transition, several frames after it was asked
|
|
40407
40846
|
// for, and the gesture has already begun by then. Kept once found — the set
|
|
@@ -73738,5 +74177,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
73738
74177
|
})
|
|
73739
74178
|
});
|
|
73740
74179
|
|
|
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 };
|
|
74180
|
+
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, RouteTransitionArea, 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 };
|
|
73742
74181
|
//# sourceMappingURL=jsenv_navi.js.map
|