@jsenv/navi 0.29.484 → 0.29.486
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev/jsenv_navi.js +135 -27
- package/dist/dev/jsenv_navi.js.map +8 -8
- package/dist/jsenv_navi.js +135 -27
- package/dist/jsenv_navi.js.map +8 -8
- package/docs/drag_interactions.md +4 -1
- package/docs/i18n.md +13 -0
- package/docs/popup_open.md +5 -0
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -1360,7 +1360,7 @@ const CONSTRAINT_MESSAGES = {
|
|
|
1360
1360
|
en: "This password must contain at most [max] characters (it currently contains [count] characters).",
|
|
1361
1361
|
},
|
|
1362
1362
|
"constraint.max_length.email": {
|
|
1363
|
-
fr: "Cette adresse e-mail doit contenir au maximum [max] caractères (
|
|
1363
|
+
fr: "Cette adresse e-mail doit contenir au maximum [max] caractères (elle contient actuellement [count] caractères).",
|
|
1364
1364
|
en: "This email address must contain at most [max] characters (it currently contains [count] characters).",
|
|
1365
1365
|
},
|
|
1366
1366
|
"constraint.max_length.default": {
|
|
@@ -12079,6 +12079,31 @@ const resolveEffectiveDocumentState = (
|
|
|
12079
12079
|
return { ...state, ...sharedState };
|
|
12080
12080
|
};
|
|
12081
12081
|
|
|
12082
|
+
/**
|
|
12083
|
+
* What a press on a link handed to the navigation it starts (see the
|
|
12084
|
+
* integrations' `carryByLinkNavigation`): each write is an `editState` applied
|
|
12085
|
+
* to the entry that navigation writes, and an `otherwise` that makes the write
|
|
12086
|
+
* where it would have been made, for a press that starts no navigation here.
|
|
12087
|
+
*/
|
|
12088
|
+
const applyPressWrites = (state, pressWrites) => {
|
|
12089
|
+
if (!pressWrites) {
|
|
12090
|
+
return state;
|
|
12091
|
+
}
|
|
12092
|
+
let stateWritten = state;
|
|
12093
|
+
for (const { editState } of pressWrites) {
|
|
12094
|
+
stateWritten = editState(stateWritten);
|
|
12095
|
+
}
|
|
12096
|
+
return stateWritten;
|
|
12097
|
+
};
|
|
12098
|
+
const writePressWritesHere = (pressWrites) => {
|
|
12099
|
+
if (!pressWrites) {
|
|
12100
|
+
return;
|
|
12101
|
+
}
|
|
12102
|
+
for (const { otherwise } of pressWrites) {
|
|
12103
|
+
otherwise();
|
|
12104
|
+
}
|
|
12105
|
+
};
|
|
12106
|
+
|
|
12082
12107
|
// Preact's own useId() (see preact/hooks) returns "P<mask0>-<mask1>", where the
|
|
12083
12108
|
// mask is derived from render order within the nearest root/async boundary:
|
|
12084
12109
|
// stable across re-renders of the same mount, but not across two mounts on the
|
|
@@ -13734,6 +13759,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13734
13759
|
// Asked to go where we already are: an address that redirects is never
|
|
13735
13760
|
// the one being displayed, so there is nothing to go to and nothing to
|
|
13736
13761
|
// stack on the history.
|
|
13762
|
+
writePressWritesHere(options.pressWrites);
|
|
13737
13763
|
return undefined;
|
|
13738
13764
|
}
|
|
13739
13765
|
return handleRoutingTask(redirectionUrl, {
|
|
@@ -13745,10 +13771,13 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13745
13771
|
// Decided before anything is announced: an elided push IS the traversal it
|
|
13746
13772
|
// becomes, and the traversal will make its own announcements when the
|
|
13747
13773
|
// browser answers — a before/after cycle here would be about a navigation
|
|
13748
|
-
// that never happens.
|
|
13774
|
+
// that never happens. A push with something of its own for its entry — a
|
|
13775
|
+
// state, what the press handed over (see carryByLinkNavigation) — is a
|
|
13776
|
+
// new entry, never one standing there already.
|
|
13749
13777
|
if (
|
|
13750
13778
|
options.navigationType === "push" &&
|
|
13751
13779
|
options.state === undefined &&
|
|
13780
|
+
!options.pressWrites &&
|
|
13752
13781
|
url !== readAddress()
|
|
13753
13782
|
) {
|
|
13754
13783
|
const delta = adjacentEntryDelta(url);
|
|
@@ -13798,6 +13827,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13798
13827
|
redirected,
|
|
13799
13828
|
landOn,
|
|
13800
13829
|
debounce,
|
|
13830
|
+
pressWrites,
|
|
13801
13831
|
} = options;
|
|
13802
13832
|
let { state } = options;
|
|
13803
13833
|
|
|
@@ -13808,15 +13838,18 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13808
13838
|
|
|
13809
13839
|
if (navigationType === "push" || navigationType === "replace") {
|
|
13810
13840
|
markUrlAsVisited(url);
|
|
13811
|
-
const effectiveState =
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
|
|
13816
|
-
|
|
13817
|
-
|
|
13818
|
-
|
|
13819
|
-
|
|
13841
|
+
const effectiveState = applyPressWrites(
|
|
13842
|
+
resolveEffectiveDocumentState(state, {
|
|
13843
|
+
navigationType,
|
|
13844
|
+
isArrival: isArrival(url, { from: urlLeft }),
|
|
13845
|
+
currentState: getDocumentState(),
|
|
13846
|
+
sharedState: {
|
|
13847
|
+
jsenv_visited_urls: Array.from(visitedUrlSet),
|
|
13848
|
+
[NAV_DEPTH_STATE_KEY]: getNavDepth(),
|
|
13849
|
+
},
|
|
13850
|
+
}),
|
|
13851
|
+
pressWrites,
|
|
13852
|
+
);
|
|
13820
13853
|
if (navigationType === "replace" && debounce && state === undefined) {
|
|
13821
13854
|
// Nothing of its own for the entry: the address moves, the state is
|
|
13822
13855
|
// carried over. The one kind of write allowed to lag, and only when
|
|
@@ -13916,6 +13949,36 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13916
13949
|
return requestedResult;
|
|
13917
13950
|
};
|
|
13918
13951
|
|
|
13952
|
+
// A press on a link is one navigation, and what the press asks of the
|
|
13953
|
+
// history entry is part of it: a popup the link's own command closes is
|
|
13954
|
+
// closed on the entry the link leads to, while the one it leaves keeps what
|
|
13955
|
+
// the reader was looking at — a back finds the popup open. The link's
|
|
13956
|
+
// listeners run before the routing is asked (below), so a write they make
|
|
13957
|
+
// is handed over, keyed by the click, rather than written onto the entry
|
|
13958
|
+
// being left. Once the link has been answered there is nothing to hand
|
|
13959
|
+
// over to: the navigation, when there was one, has already written its
|
|
13960
|
+
// entry, and a write lands there by itself.
|
|
13961
|
+
const linkPressWritesMap = new WeakMap();
|
|
13962
|
+
const answeredLinkClickSet = new WeakSet();
|
|
13963
|
+
const carryByLinkNavigation = (event, pressWrite) => {
|
|
13964
|
+
const clickEvent = findEvent(event, "click");
|
|
13965
|
+
if (
|
|
13966
|
+
!clickEvent ||
|
|
13967
|
+
clickEvent.eventPhase === Event.NONE ||
|
|
13968
|
+
answeredLinkClickSet.has(clickEvent) ||
|
|
13969
|
+
!clickEvent.target.closest("a")
|
|
13970
|
+
) {
|
|
13971
|
+
return false;
|
|
13972
|
+
}
|
|
13973
|
+
const pressWrites = linkPressWritesMap.get(clickEvent);
|
|
13974
|
+
if (pressWrites) {
|
|
13975
|
+
pressWrites.push(pressWrite);
|
|
13976
|
+
} else {
|
|
13977
|
+
linkPressWritesMap.set(clickEvent, [pressWrite]);
|
|
13978
|
+
}
|
|
13979
|
+
return true;
|
|
13980
|
+
};
|
|
13981
|
+
|
|
13919
13982
|
// A click on a link is answered on the link itself, after the link's own
|
|
13920
13983
|
// listeners: a navi control decides there whether the press is allowed — it
|
|
13921
13984
|
// refuses with preventDefault from its click reaction — and runs its command
|
|
@@ -13923,34 +13986,42 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13923
13986
|
// is the order the Navigation API integration gets for free, where the
|
|
13924
13987
|
// navigation starts once the click has been dispatched.
|
|
13925
13988
|
const onLinkClick = (e) => {
|
|
13989
|
+
answeredLinkClickSet.add(e);
|
|
13990
|
+
const pressWrites = linkPressWritesMap.get(e);
|
|
13991
|
+
linkPressWritesMap.delete(e);
|
|
13992
|
+
if (!routeLinkClick(e, pressWrites)) {
|
|
13993
|
+
writePressWritesHere(pressWrites);
|
|
13994
|
+
}
|
|
13995
|
+
};
|
|
13996
|
+
const routeLinkClick = (e, pressWrites) => {
|
|
13926
13997
|
if (e.button !== 0) {
|
|
13927
13998
|
// Ignore non-left clicks
|
|
13928
|
-
return;
|
|
13999
|
+
return false;
|
|
13929
14000
|
}
|
|
13930
14001
|
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
|
13931
14002
|
// A modifier asks the browser for something other than this tab: a new
|
|
13932
14003
|
// tab (meta on macOS, ctrl elsewhere), a new window (shift), a download
|
|
13933
14004
|
// (alt).
|
|
13934
|
-
return;
|
|
14005
|
+
return false;
|
|
13935
14006
|
}
|
|
13936
14007
|
if (e.defaultPrevented) {
|
|
13937
14008
|
// Refused — by the link itself, or by whoever came before it.
|
|
13938
|
-
return;
|
|
14009
|
+
return false;
|
|
13939
14010
|
}
|
|
13940
14011
|
const linkElement = e.currentTarget;
|
|
13941
14012
|
if (linkElement.hasAttribute("data-readonly")) {
|
|
13942
|
-
return;
|
|
14013
|
+
return false;
|
|
13943
14014
|
}
|
|
13944
14015
|
if (linkOpensElsewhere(linkElement)) {
|
|
13945
14016
|
// Another tab or window, or a download (see link_elsewhere.js).
|
|
13946
|
-
return;
|
|
14017
|
+
return false;
|
|
13947
14018
|
}
|
|
13948
14019
|
const href = linkElement.href;
|
|
13949
14020
|
const { isEmpty, isCurrent, isSameOrigin, isAnchor } =
|
|
13950
14021
|
getHrefTargetInfo(href);
|
|
13951
14022
|
if (isEmpty || !isSameOrigin) {
|
|
13952
14023
|
// Let link to other origins be handled by the browser
|
|
13953
|
-
return;
|
|
14024
|
+
return false;
|
|
13954
14025
|
}
|
|
13955
14026
|
if (isAnchor) {
|
|
13956
14027
|
// Fragment navigation belongs to the browser: it owns the indicated
|
|
@@ -13962,13 +14033,13 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13962
14033
|
// change reaches whoever is waiting on the designated element.
|
|
13963
14034
|
rearmUrlTarget();
|
|
13964
14035
|
}
|
|
13965
|
-
return;
|
|
14036
|
+
return false;
|
|
13966
14037
|
}
|
|
13967
14038
|
if (linkAsksForDocument(linkElement)) {
|
|
13968
14039
|
// The link says its address is another document of this origin (see
|
|
13969
14040
|
// link_document.js). Routing to it would land on the fallback route
|
|
13970
14041
|
// instead of loading the page.
|
|
13971
|
-
return;
|
|
14042
|
+
return false;
|
|
13972
14043
|
}
|
|
13973
14044
|
// Nothing here declared a route, so there is nothing to route to: the
|
|
13974
14045
|
// page is a plain document and a link in it is a plain link. Taking it
|
|
@@ -13976,7 +14047,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13976
14047
|
// the address bar moves and the page does not (see applyRouting's own
|
|
13977
14048
|
// "not called yet" branch, which is where that used to end up).
|
|
13978
14049
|
if (!isRouting()) {
|
|
13979
|
-
return;
|
|
14050
|
+
return false;
|
|
13980
14051
|
}
|
|
13981
14052
|
e.preventDefault();
|
|
13982
14053
|
handleRoutingTask(href, {
|
|
@@ -13990,7 +14061,9 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13990
14061
|
// whoever knows what to do with it, and it is the anchor itself —
|
|
13991
14062
|
// resolved here, where it already is.
|
|
13992
14063
|
element: linkElement,
|
|
14064
|
+
pressWrites,
|
|
13993
14065
|
});
|
|
14066
|
+
return true;
|
|
13994
14067
|
};
|
|
13995
14068
|
// Wired from the capture phase on window, the first place a click is seen,
|
|
13996
14069
|
// so that a link is answered whatever handler stops the click on its way up
|
|
@@ -14170,6 +14243,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
14170
14243
|
navBack,
|
|
14171
14244
|
navForward,
|
|
14172
14245
|
getDocumentState,
|
|
14246
|
+
carryByLinkNavigation,
|
|
14173
14247
|
isVisited,
|
|
14174
14248
|
visitedUrlsSignal,
|
|
14175
14249
|
};
|
|
@@ -14707,8 +14781,32 @@ const useNavStateBasic = (
|
|
|
14707
14781
|
// that param for gone. Only with nothing of this document behind (the state
|
|
14708
14782
|
// was entered on a cold-loaded url, navBack has nowhere to go) does it
|
|
14709
14783
|
// rewrite in place.
|
|
14710
|
-
|
|
14784
|
+
//
|
|
14785
|
+
// event: what asked for it. A leave the press of a link asks for (its
|
|
14786
|
+
// --navi-close) is made by the navigation that link starts: the entry the
|
|
14787
|
+
// link leads to does not hold the key, and every entry behind is left as
|
|
14788
|
+
// the reader saw it — a back finds the state still entered.
|
|
14789
|
+
const leave = ({ isBack, event } = {}) => {
|
|
14711
14790
|
enteredRef.current = false;
|
|
14791
|
+
if (!Object.hasOwn(browserIntegration.getDocumentState() || {}, id)) {
|
|
14792
|
+
return;
|
|
14793
|
+
}
|
|
14794
|
+
if (
|
|
14795
|
+
event &&
|
|
14796
|
+
browserIntegration.carryByLinkNavigation(event, {
|
|
14797
|
+
editState: (state) => {
|
|
14798
|
+
const stateWithoutKey = { ...state };
|
|
14799
|
+
delete stateWithoutKey[id];
|
|
14800
|
+
return stateWithoutKey;
|
|
14801
|
+
},
|
|
14802
|
+
otherwise: () => leaveEntry({ isBack }),
|
|
14803
|
+
})
|
|
14804
|
+
) {
|
|
14805
|
+
return;
|
|
14806
|
+
}
|
|
14807
|
+
leaveEntry({ isBack });
|
|
14808
|
+
};
|
|
14809
|
+
const leaveEntry = ({ isBack }) => {
|
|
14712
14810
|
const currentStateCopy = browserIntegration.getDocumentState() || {};
|
|
14713
14811
|
if (!Object.hasOwn(currentStateCopy, id)) {
|
|
14714
14812
|
return;
|
|
@@ -14766,6 +14864,9 @@ const useNavStateBasic = (
|
|
|
14766
14864
|
* the value allows associating extra data when needed.
|
|
14767
14865
|
* - `leave()`: navigate AWAY FROM this state (removes `id` from document state,
|
|
14768
14866
|
* or goes back in history when `type` is "push").
|
|
14867
|
+
* `leave({ event })` with the event that asked for it: asked by the press
|
|
14868
|
+
* of a link that navigates, the key is left out of the entry the link
|
|
14869
|
+
* leads to, and the entry it leaves keeps it.
|
|
14769
14870
|
*/
|
|
14770
14871
|
const useNavState = useNavStateWithWarnings
|
|
14771
14872
|
;
|
|
@@ -17996,8 +18097,13 @@ const useOpenPropsEffectOnOpenController = (
|
|
|
17996
18097
|
} else {
|
|
17997
18098
|
// Under type "push" a cancel discards everything written while
|
|
17998
18099
|
// the popup was open — it goes back with the entry; a confirmed
|
|
17999
|
-
// close keeps those writes (see useNavState's own leave()).
|
|
18000
|
-
|
|
18100
|
+
// close keeps those writes (see useNavState's own leave()). A
|
|
18101
|
+
// close a link's press asked for is written by the navigation
|
|
18102
|
+
// the link starts.
|
|
18103
|
+
leaveNavState({
|
|
18104
|
+
isBack: Boolean(event?.detail?.isCancel),
|
|
18105
|
+
event,
|
|
18106
|
+
});
|
|
18001
18107
|
}
|
|
18002
18108
|
}
|
|
18003
18109
|
if (signal) {
|
|
@@ -54584,7 +54690,9 @@ const LinkPseudoElements = ["::-navi-loader", "::-navi-indicator"];
|
|
|
54584
54690
|
* fetching on a hover.
|
|
54585
54691
|
* @param {string} [props.command] - What the press asks of a control around
|
|
54586
54692
|
* the link — `"--navi-close"` on a link that leaves the sheet it is in.
|
|
54587
|
-
* Triggered on the press, before the navigation.
|
|
54693
|
+
* Triggered on the press, before the navigation. A popup it closes that
|
|
54694
|
+
* keeps its open state in the history entry (`navState`) is closed on the
|
|
54695
|
+
* entry the navigation leads to: Back finds it open.
|
|
54588
54696
|
* @param {Function} [props.action] - Work the press runs, before the
|
|
54589
54697
|
* navigation. Nothing waits for it — not the navigation, not `command`: what
|
|
54590
54698
|
* the next page must find has to be written synchronously (a draft in a
|
|
@@ -58039,9 +58147,9 @@ const useExpandableContext = partName => {
|
|
|
58039
58147
|
* closeKeyShortcut?: string,
|
|
58040
58148
|
* }>}
|
|
58041
58149
|
* @param ui - Shorthand for the common shape: renders `<Expandable.UI>{ui}</Expandable.UI>`
|
|
58042
|
-
* above the content (children). Any markup is allowed
|
|
58043
|
-
*
|
|
58044
|
-
* expandable). A function receives `{ open }` to render differently per
|
|
58150
|
+
* above the content (children). Any markup is allowed: a button, a link, a
|
|
58151
|
+
* field, any navi control or `selfInteractions` claimant inside it keeps its
|
|
58152
|
+
* own behavior and does not toggle the expandable (see `isPressOnControl`). A function receives `{ open }` to render differently per
|
|
58045
58153
|
* state. For other orders/orientations, pass `<Expandable.UI>` and
|
|
58046
58154
|
* `<Expandable.Content>` as children instead.
|
|
58047
58155
|
* @param open - Drives the state from outside: the expandable opens/closes to
|