@jsenv/navi 0.29.166 → 0.29.167

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.
@@ -17635,7 +17635,9 @@ const useActionAsyncData = (action, {
17635
17635
  onLoad
17636
17636
  }) => {
17637
17637
  const loadingRef = useContext(LoadingContext);
17638
- if (!loadingRef) {
17638
+ // The boundary is where a suspension lands, so only the delegating path needs
17639
+ // one: `loading: true` draws the wait itself and never suspends.
17640
+ if (!loadingRef && loadingEffect !== "use") {
17639
17641
  throw new Error(`Missing <Loading>: useAsyncData delegates the wait, so it needs a <Loading> boundary above it — or "loading: true" to draw that wait here.`);
17640
17642
  }
17641
17643
  useOnLoad(action, onLoad);
@@ -17719,15 +17721,19 @@ const useActionAsyncData = (action, {
17719
17721
  }
17720
17722
  if (runningState === FAILED) {
17721
17723
  if (dismissedActionWeakSet.has(action)) {
17724
+ // Dismissing removes the error and nothing else: what is handed back is
17725
+ // the action's state without it — the data it holds, and no run in
17726
+ // progress. Holding nothing is one of those states, not a wait, so a
17727
+ // component drawing its own states gets it rather than being suspended
17728
+ // away from the retry it is offering.
17722
17729
  const staleData = action.dataSignal.peek();
17723
- if (staleData !== undefined) {
17724
- // Dismissed with stale data — return it so children render normally
17730
+ if (staleData !== undefined || loadingEffect === "use") {
17725
17731
  return [staleData, false, undefined];
17726
17732
  }
17727
- // Dismissed with no data — suspend until the action re-runs.
17728
- // A never-resolving promise would leave the component stuck forever,
17729
- // so we use an action-specific promise that resolves on RUNNING,
17730
- // which lets the component re-render and go through the normal loading path.
17733
+ // Nothing to hand over and the waits are delegated: there is no state
17734
+ // this component can draw, so it waits. The promise resolves on RUNNING
17735
+ // rather than never, so a run started from anywhere brings it back
17736
+ // through the ordinary loading path instead of leaving it stuck.
17731
17737
  let dismissedPromise = dismissedActionPendingPromiseWeakMap.get(action);
17732
17738
  if (!dismissedPromise) {
17733
17739
  dismissedPromise = new Promise(resolve => {
@@ -17756,7 +17762,10 @@ const useActionAsyncData = (action, {
17756
17762
  dismissedActionWeakSet.add(action);
17757
17763
  setTick(n => n + 1);
17758
17764
  };
17759
- return [undefined, false, actionError, dismissError];
17765
+ // The previous answer is still there and a failed refresh does not unmake
17766
+ // it, so both are handed over: the component can say the failure over the
17767
+ // content it already has instead of choosing between the two.
17768
+ return [action.dataSignal.peek(), false, actionError, dismissError];
17760
17769
  }
17761
17770
  // Not marked: nothing is displayed yet — the boundary that catches this is
17762
17771
  // what says so, and only if it has something to show.
@@ -39522,8 +39531,19 @@ const TextAnchor = ({
39522
39531
  // which reads as the child "jumping" even though nothing about its own
39523
39532
  // geometry changed. useDisplayedLayoutEffect skips the initial run in
39524
39533
  // that case and reruns once the ancestor actually opens instead.
39525
- useDisplayedLayoutEffect(anchorRef, anchorEl => {
39526
- const childEl = childRef.current;
39534
+ //
39535
+ // It is asked about the CHILD, not about the anchor: the anchor is this
39536
+ // effect's own measuring device, displayed or not according to what the
39537
+ // effect last decided (see the hidden attribute below), so asking whether
39538
+ // it is on screen answers with that decision rather than with a fact about
39539
+ // the screen. On the façade of something closed — an icon in a picker's
39540
+ // trigger, where the openable ancestor is the picker itself — that answer
39541
+ // is "hidden", the correction waits for the popup to open, and the icon
39542
+ // jumps half a pixel on the first click. The child is what is being
39543
+ // positioned, and it is on screen exactly when the correction means
39544
+ // something.
39545
+ useDisplayedLayoutEffect(childRef, childEl => {
39546
+ const anchorEl = anchorRef.current;
39527
39547
  if (!anchorEl || !childEl) {
39528
39548
  return;
39529
39549
  }