@atlaskit/top-layer 0.16.0 → 0.18.0

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.
Files changed (141) hide show
  1. package/AGENTS.md +113 -0
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +4 -4
  4. package/animations/package.json +1 -8
  5. package/dialog/package.json +1 -8
  6. package/dialog-scroll-lock/package.json +1 -8
  7. package/dist/cjs/animations/presets.js +96 -9
  8. package/dist/cjs/dialog/dialog-content.js +12 -30
  9. package/dist/cjs/entry-points/animations.js +12 -0
  10. package/dist/cjs/internal/set-style.js +5 -5
  11. package/dist/cjs/internal/slot.js +1 -1
  12. package/dist/cjs/internal/use-anchor-position-at-point.js +8 -8
  13. package/dist/cjs/internal/use-anchor-position.js +19 -40
  14. package/dist/cjs/internal/use-animated-visibility.js +31 -61
  15. package/dist/cjs/internal/use-initial-focus.js +9 -13
  16. package/dist/cjs/internal/use-width-from-anchor.js +6 -6
  17. package/dist/cjs/popover/popover.js +30 -58
  18. package/dist/cjs/popover-surface/popover-surface.js +4 -3
  19. package/dist/cjs/testing/polyfill.js +9 -9
  20. package/dist/cjs/use-simple-light-dismiss/index.js +3 -3
  21. package/dist/es2019/animations/presets.js +145 -2
  22. package/dist/es2019/dialog/dialog-content.js +12 -30
  23. package/dist/es2019/entry-points/animations.js +1 -1
  24. package/dist/es2019/internal/set-style.js +5 -5
  25. package/dist/es2019/internal/slot.js +1 -1
  26. package/dist/es2019/internal/use-anchor-position-at-point.js +8 -8
  27. package/dist/es2019/internal/use-anchor-position.js +19 -40
  28. package/dist/es2019/internal/use-animated-visibility.js +31 -61
  29. package/dist/es2019/internal/use-initial-focus.js +9 -13
  30. package/dist/es2019/internal/use-width-from-anchor.js +6 -6
  31. package/dist/es2019/popover/popover.js +30 -58
  32. package/dist/es2019/popover-surface/popover-surface.js +1 -1
  33. package/dist/es2019/testing/polyfill.js +7 -11
  34. package/dist/es2019/use-simple-light-dismiss/index.js +3 -3
  35. package/dist/esm/animations/presets.js +93 -9
  36. package/dist/esm/dialog/dialog-content.js +12 -30
  37. package/dist/esm/entry-points/animations.js +1 -1
  38. package/dist/esm/internal/set-style.js +5 -5
  39. package/dist/esm/internal/slot.js +1 -1
  40. package/dist/esm/internal/use-anchor-position-at-point.js +8 -8
  41. package/dist/esm/internal/use-anchor-position.js +19 -40
  42. package/dist/esm/internal/use-animated-visibility.js +31 -61
  43. package/dist/esm/internal/use-initial-focus.js +9 -13
  44. package/dist/esm/internal/use-width-from-anchor.js +6 -6
  45. package/dist/esm/popover/popover.js +30 -58
  46. package/dist/esm/popover-surface/popover-surface.js +1 -1
  47. package/dist/esm/testing/polyfill.js +9 -9
  48. package/dist/esm/use-simple-light-dismiss/index.js +3 -3
  49. package/dist/types/animations/presets.d.ts +16 -0
  50. package/dist/types/entry-points/animations.d.ts +1 -1
  51. package/dist/types/internal/set-style.d.ts +2 -2
  52. package/dist/types/internal/slot.d.ts +2 -2
  53. package/dist/types/internal/use-anchor-position-at-point.d.ts +2 -2
  54. package/dist/types/internal/use-anchor-position.d.ts +0 -4
  55. package/dist/types/internal/use-initial-focus.d.ts +1 -1
  56. package/dist/types/popover/types.d.ts +5 -7
  57. package/dist/types/popover-surface/popover-surface.d.ts +2 -2
  58. package/focus/package.json +1 -8
  59. package/get-aria-for-trigger/package.json +1 -8
  60. package/open-layer-observer/package.json +1 -8
  61. package/package.json +3 -3
  62. package/placement-map/package.json +1 -8
  63. package/popover/package.json +1 -8
  64. package/popover-surface/package.json +1 -8
  65. package/testing/polyfill/package.json +1 -8
  66. package/testing/to-be-visible/package.json +1 -8
  67. package/use-anchor-position/package.json +1 -8
  68. package/use-anchor-position-at-point/package.json +1 -8
  69. package/use-arrow-navigation/package.json +1 -8
  70. package/use-popover-id/package.json +1 -8
  71. package/use-simple-light-dismiss/package.json +1 -8
  72. package/use-width-from-anchor/package.json +1 -8
  73. package/dist/types-ts4.5/animations/presets.d.ts +0 -94
  74. package/dist/types-ts4.5/animations/types.d.ts +0 -38
  75. package/dist/types-ts4.5/dialog/create-close-event.d.ts +0 -23
  76. package/dist/types-ts4.5/dialog/dialog-content.d.ts +0 -24
  77. package/dist/types-ts4.5/dialog/index.d.ts +0 -3
  78. package/dist/types-ts4.5/dialog/types.d.ts +0 -126
  79. package/dist/types-ts4.5/dialog-scroll-lock/index.d.ts +0 -40
  80. package/dist/types-ts4.5/entry-points/animations.d.ts +0 -2
  81. package/dist/types-ts4.5/entry-points/dialog-scroll-lock.d.ts +0 -1
  82. package/dist/types-ts4.5/entry-points/dialog.d.ts +0 -2
  83. package/dist/types-ts4.5/entry-points/focus.d.ts +0 -4
  84. package/dist/types-ts4.5/entry-points/get-aria-for-trigger.d.ts +0 -1
  85. package/dist/types-ts4.5/entry-points/open-layer-observer.d.ts +0 -5
  86. package/dist/types-ts4.5/entry-points/placement-map.d.ts +0 -3
  87. package/dist/types-ts4.5/entry-points/popover-surface.d.ts +0 -2
  88. package/dist/types-ts4.5/entry-points/popover.d.ts +0 -2
  89. package/dist/types-ts4.5/entry-points/use-anchor-position-at-point.d.ts +0 -1
  90. package/dist/types-ts4.5/entry-points/use-anchor-position.d.ts +0 -1
  91. package/dist/types-ts4.5/entry-points/use-arrow-navigation.d.ts +0 -3
  92. package/dist/types-ts4.5/entry-points/use-popover-id.d.ts +0 -11
  93. package/dist/types-ts4.5/entry-points/use-simple-light-dismiss.d.ts +0 -2
  94. package/dist/types-ts4.5/entry-points/use-width-from-anchor.d.ts +0 -1
  95. package/dist/types-ts4.5/focus/get-first-focusable.d.ts +0 -8
  96. package/dist/types-ts4.5/focus/get-focusables.d.ts +0 -13
  97. package/dist/types-ts4.5/focus/get-last-focusable.d.ts +0 -8
  98. package/dist/types-ts4.5/focus/get-next-focusable.d.ts +0 -13
  99. package/dist/types-ts4.5/focus/is-in-same-layer.d.ts +0 -8
  100. package/dist/types-ts4.5/focus/is-nested-layer-focused.d.ts +0 -8
  101. package/dist/types-ts4.5/focus/selectors.d.ts +0 -4
  102. package/dist/types-ts4.5/focus/types.d.ts +0 -5
  103. package/dist/types-ts4.5/index.d.ts +0 -0
  104. package/dist/types-ts4.5/internal/anchor-positioning-fallback.d.ts +0 -26
  105. package/dist/types-ts4.5/internal/combine.d.ts +0 -14
  106. package/dist/types-ts4.5/internal/ensure-preset-styles.d.ts +0 -6
  107. package/dist/types-ts4.5/internal/get-aria-for-trigger.d.ts +0 -93
  108. package/dist/types-ts4.5/internal/placement-to-position-area.d.ts +0 -21
  109. package/dist/types-ts4.5/internal/placement-to-try-fallbacks.d.ts +0 -36
  110. package/dist/types-ts4.5/internal/reduced-motion.d.ts +0 -14
  111. package/dist/types-ts4.5/internal/resolve-css-length-to-pixels.d.ts +0 -20
  112. package/dist/types-ts4.5/internal/resolve-css-length.d.ts +0 -8
  113. package/dist/types-ts4.5/internal/resolve-placement.d.ts +0 -58
  114. package/dist/types-ts4.5/internal/role-to-aria-has-popup.d.ts +0 -13
  115. package/dist/types-ts4.5/internal/role-types.d.ts +0 -71
  116. package/dist/types-ts4.5/internal/set-style.d.ts +0 -11
  117. package/dist/types-ts4.5/internal/should-focus-into-popover.d.ts +0 -8
  118. package/dist/types-ts4.5/internal/slot.d.ts +0 -29
  119. package/dist/types-ts4.5/internal/use-anchor-position-at-point.d.ts +0 -67
  120. package/dist/types-ts4.5/internal/use-anchor-position.d.ts +0 -91
  121. package/dist/types-ts4.5/internal/use-animated-visibility.d.ts +0 -109
  122. package/dist/types-ts4.5/internal/use-animation-preset.d.ts +0 -11
  123. package/dist/types-ts4.5/internal/use-focus-wrap.d.ts +0 -25
  124. package/dist/types-ts4.5/internal/use-initial-focus.d.ts +0 -73
  125. package/dist/types-ts4.5/internal/use-preset-styles.d.ts +0 -15
  126. package/dist/types-ts4.5/internal/use-width-from-anchor.d.ts +0 -21
  127. package/dist/types-ts4.5/placement-map/index.d.ts +0 -51
  128. package/dist/types-ts4.5/placement-map/legacy-placements.d.ts +0 -27
  129. package/dist/types-ts4.5/placement-map/placement-mapping.d.ts +0 -13
  130. package/dist/types-ts4.5/popover/create-close-event.d.ts +0 -25
  131. package/dist/types-ts4.5/popover/index.d.ts +0 -3
  132. package/dist/types-ts4.5/popover/popover.d.ts +0 -17
  133. package/dist/types-ts4.5/popover/types.d.ts +0 -193
  134. package/dist/types-ts4.5/popover-surface/index.d.ts +0 -2
  135. package/dist/types-ts4.5/popover-surface/popover-surface.d.ts +0 -21
  136. package/dist/types-ts4.5/testing/polyfill.d.ts +0 -25
  137. package/dist/types-ts4.5/testing/to-be-visible.d.ts +0 -23
  138. package/dist/types-ts4.5/use-arrow-navigation/index.d.ts +0 -3
  139. package/dist/types-ts4.5/use-arrow-navigation/is-at-current-menu-level.d.ts +0 -48
  140. package/dist/types-ts4.5/use-arrow-navigation/use-arrow-navigation.d.ts +0 -102
  141. package/dist/types-ts4.5/use-simple-light-dismiss/index.d.ts +0 -45
@@ -145,17 +145,11 @@ function crossAxisShiftMargin(_ref2) {
145
145
  }
146
146
 
147
147
  /**
148
- * Returns a referentially-stable, fully-resolved `TPlacement`. `useMemo` is
149
- * keyed on the primitive fields of the input so a fresh inline `placement`
150
- * object on every render does not produce a fresh resolved object. Both
151
- * `getPlacement` and the equality check are skipped when the inputs are
152
- * unchanged.
148
+ * Returns a referentially-stable, fully-resolved `TPlacement`. The memo is
149
+ * keyed on the resolved primitive fields so a fresh inline `placement` object
150
+ * (or undefined fields vs explicit defaults) does not produce a fresh result.
153
151
  */
154
152
  function useStablePlacement(placement) {
155
- // Resolve to the fully-defaulted primitives BEFORE the memo so the deps
156
- // array sees the same key for `{}`, `undefined` fields, and explicit
157
- // defaults. Otherwise `axis: undefined` and `axis: 'block'` would be
158
- // treated as different inputs and re-run the downstream effect.
159
153
  var resolved = getPlacement({
160
154
  placement: placement
161
155
  });
@@ -165,10 +159,8 @@ function useStablePlacement(placement) {
165
159
  var gap = resolved.offset.gap;
166
160
  var shiftValue = resolved.offset.crossAxisShift.value;
167
161
  var shiftDirection = resolved.offset.crossAxisShift.direction;
168
- // Rebuild the placement object inside the memo from the resolved primitive
169
- // deps so the factory does not close over the (potentially fresh) outer
170
- // `resolved` reference, and `react-hooks/exhaustive-deps` can verify the
171
- // deps array.
162
+ // Rebuild inside the memo from primitive deps so the factory does not
163
+ // close over the outer `resolved` reference and exhaustive-deps can verify.
172
164
  return useMemo(function () {
173
165
  return {
174
166
  axis: axis,
@@ -200,10 +192,6 @@ function useStablePlacement(placement) {
200
192
  * When not supported, it falls back to JavaScript-based positioning using
201
193
  * `position: fixed` with measured coordinates, re-running on scroll (capture)
202
194
  * and resize events.
203
- *
204
- * `placement` may be a fresh inline object on every render: a structural
205
- * comparison is used internally so re-runs are skipped when the resolved
206
- * placement shape is unchanged.
207
195
  */
208
196
  // eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
209
197
  export function useAnchorPosition(_ref3) {
@@ -217,8 +205,6 @@ export function useAnchorPosition(_ref3) {
217
205
  isEnabled = _ref3$isEnabled === void 0 ? true : _ref3$isEnabled,
218
206
  isOpen = _ref3.isOpen;
219
207
  var id = useId();
220
- // Stabilize `placement` object so the same object literal
221
- // value returns an object with the same reference
222
208
  var stablePlacement = useStablePlacement(placement);
223
209
  useLayoutEffect(function () {
224
210
  if (!isEnabled) {
@@ -240,9 +226,9 @@ export function useAnchorPosition(_ref3) {
240
226
  placement: stablePlacement,
241
227
  offset: gapCssValue
242
228
  });
243
- // Hoist crossAxisShift to a single computation; reused below to
244
- // populate the active `--ds-cross-axis-shift-margin-*` custom
245
- // property for the named arrow @position-try rules.
229
+ // Computed once; reused below to populate the active
230
+ // `--ds-cross-axis-shift-margin-*` custom property for the
231
+ // named arrow @position-try rules.
246
232
  var crossAxisShift = crossAxisShiftMargin({
247
233
  placement: stablePlacement,
248
234
  crossAxisShiftCssValue: crossAxisShiftCssValue,
@@ -270,22 +256,17 @@ export function useAnchorPosition(_ref3) {
270
256
  }, {
271
257
  property: 'inset',
272
258
  value: 'auto'
273
- },
274
- // Main-axis gap between the popover and its trigger
275
- {
259
+ }, {
276
260
  property: gap.property,
277
261
  value: gap.value
278
- },
279
- // Cross-axis shift
280
- {
262
+ }, {
281
263
  property: crossAxisShift.property,
282
264
  value: crossAxisShift.value
283
265
  }];
284
266
 
285
- // Surface the active cross-axis shift value as a custom property so
286
- // each named arrow @position-try rule can re-apply it after a flip.
287
- // The four properties cover (cross-axis, side); only one is non-zero
288
- // at a time.
267
+ // Expose the active cross-axis shift via custom properties so each
268
+ // named arrow @position-try rule can re-apply it after a flip.
269
+ // One of the four (cross-axis, side) properties is non-zero at a time.
289
270
  popoverStyles.push({
290
271
  property: '--ds-cross-axis-shift-margin-start',
291
272
  value: '0px'
@@ -302,9 +283,8 @@ export function useAnchorPosition(_ref3) {
302
283
  property: '--ds-cross-axis-shift-margin-block-end',
303
284
  value: '0px'
304
285
  });
305
- // `crossAxisShift` IS the active margin - reuse instead of recomputing.
286
+ // `crossAxisShift` IS the active margin; reuse instead of recomputing.
306
287
  var crossAxisShiftActive = crossAxisShift;
307
- // Map margin property to its corresponding custom property name.
308
288
  var customPropertyByMarginProperty = {
309
289
  'margin-inline-start': '--ds-cross-axis-shift-margin-start',
310
290
  'margin-inline-end': '--ds-cross-axis-shift-margin-end',
@@ -338,18 +318,17 @@ export function useAnchorPosition(_ref3) {
338
318
  */
339
319
  trigger.style.setProperty('anchor-name', anchorName);
340
320
  var _undoPositioning = combine(setStyle({
341
- el: popover,
321
+ element: popover,
342
322
  styles: popoverStyles
343
323
  }));
344
324
  return _undoPositioning;
345
325
  }
346
326
 
347
- // JS fallback
348
- // The popover is already in the browser's top layer via popover="auto",
349
- // so it does not need position:fixed. We only reset the UA defaults
350
- // (inset: 0; margin: auto) and set top/left based on measurements.
327
+ // JS fallback. The popover is already in the top layer via
328
+ // popover="auto", so we only reset UA defaults and set top/left
329
+ // based on measurements.
351
330
  var cleanupBaseStyles = setStyle({
352
- el: popover,
331
+ element: popover,
353
332
  styles: [{
354
333
  property: 'margin',
355
334
  value: '0'
@@ -12,14 +12,16 @@ function runOnTransitionEndOrTimeout(_ref) {
12
12
  var element = _ref.element,
13
13
  safetyNetMs = _ref.safetyNetMs,
14
14
  onSettled = _ref.onSettled;
15
- var isSettled = false;
15
+ var state = {
16
+ isSettled: false
17
+ };
16
18
  function teardown() {
17
- isSettled = true;
19
+ state.isSettled = true;
18
20
  clearTimeout(safetyNetId);
19
21
  unbind();
20
22
  }
21
23
  function settle() {
22
- if (isSettled) {
24
+ if (state.isSettled) {
23
25
  return;
24
26
  }
25
27
  teardown();
@@ -103,22 +105,16 @@ export function useAnimatedVisibility(_ref2) {
103
105
  elementRef = _ref2.elementRef,
104
106
  onEnterFinish = _ref2.onEnterFinish,
105
107
  onExitFinish = _ref2.onExitFinish;
106
- // Resolve the animation preset and inject its CSS (idempotent).
107
- // Returns `null` when `animate` is falsy.
108
108
  var preset = usePresetStyles({
109
109
  preset: animate
110
110
  });
111
111
 
112
- // Whether we should play CSS transitions. False when there is no preset
113
- // or the user has enabled the "prefers reduced motion" OS setting.
112
+ // False when there is no preset or `prefers-reduced-motion` is set.
114
113
  var willAnimate = Boolean(animate) && !prefersReducedMotion();
115
114
 
116
- // `phase` is the single source of truth for the visibility lifecycle.
117
- // We promote `closed → entering` (animated) or `closed → open`
118
- // (non-animated) synchronously during render so the host element mounts
119
- // in the same commit as the open intent (React supports a single
120
- // setState during render as a synchronous re-render before paint).
121
- // All other transitions are driven by phase-specific effects below.
115
+ // Promote `closed → entering`/`closed → open` synchronously during
116
+ // render so the host element mounts in the same commit as the open
117
+ // intent. All other transitions are driven by phase-specific effects.
122
118
  var _useState = useState(function () {
123
119
  if (!isOpen) {
124
120
  return 'closed';
@@ -153,10 +149,8 @@ export function useAnimatedVisibility(_ref2) {
153
149
  var onExitFinishRef = useRef(onExitFinish);
154
150
  onExitFinishRef.current = onExitFinish;
155
151
 
156
- // `entering` (animation enabled):
157
- // Wait for the entry transition to settle, then move to `open` and fire
158
- // `onEnterFinish`. A fallback timeout (enterDurationMs + 50ms buffer)
159
- // guarantees the settle path runs even if `transitionend` is swallowed
152
+ // Animated entry: wait for `transitionend` (or a safety-net timeout) and
153
+ // move to `open`. The fallback guarantees settle on swallowed events
160
154
  // (zero-duration, browser quirk, mid-transition unmount).
161
155
  useEffect(function () {
162
156
  var _preset$enterDuration;
@@ -184,12 +178,9 @@ export function useAnimatedVisibility(_ref2) {
184
178
  });
185
179
  }, [phase, preset === null || preset === void 0 ? void 0 : preset.enterDurationMs, elementRef]);
186
180
 
187
- // Non-animated entry callback:
188
- // When animation is disabled, the lifecycle goes `closed → open`
189
- // directly with no `entering` phase. Fire `onEnterFinish` on the
190
- // transition into `open` from the non-animated path. We detect this
191
- // via a previous-phase ref to avoid firing on the animated path's
192
- // `entering → open` transition (which has its own callback above).
181
+ // Non-animated entry callback. The lifecycle goes `closed → open`
182
+ // directly with no `entering` phase; fire `onEnterFinish` on that jump.
183
+ // A previous-phase ref avoids double-firing on the animated path.
193
184
  var prevPhaseForEntryRef = useRef('closed');
194
185
  useEffect(function () {
195
186
  var prevPhase = prevPhaseForEntryRef.current;
@@ -203,12 +194,8 @@ export function useAnimatedVisibility(_ref2) {
203
194
  }
204
195
  }, [phase]);
205
196
 
206
- // `exiting` (animation enabled):
207
- // Wait for the exit transition to settle, then unmount the host element
208
- // (set phase back to `closed`) and fire `onExitFinish`. The fallback
209
- // timeout (exitDurationMs + 50ms buffer) guarantees we always unmount
210
- // even if `transitionend` is never emitted (element removed from the
211
- // top layer, zero-duration transition, interrupted animation).
197
+ // Animated exit: wait for `transitionend` (or a safety-net timeout),
198
+ // fire `onExitFinish`, then move to `closed` to unmount the host.
212
199
  useEffect(function () {
213
200
  var _preset$exitDurationM;
214
201
  if (phase !== 'exiting' || !willAnimate) {
@@ -237,33 +224,20 @@ export function useAnimatedVisibility(_ref2) {
237
224
  });
238
225
  }, [phase, willAnimate, preset === null || preset === void 0 ? void 0 : preset.exitDurationMs, elementRef]);
239
226
 
240
- // `exiting` (animation disabled):
241
- // Wait for the browser's `toggle` (closed) event (for `<div popover>`)
242
- // or `close` event (for `<dialog>`) to fire before unmounting. This
243
- // guarantees:
244
- // - the consumer's toggle/close listener (close-reason capture,
245
- // nested focus restoration, `onClose` notification) runs against
246
- // the still-attached element,
247
- // - the browser's native focus restoration triggered by
248
- // `hidePopover()` / `<dialog>.close()` has fired,
249
- // before React unmounts the node. A naive `setTimeout(0)` race
250
- // occasionally beats the `toggle` task in Chromium, causing focus
251
- // restoration to drop (the toggle event arrives at a detached element).
227
+ // Non-animated exit: wait for the browser's `toggle` (closed) or
228
+ // `close` event before unmounting, so the consumer's listener (close
229
+ // reason, nested focus restoration, `onClose`) and the browser's
230
+ // native focus restoration both run against the still-attached
231
+ // element. A naive `setTimeout(0)` occasionally beats the `toggle`
232
+ // task in Chromium and drops focus restoration.
252
233
  //
253
- // `useLayoutEffect` (not `useEffect`) so the listener is bound in the
254
- // same commit as the consumer's show/hide layout effect that calls
255
- // `hidePopover()` / `dialog.close()`. The browser queues the resulting
256
- // `toggle`/`close` event as a task, which cannot run until the JS
257
- // frame (including all effect flushes) completes, so the listener is
258
- // always attached before the event fires. Promotion to layout timing
259
- // removes any theoretical gap and future-proofs the ordering against
260
- // effect reordering. Safe under SSR: `phase` starts at `'closed'`, so
261
- // the body short-circuits and no DOM access happens on the server.
234
+ // `useLayoutEffect` so the listener binds in the same commit as the
235
+ // show/hide layout effect that calls `hidePopover()` / `dialog.close()`.
236
+ // The toggle/close event is queued as a task and cannot run until the
237
+ // frame completes. SSR-safe: `phase` starts at `'closed'`.
262
238
  //
263
- // `onExitFinish` is NOT called here. It is decoupled from the unmount
264
- // handshake and fired by the dedicated non-animated exit-callback
265
- // effect below, so consumers observe a synchronous "exit finished"
266
- // signal that matches `isOpen` flipping to `false`.
239
+ // `onExitFinish` is fired separately (see effect below) so consumers
240
+ // observe it the moment `isOpen` flips to `false`.
267
241
  useLayoutEffect(function () {
268
242
  if (phase !== 'exiting' || willAnimate) {
269
243
  return;
@@ -290,13 +264,9 @@ export function useAnimatedVisibility(_ref2) {
290
264
  }]);
291
265
  }, [phase, willAnimate, elementRef]);
292
266
 
293
- // Non-animated exit callback:
294
- // When animation is disabled there is no `transitionend` to wait for,
295
- // so fire `onExitFinish` on the transition into `exiting`. The actual
296
- // host-element unmount is gated on the browser `toggle`/`close` event
297
- // by the effect above; `onExitFinish` is observably decoupled from
298
- // that handshake so consumers see the callback fire at the same time
299
- // `isOpen` flipped to `false`.
267
+ // Non-animated exit callback. No `transitionend` to wait for, so fire
268
+ // `onExitFinish` on the transition into `exiting` (the unmount itself
269
+ // is gated by the toggle/close handshake above).
300
270
  var prevPhaseForExitRef = useRef('closed');
301
271
  useEffect(function () {
302
272
  var prevPhase = prevPhaseForExitRef.current;
@@ -128,8 +128,6 @@ function getInitialFocusTarget(_ref2) {
128
128
  });
129
129
  }
130
130
  if (role === 'menu') {
131
- // ARIA Combobox Pattern: if the popup is owned by a focused combobox,
132
- // leave focus on the textbox. Navigation is proxied via the combobox.
133
131
  if (isComboboxControllingPopup({
134
132
  container: container
135
133
  })) {
@@ -146,9 +144,9 @@ function getInitialFocusTarget(_ref2) {
146
144
  });
147
145
  }
148
146
  if (role === 'listbox') {
149
- // ARIA Combobox Pattern: if the popup is owned by a focused
150
- // combobox-like textbox (in-popup or external e.g. react-select),
151
- // leave focus on the textbox. Navigation is proxied via the combobox.
147
+ // ARIA Combobox Pattern: if a combobox-like textbox owns the popup
148
+ // (in-popup or external e.g. react-select), leave focus on the
149
+ // textbox - navigation is proxied through it.
152
150
  if (isComboboxControllingPopup({
153
151
  container: container
154
152
  })) {
@@ -210,7 +208,7 @@ function getInitialFocusTarget(_ref2) {
210
208
  * `<dialog>.close()`. If the consumer reopens before the exit transition
211
209
  * has settled, the phase machine jumps `exiting → entering` without
212
210
  * passing through `closed`, so without this branch the popup would be
213
- * visible again with focus stranded on the trigger — a keyboard usability
211
+ * visible again with focus stranded on the trigger - a keyboard usability
214
212
  * gap for menu/dialog/listbox roles.
215
213
  *
216
214
  * Note: there is a rare programmatic path where a consumer flips `isOpen`
@@ -251,22 +249,20 @@ export function useInitialFocus(_ref3) {
251
249
  var prevPhase = prevPhaseRef.current;
252
250
  prevPhaseRef.current = phase;
253
251
 
254
- // Skip the `phase === 'closed'` transitions (host is going away,
255
- // nothing to focus) and any transition whose previous phase was
256
- // neither `'closed'` (fresh open) nor `'exiting'` (mid-exit
257
- // reopen, focus already on the trigger).
252
+ // Only focus on transitions into a visible phase from `'closed'`
253
+ // (fresh open) or `'exiting'` (mid-exit reopen).
258
254
  if (phase === 'closed') {
259
255
  return;
260
256
  }
261
257
  if (prevPhase !== 'closed' && prevPhase !== 'exiting') {
262
258
  return;
263
259
  }
264
- var el = elementRef.current;
265
- if (!el) {
260
+ var element = elementRef.current;
261
+ if (!element) {
266
262
  return;
267
263
  }
268
264
  (_getInitialFocusTarge = getInitialFocusTarget({
269
- container: el,
265
+ container: element,
270
266
  role: role
271
267
  })) === null || _getInitialFocusTarge === void 0 || _getInitialFocusTarge.focus();
272
268
  }, [elementRef, phase, role]);
@@ -35,7 +35,7 @@ export function useWidthFromAnchor(_ref) {
35
35
  // explicit width constraint, allowing the popover to grow past the anchor's width.
36
36
  if (supportsAnchorSize) {
37
37
  return setStyle({
38
- el: node,
38
+ element: node,
39
39
  styles: [{
40
40
  property: 'width',
41
41
  value: 'anchor-size(width)'
@@ -47,7 +47,7 @@ export function useWidthFromAnchor(_ref) {
47
47
  var anchor = anchorRef.current;
48
48
  if (anchor) {
49
49
  return setStyle({
50
- el: node,
50
+ element: node,
51
51
  styles: [{
52
52
  property: 'width',
53
53
  value: "".concat(anchor.offsetWidth, "px")
@@ -69,7 +69,7 @@ export function useWidthFromAnchor(_ref) {
69
69
  // if its content requires it.
70
70
  if (supportsAnchorSize) {
71
71
  return setStyle({
72
- el: node,
72
+ element: node,
73
73
  styles: [minInlineSizeStyle, {
74
74
  property: 'min-width',
75
75
  value: 'anchor-size(width)'
@@ -79,7 +79,7 @@ export function useWidthFromAnchor(_ref) {
79
79
  var _anchor = anchorRef.current;
80
80
  if (_anchor) {
81
81
  return setStyle({
82
- el: node,
82
+ element: node,
83
83
  styles: [minInlineSizeStyle, {
84
84
  property: 'min-width',
85
85
  value: "".concat(_anchor.offsetWidth, "px")
@@ -89,14 +89,14 @@ export function useWidthFromAnchor(_ref) {
89
89
 
90
90
  // No anchor available in JS fallback - still apply min-inline-size.
91
91
  return setStyle({
92
- el: node,
92
+ element: node,
93
93
  styles: [minInlineSizeStyle]
94
94
  });
95
95
  }
96
96
 
97
97
  // 'none' mode: no explicit width, but still apply `min-inline-size: max-content`.
98
98
  return setStyle({
99
- el: node,
99
+ element: node,
100
100
  styles: [minInlineSizeStyle]
101
101
  });
102
102
  }, [mode, popoverRef, anchorRef, isOpen]);
@@ -21,9 +21,9 @@ var supportsPopoverHint = once(function () {
21
21
  return false;
22
22
  }
23
23
  // eslint-disable-next-line @atlaskit/platform/no-direct-document-usage -- feature detection
24
- var el = document.createElement('div');
25
- el.setAttribute('popover', 'hint');
26
- return el.popover === 'hint';
24
+ var element = document.createElement('div');
25
+ element.setAttribute('popover', 'hint');
26
+ return element.popover === 'hint';
27
27
  });
28
28
 
29
29
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- popover UA reset requires values not in cssMap's type union
@@ -66,9 +66,7 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
66
66
  var autoId = useId();
67
67
  var ownRef = useRef(null);
68
68
  var combinedRef = mergeRefs([ownRef, ref].filter(Boolean));
69
- // React 18 `useId()` returns IDs with colons (invalid in CSS selectors
70
- // and popover target attributes). Strip them; remove once React 18 is
71
- // dropped (React 19.2 uses underscores).
69
+ // `useId()` colons are invalid in CSS selectors and popover target attributes.
72
70
  var popoverId = idProp !== null && idProp !== void 0 ? idProp : "popover-".concat(autoId.replace(/:/g, ''));
73
71
  var _useAnimatedVisibilit = useAnimatedVisibility({
74
72
  isOpen: isOpen,
@@ -80,21 +78,15 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
80
78
  phase = _useAnimatedVisibilit.phase,
81
79
  preset = _useAnimatedVisibilit.preset;
82
80
 
83
- // Pre-computed phase predicate. `isVisible` mirrors "host element is
84
- // mounted and on screen" (any phase except `closed`); used as a dep
85
- // signal for listener-re-bind effects so they re-attach to the fresh
86
- // host element after a close → reopen unmount/remount cycle.
81
+ // True while the host element is mounted (any phase except `closed`).
82
+ // Used as a dep so listener-rebind effects re-attach after a remount.
87
83
  var isVisible = phase !== 'closed';
88
84
 
89
85
  // Focus management: initial focus on entry (role-dependent), Tab cycling
90
86
  // for dialog roles. Restoration is native for outermost popovers; nested
91
- // focus-capturing roles are handled below via `beforetoggle` snapshot.
92
- // See: notes/architecture/focus-restoration.md
93
- //
94
- // Both hooks take `phase` directly: `useFocusWrap` keeps its listener
95
- // attached while `phase !== 'closed'` (so focus stays trapped through
96
- // the animated-exit window — WCAG 2.4.3 regression guard);
97
- // `useInitialFocus` moves focus on the transition into `'open'`.
87
+ // focus-capturing roles are handled below via the `beforetoggle` snapshot.
88
+ // Passing `phase` keeps `useFocusWrap` attached through the animated-exit
89
+ // window (WCAG 2.4.3 guard). See notes/architecture/focus-restoration.md.
98
90
  useFocusWrap({
99
91
  elementRef: ownRef,
100
92
  role: role,
@@ -191,7 +183,6 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
191
183
 
192
184
  // Browser dismiss (Escape/click-outside).
193
185
  var reason = closeReasonRef.current;
194
- // reset for next dismiss
195
186
  closeReasonRef.current = 'light-dismiss';
196
187
  // Optional: `manual` mode has no `onClose` in the forwarded type.
197
188
  onClose === null || onClose === void 0 || onClose({
@@ -200,21 +191,12 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
200
191
  }
201
192
  }, [onClose, onOpenChange, role]);
202
193
 
203
- // Bind toggle/beforetoggle/keydown listeners via `useLayoutEffect` so
204
- // they are attached BEFORE the show/hide layout effect calls
205
- // `el.showPopover()`. `showPopover()` dispatches `beforetoggle`
206
- // synchronously; binding the listener in a regular `useEffect`
207
- // (which runs after layout effects) misses that first dispatch and
208
- // the `previouslyFocusedElementRef` snapshot never gets taken — which
209
- // breaks nested-popover focus restoration on close.
210
- //
211
- // `isVisible` is in deps so the listeners re-bind to the new host
212
- // element after a host unmount/remount cycle. The cleanup detaches
213
- // the old listeners.
214
- //
215
- // This layout effect MUST appear in the file before the show/hide
216
- // layout effect — React runs layout effects in source order on the
217
- // same commit, and we need listeners attached first.
194
+ // Bind via `useLayoutEffect`, and BEFORE the show/hide layout effect
195
+ // below, so listeners are attached when `showPopover()` synchronously
196
+ // dispatches `beforetoggle`. A regular `useEffect` would miss that
197
+ // first dispatch, dropping the `previouslyFocusedElementRef` snapshot
198
+ // and breaking nested-popover focus restoration on close. React runs
199
+ // layout effects in source order on the same commit.
218
200
  useLayoutEffect(function () {
219
201
  var element = ownRef.current;
220
202
  if (!element) {
@@ -250,13 +232,10 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
250
232
  }, [handleToggle, handleBeforeToggle, isVisible]);
251
233
 
252
234
  // Placement-dependent animation CSS vars. Kept separate from show/hide
253
- // so preset reference changes do not re-trigger visibility. `isVisible`
254
- // is in deps so the CSS vars are re-applied to the new host element after
255
- // a remount cycle (otherwise the freshly mounted element would have no
256
- // transform / placement vars set).
235
+ // so preset reference changes do not re-trigger visibility.
257
236
  useLayoutEffect(function () {
258
- var el = ownRef.current;
259
- if (!el || !(preset !== null && preset !== void 0 && preset.getProperties) || !placement) {
237
+ var element = ownRef.current;
238
+ if (!element || !(preset !== null && preset !== void 0 && preset.getProperties) || !placement) {
260
239
  return;
261
240
  }
262
241
  var props = preset.getProperties({
@@ -266,7 +245,7 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
266
245
  var _ref3 = _slicedToArray(_ref2, 2),
267
246
  key = _ref3[0],
268
247
  value = _ref3[1];
269
- el.style.setProperty(key, String(value));
248
+ element.style.setProperty(key, String(value));
270
249
  });
271
250
  }, [preset, placement, isVisible]);
272
251
 
@@ -274,42 +253,35 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
274
253
  // already in the target state. Try/catch guards `InvalidStateError` on
275
254
  // disconnected elements (StrictMode/concurrent/unmount edge cases).
276
255
  useLayoutEffect(function () {
277
- var el = ownRef.current;
278
- if (!el) {
256
+ var element = ownRef.current;
257
+ if (!element) {
279
258
  return;
280
259
  }
281
260
  if (isOpen) {
282
261
  programmaticCloseRef.current = false;
283
- // Reset the close-reason snapshot at the start of every open
284
- // cycle. The ref outlives the host element (lives on the
285
- // component, not the DOM), so a stale 'escape' from a prior
286
- // cycle would otherwise leak into the next close — especially
287
- // in the no-animation path where the host unmounts before
288
- // `handleToggle` has a chance to reset the ref itself.
262
+ // Clear stale 'escape' from a prior cycle: the ref outlives
263
+ // the host element, and the no-animation path unmounts before
264
+ // `handleToggle` can reset it.
289
265
  closeReasonRef.current = 'light-dismiss';
290
266
  try {
291
- el.showPopover();
267
+ element.showPopover();
292
268
  } catch (_unused) {}
293
269
  return function () {
294
270
  programmaticCloseRef.current = true;
295
271
  try {
296
- el.hidePopover();
272
+ element.hidePopover();
297
273
  } catch (_unused2) {}
298
274
  };
299
275
  }
300
276
  programmaticCloseRef.current = true;
301
277
  try {
302
- el.hidePopover();
278
+ element.hidePopover();
303
279
  } catch (_unused3) {}
304
280
  }, [isOpen]);
305
281
 
306
- // The host element is only rendered while the popover is open or its exit
307
- // animation is playing. Once the phase returns to `closed`, we unmount
308
- // the host entirely so it does not leave an empty `role="..."` /
309
- // `popover` element in the accessibility tree. The element re-mounts on
310
- // the next `isOpen=true` commit; refs and event listeners re-bind via
311
- // the existing layout effect and `useEffect`. The popover `id` is stable
312
- // across opens (derived from `useId()` or the consumer-supplied `idProp`).
282
+ // Unmount the host once exit completes so it does not leave an empty
283
+ // `role`/`popover` element in the accessibility tree. The element
284
+ // remounts on the next open; the `popoverId` is stable across opens.
313
285
  if (!isVisible) {
314
286
  return null;
315
287
  }
@@ -1,7 +1,7 @@
1
1
  /* popover-surface.tsx generated by @compiled/babel-plugin v0.39.1 */
2
2
  import "./popover-surface.compiled.css";
3
+ import * as React from 'react';
3
4
  import { ax, ix } from "@compiled/react/runtime";
4
- import React from 'react';
5
5
  var styles = {
6
6
  root: "_2rkofajl _1reo1wug _18m91wug _bfhk1bhr _16qs130s"
7
7
  };
@@ -352,17 +352,17 @@ function isInChainTo(_ref12) {
352
352
  function hidePopoversInStackNotInChainTo(_ref13) {
353
353
  var stack = _ref13.stack,
354
354
  target = _ref13.target;
355
- var snapshot = stack.slice();
356
- for (var i = snapshot.length - 1; i >= 0; i -= 1) {
357
- var popover = snapshot[i];
358
- if (isInChainTo({
355
+ var snapshot = stack.slice().reverse();
356
+ var stopIndex = snapshot.findIndex(function (popover) {
357
+ return isInChainTo({
359
358
  candidate: popover,
360
359
  target: target
361
- })) {
362
- break;
363
- }
364
- popover.hidePopover();
365
- }
360
+ });
361
+ });
362
+ var toHide = stopIndex === -1 ? snapshot : snapshot.slice(0, stopIndex);
363
+ toHide.forEach(function (popover) {
364
+ return popover.hidePopover();
365
+ });
366
366
  }
367
367
 
368
368
  // Two-phase light-dismiss: pointerdown stores the nearest open popover for
@@ -53,13 +53,13 @@ export function useSimpleLightDismiss(_ref) {
53
53
  var unbindClickOutside = bind(document, {
54
54
  type: 'click',
55
55
  listener: function listener(event) {
56
- var el = popoverRef.current;
57
- if (!el) {
56
+ var element = popoverRef.current;
57
+ if (!element) {
58
58
  return;
59
59
  }
60
60
 
61
61
  // If the click target is inside the popover, do not dismiss.
62
- if (event.target instanceof Node && el.contains(event.target)) {
62
+ if (event.target instanceof Node && element.contains(event.target)) {
63
63
  return;
64
64
  }
65
65
  onCloseRef.current({
@@ -1,4 +1,5 @@
1
1
  import { type TAnimationPreset } from './types';
2
+ export declare function popupMotion(): TAnimationPreset;
2
3
  type TSlideAndFadeOptions = {
3
4
  /**
4
5
  * Slide distance in pixels. Defaults to `4`.
@@ -51,6 +52,21 @@ export declare function fade(): TAnimationPreset;
51
52
  * ```
52
53
  */
53
54
  export declare function scaleAndFade(): TAnimationPreset;
55
+ /**
56
+ * Dialog motion animation.
57
+ *
58
+ * Includes backdrop fade animation.
59
+ *
60
+ * @example
61
+ * ```tsx
62
+ * import { dialogMotion } from '@atlaskit/top-layer/animations';
63
+ *
64
+ * <Dialog animate={dialogMotion()} isOpen={isOpen} onClose={handleClose} label="...">
65
+ * ...
66
+ * </Dialog>
67
+ * ```
68
+ */
69
+ export declare function dialogMotion(): TAnimationPreset;
54
70
  type TDialogSlideUpAndFadeOptions = {
55
71
  /**
56
72
  * Slide distance in pixels. Defaults to `12`.