@jsenv/navi 0.29.429 → 0.29.431

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.
@@ -7107,6 +7107,55 @@ const applyNavigationToNavDepth = (navigationType, state) => {
7107
7107
  canNavForwardSignal.value = navDepth < navDepthMax;
7108
7108
  };
7109
7109
 
7110
+ /**
7111
+ * Whether the render running now is the one putting a new page on screen.
7112
+ *
7113
+ * A layer drawn over the pages — a popup bound to the address, the slides
7114
+ * inside it — can open, close or change place in the very navigation that
7115
+ * replaces the page beneath it: a link inside the layer leads to another page
7116
+ * and the layer's weak params are dropped, a back to the page it was open over
7117
+ * brings them back. For the layer that is not a movement of its own: the page
7118
+ * changing IS the movement. A route transition already carries it, photographed
7119
+ * as furniture with the page it belongs to (transition_furniture.js), and with
7120
+ * no transition the page cuts and the layer cuts with it. Played on its own as
7121
+ * well, it moves twice — an entrance or an exit over a page sliding past, or
7122
+ * appearing at once.
7123
+ *
7124
+ * So whatever reacts to such a change in a render — a popup's open state, a
7125
+ * slide container's current slide — asks here whether that render carries a
7126
+ * page change, and if so arrives where it goes without travelling there.
7127
+ *
7128
+ * A page is what navi animates between (route_page.js): a route, and the
7129
+ * params telling apart branches of one route. Which routes match is decided by
7130
+ * the path alone, so a navigation that changes the path changes the page; one
7131
+ * that keeps it changes the page only where a param IS a page — and navi knows
7132
+ * those only through the relation or the RouteTravel row that names them, so
7133
+ * that is who says so. A search param a page merely reads is not one: writing
7134
+ * it is the page answering, and a layer opened by it (the `?settings` its door
7135
+ * pushes, the back button taking it out) moves on its own.
7136
+ *
7137
+ * The answer lasts until the render applying the navigation is over: the held
7138
+ * one when somebody photographs the change, Preact's own otherwise, over by the
7139
+ * next frame (see whenPageRendered). Asked from a layout effect it is exact; an
7140
+ * opening deferred past the commit takes the answer with it, read when the
7141
+ * effect ran.
7142
+ */
7143
+
7144
+
7145
+ let renderingPageChange = false;
7146
+
7147
+ const notePageChange = () => {
7148
+ if (renderingPageChange) {
7149
+ return;
7150
+ }
7151
+ renderingPageChange = true;
7152
+ whenPageRendered(() => {
7153
+ renderingPageChange = false;
7154
+ });
7155
+ };
7156
+
7157
+ const isRenderingPageChange = () => renderingPageChange;
7158
+
7110
7159
  // Global signal registry for route template detection
7111
7160
  const globalSignalRegistry = new Map();
7112
7161
 
@@ -10742,8 +10791,12 @@ This prevents cross-test pollution and ensures clean state.`,
10742
10791
  // read again.
10743
10792
  const path = urlWithoutSearchAndHash(url);
10744
10793
  const pathKept = path === previousPath;
10794
+ // A new path is a new page: what the integration tells whatever reacts to
10795
+ // this change in the render it causes (see page_change.js). Not the first
10796
+ // one — there was no page before it, and what it mounts mounts as it is.
10797
+ const pageChanged = previousPath !== null && !pathKept;
10745
10798
  previousPath = path;
10746
- const returnValue = {};
10799
+ const returnValue = { pageChanged };
10747
10800
  const routeMatchInfoSet = new Set();
10748
10801
  for (const route of routeSet) {
10749
10802
  const routePrivateProperties = getRoutePrivateProperties(route);
@@ -12629,11 +12682,14 @@ const applyRouting = (
12629
12682
  // The routes' actions follow the address by themselves (see routeAction):
12630
12683
  // what a navigation leaves to the routing is a reload, the one that asks
12631
12684
  // them again with the address unchanged.
12632
- const { reloadSet } = updateRoutes(url, {
12685
+ const { pageChanged, reloadSet } = updateRoutes(url, {
12633
12686
  navigationType,
12634
12687
  isVisited,
12635
12688
  // state,
12636
12689
  });
12690
+ if (pageChanged) {
12691
+ notePageChange();
12692
+ }
12637
12693
  if (!reloadSet || reloadSet.size === 0) {
12638
12694
  return {
12639
12695
  allResult: undefined,
@@ -16104,8 +16160,8 @@ const useOpenPropsEffectOnOpenController = (
16104
16160
  // Tracks whether the effect below has ever run before — only the very
16105
16161
  // first run gets the "mount already open" treatment (`open` truthy from
16106
16162
  // the start, or the uncontrolled, mount-only `defaultOpen`); every
16107
- // subsequent `open` change is a real, later toggle and should animate
16108
- // normally like any other interactive open/close.
16163
+ // subsequent `open` change is a real, later toggle and animates like any
16164
+ // interactive open/close — unless a page change carries it (see below).
16109
16165
  const isFirstRunRef = useRef(true);
16110
16166
  // What `open` was on the previous run of the effect below. preact re-runs
16111
16167
  // an effect for a change of its deps — or for none at all, when a
@@ -16125,6 +16181,12 @@ const useOpenPropsEffectOnOpenController = (
16125
16181
  isFirstRunRef.current = false;
16126
16182
  const openChanged = open !== lastRunOpenRef.current;
16127
16183
  lastRunOpenRef.current = open;
16184
+ // Opened or closed by the navigation that puts another page on screen: a
16185
+ // link inside the popup leading away, a back to the page it stood over.
16186
+ // The page changing is its movement, so it has none of its own — a route
16187
+ // transition carries it with its page, and without one it cuts with the
16188
+ // page (see page_change.js).
16189
+ const carriedByPageChange = isRenderingPageChange();
16128
16190
 
16129
16191
  if (isFirstRun) {
16130
16192
  // "interaction" is said even over what the caller holds reading open: a
@@ -16143,10 +16205,12 @@ const useOpenPropsEffectOnOpenController = (
16143
16205
  // other truthy value means it was simply already open: nothing was ever
16144
16206
  // shown as "closed" for the user to see it transition away from, so the
16145
16207
  // entrance is skipped (`silent`, see popover.jsx's own openEffect).
16146
- //
16208
+ // A popup built by an opening a page change carries is silent too,
16209
+ // whatever built it: read now, the answer only holds for this render.
16210
+ const silent = mountOpenReason !== "interaction" || carriedByPageChange;
16147
16211
  mountOpenOwedRef.current = () =>
16148
16212
  openController.open(new CustomEvent("open_by_prop", { detail: {} }), {
16149
- silent: mountOpenReason !== "interaction",
16213
+ silent,
16150
16214
  });
16151
16215
  }
16152
16216
  return undefined;
@@ -16178,11 +16242,13 @@ const useOpenPropsEffectOnOpenController = (
16178
16242
  });
16179
16243
  return undefined;
16180
16244
  }
16181
- openController.open(new CustomEvent("open_by_prop", { detail: {} }));
16245
+ openController.open(new CustomEvent("open_by_prop", { detail: {} }), {
16246
+ silent: carriedByPageChange,
16247
+ });
16182
16248
  } else {
16183
16249
  openController.requestClose(
16184
16250
  new CustomEvent("close_by_prop", { detail: {} }),
16185
- { isCancel: true },
16251
+ { isCancel: true, silent: carriedByPageChange },
16186
16252
  );
16187
16253
  }
16188
16254
  // The request can be refused (a busy form denying the close): the popup
@@ -30911,14 +30977,14 @@ import.meta.css = /* css */[`[data-scrollable] > .navi_loading_outline_wrapper,
30911
30977
  }
30912
30978
 
30913
30979
  [data-scrollable] {
30914
- overflow: var(--x-scrollable-overflow, auto);
30915
30980
  scroll-padding: var(--navi-scroll-padding, var(--navi-s));
30916
30981
  --box-header-z-index: var(--navi-z-index-sticky);
30917
30982
  --box-footer-z-index: var(--navi-z-index-sticky);
30918
30983
  isolation: isolate;
30984
+ overflow: auto;
30919
30985
 
30920
30986
  &[data-scrollable-overflow="scroll"] {
30921
- --x-scrollable-overflow: scroll;
30987
+ overflow: scroll;
30922
30988
  }
30923
30989
 
30924
30990
  & > [data-header] {
@@ -30940,9 +31006,9 @@ import.meta.css = /* css */[`[data-scrollable] > .navi_loading_outline_wrapper,
30940
31006
  }
30941
31007
 
30942
31008
  &:has( > [data-body]) {
30943
- --x-scrollable-overflow: hidden;
30944
31009
  flex-direction: column;
30945
31010
  display: flex;
31011
+ overflow: hidden;
30946
31012
 
30947
31013
  & > [data-header], & > [data-footer] {
30948
31014
  z-index: auto;
@@ -36173,6 +36239,9 @@ const rebuildWatcher = () => {
36173
36239
  if (fromIndex === index) {
36174
36240
  return;
36175
36241
  }
36242
+ // A page of a relation can be a param: a move between two of them is a
36243
+ // page change the path does not show (see page_change.js).
36244
+ notePageChange();
36176
36245
  if (navigationAnimated) {
36177
36246
  // The movement on screen was turned round for this very navigation (see
36178
36247
  // turnRunningTransitionRound): it is already being answered, by the
@@ -37537,6 +37606,10 @@ const RouteTravel = ({
37537
37606
  }
37538
37607
  return;
37539
37608
  }
37609
+ // Whoever asked for it: a tab of this row can be a param, and a move
37610
+ // between two of them is a page change the path does not show (see
37611
+ // page_change.js).
37612
+ notePageChange();
37540
37613
  const page = pages[index];
37541
37614
  // A page this box asked for itself — a travel's own navigation, or one
37542
37615
  // it had given up waiting on: what arrives here is the answer to a
@@ -54254,11 +54327,13 @@ const Expandable = props => {
54254
54327
  openController.openEffect = openEvent => {
54255
54328
  const contentContainer = contentContainerRef.current;
54256
54329
  // `silent`: the expandable was already open when the page appeared
54257
- // (`open`/`defaultOpen` at mount). Nothing changed for anyone to be told
54258
- // about, nothing was ever shown closed to move away from, and a page must
54259
- // not have its focus stolen by a section that was simply already open — so
54260
- // an opening that was never an opening plays nothing, says nothing and
54261
- // takes nothing. The action it carries still runs: its content is due.
54330
+ // (`open`/`defaultOpen` at mount, or the navigation putting that page on
54331
+ // screen opening it — see page_change.js). Nothing changed for anyone to
54332
+ // be told about, nothing was ever shown closed to move away from, and a
54333
+ // page must not have its focus stolen by a section that was simply
54334
+ // already open — so an opening that was never an opening plays nothing,
54335
+ // says nothing and takes nothing. The action it carries still runs: its
54336
+ // content is due.
54262
54337
  const silent = Boolean(openEvent.detail.silent);
54263
54338
  const revealing = animation && !silent && Boolean(contentContainer);
54264
54339
  // Where the last paint left the track — 0 when fully closed, partway when
@@ -54305,7 +54380,9 @@ const Expandable = props => {
54305
54380
  effectiveAction.abort();
54306
54381
  }
54307
54382
  cancelSettleWatch();
54308
- const collapsing = animation && Boolean(contentContainerAtClose);
54383
+ // `silent`: closed by the navigation that puts another page on screen,
54384
+ // which is its movement (see page_change.js).
54385
+ const collapsing = animation && !closeEvent.detail.silent && Boolean(contentContainerAtClose);
54309
54386
  if (collapsing) {
54310
54387
  // Now, while the content is still fully laid out — the collapsing
54311
54388
  // track uncovers a content frozen at that size.
@@ -61661,10 +61738,23 @@ const SlideContainer = ({
61661
61738
  y: 0
61662
61739
  };
61663
61740
  const durationMs = durationToMs(duration);
61741
+ // A change of slide the page changing carries is no travel: the page is
61742
+ // the movement, and the slides land where the address puts them (see
61743
+ // page_change.js). A travel still playing is cut on the spot, and the
61744
+ // indicator riding it with it.
61745
+ const landsWithPage = isRenderingPageChange() && (stageRef.current ? stageRef.current.area : drawnAreaRef.current) !== currentArea;
61746
+ if (landsWithPage && trackAnimationRef.current) {
61747
+ trackAnimationRef.current.cancel();
61748
+ trackAnimationRef.current = null;
61749
+ movingRef.current = null;
61750
+ cancelTravelProgressAnimation();
61751
+ paintTravelProgress(0);
61752
+ }
61753
+ const still = noTravel || landsWithPage;
61664
61754
  // Nothing is travelling, so nothing is staged: the picture to paint is the
61665
61755
  // map itself, and a stage left over from a travel that has just been given
61666
61756
  // up on would be painted instead of it.
61667
- if (noTravel) {
61757
+ if (still) {
61668
61758
  stageRef.current = null;
61669
61759
  }
61670
61760
  let stage = stageRef.current;
@@ -61672,7 +61762,7 @@ const SlideContainer = ({
61672
61762
  // between the picture and the slide arriving, on the axis it walks.
61673
61763
  let travelStep = null;
61674
61764
  const drawnArea = stage ? stage.area : drawnAreaRef.current;
61675
- const travelStarts = !noTravel && durationMs > 0 && drawnArea !== undefined && drawnArea !== currentArea && slideElements.some(slideElement => readArea(slideElement) === drawnArea);
61765
+ const travelStarts = !still && durationMs > 0 && drawnArea !== undefined && drawnArea !== currentArea && slideElements.some(slideElement => readArea(slideElement) === drawnArea);
61676
61766
  if (travelStarts) {
61677
61767
  // Where the slide being left IS — the place the stage gave it if a travel
61678
61768
  // was already playing (a press landing mid-travel departs from where the
@@ -61799,7 +61889,7 @@ const SlideContainer = ({
61799
61889
  // duration (the ask is zero, so ratioOfOneTravel answers 1), slowing the
61800
61890
  // travel at every re-render.
61801
61891
  const sameTravelPlaying = travelInFlight && !offsetDragged && offsetTargetBefore === offset;
61802
- const travels = !sameTravelPlaying && !noTravel && durationMs > 0 && offsetBefore !== undefined && offsetBefore !== offset;
61892
+ const travels = !sameTravelPlaying && !still && durationMs > 0 && offsetBefore !== undefined && offsetBefore !== offset;
61803
61893
  if (travels) {
61804
61894
  // The time it takes is the distance it has left to cover: a travel picked
61805
61895
  // up a fifth of the way through goes back in a fifth of the time, so what
@@ -65808,6 +65898,12 @@ const css$E = /* css */`
65808
65898
  }
65809
65899
  }
65810
65900
  }
65901
+ /* Off while the dialog's own transitions are off (switchTransitionsOff):
65902
+ the inline style that turns them off cannot reach a pseudo-element.
65903
+ After the rules above, which it must win over at equal weight. */
65904
+ &[navi-transitions-off]::backdrop {
65905
+ transition-property: none;
65906
+ }
65811
65907
 
65812
65908
  &[data-focus-visible],
65813
65909
  /* …or something filling it holds the keyboard and offers its ring to
@@ -67030,8 +67126,9 @@ const useDialogProps = props => {
67030
67126
  const dialogEl = ref.current;
67031
67127
  // A mount-time opening was never seen closed (see openEffect's own
67032
67128
  // `silent`): there is no box it comes from, because nothing was shown
67033
- // before it.
67034
- if (!dialogEl || opened && (!lifting || event.detail.silent)) {
67129
+ // before it. And a change a page change carries moves with that page,
67130
+ // in and out of no anchor (see page_change.js).
67131
+ if (!dialogEl || event.detail.silent || opened && !lifting) {
67035
67132
  applyChange();
67036
67133
  return;
67037
67134
  }
@@ -67047,7 +67144,11 @@ const useDialogProps = props => {
67047
67144
  }
67048
67145
  const anchorElement = resolveAnchorElement(event);
67049
67146
  if (!anchorElement) {
67050
- {
67147
+ // An opening by the caller's state (`open`, `signal`, `navState`) is
67148
+ // told nothing about its cause, and that cause may be the address —
67149
+ // a back to an entry where the dialog was open, nothing pressed — so
67150
+ // a missing anchor there is not something the app could have given.
67151
+ if (event.type !== "open_by_prop") {
67051
67152
  console.warn(`[navi] Dialog has animation="lifting" and no anchor to lift out of, so it simply appears. The anchor is whatever opened it — a <Button command="--navi-open">, the "source" given to triggerNaviCommand — or the "anchor" prop.`);
67052
67153
  }
67053
67154
  applyChange();
@@ -67083,8 +67184,9 @@ const useDialogProps = props => {
67083
67184
  }
67084
67185
 
67085
67186
  // Set by useOpenControllerByProps for the very first open triggered by
67086
- // `open`/`defaultOpen` already being truthy at mount — see popover.jsx's
67087
- // own openEffect for the full reasoning, mirrored here identically.
67187
+ // `open`/`defaultOpen` already being truthy at mount, and for an open a
67188
+ // page change carries — see popover.jsx's own openEffect for the full
67189
+ // reasoning, mirrored here identically.
67088
67190
  const silent = Boolean(e.detail.silent);
67089
67191
 
67090
67192
  // document.documentElement — the shared "no real container, use the
@@ -67128,7 +67230,7 @@ const useDialogProps = props => {
67128
67230
  // comment), even though Dialog never needs to measure/flip anything: it
67129
67231
  // still needs a genuinely rendered "closed" frame to transition from, not a
67130
67232
  // jump straight from not-shown to aria-expanded="true".
67131
- dialogEl.style.transitionProperty = "none";
67233
+ switchTransitionsOff(dialogEl);
67132
67234
  if (backdropEl) {
67133
67235
  disarmBackdropHideRef.current?.();
67134
67236
  disarmBackdropHideRef.current = null;
@@ -67396,12 +67498,12 @@ const useDialogProps = props => {
67396
67498
  dialogEl.setAttribute("aria-expanded", "true");
67397
67499
  backdropEl?.setAttribute("aria-expanded", "true");
67398
67500
  dialogEl.getBoundingClientRect();
67399
- dialogEl.style.transitionProperty = "";
67501
+ switchTransitionsOn(dialogEl);
67400
67502
  if (backdropEl) {
67401
67503
  backdropEl.style.transitionProperty = "";
67402
67504
  }
67403
67505
  } else {
67404
- dialogEl.style.transitionProperty = "";
67506
+ switchTransitionsOn(dialogEl);
67405
67507
  dialogEl.setAttribute("aria-expanded", "true");
67406
67508
  backdropEl?.setAttribute("aria-expanded", "true");
67407
67509
  if (backdropEl) {
@@ -67437,6 +67539,15 @@ const useDialogProps = props => {
67437
67539
  return closeEvent => {
67438
67540
  debugPopup(`"${closeEvent.type}" on ${getElementSignature(closeEvent.target)} -> closeDialog`);
67439
67541
  clearTextSelectionInside(dialogEl);
67542
+ // Closed by the navigation that puts another page on screen: it leaves
67543
+ // with that page, and plays no exit of its own (see page_change.js).
67544
+ const silent = Boolean(closeEvent.detail.silent);
67545
+ if (silent) {
67546
+ switchTransitionsOff(dialogEl);
67547
+ if (backdropEl) {
67548
+ backdropEl.style.transitionProperty = "none";
67549
+ }
67550
+ }
67440
67551
  dialogEl.setAttribute("aria-expanded", "false");
67441
67552
  if (!isTopLayer) {
67442
67553
  openLocalDialogCount = Math.max(0, openLocalDialogCount - 1);
@@ -67476,7 +67587,7 @@ const useDialogProps = props => {
67476
67587
  // next opening clears it (see openEffect's own unfreezeSize).
67477
67588
  freezeSize(dialogEl);
67478
67589
  cancelOpenInteractionSuppression?.();
67479
- if (hasCssTransitionAnimation) {
67590
+ if (hasCssTransitionAnimation && !silent) {
67480
67591
  suppressPointerEventsDuringTransition(dialogEl);
67481
67592
  }
67482
67593
  if (backdropEl) {
@@ -67487,6 +67598,15 @@ const useDialogProps = props => {
67487
67598
  }
67488
67599
  restoreFocus(closeEvent);
67489
67600
  cleanup();
67601
+ if (silent) {
67602
+ // The closed frame committed with nothing transitioning, before
67603
+ // transitions come back for the next opening.
67604
+ dialogEl.getBoundingClientRect();
67605
+ switchTransitionsOn(dialogEl);
67606
+ if (backdropEl) {
67607
+ backdropEl.style.transitionProperty = "";
67608
+ }
67609
+ }
67490
67610
  };
67491
67611
  };
67492
67612
  const onKeyDownShortcuts = createOnKeyDownForShortcuts({
@@ -67756,6 +67876,19 @@ const warnBottomSheetHoldingKeyboardControl = dialogEl => {
67756
67876
  }
67757
67877
  console.warn(`[navi] a Dialog docked to the bottom edge (dockedOnSmallTouchScreen="bottom") holds a field that raises the virtual keyboard. On a phone the keyboard rises from the edge the sheet rests on and reflows the sheet into the strip left above it, at every keystroke. A sheet one types into rests on the top edge: dockedOnSmallTouchScreen without a value. "bottom" is for a sheet one reads and taps.`, controlEl);
67758
67878
  };
67879
+
67880
+ // The dialog's own transitions, off while a frame is pinned (the closed one an
67881
+ // entrance starts from, the open one a silent opening lands on, the closed one
67882
+ // a silent close leaves) and back on after it. A modal's wall is its native
67883
+ // ::backdrop, which takes no inline style: it reads the attribute instead.
67884
+ const switchTransitionsOff = dialogEl => {
67885
+ dialogEl.style.transitionProperty = "none";
67886
+ dialogEl.setAttribute("navi-transitions-off", "");
67887
+ };
67888
+ const switchTransitionsOn = dialogEl => {
67889
+ dialogEl.style.transitionProperty = "";
67890
+ dialogEl.removeAttribute("navi-transitions-off");
67891
+ };
67759
67892
  const DIALOG_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible", ":focus-within"];
67760
67893
 
67761
67894
  // Lets consumers pass animationDuration="0.5s" as a regular prop; Box maps
@@ -68688,8 +68821,10 @@ const usePopoverProps = props => {
68688
68821
  // `open`/`defaultOpen` already being truthy at mount — there's nothing
68689
68822
  // to visually transition away from (nothing was ever shown as "closed"
68690
68823
  // to the user), so this open skips the animation entirely instead of
68691
- // playing it against a closed frame that was never actually seen. See
68692
- // the final commit step below for how that's done.
68824
+ // playing it against a closed frame that was never actually seen. Set
68825
+ // too for an open the page changing carries: that page is its movement
68826
+ // (see page_change.js). See the final commit step below for how that's
68827
+ // done.
68693
68828
  const silent = Boolean(e.detail.silent);
68694
68829
  const [cleanup, addCleanup] = createPubSub(true);
68695
68830
 
@@ -69125,7 +69260,7 @@ const usePopoverProps = props => {
69125
69260
  // focus in. Inlined rather than a standalone function since it only
69126
69261
  // has this one call site.
69127
69262
  //
69128
- // `silent` (mounting already open via `open`/`defaultOpen`) flips the
69263
+ // `silent` (mounting already open, or carried by a page change) flips the
69129
69264
  // order instead: aria-expanded first, *then* re-enable transitions, with
69130
69265
  // its own forced reflow in between the two — without that reflow, the
69131
69266
  // browser coalesces "flip aria-expanded" and "re-enable transitions"
@@ -69172,6 +69307,15 @@ const usePopoverProps = props => {
69172
69307
  return closeEvent => {
69173
69308
  debugPopup(closeEvent, `closePopover()`);
69174
69309
  clearTextSelectionInside(popoverEl);
69310
+ // Closed by the navigation that puts another page on screen: it leaves
69311
+ // with that page, and plays no exit of its own (see page_change.js).
69312
+ const silent = Boolean(closeEvent.detail.silent);
69313
+ if (silent) {
69314
+ popoverEl.style.transitionProperty = "none";
69315
+ if (backdropEl) {
69316
+ backdropEl.style.transitionProperty = "none";
69317
+ }
69318
+ }
69175
69319
  popoverEl.setAttribute("aria-expanded", "false");
69176
69320
  // Set regardless of isTopLayer — see the open side's own identical
69177
69321
  // comment (openEffect above) for why hidePopover() alone isn't
@@ -69198,7 +69342,7 @@ const usePopoverProps = props => {
69198
69342
  // open is its own separate call with no way to reach back into this
69199
69343
  // one).
69200
69344
  cancelOpenInteractionSuppression?.();
69201
- if (hasCssTransitionAnimation) {
69345
+ if (hasCssTransitionAnimation && !silent) {
69202
69346
  suppressPointerEventsDuringTransition(popoverEl);
69203
69347
  }
69204
69348
  if (backdropEl) {
@@ -69233,6 +69377,15 @@ const usePopoverProps = props => {
69233
69377
  popoverEl.removeAttribute("data-position-y-current");
69234
69378
  popoverEl.removeAttribute("data-position-x-current");
69235
69379
  cleanup();
69380
+ if (silent) {
69381
+ // The closed frame committed with nothing transitioning, before
69382
+ // transitions come back for the next opening.
69383
+ popoverEl.getBoundingClientRect();
69384
+ popoverEl.style.transitionProperty = "";
69385
+ if (backdropEl) {
69386
+ backdropEl.style.transitionProperty = "";
69387
+ }
69388
+ }
69236
69389
  };
69237
69390
  };
69238
69391
  const onKeyDownShortcuts = createOnKeyDownForShortcuts({