@atlaskit/top-layer 0.11.0 → 0.12.1

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 (96) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cjs/animations/presets.js +5 -0
  3. package/dist/cjs/entry-points/use-arrow-navigation.js +3 -2
  4. package/dist/cjs/internal/placement-to-position-area.js +43 -0
  5. package/dist/cjs/internal/placement-to-try-fallbacks.js +82 -0
  6. package/dist/cjs/internal/use-anchor-position.js +18 -131
  7. package/dist/cjs/internal/use-animated-visibility.js +84 -7
  8. package/dist/cjs/popover/popover.js +2 -0
  9. package/dist/cjs/popup/popup-content.js +55 -15
  10. package/dist/cjs/popup/popup-context.js +14 -33
  11. package/dist/cjs/popup/popup-provider.js +15 -0
  12. package/dist/cjs/popup/popup-trigger-function.js +9 -6
  13. package/dist/cjs/popup/popup-trigger.js +14 -9
  14. package/dist/cjs/popup/popup.js +7 -7
  15. package/dist/cjs/popup/use-maybe-popup-context.js +17 -0
  16. package/dist/cjs/popup/use-popup-context.js +20 -0
  17. package/dist/cjs/use-arrow-navigation/index.js +3 -2
  18. package/dist/cjs/use-arrow-navigation/is-at-current-menu-level.js +87 -0
  19. package/dist/cjs/use-arrow-navigation/use-arrow-navigation.js +0 -82
  20. package/dist/es2019/animations/presets.js +5 -0
  21. package/dist/es2019/entry-points/use-arrow-navigation.js +2 -1
  22. package/dist/es2019/internal/placement-to-position-area.js +40 -0
  23. package/dist/es2019/internal/placement-to-try-fallbacks.js +77 -0
  24. package/dist/es2019/internal/use-anchor-position.js +2 -116
  25. package/dist/es2019/internal/use-animated-visibility.js +84 -7
  26. package/dist/es2019/popover/popover.js +2 -0
  27. package/dist/es2019/popup/popup-content.js +55 -14
  28. package/dist/es2019/popup/popup-context.js +14 -30
  29. package/dist/es2019/popup/popup-provider.js +10 -0
  30. package/dist/es2019/popup/popup-trigger-function.js +8 -5
  31. package/dist/es2019/popup/popup-trigger.js +14 -8
  32. package/dist/es2019/popup/popup.js +4 -4
  33. package/dist/es2019/popup/use-maybe-popup-context.js +12 -0
  34. package/dist/es2019/popup/use-popup-context.js +15 -0
  35. package/dist/es2019/use-arrow-navigation/index.js +2 -1
  36. package/dist/es2019/use-arrow-navigation/is-at-current-menu-level.js +81 -0
  37. package/dist/es2019/use-arrow-navigation/use-arrow-navigation.js +0 -81
  38. package/dist/esm/animations/presets.js +5 -0
  39. package/dist/esm/entry-points/use-arrow-navigation.js +2 -1
  40. package/dist/esm/internal/placement-to-position-area.js +38 -0
  41. package/dist/esm/internal/placement-to-try-fallbacks.js +76 -0
  42. package/dist/esm/internal/use-anchor-position.js +16 -127
  43. package/dist/esm/internal/use-animated-visibility.js +84 -7
  44. package/dist/esm/popover/popover.js +2 -0
  45. package/dist/esm/popup/popup-content.js +55 -14
  46. package/dist/esm/popup/popup-context.js +14 -30
  47. package/dist/esm/popup/popup-provider.js +10 -0
  48. package/dist/esm/popup/popup-trigger-function.js +8 -5
  49. package/dist/esm/popup/popup-trigger.js +14 -8
  50. package/dist/esm/popup/popup.js +6 -6
  51. package/dist/esm/popup/use-maybe-popup-context.js +12 -0
  52. package/dist/esm/popup/use-popup-context.js +15 -0
  53. package/dist/esm/use-arrow-navigation/index.js +2 -1
  54. package/dist/esm/use-arrow-navigation/is-at-current-menu-level.js +81 -0
  55. package/dist/esm/use-arrow-navigation/use-arrow-navigation.js +0 -81
  56. package/dist/types/animations/types.d.ts +5 -1
  57. package/dist/types/entry-points/use-arrow-navigation.d.ts +2 -1
  58. package/dist/types/internal/placement-to-position-area.d.ts +21 -0
  59. package/dist/types/internal/placement-to-try-fallbacks.d.ts +36 -0
  60. package/dist/types/internal/use-anchor-position.d.ts +0 -55
  61. package/dist/types/internal/use-animated-visibility.d.ts +8 -2
  62. package/dist/types/popover/types.d.ts +8 -0
  63. package/dist/types/popup/popup-context.d.ts +25 -25
  64. package/dist/types/popup/popup-provider.d.ts +10 -0
  65. package/dist/types/popup/types.d.ts +12 -0
  66. package/dist/types/popup/use-maybe-popup-context.d.ts +8 -0
  67. package/dist/types/popup/use-popup-context.d.ts +7 -0
  68. package/dist/types/use-arrow-navigation/index.d.ts +2 -1
  69. package/dist/types/use-arrow-navigation/is-at-current-menu-level.d.ts +48 -0
  70. package/dist/types/use-arrow-navigation/use-arrow-navigation.d.ts +0 -48
  71. package/dist/types-ts4.5/animations/types.d.ts +5 -1
  72. package/dist/types-ts4.5/entry-points/use-arrow-navigation.d.ts +2 -1
  73. package/dist/types-ts4.5/internal/placement-to-position-area.d.ts +21 -0
  74. package/dist/types-ts4.5/internal/placement-to-try-fallbacks.d.ts +36 -0
  75. package/dist/types-ts4.5/internal/use-anchor-position.d.ts +0 -55
  76. package/dist/types-ts4.5/internal/use-animated-visibility.d.ts +8 -2
  77. package/dist/types-ts4.5/popover/types.d.ts +8 -0
  78. package/dist/types-ts4.5/popup/popup-context.d.ts +25 -25
  79. package/dist/types-ts4.5/popup/popup-provider.d.ts +10 -0
  80. package/dist/types-ts4.5/popup/types.d.ts +12 -0
  81. package/dist/types-ts4.5/popup/use-maybe-popup-context.d.ts +8 -0
  82. package/dist/types-ts4.5/popup/use-popup-context.d.ts +7 -0
  83. package/dist/types-ts4.5/use-arrow-navigation/index.d.ts +2 -1
  84. package/dist/types-ts4.5/use-arrow-navigation/is-at-current-menu-level.d.ts +48 -0
  85. package/dist/types-ts4.5/use-arrow-navigation/use-arrow-navigation.d.ts +0 -48
  86. package/package.json +2 -2
  87. package/dist/cjs/arrow/index.js +0 -131
  88. package/dist/cjs/arrow/types.js +0 -5
  89. package/dist/es2019/arrow/index.js +0 -269
  90. package/dist/es2019/arrow/types.js +0 -1
  91. package/dist/esm/arrow/index.js +0 -124
  92. package/dist/esm/arrow/types.js +0 -1
  93. package/dist/types/arrow/index.d.ts +0 -24
  94. package/dist/types/arrow/types.d.ts +0 -29
  95. package/dist/types-ts4.5/arrow/index.d.ts +0 -24
  96. package/dist/types-ts4.5/arrow/types.d.ts +0 -29
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 0.12.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`c3913985e2415`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c3913985e2415) -
8
+ Internal: remove unused `src/arrow/` module. The `arrow()` preset and `TArrowPreset` type were
9
+ never exported from `package.json` and had no consumers in the codebase.
10
+
11
+ ## 0.12.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [`cc76d2e733b71`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/cc76d2e733b71) - -
16
+ The prop `onEnterFinish` has been added to `Popup.Content` and `Popover`, for lifecycle
17
+ coordination after the entry animation completes.
18
+ - The prop `onExitFinish` has been added to `Popup.Content`, for lifecycle coordination after the
19
+ exit animation completes. `Popover` already exposed this prop.
20
+
21
+ - Updates the popup trigger's `aria-expanded` attribute, so it stays `"true"` for the full
22
+ duration of the popup's open and close animations, only going `false` after the exit animation
23
+ completes.
24
+
25
+ - Internal refactor to the popup context to use a string union for state.
26
+
3
27
  ## 0.11.0
4
28
 
5
29
  ### Minor Changes
@@ -86,6 +86,7 @@ function slideAndFade(options) {
86
86
  distance: distance
87
87
  });
88
88
  },
89
+ enterDurationMs: 350,
89
90
  exitDurationMs: 175
90
91
  };
91
92
  }
@@ -111,6 +112,7 @@ function fade() {
111
112
  return {
112
113
  name: 'fade',
113
114
  css: FADE_CSS,
115
+ enterDurationMs: 350,
114
116
  exitDurationMs: 175
115
117
  };
116
118
  }
@@ -136,6 +138,7 @@ function scaleAndFade() {
136
138
  return {
137
139
  name: 'scale-and-fade',
138
140
  css: SCALE_AND_FADE_CSS,
141
+ enterDurationMs: 350,
139
142
  exitDurationMs: 175
140
143
  };
141
144
  }
@@ -175,6 +178,7 @@ function dialogSlideUpAndFade(options) {
175
178
  return {
176
179
  name: distance === 12 ? 'slide-up-and-fade' : "slide-up-and-fade-".concat(distance),
177
180
  css: distance === 12 ? DIALOG_SLIDE_UP_AND_FADE_CSS : DIALOG_SLIDE_UP_AND_FADE_CSS.replace(/12px/g, "".concat(distance, "px")),
181
+ enterDurationMs: 350,
178
182
  exitDurationMs: 175
179
183
  };
180
184
  }
@@ -203,6 +207,7 @@ function dialogFade() {
203
207
  return {
204
208
  name: 'fade',
205
209
  css: DIALOG_FADE_CSS,
210
+ enterDurationMs: 350,
206
211
  exitDurationMs: 175
207
212
  };
208
213
  }
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  Object.defineProperty(exports, "isAtCurrentMenuLevel", {
7
7
  enumerable: true,
8
8
  get: function get() {
9
- return _useArrowNavigation.isAtCurrentMenuLevel;
9
+ return _isAtCurrentMenuLevel.isAtCurrentMenuLevel;
10
10
  }
11
11
  });
12
12
  Object.defineProperty(exports, "useArrowNavigation", {
@@ -15,4 +15,5 @@ Object.defineProperty(exports, "useArrowNavigation", {
15
15
  return _useArrowNavigation.useArrowNavigation;
16
16
  }
17
17
  });
18
- var _useArrowNavigation = require("../use-arrow-navigation");
18
+ var _useArrowNavigation = require("../use-arrow-navigation");
19
+ var _isAtCurrentMenuLevel = require("../use-arrow-navigation/is-at-current-menu-level");
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.placementToPositionArea = placementToPositionArea;
7
+ var _resolvePlacement = require("./resolve-placement");
8
+ /**
9
+ * Resolves placement options to CSS `position-area` syntax.
10
+ *
11
+ * The `align` field represents the *visual* alignment:
12
+ * - `align: 'start'` means "aligned to the trigger's start edge" (left in LTR for block axis)
13
+ * - `align: 'end'` means "aligned to the trigger's end edge"
14
+ * - `align: 'center'` means centered (single-axis position-area)
15
+ *
16
+ * CSS `position-area` uses `span-*` keywords which indicate the *expansion direction*.
17
+ * Visual start-alignment requires `span-{cross-axis}-end` (expand toward end = start-aligned).
18
+ * This function handles the inversion internally.
19
+ *
20
+ * @example
21
+ * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'center' } }) // → 'block-end'
22
+ * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'start' } }) // → 'block-end span-inline-end'
23
+ * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'end' } }) // → 'block-end span-inline-start'
24
+ */
25
+ function placementToPositionArea(_ref) {
26
+ var placement = _ref.placement;
27
+ var _getPlacement = (0, _resolvePlacement.getPlacement)({
28
+ placement: placement
29
+ }),
30
+ axis = _getPlacement.axis,
31
+ edge = _getPlacement.edge,
32
+ align = _getPlacement.align;
33
+ var edgeValue = "".concat(axis, "-").concat(edge);
34
+ if (align === 'center') {
35
+ return edgeValue;
36
+ }
37
+
38
+ // Cross-axis name: block ↔ inline
39
+ var crossAxis = axis === 'block' ? 'inline' : 'block';
40
+ // Invert align → CSS span direction: visual 'start' → span toward 'end'
41
+ var spanDir = align === 'start' ? 'end' : 'start';
42
+ return "".concat(edgeValue, " span-").concat(crossAxis, "-").concat(spanDir);
43
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.placementToTryFallbacks = placementToTryFallbacks;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ var _resolvePlacement = require("./resolve-placement");
10
+ /**
11
+ * Returns `position-try-fallbacks` value based on placement.
12
+ *
13
+ * For centered placements, includes cross-axis aligned position-area
14
+ * values so the browser can shift the popover along the cross-axis
15
+ * when the centered position would overflow the viewport edge.
16
+ *
17
+ * Fallback order for centered placements (e.g. `block-end`):
18
+ * 1. Same edge, start-aligned (shift for near-edge overflow)
19
+ * 2. Same edge, end-aligned (shift for far-edge overflow)
20
+ * 3. Flipped edge, centered
21
+ * 4. Flipped edge, start-aligned
22
+ * 5. Flipped edge, end-aligned
23
+ *
24
+ * For aligned placements (start/end), includes the same-edge centered
25
+ * position as fallbacks so the browser can try centering when the aligned
26
+ * position would overflow, before flipping to the opposite edge.
27
+ *
28
+ * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
29
+ *
30
+ * When a popup is in a viewport corner (e.g. inline-end align-end at the
31
+ * top-right), flipping only the primary axis (`flip-inline`) moves the popup
32
+ * to the left but keeps the same cross-axis span direction (e.g. upward),
33
+ * which is still off-screen. The combined keyword `flip-inline flip-block`
34
+ * mirrors the popup diagonally. It flips BOTH the position-area AND both
35
+ * inline and block margins simultaneously, placing the popup at the
36
+ * diagonally opposite corner where there is always space.
37
+ *
38
+ * Named `position-area` entries (e.g. `inline-start span-block-end`) in
39
+ * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
40
+ * tactic keywords correctly flip the gap margin along with the position.
41
+ */
42
+ function placementToTryFallbacks(_ref) {
43
+ var placement = _ref.placement;
44
+ var _getPlacement = (0, _resolvePlacement.getPlacement)({
45
+ placement: placement
46
+ }),
47
+ axis = _getPlacement.axis,
48
+ edge = _getPlacement.edge,
49
+ align = _getPlacement.align;
50
+ var crossAxis = axis === 'block' ? 'inline' : 'block';
51
+ var flippedEdge = edge === 'start' ? 'end' : 'start';
52
+ var sameEdge = "".concat(axis, "-").concat(edge);
53
+ var oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
54
+ var flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
55
+ var flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
56
+
57
+ // Single algorithm: produce the shift list against any base alignment.
58
+ // For `align: 'start'` the "near" shift expands toward `end`; for
59
+ // `align: 'end'` it expands toward `start`; for `align: 'center'`
60
+ // either order is symmetric (we use end-then-start to match the
61
+ // historical fallback list).
62
+ function shifts(baseAlign, edgeKey) {
63
+ if (baseAlign === 'center') {
64
+ return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
65
+ }
66
+ var near = baseAlign === 'start' ? 'end' : 'start';
67
+ var far = baseAlign === 'start' ? 'start' : 'end';
68
+ return ["".concat(edgeKey, " span-").concat(crossAxis, "-").concat(near), edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
69
+ }
70
+ if (align !== 'center') {
71
+ // Aligned (start/end): try same-edge shifts, then single-axis flip,
72
+ // then diagonal flip for corner overflow, then opposite-edge shifts.
73
+ // Legacy Popper fallback ordering for e.g. bottom-start:
74
+ // [bottom, bottom-end, top-start, top, top-end, auto].
75
+ return [].concat((0, _toConsumableArray2.default)(shifts(align, sameEdge)), [flipKeyword, "".concat(flipKeyword, " ").concat(flipCrossKeyword)], (0, _toConsumableArray2.default)(shifts(align, oppositeEdge))).join(', ');
76
+ }
77
+
78
+ // Centered: same-edge shifts, single-axis flip, opposite-edge shifts.
79
+ // Diagonal flip is unnecessary because centered placements expand
80
+ // equally in both cross-axis directions.
81
+ return [].concat((0, _toConsumableArray2.default)(shifts('center', sameEdge)), [flipKeyword], (0, _toConsumableArray2.default)(shifts('center', oppositeEdge))).join(', ');
82
+ }
@@ -4,10 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.placementToPositionArea = placementToPositionArea;
8
- exports.placementToTryFallbacks = placementToTryFallbacks;
9
7
  exports.useAnchorPosition = useAnchorPosition;
10
- var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
11
8
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
12
9
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
13
10
  var _react = require("react");
@@ -16,6 +13,8 @@ var _rafSchd = _interopRequireDefault(require("raf-schd"));
16
13
  var _once = _interopRequireDefault(require("@atlaskit/ds-lib/once"));
17
14
  var _anchorPositioningFallback = require("./anchor-positioning-fallback");
18
15
  var _combine = require("./combine");
16
+ var _placementToPositionArea = require("./placement-to-position-area");
17
+ var _placementToTryFallbacks = require("./placement-to-try-fallbacks");
19
18
  var _resolveCssLengthToPixels = require("./resolve-css-length-to-pixels");
20
19
  var _resolvePlacement = require("./resolve-placement");
21
20
  var _setStyle = require("./set-style");
@@ -58,118 +57,6 @@ var NoopResizeObserver = /*#__PURE__*/function () {
58
57
  }]);
59
58
  }();
60
59
 
61
- /**
62
- * Resolves placement options to CSS `position-area` syntax.
63
- *
64
- * The `align` field represents the *visual* alignment:
65
- * - `align: 'start'` means "aligned to the trigger's start edge" (left in LTR for block axis)
66
- * - `align: 'end'` means "aligned to the trigger's end edge"
67
- * - `align: 'center'` means centered (single-axis position-area)
68
- *
69
- * CSS `position-area` uses `span-*` keywords which indicate the *expansion direction*.
70
- * Visual start-alignment requires `span-{cross-axis}-end` (expand toward end = start-aligned).
71
- * This function handles the inversion internally.
72
- *
73
- * @example
74
- * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'center' } }) // → 'block-end'
75
- * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'start' } }) // → 'block-end span-inline-end'
76
- * placementToPositionArea({ placement: { axis: 'block', edge: 'end', align: 'end' } }) // → 'block-end span-inline-start'
77
- */
78
- function placementToPositionArea(_ref) {
79
- var placement = _ref.placement;
80
- var _getPlacement = (0, _resolvePlacement.getPlacement)({
81
- placement: placement
82
- }),
83
- axis = _getPlacement.axis,
84
- edge = _getPlacement.edge,
85
- align = _getPlacement.align;
86
- var edgeValue = "".concat(axis, "-").concat(edge);
87
- if (align === 'center') {
88
- return edgeValue;
89
- }
90
-
91
- // Cross-axis name: block ↔ inline
92
- var crossAxis = axis === 'block' ? 'inline' : 'block';
93
- // Invert align → CSS span direction: visual 'start' → span toward 'end'
94
- var spanDir = align === 'start' ? 'end' : 'start';
95
- return "".concat(edgeValue, " span-").concat(crossAxis, "-").concat(spanDir);
96
- }
97
-
98
- /**
99
- * Returns `position-try-fallbacks` value based on placement.
100
- *
101
- * For centered placements, includes cross-axis aligned position-area
102
- * values so the browser can shift the popover along the cross-axis
103
- * when the centered position would overflow the viewport edge.
104
- *
105
- * Fallback order for centered placements (e.g. `block-end`):
106
- * 1. Same edge, start-aligned (shift for near-edge overflow)
107
- * 2. Same edge, end-aligned (shift for far-edge overflow)
108
- * 3. Flipped edge, centered
109
- * 4. Flipped edge, start-aligned
110
- * 5. Flipped edge, end-aligned
111
- *
112
- * For aligned placements (start/end), includes the same-edge centered
113
- * position as fallbacks so the browser can try centering when the aligned
114
- * position would overflow, before flipping to the opposite edge.
115
- *
116
- * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
117
- *
118
- * When a popup is in a viewport corner (e.g. inline-end align-end at the
119
- * top-right), flipping only the primary axis (`flip-inline`) moves the popup
120
- * to the left but keeps the same cross-axis span direction (e.g. upward),
121
- * which is still off-screen. The combined keyword `flip-inline flip-block`
122
- * mirrors the popup diagonally. It flips BOTH the position-area AND both
123
- * inline and block margins simultaneously, placing the popup at the
124
- * diagonally opposite corner where there is always space.
125
- *
126
- * Named `position-area` entries (e.g. `inline-start span-block-end`) in
127
- * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
128
- * tactic keywords correctly flip the gap margin along with the position.
129
- */
130
- // eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
131
- function placementToTryFallbacks(_ref2) {
132
- var placement = _ref2.placement;
133
- var _getPlacement2 = (0, _resolvePlacement.getPlacement)({
134
- placement: placement
135
- }),
136
- axis = _getPlacement2.axis,
137
- edge = _getPlacement2.edge,
138
- align = _getPlacement2.align;
139
- var crossAxis = axis === 'block' ? 'inline' : 'block';
140
- var flippedEdge = edge === 'start' ? 'end' : 'start';
141
- var sameEdge = "".concat(axis, "-").concat(edge);
142
- var oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
143
- var flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
144
- var flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
145
-
146
- // Single algorithm: produce the shift list against any base alignment.
147
- // For `align: 'start'` the "near" shift expands toward `end`; for
148
- // `align: 'end'` it expands toward `start`; for `align: 'center'`
149
- // either order is symmetric (we use end-then-start to match the
150
- // historical fallback list).
151
- function shifts(baseAlign, edgeKey) {
152
- if (baseAlign === 'center') {
153
- return ["".concat(edgeKey, " span-").concat(crossAxis, "-end"), "".concat(edgeKey, " span-").concat(crossAxis, "-start")];
154
- }
155
- var near = baseAlign === 'start' ? 'end' : 'start';
156
- var far = baseAlign === 'start' ? 'start' : 'end';
157
- return ["".concat(edgeKey, " span-").concat(crossAxis, "-").concat(near), edgeKey, "".concat(edgeKey, " span-").concat(crossAxis, "-").concat(far)];
158
- }
159
- if (align !== 'center') {
160
- // Aligned (start/end): try same-edge shifts, then single-axis flip,
161
- // then diagonal flip for corner overflow, then opposite-edge shifts.
162
- // Legacy Popper fallback ordering for e.g. bottom-start:
163
- // [bottom, bottom-end, top-start, top, top-end, auto].
164
- return [].concat((0, _toConsumableArray2.default)(shifts(align, sameEdge)), [flipKeyword, "".concat(flipKeyword, " ").concat(flipCrossKeyword)], (0, _toConsumableArray2.default)(shifts(align, oppositeEdge))).join(', ');
165
- }
166
-
167
- // Centered: same-edge shifts, single-axis flip, opposite-edge shifts.
168
- // Diagonal flip is unnecessary because centered placements expand
169
- // equally in both cross-axis directions.
170
- return [].concat((0, _toConsumableArray2.default)(shifts('center', sameEdge)), [flipKeyword], (0, _toConsumableArray2.default)(shifts('center', oppositeEdge))).join(', ');
171
- }
172
-
173
60
  /**
174
61
  * Returns true when the popover is currently open. Wrapped because the
175
62
  * `:popover-open` pseudo-class is not implemented in some test environments
@@ -201,9 +88,9 @@ var supportsAnchorPositioning = (0, _once.default)(function () {
201
88
  * For example, a `block-end` placement (popover below) gets
202
89
  * `margin-block-start: 8px` to push it away from the trigger's bottom edge.
203
90
  */
204
- function edgeMargin(_ref3) {
205
- var placement = _ref3.placement,
206
- offset = _ref3.offset;
91
+ function edgeMargin(_ref) {
92
+ var placement = _ref.placement,
93
+ offset = _ref.offset;
207
94
  var axis = placement.axis,
208
95
  edge = placement.edge;
209
96
  var value = offset;
@@ -244,10 +131,10 @@ function edgeMargin(_ref3) {
244
131
  * positive), `align: 'center'` uses START. Margin on the un-anchored side
245
132
  * has no effect under CSS Anchor Positioning.
246
133
  */
247
- function crossAxisShiftMargin(_ref4) {
248
- var placement = _ref4.placement,
249
- crossAxisShiftCssValue = _ref4.crossAxisShiftCssValue,
250
- direction = _ref4.direction;
134
+ function crossAxisShiftMargin(_ref2) {
135
+ var placement = _ref2.placement,
136
+ crossAxisShiftCssValue = _ref2.crossAxisShiftCssValue,
137
+ direction = _ref2.direction;
251
138
  var axis = placement.axis,
252
139
  align = placement.align;
253
140
  var directionSign = direction === 'forwards' ? 1 : -1;
@@ -326,13 +213,13 @@ function useStablePlacement(placement) {
326
213
  * placement shape is unchanged.
327
214
  */
328
215
  // eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
329
- function useAnchorPosition(_ref5) {
330
- var anchorRef = _ref5.anchorRef,
331
- popoverRef = _ref5.popoverRef,
332
- _ref5$placement = _ref5.placement,
333
- placement = _ref5$placement === void 0 ? {} : _ref5$placement,
334
- _ref5$forceFallbackPo = _ref5.forceFallbackPositioning,
335
- forceFallbackPositioning = _ref5$forceFallbackPo === void 0 ? false : _ref5$forceFallbackPo;
216
+ function useAnchorPosition(_ref3) {
217
+ var anchorRef = _ref3.anchorRef,
218
+ popoverRef = _ref3.popoverRef,
219
+ _ref3$placement = _ref3.placement,
220
+ placement = _ref3$placement === void 0 ? {} : _ref3$placement,
221
+ _ref3$forceFallbackPo = _ref3.forceFallbackPositioning,
222
+ forceFallbackPositioning = _ref3$forceFallbackPo === void 0 ? false : _ref3$forceFallbackPo;
336
223
  var id = (0, _react.useId)();
337
224
  // Stabilize `placement` object so the same object literal
338
225
  // value returns an object with the same reference
@@ -367,12 +254,12 @@ function useAnchorPosition(_ref5) {
367
254
  value: anchorName
368
255
  }, {
369
256
  property: 'position-area',
370
- value: placementToPositionArea({
257
+ value: (0, _placementToPositionArea.placementToPositionArea)({
371
258
  placement: stablePlacement
372
259
  })
373
260
  }, {
374
261
  property: 'position-try-fallbacks',
375
- value: placementToTryFallbacks({
262
+ value: (0, _placementToTryFallbacks.placementToTryFallbacks)({
376
263
  placement: stablePlacement
377
264
  })
378
265
  },
@@ -51,6 +51,7 @@ function useAnimatedVisibility(_ref) {
51
51
  var isOpen = _ref.isOpen,
52
52
  animate = _ref.animate,
53
53
  elementRef = _ref.elementRef,
54
+ onEnterFinish = _ref.onEnterFinish,
54
55
  onExitFinish = _ref.onExitFinish;
55
56
  // Resolve the animation preset and inject its CSS (idempotent).
56
57
  // Returns `null` when `animate` is falsy.
@@ -87,13 +88,76 @@ function useAnimatedVisibility(_ref) {
87
88
  setShowChildren(false);
88
89
  }
89
90
 
90
- // Keep a stable ref to the latest `onExitFinish` so the effect and
91
- // timeout closures below always call the current callback without
92
- // needing `onExitFinish` in dependency arrays (which would reset
93
- // the timeout on every new closure).
91
+ // Keep stable refs to the latest callbacks so effects and timeout closures
92
+ // always call the current callback without needing them in dependency arrays.
93
+ var onEnterFinishRef = (0, _react.useRef)(onEnterFinish);
94
+ onEnterFinishRef.current = onEnterFinish;
94
95
  var onExitFinishRef = (0, _react.useRef)(onExitFinish);
95
96
  onExitFinishRef.current = onExitFinish;
96
97
 
98
+ // ── Animated entry effect ──
99
+ //
100
+ // Fires `onEnterFinish` after the entry transition completes.
101
+ // When there is no animation, fires it immediately via a separate effect.
102
+ //
103
+ // A fallback timeout (enterDurationMs + 50ms buffer) ensures it always
104
+ // fires even if `transitionend` is never emitted (e.g. zero-duration,
105
+ // browser quirk, or reduced motion).
106
+ (0, _react.useEffect)(function () {
107
+ var _preset$enterDuration;
108
+ if (!isOpen || !showChildren || !willAnimate) {
109
+ return;
110
+ }
111
+ var element = elementRef.current;
112
+ if (!element) {
113
+ return;
114
+ }
115
+
116
+ // Both the transitionend listener and the fallback timeout are guarded by
117
+ // a shared `hasFired` flag to prevent double-firing. This handles the race
118
+ // where the 350ms transition finishes after the 400ms fallback fires
119
+ // (or vice versa): whichever fires first sets `hasFired = true`, and the
120
+ // second path becomes a no-op.
121
+ var hasFired = false;
122
+ function handleTransitionEnd() {
123
+ var _onEnterFinishRef$cur;
124
+ if (hasFired) {
125
+ return;
126
+ }
127
+ hasFired = true;
128
+ clearTimeout(fallbackId);
129
+ unbind();
130
+ (_onEnterFinishRef$cur = onEnterFinishRef.current) === null || _onEnterFinishRef$cur === void 0 || _onEnterFinishRef$cur.call(onEnterFinishRef);
131
+ }
132
+ var fallbackId = setTimeout(handleTransitionEnd, ((_preset$enterDuration = preset === null || preset === void 0 ? void 0 : preset.enterDurationMs) !== null && _preset$enterDuration !== void 0 ? _preset$enterDuration : 0) + 50);
133
+ var unbind = (0, _bindEventListener.bind)(element, {
134
+ type: 'transitionend',
135
+ listener: handleTransitionEnd,
136
+ options: {
137
+ once: true
138
+ }
139
+ });
140
+ return function () {
141
+ hasFired = true;
142
+ clearTimeout(fallbackId);
143
+ unbind();
144
+ };
145
+ }, [isOpen, showChildren, willAnimate, preset === null || preset === void 0 ? void 0 : preset.enterDurationMs, elementRef]);
146
+
147
+ // ── Non-animated entry callback ──
148
+ //
149
+ // When there is no animation, fire `onEnterFinish` immediately on mount and after `isOpen` goes false->true.
150
+ // The initial value is false to make sure it fires on mount if the current `isOpen` is true.
151
+ var prevIsOpenForEntryRef = (0, _react.useRef)(false);
152
+ (0, _react.useEffect)(function () {
153
+ var prevIsOpen = prevIsOpenForEntryRef.current;
154
+ prevIsOpenForEntryRef.current = isOpen;
155
+ if (!prevIsOpen && isOpen && !willAnimate) {
156
+ var _onEnterFinishRef$cur2;
157
+ (_onEnterFinishRef$cur2 = onEnterFinishRef.current) === null || _onEnterFinishRef$cur2 === void 0 || _onEnterFinishRef$cur2.call(onEnterFinishRef);
158
+ }
159
+ }, [isOpen, willAnimate]);
160
+
97
161
  // ── Animated exit effect ──
98
162
  //
99
163
  // Runs when all three conditions are true:
@@ -118,20 +182,32 @@ function useAnimatedVisibility(_ref) {
118
182
  if (!element) {
119
183
  return;
120
184
  }
121
- function finish() {
185
+
186
+ // Both the transitionend listener and the fallback timeout are guarded by
187
+ // a shared `hasFired` flag to prevent double-firing. This handles the race
188
+ // where the 350ms transition finishes after the 400ms fallback fires
189
+ // (or vice versa): whichever fires first sets `hasFired = true`, and the
190
+ // second path becomes a no-op.
191
+ var hasFired = false;
192
+ function handleTransitionEnd() {
122
193
  var _onExitFinishRef$curr;
194
+ if (hasFired) {
195
+ return;
196
+ }
197
+ hasFired = true;
123
198
  clearTimeout(fallbackId);
199
+ unbind();
124
200
  setShowChildren(false);
125
201
  (_onExitFinishRef$curr = onExitFinishRef.current) === null || _onExitFinishRef$curr === void 0 || _onExitFinishRef$curr.call(onExitFinishRef);
126
202
  }
127
203
 
128
204
  // Fallback: unmount even if transitionend never fires
129
- var fallbackId = setTimeout(finish, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
205
+ var fallbackId = setTimeout(handleTransitionEnd, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
130
206
 
131
207
  // Primary: listen for the CSS transition to complete
132
208
  var unbind = (0, _bindEventListener.bind)(element, {
133
209
  type: 'transitionend',
134
- listener: finish,
210
+ listener: handleTransitionEnd,
135
211
  options: {
136
212
  once: true
137
213
  }
@@ -139,6 +215,7 @@ function useAnimatedVisibility(_ref) {
139
215
 
140
216
  // Cleanup on re-render or unmount: cancel pending timeout and listener
141
217
  return function () {
218
+ hasFired = true;
142
219
  clearTimeout(fallbackId);
143
220
  unbind();
144
221
  };
@@ -75,6 +75,7 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
75
75
  modeProp = _ref$mode === void 0 ? 'auto' : _ref$mode,
76
76
  onClose = _ref.onClose,
77
77
  onOpenChange = _ref.onOpenChange,
78
+ onEnterFinish = _ref.onEnterFinish,
78
79
  onExitFinish = _ref.onExitFinish,
79
80
  animate = _ref.animate,
80
81
  placement = _ref.placement,
@@ -98,6 +99,7 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
98
99
  isOpen: isOpen,
99
100
  animate: animate,
100
101
  elementRef: ownRef,
102
+ onEnterFinish: onEnterFinish,
101
103
  onExitFinish: onExitFinish
102
104
  }),
103
105
  showChildren = _useAnimatedVisibilit.showChildren,