@jsenv/navi 0.29.360 → 0.29.361

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.
@@ -4474,9 +4474,12 @@ const findControlHost = (el) => {
4474
4474
  * `findControlHost` above answers for a control's own DOM (itself, or the native
4475
4475
  * element it wraps). This one is for something that is not part of a control but
4476
4476
  * has to reach one — an interaction declared on a box (see
4477
- * interaction/interactions.js), which may be the control, may hold it, or may sit
4478
- * inside it. Nearest wins in that order, and the answer is null when there is no
4479
- * control anywhere: not every box lives in one.
4477
+ * interaction/interactions.js), which may be the control, may sit inside it, or
4478
+ * may be a wrapper around exactly one. Nearest wins in that order, and the answer
4479
+ * is null when there is no control the box belongs to: not every box lives in
4480
+ * one, and a box laying out several controls (a row of badges, a toolbar) is
4481
+ * held by none of them — its interactions are its own, and a press on its empty
4482
+ * part is not a press on the first control it happens to contain.
4480
4483
  */
4481
4484
  const findNearestControlHost = (el) => {
4482
4485
  // Itself, then upwards — the box is inside a button, or is one.
@@ -4484,8 +4487,22 @@ const findNearestControlHost = (el) => {
4484
4487
  if (selfOrAncestor) {
4485
4488
  return selfOrAncestor;
4486
4489
  }
4487
- // …then downwards: the box holds the control rather than being held by it.
4488
- return el.querySelector("[navi-control-host]");
4490
+ // …then downwards, only when the box wraps a single control. Counted by
4491
+ // control, not by host: a picker holds the hosts of its popup content, and a
4492
+ // box around that one picker is still around one control.
4493
+ let single = null;
4494
+ for (const host of el.querySelectorAll("[navi-control-host]")) {
4495
+ const controlRoot = host.closest("[navi-control]") || host;
4496
+ const controlAbove = controlRoot.parentElement.closest("[navi-control]");
4497
+ if (controlAbove && el.contains(controlAbove)) {
4498
+ continue;
4499
+ }
4500
+ if (single && single !== controlRoot) {
4501
+ return null;
4502
+ }
4503
+ single = controlRoot;
4504
+ }
4505
+ return single ? findControlHost(single) : null;
4489
4506
  };
4490
4507
  const isControlRoot = (el) => {
4491
4508
  return el.hasAttribute("navi-control");
@@ -10600,9 +10617,10 @@ const interactionsDisputeThePress = (interactions) => {
10600
10617
  *
10601
10618
  * The control is not passed in: it is found from the element, which is what lets
10602
10619
  * `interactions` live on a Box rather than on the control itself. A Box that IS a
10603
- * control (a Button) is its own; a Box around one or inside one reaches it; a Box
10604
- * with no control anywhere near it can still answer with a callback of the
10605
- * caller's, and only "request_action" has nothing to ask.
10620
+ * control (a Button) is its own; a Box inside one, or wrapping exactly one,
10621
+ * reaches it; a Box with no control anywhere near it or laying out several,
10622
+ * which belongs to none of them still answers with a callback of the caller's,
10623
+ * and only "request_action" has nothing to ask.
10606
10624
  *
10607
10625
  * Set up once per element rather than on every render, which is what lets a
10608
10626
  * detector be a plain `setup`/teardown pair. So the interactions themselves are