@jsenv/navi 0.29.507 → 0.29.508

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.
@@ -57481,6 +57481,10 @@ const css$$ = /* css */`@layer navi {
57481
57481
  --link-color: unset;
57482
57482
  --link-text-decoration: none;
57483
57483
  }
57484
+
57485
+ .navi_link[data-color-inherit] {
57486
+ --link-color-visited: var(--navi-link-color-visited, var(--link-color));
57487
+ }
57484
57488
  }
57485
57489
 
57486
57490
  .navi_link {
@@ -58313,6 +58317,7 @@ const LinkPlain = props => {
58313
58317
  // Visual
58314
58318
  ,
58315
58319
  "data-variant": variant,
58320
+ "data-color-inherit": props.color === "inherit" ? "" : undefined,
58316
58321
  "data-current-effect-bold": currentEffectBoldTechnique,
58317
58322
  "data-current-effect-shadow": currentEffectShadow ? "" : undefined,
58318
58323
  "data-current-indicator-position": currentIndicatorPosition,
@@ -70445,7 +70450,7 @@ const SlideContainer = ({
70445
70450
  // A transfer waiting for a travel that never happened — a controlled
70446
70451
  // `current` the caller chose not to move: dropped, the focus has no
70447
70452
  // business going anywhere. The one for a travel that DID happen stays,
70448
- // and lands when the slide it is for says it is settled (see settleFocus).
70453
+ // and lands once the slide it is for is final (see landFocusHandOver).
70449
70454
  if (focusHandOverRef.current && focusHandOverRef.current.area !== readArea(currentElement)) {
70450
70455
  focusHandOverRef.current = null;
70451
70456
  }
@@ -70599,6 +70604,11 @@ const SlideContainer = ({
70599
70604
  requestAnimationFrame(rollBack);
70600
70605
  }
70601
70606
  }
70607
+ // The slide a transfer waits for is current (any other one was dropped
70608
+ // above): it lands once the renders this commit sets off are over.
70609
+ if (focusHandOverRef.current) {
70610
+ landFocusHandOver();
70611
+ }
70602
70612
  // The keyboard is on a slide about to go out of reach and nobody has moved
70603
70613
  // it: inert would drop it on the floor (document.body), so it is handed to
70604
70614
  // the slide on screen instead. No event to read — this travel was asked for
@@ -70616,9 +70626,10 @@ const SlideContainer = ({
70616
70626
  // Out of reach LAST, once the keyboard has already moved on: a browser
70617
70627
  // takes the focus off an element the moment it becomes inert, and on its
70618
70628
  // own schedule — doing this first would let that undo the landing above and
70619
- // leave the focus on nothing.
70620
- for (const slideElement of slideElements) {
70621
- slideElement.toggleAttribute("inert", slideElement !== currentElement);
70629
+ // leave the focus on nothing. A transfer still on its way does it itself,
70630
+ // once landed.
70631
+ if (!focusHandOverRef.current) {
70632
+ markOutOfReach(currentElement);
70622
70633
  }
70623
70634
  // What is on screen now, for the travel after this one to depart from.
70624
70635
  // While a travel is playing the stage is the one that knows (it holds the
@@ -70969,14 +70980,7 @@ const SlideContainer = ({
70969
70980
  // dialog is OPEN, not when it was asked to open). `prepareFocusTransfer` has
70970
70981
  // to read the interaction — which element a mousedown landed on, whether the
70971
70982
  // modality is the keyboard — while the event is still being dispatched. The
70972
- // landing waits for the slide to say its DOM is settled (settleFocus below),
70973
- // which is later than one would think: a travel hands the slide a value
70974
- // (useSlideValue) and that value reaches it through context, so Preact
70975
- // re-renders the slide in a flush of its own — the container's own layout
70976
- // effect runs BEFORE its children have seen the value. A screen keyed by it,
70977
- // a form whose uncontrolled fields must start again from a new prefill,
70978
- // replaces its whole subtree there. Landing before that took the focus to a
70979
- // node about to be thrown away, and the focus went to document.body with it.
70983
+ // landing waits for the slide's DOM to be final (see landFocusHandOver).
70980
70984
  const handOverFocus = (slideElement, focusTransfer, event) => {
70981
70985
  focusTransfer.transferFocus(event, slideElement);
70982
70986
  // Asked of the SLIDE, not of this box: the box contains itself, so asking
@@ -71001,21 +71005,46 @@ const SlideContainer = ({
71001
71005
  }
71002
71006
  };
71003
71007
 
71004
- // A slide reporting that its DOM is settled (its own layout effect, see
71005
- // Slide) — the moment the transfer prepared in goToArea can land. Every
71006
- // slide reports on every commit; only the one a transfer is waiting for,
71007
- // and only while it is the current one, takes it.
71008
- const settleFocus = slideArea => {
71008
+ // The transfer prepared in goToArea lands once the slide it is for is the
71009
+ // current one AND everything the travel set off has rendered — which is
71010
+ // later than this box's own commit. A travel hands the slide a value
71011
+ // (useSlideValue), and what reads it below a component that skipped its own
71012
+ // render is re-rendered by Preact in a commit of its own, after this one. A
71013
+ // screen keyed by it, a form whose uncontrolled fields must start again from
71014
+ // a new prefill, replaces its whole subtree there: a focus landed before it
71015
+ // goes to document.body with the node. Nor can the slide say when it is done
71016
+ // from its own layout effect: rendered in the same pass as this box, its
71017
+ // effects run before this box has made it current.
71018
+ // Preact drains its render queue in one go, the renders it cascades into
71019
+ // included, so a microtask queued from this commit runs after all of them.
71020
+ // Until then the slide being left stays within reach (see markOutOfReach):
71021
+ // inert would take the keyboard off it first, and drop it on document.body.
71022
+ const landFocusHandOver = () => {
71009
71023
  const focusHandOver = focusHandOverRef.current;
71010
- if (!focusHandOver || focusHandOver.area !== slideArea) {
71011
- return;
71012
- }
71013
- const slideElement = readMap().slideElements.find(slideElement => readArea(slideElement) === slideArea);
71014
- if (!slideElement || !slideElement.hasAttribute("data-current")) {
71015
- return;
71024
+ queueMicrotask(() => {
71025
+ // Already landed by an earlier commit of this cascade, given up on, or
71026
+ // replaced by the transfer of a newer travel.
71027
+ if (focusHandOverRef.current !== focusHandOver || !trackRef.current) {
71028
+ return;
71029
+ }
71030
+ focusHandOverRef.current = null;
71031
+ const currentElement = readMap().slideElements.find(slideElement => slideElement.hasAttribute("data-current"));
71032
+ if (!currentElement) {
71033
+ return;
71034
+ }
71035
+ if (readArea(currentElement) === focusHandOver.area) {
71036
+ handOverFocus(currentElement, focusHandOver.focusTransfer, focusHandOver.event);
71037
+ }
71038
+ markOutOfReach(currentElement);
71039
+ });
71040
+ };
71041
+
71042
+ // Every slide but the one on screen out of reach — of the keyboard and of
71043
+ // assistive technology alike.
71044
+ const markOutOfReach = currentElement => {
71045
+ for (const slideElement of readMap().slideElements) {
71046
+ slideElement.toggleAttribute("inert", slideElement !== currentElement);
71016
71047
  }
71017
- focusHandOverRef.current = null;
71018
- handOverFocus(slideElement, focusHandOver.focusTransfer, focusHandOver.event);
71019
71048
  };
71020
71049
 
71021
71050
  /**
@@ -72203,7 +72232,6 @@ const SlideContainer = ({
72203
72232
  answeredAreas,
72204
72233
  done,
72205
72234
  valueByArea,
72206
- settleFocus,
72207
72235
  // What a slide reads to know whether its content is rendered yet
72208
72236
  // (see Slide's `mount`).
72209
72237
  mount,
@@ -72307,15 +72335,6 @@ const Slide = ({
72307
72335
  }), [nextIsLocked, preventNavPrevious]);
72308
72336
  // What the travel into this slide carried, if anything (see useSlideValue).
72309
72337
  const slideValue = container?.valueByArea?.[slideArea];
72310
- // This slide's DOM is settled — said after EVERY commit, no dependency
72311
- // array, because it is a fact about the render that just happened, not a
72312
- // reaction to a particular prop. The container is the one holding a focus
72313
- // transfer waiting for it (see settleFocus): a travel's value reaches this
72314
- // slide through context one flush after the container moved, and what it
72315
- // shows (a form keyed by a prefill) is only final here.
72316
- useLayoutEffect(() => {
72317
- container?.settleFocus?.(slideArea);
72318
- });
72319
72338
  return jsx(SlideContext.Provider, {
72320
72339
  value: locks,
72321
72340
  children: jsx(SlideValueContext.Provider, {