@jsenv/navi 0.29.456 → 0.29.458
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 +60 -16
- package/dist/dev/jsenv_navi.js.map +4 -4
- package/dist/jsenv_navi.js +60 -16
- package/dist/jsenv_navi.js.map +4 -4
- package/docs/dynamic_import.md +18 -0
- package/docs/interactions.md +27 -0
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -24292,10 +24292,9 @@ const useKeyboardShortcuts = (
|
|
|
24292
24292
|
);
|
|
24293
24293
|
shortcut.action = useAction(shortcut.action);
|
|
24294
24294
|
}
|
|
24295
|
-
const onKeyDown = createOnKeyDownForShortcutArray(
|
|
24296
|
-
|
|
24297
|
-
|
|
24298
|
-
);
|
|
24295
|
+
const onKeyDown = createOnKeyDownForShortcutArray(shortcuts, {
|
|
24296
|
+
busyRef: shortcutActionIsBusyRef,
|
|
24297
|
+
});
|
|
24299
24298
|
useEffect(() => {
|
|
24300
24299
|
const element = elementRef.current;
|
|
24301
24300
|
if (!element) {
|
|
@@ -24313,7 +24312,10 @@ const useKeyboardShortcuts = (
|
|
|
24313
24312
|
}, [shortcutDeps]);
|
|
24314
24313
|
};
|
|
24315
24314
|
|
|
24316
|
-
const createOnKeyDownForShortcutArray = (
|
|
24315
|
+
const createOnKeyDownForShortcutArray = (
|
|
24316
|
+
shortcuts,
|
|
24317
|
+
{ busyRef, ownsTarget } = {},
|
|
24318
|
+
) => {
|
|
24317
24319
|
const shortcutsCopy = [];
|
|
24318
24320
|
for (const shortcutCandidate of shortcuts) {
|
|
24319
24321
|
shortcutsCopy.push({
|
|
@@ -24359,10 +24361,20 @@ const createOnKeyDownForShortcutArray = (shortcuts, busyRef) => {
|
|
|
24359
24361
|
}
|
|
24360
24362
|
|
|
24361
24363
|
return (keyboardEvent) => {
|
|
24362
|
-
return applyKeyboardShortcuts(shortcutsCopy, keyboardEvent
|
|
24364
|
+
return applyKeyboardShortcuts(shortcutsCopy, keyboardEvent, {
|
|
24365
|
+
ownsTarget,
|
|
24366
|
+
});
|
|
24363
24367
|
};
|
|
24364
24368
|
};
|
|
24365
|
-
|
|
24369
|
+
/**
|
|
24370
|
+
* @param {object} shortcuts
|
|
24371
|
+
* @param {object} [options]
|
|
24372
|
+
* @param {(target: Element) => boolean} [options.ownsTarget] Whether a
|
|
24373
|
+
* descendant the key was pressed in is one the shortcuts speak for, so its
|
|
24374
|
+
* native behavior (the caret, typing) is theirs to take. Without it only the
|
|
24375
|
+
* listening element itself is; a descendant keeps every key it has a use for.
|
|
24376
|
+
*/
|
|
24377
|
+
const createOnKeyDownForShortcuts = (shortcuts, { ownsTarget } = {}) => {
|
|
24366
24378
|
const shortcutsArray = [];
|
|
24367
24379
|
for (const key of Object.keys(shortcuts)) {
|
|
24368
24380
|
const value = shortcuts[key];
|
|
@@ -24374,16 +24386,18 @@ const createOnKeyDownForShortcuts = (shortcuts) => {
|
|
|
24374
24386
|
}
|
|
24375
24387
|
shortcutsArray.push(shortcut);
|
|
24376
24388
|
}
|
|
24377
|
-
return createOnKeyDownForShortcutArray(shortcutsArray);
|
|
24389
|
+
return createOnKeyDownForShortcutArray(shortcutsArray, { ownsTarget });
|
|
24378
24390
|
};
|
|
24379
24391
|
|
|
24380
|
-
const applyKeyboardShortcuts = (shortcuts, keyboardEvent) => {
|
|
24392
|
+
const applyKeyboardShortcuts = (shortcuts, keyboardEvent, { ownsTarget }) => {
|
|
24381
24393
|
const currentTarget = keyboardEvent.currentTarget;
|
|
24382
24394
|
const target = keyboardEvent.target;
|
|
24383
24395
|
let canIntercept;
|
|
24384
24396
|
if (target === currentTarget) {
|
|
24385
24397
|
// the event occurs on the element itself so we are sure we won't interfere with native behaviors of child elements
|
|
24386
24398
|
canIntercept = true;
|
|
24399
|
+
} else if (ownsTarget && ownsTarget(target)) {
|
|
24400
|
+
canIntercept = true;
|
|
24387
24401
|
} else {
|
|
24388
24402
|
// we need to check if the default action is something that we can allow to be intercepted
|
|
24389
24403
|
const defaultAction = getKeyboardEventDefaultAction(keyboardEvent);
|
|
@@ -24601,6 +24615,17 @@ const isSameKey = (browserEventKey, key) => {
|
|
|
24601
24615
|
* knows what "ctrl+backspace" means, which keys a control may take without
|
|
24602
24616
|
* swallowing what the browser owed them, and which it may not.
|
|
24603
24617
|
*
|
|
24618
|
+
* The control's own element is the exception to that last part. `interactions`
|
|
24619
|
+
* are set up on a field's outer box while the key goes down in its `<input>`,
|
|
24620
|
+
* and that field is the control the declaration speaks for: an ArrowUp declared
|
|
24621
|
+
* on a text field is the field saying what ArrowUp does there, not a container
|
|
24622
|
+
* taking the caret from a field inside it. A field inside a box that declares
|
|
24623
|
+
* keys for something else (a row, a list) keeps every key it has a use for.
|
|
24624
|
+
*
|
|
24625
|
+
* A declared key that matches takes the key: its default does not happen as
|
|
24626
|
+
* well, whether the gate lets the interaction through or refuses it and says
|
|
24627
|
+
* why — the same as a number field's arrows.
|
|
24628
|
+
*
|
|
24604
24629
|
* The interaction is dispatched under its full name, colon included, so
|
|
24605
24630
|
* `findEvent(event, "keyboard:ctrl+backspace")` gets back to it — the shortcut
|
|
24606
24631
|
* that asked is what the action wants to know, not that a key went down.
|
|
@@ -24617,9 +24642,12 @@ defineInteractionDetector({
|
|
|
24617
24642
|
for (const type of types) {
|
|
24618
24643
|
shortcuts[type.slice(KEYBOARD_PREFIX.length)] = (keyboardEvent) => {
|
|
24619
24644
|
trigger(type, keyboardEvent);
|
|
24645
|
+
keyboardEvent.preventDefault();
|
|
24620
24646
|
};
|
|
24621
24647
|
}
|
|
24622
|
-
const onKeyDown = createOnKeyDownForShortcuts(shortcuts
|
|
24648
|
+
const onKeyDown = createOnKeyDownForShortcuts(shortcuts, {
|
|
24649
|
+
ownsTarget: (target) => target === findNearestControlHost(element),
|
|
24650
|
+
});
|
|
24623
24651
|
element.addEventListener("keydown", onKeyDown);
|
|
24624
24652
|
return () => {
|
|
24625
24653
|
element.removeEventListener("keydown", onKeyDown);
|
|
@@ -38460,6 +38488,14 @@ const activeRouteReadsSignal = computed(() => {
|
|
|
38460
38488
|
* params read: that address is the current one with the state set to the
|
|
38461
38489
|
* popup's value (see `prefetch` on Button).
|
|
38462
38490
|
* @param {object} [options]
|
|
38491
|
+
* @param {() => any} [options.when] - a condition on app state the action
|
|
38492
|
+
* asks under, read off signals like the params: falsy, it runs nothing.
|
|
38493
|
+
* Unlike a params function it leaves the action asking nothing of the
|
|
38494
|
+
* address, so a link to the route still prefetches an action without
|
|
38495
|
+
* params when the condition holds at that moment — a page's code only some
|
|
38496
|
+
* readers may download (`() => meIsAdminSignal.value`). A condition reading
|
|
38497
|
+
* the address belongs in the params: a link reads `when` as it is, not as
|
|
38498
|
+
* the address it leads to will make it.
|
|
38463
38499
|
* @param {boolean} [options.prefetch=true] - `false` keeps the action from
|
|
38464
38500
|
* being prerun ahead of what asks for it, when the read is not worth a
|
|
38465
38501
|
* hover or a press that may not end in an opening.
|
|
@@ -38468,7 +38504,7 @@ const routeAction = (
|
|
|
38468
38504
|
routeOrRoutes,
|
|
38469
38505
|
action,
|
|
38470
38506
|
paramsEffect,
|
|
38471
|
-
{ prefetch = true, ...options } = {},
|
|
38507
|
+
{ when, prefetch = true, ...options } = {},
|
|
38472
38508
|
) => {
|
|
38473
38509
|
if (typeof action === "function") {
|
|
38474
38510
|
action = createAction(action);
|
|
@@ -38478,7 +38514,12 @@ const routeAction = (
|
|
|
38478
38514
|
routes.length === 1
|
|
38479
38515
|
? routes[0].matchingSignal
|
|
38480
38516
|
: anyMatchingRouteSignal(routes);
|
|
38481
|
-
const readParams =
|
|
38517
|
+
const readParams = () => {
|
|
38518
|
+
if (when && !when()) {
|
|
38519
|
+
return null;
|
|
38520
|
+
}
|
|
38521
|
+
return paramsEffect ? paramsEffect() : true;
|
|
38522
|
+
};
|
|
38482
38523
|
const readParamsAsked = () => {
|
|
38483
38524
|
const matching = routeMatchingSignal.value;
|
|
38484
38525
|
const params = readParams();
|
|
@@ -38514,10 +38555,13 @@ const routeAction = (
|
|
|
38514
38555
|
for (const route of routes) {
|
|
38515
38556
|
if (paramsEffect) {
|
|
38516
38557
|
registerRouteStatePreload(route, (values) => {
|
|
38517
|
-
prefetchAsIf(action,
|
|
38558
|
+
prefetchAsIf(action, readParams, values);
|
|
38518
38559
|
});
|
|
38519
38560
|
} else {
|
|
38520
38561
|
registerRoutePreload(route, () => {
|
|
38562
|
+
if (!untracked(readParams)) {
|
|
38563
|
+
return;
|
|
38564
|
+
}
|
|
38521
38565
|
prerunAhead(action.bindParams(true));
|
|
38522
38566
|
});
|
|
38523
38567
|
}
|
|
@@ -38530,12 +38574,12 @@ const routeAction = (
|
|
|
38530
38574
|
// (see readStateAsIf), prerun only when that changes them: params the state
|
|
38531
38575
|
// leaves alone are the ones the action already runs on — or is meant not to,
|
|
38532
38576
|
// and a prerun would retry a FAILED one behind the screen's back.
|
|
38533
|
-
const prefetchAsIf = (action,
|
|
38534
|
-
const params = readStateAsIf(values,
|
|
38577
|
+
const prefetchAsIf = (action, readParams, values) => {
|
|
38578
|
+
const params = readStateAsIf(values, readParams);
|
|
38535
38579
|
if (!params) {
|
|
38536
38580
|
return;
|
|
38537
38581
|
}
|
|
38538
|
-
if (compareTwoJsValues(params, untracked(
|
|
38582
|
+
if (compareTwoJsValues(params, untracked(readParams))) {
|
|
38539
38583
|
return;
|
|
38540
38584
|
}
|
|
38541
38585
|
prerunAhead(action.bindParams(params));
|