@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.
@@ -24292,10 +24292,9 @@ const useKeyboardShortcuts = (
24292
24292
  );
24293
24293
  shortcut.action = useAction(shortcut.action);
24294
24294
  }
24295
- const onKeyDown = createOnKeyDownForShortcutArray(
24296
- shortcuts,
24297
- shortcutActionIsBusyRef,
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 = (shortcuts, busyRef) => {
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
- const createOnKeyDownForShortcuts = (shortcuts) => {
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 = paramsEffect || (() => true);
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, paramsEffect, values);
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, paramsEffect, values) => {
38534
- const params = readStateAsIf(values, paramsEffect);
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(paramsEffect))) {
38582
+ if (compareTwoJsValues(params, untracked(readParams))) {
38539
38583
  return;
38540
38584
  }
38541
38585
  prerunAhead(action.bindParams(params));