@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.
@@ -55951,6 +55951,10 @@ const css$$ = /* css */`@layer navi {
55951
55951
  --link-color: unset;
55952
55952
  --link-text-decoration: none;
55953
55953
  }
55954
+
55955
+ .navi_link[data-color-inherit] {
55956
+ --link-color-visited: var(--navi-link-color-visited, var(--link-color));
55957
+ }
55954
55958
  }
55955
55959
 
55956
55960
  .navi_link {
@@ -56767,6 +56771,7 @@ const LinkPlain = props => {
56767
56771
  // Visual
56768
56772
  ,
56769
56773
  "data-variant": variant,
56774
+ "data-color-inherit": props.color === "inherit" ? "" : undefined,
56770
56775
  "data-current-effect-bold": currentEffectBoldTechnique,
56771
56776
  "data-current-effect-shadow": currentEffectShadow ? "" : undefined,
56772
56777
  "data-current-indicator-position": currentIndicatorPosition,
@@ -68838,7 +68843,7 @@ const SlideContainer = ({
68838
68843
  // A transfer waiting for a travel that never happened — a controlled
68839
68844
  // `current` the caller chose not to move: dropped, the focus has no
68840
68845
  // business going anywhere. The one for a travel that DID happen stays,
68841
- // and lands when the slide it is for says it is settled (see settleFocus).
68846
+ // and lands once the slide it is for is final (see landFocusHandOver).
68842
68847
  if (focusHandOverRef.current && focusHandOverRef.current.area !== readArea(currentElement)) {
68843
68848
  focusHandOverRef.current = null;
68844
68849
  }
@@ -68992,6 +68997,11 @@ const SlideContainer = ({
68992
68997
  requestAnimationFrame(rollBack);
68993
68998
  }
68994
68999
  }
69000
+ // The slide a transfer waits for is current (any other one was dropped
69001
+ // above): it lands once the renders this commit sets off are over.
69002
+ if (focusHandOverRef.current) {
69003
+ landFocusHandOver();
69004
+ }
68995
69005
  // The keyboard is on a slide about to go out of reach and nobody has moved
68996
69006
  // it: inert would drop it on the floor (document.body), so it is handed to
68997
69007
  // the slide on screen instead. No event to read — this travel was asked for
@@ -69009,9 +69019,10 @@ const SlideContainer = ({
69009
69019
  // Out of reach LAST, once the keyboard has already moved on: a browser
69010
69020
  // takes the focus off an element the moment it becomes inert, and on its
69011
69021
  // own schedule — doing this first would let that undo the landing above and
69012
- // leave the focus on nothing.
69013
- for (const slideElement of slideElements) {
69014
- slideElement.toggleAttribute("inert", slideElement !== currentElement);
69022
+ // leave the focus on nothing. A transfer still on its way does it itself,
69023
+ // once landed.
69024
+ if (!focusHandOverRef.current) {
69025
+ markOutOfReach(currentElement);
69015
69026
  }
69016
69027
  // What is on screen now, for the travel after this one to depart from.
69017
69028
  // While a travel is playing the stage is the one that knows (it holds the
@@ -69362,14 +69373,7 @@ const SlideContainer = ({
69362
69373
  // dialog is OPEN, not when it was asked to open). `prepareFocusTransfer` has
69363
69374
  // to read the interaction — which element a mousedown landed on, whether the
69364
69375
  // modality is the keyboard — while the event is still being dispatched. The
69365
- // landing waits for the slide to say its DOM is settled (settleFocus below),
69366
- // which is later than one would think: a travel hands the slide a value
69367
- // (useSlideValue) and that value reaches it through context, so Preact
69368
- // re-renders the slide in a flush of its own — the container's own layout
69369
- // effect runs BEFORE its children have seen the value. A screen keyed by it,
69370
- // a form whose uncontrolled fields must start again from a new prefill,
69371
- // replaces its whole subtree there. Landing before that took the focus to a
69372
- // node about to be thrown away, and the focus went to document.body with it.
69376
+ // landing waits for the slide's DOM to be final (see landFocusHandOver).
69373
69377
  const handOverFocus = (slideElement, focusTransfer, event) => {
69374
69378
  focusTransfer.transferFocus(event, slideElement);
69375
69379
  // Asked of the SLIDE, not of this box: the box contains itself, so asking
@@ -69394,21 +69398,46 @@ const SlideContainer = ({
69394
69398
  }
69395
69399
  };
69396
69400
 
69397
- // A slide reporting that its DOM is settled (its own layout effect, see
69398
- // Slide) — the moment the transfer prepared in goToArea can land. Every
69399
- // slide reports on every commit; only the one a transfer is waiting for,
69400
- // and only while it is the current one, takes it.
69401
- const settleFocus = slideArea => {
69401
+ // The transfer prepared in goToArea lands once the slide it is for is the
69402
+ // current one AND everything the travel set off has rendered — which is
69403
+ // later than this box's own commit. A travel hands the slide a value
69404
+ // (useSlideValue), and what reads it below a component that skipped its own
69405
+ // render is re-rendered by Preact in a commit of its own, after this one. A
69406
+ // screen keyed by it, a form whose uncontrolled fields must start again from
69407
+ // a new prefill, replaces its whole subtree there: a focus landed before it
69408
+ // goes to document.body with the node. Nor can the slide say when it is done
69409
+ // from its own layout effect: rendered in the same pass as this box, its
69410
+ // effects run before this box has made it current.
69411
+ // Preact drains its render queue in one go, the renders it cascades into
69412
+ // included, so a microtask queued from this commit runs after all of them.
69413
+ // Until then the slide being left stays within reach (see markOutOfReach):
69414
+ // inert would take the keyboard off it first, and drop it on document.body.
69415
+ const landFocusHandOver = () => {
69402
69416
  const focusHandOver = focusHandOverRef.current;
69403
- if (!focusHandOver || focusHandOver.area !== slideArea) {
69404
- return;
69405
- }
69406
- const slideElement = readMap().slideElements.find(slideElement => readArea(slideElement) === slideArea);
69407
- if (!slideElement || !slideElement.hasAttribute("data-current")) {
69408
- return;
69417
+ queueMicrotask(() => {
69418
+ // Already landed by an earlier commit of this cascade, given up on, or
69419
+ // replaced by the transfer of a newer travel.
69420
+ if (focusHandOverRef.current !== focusHandOver || !trackRef.current) {
69421
+ return;
69422
+ }
69423
+ focusHandOverRef.current = null;
69424
+ const currentElement = readMap().slideElements.find(slideElement => slideElement.hasAttribute("data-current"));
69425
+ if (!currentElement) {
69426
+ return;
69427
+ }
69428
+ if (readArea(currentElement) === focusHandOver.area) {
69429
+ handOverFocus(currentElement, focusHandOver.focusTransfer, focusHandOver.event);
69430
+ }
69431
+ markOutOfReach(currentElement);
69432
+ });
69433
+ };
69434
+
69435
+ // Every slide but the one on screen out of reach — of the keyboard and of
69436
+ // assistive technology alike.
69437
+ const markOutOfReach = currentElement => {
69438
+ for (const slideElement of readMap().slideElements) {
69439
+ slideElement.toggleAttribute("inert", slideElement !== currentElement);
69409
69440
  }
69410
- focusHandOverRef.current = null;
69411
- handOverFocus(slideElement, focusHandOver.focusTransfer, focusHandOver.event);
69412
69441
  };
69413
69442
 
69414
69443
  /**
@@ -70596,7 +70625,6 @@ const SlideContainer = ({
70596
70625
  answeredAreas,
70597
70626
  done,
70598
70627
  valueByArea,
70599
- settleFocus,
70600
70628
  // What a slide reads to know whether its content is rendered yet
70601
70629
  // (see Slide's `mount`).
70602
70630
  mount,
@@ -70680,15 +70708,6 @@ const Slide = ({
70680
70708
  }), [nextIsLocked, preventNavPrevious]);
70681
70709
  // What the travel into this slide carried, if anything (see useSlideValue).
70682
70710
  const slideValue = container?.valueByArea?.[slideArea];
70683
- // This slide's DOM is settled — said after EVERY commit, no dependency
70684
- // array, because it is a fact about the render that just happened, not a
70685
- // reaction to a particular prop. The container is the one holding a focus
70686
- // transfer waiting for it (see settleFocus): a travel's value reaches this
70687
- // slide through context one flush after the container moved, and what it
70688
- // shows (a form keyed by a prefill) is only final here.
70689
- useLayoutEffect(() => {
70690
- container?.settleFocus?.(slideArea);
70691
- });
70692
70711
  return jsx(SlideContext.Provider, {
70693
70712
  value: locks,
70694
70713
  children: jsx(SlideValueContext.Provider, {