@jsenv/navi 0.29.34 → 0.29.36

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.
@@ -11579,6 +11579,11 @@ const detectors = [];
11579
11579
  * The third argument carries `{ types, readConfig }`: the claimed names actually
11580
11580
  * declared, and a number read off the element or any ancestor carrying that
11581
11581
  * attribute (so a whole list is tuned in one place).
11582
+ * @param {boolean} [definition.disputesPress] Whether this detector's interactions
11583
+ * are still deciding what a press IS while the finger/button is down — the press
11584
+ * belongs to the gesture until it resolves. Said here so that anything acting on
11585
+ * the press itself can step back and wait for the click instead (see
11586
+ * interactionsDisputeThePress).
11582
11587
  */
11583
11588
  const defineInteractionDetector = (definition) => {
11584
11589
  detectors.push(definition);
@@ -11628,6 +11633,40 @@ const resolveInteractions = (interactions) => {
11628
11633
  return resolved;
11629
11634
  };
11630
11635
 
11636
+ /**
11637
+ * Whether the declared interactions are still deciding what the press is.
11638
+ *
11639
+ * A control that acts on `mousedown` — a picker opening its popup, a button
11640
+ * whose action is asked for on the press — answers before anyone knows what the
11641
+ * press will become. That is right when nothing else disputes it: the press has
11642
+ * only one meaning, so reading it early is only reading it sooner. It is wrong
11643
+ * the moment a gesture is declared on the same element: the finger going down is
11644
+ * then the beginning of something that may be a drag, a swipe or a hold, and
11645
+ * whoever answers on the spot both takes an answer the user never gave and
11646
+ * prevents the gesture from ever forming.
11647
+ *
11648
+ * So this says "the press is disputed, do not read it yet" — and what such a
11649
+ * control does then is wait for the `click`, which the browser only delivers if
11650
+ * the press stayed a press (the gestures swallow the one they leave behind).
11651
+ */
11652
+ const interactionsDisputeThePress = (interactions) => {
11653
+ if (!interactions) {
11654
+ return false;
11655
+ }
11656
+ for (const type of Object.keys(interactions)) {
11657
+ if (!interactions[type]) {
11658
+ // Same as resolveInteractions: a falsy effect means "not this one".
11659
+ continue;
11660
+ }
11661
+ for (const detector of detectors) {
11662
+ if (detector.disputesPress && detector.claims(type)) {
11663
+ return true;
11664
+ }
11665
+ }
11666
+ }
11667
+ return false;
11668
+ };
11669
+
11631
11670
  /**
11632
11671
  * Installs the detectors for the interactions declared on an element, and takes
11633
11672
  * them down when they change or when it goes away.
@@ -12054,6 +12093,9 @@ import.meta.css = [/* css */`
12054
12093
  defineInteractionDetector({
12055
12094
  name: "press",
12056
12095
  claims: type => type in AXIS_BY_SWIPE_TYPE || type === "longpress",
12096
+ // A swipe and a hold are both "what this press turns out to be": until it
12097
+ // turns out, the press is theirs.
12098
+ disputesPress: true,
12057
12099
  setup: (element, trigger, {
12058
12100
  types,
12059
12101
  readConfig
@@ -12483,6 +12525,9 @@ defineInteractionDetector({
12483
12525
  type === LAND ||
12484
12526
  type === TOSS ||
12485
12527
  type === GRAB,
12528
+ // The press is the beginning of the gesture, not an answer: nothing may read
12529
+ // it until it is known whether the hand is dragging or just pressing.
12530
+ disputesPress: true,
12486
12531
  setup: (element, trigger, { types, readConfig }) => {
12487
12532
  const canMove = types.includes(MOVE);
12488
12533
  const canReorder = types.includes(REORDER);
@@ -24580,6 +24625,11 @@ const useControlProps = (props, {
24580
24625
  actionAfterChange = actionEvent === "change",
24581
24626
  actionDebounce
24582
24627
  } = props;
24628
+ // Asking for the action on the press is only right while the press means
24629
+ // one thing. A gesture declared on the same control (interactions={{ grab,
24630
+ // land }}, a swipe, a hold) is still deciding what that press IS, so the
24631
+ // control waits for the click instead — see interactionsDisputeThePress.
24632
+ const actsOnMouseDown = actionOnMouseDown && !interactionsDisputeThePress(props.interactions);
24583
24633
  const transferFocusToTarget = pointerEvent => {
24584
24634
  const naviProxyTarget = findFocusDelegateTarget(pointerEvent.currentTarget) || findControlProxyTarget(pointerEvent.currentTarget);
24585
24635
  if (!naviProxyTarget) {
@@ -24703,7 +24753,7 @@ const useControlProps = (props, {
24703
24753
  return {
24704
24754
  keyDown: keyDownDefault,
24705
24755
  mouseDown: e => {
24706
- if (actionOnMouseDown) {
24756
+ if (actsOnMouseDown) {
24707
24757
  return {
24708
24758
  name: "mousedown",
24709
24759
  allowed: () => onButtonInteractionAllowed(e)
@@ -24712,7 +24762,7 @@ const useControlProps = (props, {
24712
24762
  return null;
24713
24763
  },
24714
24764
  click: e => {
24715
- if (actionOnMouseDown) {
24765
+ if (actsOnMouseDown) {
24716
24766
  return null;
24717
24767
  }
24718
24768
  return {
@@ -51750,6 +51800,16 @@ const PickerCustom = props => {
51750
51800
  };
51751
51801
  }
51752
51802
  });
51803
+
51804
+ // Opening on the press mimics the native select, and it is only right
51805
+ // while nothing else disputes that press. A gesture declared on the same
51806
+ // picker (interactions={{ land, grab }}) makes the finger going down the
51807
+ // beginning of something that is not yet a choice — opening there would
51808
+ // both answer for the user and take the press from the gesture, which
51809
+ // could then never form. So the picker steps back and opens on the click,
51810
+ // which the browser only delivers if the press stayed a press (a gesture
51811
+ // swallows the click it leaves behind).
51812
+ const pressIsDisputed = interactionsDisputeThePress(props.interactions);
51753
51813
  Object.assign(pickerProps, {
51754
51814
  eventReactionDefinitions: {
51755
51815
  mouseDown: e => {
@@ -51757,6 +51817,9 @@ const PickerCustom = props => {
51757
51817
  return null;
51758
51818
  }
51759
51819
  if (openController.opened) {
51820
+ // Closing stays on the press even then: a gesture starting on an
51821
+ // open picker wants the popup out of the way, and there is no
51822
+ // choice being taken from anyone.
51760
51823
  return {
51761
51824
  name: "mousedown to close picker",
51762
51825
  allowed: () => requestClose(e, {
@@ -51764,6 +51827,9 @@ const PickerCustom = props => {
51764
51827
  })
51765
51828
  };
51766
51829
  }
51830
+ if (pressIsDisputed) {
51831
+ return null;
51832
+ }
51767
51833
  return {
51768
51834
  name: "mousedown to open picker",
51769
51835
  allowed: () => {
@@ -51779,6 +51845,8 @@ const PickerCustom = props => {
51779
51845
  }
51780
51846
  // When a label is clicked it transfers focus to the select
51781
51847
  // in that case we want to open it (otherwise we have already opened on mousedown interaction)
51848
+ // And when a gesture disputes the press (see pressIsDisputed
51849
+ // above), this is where the picker opens for real.
51782
51850
  return {
51783
51851
  name: e.detail === 0 ? "click (keyboard or progammatic) to open picker" : "click to open picker",
51784
51852
  prevented: () => {