@jsenv/navi 0.29.362 → 0.29.364

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.
@@ -8914,6 +8914,17 @@ const naviI18nFromValidityMessage = ({ key, params }) => {
8914
8914
  return naviI18n(`constraint.${key}`, params);
8915
8915
  };
8916
8916
 
8917
+ // The characters a ui state holds, for the rules that read a value as text
8918
+ // (length, pattern, number, email…). `undefined` and `null` both hold none:
8919
+ // `String(null)` would hand those rules the four letters "null" — a number
8920
+ // field cleared with `value={null}` then reported "must be a number".
8921
+ const uiStateAsText = (uiState) => {
8922
+ if (uiState === undefined || uiState === null) {
8923
+ return "";
8924
+ }
8925
+ return String(uiState);
8926
+ };
8927
+
8917
8928
  /**
8918
8929
  * https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation
8919
8930
  */
@@ -8980,8 +8991,7 @@ const REQUIRED_CONSTRAINT = {
8980
8991
  return naviI18n("constraint.required.checkbox");
8981
8992
  }
8982
8993
 
8983
- const valueAsString =
8984
- field.uiState === undefined ? "" : String(field.uiState);
8994
+ const valueAsString = uiStateAsText(field.uiState);
8985
8995
  if (valueAsString) {
8986
8996
  return null;
8987
8997
  }
@@ -9032,8 +9042,7 @@ const PATTERN_CONSTRAINT = {
9032
9042
  if (!pattern) {
9033
9043
  return null;
9034
9044
  }
9035
- const valueAsString =
9036
- field.uiState === undefined ? "" : String(field.uiState);
9045
+ const valueAsString = uiStateAsText(field.uiState);
9037
9046
  if (!valueAsString) {
9038
9047
  return null;
9039
9048
  }
@@ -9068,8 +9077,7 @@ const TYPE_EMAIL_CONSTRAINT = {
9068
9077
  if (type !== "email") {
9069
9078
  return null;
9070
9079
  }
9071
- const valueAsString =
9072
- field.uiState === undefined ? "" : String(field.uiState);
9080
+ const valueAsString = uiStateAsText(field.uiState);
9073
9081
  if (!valueAsString) {
9074
9082
  return null;
9075
9083
  }
@@ -9102,8 +9110,7 @@ const MIN_LENGTH_CONSTRAINT = {
9102
9110
  if (minLength === undefined) {
9103
9111
  return null;
9104
9112
  }
9105
- const valueAsString =
9106
- field.uiState === undefined ? "" : String(field.uiState);
9113
+ const valueAsString = uiStateAsText(field.uiState);
9107
9114
  if (!valueAsString && !field.controlHostProps.required) {
9108
9115
  return null;
9109
9116
  }
@@ -9198,8 +9205,7 @@ const MAX_LENGTH_CONSTRAINT = {
9198
9205
  if (maxLength === undefined) {
9199
9206
  return null;
9200
9207
  }
9201
- const valueAsString =
9202
- field.uiState === undefined ? "" : String(field.uiState);
9208
+ const valueAsString = uiStateAsText(field.uiState);
9203
9209
  if (!valueAsString) {
9204
9210
  return null;
9205
9211
  }
@@ -9240,8 +9246,7 @@ const TYPE_NUMBER_CONSTRAINT = {
9240
9246
  if (!isNumberInput(type, naviType)) {
9241
9247
  return null;
9242
9248
  }
9243
- const valueAsString =
9244
- field.uiState === undefined ? "" : String(field.uiState);
9249
+ const valueAsString = uiStateAsText(field.uiState);
9245
9250
  if (!valueAsString) {
9246
9251
  return null;
9247
9252
  }
@@ -9306,8 +9311,7 @@ const MIN_CONSTRAINT = {
9306
9311
  }
9307
9312
  const type = field.controlHostProps.type;
9308
9313
  const naviInputType = field.controlHostProps["navi-input-type"];
9309
- const valueAsString =
9310
- field.uiState === undefined ? "" : String(field.uiState);
9314
+ const valueAsString = uiStateAsText(field.uiState);
9311
9315
  if (!valueAsString) {
9312
9316
  return null;
9313
9317
  }
@@ -9406,8 +9410,7 @@ const MAX_CONSTRAINT = {
9406
9410
  }
9407
9411
  const type = field.controlHostProps.type;
9408
9412
  const naviInputType = field.controlHostProps["navi-input-type"];
9409
- const valueAsString =
9410
- field.uiState === undefined ? "" : String(field.uiState);
9413
+ const valueAsString = uiStateAsText(field.uiState);
9411
9414
  if (!valueAsString) {
9412
9415
  return null;
9413
9416
  }
@@ -9540,8 +9543,7 @@ const STEP_CONSTRAINT = {
9540
9543
  return null;
9541
9544
  }
9542
9545
  const stepString = String(stepRaw);
9543
- const valueAsString =
9544
- field.uiState === undefined ? "" : String(field.uiState);
9546
+ const valueAsString = uiStateAsText(field.uiState);
9545
9547
  if (!valueAsString) {
9546
9548
  return null;
9547
9549
  }
@@ -12341,8 +12343,7 @@ const DISPLAYABLE_CONSTRAINT = {
12341
12343
  if (!isConstraintAttributeOn(displayable)) {
12342
12344
  return null;
12343
12345
  }
12344
- const valueAsString =
12345
- field.uiState === undefined ? "" : String(field.uiState);
12346
+ const valueAsString = uiStateAsText(field.uiState);
12346
12347
  const maxStackedMarksAttribute =
12347
12348
  field.controlHostProps["data-max-stacked-marks"];
12348
12349
  const result = DISPLAYABLE_RULE.applyOn(true, valueAsString, {
@@ -12383,8 +12384,7 @@ const MAX_LINE_BREAKS_CONSTRAINT = {
12383
12384
  if (isNaN(maxLineBreaks)) {
12384
12385
  return null;
12385
12386
  }
12386
- const valueAsString =
12387
- field.uiState === undefined ? "" : String(field.uiState);
12387
+ const valueAsString = uiStateAsText(field.uiState);
12388
12388
  const result = MAX_LINE_BREAKS_RULE.applyOn(maxLineBreaks, valueAsString);
12389
12389
  if (!result) {
12390
12390
  return null;
@@ -12413,8 +12413,7 @@ const NO_EMOJI_CONSTRAINT = {
12413
12413
  if (!isConstraintAttributeOn(noEmoji)) {
12414
12414
  return null;
12415
12415
  }
12416
- const valueAsString =
12417
- field.uiState === undefined ? "" : String(field.uiState);
12416
+ const valueAsString = uiStateAsText(field.uiState);
12418
12417
  const result = NO_EMOJI_RULE.applyOn(true, valueAsString);
12419
12418
  if (!result) {
12420
12419
  return null;
@@ -12428,8 +12427,7 @@ const MIN_LOWER_LETTER_CONSTRAINT = {
12428
12427
  name: "min_lower_letter",
12429
12428
  messageAttribute: "data-min-lower-letter-message",
12430
12429
  check: (field) => {
12431
- const valueAsString =
12432
- field.uiState === undefined ? "" : String(field.uiState);
12430
+ const valueAsString = uiStateAsText(field.uiState);
12433
12431
  const required = field.controlHostProps.required;
12434
12432
  if (!valueAsString && !required) {
12435
12433
  return "";
@@ -12474,8 +12472,7 @@ const MIN_UPPER_LETTER_CONSTRAINT = {
12474
12472
  name: "min_upper_letter",
12475
12473
  messageAttribute: "data-min-upper-letter-message",
12476
12474
  check: (field) => {
12477
- const valueAsString =
12478
- field.uiState === undefined ? "" : String(field.uiState);
12475
+ const valueAsString = uiStateAsText(field.uiState);
12479
12476
  const required = field.controlHostProps.required;
12480
12477
  if (!valueAsString && !required) {
12481
12478
  return null;
@@ -12511,8 +12508,7 @@ const MIN_DIGIT_CONSTRAINT = {
12511
12508
  name: "min_digit",
12512
12509
  messageAttribute: "data-min-digit-message",
12513
12510
  check: (field) => {
12514
- const valueAsString =
12515
- field.uiState === undefined ? "" : String(field.uiState);
12511
+ const valueAsString = uiStateAsText(field.uiState);
12516
12512
  const required = field.controlHostProps.required;
12517
12513
  if (!valueAsString && !required) {
12518
12514
  return null;
@@ -12548,8 +12544,7 @@ const MIN_SPECIAL_CHAR_CONSTRAINT = {
12548
12544
  name: "min_special_char",
12549
12545
  messageAttribute: "data-min-special-char-message",
12550
12546
  check: (field) => {
12551
- const valueAsString =
12552
- field.uiState === undefined ? "" : String(field.uiState);
12547
+ const valueAsString = uiStateAsText(field.uiState);
12553
12548
  const required = field.controlHostProps.required;
12554
12549
  if (!valueAsString && !required) {
12555
12550
  return null;
@@ -12666,8 +12661,7 @@ const SAME_AS_CONSTRAINT = {
12666
12661
  // Reference field is empty — nothing to compare against yet.
12667
12662
  return null;
12668
12663
  }
12669
- const valueAsString =
12670
- field.uiState === undefined ? "" : String(field.uiState);
12664
+ const valueAsString = uiStateAsText(field.uiState);
12671
12665
  if (valueAsString === otherFieldValue) {
12672
12666
  return null;
12673
12667
  }
@@ -12708,8 +12702,7 @@ CONSTRAINT_ATTRIBUTE_SET.add("data-same-as");
12708
12702
 
12709
12703
 
12710
12704
  const applyRule = (field) => {
12711
- const valueAsString =
12712
- field.uiState === undefined ? "" : String(field.uiState);
12705
+ const valueAsString = uiStateAsText(field.uiState);
12713
12706
  return SINGLE_SPACE_RULE.applyOn(true, valueAsString);
12714
12707
  };
12715
12708
 
@@ -36535,9 +36528,9 @@ const getInvalidCharsMessage = (
36535
36528
  uiState,
36536
36529
  { charClass, messageKey, uiStateNow },
36537
36530
  ) => {
36538
- const str = uiState === undefined ? "" : String(uiState);
36531
+ const str = uiStateAsText(uiState);
36539
36532
  if (compileCharClassAnchored(charClass).test(str)) return null;
36540
- const strNow = uiStateNow === undefined ? "" : String(uiStateNow);
36533
+ const strNow = uiStateAsText(uiStateNow);
36541
36534
  if (
36542
36535
  countCharsOutsideClass(str, charClass) <=
36543
36536
  countCharsOutsideClass(strNow, charClass)
@@ -36550,9 +36543,9 @@ const getInvalidCharsMessage = (
36550
36543
  // Paste / set: truncate what the gesture adds beyond the limit.
36551
36544
  const getLengthOverflowResult = (uiState, { maxLength, uiStateNow }) => {
36552
36545
  if (maxLength === undefined) return null;
36553
- const str = uiState === undefined ? "" : String(uiState);
36546
+ const str = uiStateAsText(uiState);
36554
36547
  if (str.length <= maxLength) return null;
36555
- const strNow = uiStateNow === undefined ? "" : String(uiStateNow);
36548
+ const strNow = uiStateAsText(uiStateNow);
36556
36549
  if (str.length <= strNow.length) return null;
36557
36550
  return {
36558
36551
  fixedValue: str.slice(0, maxLength),
@@ -55439,6 +55432,10 @@ const SlideContainer = ({
55439
55432
  // one being travelled TO while the track moves. What the next travel departs
55440
55433
  // from, because it is what one is looking at.
55441
55434
  const drawnAreaRef = useRef(undefined);
55435
+ // The movement the track is playing, while it plays: the slide it is leaving
55436
+ // and the slide it is going to. A hand landing on the box takes it over from
55437
+ // its origin (see onStart in createTravelHandlers).
55438
+ const movingRef = useRef(null);
55442
55439
  // Which way the travel about to be drawn goes, when whatever asked for it
55443
55440
  // knows: a window stepping off its last slide comes back on its first, and
55444
55441
  // only the press says that is a step forward — the map, read between those
@@ -55700,6 +55697,7 @@ const SlideContainer = ({
55700
55697
  }
55701
55698
  stageRef.current = null;
55702
55699
  trackAnimationRef.current = null;
55700
+ movingRef.current = null;
55703
55701
  // At rest the picture IS the current slide, whatever the last gesture wrote
55704
55702
  // there: an indicator has nothing left to lean towards.
55705
55703
  paintTravelProgress(0);
@@ -55894,7 +55892,7 @@ const SlideContainer = ({
55894
55892
  // there, and when it is over this is what holds. Except under a hand-off
55895
55893
  // still waiting for its travel: the track stays where the finger left it,
55896
55894
  // until the render that moves it or the frame after which the gesture gives
55897
- // up on it (see returnToRest in onEnd).
55895
+ // up on it (see settleTowards in onEnd).
55898
55896
  if (!travelFromRef.current) {
55899
55897
  track.style.setProperty("--slide-container-offset", offset);
55900
55898
  }
@@ -55929,6 +55927,10 @@ const SlideContainer = ({
55929
55927
  duration: durationMs * travelRatio,
55930
55928
  easing
55931
55929
  });
55930
+ movingRef.current = {
55931
+ from: drawnArea,
55932
+ to: currentArea
55933
+ };
55932
55934
  // The trait travels with the slides: from where the gesture left it when
55933
55935
  // there was one, from a whole box away when the travel was asked for.
55934
55936
  const progressFrom = travelProgressFromRef.current ?? (travelStep ? travelStep.x || travelStep.y : 0);
@@ -56714,7 +56716,7 @@ const SlideContainer = ({
56714
56716
  // The two slides the gesture can bring in, placed one box either side of the
56715
56717
  // one being dragged — the same stage a travel builds, except that both ends
56716
56718
  // are set up at once because the finger has not said yet which way it goes.
56717
- const stageDrag = drag => {
56719
+ const stageDrag = (drag, currentArea) => {
56718
56720
  const {
56719
56721
  slideElements,
56720
56722
  placeOf
@@ -56742,7 +56744,7 @@ const SlideContainer = ({
56742
56744
  }
56743
56745
  stageRef.current = {
56744
56746
  placeByArea,
56745
- area: drag.area
56747
+ area: currentArea
56746
56748
  };
56747
56749
  for (const slideElement of slideElements) {
56748
56750
  const area = readArea(slideElement);
@@ -56758,33 +56760,63 @@ const SlideContainer = ({
56758
56760
  }
56759
56761
  };
56760
56762
 
56761
- // Let go of without enough of a gesture to travel: the slide comes back to
56762
- // where it was, over the distance it was pulled so a slide barely moved
56763
- // snaps back and one dragged most of the way there takes its time.
56764
- const returnToRest = drag => {
56763
+ // Let go of, and the slides go where the gesture leaves them: back on the
56764
+ // slide being dragged when nothing travels, on to the slide arriving when a
56765
+ // travel caught in flight is let carry on. Over the distance left to cover,
56766
+ // so a slide barely moved snaps back and one dragged most of the way there
56767
+ // takes its time.
56768
+ const settleTowards = (drag, area) => {
56765
56769
  const track = trackRef.current;
56766
56770
  if (!track) {
56767
56771
  return;
56768
56772
  }
56769
- const restOffset = `${drag.baseOffset.x}px ${drag.baseOffset.y}px`;
56773
+ const stage = stageRef.current;
56774
+ const {
56775
+ placeOf
56776
+ } = readMap();
56777
+ const place = stage?.placeByArea.get(area) || placeOf.get(area) || {
56778
+ x: 0,
56779
+ y: 0
56780
+ };
56781
+ const restPx = {
56782
+ x: -place.x * drag.box.width,
56783
+ y: -place.y * drag.box.height
56784
+ };
56785
+ const nowPx = {
56786
+ x: drag.baseOffset.x + drag.pull.x,
56787
+ y: drag.baseOffset.y + drag.pull.y
56788
+ };
56789
+ const restOffset = `${restPx.x}px ${restPx.y}px`;
56770
56790
  const durationMs = durationToMs(duration);
56771
- const pulled = Math.abs(drag.pull[drag.axis]);
56772
56791
  const size = drag.axis === "x" ? drag.box.width : drag.box.height;
56792
+ const left = Math.abs(restPx[drag.axis] - nowPx[drag.axis]);
56773
56793
  trackAnimationRef.current?.cancel();
56774
56794
  trackAnimationRef.current = null;
56775
56795
  track.style.setProperty("--slide-container-offset", restOffset);
56776
- if (!durationMs || !pulled) {
56796
+ if (!durationMs || !left) {
56777
56797
  paintTravelProgress(0);
56778
56798
  settleTravel();
56779
56799
  return;
56780
56800
  }
56781
- animateTravelProgress(drag.progress, durationMs * (pulled / size), "ease-out", drag.areaPulled);
56801
+ // Which other slide the picture leans on while it arrives: the one being
56802
+ // pulled in when it comes back on the dragged slide, the dragged slide
56803
+ // itself when it goes on to the one arriving — and the trait is then a
56804
+ // box short of that one, which is what it has to close.
56805
+ const arrivesOnBase = area === drag.area;
56806
+ const sign = drag.pull[drag.axis] > 0 ? 1 : -1;
56807
+ const progressFrom = arrivesOnBase ? drag.progress : drag.progress - sign;
56808
+ const otherArea = arrivesOnBase ? drag.areaPulled : drag.area;
56809
+ movingRef.current = {
56810
+ from: otherArea,
56811
+ to: area
56812
+ };
56813
+ animateTravelProgress(progressFrom, durationMs * (left / size), "ease-out", otherArea);
56782
56814
  const animation = track.animate([{
56783
- translate: drag.offset
56815
+ translate: `${nowPx.x}px ${nowPx.y}px`
56784
56816
  }, {
56785
56817
  translate: restOffset
56786
56818
  }], {
56787
- duration: durationMs * (pulled / size),
56819
+ duration: durationMs * (left / size),
56788
56820
  easing: "ease-out"
56789
56821
  });
56790
56822
  trackAnimationRef.current = animation;
@@ -56815,11 +56847,14 @@ const SlideContainer = ({
56815
56847
  // value underneath it, which is the far end of the travel — the very jump
56816
56848
  // this is about.
56817
56849
  trackElement.style.setProperty("--slide-container-offset", offsetOnScreen);
56850
+ const moving = movingRef.current || {};
56818
56851
  return {
56819
56852
  trackElement,
56820
56853
  onScreenPx,
56821
56854
  offsetOnScreen,
56822
- offsetTarget: offsetRef.current
56855
+ offsetTarget: offsetRef.current,
56856
+ from: moving.from,
56857
+ to: moving.to
56823
56858
  };
56824
56859
  };
56825
56860
  // Which way a caught travel was going: a hand reaching for something moving
@@ -56866,8 +56901,6 @@ const SlideContainer = ({
56866
56901
  sign,
56867
56902
  target
56868
56903
  }) => {
56869
- let areaBack = axis === "x" ? areaTowards(-1, 0) : areaTowards(0, -1);
56870
- let areaOn = axis === "x" ? areaTowards(1, 0) : areaTowards(0, 1);
56871
56904
  // Everything positional is read HERE rather than when the pointer
56872
56905
  // landed: the travel that was playing then may have arrived since, and
56873
56906
  // it is what the slides are doing at the moment the gesture takes them
@@ -56878,39 +56911,66 @@ const SlideContainer = ({
56878
56911
  placeOf
56879
56912
  } = readMap();
56880
56913
  const currentElement = slideElements.find(slideElement => slideElement.hasAttribute("data-current")) || slideElements[0];
56881
- // The hold goToArea reads at the release, read again HERE, off the same
56882
- // slide and the same attribute: a slide that will refuse the arrival
56883
- // must not offer the journey. A locked direction simply has nowhere to
56884
- // go for the length of this gesture — the one case the gesture already
56885
- // knows, being the last slide of a walk. The hand then gets the wall it
56886
- // can lean on and never walk through (see drag_to_travel), the slide
56887
- // behind it stays offstage instead of being read on the way, and the
56888
- // release has nothing left to refuse.
56889
- // Nothing here about `released` (--navi-done): that is one particular
56890
- // departure letting go, decided as it happens, and a gesture armed
56891
- // before it has no such thing to read — the attribute as rendered is
56892
- // what the hand is answered from.
56893
- if (currentElement?.hasAttribute("data-prevent-nav-previous")) {
56894
- areaBack = undefined;
56895
- }
56896
- if (currentElement?.hasAttribute("data-prevent-nav-next")) {
56897
- areaOn = undefined;
56898
- }
56899
56914
  const box = track.getBoundingClientRect();
56900
- if (!areaBack && !areaOn || !currentElement || !box.width || !box.height ||
56901
- // Something else with a better claim on the gesture: a scroller
56902
- // between the finger and the slide, with room left that way.
56903
- scrollRoomTowards(target, currentElement, axis, sign)) {
56915
+ if (!currentElement || !box.width || !box.height) {
56904
56916
  return false;
56905
56917
  }
56906
- const area = readArea(currentElement);
56907
- // Where the slide being dragged stands: where the stage put it while a
56908
- // travel is playing, its place on the map otherwise.
56918
+ const currentArea = readArea(currentElement);
56909
56919
  const stage = stageRef.current;
56910
- const basePlace = stage?.placeByArea.get(area) || placeOf.get(area) || {
56920
+ // Where a slide stands: where the stage put it while a travel is
56921
+ // playing, its place on the map otherwise.
56922
+ const placeOfArea = someArea => stage?.placeByArea.get(someArea) || placeOf.get(someArea) || {
56911
56923
  x: 0,
56912
56924
  y: 0
56913
56925
  };
56926
+ // A travel caught in flight is measured from the slide it SET OFF from,
56927
+ // with the slide it was going to as the one thing the hand can bring
56928
+ // in — the way drag_to_travel reads a `slack`: how far the box already
56929
+ // sits from its resting place, towards what is being pulled in. That is
56930
+ // what makes its answer "carry on" mean arriving. Based on the slide
56931
+ // arriving instead, the slack would point back at the origin, and a
56932
+ // hand that merely touched the box would send it all the way back.
56933
+ // A movement with no origin of its own (the track re-placed without a
56934
+ // travel) is dragged from the slide shown, like any slide at rest.
56935
+ const origin = caughtTravel && caughtTravel.from !== caughtTravel.to ? caughtTravel.from : null;
56936
+ let area;
56937
+ let areaBack;
56938
+ let areaOn;
56939
+ if (origin) {
56940
+ area = origin;
56941
+ const towardsEnd = axis === "x" ? placeOfArea(currentArea).x > placeOfArea(origin).x : placeOfArea(currentArea).y > placeOfArea(origin).y;
56942
+ areaBack = towardsEnd ? undefined : currentArea;
56943
+ areaOn = towardsEnd ? currentArea : undefined;
56944
+ } else {
56945
+ area = currentArea;
56946
+ areaBack = axis === "x" ? areaTowards(-1, 0) : areaTowards(0, -1);
56947
+ areaOn = axis === "x" ? areaTowards(1, 0) : areaTowards(0, 1);
56948
+ // The hold goToArea reads at the release, read again HERE, off the
56949
+ // same slide and the same attribute: a slide that will refuse the
56950
+ // arrival must not offer the journey. A locked direction simply has
56951
+ // nowhere to go for the length of this gesture — the one case the
56952
+ // gesture already knows, being the last slide of a walk. The hand
56953
+ // then gets the wall it can lean on and never walk through (see
56954
+ // drag_to_travel), the slide behind it stays offstage instead of
56955
+ // being read on the way, and the release has nothing left to refuse.
56956
+ // Nothing here about `released` (--navi-done): that is one particular
56957
+ // departure letting go, decided as it happens, and a gesture armed
56958
+ // before it has no such thing to read — the attribute as rendered is
56959
+ // what the hand is answered from.
56960
+ if (currentElement.hasAttribute("data-prevent-nav-previous")) {
56961
+ areaBack = undefined;
56962
+ }
56963
+ if (currentElement.hasAttribute("data-prevent-nav-next")) {
56964
+ areaOn = undefined;
56965
+ }
56966
+ if (!areaBack && !areaOn ||
56967
+ // Something else with a better claim on the gesture: a scroller
56968
+ // between the finger and the slide, with room left that way.
56969
+ scrollRoomTowards(target, currentElement, axis, sign)) {
56970
+ return false;
56971
+ }
56972
+ }
56973
+ const basePlace = placeOfArea(area);
56914
56974
  const baseOffset = {
56915
56975
  x: -basePlace.x * box.width,
56916
56976
  y: -basePlace.y * box.height
@@ -56941,7 +57001,8 @@ const SlideContainer = ({
56941
57001
  [axis]: slack
56942
57002
  };
56943
57003
  drag.progress = slack / size;
56944
- stageDrag(drag);
57004
+ drag.areaPulled = slack > 0 ? areaBack : slack < 0 ? areaOn : null;
57005
+ stageDrag(drag, currentArea);
56945
57006
  // From here the box is busy, whichever input asked: a wheel gesture and
56946
57007
  // a press must not both be moving the same track.
56947
57008
  dragRef.current = drag;
@@ -56972,24 +57033,50 @@ const SlideContainer = ({
56972
57033
  event
56973
57034
  }) => {
56974
57035
  dragRef.current = null;
56975
- if (!travels) {
56976
- returnToRest(drag);
57036
+ // Where the gesture leaves the slides: on the one it was pulling in
57037
+ // when it says so, back on the one it was dragging otherwise.
57038
+ const destination = travels ? sign > 0 ? drag.areaBack : drag.areaOn : drag.area;
57039
+ const {
57040
+ slideElements,
57041
+ placeOf
57042
+ } = readMap();
57043
+ const currentElement = slideElements.find(slideElement => slideElement.hasAttribute("data-current")) || slideElements[0];
57044
+ const currentArea = currentElement && readArea(currentElement);
57045
+ if (!destination || destination === currentArea) {
57046
+ // Nothing to ask of the state: the slide it names is already the one
57047
+ // shown — a drag let go of short of a travel, a travel caught in
57048
+ // flight and let carry on. The track goes there on its own.
57049
+ settleTowards(drag, destination || drag.area);
56977
57050
  return;
56978
57051
  }
56979
57052
  // Where the slide is being left, for the travel to depart from instead
56980
57053
  // of from the map.
56981
57054
  travelFromRef.current = drag.offset;
56982
57055
  // …and where the indicator is being left, said about the slide that is
56983
- // ARRIVING: the picture is `sign` of a box short of it, and that is
56984
- // what the travel about to be drawn has to close.
56985
- travelProgressFromRef.current = drag.progress - sign;
56986
- const moved = axis === "x" ? move(-sign, 0, event) : move(0, -sign, event);
57056
+ // ARRIVING: a box short of the slide being pulled in, right where the
57057
+ // finger left it when going back to the slide being dragged.
57058
+ travelProgressFromRef.current = travels ? drag.progress - sign : drag.progress;
57059
+ // Which way the travel goes, read off where the two slides stand
57060
+ // rather than off the pull: a travel caught in flight and put back
57061
+ // goes the way it came, whatever the finger did meanwhile.
57062
+ const stage = stageRef.current;
57063
+ const placeOfArea = someArea => stage?.placeByArea.get(someArea) || placeOf.get(someArea) || {
57064
+ x: 0,
57065
+ y: 0
57066
+ };
57067
+ const towards = Math.sign(placeOfArea(destination)[axis] - placeOfArea(currentArea)[axis]);
57068
+ const moved = goToArea(destination, {
57069
+ forward: towards > 0,
57070
+ event,
57071
+ dx: axis === "x" ? towards : 0,
57072
+ dy: axis === "y" ? towards : 0
57073
+ });
56987
57074
  if (!moved) {
56988
57075
  // Nowhere to go after all — a slide holding on to the user
56989
57076
  // (preventNav), or a caller that refused the change.
56990
57077
  travelFromRef.current = null;
56991
57078
  travelProgressFromRef.current = null;
56992
- returnToRest(drag);
57079
+ settleTowards(drag, currentArea);
56993
57080
  return;
56994
57081
  }
56995
57082
  // A container whose `current` is held outside and was not moved: no
@@ -57000,7 +57087,7 @@ const SlideContainer = ({
57000
57087
  if (travelFromRef.current) {
57001
57088
  travelFromRef.current = null;
57002
57089
  travelProgressFromRef.current = null;
57003
- returnToRest(drag);
57090
+ settleTowards(drag, currentArea);
57004
57091
  }
57005
57092
  });
57006
57093
  },
@@ -57015,9 +57102,15 @@ const SlideContainer = ({
57015
57102
  trackElement: trackCaught,
57016
57103
  offsetOnScreen,
57017
57104
  offsetTarget,
57018
- onScreenPx: caughtOnScreenPx
57105
+ onScreenPx: caughtOnScreenPx,
57106
+ from,
57107
+ to
57019
57108
  } = caughtTravel;
57020
57109
  caughtTravel = null;
57110
+ movingRef.current = {
57111
+ from,
57112
+ to
57113
+ };
57021
57114
  if (offsetOnScreen === offsetTarget) {
57022
57115
  settleTravel();
57023
57116
  return;
@@ -63943,6 +64036,12 @@ const PickerCustom = props => {
63943
64036
  // PickerNative takes.
63944
64037
  pickerProps.resetOnError = true;
63945
64038
  }
64039
+ if (pickerProps.resetOnAbort === undefined) {
64040
+ // Same reasoning for an action the app abandons (an AbortError, e.g. a
64041
+ // verification step the user dismissed): the popup is already closed, so
64042
+ // the abandoned value rolls back instead of staying selected in the list.
64043
+ pickerProps.resetOnAbort = true;
64044
+ }
63946
64045
  // ref
63947
64046
  const popupRef = useRef(null);
63948
64047
  popupProps.ref = popupRef;