@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.
@@ -9248,6 +9248,17 @@ const naviI18nFromValidityMessage = ({ key, params }) => {
9248
9248
  return naviI18n(`constraint.${key}`, params);
9249
9249
  };
9250
9250
 
9251
+ // The characters a ui state holds, for the rules that read a value as text
9252
+ // (length, pattern, number, email…). `undefined` and `null` both hold none:
9253
+ // `String(null)` would hand those rules the four letters "null" — a number
9254
+ // field cleared with `value={null}` then reported "must be a number".
9255
+ const uiStateAsText = (uiState) => {
9256
+ if (uiState === undefined || uiState === null) {
9257
+ return "";
9258
+ }
9259
+ return String(uiState);
9260
+ };
9261
+
9251
9262
  /**
9252
9263
  * https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation
9253
9264
  */
@@ -9314,8 +9325,7 @@ const REQUIRED_CONSTRAINT = {
9314
9325
  return naviI18n("constraint.required.checkbox");
9315
9326
  }
9316
9327
 
9317
- const valueAsString =
9318
- field.uiState === undefined ? "" : String(field.uiState);
9328
+ const valueAsString = uiStateAsText(field.uiState);
9319
9329
  if (valueAsString) {
9320
9330
  return null;
9321
9331
  }
@@ -9366,8 +9376,7 @@ const PATTERN_CONSTRAINT = {
9366
9376
  if (!pattern) {
9367
9377
  return null;
9368
9378
  }
9369
- const valueAsString =
9370
- field.uiState === undefined ? "" : String(field.uiState);
9379
+ const valueAsString = uiStateAsText(field.uiState);
9371
9380
  if (!valueAsString) {
9372
9381
  return null;
9373
9382
  }
@@ -9402,8 +9411,7 @@ const TYPE_EMAIL_CONSTRAINT = {
9402
9411
  if (type !== "email") {
9403
9412
  return null;
9404
9413
  }
9405
- const valueAsString =
9406
- field.uiState === undefined ? "" : String(field.uiState);
9414
+ const valueAsString = uiStateAsText(field.uiState);
9407
9415
  if (!valueAsString) {
9408
9416
  return null;
9409
9417
  }
@@ -9436,8 +9444,7 @@ const MIN_LENGTH_CONSTRAINT = {
9436
9444
  if (minLength === undefined) {
9437
9445
  return null;
9438
9446
  }
9439
- const valueAsString =
9440
- field.uiState === undefined ? "" : String(field.uiState);
9447
+ const valueAsString = uiStateAsText(field.uiState);
9441
9448
  if (!valueAsString && !field.controlHostProps.required) {
9442
9449
  return null;
9443
9450
  }
@@ -9532,8 +9539,7 @@ const MAX_LENGTH_CONSTRAINT = {
9532
9539
  if (maxLength === undefined) {
9533
9540
  return null;
9534
9541
  }
9535
- const valueAsString =
9536
- field.uiState === undefined ? "" : String(field.uiState);
9542
+ const valueAsString = uiStateAsText(field.uiState);
9537
9543
  if (!valueAsString) {
9538
9544
  return null;
9539
9545
  }
@@ -9574,8 +9580,7 @@ const TYPE_NUMBER_CONSTRAINT = {
9574
9580
  if (!isNumberInput(type, naviType)) {
9575
9581
  return null;
9576
9582
  }
9577
- const valueAsString =
9578
- field.uiState === undefined ? "" : String(field.uiState);
9583
+ const valueAsString = uiStateAsText(field.uiState);
9579
9584
  if (!valueAsString) {
9580
9585
  return null;
9581
9586
  }
@@ -9640,8 +9645,7 @@ const MIN_CONSTRAINT = {
9640
9645
  }
9641
9646
  const type = field.controlHostProps.type;
9642
9647
  const naviInputType = field.controlHostProps["navi-input-type"];
9643
- const valueAsString =
9644
- field.uiState === undefined ? "" : String(field.uiState);
9648
+ const valueAsString = uiStateAsText(field.uiState);
9645
9649
  if (!valueAsString) {
9646
9650
  return null;
9647
9651
  }
@@ -9740,8 +9744,7 @@ const MAX_CONSTRAINT = {
9740
9744
  }
9741
9745
  const type = field.controlHostProps.type;
9742
9746
  const naviInputType = field.controlHostProps["navi-input-type"];
9743
- const valueAsString =
9744
- field.uiState === undefined ? "" : String(field.uiState);
9747
+ const valueAsString = uiStateAsText(field.uiState);
9745
9748
  if (!valueAsString) {
9746
9749
  return null;
9747
9750
  }
@@ -9874,8 +9877,7 @@ const STEP_CONSTRAINT = {
9874
9877
  return null;
9875
9878
  }
9876
9879
  const stepString = String(stepRaw);
9877
- const valueAsString =
9878
- field.uiState === undefined ? "" : String(field.uiState);
9880
+ const valueAsString = uiStateAsText(field.uiState);
9879
9881
  if (!valueAsString) {
9880
9882
  return null;
9881
9883
  }
@@ -12824,8 +12826,7 @@ const DISPLAYABLE_CONSTRAINT = {
12824
12826
  if (!isConstraintAttributeOn(displayable)) {
12825
12827
  return null;
12826
12828
  }
12827
- const valueAsString =
12828
- field.uiState === undefined ? "" : String(field.uiState);
12829
+ const valueAsString = uiStateAsText(field.uiState);
12829
12830
  const maxStackedMarksAttribute =
12830
12831
  field.controlHostProps["data-max-stacked-marks"];
12831
12832
  const result = DISPLAYABLE_RULE.applyOn(true, valueAsString, {
@@ -12866,8 +12867,7 @@ const MAX_LINE_BREAKS_CONSTRAINT = {
12866
12867
  if (isNaN(maxLineBreaks)) {
12867
12868
  return null;
12868
12869
  }
12869
- const valueAsString =
12870
- field.uiState === undefined ? "" : String(field.uiState);
12870
+ const valueAsString = uiStateAsText(field.uiState);
12871
12871
  const result = MAX_LINE_BREAKS_RULE.applyOn(maxLineBreaks, valueAsString);
12872
12872
  if (!result) {
12873
12873
  return null;
@@ -12896,8 +12896,7 @@ const NO_EMOJI_CONSTRAINT = {
12896
12896
  if (!isConstraintAttributeOn(noEmoji)) {
12897
12897
  return null;
12898
12898
  }
12899
- const valueAsString =
12900
- field.uiState === undefined ? "" : String(field.uiState);
12899
+ const valueAsString = uiStateAsText(field.uiState);
12901
12900
  const result = NO_EMOJI_RULE.applyOn(true, valueAsString);
12902
12901
  if (!result) {
12903
12902
  return null;
@@ -12911,8 +12910,7 @@ const MIN_LOWER_LETTER_CONSTRAINT = {
12911
12910
  name: "min_lower_letter",
12912
12911
  messageAttribute: "data-min-lower-letter-message",
12913
12912
  check: (field) => {
12914
- const valueAsString =
12915
- field.uiState === undefined ? "" : String(field.uiState);
12913
+ const valueAsString = uiStateAsText(field.uiState);
12916
12914
  const required = field.controlHostProps.required;
12917
12915
  if (!valueAsString && !required) {
12918
12916
  return "";
@@ -12957,8 +12955,7 @@ const MIN_UPPER_LETTER_CONSTRAINT = {
12957
12955
  name: "min_upper_letter",
12958
12956
  messageAttribute: "data-min-upper-letter-message",
12959
12957
  check: (field) => {
12960
- const valueAsString =
12961
- field.uiState === undefined ? "" : String(field.uiState);
12958
+ const valueAsString = uiStateAsText(field.uiState);
12962
12959
  const required = field.controlHostProps.required;
12963
12960
  if (!valueAsString && !required) {
12964
12961
  return null;
@@ -12994,8 +12991,7 @@ const MIN_DIGIT_CONSTRAINT = {
12994
12991
  name: "min_digit",
12995
12992
  messageAttribute: "data-min-digit-message",
12996
12993
  check: (field) => {
12997
- const valueAsString =
12998
- field.uiState === undefined ? "" : String(field.uiState);
12994
+ const valueAsString = uiStateAsText(field.uiState);
12999
12995
  const required = field.controlHostProps.required;
13000
12996
  if (!valueAsString && !required) {
13001
12997
  return null;
@@ -13031,8 +13027,7 @@ const MIN_SPECIAL_CHAR_CONSTRAINT = {
13031
13027
  name: "min_special_char",
13032
13028
  messageAttribute: "data-min-special-char-message",
13033
13029
  check: (field) => {
13034
- const valueAsString =
13035
- field.uiState === undefined ? "" : String(field.uiState);
13030
+ const valueAsString = uiStateAsText(field.uiState);
13036
13031
  const required = field.controlHostProps.required;
13037
13032
  if (!valueAsString && !required) {
13038
13033
  return null;
@@ -13149,8 +13144,7 @@ const SAME_AS_CONSTRAINT = {
13149
13144
  // Reference field is empty — nothing to compare against yet.
13150
13145
  return null;
13151
13146
  }
13152
- const valueAsString =
13153
- field.uiState === undefined ? "" : String(field.uiState);
13147
+ const valueAsString = uiStateAsText(field.uiState);
13154
13148
  if (valueAsString === otherFieldValue) {
13155
13149
  return null;
13156
13150
  }
@@ -13191,8 +13185,7 @@ CONSTRAINT_ATTRIBUTE_SET.add("data-same-as");
13191
13185
 
13192
13186
 
13193
13187
  const applyRule = (field) => {
13194
- const valueAsString =
13195
- field.uiState === undefined ? "" : String(field.uiState);
13188
+ const valueAsString = uiStateAsText(field.uiState);
13196
13189
  return SINGLE_SPACE_RULE.applyOn(true, valueAsString);
13197
13190
  };
13198
13191
 
@@ -37479,9 +37472,9 @@ const getInvalidCharsMessage = (
37479
37472
  uiState,
37480
37473
  { charClass, messageKey, uiStateNow },
37481
37474
  ) => {
37482
- const str = uiState === undefined ? "" : String(uiState);
37475
+ const str = uiStateAsText(uiState);
37483
37476
  if (compileCharClassAnchored(charClass).test(str)) return null;
37484
- const strNow = uiStateNow === undefined ? "" : String(uiStateNow);
37477
+ const strNow = uiStateAsText(uiStateNow);
37485
37478
  if (
37486
37479
  countCharsOutsideClass(str, charClass) <=
37487
37480
  countCharsOutsideClass(strNow, charClass)
@@ -37494,9 +37487,9 @@ const getInvalidCharsMessage = (
37494
37487
  // Paste / set: truncate what the gesture adds beyond the limit.
37495
37488
  const getLengthOverflowResult = (uiState, { maxLength, uiStateNow }) => {
37496
37489
  if (maxLength === undefined) return null;
37497
- const str = uiState === undefined ? "" : String(uiState);
37490
+ const str = uiStateAsText(uiState);
37498
37491
  if (str.length <= maxLength) return null;
37499
- const strNow = uiStateNow === undefined ? "" : String(uiStateNow);
37492
+ const strNow = uiStateAsText(uiStateNow);
37500
37493
  if (str.length <= strNow.length) return null;
37501
37494
  return {
37502
37495
  fixedValue: str.slice(0, maxLength),
@@ -56562,6 +56555,10 @@ const SlideContainer = ({
56562
56555
  // one being travelled TO while the track moves. What the next travel departs
56563
56556
  // from, because it is what one is looking at.
56564
56557
  const drawnAreaRef = useRef(undefined);
56558
+ // The movement the track is playing, while it plays: the slide it is leaving
56559
+ // and the slide it is going to. A hand landing on the box takes it over from
56560
+ // its origin (see onStart in createTravelHandlers).
56561
+ const movingRef = useRef(null);
56565
56562
  // Which way the travel about to be drawn goes, when whatever asked for it
56566
56563
  // knows: a window stepping off its last slide comes back on its first, and
56567
56564
  // only the press says that is a step forward — the map, read between those
@@ -56830,6 +56827,7 @@ const SlideContainer = ({
56830
56827
  }
56831
56828
  stageRef.current = null;
56832
56829
  trackAnimationRef.current = null;
56830
+ movingRef.current = null;
56833
56831
  // At rest the picture IS the current slide, whatever the last gesture wrote
56834
56832
  // there: an indicator has nothing left to lean towards.
56835
56833
  paintTravelProgress(0);
@@ -57024,7 +57022,7 @@ const SlideContainer = ({
57024
57022
  // there, and when it is over this is what holds. Except under a hand-off
57025
57023
  // still waiting for its travel: the track stays where the finger left it,
57026
57024
  // until the render that moves it or the frame after which the gesture gives
57027
- // up on it (see returnToRest in onEnd).
57025
+ // up on it (see settleTowards in onEnd).
57028
57026
  if (!travelFromRef.current) {
57029
57027
  track.style.setProperty("--slide-container-offset", offset);
57030
57028
  }
@@ -57059,6 +57057,10 @@ const SlideContainer = ({
57059
57057
  duration: durationMs * travelRatio,
57060
57058
  easing
57061
57059
  });
57060
+ movingRef.current = {
57061
+ from: drawnArea,
57062
+ to: currentArea
57063
+ };
57062
57064
  // The trait travels with the slides: from where the gesture left it when
57063
57065
  // there was one, from a whole box away when the travel was asked for.
57064
57066
  const progressFrom = travelProgressFromRef.current ?? (travelStep ? travelStep.x || travelStep.y : 0);
@@ -57844,7 +57846,7 @@ const SlideContainer = ({
57844
57846
  // The two slides the gesture can bring in, placed one box either side of the
57845
57847
  // one being dragged — the same stage a travel builds, except that both ends
57846
57848
  // are set up at once because the finger has not said yet which way it goes.
57847
- const stageDrag = drag => {
57849
+ const stageDrag = (drag, currentArea) => {
57848
57850
  const {
57849
57851
  slideElements,
57850
57852
  placeOf
@@ -57872,7 +57874,7 @@ const SlideContainer = ({
57872
57874
  }
57873
57875
  stageRef.current = {
57874
57876
  placeByArea,
57875
- area: drag.area
57877
+ area: currentArea
57876
57878
  };
57877
57879
  for (const slideElement of slideElements) {
57878
57880
  const area = readArea(slideElement);
@@ -57888,33 +57890,63 @@ const SlideContainer = ({
57888
57890
  }
57889
57891
  };
57890
57892
 
57891
- // Let go of without enough of a gesture to travel: the slide comes back to
57892
- // where it was, over the distance it was pulled so a slide barely moved
57893
- // snaps back and one dragged most of the way there takes its time.
57894
- const returnToRest = drag => {
57893
+ // Let go of, and the slides go where the gesture leaves them: back on the
57894
+ // slide being dragged when nothing travels, on to the slide arriving when a
57895
+ // travel caught in flight is let carry on. Over the distance left to cover,
57896
+ // so a slide barely moved snaps back and one dragged most of the way there
57897
+ // takes its time.
57898
+ const settleTowards = (drag, area) => {
57895
57899
  const track = trackRef.current;
57896
57900
  if (!track) {
57897
57901
  return;
57898
57902
  }
57899
- const restOffset = `${drag.baseOffset.x}px ${drag.baseOffset.y}px`;
57903
+ const stage = stageRef.current;
57904
+ const {
57905
+ placeOf
57906
+ } = readMap();
57907
+ const place = stage?.placeByArea.get(area) || placeOf.get(area) || {
57908
+ x: 0,
57909
+ y: 0
57910
+ };
57911
+ const restPx = {
57912
+ x: -place.x * drag.box.width,
57913
+ y: -place.y * drag.box.height
57914
+ };
57915
+ const nowPx = {
57916
+ x: drag.baseOffset.x + drag.pull.x,
57917
+ y: drag.baseOffset.y + drag.pull.y
57918
+ };
57919
+ const restOffset = `${restPx.x}px ${restPx.y}px`;
57900
57920
  const durationMs = durationToMs(duration);
57901
- const pulled = Math.abs(drag.pull[drag.axis]);
57902
57921
  const size = drag.axis === "x" ? drag.box.width : drag.box.height;
57922
+ const left = Math.abs(restPx[drag.axis] - nowPx[drag.axis]);
57903
57923
  trackAnimationRef.current?.cancel();
57904
57924
  trackAnimationRef.current = null;
57905
57925
  track.style.setProperty("--slide-container-offset", restOffset);
57906
- if (!durationMs || !pulled) {
57926
+ if (!durationMs || !left) {
57907
57927
  paintTravelProgress(0);
57908
57928
  settleTravel();
57909
57929
  return;
57910
57930
  }
57911
- animateTravelProgress(drag.progress, durationMs * (pulled / size), "ease-out", drag.areaPulled);
57931
+ // Which other slide the picture leans on while it arrives: the one being
57932
+ // pulled in when it comes back on the dragged slide, the dragged slide
57933
+ // itself when it goes on to the one arriving — and the trait is then a
57934
+ // box short of that one, which is what it has to close.
57935
+ const arrivesOnBase = area === drag.area;
57936
+ const sign = drag.pull[drag.axis] > 0 ? 1 : -1;
57937
+ const progressFrom = arrivesOnBase ? drag.progress : drag.progress - sign;
57938
+ const otherArea = arrivesOnBase ? drag.areaPulled : drag.area;
57939
+ movingRef.current = {
57940
+ from: otherArea,
57941
+ to: area
57942
+ };
57943
+ animateTravelProgress(progressFrom, durationMs * (left / size), "ease-out", otherArea);
57912
57944
  const animation = track.animate([{
57913
- translate: drag.offset
57945
+ translate: `${nowPx.x}px ${nowPx.y}px`
57914
57946
  }, {
57915
57947
  translate: restOffset
57916
57948
  }], {
57917
- duration: durationMs * (pulled / size),
57949
+ duration: durationMs * (left / size),
57918
57950
  easing: "ease-out"
57919
57951
  });
57920
57952
  trackAnimationRef.current = animation;
@@ -57945,11 +57977,14 @@ const SlideContainer = ({
57945
57977
  // value underneath it, which is the far end of the travel — the very jump
57946
57978
  // this is about.
57947
57979
  trackElement.style.setProperty("--slide-container-offset", offsetOnScreen);
57980
+ const moving = movingRef.current || {};
57948
57981
  return {
57949
57982
  trackElement,
57950
57983
  onScreenPx,
57951
57984
  offsetOnScreen,
57952
- offsetTarget: offsetRef.current
57985
+ offsetTarget: offsetRef.current,
57986
+ from: moving.from,
57987
+ to: moving.to
57953
57988
  };
57954
57989
  };
57955
57990
  // Which way a caught travel was going: a hand reaching for something moving
@@ -57996,8 +58031,6 @@ const SlideContainer = ({
57996
58031
  sign,
57997
58032
  target
57998
58033
  }) => {
57999
- let areaBack = axis === "x" ? areaTowards(-1, 0) : areaTowards(0, -1);
58000
- let areaOn = axis === "x" ? areaTowards(1, 0) : areaTowards(0, 1);
58001
58034
  // Everything positional is read HERE rather than when the pointer
58002
58035
  // landed: the travel that was playing then may have arrived since, and
58003
58036
  // it is what the slides are doing at the moment the gesture takes them
@@ -58008,39 +58041,66 @@ const SlideContainer = ({
58008
58041
  placeOf
58009
58042
  } = readMap();
58010
58043
  const currentElement = slideElements.find(slideElement => slideElement.hasAttribute("data-current")) || slideElements[0];
58011
- // The hold goToArea reads at the release, read again HERE, off the same
58012
- // slide and the same attribute: a slide that will refuse the arrival
58013
- // must not offer the journey. A locked direction simply has nowhere to
58014
- // go for the length of this gesture — the one case the gesture already
58015
- // knows, being the last slide of a walk. The hand then gets the wall it
58016
- // can lean on and never walk through (see drag_to_travel), the slide
58017
- // behind it stays offstage instead of being read on the way, and the
58018
- // release has nothing left to refuse.
58019
- // Nothing here about `released` (--navi-done): that is one particular
58020
- // departure letting go, decided as it happens, and a gesture armed
58021
- // before it has no such thing to read — the attribute as rendered is
58022
- // what the hand is answered from.
58023
- if (currentElement?.hasAttribute("data-prevent-nav-previous")) {
58024
- areaBack = undefined;
58025
- }
58026
- if (currentElement?.hasAttribute("data-prevent-nav-next")) {
58027
- areaOn = undefined;
58028
- }
58029
58044
  const box = track.getBoundingClientRect();
58030
- if (!areaBack && !areaOn || !currentElement || !box.width || !box.height ||
58031
- // Something else with a better claim on the gesture: a scroller
58032
- // between the finger and the slide, with room left that way.
58033
- scrollRoomTowards(target, currentElement, axis, sign)) {
58045
+ if (!currentElement || !box.width || !box.height) {
58034
58046
  return false;
58035
58047
  }
58036
- const area = readArea(currentElement);
58037
- // Where the slide being dragged stands: where the stage put it while a
58038
- // travel is playing, its place on the map otherwise.
58048
+ const currentArea = readArea(currentElement);
58039
58049
  const stage = stageRef.current;
58040
- const basePlace = stage?.placeByArea.get(area) || placeOf.get(area) || {
58050
+ // Where a slide stands: where the stage put it while a travel is
58051
+ // playing, its place on the map otherwise.
58052
+ const placeOfArea = someArea => stage?.placeByArea.get(someArea) || placeOf.get(someArea) || {
58041
58053
  x: 0,
58042
58054
  y: 0
58043
58055
  };
58056
+ // A travel caught in flight is measured from the slide it SET OFF from,
58057
+ // with the slide it was going to as the one thing the hand can bring
58058
+ // in — the way drag_to_travel reads a `slack`: how far the box already
58059
+ // sits from its resting place, towards what is being pulled in. That is
58060
+ // what makes its answer "carry on" mean arriving. Based on the slide
58061
+ // arriving instead, the slack would point back at the origin, and a
58062
+ // hand that merely touched the box would send it all the way back.
58063
+ // A movement with no origin of its own (the track re-placed without a
58064
+ // travel) is dragged from the slide shown, like any slide at rest.
58065
+ const origin = caughtTravel && caughtTravel.from !== caughtTravel.to ? caughtTravel.from : null;
58066
+ let area;
58067
+ let areaBack;
58068
+ let areaOn;
58069
+ if (origin) {
58070
+ area = origin;
58071
+ const towardsEnd = axis === "x" ? placeOfArea(currentArea).x > placeOfArea(origin).x : placeOfArea(currentArea).y > placeOfArea(origin).y;
58072
+ areaBack = towardsEnd ? undefined : currentArea;
58073
+ areaOn = towardsEnd ? currentArea : undefined;
58074
+ } else {
58075
+ area = currentArea;
58076
+ areaBack = axis === "x" ? areaTowards(-1, 0) : areaTowards(0, -1);
58077
+ areaOn = axis === "x" ? areaTowards(1, 0) : areaTowards(0, 1);
58078
+ // The hold goToArea reads at the release, read again HERE, off the
58079
+ // same slide and the same attribute: a slide that will refuse the
58080
+ // arrival must not offer the journey. A locked direction simply has
58081
+ // nowhere to go for the length of this gesture — the one case the
58082
+ // gesture already knows, being the last slide of a walk. The hand
58083
+ // then gets the wall it can lean on and never walk through (see
58084
+ // drag_to_travel), the slide behind it stays offstage instead of
58085
+ // being read on the way, and the release has nothing left to refuse.
58086
+ // Nothing here about `released` (--navi-done): that is one particular
58087
+ // departure letting go, decided as it happens, and a gesture armed
58088
+ // before it has no such thing to read — the attribute as rendered is
58089
+ // what the hand is answered from.
58090
+ if (currentElement.hasAttribute("data-prevent-nav-previous")) {
58091
+ areaBack = undefined;
58092
+ }
58093
+ if (currentElement.hasAttribute("data-prevent-nav-next")) {
58094
+ areaOn = undefined;
58095
+ }
58096
+ if (!areaBack && !areaOn ||
58097
+ // Something else with a better claim on the gesture: a scroller
58098
+ // between the finger and the slide, with room left that way.
58099
+ scrollRoomTowards(target, currentElement, axis, sign)) {
58100
+ return false;
58101
+ }
58102
+ }
58103
+ const basePlace = placeOfArea(area);
58044
58104
  const baseOffset = {
58045
58105
  x: -basePlace.x * box.width,
58046
58106
  y: -basePlace.y * box.height
@@ -58071,7 +58131,8 @@ const SlideContainer = ({
58071
58131
  [axis]: slack
58072
58132
  };
58073
58133
  drag.progress = slack / size;
58074
- stageDrag(drag);
58134
+ drag.areaPulled = slack > 0 ? areaBack : slack < 0 ? areaOn : null;
58135
+ stageDrag(drag, currentArea);
58075
58136
  // From here the box is busy, whichever input asked: a wheel gesture and
58076
58137
  // a press must not both be moving the same track.
58077
58138
  dragRef.current = drag;
@@ -58102,24 +58163,50 @@ const SlideContainer = ({
58102
58163
  event
58103
58164
  }) => {
58104
58165
  dragRef.current = null;
58105
- if (!travels) {
58106
- returnToRest(drag);
58166
+ // Where the gesture leaves the slides: on the one it was pulling in
58167
+ // when it says so, back on the one it was dragging otherwise.
58168
+ const destination = travels ? sign > 0 ? drag.areaBack : drag.areaOn : drag.area;
58169
+ const {
58170
+ slideElements,
58171
+ placeOf
58172
+ } = readMap();
58173
+ const currentElement = slideElements.find(slideElement => slideElement.hasAttribute("data-current")) || slideElements[0];
58174
+ const currentArea = currentElement && readArea(currentElement);
58175
+ if (!destination || destination === currentArea) {
58176
+ // Nothing to ask of the state: the slide it names is already the one
58177
+ // shown — a drag let go of short of a travel, a travel caught in
58178
+ // flight and let carry on. The track goes there on its own.
58179
+ settleTowards(drag, destination || drag.area);
58107
58180
  return;
58108
58181
  }
58109
58182
  // Where the slide is being left, for the travel to depart from instead
58110
58183
  // of from the map.
58111
58184
  travelFromRef.current = drag.offset;
58112
58185
  // …and where the indicator is being left, said about the slide that is
58113
- // ARRIVING: the picture is `sign` of a box short of it, and that is
58114
- // what the travel about to be drawn has to close.
58115
- travelProgressFromRef.current = drag.progress - sign;
58116
- const moved = axis === "x" ? move(-sign, 0, event) : move(0, -sign, event);
58186
+ // ARRIVING: a box short of the slide being pulled in, right where the
58187
+ // finger left it when going back to the slide being dragged.
58188
+ travelProgressFromRef.current = travels ? drag.progress - sign : drag.progress;
58189
+ // Which way the travel goes, read off where the two slides stand
58190
+ // rather than off the pull: a travel caught in flight and put back
58191
+ // goes the way it came, whatever the finger did meanwhile.
58192
+ const stage = stageRef.current;
58193
+ const placeOfArea = someArea => stage?.placeByArea.get(someArea) || placeOf.get(someArea) || {
58194
+ x: 0,
58195
+ y: 0
58196
+ };
58197
+ const towards = Math.sign(placeOfArea(destination)[axis] - placeOfArea(currentArea)[axis]);
58198
+ const moved = goToArea(destination, {
58199
+ forward: towards > 0,
58200
+ event,
58201
+ dx: axis === "x" ? towards : 0,
58202
+ dy: axis === "y" ? towards : 0
58203
+ });
58117
58204
  if (!moved) {
58118
58205
  // Nowhere to go after all — a slide holding on to the user
58119
58206
  // (preventNav), or a caller that refused the change.
58120
58207
  travelFromRef.current = null;
58121
58208
  travelProgressFromRef.current = null;
58122
- returnToRest(drag);
58209
+ settleTowards(drag, currentArea);
58123
58210
  return;
58124
58211
  }
58125
58212
  // A container whose `current` is held outside and was not moved: no
@@ -58130,7 +58217,7 @@ const SlideContainer = ({
58130
58217
  if (travelFromRef.current) {
58131
58218
  travelFromRef.current = null;
58132
58219
  travelProgressFromRef.current = null;
58133
- returnToRest(drag);
58220
+ settleTowards(drag, currentArea);
58134
58221
  }
58135
58222
  });
58136
58223
  },
@@ -58145,9 +58232,15 @@ const SlideContainer = ({
58145
58232
  trackElement: trackCaught,
58146
58233
  offsetOnScreen,
58147
58234
  offsetTarget,
58148
- onScreenPx: caughtOnScreenPx
58235
+ onScreenPx: caughtOnScreenPx,
58236
+ from,
58237
+ to
58149
58238
  } = caughtTravel;
58150
58239
  caughtTravel = null;
58240
+ movingRef.current = {
58241
+ from,
58242
+ to
58243
+ };
58151
58244
  if (offsetOnScreen === offsetTarget) {
58152
58245
  settleTravel();
58153
58246
  return;
@@ -65237,6 +65330,12 @@ const PickerCustom = props => {
65237
65330
  // PickerNative takes.
65238
65331
  pickerProps.resetOnError = true;
65239
65332
  }
65333
+ if (pickerProps.resetOnAbort === undefined) {
65334
+ // Same reasoning for an action the app abandons (an AbortError, e.g. a
65335
+ // verification step the user dismissed): the popup is already closed, so
65336
+ // the abandoned value rolls back instead of staying selected in the list.
65337
+ pickerProps.resetOnAbort = true;
65338
+ }
65240
65339
  // ref
65241
65340
  const popupRef = useRef(null);
65242
65341
  popupProps.ref = popupRef;