@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/jsenv_navi.js
CHANGED
|
@@ -1333,7 +1333,7 @@ const CONSTRAINT_MESSAGES = {
|
|
|
1333
1333
|
en: "This password must contain at most [max] characters (it currently contains [count] characters).",
|
|
1334
1334
|
},
|
|
1335
1335
|
"constraint.max_length.email": {
|
|
1336
|
-
fr: "Cette adresse e-mail doit contenir au maximum [max] caractères (
|
|
1336
|
+
fr: "Cette adresse e-mail doit contenir au maximum [max] caractères (elle contient actuellement [count] caractères).",
|
|
1337
1337
|
en: "This email address must contain at most [max] characters (it currently contains [count] characters).",
|
|
1338
1338
|
},
|
|
1339
1339
|
"constraint.max_length.default": {
|
|
@@ -11489,6 +11489,31 @@ const resolveEffectiveDocumentState = (
|
|
|
11489
11489
|
return { ...state, ...sharedState };
|
|
11490
11490
|
};
|
|
11491
11491
|
|
|
11492
|
+
/**
|
|
11493
|
+
* What a press on a link handed to the navigation it starts (see the
|
|
11494
|
+
* integrations' `carryByLinkNavigation`): each write is an `editState` applied
|
|
11495
|
+
* to the entry that navigation writes, and an `otherwise` that makes the write
|
|
11496
|
+
* where it would have been made, for a press that starts no navigation here.
|
|
11497
|
+
*/
|
|
11498
|
+
const applyPressWrites = (state, pressWrites) => {
|
|
11499
|
+
if (!pressWrites) {
|
|
11500
|
+
return state;
|
|
11501
|
+
}
|
|
11502
|
+
let stateWritten = state;
|
|
11503
|
+
for (const { editState } of pressWrites) {
|
|
11504
|
+
stateWritten = editState(stateWritten);
|
|
11505
|
+
}
|
|
11506
|
+
return stateWritten;
|
|
11507
|
+
};
|
|
11508
|
+
const writePressWritesHere = (pressWrites) => {
|
|
11509
|
+
if (!pressWrites) {
|
|
11510
|
+
return;
|
|
11511
|
+
}
|
|
11512
|
+
for (const { otherwise } of pressWrites) {
|
|
11513
|
+
otherwise();
|
|
11514
|
+
}
|
|
11515
|
+
};
|
|
11516
|
+
|
|
11492
11517
|
// Preact's own useId() (see preact/hooks) returns "P<mask0>-<mask1>", where the
|
|
11493
11518
|
// mask is derived from render order within the nearest root/async boundary:
|
|
11494
11519
|
// stable across re-renders of the same mount, but not across two mounts on the
|
|
@@ -13133,6 +13158,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13133
13158
|
// Asked to go where we already are: an address that redirects is never
|
|
13134
13159
|
// the one being displayed, so there is nothing to go to and nothing to
|
|
13135
13160
|
// stack on the history.
|
|
13161
|
+
writePressWritesHere(options.pressWrites);
|
|
13136
13162
|
return undefined;
|
|
13137
13163
|
}
|
|
13138
13164
|
return handleRoutingTask(redirectionUrl, {
|
|
@@ -13144,10 +13170,13 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13144
13170
|
// Decided before anything is announced: an elided push IS the traversal it
|
|
13145
13171
|
// becomes, and the traversal will make its own announcements when the
|
|
13146
13172
|
// browser answers — a before/after cycle here would be about a navigation
|
|
13147
|
-
// that never happens.
|
|
13173
|
+
// that never happens. A push with something of its own for its entry — a
|
|
13174
|
+
// state, what the press handed over (see carryByLinkNavigation) — is a
|
|
13175
|
+
// new entry, never one standing there already.
|
|
13148
13176
|
if (
|
|
13149
13177
|
options.navigationType === "push" &&
|
|
13150
13178
|
options.state === undefined &&
|
|
13179
|
+
!options.pressWrites &&
|
|
13151
13180
|
url !== readAddress()
|
|
13152
13181
|
) {
|
|
13153
13182
|
const delta = adjacentEntryDelta(url);
|
|
@@ -13197,6 +13226,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13197
13226
|
redirected,
|
|
13198
13227
|
landOn,
|
|
13199
13228
|
debounce,
|
|
13229
|
+
pressWrites,
|
|
13200
13230
|
} = options;
|
|
13201
13231
|
let { state } = options;
|
|
13202
13232
|
|
|
@@ -13207,15 +13237,18 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13207
13237
|
|
|
13208
13238
|
if (navigationType === "push" || navigationType === "replace") {
|
|
13209
13239
|
markUrlAsVisited(url);
|
|
13210
|
-
const effectiveState =
|
|
13211
|
-
|
|
13212
|
-
|
|
13213
|
-
|
|
13214
|
-
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
|
|
13240
|
+
const effectiveState = applyPressWrites(
|
|
13241
|
+
resolveEffectiveDocumentState(state, {
|
|
13242
|
+
navigationType,
|
|
13243
|
+
isArrival: isArrival(url, { from: urlLeft }),
|
|
13244
|
+
currentState: getDocumentState(),
|
|
13245
|
+
sharedState: {
|
|
13246
|
+
jsenv_visited_urls: Array.from(visitedUrlSet),
|
|
13247
|
+
[NAV_DEPTH_STATE_KEY]: getNavDepth(),
|
|
13248
|
+
},
|
|
13249
|
+
}),
|
|
13250
|
+
pressWrites,
|
|
13251
|
+
);
|
|
13219
13252
|
if (navigationType === "replace" && debounce && state === undefined) {
|
|
13220
13253
|
// Nothing of its own for the entry: the address moves, the state is
|
|
13221
13254
|
// carried over. The one kind of write allowed to lag, and only when
|
|
@@ -13315,6 +13348,36 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13315
13348
|
return requestedResult;
|
|
13316
13349
|
};
|
|
13317
13350
|
|
|
13351
|
+
// A press on a link is one navigation, and what the press asks of the
|
|
13352
|
+
// history entry is part of it: a popup the link's own command closes is
|
|
13353
|
+
// closed on the entry the link leads to, while the one it leaves keeps what
|
|
13354
|
+
// the reader was looking at — a back finds the popup open. The link's
|
|
13355
|
+
// listeners run before the routing is asked (below), so a write they make
|
|
13356
|
+
// is handed over, keyed by the click, rather than written onto the entry
|
|
13357
|
+
// being left. Once the link has been answered there is nothing to hand
|
|
13358
|
+
// over to: the navigation, when there was one, has already written its
|
|
13359
|
+
// entry, and a write lands there by itself.
|
|
13360
|
+
const linkPressWritesMap = new WeakMap();
|
|
13361
|
+
const answeredLinkClickSet = new WeakSet();
|
|
13362
|
+
const carryByLinkNavigation = (event, pressWrite) => {
|
|
13363
|
+
const clickEvent = findEvent(event, "click");
|
|
13364
|
+
if (
|
|
13365
|
+
!clickEvent ||
|
|
13366
|
+
clickEvent.eventPhase === Event.NONE ||
|
|
13367
|
+
answeredLinkClickSet.has(clickEvent) ||
|
|
13368
|
+
!clickEvent.target.closest("a")
|
|
13369
|
+
) {
|
|
13370
|
+
return false;
|
|
13371
|
+
}
|
|
13372
|
+
const pressWrites = linkPressWritesMap.get(clickEvent);
|
|
13373
|
+
if (pressWrites) {
|
|
13374
|
+
pressWrites.push(pressWrite);
|
|
13375
|
+
} else {
|
|
13376
|
+
linkPressWritesMap.set(clickEvent, [pressWrite]);
|
|
13377
|
+
}
|
|
13378
|
+
return true;
|
|
13379
|
+
};
|
|
13380
|
+
|
|
13318
13381
|
// A click on a link is answered on the link itself, after the link's own
|
|
13319
13382
|
// listeners: a navi control decides there whether the press is allowed — it
|
|
13320
13383
|
// refuses with preventDefault from its click reaction — and runs its command
|
|
@@ -13322,34 +13385,42 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13322
13385
|
// is the order the Navigation API integration gets for free, where the
|
|
13323
13386
|
// navigation starts once the click has been dispatched.
|
|
13324
13387
|
const onLinkClick = (e) => {
|
|
13388
|
+
answeredLinkClickSet.add(e);
|
|
13389
|
+
const pressWrites = linkPressWritesMap.get(e);
|
|
13390
|
+
linkPressWritesMap.delete(e);
|
|
13391
|
+
if (!routeLinkClick(e, pressWrites)) {
|
|
13392
|
+
writePressWritesHere(pressWrites);
|
|
13393
|
+
}
|
|
13394
|
+
};
|
|
13395
|
+
const routeLinkClick = (e, pressWrites) => {
|
|
13325
13396
|
if (e.button !== 0) {
|
|
13326
13397
|
// Ignore non-left clicks
|
|
13327
|
-
return;
|
|
13398
|
+
return false;
|
|
13328
13399
|
}
|
|
13329
13400
|
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
|
13330
13401
|
// A modifier asks the browser for something other than this tab: a new
|
|
13331
13402
|
// tab (meta on macOS, ctrl elsewhere), a new window (shift), a download
|
|
13332
13403
|
// (alt).
|
|
13333
|
-
return;
|
|
13404
|
+
return false;
|
|
13334
13405
|
}
|
|
13335
13406
|
if (e.defaultPrevented) {
|
|
13336
13407
|
// Refused — by the link itself, or by whoever came before it.
|
|
13337
|
-
return;
|
|
13408
|
+
return false;
|
|
13338
13409
|
}
|
|
13339
13410
|
const linkElement = e.currentTarget;
|
|
13340
13411
|
if (linkElement.hasAttribute("data-readonly")) {
|
|
13341
|
-
return;
|
|
13412
|
+
return false;
|
|
13342
13413
|
}
|
|
13343
13414
|
if (linkOpensElsewhere(linkElement)) {
|
|
13344
13415
|
// Another tab or window, or a download (see link_elsewhere.js).
|
|
13345
|
-
return;
|
|
13416
|
+
return false;
|
|
13346
13417
|
}
|
|
13347
13418
|
const href = linkElement.href;
|
|
13348
13419
|
const { isEmpty, isCurrent, isSameOrigin, isAnchor } =
|
|
13349
13420
|
getHrefTargetInfo(href);
|
|
13350
13421
|
if (isEmpty || !isSameOrigin) {
|
|
13351
13422
|
// Let link to other origins be handled by the browser
|
|
13352
|
-
return;
|
|
13423
|
+
return false;
|
|
13353
13424
|
}
|
|
13354
13425
|
if (isAnchor) {
|
|
13355
13426
|
// Fragment navigation belongs to the browser: it owns the indicated
|
|
@@ -13361,13 +13432,13 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13361
13432
|
// change reaches whoever is waiting on the designated element.
|
|
13362
13433
|
rearmUrlTarget();
|
|
13363
13434
|
}
|
|
13364
|
-
return;
|
|
13435
|
+
return false;
|
|
13365
13436
|
}
|
|
13366
13437
|
if (linkAsksForDocument(linkElement)) {
|
|
13367
13438
|
// The link says its address is another document of this origin (see
|
|
13368
13439
|
// link_document.js). Routing to it would land on the fallback route
|
|
13369
13440
|
// instead of loading the page.
|
|
13370
|
-
return;
|
|
13441
|
+
return false;
|
|
13371
13442
|
}
|
|
13372
13443
|
// Nothing here declared a route, so there is nothing to route to: the
|
|
13373
13444
|
// page is a plain document and a link in it is a plain link. Taking it
|
|
@@ -13375,7 +13446,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13375
13446
|
// the address bar moves and the page does not (see applyRouting's own
|
|
13376
13447
|
// "not called yet" branch, which is where that used to end up).
|
|
13377
13448
|
if (!isRouting()) {
|
|
13378
|
-
return;
|
|
13449
|
+
return false;
|
|
13379
13450
|
}
|
|
13380
13451
|
e.preventDefault();
|
|
13381
13452
|
handleRoutingTask(href, {
|
|
@@ -13389,7 +13460,9 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13389
13460
|
// whoever knows what to do with it, and it is the anchor itself —
|
|
13390
13461
|
// resolved here, where it already is.
|
|
13391
13462
|
element: linkElement,
|
|
13463
|
+
pressWrites,
|
|
13392
13464
|
});
|
|
13465
|
+
return true;
|
|
13393
13466
|
};
|
|
13394
13467
|
// Wired from the capture phase on window, the first place a click is seen,
|
|
13395
13468
|
// so that a link is answered whatever handler stops the click on its way up
|
|
@@ -13569,6 +13642,7 @@ const setupBrowserIntegrationViaHistory = ({
|
|
|
13569
13642
|
navBack,
|
|
13570
13643
|
navForward,
|
|
13571
13644
|
getDocumentState,
|
|
13645
|
+
carryByLinkNavigation,
|
|
13572
13646
|
isVisited,
|
|
13573
13647
|
visitedUrlsSignal,
|
|
13574
13648
|
};
|
|
@@ -13968,8 +14042,32 @@ const useNavStateBasic = (
|
|
|
13968
14042
|
// that param for gone. Only with nothing of this document behind (the state
|
|
13969
14043
|
// was entered on a cold-loaded url, navBack has nowhere to go) does it
|
|
13970
14044
|
// rewrite in place.
|
|
13971
|
-
|
|
14045
|
+
//
|
|
14046
|
+
// event: what asked for it. A leave the press of a link asks for (its
|
|
14047
|
+
// --navi-close) is made by the navigation that link starts: the entry the
|
|
14048
|
+
// link leads to does not hold the key, and every entry behind is left as
|
|
14049
|
+
// the reader saw it — a back finds the state still entered.
|
|
14050
|
+
const leave = ({ isBack, event } = {}) => {
|
|
13972
14051
|
enteredRef.current = false;
|
|
14052
|
+
if (!Object.hasOwn(browserIntegration.getDocumentState() || {}, id)) {
|
|
14053
|
+
return;
|
|
14054
|
+
}
|
|
14055
|
+
if (
|
|
14056
|
+
event &&
|
|
14057
|
+
browserIntegration.carryByLinkNavigation(event, {
|
|
14058
|
+
editState: (state) => {
|
|
14059
|
+
const stateWithoutKey = { ...state };
|
|
14060
|
+
delete stateWithoutKey[id];
|
|
14061
|
+
return stateWithoutKey;
|
|
14062
|
+
},
|
|
14063
|
+
otherwise: () => leaveEntry({ isBack }),
|
|
14064
|
+
})
|
|
14065
|
+
) {
|
|
14066
|
+
return;
|
|
14067
|
+
}
|
|
14068
|
+
leaveEntry({ isBack });
|
|
14069
|
+
};
|
|
14070
|
+
const leaveEntry = ({ isBack }) => {
|
|
13973
14071
|
const currentStateCopy = browserIntegration.getDocumentState() || {};
|
|
13974
14072
|
if (!Object.hasOwn(currentStateCopy, id)) {
|
|
13975
14073
|
return;
|
|
@@ -14027,6 +14125,9 @@ const useNavStateBasic = (
|
|
|
14027
14125
|
* the value allows associating extra data when needed.
|
|
14028
14126
|
* - `leave()`: navigate AWAY FROM this state (removes `id` from document state,
|
|
14029
14127
|
* or goes back in history when `type` is "push").
|
|
14128
|
+
* `leave({ event })` with the event that asked for it: asked by the press
|
|
14129
|
+
* of a link that navigates, the key is left out of the entry the link
|
|
14130
|
+
* leads to, and the entry it leaves keeps it.
|
|
14030
14131
|
*/
|
|
14031
14132
|
const useNavState = useNavStateBasic;
|
|
14032
14133
|
|
|
@@ -17210,8 +17311,13 @@ const useOpenPropsEffectOnOpenController = (
|
|
|
17210
17311
|
} else {
|
|
17211
17312
|
// Under type "push" a cancel discards everything written while
|
|
17212
17313
|
// the popup was open — it goes back with the entry; a confirmed
|
|
17213
|
-
// close keeps those writes (see useNavState's own leave()).
|
|
17214
|
-
|
|
17314
|
+
// close keeps those writes (see useNavState's own leave()). A
|
|
17315
|
+
// close a link's press asked for is written by the navigation
|
|
17316
|
+
// the link starts.
|
|
17317
|
+
leaveNavState({
|
|
17318
|
+
isBack: Boolean(event?.detail?.isCancel),
|
|
17319
|
+
event,
|
|
17320
|
+
});
|
|
17215
17321
|
}
|
|
17216
17322
|
}
|
|
17217
17323
|
if (signal) {
|
|
@@ -53123,7 +53229,9 @@ const LinkPseudoElements = ["::-navi-loader", "::-navi-indicator"];
|
|
|
53123
53229
|
* fetching on a hover.
|
|
53124
53230
|
* @param {string} [props.command] - What the press asks of a control around
|
|
53125
53231
|
* the link — `"--navi-close"` on a link that leaves the sheet it is in.
|
|
53126
|
-
* Triggered on the press, before the navigation.
|
|
53232
|
+
* Triggered on the press, before the navigation. A popup it closes that
|
|
53233
|
+
* keeps its open state in the history entry (`navState`) is closed on the
|
|
53234
|
+
* entry the navigation leads to: Back finds it open.
|
|
53127
53235
|
* @param {Function} [props.action] - Work the press runs, before the
|
|
53128
53236
|
* navigation. Nothing waits for it — not the navigation, not `command`: what
|
|
53129
53237
|
* the next page must find has to be written synchronously (a draft in a
|
|
@@ -56562,9 +56670,9 @@ const useExpandableContext = partName => {
|
|
|
56562
56670
|
* closeKeyShortcut?: string,
|
|
56563
56671
|
* }>}
|
|
56564
56672
|
* @param ui - Shorthand for the common shape: renders `<Expandable.UI>{ui}</Expandable.UI>`
|
|
56565
|
-
* above the content (children). Any markup is allowed
|
|
56566
|
-
*
|
|
56567
|
-
* expandable). A function receives `{ open }` to render differently per
|
|
56673
|
+
* above the content (children). Any markup is allowed: a button, a link, a
|
|
56674
|
+
* field, any navi control or `selfInteractions` claimant inside it keeps its
|
|
56675
|
+
* own behavior and does not toggle the expandable (see `isPressOnControl`). A function receives `{ open }` to render differently per
|
|
56568
56676
|
* state. For other orders/orientations, pass `<Expandable.UI>` and
|
|
56569
56677
|
* `<Expandable.Content>` as children instead.
|
|
56570
56678
|
* @param open - Drives the state from outside: the expandable opens/closes to
|