@jsenv/navi 0.29.117 → 0.29.118
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 +145 -28
- package/dist/jsenv_navi.js.map +20 -9
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -26618,6 +26618,49 @@ const RouteUI = ({
|
|
|
26618
26618
|
return element;
|
|
26619
26619
|
};
|
|
26620
26620
|
|
|
26621
|
+
/**
|
|
26622
|
+
* Where a route movement is heading, said before its first picture is taken.
|
|
26623
|
+
*
|
|
26624
|
+
* A view transition pairs, across its two pictures, whatever wears the same
|
|
26625
|
+
* name on both — and a name is read off the DOM as it stands when the
|
|
26626
|
+
* transition starts. So whoever names an element for a movement between two
|
|
26627
|
+
* pages (the bar under the current tab of a <Nav>, which glides from one tab
|
|
26628
|
+
* to the next) has to decide whether this movement is one it takes part in
|
|
26629
|
+
* before that reading: on a page the row is not on, its bar must leave with the
|
|
26630
|
+
* page, unnamed.
|
|
26631
|
+
*
|
|
26632
|
+
* Everything that decision needs is on the page itself, except one thing:
|
|
26633
|
+
* where the movement goes. That is what is published here, by whoever starts
|
|
26634
|
+
* the movement — route_transition.jsx for a relation between two pages,
|
|
26635
|
+
* route_travel.jsx for a row a finger pushes — before their transition starts.
|
|
26636
|
+
* The navigation's own announcement (before_routing.js) cannot stand in for
|
|
26637
|
+
* it: a travel a finger sets off starts its transition first and navigates
|
|
26638
|
+
* from inside it.
|
|
26639
|
+
*
|
|
26640
|
+
* Only one movement plays at a time (one view transition per document), which
|
|
26641
|
+
* is what lets both say it in one place. Taken down by the one that put it up,
|
|
26642
|
+
* and by it alone: a movement ending after another has replaced it must not
|
|
26643
|
+
* wipe what the new one stands on.
|
|
26644
|
+
*/
|
|
26645
|
+
|
|
26646
|
+
|
|
26647
|
+
const [publishDestination, observeTransitionDestination] = createPubSub();
|
|
26648
|
+
|
|
26649
|
+
let destinationOwner = null;
|
|
26650
|
+
|
|
26651
|
+
const holdTransitionDestination = (owner, url) => {
|
|
26652
|
+
destinationOwner = owner;
|
|
26653
|
+
publishDestination(new URL(url, window.location.href).href);
|
|
26654
|
+
};
|
|
26655
|
+
|
|
26656
|
+
const releaseTransitionDestination = (owner) => {
|
|
26657
|
+
if (owner !== destinationOwner) {
|
|
26658
|
+
return;
|
|
26659
|
+
}
|
|
26660
|
+
destinationOwner = null;
|
|
26661
|
+
publishDestination(null);
|
|
26662
|
+
};
|
|
26663
|
+
|
|
26621
26664
|
/**
|
|
26622
26665
|
* The window two pages are seen through while one replaces the other, measured
|
|
26623
26666
|
* once and published for the length of the movement.
|
|
@@ -27498,6 +27541,7 @@ const rebuildWatcher = () => {
|
|
|
27498
27541
|
}
|
|
27499
27542
|
beginTransition({
|
|
27500
27543
|
page: pages[index],
|
|
27544
|
+
url: navigationUrl,
|
|
27501
27545
|
// Which way it plays: what the navigation itself said first — the link
|
|
27502
27546
|
// being pressed is where the way the app is being walked is known — then
|
|
27503
27547
|
// the relation, and forward for a navigation that asked for a movement
|
|
@@ -27518,11 +27562,12 @@ const rebuildWatcher = () => {
|
|
|
27518
27562
|
|
|
27519
27563
|
// What plays when no relation matched (see defineRouteDefaultTransition), what
|
|
27520
27564
|
// the navigation now landing asked for on its own (see readNavigationRequest),
|
|
27521
|
-
// and whether it found an answer already — a relation's
|
|
27522
|
-
// a RouteTravel travel. The last
|
|
27523
|
-
// navigation, so they are always about the latest one.
|
|
27565
|
+
// where it goes, and whether it found an answer already — a relation's
|
|
27566
|
+
// transition, a "none", a RouteTravel travel. The last three are read at the
|
|
27567
|
+
// start of every navigation, so they are always about the latest one.
|
|
27524
27568
|
let defaultTransition = null;
|
|
27525
27569
|
let navigationRequest = null;
|
|
27570
|
+
let navigationUrl = null;
|
|
27526
27571
|
let navigationAnimated = false;
|
|
27527
27572
|
|
|
27528
27573
|
// The two ends of every navigation, watched from here on. The picture of the
|
|
@@ -27534,6 +27579,7 @@ let navigationAnimated = false;
|
|
|
27534
27579
|
observeBeforeRouting(details => {
|
|
27535
27580
|
navigationAnimated = false;
|
|
27536
27581
|
navigationRequest = readNavigationRequest(details);
|
|
27582
|
+
navigationUrl = details.url;
|
|
27537
27583
|
if (relations.length === 0 && !defaultTransition && !navigationRequest) {
|
|
27538
27584
|
return;
|
|
27539
27585
|
}
|
|
@@ -27541,9 +27587,11 @@ observeBeforeRouting(details => {
|
|
|
27541
27587
|
});
|
|
27542
27588
|
observeAfterRouting(() => {
|
|
27543
27589
|
const request = navigationRequest;
|
|
27590
|
+
const url = navigationUrl;
|
|
27544
27591
|
// Read here and dropped here: a request answers for the navigation it was
|
|
27545
27592
|
// made on, and the next one is back to the relations.
|
|
27546
27593
|
navigationRequest = null;
|
|
27594
|
+
navigationUrl = null;
|
|
27547
27595
|
if (!navigationAnimated && (request || defaultTransition)) {
|
|
27548
27596
|
const {
|
|
27549
27597
|
type,
|
|
@@ -27552,6 +27600,7 @@ observeAfterRouting(() => {
|
|
|
27552
27600
|
if (type !== "none") {
|
|
27553
27601
|
beginTransition({
|
|
27554
27602
|
page: null,
|
|
27603
|
+
url,
|
|
27555
27604
|
// A default has no direction: nothing says which of two arbitrary
|
|
27556
27605
|
// pages is before the other, and the attribute is then worn empty —
|
|
27557
27606
|
// present for whoever keys on "one of ours is playing", silent on the
|
|
@@ -27599,6 +27648,7 @@ const findRelation = (fromPage, toPage) => {
|
|
|
27599
27648
|
let currentTransition = null;
|
|
27600
27649
|
const beginTransition = ({
|
|
27601
27650
|
page,
|
|
27651
|
+
url,
|
|
27602
27652
|
direction,
|
|
27603
27653
|
type,
|
|
27604
27654
|
duration
|
|
@@ -27615,6 +27665,9 @@ const beginTransition = ({
|
|
|
27615
27665
|
}
|
|
27616
27666
|
const transition = {};
|
|
27617
27667
|
currentTransition = transition;
|
|
27668
|
+
// Said before the picture is taken: whoever names something for a movement
|
|
27669
|
+
// between two pages decides on it now (see transition_destination.js).
|
|
27670
|
+
holdTransitionDestination(transition, url);
|
|
27618
27671
|
documentElement.setAttribute(TRANSITION_ATTRIBUTE, direction);
|
|
27619
27672
|
if (type) {
|
|
27620
27673
|
documentElement.setAttribute(TRANSITION_TYPE_ATTRIBUTE, type);
|
|
@@ -27719,6 +27772,7 @@ const beginTransition = ({
|
|
|
27719
27772
|
documentElement.removeAttribute(TRANSITION_TYPE_ATTRIBUTE);
|
|
27720
27773
|
documentElement.removeAttribute(TRANSITION_TARGET_ATTRIBUTE);
|
|
27721
27774
|
releaseTransitionWindow(transition);
|
|
27775
|
+
releaseTransitionDestination(transition);
|
|
27722
27776
|
if (restoreDuration) {
|
|
27723
27777
|
restoreDuration();
|
|
27724
27778
|
}
|
|
@@ -28380,8 +28434,12 @@ const RouteTravel = ({
|
|
|
28380
28434
|
travelRef.current = travel;
|
|
28381
28435
|
// Taken before the picture is: the browser reads the name off the DOM as it
|
|
28382
28436
|
// stands when the transition starts, and this box is only a picture of its
|
|
28383
|
-
// own for as long as it is the one travelling.
|
|
28437
|
+
// own for as long as it is the one travelling. Where it travels to is said
|
|
28438
|
+
// at the same moment and for the same reason: whoever names something for
|
|
28439
|
+
// a movement between two pages decides on it now (see
|
|
28440
|
+
// transition_destination.js).
|
|
28384
28441
|
nameForTravel(elementRef.current);
|
|
28442
|
+
holdTransitionDestination(travel, page.route.buildUrl(page.params));
|
|
28385
28443
|
document.documentElement.setAttribute(TRAVEL_ATTRIBUTE, direction);
|
|
28386
28444
|
document.documentElement.setAttribute(TRAVEL_AXIS_ATTRIBUTE, axis);
|
|
28387
28445
|
if (scrub) {
|
|
@@ -28737,6 +28795,7 @@ const RouteTravel = ({
|
|
|
28737
28795
|
document.documentElement.removeAttribute(DRAGGED_ATTRIBUTE);
|
|
28738
28796
|
document.documentElement.removeAttribute(TURNED_ATTRIBUTE);
|
|
28739
28797
|
releaseTransitionWindow(travel);
|
|
28798
|
+
releaseTransitionDestination(travel);
|
|
28740
28799
|
}
|
|
28741
28800
|
};
|
|
28742
28801
|
|
|
@@ -38724,8 +38783,7 @@ const BinderItemContext = createContext(null);
|
|
|
38724
38783
|
|
|
38725
38784
|
/**
|
|
38726
38785
|
* What a <Link> learns from the <Nav> around it: where to draw the bar that
|
|
38727
|
-
* says "you are here",
|
|
38728
|
-
* bar from one page to the next, and — for a row of tabs that are slides — which
|
|
38786
|
+
* says "you are here", and — for a row of tabs that are slides — which
|
|
38729
38787
|
* <SlideContainer> they are about and which of its slides is on screen (see
|
|
38730
38788
|
* nav.jsx).
|
|
38731
38789
|
*/
|
|
@@ -39421,14 +39479,7 @@ const LinkPlain = props => {
|
|
|
39421
39479
|
// around this link.
|
|
39422
39480
|
const currentIndicatorAsked = currentIndicator ?? nav?.currentIndicator;
|
|
39423
39481
|
const currentIndicatorPosition = currentIndicatorAsked === true ? "bottom" : currentIndicatorAsked;
|
|
39424
|
-
const currentIndicatorEl = currentIndicatorPosition === "left" || currentIndicatorPosition === "right" || currentIndicatorPosition === "top" || currentIndicatorPosition === "bottom" ? jsx(LinkCurrentIndicator
|
|
39425
|
-
// Only the bar one can actually see carries the row's name, because a
|
|
39426
|
-
// name belongs to one element at a time and every tab holds a bar. The
|
|
39427
|
-
// browser then has the same thing in two places from one page to the
|
|
39428
|
-
// next, and moves it — which is the whole of "the bar slides".
|
|
39429
|
-
, {
|
|
39430
|
-
viewTransitionName: innerCurrent ? nav?.indicatorName : null
|
|
39431
|
-
}) : null;
|
|
39482
|
+
const currentIndicatorEl = currentIndicatorPosition === "left" || currentIndicatorPosition === "right" || currentIndicatorPosition === "top" || currentIndicatorPosition === "bottom" ? jsx(LinkCurrentIndicator, {}) : null;
|
|
39432
39483
|
const {
|
|
39433
39484
|
onClick,
|
|
39434
39485
|
preventDefault
|
|
@@ -39547,14 +39598,12 @@ const LinkPlain = props => {
|
|
|
39547
39598
|
children: [startIconEl, innerChildren, endIconEl]
|
|
39548
39599
|
});
|
|
39549
39600
|
};
|
|
39550
|
-
|
|
39551
|
-
|
|
39552
|
-
|
|
39601
|
+
|
|
39602
|
+
// Named by the <Nav> around the link when the link is current, from its CSS:
|
|
39603
|
+
// that is what makes the bar glide from one tab to the next (see nav.jsx).
|
|
39604
|
+
const LinkCurrentIndicator = () => {
|
|
39553
39605
|
return jsx("span", {
|
|
39554
|
-
className: "navi_current_indicator"
|
|
39555
|
-
style: viewTransitionName ? {
|
|
39556
|
-
viewTransitionName
|
|
39557
|
-
} : undefined
|
|
39606
|
+
className: "navi_current_indicator"
|
|
39558
39607
|
});
|
|
39559
39608
|
};
|
|
39560
39609
|
markAsOutsideTextFlow(LinkCurrentIndicator);
|
|
@@ -39564,6 +39613,9 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
39564
39613
|
* https://dribbble.com/search/tabs
|
|
39565
39614
|
*/
|
|
39566
39615
|
let navCount = 0;
|
|
39616
|
+
// Worn by a nav of routes while a route movement between two of its tabs is
|
|
39617
|
+
// pictured (see markIndicatorTakesPart, and the CSS below for what it decides).
|
|
39618
|
+
const BETWEEN_TABS_ATTRIBUTE = "data-nav-between-tabs";
|
|
39567
39619
|
const css$V = /* css */`
|
|
39568
39620
|
@layer navi {
|
|
39569
39621
|
.navi_nav {
|
|
@@ -39643,6 +39695,30 @@ const css$V = /* css */`
|
|
|
39643
39695
|
}
|
|
39644
39696
|
}
|
|
39645
39697
|
|
|
39698
|
+
/* The bar under the current tab of a nav made of routes is NAMED: a change
|
|
39699
|
+
played as a view transition then finds it on both pictures and moves it
|
|
39700
|
+
from the tab it was under to the tab it is under, which is all "the bar
|
|
39701
|
+
slides" is. The name is the row's (--nav-indicator-name, absent when the
|
|
39702
|
+
row asked for no slide) and only the bar one can see wears it: every tab
|
|
39703
|
+
holds a bar, and a name belongs to one element at a time. */
|
|
39704
|
+
.navi_nav .navi_link[data-href-current] .navi_current_indicator {
|
|
39705
|
+
view-transition-name: var(--nav-indicator-name);
|
|
39706
|
+
}
|
|
39707
|
+
/* Named for a movement it takes part in, and for that alone. While the PAGES
|
|
39708
|
+
are the ones moving — a route transition, a route travel — a name lifts the
|
|
39709
|
+
bar out of its page's picture into a picture of its own, and a picture of
|
|
39710
|
+
its own is precisely what does not travel: it stands where it was captured,
|
|
39711
|
+
fading, while the row slides away under it. Right when the row is on both
|
|
39712
|
+
sides and the bar has a tab to glide to; wrong anywhere else, where the bar
|
|
39713
|
+
must leave or arrive with its row. So the name is dropped unless the
|
|
39714
|
+
movement goes from a tab of this row to another one of its tabs (see
|
|
39715
|
+
markIndicatorTakesPart). */
|
|
39716
|
+
:root:is([data-navi-route-transition], [data-navi-route-travel])
|
|
39717
|
+
.navi_nav:not([${BETWEEN_TABS_ATTRIBUTE}])
|
|
39718
|
+
.navi_current_indicator {
|
|
39719
|
+
view-transition-name: none;
|
|
39720
|
+
}
|
|
39721
|
+
|
|
39646
39722
|
.navi_nav {
|
|
39647
39723
|
display: flex;
|
|
39648
39724
|
width: fit-content;
|
|
@@ -39824,9 +39900,12 @@ const positionOfCurrentIndicator = (currentIndicator, vertical) => {
|
|
|
39824
39900
|
* does so by being NAMED, which is all the browser needs: any change played as
|
|
39825
39901
|
* a view transition animates it on the same clock as everything else in that
|
|
39826
39902
|
* transition. Inside a `RouteTravel` that means it follows the pages, and the
|
|
39827
|
-
* thumb dragging them, without either of them being told about the other.
|
|
39828
|
-
* a
|
|
39829
|
-
*
|
|
39903
|
+
* thumb dragging them, without either of them being told about the other. It
|
|
39904
|
+
* is named for a movement between two tabs of the row and for nothing else:
|
|
39905
|
+
* when the pages move and the row is on one side only, the bar leaves or
|
|
39906
|
+
* arrives with its row. For a nav made of slides (`slideContainer`) the bar
|
|
39907
|
+
* is one element for the whole row, and it reads the travel the container
|
|
39908
|
+
* publishes.
|
|
39830
39909
|
* @param {string} [props.slideContainer] - the id of a `<SlideContainer>` these
|
|
39831
39910
|
* tabs are about: each one says which slide it is (`<Link slide="…">`), the
|
|
39832
39911
|
* container says which one is on screen, and pressing a tab travels there.
|
|
@@ -39959,16 +40038,47 @@ const Nav = ({
|
|
|
39959
40038
|
useLayoutEffect(() => {
|
|
39960
40039
|
paintIndicatorGeometry();
|
|
39961
40040
|
});
|
|
40041
|
+
|
|
40042
|
+
// Whether the bar keeps its name for the route movement about to be pictured
|
|
40043
|
+
// (see the CSS above). Written on the DOM as the movement is announced rather
|
|
40044
|
+
// than rendered: rendering is held from a navigation's first word until the
|
|
40045
|
+
// movement's first picture is taken (see rendering_hold.js), so a render
|
|
40046
|
+
// would land on the second picture with the first already taken.
|
|
40047
|
+
useLayoutEffect(() => {
|
|
40048
|
+
const navElement = navRef.current;
|
|
40049
|
+
const markIndicatorTakesPart = destinationUrl => {
|
|
40050
|
+
if (destinationUrl === null) {
|
|
40051
|
+
navElement.removeAttribute(BETWEEN_TABS_ATTRIBUTE);
|
|
40052
|
+
return;
|
|
40053
|
+
}
|
|
40054
|
+
// From a tab of this row: the row still shows the page being left, and
|
|
40055
|
+
// the tab it is on. To a tab of this row: one of its links aims at the
|
|
40056
|
+
// page the movement goes to. A row mounted while the movement plays hears
|
|
40057
|
+
// nothing here and stays unnamed, rightly: its bar is on the second
|
|
40058
|
+
// picture alone, with nothing on the first to glide from.
|
|
40059
|
+
const fromTab = navElement.querySelector("[data-href-current]");
|
|
40060
|
+
let toTab = null;
|
|
40061
|
+
for (const linkElement of navElement.querySelectorAll("a[href]")) {
|
|
40062
|
+
if (linkElement.href === destinationUrl) {
|
|
40063
|
+
toTab = linkElement;
|
|
40064
|
+
break;
|
|
40065
|
+
}
|
|
40066
|
+
}
|
|
40067
|
+
if (fromTab && toTab) {
|
|
40068
|
+
navElement.setAttribute(BETWEEN_TABS_ATTRIBUTE, "");
|
|
40069
|
+
} else {
|
|
40070
|
+
navElement.removeAttribute(BETWEEN_TABS_ATTRIBUTE);
|
|
40071
|
+
}
|
|
40072
|
+
};
|
|
40073
|
+
return observeTransitionDestination(markIndicatorTakesPart);
|
|
40074
|
+
}, []);
|
|
39962
40075
|
const navContextValue = useMemo(() => ({
|
|
39963
40076
|
// The bar belongs to the row itself when the tabs are slides, so the
|
|
39964
40077
|
// links draw none of their own.
|
|
39965
40078
|
currentIndicator: slideContainer ? undefined : currentIndicator,
|
|
39966
|
-
// Read by the link that is current, and by it alone: a name belongs to
|
|
39967
|
-
// one element at a time, and the bar exists in every tab.
|
|
39968
|
-
indicatorName: currentIndicatorSlides ? indicatorNameRef.current : null,
|
|
39969
40079
|
slideContainer,
|
|
39970
40080
|
currentSlideArea
|
|
39971
|
-
}), [currentIndicator,
|
|
40081
|
+
}), [currentIndicator, slideContainer, currentSlideArea]);
|
|
39972
40082
|
children = toChildArray(children);
|
|
39973
40083
|
return jsxs(Box, {
|
|
39974
40084
|
as: "nav",
|
|
@@ -39998,6 +40108,13 @@ const Nav = ({
|
|
|
39998
40108
|
expandY: expandY,
|
|
39999
40109
|
spacing: spacing,
|
|
40000
40110
|
...props,
|
|
40111
|
+
// The name the bar of the current tab wears, handed to the CSS above
|
|
40112
|
+
// rather than to the links: which bar wears it, and when, is decided
|
|
40113
|
+
// there.
|
|
40114
|
+
style: currentIndicatorSlides && !slideContainer ? {
|
|
40115
|
+
...props.style,
|
|
40116
|
+
"--nav-indicator-name": indicatorNameRef.current
|
|
40117
|
+
} : props.style,
|
|
40001
40118
|
styleCSSVars: NavStyleCSSVars,
|
|
40002
40119
|
children: [indicatorPosition && jsx("span", {
|
|
40003
40120
|
className: "navi_nav_indicator"
|