@atlaskit/top-layer 0.6.1 → 0.6.2

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 (51) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +2 -4
  3. package/dist/cjs/arrow/index.js +2 -2
  4. package/dist/cjs/dialog/dialog-content.js +1 -6
  5. package/dist/cjs/focus/focus.js +4 -4
  6. package/dist/cjs/internal/combine.js +2 -2
  7. package/dist/cjs/internal/use-anchor-position.js +24 -27
  8. package/dist/cjs/internal/use-animated-visibility.js +3 -3
  9. package/dist/cjs/internal/use-focus-wrap.js +7 -7
  10. package/dist/cjs/internal/use-initial-focus.js +1 -1
  11. package/dist/cjs/popover/popover.js +9 -9
  12. package/dist/cjs/popup/popup-content.js +2 -2
  13. package/dist/cjs/popup/popup-trigger.js +2 -2
  14. package/dist/cjs/use-simple-light-dismiss/index.js +1 -1
  15. package/dist/es2019/arrow/index.js +2 -2
  16. package/dist/es2019/dialog/dialog-content.js +1 -6
  17. package/dist/es2019/focus/focus.js +1 -1
  18. package/dist/es2019/internal/combine.js +1 -1
  19. package/dist/es2019/internal/use-anchor-position.js +24 -15
  20. package/dist/es2019/internal/use-animated-visibility.js +3 -3
  21. package/dist/es2019/internal/use-focus-wrap.js +7 -7
  22. package/dist/es2019/internal/use-initial-focus.js +1 -1
  23. package/dist/es2019/popover/popover.js +9 -9
  24. package/dist/es2019/popup/popup-content.js +2 -2
  25. package/dist/es2019/popup/popup-trigger.js +2 -2
  26. package/dist/es2019/use-simple-light-dismiss/index.js +1 -1
  27. package/dist/esm/arrow/index.js +2 -2
  28. package/dist/esm/dialog/dialog-content.js +1 -6
  29. package/dist/esm/focus/focus.js +4 -4
  30. package/dist/esm/internal/combine.js +2 -2
  31. package/dist/esm/internal/use-anchor-position.js +24 -27
  32. package/dist/esm/internal/use-animated-visibility.js +3 -3
  33. package/dist/esm/internal/use-focus-wrap.js +7 -7
  34. package/dist/esm/internal/use-initial-focus.js +1 -1
  35. package/dist/esm/popover/popover.js +9 -9
  36. package/dist/esm/popup/popup-content.js +2 -2
  37. package/dist/esm/popup/popup-trigger.js +2 -2
  38. package/dist/esm/use-simple-light-dismiss/index.js +1 -1
  39. package/dist/types/internal/ensure-preset-styles.d.ts +1 -1
  40. package/dist/types/internal/use-anchor-position.d.ts +15 -1
  41. package/dist/types/internal/use-focus-wrap.d.ts +1 -1
  42. package/dist/types/popup/popup-content.d.ts +1 -1
  43. package/dist/types/popup/popup-trigger.d.ts +1 -1
  44. package/dist/types/use-simple-light-dismiss/index.d.ts +3 -3
  45. package/dist/types-ts4.5/internal/ensure-preset-styles.d.ts +1 -1
  46. package/dist/types-ts4.5/internal/use-anchor-position.d.ts +15 -1
  47. package/dist/types-ts4.5/internal/use-focus-wrap.d.ts +1 -1
  48. package/dist/types-ts4.5/popup/popup-content.d.ts +1 -1
  49. package/dist/types-ts4.5/popup/popup-trigger.d.ts +1 -1
  50. package/dist/types-ts4.5/use-simple-light-dismiss/index.d.ts +3 -3
  51. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 0.6.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [`9d77f6602f870`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9d77f6602f870) -
8
+ Fix two CSS anchor positioning bugs for aligned placements (align-start/align-end):
9
+ 1. Popups at viewport corners now correctly fall back to the diagonally opposite corner when their
10
+ preferred placement has no space, rather than remaining partially off-screen.
11
+
12
+ 2. Popups near a single viewport edge now correctly trigger position fallbacks when their content
13
+ is wider than the available space, rather than wrapping content into a narrow column.
14
+
3
15
  ## 0.6.1
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -129,7 +129,7 @@ Browsers without `@starting-style` support will show/hide elements instantly —
129
129
 
130
130
  Browser tests in `__tests__/playwright/` verify the following WCAG 2.2 success criteria. See
131
131
  [`notes/goals/accessibility-criteria.md`](notes/goals/accessibility-criteria.md) and
132
- [`notes/decisions/accessibility-audit-report.md`](notes/decisions/accessibility-audit-report.md) for
132
+ [`notes/audits/accessibility-audit-report.md`](notes/audits/accessibility-audit-report.md) for
133
133
  details.
134
134
 
135
135
  | A11y criterion | Browser test |
@@ -150,6 +150,4 @@ details.
150
150
  ## Documentation
151
151
 
152
152
  See [`notes/`](notes/) for project documentation, architecture decisions, migration records, and
153
- audit reports. The [`notes/README.md`](notes/README.md) provides a full index, including **current
154
- migration status** and links to
155
- [`notes/decisions/migration-roadmap.md`](notes/decisions/migration-roadmap.md).
153
+ audit reports. The [`notes/README.md`](notes/README.md) provides a full index.
@@ -21,7 +21,7 @@ var _useAnchorPosition = require("../internal/use-anchor-position");
21
21
  *
22
22
  * Constraints:
23
23
  * - `box-shadow` must be `none` (interferes with `clip-path: inset() margin-box`)
24
- * - `::before` and `::after` are consumed - consumers cannot use them
24
+ * - `::before` and `::after` are consumed — consumers cannot use them
25
25
  * - Arrow pseudo-elements use `background: inherit` from the popover element
26
26
  *
27
27
  * @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
@@ -46,7 +46,7 @@ function positionAreaToRuleName(_ref) {
46
46
  * that change both `position-area` and `margin` when flipping.
47
47
  *
48
48
  * This is required for the arrow technique because built-in keywords
49
- * (`flip-block`, `flip-inline`) only flip `position-area` - they do
49
+ * (`flip-block`, `flip-inline`) only flip `position-area` — they do
50
50
  * not update the margin direction needed to reveal the correct arrow.
51
51
  */
52
52
  function getTryFallbacks(_ref2) {
@@ -128,12 +128,7 @@ var Dialog = exports.Dialog = /*#__PURE__*/(0, _react.forwardRef)(function Dialo
128
128
  var escapedId = CSS.escape(dialogId);
129
129
  return /*#__PURE__*/_react.default.createElement("dialog", (0, _extends2.default)({
130
130
  ref: combinedRef,
131
- id: dialogId
132
- // Modern browsers infer modal semantics from `.showModal()` but
133
- // some assistive tech still keys off `aria-modal="true"`. Setting
134
- // it explicitly is recommended by WAI-ARIA APG dialog pattern.
135
- ,
136
- "aria-modal": "true",
131
+ id: dialogId,
137
132
  "aria-label": label,
138
133
  "aria-labelledby": label ? undefined : labelledBy,
139
134
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
@@ -46,10 +46,10 @@ var selectors = function () {
46
46
  function getFocusables(_ref) {
47
47
  var container = _ref.container,
48
48
  filter = _ref.filter;
49
- return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (element) {
50
- return element instanceof HTMLElement;
51
- }).filter(function (element) {
52
- return !filter || filter(element, container);
49
+ return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (el) {
50
+ return el instanceof HTMLElement;
51
+ }).filter(function (el) {
52
+ return !filter || filter(el, container);
53
53
  });
54
54
  }
55
55
 
@@ -22,8 +22,8 @@ function combine() {
22
22
  cleanupFns[_key] = arguments[_key];
23
23
  }
24
24
  return function cleanup() {
25
- cleanupFns.forEach(function (callback) {
26
- return callback === null || callback === void 0 ? void 0 : callback();
25
+ cleanupFns.forEach(function (fn) {
26
+ return fn === null || fn === void 0 ? void 0 : fn();
27
27
  });
28
28
  };
29
29
  }
@@ -13,8 +13,6 @@ Object.defineProperty(exports, "getPlacement", {
13
13
  exports.placementToPositionArea = placementToPositionArea;
14
14
  exports.placementToTryFallbacks = placementToTryFallbacks;
15
15
  exports.useAnchorPosition = useAnchorPosition;
16
- var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
17
- var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
18
16
  var _react = require("react");
19
17
  var _bindEventListener = require("bind-event-listener");
20
18
  var _rafSchd = _interopRequireDefault(require("raf-schd"));
@@ -93,6 +91,20 @@ function placementToPositionArea(_ref) {
93
91
  * For aligned placements (start/end), includes the same-edge centered
94
92
  * position as fallbacks so the browser can try centering when the aligned
95
93
  * position would overflow, before flipping to the opposite edge.
94
+ *
95
+ * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
96
+ *
97
+ * When a popup is in a viewport corner (e.g. inline-end align-end at the
98
+ * top-right), flipping only the primary axis (`flip-inline`) moves the popup
99
+ * to the left but keeps the same cross-axis span direction (e.g. upward),
100
+ * which is still off-screen. The combined keyword `flip-inline flip-block`
101
+ * mirrors the popup diagonally — it flips BOTH the position-area AND both
102
+ * inline and block margins simultaneously, placing the popup at the
103
+ * diagonally opposite corner where there is always space.
104
+ *
105
+ * Named `position-area` entries (e.g. `inline-start span-block-end`) in
106
+ * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
107
+ * tactic keywords correctly flip the gap margin along with the position.
96
108
  */
97
109
  function placementToTryFallbacks(_ref2) {
98
110
  var placement = _ref2.placement;
@@ -108,9 +120,10 @@ function placementToTryFallbacks(_ref2) {
108
120
  var _sameEdge = "".concat(axis, "-").concat(edge);
109
121
  var _oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
110
122
  var _flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
123
+ var flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
124
+ // Try same-edge shifts first; two flip entries cover single-edge then corner overflow.
111
125
  // Legacy Popper fallbacks for e.g. bottom-start: [bottom, bottom-end, top-start, top, top-end, auto].
112
- // Include same-edge centered so the browser can try center when start/end would overflow.
113
- return ["".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _sameEdge, "".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end'), _flipKeyword, "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _oppositeEdge, "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end')].join(', ');
126
+ return ["".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _sameEdge, "".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end'), _flipKeyword, "".concat(_flipKeyword, " ").concat(flipCrossKeyword), "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _oppositeEdge, "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end')].join(', ');
114
127
  }
115
128
  var sameEdge = "".concat(axis, "-").concat(edge);
116
129
  var oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
@@ -315,6 +328,12 @@ function useAnchorPosition(_ref5) {
315
328
  property: 'inset',
316
329
  value: 'auto'
317
330
  },
331
+ // Ensures the popup's margin box overflows the viewport when its span region is too
332
+ // narrow, triggering position-try-fallbacks correctly rather than wrapping content.
333
+ {
334
+ property: 'min-inline-size',
335
+ value: 'max-content'
336
+ },
318
337
  // Main-axis gap between the popover and its trigger
319
338
  {
320
339
  property: gap.property,
@@ -475,29 +494,7 @@ function useAnchorPosition(_ref5) {
475
494
  // ResizeObserver fires once the browser has real dimensions.
476
495
  // Self-disconnects after one valid measurement; ongoing
477
496
  // scroll/resize is handled by the window listeners below.
478
- // `ResizeObserver` is missing in some non-DOM jest environments
479
- // (e.g. post-office's `node` environment). Fall back to a no-op
480
- // observer there — the scroll/resize listeners below still keep
481
- // the popover positioned in the rare case the consumer also
482
- // polyfilled `showPopover` but not `ResizeObserver`. Real
483
- // browsers always have it.
484
- var NoopResizeObserver = /*#__PURE__*/function () {
485
- function NoopResizeObserver() {
486
- (0, _classCallCheck2.default)(this, NoopResizeObserver);
487
- }
488
- return (0, _createClass2.default)(NoopResizeObserver, [{
489
- key: "observe",
490
- value: function observe() {}
491
- }, {
492
- key: "unobserve",
493
- value: function unobserve() {}
494
- }, {
495
- key: "disconnect",
496
- value: function disconnect() {}
497
- }]);
498
- }();
499
- var ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
500
- var resizeObserver = new ResizeObserverImpl(function () {
497
+ var resizeObserver = new ResizeObserver(function () {
501
498
  if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
502
499
  update();
503
500
  resizeObserver.disconnect();
@@ -114,8 +114,8 @@ function useAnimatedVisibility(_ref) {
114
114
  if (isOpen || !showChildren || !willAnimate) {
115
115
  return;
116
116
  }
117
- var element = elementRef.current;
118
- if (!element) {
117
+ var el = elementRef.current;
118
+ if (!el) {
119
119
  return;
120
120
  }
121
121
  function finish() {
@@ -129,7 +129,7 @@ function useAnimatedVisibility(_ref) {
129
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);
130
130
 
131
131
  // Primary: listen for the CSS transition to complete
132
- var unbind = (0, _bindEventListener.bind)(element, {
132
+ var unbind = (0, _bindEventListener.bind)(el, {
133
133
  type: 'transitionend',
134
134
  listener: finish,
135
135
  options: {
@@ -39,7 +39,7 @@ function roleRequiresFocusWrap(role) {
39
39
  * elements within the container using wrapping navigation.
40
40
  *
41
41
  * Light dismiss (Escape, click outside) continues to work natively
42
- * via `popover="auto"` - this hook only intercepts Tab.
42
+ * via `popover="auto"` — this hook only intercepts Tab.
43
43
  *
44
44
  * Always call this hook unconditionally. The listener is only
45
45
  * attached when the role requires focus wrapping, and is cleaned
@@ -49,11 +49,11 @@ function useFocusWrap(_ref) {
49
49
  var elementRef = _ref.elementRef,
50
50
  role = _ref.role;
51
51
  (0, _react.useEffect)(function () {
52
- var element = elementRef.current;
53
- if (!element || !roleRequiresFocusWrap(role)) {
52
+ var el = elementRef.current;
53
+ if (!el || !roleRequiresFocusWrap(role)) {
54
54
  return;
55
55
  }
56
- var unbind = (0, _bindEventListener.bind)(element, {
56
+ var unbind = (0, _bindEventListener.bind)(el, {
57
57
  type: 'keydown',
58
58
  listener: function listener(event) {
59
59
  if (event.key !== 'Tab') {
@@ -65,7 +65,7 @@ function useFocusWrap(_ref) {
65
65
  // Try to move to the next/previous focusable element relative
66
66
  // to the currently focused element within the container.
67
67
  var next = (0, _focus.getNextFocusable)({
68
- container: element,
68
+ container: el,
69
69
  direction: direction
70
70
  });
71
71
  if (next) {
@@ -77,9 +77,9 @@ function useFocusWrap(_ref) {
77
77
  // focused element isn't in the focusable list). Fall back to
78
78
  // the first or last focusable element depending on direction.
79
79
  var fallback = direction === 'forwards' ? (0, _focus.getFirstFocusable)({
80
- container: element
80
+ container: el
81
81
  }) : (0, _focus.getLastFocusable)({
82
- container: element
82
+ container: el
83
83
  });
84
84
  if (fallback) {
85
85
  fallback.focus();
@@ -18,7 +18,7 @@ var _focus = require("../focus/focus");
18
18
  * - no role / other roles: no focus movement
19
19
  *
20
20
  * Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
21
- * attribute - it only calls `.focus()` imperatively during commit, which
21
+ * attribute — it only calls `.focus()` imperatively during commit, which
22
22
  * has no effect on hidden popover content. Consumers must set the native
23
23
  * attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
24
24
  * React 19+ reflects the JSX prop as the HTML attribute automatically.
@@ -126,21 +126,21 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
126
126
  // the browser processes light dismiss), read in the toggle handler.
127
127
  var closeReasonRef = (0, _react.useRef)('light-dismiss');
128
128
  var handleToggle = (0, _react.useCallback)(function (event) {
129
- var element = ownRef.current;
129
+ var el = ownRef.current;
130
130
  if (event.newState === 'open') {
131
- if (element) {
131
+ if (el) {
132
132
  onOpenChange === null || onOpenChange === void 0 || onOpenChange({
133
133
  isOpen: true,
134
- element: element
134
+ element: el
135
135
  });
136
136
  }
137
137
  return;
138
138
  }
139
139
  if (event.newState === 'closed') {
140
- if (element) {
140
+ if (el) {
141
141
  onOpenChange === null || onOpenChange === void 0 || onOpenChange({
142
142
  isOpen: false,
143
- element: element
143
+ element: el
144
144
  });
145
145
  }
146
146
 
@@ -158,13 +158,13 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
158
158
  }
159
159
  }, [onClose, onOpenChange]);
160
160
  (0, _react.useEffect)(function () {
161
- var element = ownRef.current;
162
- if (!element) {
161
+ var el = ownRef.current;
162
+ if (!el) {
163
163
  return;
164
164
  }
165
165
 
166
166
  // Capture-phase: tag Escape before the browser processes light dismiss.
167
- var unbindEscape = (0, _bindEventListener.bind)(element, {
167
+ var unbindEscape = (0, _bindEventListener.bind)(el, {
168
168
  type: 'keydown',
169
169
  listener: function listener(event) {
170
170
  if (event.key === 'Escape') {
@@ -175,7 +175,7 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
175
175
  capture: true
176
176
  }
177
177
  });
178
- var unbindToggle = (0, _bindEventListener.bind)(element, {
178
+ var unbindToggle = (0, _bindEventListener.bind)(el, {
179
179
  type: 'toggle',
180
180
  listener: handleToggle
181
181
  });
@@ -20,7 +20,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
20
20
  /**
21
21
  * Thin context wrapper that composes `Popover` + `useAnchorPosition`.
22
22
  *
23
- * Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
23
+ * Used inside the `<Popup>` compound — reads triggerRef, placement, isOpen,
24
24
  * and onClose from context. For standalone usage (tooltip, spotlight, flag),
25
25
  * use `Popover` + `useAnchorPosition` directly.
26
26
  */
@@ -97,7 +97,7 @@ var PopupContent = exports.PopupContent = /*#__PURE__*/(0, _react.forwardRef)(fu
97
97
  // ── Nested popover focus restoration fallback ──
98
98
  // The browser only captures `previouslyFocusedElement` for the
99
99
  // outermost popover="auto" in the stack. Inner (nested) popovers
100
- // have shouldRestoreFocus=false, so the browser will not restore
100
+ // have shouldRestoreFocus=false, so the browser won't restore
101
101
  // focus when they close.
102
102
  //
103
103
  // We detect this case by checking if focus is still inside the
@@ -26,7 +26,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
26
26
  * from opening.
27
27
  *
28
28
  * If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
29
- * instead - it hands you raw props via a render-prop and avoids
29
+ * instead — it hands you raw props via a render-prop and avoids
30
30
  * `cloneElement` entirely.
31
31
  */
32
32
  function PopupTrigger(_ref) {
@@ -40,7 +40,7 @@ function PopupTrigger(_ref) {
40
40
  var childOnClick = /*#__PURE__*/(0, _react.isValidElement)(children) ? children.props.onClick : undefined;
41
41
 
42
42
  // Use a ref to track the latest isOpen value so the click handler
43
- // does not need isOpen in its dependency array (which would recreate
43
+ // doesn't need isOpen in its dependency array (which would recreate
44
44
  // the handler on every open/close, breaking cloneElement identity).
45
45
  var isOpenRef = _react.default.useRef(isOpen);
46
46
  isOpenRef.current = isOpen;
@@ -26,7 +26,7 @@ function useSimpleLightDismiss(_ref) {
26
26
  var popoverRef = _ref.popoverRef,
27
27
  isOpen = _ref.isOpen,
28
28
  onClose = _ref.onClose;
29
- // Keep a stable ref to onClose so the effect does not re-bind on every render.
29
+ // Keep a stable ref to onClose so the effect doesn't re-bind on every render.
30
30
  var onCloseRef = (0, _react.useRef)(onClose);
31
31
  onCloseRef.current = onClose;
32
32
  (0, _react.useEffect)(function () {
@@ -14,7 +14,7 @@ import { getPlacement, placementToPositionArea } from '../internal/use-anchor-po
14
14
  *
15
15
  * Constraints:
16
16
  * - `box-shadow` must be `none` (interferes with `clip-path: inset() margin-box`)
17
- * - `::before` and `::after` are consumed - consumers cannot use them
17
+ * - `::before` and `::after` are consumed — consumers cannot use them
18
18
  * - Arrow pseudo-elements use `background: inherit` from the popover element
19
19
  *
20
20
  * @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
@@ -184,7 +184,7 @@ function positionAreaToRuleName({
184
184
  * that change both `position-area` and `margin` when flipping.
185
185
  *
186
186
  * This is required for the arrow technique because built-in keywords
187
- * (`flip-block`, `flip-inline`) only flip `position-area` - they do
187
+ * (`flip-block`, `flip-inline`) only flip `position-area` — they do
188
188
  * not update the margin direction needed to reveal the correct arrow.
189
189
  */
190
190
  function getTryFallbacks({
@@ -120,12 +120,7 @@ export const Dialog = /*#__PURE__*/forwardRef(function Dialog({
120
120
  const escapedId = CSS.escape(dialogId);
121
121
  return /*#__PURE__*/React.createElement("dialog", _extends({
122
122
  ref: combinedRef,
123
- id: dialogId
124
- // Modern browsers infer modal semantics from `.showModal()` but
125
- // some assistive tech still keys off `aria-modal="true"`. Setting
126
- // it explicitly is recommended by WAI-ARIA APG dialog pattern.
127
- ,
128
- "aria-modal": "true",
123
+ id: dialogId,
129
124
  "aria-label": label,
130
125
  "aria-labelledby": label ? undefined : labelledBy,
131
126
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
@@ -39,7 +39,7 @@ function getFocusables({
39
39
  container,
40
40
  filter
41
41
  }) {
42
- return Array.from(container.querySelectorAll(selectors.focusable)).filter(element => element instanceof HTMLElement).filter(element => !filter || filter(element, container));
42
+ return Array.from(container.querySelectorAll(selectors.focusable)).filter(el => el instanceof HTMLElement).filter(el => !filter || filter(el, container));
43
43
  }
44
44
 
45
45
  /**
@@ -13,6 +13,6 @@
13
13
  */
14
14
  export function combine(...cleanupFns) {
15
15
  return function cleanup() {
16
- cleanupFns.forEach(callback => callback === null || callback === void 0 ? void 0 : callback());
16
+ cleanupFns.forEach(fn => fn === null || fn === void 0 ? void 0 : fn());
17
17
  };
18
18
  }
@@ -79,6 +79,20 @@ export function placementToPositionArea({
79
79
  * For aligned placements (start/end), includes the same-edge centered
80
80
  * position as fallbacks so the browser can try centering when the aligned
81
81
  * position would overflow, before flipping to the opposite edge.
82
+ *
83
+ * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
84
+ *
85
+ * When a popup is in a viewport corner (e.g. inline-end align-end at the
86
+ * top-right), flipping only the primary axis (`flip-inline`) moves the popup
87
+ * to the left but keeps the same cross-axis span direction (e.g. upward),
88
+ * which is still off-screen. The combined keyword `flip-inline flip-block`
89
+ * mirrors the popup diagonally — it flips BOTH the position-area AND both
90
+ * inline and block margins simultaneously, placing the popup at the
91
+ * diagonally opposite corner where there is always space.
92
+ *
93
+ * Named `position-area` entries (e.g. `inline-start span-block-end`) in
94
+ * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
95
+ * tactic keywords correctly flip the gap margin along with the position.
82
96
  */
83
97
  export function placementToTryFallbacks({
84
98
  placement
@@ -96,9 +110,10 @@ export function placementToTryFallbacks({
96
110
  const sameEdge = `${axis}-${edge}`;
97
111
  const oppositeEdge = `${axis}-${flippedEdge}`;
98
112
  const flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
113
+ const flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
114
+ // Try same-edge shifts first; two flip entries cover single-edge then corner overflow.
99
115
  // Legacy Popper fallbacks for e.g. bottom-start: [bottom, bottom-end, top-start, top, top-end, auto].
100
- // Include same-edge centered so the browser can try center when start/end would overflow.
101
- return [`${sameEdge} span-${crossAxis}-${align === 'start' ? 'end' : 'start'}`, sameEdge, `${sameEdge} span-${crossAxis}-${align === 'start' ? 'start' : 'end'}`, flipKeyword, `${oppositeEdge} span-${crossAxis}-${align === 'start' ? 'end' : 'start'}`, oppositeEdge, `${oppositeEdge} span-${crossAxis}-${align === 'start' ? 'start' : 'end'}`].join(', ');
116
+ return [`${sameEdge} span-${crossAxis}-${align === 'start' ? 'end' : 'start'}`, sameEdge, `${sameEdge} span-${crossAxis}-${align === 'start' ? 'start' : 'end'}`, flipKeyword, `${flipKeyword} ${flipCrossKeyword}`, `${oppositeEdge} span-${crossAxis}-${align === 'start' ? 'end' : 'start'}`, oppositeEdge, `${oppositeEdge} span-${crossAxis}-${align === 'start' ? 'start' : 'end'}`].join(', ');
102
117
  }
103
118
  const sameEdge = `${axis}-${edge}`;
104
119
  const oppositeEdge = `${axis}-${flippedEdge}`;
@@ -308,6 +323,12 @@ export function useAnchorPosition({
308
323
  property: 'inset',
309
324
  value: 'auto'
310
325
  },
326
+ // Ensures the popup's margin box overflows the viewport when its span region is too
327
+ // narrow, triggering position-try-fallbacks correctly rather than wrapping content.
328
+ {
329
+ property: 'min-inline-size',
330
+ value: 'max-content'
331
+ },
311
332
  // Main-axis gap between the popover and its trigger
312
333
  {
313
334
  property: gap.property,
@@ -467,19 +488,7 @@ export function useAnchorPosition({
467
488
  // ResizeObserver fires once the browser has real dimensions.
468
489
  // Self-disconnects after one valid measurement; ongoing
469
490
  // scroll/resize is handled by the window listeners below.
470
- // `ResizeObserver` is missing in some non-DOM jest environments
471
- // (e.g. post-office's `node` environment). Fall back to a no-op
472
- // observer there — the scroll/resize listeners below still keep
473
- // the popover positioned in the rare case the consumer also
474
- // polyfilled `showPopover` but not `ResizeObserver`. Real
475
- // browsers always have it.
476
- const NoopResizeObserver = class {
477
- observe() {}
478
- unobserve() {}
479
- disconnect() {}
480
- };
481
- const ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
482
- const resizeObserver = new ResizeObserverImpl(() => {
491
+ const resizeObserver = new ResizeObserver(() => {
483
492
  if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
484
493
  update();
485
494
  resizeObserver.disconnect();
@@ -104,8 +104,8 @@ export function useAnimatedVisibility({
104
104
  if (isOpen || !showChildren || !willAnimate) {
105
105
  return;
106
106
  }
107
- const element = elementRef.current;
108
- if (!element) {
107
+ const el = elementRef.current;
108
+ if (!el) {
109
109
  return;
110
110
  }
111
111
  function finish() {
@@ -119,7 +119,7 @@ export function useAnimatedVisibility({
119
119
  const fallbackId = setTimeout(finish, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
120
120
 
121
121
  // Primary: listen for the CSS transition to complete
122
- const unbind = bind(element, {
122
+ const unbind = bind(el, {
123
123
  type: 'transitionend',
124
124
  listener: finish,
125
125
  options: {
@@ -34,7 +34,7 @@ function roleRequiresFocusWrap(role) {
34
34
  * elements within the container using wrapping navigation.
35
35
  *
36
36
  * Light dismiss (Escape, click outside) continues to work natively
37
- * via `popover="auto"` - this hook only intercepts Tab.
37
+ * via `popover="auto"` — this hook only intercepts Tab.
38
38
  *
39
39
  * Always call this hook unconditionally. The listener is only
40
40
  * attached when the role requires focus wrapping, and is cleaned
@@ -45,11 +45,11 @@ export function useFocusWrap({
45
45
  role
46
46
  }) {
47
47
  useEffect(() => {
48
- const element = elementRef.current;
49
- if (!element || !roleRequiresFocusWrap(role)) {
48
+ const el = elementRef.current;
49
+ if (!el || !roleRequiresFocusWrap(role)) {
50
50
  return;
51
51
  }
52
- const unbind = bind(element, {
52
+ const unbind = bind(el, {
53
53
  type: 'keydown',
54
54
  listener: event => {
55
55
  if (event.key !== 'Tab') {
@@ -61,7 +61,7 @@ export function useFocusWrap({
61
61
  // Try to move to the next/previous focusable element relative
62
62
  // to the currently focused element within the container.
63
63
  const next = getNextFocusable({
64
- container: element,
64
+ container: el,
65
65
  direction
66
66
  });
67
67
  if (next) {
@@ -73,9 +73,9 @@ export function useFocusWrap({
73
73
  // focused element isn't in the focusable list). Fall back to
74
74
  // the first or last focusable element depending on direction.
75
75
  const fallback = direction === 'forwards' ? getFirstFocusable({
76
- container: element
76
+ container: el
77
77
  }) : getLastFocusable({
78
- container: element
78
+ container: el
79
79
  });
80
80
  if (fallback) {
81
81
  fallback.focus();
@@ -13,7 +13,7 @@ import { getFirstFocusable } from '../focus/focus';
13
13
  * - no role / other roles: no focus movement
14
14
  *
15
15
  * Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
16
- * attribute - it only calls `.focus()` imperatively during commit, which
16
+ * attribute — it only calls `.focus()` imperatively during commit, which
17
17
  * has no effect on hidden popover content. Consumers must set the native
18
18
  * attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
19
19
  * React 19+ reflects the JSX prop as the HTML attribute automatically.
@@ -116,21 +116,21 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
116
116
  // the browser processes light dismiss), read in the toggle handler.
117
117
  const closeReasonRef = useRef('light-dismiss');
118
118
  const handleToggle = useCallback(event => {
119
- const element = ownRef.current;
119
+ const el = ownRef.current;
120
120
  if (event.newState === 'open') {
121
- if (element) {
121
+ if (el) {
122
122
  onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
123
123
  isOpen: true,
124
- element: element
124
+ element: el
125
125
  });
126
126
  }
127
127
  return;
128
128
  }
129
129
  if (event.newState === 'closed') {
130
- if (element) {
130
+ if (el) {
131
131
  onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
132
132
  isOpen: false,
133
- element: element
133
+ element: el
134
134
  });
135
135
  }
136
136
 
@@ -148,13 +148,13 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
148
148
  }
149
149
  }, [onClose, onOpenChange]);
150
150
  useEffect(() => {
151
- const element = ownRef.current;
152
- if (!element) {
151
+ const el = ownRef.current;
152
+ if (!el) {
153
153
  return;
154
154
  }
155
155
 
156
156
  // Capture-phase: tag Escape before the browser processes light dismiss.
157
- const unbindEscape = bind(element, {
157
+ const unbindEscape = bind(el, {
158
158
  type: 'keydown',
159
159
  listener: event => {
160
160
  if (event.key === 'Escape') {
@@ -165,7 +165,7 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
165
165
  capture: true
166
166
  }
167
167
  });
168
- const unbindToggle = bind(element, {
168
+ const unbindToggle = bind(el, {
169
169
  type: 'toggle',
170
170
  listener: handleToggle
171
171
  });
@@ -11,7 +11,7 @@ import { useMaybePopupContext } from './popup-context';
11
11
  /**
12
12
  * Thin context wrapper that composes `Popover` + `useAnchorPosition`.
13
13
  *
14
- * Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
14
+ * Used inside the `<Popup>` compound — reads triggerRef, placement, isOpen,
15
15
  * and onClose from context. For standalone usage (tooltip, spotlight, flag),
16
16
  * use `Popover` + `useAnchorPosition` directly.
17
17
  */
@@ -88,7 +88,7 @@ export const PopupContent = /*#__PURE__*/forwardRef(function PopupContent({
88
88
  // ── Nested popover focus restoration fallback ──
89
89
  // The browser only captures `previouslyFocusedElement` for the
90
90
  // outermost popover="auto" in the stack. Inner (nested) popovers
91
- // have shouldRestoreFocus=false, so the browser will not restore
91
+ // have shouldRestoreFocus=false, so the browser won't restore
92
92
  // focus when they close.
93
93
  //
94
94
  // We detect this case by checking if focus is still inside the
@@ -18,7 +18,7 @@ import { usePopupContext } from './popup-context';
18
18
  * from opening.
19
19
  *
20
20
  * If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
21
- * instead - it hands you raw props via a render-prop and avoids
21
+ * instead — it hands you raw props via a render-prop and avoids
22
22
  * `cloneElement` entirely.
23
23
  */
24
24
  export function PopupTrigger({
@@ -34,7 +34,7 @@ export function PopupTrigger({
34
34
  const childOnClick = /*#__PURE__*/isValidElement(children) ? children.props.onClick : undefined;
35
35
 
36
36
  // Use a ref to track the latest isOpen value so the click handler
37
- // does not need isOpen in its dependency array (which would recreate
37
+ // doesn't need isOpen in its dependency array (which would recreate
38
38
  // the handler on every open/close, breaking cloneElement identity).
39
39
  const isOpenRef = React.useRef(isOpen);
40
40
  isOpenRef.current = isOpen;
@@ -21,7 +21,7 @@ export function useSimpleLightDismiss({
21
21
  isOpen,
22
22
  onClose
23
23
  }) {
24
- // Keep a stable ref to onClose so the effect does not re-bind on every render.
24
+ // Keep a stable ref to onClose so the effect doesn't re-bind on every render.
25
25
  const onCloseRef = useRef(onClose);
26
26
  onCloseRef.current = onClose;
27
27
  useEffect(() => {
@@ -14,7 +14,7 @@ import { getPlacement, placementToPositionArea } from '../internal/use-anchor-po
14
14
  *
15
15
  * Constraints:
16
16
  * - `box-shadow` must be `none` (interferes with `clip-path: inset() margin-box`)
17
- * - `::before` and `::after` are consumed - consumers cannot use them
17
+ * - `::before` and `::after` are consumed — consumers cannot use them
18
18
  * - Arrow pseudo-elements use `background: inherit` from the popover element
19
19
  *
20
20
  * @see https://goulet.dev/posts/tooltip-with-popover-and-anchor-positioning/
@@ -39,7 +39,7 @@ function positionAreaToRuleName(_ref) {
39
39
  * that change both `position-area` and `margin` when flipping.
40
40
  *
41
41
  * This is required for the arrow technique because built-in keywords
42
- * (`flip-block`, `flip-inline`) only flip `position-area` - they do
42
+ * (`flip-block`, `flip-inline`) only flip `position-area` — they do
43
43
  * not update the margin direction needed to reveal the correct arrow.
44
44
  */
45
45
  function getTryFallbacks(_ref2) {
@@ -119,12 +119,7 @@ export var Dialog = /*#__PURE__*/forwardRef(function Dialog(_ref, ref) {
119
119
  var escapedId = CSS.escape(dialogId);
120
120
  return /*#__PURE__*/React.createElement("dialog", _extends({
121
121
  ref: combinedRef,
122
- id: dialogId
123
- // Modern browsers infer modal semantics from `.showModal()` but
124
- // some assistive tech still keys off `aria-modal="true"`. Setting
125
- // it explicitly is recommended by WAI-ARIA APG dialog pattern.
126
- ,
127
- "aria-modal": "true",
122
+ id: dialogId,
128
123
  "aria-label": label,
129
124
  "aria-labelledby": label ? undefined : labelledBy,
130
125
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
@@ -38,10 +38,10 @@ var selectors = function () {
38
38
  function getFocusables(_ref) {
39
39
  var container = _ref.container,
40
40
  filter = _ref.filter;
41
- return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (element) {
42
- return element instanceof HTMLElement;
43
- }).filter(function (element) {
44
- return !filter || filter(element, container);
41
+ return Array.from(container.querySelectorAll(selectors.focusable)).filter(function (el) {
42
+ return el instanceof HTMLElement;
43
+ }).filter(function (el) {
44
+ return !filter || filter(el, container);
45
45
  });
46
46
  }
47
47
 
@@ -16,8 +16,8 @@ export function combine() {
16
16
  cleanupFns[_key] = arguments[_key];
17
17
  }
18
18
  return function cleanup() {
19
- cleanupFns.forEach(function (callback) {
20
- return callback === null || callback === void 0 ? void 0 : callback();
19
+ cleanupFns.forEach(function (fn) {
20
+ return fn === null || fn === void 0 ? void 0 : fn();
21
21
  });
22
22
  };
23
23
  }
@@ -1,5 +1,3 @@
1
- import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
- import _createClass from "@babel/runtime/helpers/createClass";
3
1
  /**
4
2
  * Anchor positioning for top-layer popovers. See
5
3
  * `notes/architecture/positioning.md` for the full model.
@@ -79,6 +77,20 @@ export function placementToPositionArea(_ref) {
79
77
  * For aligned placements (start/end), includes the same-edge centered
80
78
  * position as fallbacks so the browser can try centering when the aligned
81
79
  * position would overflow, before flipping to the opposite edge.
80
+ *
81
+ * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
82
+ *
83
+ * When a popup is in a viewport corner (e.g. inline-end align-end at the
84
+ * top-right), flipping only the primary axis (`flip-inline`) moves the popup
85
+ * to the left but keeps the same cross-axis span direction (e.g. upward),
86
+ * which is still off-screen. The combined keyword `flip-inline flip-block`
87
+ * mirrors the popup diagonally — it flips BOTH the position-area AND both
88
+ * inline and block margins simultaneously, placing the popup at the
89
+ * diagonally opposite corner where there is always space.
90
+ *
91
+ * Named `position-area` entries (e.g. `inline-start span-block-end`) in
92
+ * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
93
+ * tactic keywords correctly flip the gap margin along with the position.
82
94
  */
83
95
  export function placementToTryFallbacks(_ref2) {
84
96
  var placement = _ref2.placement;
@@ -94,9 +106,10 @@ export function placementToTryFallbacks(_ref2) {
94
106
  var _sameEdge = "".concat(axis, "-").concat(edge);
95
107
  var _oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
96
108
  var _flipKeyword = axis === 'block' ? 'flip-block' : 'flip-inline';
109
+ var flipCrossKeyword = axis === 'block' ? 'flip-inline' : 'flip-block';
110
+ // Try same-edge shifts first; two flip entries cover single-edge then corner overflow.
97
111
  // Legacy Popper fallbacks for e.g. bottom-start: [bottom, bottom-end, top-start, top, top-end, auto].
98
- // Include same-edge centered so the browser can try center when start/end would overflow.
99
- return ["".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _sameEdge, "".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end'), _flipKeyword, "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _oppositeEdge, "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end')].join(', ');
112
+ return ["".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _sameEdge, "".concat(_sameEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end'), _flipKeyword, "".concat(_flipKeyword, " ").concat(flipCrossKeyword), "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'end' : 'start'), _oppositeEdge, "".concat(_oppositeEdge, " span-").concat(crossAxis, "-").concat(align === 'start' ? 'start' : 'end')].join(', ');
100
113
  }
101
114
  var sameEdge = "".concat(axis, "-").concat(edge);
102
115
  var oppositeEdge = "".concat(axis, "-").concat(flippedEdge);
@@ -301,6 +314,12 @@ export function useAnchorPosition(_ref5) {
301
314
  property: 'inset',
302
315
  value: 'auto'
303
316
  },
317
+ // Ensures the popup's margin box overflows the viewport when its span region is too
318
+ // narrow, triggering position-try-fallbacks correctly rather than wrapping content.
319
+ {
320
+ property: 'min-inline-size',
321
+ value: 'max-content'
322
+ },
304
323
  // Main-axis gap between the popover and its trigger
305
324
  {
306
325
  property: gap.property,
@@ -461,29 +480,7 @@ export function useAnchorPosition(_ref5) {
461
480
  // ResizeObserver fires once the browser has real dimensions.
462
481
  // Self-disconnects after one valid measurement; ongoing
463
482
  // scroll/resize is handled by the window listeners below.
464
- // `ResizeObserver` is missing in some non-DOM jest environments
465
- // (e.g. post-office's `node` environment). Fall back to a no-op
466
- // observer there — the scroll/resize listeners below still keep
467
- // the popover positioned in the rare case the consumer also
468
- // polyfilled `showPopover` but not `ResizeObserver`. Real
469
- // browsers always have it.
470
- var NoopResizeObserver = /*#__PURE__*/function () {
471
- function NoopResizeObserver() {
472
- _classCallCheck(this, NoopResizeObserver);
473
- }
474
- return _createClass(NoopResizeObserver, [{
475
- key: "observe",
476
- value: function observe() {}
477
- }, {
478
- key: "unobserve",
479
- value: function unobserve() {}
480
- }, {
481
- key: "disconnect",
482
- value: function disconnect() {}
483
- }]);
484
- }();
485
- var ResizeObserverImpl = typeof ResizeObserver !== 'undefined' ? ResizeObserver : NoopResizeObserver;
486
- var resizeObserver = new ResizeObserverImpl(function () {
483
+ var resizeObserver = new ResizeObserver(function () {
487
484
  if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
488
485
  update();
489
486
  resizeObserver.disconnect();
@@ -107,8 +107,8 @@ export function useAnimatedVisibility(_ref) {
107
107
  if (isOpen || !showChildren || !willAnimate) {
108
108
  return;
109
109
  }
110
- var element = elementRef.current;
111
- if (!element) {
110
+ var el = elementRef.current;
111
+ if (!el) {
112
112
  return;
113
113
  }
114
114
  function finish() {
@@ -122,7 +122,7 @@ export function useAnimatedVisibility(_ref) {
122
122
  var fallbackId = setTimeout(finish, ((_preset$exitDurationM = preset === null || preset === void 0 ? void 0 : preset.exitDurationMs) !== null && _preset$exitDurationM !== void 0 ? _preset$exitDurationM : 0) + 50);
123
123
 
124
124
  // Primary: listen for the CSS transition to complete
125
- var unbind = bind(element, {
125
+ var unbind = bind(el, {
126
126
  type: 'transitionend',
127
127
  listener: finish,
128
128
  options: {
@@ -34,7 +34,7 @@ function roleRequiresFocusWrap(role) {
34
34
  * elements within the container using wrapping navigation.
35
35
  *
36
36
  * Light dismiss (Escape, click outside) continues to work natively
37
- * via `popover="auto"` - this hook only intercepts Tab.
37
+ * via `popover="auto"` — this hook only intercepts Tab.
38
38
  *
39
39
  * Always call this hook unconditionally. The listener is only
40
40
  * attached when the role requires focus wrapping, and is cleaned
@@ -44,11 +44,11 @@ export function useFocusWrap(_ref) {
44
44
  var elementRef = _ref.elementRef,
45
45
  role = _ref.role;
46
46
  useEffect(function () {
47
- var element = elementRef.current;
48
- if (!element || !roleRequiresFocusWrap(role)) {
47
+ var el = elementRef.current;
48
+ if (!el || !roleRequiresFocusWrap(role)) {
49
49
  return;
50
50
  }
51
- var unbind = bind(element, {
51
+ var unbind = bind(el, {
52
52
  type: 'keydown',
53
53
  listener: function listener(event) {
54
54
  if (event.key !== 'Tab') {
@@ -60,7 +60,7 @@ export function useFocusWrap(_ref) {
60
60
  // Try to move to the next/previous focusable element relative
61
61
  // to the currently focused element within the container.
62
62
  var next = getNextFocusable({
63
- container: element,
63
+ container: el,
64
64
  direction: direction
65
65
  });
66
66
  if (next) {
@@ -72,9 +72,9 @@ export function useFocusWrap(_ref) {
72
72
  // focused element isn't in the focusable list). Fall back to
73
73
  // the first or last focusable element depending on direction.
74
74
  var fallback = direction === 'forwards' ? getFirstFocusable({
75
- container: element
75
+ container: el
76
76
  }) : getLastFocusable({
77
- container: element
77
+ container: el
78
78
  });
79
79
  if (fallback) {
80
80
  fallback.focus();
@@ -13,7 +13,7 @@ import { getFirstFocusable } from '../focus/focus';
13
13
  * - no role / other roles: no focus movement
14
14
  *
15
15
  * Note: React 18's `autoFocus` JSX prop does NOT set the HTML `autofocus`
16
- * attribute - it only calls `.focus()` imperatively during commit, which
16
+ * attribute — it only calls `.focus()` imperatively during commit, which
17
17
  * has no effect on hidden popover content. Consumers must set the native
18
18
  * attribute via a ref callback (e.g. `node.setAttribute('autofocus', '')`).
19
19
  * React 19+ reflects the JSX prop as the HTML attribute automatically.
@@ -117,21 +117,21 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
117
117
  // the browser processes light dismiss), read in the toggle handler.
118
118
  var closeReasonRef = useRef('light-dismiss');
119
119
  var handleToggle = useCallback(function (event) {
120
- var element = ownRef.current;
120
+ var el = ownRef.current;
121
121
  if (event.newState === 'open') {
122
- if (element) {
122
+ if (el) {
123
123
  onOpenChange === null || onOpenChange === void 0 || onOpenChange({
124
124
  isOpen: true,
125
- element: element
125
+ element: el
126
126
  });
127
127
  }
128
128
  return;
129
129
  }
130
130
  if (event.newState === 'closed') {
131
- if (element) {
131
+ if (el) {
132
132
  onOpenChange === null || onOpenChange === void 0 || onOpenChange({
133
133
  isOpen: false,
134
- element: element
134
+ element: el
135
135
  });
136
136
  }
137
137
 
@@ -149,13 +149,13 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
149
149
  }
150
150
  }, [onClose, onOpenChange]);
151
151
  useEffect(function () {
152
- var element = ownRef.current;
153
- if (!element) {
152
+ var el = ownRef.current;
153
+ if (!el) {
154
154
  return;
155
155
  }
156
156
 
157
157
  // Capture-phase: tag Escape before the browser processes light dismiss.
158
- var unbindEscape = bind(element, {
158
+ var unbindEscape = bind(el, {
159
159
  type: 'keydown',
160
160
  listener: function listener(event) {
161
161
  if (event.key === 'Escape') {
@@ -166,7 +166,7 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
166
166
  capture: true
167
167
  }
168
168
  });
169
- var unbindToggle = bind(element, {
169
+ var unbindToggle = bind(el, {
170
170
  type: 'toggle',
171
171
  listener: handleToggle
172
172
  });
@@ -11,7 +11,7 @@ import { useMaybePopupContext } from './popup-context';
11
11
  /**
12
12
  * Thin context wrapper that composes `Popover` + `useAnchorPosition`.
13
13
  *
14
- * Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
14
+ * Used inside the `<Popup>` compound — reads triggerRef, placement, isOpen,
15
15
  * and onClose from context. For standalone usage (tooltip, spotlight, flag),
16
16
  * use `Popover` + `useAnchorPosition` directly.
17
17
  */
@@ -88,7 +88,7 @@ export var PopupContent = /*#__PURE__*/forwardRef(function PopupContent(_ref, re
88
88
  // ── Nested popover focus restoration fallback ──
89
89
  // The browser only captures `previouslyFocusedElement` for the
90
90
  // outermost popover="auto" in the stack. Inner (nested) popovers
91
- // have shouldRestoreFocus=false, so the browser will not restore
91
+ // have shouldRestoreFocus=false, so the browser won't restore
92
92
  // focus when they close.
93
93
  //
94
94
  // We detect this case by checking if focus is still inside the
@@ -18,7 +18,7 @@ import { usePopupContext } from './popup-context';
18
18
  * from opening.
19
19
  *
20
20
  * If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
21
- * instead - it hands you raw props via a render-prop and avoids
21
+ * instead — it hands you raw props via a render-prop and avoids
22
22
  * `cloneElement` entirely.
23
23
  */
24
24
  export function PopupTrigger(_ref) {
@@ -32,7 +32,7 @@ export function PopupTrigger(_ref) {
32
32
  var childOnClick = /*#__PURE__*/isValidElement(children) ? children.props.onClick : undefined;
33
33
 
34
34
  // Use a ref to track the latest isOpen value so the click handler
35
- // does not need isOpen in its dependency array (which would recreate
35
+ // doesn't need isOpen in its dependency array (which would recreate
36
36
  // the handler on every open/close, breaking cloneElement identity).
37
37
  var isOpenRef = React.useRef(isOpen);
38
38
  isOpenRef.current = isOpen;
@@ -20,7 +20,7 @@ export function useSimpleLightDismiss(_ref) {
20
20
  var popoverRef = _ref.popoverRef,
21
21
  isOpen = _ref.isOpen,
22
22
  onClose = _ref.onClose;
23
- // Keep a stable ref to onClose so the effect does not re-bind on every render.
23
+ // Keep a stable ref to onClose so the effect doesn't re-bind on every render.
24
24
  var onCloseRef = useRef(onClose);
25
25
  onCloseRef.current = onClose;
26
26
  useEffect(function () {
@@ -1,4 +1,4 @@
1
- export declare function ensurePresetStyles({ preset, }: {
1
+ export declare function ensurePresetStyles({ preset }: {
2
2
  preset: {
3
3
  css: string;
4
4
  name: string;
@@ -53,6 +53,20 @@ export declare function placementToPositionArea({ placement }: {
53
53
  * For aligned placements (start/end), includes the same-edge centered
54
54
  * position as fallbacks so the browser can try centering when the aligned
55
55
  * position would overflow, before flipping to the opposite edge.
56
+ *
57
+ * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
58
+ *
59
+ * When a popup is in a viewport corner (e.g. inline-end align-end at the
60
+ * top-right), flipping only the primary axis (`flip-inline`) moves the popup
61
+ * to the left but keeps the same cross-axis span direction (e.g. upward),
62
+ * which is still off-screen. The combined keyword `flip-inline flip-block`
63
+ * mirrors the popup diagonally — it flips BOTH the position-area AND both
64
+ * inline and block margins simultaneously, placing the popup at the
65
+ * diagonally opposite corner where there is always space.
66
+ *
67
+ * Named `position-area` entries (e.g. `inline-start span-block-end`) in
68
+ * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
69
+ * tactic keywords correctly flip the gap margin along with the position.
56
70
  */
57
71
  export declare function placementToTryFallbacks({ placement }: {
58
72
  placement: TPlacementOptions;
@@ -118,7 +132,7 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, fo
118
132
  * the preset's named `@position-try` rules (which update both
119
133
  * `position-area` and `margin` on flip) and sets `--ds-arrow-size`.
120
134
  *
121
- * Pass `null` to disable. Has no effect in the JS fallback path -
135
+ * Pass `null` to disable. Has no effect in the JS fallback path —
122
136
  * arrows are CSS-only.
123
137
  */
124
138
  arrow?: TArrowPreset | null;
@@ -8,7 +8,7 @@ import { type RefObject } from 'react';
8
8
  * elements within the container using wrapping navigation.
9
9
  *
10
10
  * Light dismiss (Escape, click outside) continues to work natively
11
- * via `popover="auto"` - this hook only intercepts Tab.
11
+ * via `popover="auto"` — this hook only intercepts Tab.
12
12
  *
13
13
  * Always call this hook unconditionally. The listener is only
14
14
  * attached when the role requires focus wrapping, and is cleaned
@@ -7,7 +7,7 @@ import { type TPopupContentProps } from './types';
7
7
  /**
8
8
  * Thin context wrapper that composes `Popover` + `useAnchorPosition`.
9
9
  *
10
- * Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
10
+ * Used inside the `<Popup>` compound — reads triggerRef, placement, isOpen,
11
11
  * and onClose from context. For standalone usage (tooltip, spotlight, flag),
12
12
  * use `Popover` + `useAnchorPosition` directly.
13
13
  */
@@ -17,7 +17,7 @@ import { type TPopupTriggerProps } from './types';
17
17
  * from opening.
18
18
  *
19
19
  * If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
20
- * instead - it hands you raw props via a render-prop and avoids
20
+ * instead — it hands you raw props via a render-prop and avoids
21
21
  * `cloneElement` entirely.
22
22
  */
23
23
  export declare function PopupTrigger({ children }: TPopupTriggerProps): ReactNode;
@@ -13,12 +13,12 @@ type TUseSimpleLightDismissOptions = {
13
13
  /**
14
14
  * Called when a light-dismiss event occurs.
15
15
  *
16
- * - `reason: 'escape'` - the user pressed the Escape key.
17
- * - `reason: 'light-dismiss'` - the user clicked outside the popover.
16
+ * - `reason: 'escape'` — the user pressed the Escape key.
17
+ * - `reason: 'light-dismiss'` — the user clicked outside the popover.
18
18
  *
19
19
  * **Note:** This hook provides simple, standalone light dismiss that does not
20
20
  * participate in the browser's `popover="auto"` dismiss stack. Every active
21
- * instance will fire independently - if multiple popovers use this hook,
21
+ * instance will fire independently — if multiple popovers use this hook,
22
22
  * they will all receive dismiss events.
23
23
  */
24
24
  onClose: (args: {
@@ -1,4 +1,4 @@
1
- export declare function ensurePresetStyles({ preset, }: {
1
+ export declare function ensurePresetStyles({ preset }: {
2
2
  preset: {
3
3
  css: string;
4
4
  name: string;
@@ -53,6 +53,20 @@ export declare function placementToPositionArea({ placement }: {
53
53
  * For aligned placements (start/end), includes the same-edge centered
54
54
  * position as fallbacks so the browser can try centering when the aligned
55
55
  * position would overflow, before flipping to the opposite edge.
56
+ *
57
+ * **Why `flip-inline flip-block` (or `flip-block flip-inline`) is included:**
58
+ *
59
+ * When a popup is in a viewport corner (e.g. inline-end align-end at the
60
+ * top-right), flipping only the primary axis (`flip-inline`) moves the popup
61
+ * to the left but keeps the same cross-axis span direction (e.g. upward),
62
+ * which is still off-screen. The combined keyword `flip-inline flip-block`
63
+ * mirrors the popup diagonally — it flips BOTH the position-area AND both
64
+ * inline and block margins simultaneously, placing the popup at the
65
+ * diagonally opposite corner where there is always space.
66
+ *
67
+ * Named `position-area` entries (e.g. `inline-start span-block-end`) in
68
+ * `position-try-fallbacks` do NOT update margins, so only the `flip-*`
69
+ * tactic keywords correctly flip the gap margin along with the position.
56
70
  */
57
71
  export declare function placementToTryFallbacks({ placement }: {
58
72
  placement: TPlacementOptions;
@@ -118,7 +132,7 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, fo
118
132
  * the preset's named `@position-try` rules (which update both
119
133
  * `position-area` and `margin` on flip) and sets `--ds-arrow-size`.
120
134
  *
121
- * Pass `null` to disable. Has no effect in the JS fallback path -
135
+ * Pass `null` to disable. Has no effect in the JS fallback path —
122
136
  * arrows are CSS-only.
123
137
  */
124
138
  arrow?: TArrowPreset | null;
@@ -8,7 +8,7 @@ import { type RefObject } from 'react';
8
8
  * elements within the container using wrapping navigation.
9
9
  *
10
10
  * Light dismiss (Escape, click outside) continues to work natively
11
- * via `popover="auto"` - this hook only intercepts Tab.
11
+ * via `popover="auto"` — this hook only intercepts Tab.
12
12
  *
13
13
  * Always call this hook unconditionally. The listener is only
14
14
  * attached when the role requires focus wrapping, and is cleaned
@@ -7,7 +7,7 @@ import { type TPopupContentProps } from './types';
7
7
  /**
8
8
  * Thin context wrapper that composes `Popover` + `useAnchorPosition`.
9
9
  *
10
- * Used inside the `<Popup>` compound - reads triggerRef, placement, isOpen,
10
+ * Used inside the `<Popup>` compound — reads triggerRef, placement, isOpen,
11
11
  * and onClose from context. For standalone usage (tooltip, spotlight, flag),
12
12
  * use `Popover` + `useAnchorPosition` directly.
13
13
  */
@@ -17,7 +17,7 @@ import { type TPopupTriggerProps } from './types';
17
17
  * from opening.
18
18
  *
19
19
  * If you need Compiled `css` on the trigger, use `Popup.TriggerFunction`
20
- * instead - it hands you raw props via a render-prop and avoids
20
+ * instead — it hands you raw props via a render-prop and avoids
21
21
  * `cloneElement` entirely.
22
22
  */
23
23
  export declare function PopupTrigger({ children }: TPopupTriggerProps): ReactNode;
@@ -13,12 +13,12 @@ type TUseSimpleLightDismissOptions = {
13
13
  /**
14
14
  * Called when a light-dismiss event occurs.
15
15
  *
16
- * - `reason: 'escape'` - the user pressed the Escape key.
17
- * - `reason: 'light-dismiss'` - the user clicked outside the popover.
16
+ * - `reason: 'escape'` — the user pressed the Escape key.
17
+ * - `reason: 'light-dismiss'` — the user clicked outside the popover.
18
18
  *
19
19
  * **Note:** This hook provides simple, standalone light dismiss that does not
20
20
  * participate in the browser's `popover="auto"` dismiss stack. Every active
21
- * instance will fire independently - if multiple popovers use this hook,
21
+ * instance will fire independently — if multiple popovers use this hook,
22
22
  * they will all receive dismiss events.
23
23
  */
24
24
  onClose: (args: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/top-layer",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Low-level layering primitives based on popover and dialog",
5
5
  "homepage": "https://atlassian.design/components/top-layer",
6
6
  "repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",