@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.
@@ -33796,6 +33796,34 @@ const pushPopupThemeColor = ({
33796
33796
  };
33797
33797
  };
33798
33798
 
33799
+ /**
33800
+ * What a popup's wall paints, read off the `--backdrop-background` it is
33801
+ * painted from rather than off the wall: for the length of a route transition
33802
+ * played on an area the wall itself is turned transparent and stood in for
33803
+ * (transition_furniture.js), and a popup opening then would find nothing laid
33804
+ * over the edge. The variable holds a token list, resolved to a colour on an
33805
+ * element of its own, given what the wall inherits that a colour depends on:
33806
+ * color-scheme for light-dark() and the system colours, color for
33807
+ * currentcolor.
33808
+ *
33809
+ * @param {Element} element - The element declaring the variable: the dialog
33810
+ * for its ::backdrop, a popover's wall for itself.
33811
+ * @returns {string}
33812
+ */
33813
+ const readBackdropColor = (element) => {
33814
+ const elementStyle = getComputedStyle(element);
33815
+ const probe = document.createElement("div");
33816
+ probe.style.colorScheme = elementStyle.colorScheme;
33817
+ probe.style.color = elementStyle.color;
33818
+ probe.style.background = elementStyle.getPropertyValue(
33819
+ "--backdrop-background",
33820
+ );
33821
+ document.body.append(probe);
33822
+ const color = getComputedStyle(probe).backgroundColor;
33823
+ probe.remove();
33824
+ return color;
33825
+ };
33826
+
33799
33827
  let renderQueued = false;
33800
33828
  // Once per commit: a Head re-rendering leaves and arrives again in the same
33801
33829
  // commit, and the browser must not be handed the colour from in between.
@@ -35057,9 +35085,16 @@ const WALL_ATTRIBUTE = "data-navi-transition-wall";
35057
35085
  // property would replace it.
35058
35086
  const FURNITURE_ATTRIBUTE = "data-navi-transition-furniture";
35059
35087
  // What the wall paints, resolved on the matched element in both cases (the
35060
- // dialog for its ::backdrop, the popover's wall for itself): the same two
35061
- // properties, copied onto the stand-in.
35062
- const WALL_PROPERTIES = ["--backdrop-background", "--backdrop-filter"];
35088
+ // dialog for its ::backdrop, the popover's wall for itself), and what a colour
35089
+ // in it depends on: color-scheme for light-dark() and the system colours,
35090
+ // color for currentcolor. Copied onto the stand-in, which paints them in a
35091
+ // context of its own.
35092
+ const WALL_PROPERTIES = [
35093
+ "--backdrop-background",
35094
+ "--backdrop-filter",
35095
+ "color-scheme",
35096
+ "color",
35097
+ ];
35063
35098
 
35064
35099
  // The pictures the wall is painted into: the pages', and every bar's own.
35065
35100
  const FIXED_BAR_SELECTOR$1 = ".navi_fixed_bar";
@@ -57540,24 +57575,32 @@ const ControlSwap = props => {
57540
57575
  }
57541
57576
  // Reading .value during render is what subscribes the row to it.
57542
57577
  const valueRequested = signal ? signal.value : value;
57543
- const [activeName, setActiveName] = useState(() => {
57578
+ // The side holding the floor, and the cap whose press gave it (null when
57579
+ // `value`/`signal` did): which cap was pressed decides where the focus goes.
57580
+ const [floor, setFloor] = useState(() => {
57544
57581
  const nameRequested = valueRequested === undefined ? defaultValue : valueRequested;
57545
- return nameRequested === undefined ? sides[0].name : nameRequested;
57582
+ return {
57583
+ name: nameRequested === undefined ? sides[0].name : nameRequested,
57584
+ pressedCapIndex: null
57585
+ };
57546
57586
  });
57547
- const activeIndexFound = sides.findIndex(side => side.name === activeName);
57587
+ const activeIndexFound = sides.findIndex(side => side.name === floor.name);
57548
57588
  const activeIndex = activeIndexFound === -1 ? 0 : activeIndexFound;
57549
57589
  const activeSide = sides[activeIndex];
57550
57590
  const capRefs = [useRef(), useRef()];
57551
57591
  const slotRefs = [useRef(), useRef()];
57552
57592
  const slotIdPrefix = useId();
57553
- const activeNameRef = useRef(activeName);
57593
+ const activeNameRef = useRef(floor.name);
57554
57594
  activeNameRef.current = activeSide.name;
57555
- const swapTo = (name, event) => {
57595
+ const swapTo = (name, event, pressedCapIndex = null) => {
57556
57596
  if (name === activeNameRef.current) {
57557
57597
  return;
57558
57598
  }
57559
57599
  activeNameRef.current = name;
57560
- setActiveName(name);
57600
+ setFloor({
57601
+ name,
57602
+ pressedCapIndex
57603
+ });
57561
57604
  if (signal) {
57562
57605
  signal.value = name;
57563
57606
  }
@@ -57590,14 +57633,14 @@ const ControlSwap = props => {
57590
57633
  isFirstActiveRunRef.current = false;
57591
57634
  return;
57592
57635
  }
57593
- focusWithTheFloor(slotRefs[activeIndex].current, activeSide, capRefs[activeIndex].current);
57636
+ focusWithTheFloor(slotRefs[activeIndex].current, activeSide, capRefs[activeIndex].current, floor.pressedCapIndex === null ? null : capRefs[floor.pressedCapIndex].current);
57594
57637
  }, [activeSide.name]);
57595
57638
 
57596
57639
  // Both caps do the same thing, and it is the reason they sit outside the
57597
57640
  // controls: whichever one the finger lands on, the floor goes to the other
57598
57641
  // side. The same pixel opens the search and closes it.
57599
- const swapOnPress = event => {
57600
- swapTo(sides[activeIndex === 0 ? 1 : 0].name, event);
57642
+ const swapOnPress = (event, pressedCapIndex) => {
57643
+ swapTo(sides[activeIndex === 0 ? 1 : 0].name, event, pressedCapIndex);
57601
57644
  };
57602
57645
  return jsxs(Box, {
57603
57646
  flex: "x",
@@ -57611,7 +57654,7 @@ const ControlSwap = props => {
57611
57654
  side: sides[0],
57612
57655
  slotId: `${slotIdPrefix}_0`,
57613
57656
  active: activeIndex === 0,
57614
- onPress: swapOnPress
57657
+ onPress: event => swapOnPress(event, 0)
57615
57658
  }), jsx("div", {
57616
57659
  className: "navi_control_swap_stage",
57617
57660
  children: jsx("div", {
@@ -57629,7 +57672,7 @@ const ControlSwap = props => {
57629
57672
  side: sides[1],
57630
57673
  slotId: `${slotIdPrefix}_1`,
57631
57674
  active: activeIndex === 1,
57632
- onPress: swapOnPress
57675
+ onPress: event => swapOnPress(event, 1)
57633
57676
  })]
57634
57677
  });
57635
57678
  };
@@ -57660,12 +57703,14 @@ const ControlSwap = props => {
57660
57703
  * the collapsed one — the side holding the floor spells out in full what a
57661
57704
  * dot could only hint at — so it is read straight off the state
57662
57705
  * (`badge={Boolean(groupId)}`), with no "and this side is hidden" to add.
57663
- * @param autoFocus - On by default: the focus goes into this control when it
57664
- * takes the floor, where navi's ladder puts it — an `autoFocus` inside the
57665
- * control first, its first focusable otherwise. `false` leaves it on the cap
57666
- * that was pressed, for a control one reads before writing in (and, on a
57667
- * phone, for a keyboard that must not rise). Never on mount, whatever the
57668
- * setting.
57706
+ * @param autoFocus - On by default: the focus goes into this control when its
57707
+ * own cap (or `value`/`signal`) gives it the floor, where navi's ladder puts
57708
+ * it — an `autoFocus` inside the control first, its first focusable
57709
+ * otherwise. `false` leaves it on the cap that was pressed, for a control one
57710
+ * reads before writing in (and, on a phone, for a keyboard that must not
57711
+ * rise). Whatever the setting, never on mount, and never when the floor comes
57712
+ * back because the other side was put away by its own cap: that press closed
57713
+ * something, it did not ask for this control.
57669
57714
  *
57670
57715
  * Anything else — `data-testid`, `variant`, `backgroundColor`, `color`, an
57671
57716
  * `aria-describedby` — goes to the cap, which is a `<Button>`. It is the one
@@ -57740,9 +57785,13 @@ const readSides = children => {
57740
57785
  return sides;
57741
57786
  };
57742
57787
 
57743
- // The floor moved: the press that gave it landed on a cap, and what one wants
57744
- // next is the control that just arrived — typing into the search field one just
57745
- // opened, not pressing its icon again.
57788
+ // The floor moved. A press on the arriving side's own cap — the collapsed one —
57789
+ // asks for that control: what one wants next is typing into the search field
57790
+ // one just opened, not pressing its icon again. A press on the other cap puts
57791
+ // the side holding the floor away, and the arriving one only comes back because
57792
+ // the row has room for one control: the focus stays on the cap pressed, and on
57793
+ // a phone no keyboard rises over the list one went back to. A swap with no
57794
+ // press behind it (`value`/`signal` moved) is taken as asking for the arrival.
57746
57795
  //
57747
57796
  // WHERE inside is navi's own ladder (findFocusTarget): an `autoFocus` in the
57748
57797
  // control's own content first, the first focusable otherwise, a last resort
@@ -57757,8 +57806,9 @@ const readSides = children => {
57757
57806
  // open". A field marked that way so its sheet opens quietly would otherwise
57758
57807
  // leave the focus on the magnifier that was pressed to reach it.
57759
57808
  // A side one reads before writing in says `autoFocus={false}`.
57760
- const focusWithTheFloor = (arrivingSlot, arrivingSide, arrivingCap) => {
57761
- if (arrivingSide.autoFocus !== false) {
57809
+ const focusWithTheFloor = (arrivingSlot, arrivingSide, arrivingCap, pressedCap) => {
57810
+ const arrivalAskedFor = !pressedCap || pressedCap === arrivingCap;
57811
+ if (arrivalAskedFor && arrivingSide.autoFocus !== false) {
57762
57812
  const found = findFocusTarget(arrivingSlot, {
57763
57813
  restoreMayClaim: true
57764
57814
  });
@@ -57768,13 +57818,14 @@ const focusWithTheFloor = (arrivingSlot, arrivingSide, arrivingCap) => {
57768
57818
  }
57769
57819
  }
57770
57820
  // Whatever the leaving slot held is inert and off the window now, so the
57771
- // browser dropped its focus to the document body: it has to land somewhere,
57772
- // and the cap of the side taking over is where the gesture was.
57821
+ // browser dropped its focus to the document body (Safari never gave it to
57822
+ // the pressed button in the first place): it has to land somewhere, and the
57823
+ // cap pressed is where the gesture was.
57773
57824
  const {
57774
57825
  activeElement
57775
57826
  } = document;
57776
57827
  if (!activeElement || activeElement === document.body) {
57777
- moveFocusTo(arrivingCap);
57828
+ moveFocusTo(pressedCap || arrivingCap);
57778
57829
  }
57779
57830
  };
57780
57831
 
@@ -68919,7 +68970,7 @@ const useDialogProps = props => {
68919
68970
  if (isTopLayer && themeColor !== false) {
68920
68971
  addCleanup(pushPopupThemeColor({
68921
68972
  themeColor,
68922
- backdropColor: backdrop ? getComputedStyle(dialogEl, "::backdrop").backgroundColor : null,
68973
+ backdropColor: backdrop ? readBackdropColor(dialogEl) : null,
68923
68974
  surfaceColor: flushEdges.top ? getComputedStyle(dialogEl).backgroundColor : null
68924
68975
  }));
68925
68976
  }
@@ -70721,7 +70772,7 @@ const usePopoverProps = props => {
70721
70772
  if (isTopLayer && themeColor !== false) {
70722
70773
  addCleanup(pushPopupThemeColor({
70723
70774
  themeColor,
70724
- backdropColor: backdropEl ? getComputedStyle(backdropEl).backgroundColor : null
70775
+ backdropColor: backdropEl ? readBackdropColor(backdropEl) : null
70725
70776
  }));
70726
70777
  }
70727
70778
  const cancelOpenInteractionSuppression = !silent && hasCssTransitionAnimation ? suppressPointerEventsDuringTransition(popoverEl) : null;