@jsenv/navi 0.29.408 → 0.29.409

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.
@@ -12662,12 +12662,13 @@ const useBoundAction = (action, actionParamsSignal) => {
12662
12662
  if (existingNoopAction) {
12663
12663
  return existingNoopAction;
12664
12664
  }
12665
+ // Not bound to the params signal: nothing reads what a noop runs with, and
12666
+ // a proxy following the signal would retarget (a new child action for each
12667
+ // new value) at every change — for every button of a form, at every change
12668
+ // of any of its fields.
12665
12669
  const noopAction = createAction(() => {}, { params: undefined });
12666
- const noopActionBound = actionParamsSignal
12667
- ? noopAction.bindParams(actionParamsSignal)
12668
- : noopAction;
12669
- noopActionRef.current = noopActionBound;
12670
- return noopActionBound;
12670
+ noopActionRef.current = noopAction;
12671
+ return noopAction;
12671
12672
  }
12672
12673
  const isFunction = typeof action === "function";
12673
12674
  if (!isFunction) {
@@ -80989,7 +80990,6 @@ const useWheelInteractions = ({
80989
80990
  attemptInteraction,
80990
80991
  cancelAnim,
80991
80992
  setPos,
80992
- releaseScrub,
80993
80993
  snapPosToRow,
80994
80994
  getItemSize,
80995
80995
  viewportMain,
@@ -81397,8 +81397,6 @@ const useWheelInteractions = ({
81397
81397
  clearTimeout(settleTimer);
81398
81398
  stopClaimingGesture();
81399
81399
  cancelAnim();
81400
- // Nothing is left to settle the scrub in progress.
81401
- releaseScrub();
81402
81400
  document.removeEventListener("pointerdown", onDocumentPointerDown, {
81403
81401
  capture: true
81404
81402
  });
@@ -81564,11 +81562,11 @@ function WheelUI(props) {
81564
81562
  ...props,
81565
81563
  ref: inputRef,
81566
81564
  type: "navi_js",
81567
- // An arrow or a tap changes the value at once while the row glides into
81568
- // place, and the action must wait for the wheel to come to rest. "custom"
81569
- // stops setUIState from auto-firing the action on every value change;
81570
- // commitSelection dispatches it explicitly on settle. A caller can still
81571
- // override actionEvent.
81565
+ // uiAction fires live (every center-crossing, via setPos live reports);
81566
+ // the committed action must fire only when the wheel stabilizes. "custom"
81567
+ // stops setUIState from auto-firing the action on every value change, so
81568
+ // the live reports are uiAction-only; commitSelection then dispatches the
81569
+ // action explicitly on settle. A caller can still override actionEvent.
81572
81570
  actionEvent: props.actionEvent ?? "custom"
81573
81571
  }, {
81574
81572
  controlType: "input"
@@ -81664,11 +81662,6 @@ function WheelUI(props) {
81664
81662
  // while our own scroll-driven selection does not scroll a second time. Holds the
81665
81663
  // TARGET so rapid inputs step from it and accumulate. null = nothing pending.
81666
81664
  const centeredIndexRef = useRef(null);
81667
- // A user scrub moved the wheel onto a row that is not the value yet: set at
81668
- // the first row it crosses, cleared when it settles (commitSelection), when
81669
- // an arrow or a tap sets a value at once (glideToIndex), or when it is
81670
- // dropped (releaseScrub). See setPos.
81671
- const scrubHoldsRowRef = useRef(false);
81672
81665
  // The wheel does NOT use native scroll. `posRef` is our own virtual scroll
81673
81666
  // position (px, main axis); the list track is translated by -pos. This is the
81674
81667
  // single source of truth, wrapped modulo the real-list extent in loop mode, so
@@ -81857,14 +81850,12 @@ function WheelUI(props) {
81857
81850
  posRef.current = clampNumber(posRef.current, 0, (count - 1) * size);
81858
81851
  };
81859
81852
 
81860
- // `live` marks a user scrub (drag, momentum, wheel scroll). A scrub moves the
81861
- // drawing, not the value: the row it reaches is held by the wheel, and only
81862
- // commitSelection turns it into the value, once the motion settles. Reported
81863
- // at each crossing, every notch would be a value change for all that is
81864
- // bound to the wheel — its group, its form, a signal, the address, which
81865
- // records where a value was put down, not the path the finger took
81866
- // (navigation.md, "A value written per frame"). A programmatic move
81867
- // (centerOnIndex) omits `live`: it places the value the wheel already has.
81853
+ // `live` (user scrubs: drag, momentum, wheel scroll) reports the value as each
81854
+ // item crosses the center, so uiAction tracks the wheel in real time — like
81855
+ // every other control. The committed action still fires only once it settles
81856
+ // (commitSelection). A programmatic move (centerOnIndex on an external value
81857
+ // sync) omits it, so scrolling the wheel into place doesn't echo the value
81858
+ // back out.
81868
81859
  const setPos = (vp, pos, {
81869
81860
  live = false
81870
81861
  } = {}) => {
@@ -81875,25 +81866,18 @@ function WheelUI(props) {
81875
81866
  renderPos(vp);
81876
81867
  if (live && interactive) {
81877
81868
  const index = centeredIndex(vp);
81878
- if (index !== centeredIndexRef.current && trackedItemsRef.current[index]) {
81879
- // In step with the scrub so the next arrow or tap steps from the row
81880
- // the wheel is on (see currentTargetIndex).
81881
- centeredIndexRef.current = index;
81882
- scrubHoldsRowRef.current = true;
81869
+ if (index !== centeredIndexRef.current) {
81870
+ const item = trackedItemsRef.current[index];
81871
+ if (item) {
81872
+ // Keep centeredIndexRef in step so the every-render
81873
+ // syncCenterToSelection doesn't read this as an external change and
81874
+ // fight the in-progress motion.
81875
+ centeredIndexRef.current = index;
81876
+ requestSelectValue(item.value, new CustomEvent("navi_wheel_scrub"));
81877
+ }
81883
81878
  }
81884
81879
  }
81885
81880
  };
81886
- // The scrub was dropped before it settled (the wheel stopped being
81887
- // interactive, or its input bindings were torn down): the row it held never
81888
- // became the value. Forgetting it lets the next sync put the wheel back on
81889
- // the value.
81890
- const releaseScrub = () => {
81891
- if (!scrubHoldsRowRef.current) {
81892
- return;
81893
- }
81894
- scrubHoldsRowRef.current = false;
81895
- centeredIndexRef.current = null;
81896
- };
81897
81881
 
81898
81882
  // Returns whether it actually interrupted a motion in flight — lets the caller
81899
81883
  // tell a fresh gesture from one that "caught" a spinning/gliding wheel.
@@ -81929,7 +81913,6 @@ function WheelUI(props) {
81929
81913
  renderPos(vp);
81930
81914
  }
81931
81915
  centeredIndexRef.current = index;
81932
- scrubHoldsRowRef.current = false;
81933
81916
  if (!interactive || glideFromOutsideRef.current) {
81934
81917
  return;
81935
81918
  }
@@ -82127,7 +82110,6 @@ function WheelUI(props) {
82127
82110
  // inputs accumulate.
82128
82111
  const glideToIndex = (vp, index, event) => {
82129
82112
  centeredIndexRef.current = index;
82130
- scrubHoldsRowRef.current = false;
82131
82113
  requestSelectValue(trackedItemsRef.current[index].value, event);
82132
82114
  glideTo(vp, glideTargetFor(vp, index));
82133
82115
  };
@@ -82158,12 +82140,12 @@ function WheelUI(props) {
82158
82140
  // Sync the center with the current value — used on first display and whenever
82159
82141
  // the controlled value changes from outside.
82160
82142
  const syncCenterToSelection = (viewportEl, behavior) => {
82161
- // A fling in flight, or a scrub holding a row, commits on settle: the finger
82162
- // owns the wheel until then, and the row it leaves the wheel on overrules a
82163
- // value arriving meanwhile. A glide is different: its target is re-aimed
82164
- // below (glideTo never restarts the loop), so a value set from outside
82165
- // mid-glide is where the wheel ends up.
82166
- if (momentumRef.current !== null || scrubHoldsRowRef.current) {
82143
+ // A fling in flight reports its own value at every row crossing and commits
82144
+ // on settle: the finger that threw it owns the wheel until then, and a value
82145
+ // arriving meanwhile is re-stated by the next crossing anyway. A glide is
82146
+ // different: its target is re-aimed below (glideTo never restarts the
82147
+ // loop), so a value set from outside mid-glide is where the wheel ends up.
82148
+ if (momentumRef.current !== null) {
82167
82149
  return;
82168
82150
  }
82169
82151
  if (trackedItemsRef.current.length === 0) {
@@ -82246,7 +82228,6 @@ function WheelUI(props) {
82246
82228
  attemptInteraction,
82247
82229
  cancelAnim,
82248
82230
  setPos,
82249
- releaseScrub,
82250
82231
  snapPosToRow,
82251
82232
  getItemSize,
82252
82233
  viewportMain,