@jsenv/navi 0.29.451 → 0.29.452

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.
@@ -32840,6 +32840,34 @@ const pushPopupThemeColor = ({
32840
32840
  };
32841
32841
  };
32842
32842
 
32843
+ /**
32844
+ * What a popup's wall paints, read off the `--backdrop-background` it is
32845
+ * painted from rather than off the wall: for the length of a route transition
32846
+ * played on an area the wall itself is turned transparent and stood in for
32847
+ * (transition_furniture.js), and a popup opening then would find nothing laid
32848
+ * over the edge. The variable holds a token list, resolved to a colour on an
32849
+ * element of its own, given what the wall inherits that a colour depends on:
32850
+ * color-scheme for light-dark() and the system colours, color for
32851
+ * currentcolor.
32852
+ *
32853
+ * @param {Element} element - The element declaring the variable: the dialog
32854
+ * for its ::backdrop, a popover's wall for itself.
32855
+ * @returns {string}
32856
+ */
32857
+ const readBackdropColor = (element) => {
32858
+ const elementStyle = getComputedStyle(element);
32859
+ const probe = document.createElement("div");
32860
+ probe.style.colorScheme = elementStyle.colorScheme;
32861
+ probe.style.color = elementStyle.color;
32862
+ probe.style.background = elementStyle.getPropertyValue(
32863
+ "--backdrop-background",
32864
+ );
32865
+ document.body.append(probe);
32866
+ const color = getComputedStyle(probe).backgroundColor;
32867
+ probe.remove();
32868
+ return color;
32869
+ };
32870
+
32843
32871
  let renderQueued = false;
32844
32872
  // Once per commit: a Head re-rendering leaves and arrives again in the same
32845
32873
  // commit, and the browser must not be handed the colour from in between.
@@ -34061,9 +34089,16 @@ const WALL_ATTRIBUTE = "data-navi-transition-wall";
34061
34089
  // property would replace it.
34062
34090
  const FURNITURE_ATTRIBUTE = "data-navi-transition-furniture";
34063
34091
  // What the wall paints, resolved on the matched element in both cases (the
34064
- // dialog for its ::backdrop, the popover's wall for itself): the same two
34065
- // properties, copied onto the stand-in.
34066
- const WALL_PROPERTIES = ["--backdrop-background", "--backdrop-filter"];
34092
+ // dialog for its ::backdrop, the popover's wall for itself), and what a colour
34093
+ // in it depends on: color-scheme for light-dark() and the system colours,
34094
+ // color for currentcolor. Copied onto the stand-in, which paints them in a
34095
+ // context of its own.
34096
+ const WALL_PROPERTIES = [
34097
+ "--backdrop-background",
34098
+ "--backdrop-filter",
34099
+ "color-scheme",
34100
+ "color",
34101
+ ];
34067
34102
 
34068
34103
  // The pictures the wall is painted into: the pages', and every bar's own.
34069
34104
  const FIXED_BAR_SELECTOR$1 = ".navi_fixed_bar";
@@ -56331,24 +56366,32 @@ const ControlSwap = props => {
56331
56366
  }
56332
56367
  // Reading .value during render is what subscribes the row to it.
56333
56368
  const valueRequested = signal ? signal.value : value;
56334
- const [activeName, setActiveName] = useState(() => {
56369
+ // The side holding the floor, and the cap whose press gave it (null when
56370
+ // `value`/`signal` did): which cap was pressed decides where the focus goes.
56371
+ const [floor, setFloor] = useState(() => {
56335
56372
  const nameRequested = valueRequested === undefined ? defaultValue : valueRequested;
56336
- return nameRequested === undefined ? sides[0].name : nameRequested;
56373
+ return {
56374
+ name: nameRequested === undefined ? sides[0].name : nameRequested,
56375
+ pressedCapIndex: null
56376
+ };
56337
56377
  });
56338
- const activeIndexFound = sides.findIndex(side => side.name === activeName);
56378
+ const activeIndexFound = sides.findIndex(side => side.name === floor.name);
56339
56379
  const activeIndex = activeIndexFound === -1 ? 0 : activeIndexFound;
56340
56380
  const activeSide = sides[activeIndex];
56341
56381
  const capRefs = [useRef(), useRef()];
56342
56382
  const slotRefs = [useRef(), useRef()];
56343
56383
  const slotIdPrefix = useId();
56344
- const activeNameRef = useRef(activeName);
56384
+ const activeNameRef = useRef(floor.name);
56345
56385
  activeNameRef.current = activeSide.name;
56346
- const swapTo = (name, event) => {
56386
+ const swapTo = (name, event, pressedCapIndex = null) => {
56347
56387
  if (name === activeNameRef.current) {
56348
56388
  return;
56349
56389
  }
56350
56390
  activeNameRef.current = name;
56351
- setActiveName(name);
56391
+ setFloor({
56392
+ name,
56393
+ pressedCapIndex
56394
+ });
56352
56395
  if (signal) {
56353
56396
  signal.value = name;
56354
56397
  }
@@ -56381,14 +56424,14 @@ const ControlSwap = props => {
56381
56424
  isFirstActiveRunRef.current = false;
56382
56425
  return;
56383
56426
  }
56384
- focusWithTheFloor(slotRefs[activeIndex].current, activeSide, capRefs[activeIndex].current);
56427
+ focusWithTheFloor(slotRefs[activeIndex].current, activeSide, capRefs[activeIndex].current, floor.pressedCapIndex === null ? null : capRefs[floor.pressedCapIndex].current);
56385
56428
  }, [activeSide.name]);
56386
56429
 
56387
56430
  // Both caps do the same thing, and it is the reason they sit outside the
56388
56431
  // controls: whichever one the finger lands on, the floor goes to the other
56389
56432
  // side. The same pixel opens the search and closes it.
56390
- const swapOnPress = event => {
56391
- swapTo(sides[activeIndex === 0 ? 1 : 0].name, event);
56433
+ const swapOnPress = (event, pressedCapIndex) => {
56434
+ swapTo(sides[activeIndex === 0 ? 1 : 0].name, event, pressedCapIndex);
56392
56435
  };
56393
56436
  return jsxs(Box, {
56394
56437
  flex: "x",
@@ -56402,7 +56445,7 @@ const ControlSwap = props => {
56402
56445
  side: sides[0],
56403
56446
  slotId: `${slotIdPrefix}_0`,
56404
56447
  active: activeIndex === 0,
56405
- onPress: swapOnPress
56448
+ onPress: event => swapOnPress(event, 0)
56406
56449
  }), jsx("div", {
56407
56450
  className: "navi_control_swap_stage",
56408
56451
  children: jsx("div", {
@@ -56420,7 +56463,7 @@ const ControlSwap = props => {
56420
56463
  side: sides[1],
56421
56464
  slotId: `${slotIdPrefix}_1`,
56422
56465
  active: activeIndex === 1,
56423
- onPress: swapOnPress
56466
+ onPress: event => swapOnPress(event, 1)
56424
56467
  })]
56425
56468
  });
56426
56469
  };
@@ -56451,12 +56494,14 @@ const ControlSwap = props => {
56451
56494
  * the collapsed one — the side holding the floor spells out in full what a
56452
56495
  * dot could only hint at — so it is read straight off the state
56453
56496
  * (`badge={Boolean(groupId)}`), with no "and this side is hidden" to add.
56454
- * @param autoFocus - On by default: the focus goes into this control when it
56455
- * takes the floor, where navi's ladder puts it — an `autoFocus` inside the
56456
- * control first, its first focusable otherwise. `false` leaves it on the cap
56457
- * that was pressed, for a control one reads before writing in (and, on a
56458
- * phone, for a keyboard that must not rise). Never on mount, whatever the
56459
- * setting.
56497
+ * @param autoFocus - On by default: the focus goes into this control when its
56498
+ * own cap (or `value`/`signal`) gives it the floor, where navi's ladder puts
56499
+ * it — an `autoFocus` inside the control first, its first focusable
56500
+ * otherwise. `false` leaves it on the cap that was pressed, for a control one
56501
+ * reads before writing in (and, on a phone, for a keyboard that must not
56502
+ * rise). Whatever the setting, never on mount, and never when the floor comes
56503
+ * back because the other side was put away by its own cap: that press closed
56504
+ * something, it did not ask for this control.
56460
56505
  *
56461
56506
  * Anything else — `data-testid`, `variant`, `backgroundColor`, `color`, an
56462
56507
  * `aria-describedby` — goes to the cap, which is a `<Button>`. It is the one
@@ -56531,9 +56576,13 @@ const readSides = children => {
56531
56576
  return sides;
56532
56577
  };
56533
56578
 
56534
- // The floor moved: the press that gave it landed on a cap, and what one wants
56535
- // next is the control that just arrived — typing into the search field one just
56536
- // opened, not pressing its icon again.
56579
+ // The floor moved. A press on the arriving side's own cap — the collapsed one —
56580
+ // asks for that control: what one wants next is typing into the search field
56581
+ // one just opened, not pressing its icon again. A press on the other cap puts
56582
+ // the side holding the floor away, and the arriving one only comes back because
56583
+ // the row has room for one control: the focus stays on the cap pressed, and on
56584
+ // a phone no keyboard rises over the list one went back to. A swap with no
56585
+ // press behind it (`value`/`signal` moved) is taken as asking for the arrival.
56537
56586
  //
56538
56587
  // WHERE inside is navi's own ladder (findFocusTarget): an `autoFocus` in the
56539
56588
  // control's own content first, the first focusable otherwise, a last resort
@@ -56548,8 +56597,9 @@ const readSides = children => {
56548
56597
  // open". A field marked that way so its sheet opens quietly would otherwise
56549
56598
  // leave the focus on the magnifier that was pressed to reach it.
56550
56599
  // A side one reads before writing in says `autoFocus={false}`.
56551
- const focusWithTheFloor = (arrivingSlot, arrivingSide, arrivingCap) => {
56552
- if (arrivingSide.autoFocus !== false) {
56600
+ const focusWithTheFloor = (arrivingSlot, arrivingSide, arrivingCap, pressedCap) => {
56601
+ const arrivalAskedFor = !pressedCap || pressedCap === arrivingCap;
56602
+ if (arrivalAskedFor && arrivingSide.autoFocus !== false) {
56553
56603
  const found = findFocusTarget(arrivingSlot, {
56554
56604
  restoreMayClaim: true
56555
56605
  });
@@ -56559,13 +56609,14 @@ const focusWithTheFloor = (arrivingSlot, arrivingSide, arrivingCap) => {
56559
56609
  }
56560
56610
  }
56561
56611
  // Whatever the leaving slot held is inert and off the window now, so the
56562
- // browser dropped its focus to the document body: it has to land somewhere,
56563
- // and the cap of the side taking over is where the gesture was.
56612
+ // browser dropped its focus to the document body (Safari never gave it to
56613
+ // the pressed button in the first place): it has to land somewhere, and the
56614
+ // cap pressed is where the gesture was.
56564
56615
  const {
56565
56616
  activeElement
56566
56617
  } = document;
56567
56618
  if (!activeElement || activeElement === document.body) {
56568
- moveFocusTo(arrivingCap);
56619
+ moveFocusTo(pressedCap || arrivingCap);
56569
56620
  }
56570
56621
  };
56571
56622
 
@@ -67563,7 +67614,7 @@ const useDialogProps = props => {
67563
67614
  if (isTopLayer && themeColor !== false) {
67564
67615
  addCleanup(pushPopupThemeColor({
67565
67616
  themeColor,
67566
- backdropColor: backdrop ? getComputedStyle(dialogEl, "::backdrop").backgroundColor : null,
67617
+ backdropColor: backdrop ? readBackdropColor(dialogEl) : null,
67567
67618
  surfaceColor: flushEdges.top ? getComputedStyle(dialogEl).backgroundColor : null
67568
67619
  }));
67569
67620
  }
@@ -69330,7 +69381,7 @@ const usePopoverProps = props => {
69330
69381
  if (isTopLayer && themeColor !== false) {
69331
69382
  addCleanup(pushPopupThemeColor({
69332
69383
  themeColor,
69333
- backdropColor: backdropEl ? getComputedStyle(backdropEl).backgroundColor : null
69384
+ backdropColor: backdropEl ? readBackdropColor(backdropEl) : null
69334
69385
  }));
69335
69386
  }
69336
69387
  const cancelOpenInteractionSuppression = !silent && hasCssTransitionAnimation ? suppressPointerEventsDuringTransition(popoverEl) : null;