@atlaskit/top-layer 0.5.1 → 0.6.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 (57) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/README.md +4 -2
  3. package/dist/cjs/arrow/index.js +2 -2
  4. package/dist/cjs/dialog/dialog-content.js +6 -1
  5. package/dist/cjs/entry-points/open-layer-observer.js +33 -0
  6. package/dist/cjs/focus/focus.js +4 -4
  7. package/dist/cjs/internal/combine.js +2 -2
  8. package/dist/cjs/internal/use-anchor-position.js +25 -1
  9. package/dist/cjs/internal/use-animated-visibility.js +3 -3
  10. package/dist/cjs/internal/use-focus-wrap.js +7 -7
  11. package/dist/cjs/internal/use-initial-focus.js +1 -1
  12. package/dist/cjs/popover/popover.js +9 -9
  13. package/dist/cjs/popup/popup-content.js +2 -2
  14. package/dist/cjs/popup/popup-trigger.js +2 -2
  15. package/dist/cjs/use-simple-light-dismiss/index.js +1 -1
  16. package/dist/es2019/arrow/index.js +2 -2
  17. package/dist/es2019/dialog/dialog-content.js +6 -1
  18. package/dist/es2019/entry-points/open-layer-observer.js +4 -0
  19. package/dist/es2019/focus/focus.js +1 -1
  20. package/dist/es2019/internal/combine.js +1 -1
  21. package/dist/es2019/internal/use-anchor-position.js +13 -1
  22. package/dist/es2019/internal/use-animated-visibility.js +3 -3
  23. package/dist/es2019/internal/use-focus-wrap.js +7 -7
  24. package/dist/es2019/internal/use-initial-focus.js +1 -1
  25. package/dist/es2019/popover/popover.js +9 -9
  26. package/dist/es2019/popup/popup-content.js +2 -2
  27. package/dist/es2019/popup/popup-trigger.js +2 -2
  28. package/dist/es2019/use-simple-light-dismiss/index.js +1 -1
  29. package/dist/esm/arrow/index.js +2 -2
  30. package/dist/esm/dialog/dialog-content.js +6 -1
  31. package/dist/esm/entry-points/open-layer-observer.js +4 -0
  32. package/dist/esm/focus/focus.js +4 -4
  33. package/dist/esm/internal/combine.js +2 -2
  34. package/dist/esm/internal/use-anchor-position.js +25 -1
  35. package/dist/esm/internal/use-animated-visibility.js +3 -3
  36. package/dist/esm/internal/use-focus-wrap.js +7 -7
  37. package/dist/esm/internal/use-initial-focus.js +1 -1
  38. package/dist/esm/popover/popover.js +9 -9
  39. package/dist/esm/popup/popup-content.js +2 -2
  40. package/dist/esm/popup/popup-trigger.js +2 -2
  41. package/dist/esm/use-simple-light-dismiss/index.js +1 -1
  42. package/dist/types/entry-points/open-layer-observer.d.ts +5 -0
  43. package/dist/types/internal/ensure-preset-styles.d.ts +1 -1
  44. package/dist/types/internal/use-anchor-position.d.ts +1 -1
  45. package/dist/types/internal/use-focus-wrap.d.ts +1 -1
  46. package/dist/types/popup/popup-content.d.ts +1 -1
  47. package/dist/types/popup/popup-trigger.d.ts +1 -1
  48. package/dist/types/use-simple-light-dismiss/index.d.ts +3 -3
  49. package/dist/types-ts4.5/entry-points/open-layer-observer.d.ts +5 -0
  50. package/dist/types-ts4.5/internal/ensure-preset-styles.d.ts +1 -1
  51. package/dist/types-ts4.5/internal/use-anchor-position.d.ts +1 -1
  52. package/dist/types-ts4.5/internal/use-focus-wrap.d.ts +1 -1
  53. package/dist/types-ts4.5/popup/popup-content.d.ts +1 -1
  54. package/dist/types-ts4.5/popup/popup-trigger.d.ts +1 -1
  55. package/dist/types-ts4.5/use-simple-light-dismiss/index.d.ts +3 -3
  56. package/open-layer-observer/package.json +17 -0
  57. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,112 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 0.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`2bed6255731de`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/2bed6255731de) -
8
+ Top-layer adoption work behind the `platform-dst-top-layer` feature flag. Public adopter APIs are
9
+ intentionally kept narrow while the top-layer API surface settles, with one exception called out
10
+ below.
11
+
12
+ Highlights:
13
+ - Pass the full `[along, away]` legacy popper offset through to the new top-layer
14
+ `placement.offset` API (via `fromLegacyPlacement`). Previously only the `away` axis was
15
+ forwarded, which dropped the `along` offset for consumers of `Popup`, `PopupSelect`,
16
+ `Spotlight`, and `Tooltip` when `platform-dst-top-layer` is enabled.
17
+ - Fix broken import of `dialogHeight` and `dialogWidth` from the removed utils module in
18
+ `@atlaskit/modal-dialog`.
19
+
20
+ Public API:
21
+ - **`@atlaskit/tooltip`** (`minor`): add an optional `testId?: string` field to `TriggerProps`.
22
+ This is additive (no existing prop changes shape). Required because `@atlaskit/button/new` (and
23
+ other `Pressable`-backed primitives) overwrite `data-testid` from spread, so the legacy
24
+ `(triggerProps as any)['data-testid']` workaround is silently absorbed by those consumers. A
25
+ typed `testId` field flows through their own `testId` destructure instead, restoring
26
+ `data-testid` propagation onto the rendered trigger element.
27
+ - **`@atlaskit/popup`**, **`@atlaskit/dropdown-menu`** (`patch`): no public type changes. Wider
28
+ `aria-haspopup` unions that the FF-on path produces are bridged at the package boundary into
29
+ `@atlaskit/top-layer` with localised `FUDGE(top-layer-api)` casts, documented in
30
+ `packages/design-system/top-layer/notes/decisions/migration-roadmap.md` ("Open API decisions
31
+ deferred to a follow-up PR"). They will be widened in a follow-up `minor` PR once the top-layer
32
+ API is committed.
33
+ - **`@atlaskit/modal-dialog`**, **`@atlaskit/select`**, **`@atlaskit/spotlight`**
34
+ (`patch`/`minor`): no public type changes; bug fixes only.
35
+
36
+ Merge-readiness fixes (FF-on test wiring + adopter behavior):
37
+ - **`@atlaskit/popup`** (`minor`): wire the compositional `PopupContent` to delegate to
38
+ `PopupContentTopLayer` when `platform-dst-top-layer` is enabled. Previously only the legacy
39
+ `Popup` component had the FF branch, leaving consumers of the compositional API on the legacy
40
+ popper path.
41
+ - **`@atlaskit/select`** (`minor`): add an `onClick` handler to the `PopupSelect` top-layer
42
+ trigger so clicks open/close the menu (mirrors the legacy global click handler in
43
+ `popup-select.tsx`). Add explicit Escape handling on the menu's `onKeyDown` so the menu closes
44
+ and focus returns to the trigger.
45
+ - **`@atlaskit/top-layer`** (`patch`): the `<dialog>` rendered by the Dialog primitive now sets
46
+ `aria-modal="true"` explicitly. Modern browsers infer modal semantics from `.showModal()` but
47
+ some assistive tech still keys off the explicit attribute.
48
+ - **`@atlaskit/top-layer`** (`patch`): guard `use-anchor-positioning` against environments where
49
+ `ResizeObserver` is not defined (e.g. jest's `node` environment, used by the post-office test
50
+ suite). The observer is used to wait for the popover's first valid layout before measuring;
51
+ consumers in non-DOM jest environments now get a no-op observer and the scroll/resize listeners
52
+ still apply if the host environment polyfills `showPopover`. Real browsers always have
53
+ `ResizeObserver`.
54
+ - **`@atlaskit/modal-dialog`** (`patch`): on the FF-on path, drop the `tabIndex={-1}` (and unused
55
+ `:focus-visible` outline) from the modal content wrapper. The native `<dialog>.showModal()`
56
+ focus-delegate algorithm picks the first focusable descendant (including `tabindex=-1`), and the
57
+ wrapper was hijacking initial focus from the close button. Also honor `shouldReturnFocus={ref}`
58
+ on the FF-on path (an unmount-cleanup focuses the ref after `dialog.close()` so it overrides the
59
+ browser's automatic return-to-trigger). Boolean `shouldReturnFocus={false}` is not yet honored
60
+ on the FF-on path — see `top-layer/notes/merge-blockers.md`.
61
+ - **`@atlaskit/datetime-picker`** (`patch`): on the FF-on path, set `mode="manual"` on the
62
+ `Popup.Content` rendered by both `internal/menu-top-layer.tsx` (date-picker calendar) and
63
+ `internal/fixed-layer-menu-top-layer.tsx` (time-picker menu). With the default `mode="auto"`,
64
+ the same click event that opens the menu (which targets the react-select combobox input —
65
+ outside the popover element) bubbles to the browser's native popover light-dismiss handler and
66
+ immediately closes the menu. react-select / DateTimePicker already own outside-click and Esc
67
+ dismissal via their own state, so opting out of the native auto-dismiss is the correct
68
+ integration. Also extend the existing Esc → trigger-focus restoration in
69
+ `components/date-picker.tsx` to the FF-on path (manual mode disables the browser's built-in
70
+ focus return, and the legacy code path was already handling this for itself behind an FF
71
+ negation).
72
+ - **`@atlaskit/popup`** (no public API change): no source changes — only FF-on Playwright
73
+ spec/example fixes drove the suite from 21/3/2 to 27/0/0. Notable: the two `test.fixme`'d
74
+ nested-popover cases were not browser limitations; `popover="auto"` chains correctly via DOM
75
+ ancestry (the original fixmes had the wrong testId selector). Added `testId` props to two
76
+ examples (`16-popup-with-a11y-props`, `18-should-fit-container`) so default-shape tests can
77
+ reach the trigger.
78
+ - Test alignment for FF-on Playwright suites across `popup`, `select`, `datetime-picker`,
79
+ `inline-dialog`, `inline-message`, and `modal-dialog`: selector updates to match the new
80
+ top-layer testId convention (`${testId}--content`, `[role="dialog"][aria-label="calendar"]`),
81
+ per-spec `skipAxeCheck()` for example-level color-contrast violations unrelated to the
82
+ migration, and focus assertions adjusted to match native `<dialog>` / `Popup.Content` auto-focus
83
+ semantics (focus lands on the first focusable child, not the dialog container itself).
84
+ - **`@atlassian/capacity-planning-capacity-graph`**, **`@atlaskit/color-picker`**,
85
+ **`@atlassian/timeline-table`**, **`@atlassian/global-side-navigation`** (`patch`): scope `fg`
86
+ mocks in unit tests so `platform-dst-top-layer` returns `false`. JSDOM does not implement the
87
+ native Popover API (`showPopover`/`hidePopover`/`toggle` events), so leaving the gate ON in unit
88
+ tests caused popover content to remain in the DOM after close and broke close-behaviour
89
+ assertions. Browser coverage for the FF-on path is provided by the Playwright suites listed
90
+ above.
91
+ - **`@atlaskit/dropdown-menu`** (no public API change): test/example-only fixes for the FF-on
92
+ Playwright suite. Added `role="menuitem"` to the nested-trigger `ButtonItem` in
93
+ `examples/93-testing-nested-keyboard-navigation-top-layer.tsx` to satisfy axe's
94
+ `aria-required-children` rule on the parent menu. Added a `test.beforeEach(skipAxeCheck)` to
95
+ `dropdown-menu.spec.tsx` (FF-on suite) for example-level `color-contrast` violations on the
96
+ pre-existing `color.text.selected`/`color.background.selected` token pair (3.91:1). Replaced a
97
+ deadlocking `await expect(moveItem).not.toBeFocused()` pre-open assertion (Playwright's
98
+ auto-wait blocks 5s on the absent element) with `await expect(moveItem).not.toBeVisible()`.
99
+ Suite result: 22/22 passing.
100
+
101
+ ## 0.6.0
102
+
103
+ ### Minor Changes
104
+
105
+ - [`a75acf807a927`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a75acf807a927) -
106
+ The public APIs for the Open Layer Observer from @atlaskit/layering have been re-exported from the
107
+ @atlaskit/top-layer package. The long term vision is for all layering concerns to come from the
108
+ top-layer package.
109
+
3
110
  ## 0.5.1
4
111
 
5
112
  ### 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/audits/accessibility-audit-report.md`](notes/audits/accessibility-audit-report.md) for
132
+ [`notes/decisions/accessibility-audit-report.md`](notes/decisions/accessibility-audit-report.md) for
133
133
  details.
134
134
 
135
135
  | A11y criterion | Browser test |
@@ -150,4 +150,6 @@ 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.
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).
@@ -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,7 +128,12 @@ 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,
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",
132
137
  "aria-label": label,
133
138
  "aria-labelledby": label ? undefined : labelledBy,
134
139
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "OpenLayerObserver", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _openLayerObserver.OpenLayerObserver;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "OpenLayerObserverNamespaceProvider", {
13
+ enumerable: true,
14
+ get: function get() {
15
+ return _openLayerObserverNamespaceProvider.OpenLayerObserverNamespaceProvider;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "useNotifyOpenLayerObserver", {
19
+ enumerable: true,
20
+ get: function get() {
21
+ return _useNotifyOpenLayerObserver.useNotifyOpenLayerObserver;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "useOpenLayerObserver", {
25
+ enumerable: true,
26
+ get: function get() {
27
+ return _useOpenLayerObserver.useOpenLayerObserver;
28
+ }
29
+ });
30
+ var _openLayerObserver = require("@atlaskit/layering/experimental/open-layer-observer/open-layer-observer");
31
+ var _useNotifyOpenLayerObserver = require("@atlaskit/layering/experimental/use-notify-open-layer-observer");
32
+ var _useOpenLayerObserver = require("@atlaskit/layering/experimental/use-open-layer-observer");
33
+ var _openLayerObserverNamespaceProvider = require("@atlaskit/layering/experimental/open-layer-observer-namespace-provider");
@@ -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 (el) {
50
- return el instanceof HTMLElement;
51
- }).filter(function (el) {
52
- return !filter || filter(el, container);
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);
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 (fn) {
26
- return fn === null || fn === void 0 ? void 0 : fn();
25
+ cleanupFns.forEach(function (callback) {
26
+ return callback === null || callback === void 0 ? void 0 : callback();
27
27
  });
28
28
  };
29
29
  }
@@ -13,6 +13,8 @@ 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"));
16
18
  var _react = require("react");
17
19
  var _bindEventListener = require("bind-event-listener");
18
20
  var _rafSchd = _interopRequireDefault(require("raf-schd"));
@@ -473,7 +475,29 @@ function useAnchorPosition(_ref5) {
473
475
  // ResizeObserver fires once the browser has real dimensions.
474
476
  // Self-disconnects after one valid measurement; ongoing
475
477
  // scroll/resize is handled by the window listeners below.
476
- var resizeObserver = new ResizeObserver(function () {
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 () {
477
501
  if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
478
502
  update();
479
503
  resizeObserver.disconnect();
@@ -114,8 +114,8 @@ function useAnimatedVisibility(_ref) {
114
114
  if (isOpen || !showChildren || !willAnimate) {
115
115
  return;
116
116
  }
117
- var el = elementRef.current;
118
- if (!el) {
117
+ var element = elementRef.current;
118
+ if (!element) {
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)(el, {
132
+ var unbind = (0, _bindEventListener.bind)(element, {
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 el = elementRef.current;
53
- if (!el || !roleRequiresFocusWrap(role)) {
52
+ var element = elementRef.current;
53
+ if (!element || !roleRequiresFocusWrap(role)) {
54
54
  return;
55
55
  }
56
- var unbind = (0, _bindEventListener.bind)(el, {
56
+ var unbind = (0, _bindEventListener.bind)(element, {
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: el,
68
+ container: element,
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: el
80
+ container: element
81
81
  }) : (0, _focus.getLastFocusable)({
82
- container: el
82
+ container: element
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 el = ownRef.current;
129
+ var element = ownRef.current;
130
130
  if (event.newState === 'open') {
131
- if (el) {
131
+ if (element) {
132
132
  onOpenChange === null || onOpenChange === void 0 || onOpenChange({
133
133
  isOpen: true,
134
- element: el
134
+ element: element
135
135
  });
136
136
  }
137
137
  return;
138
138
  }
139
139
  if (event.newState === 'closed') {
140
- if (el) {
140
+ if (element) {
141
141
  onOpenChange === null || onOpenChange === void 0 || onOpenChange({
142
142
  isOpen: false,
143
- element: el
143
+ element: element
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 el = ownRef.current;
162
- if (!el) {
161
+ var element = ownRef.current;
162
+ if (!element) {
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)(el, {
167
+ var unbindEscape = (0, _bindEventListener.bind)(element, {
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)(el, {
178
+ var unbindToggle = (0, _bindEventListener.bind)(element, {
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 won't restore
100
+ // have shouldRestoreFocus=false, so the browser will not 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
- // doesn't need isOpen in its dependency array (which would recreate
43
+ // does not 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 doesn't re-bind on every render.
29
+ // Keep a stable ref to onClose so the effect does not 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,7 +120,12 @@ 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,
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",
124
129
  "aria-label": label,
125
130
  "aria-labelledby": label ? undefined : labelledBy,
126
131
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
@@ -0,0 +1,4 @@
1
+ export { OpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer/open-layer-observer';
2
+ export { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/use-notify-open-layer-observer';
3
+ export { useOpenLayerObserver } from '@atlaskit/layering/experimental/use-open-layer-observer';
4
+ export { OpenLayerObserverNamespaceProvider } from '@atlaskit/layering/experimental/open-layer-observer-namespace-provider';
@@ -39,7 +39,7 @@ function getFocusables({
39
39
  container,
40
40
  filter
41
41
  }) {
42
- return Array.from(container.querySelectorAll(selectors.focusable)).filter(el => el instanceof HTMLElement).filter(el => !filter || filter(el, container));
42
+ return Array.from(container.querySelectorAll(selectors.focusable)).filter(element => element instanceof HTMLElement).filter(element => !filter || filter(element, 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(fn => fn === null || fn === void 0 ? void 0 : fn());
16
+ cleanupFns.forEach(callback => callback === null || callback === void 0 ? void 0 : callback());
17
17
  };
18
18
  }
@@ -467,7 +467,19 @@ export function useAnchorPosition({
467
467
  // ResizeObserver fires once the browser has real dimensions.
468
468
  // Self-disconnects after one valid measurement; ongoing
469
469
  // scroll/resize is handled by the window listeners below.
470
- const resizeObserver = new ResizeObserver(() => {
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(() => {
471
483
  if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
472
484
  update();
473
485
  resizeObserver.disconnect();
@@ -104,8 +104,8 @@ export function useAnimatedVisibility({
104
104
  if (isOpen || !showChildren || !willAnimate) {
105
105
  return;
106
106
  }
107
- const el = elementRef.current;
108
- if (!el) {
107
+ const element = elementRef.current;
108
+ if (!element) {
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(el, {
122
+ const unbind = bind(element, {
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 el = elementRef.current;
49
- if (!el || !roleRequiresFocusWrap(role)) {
48
+ const element = elementRef.current;
49
+ if (!element || !roleRequiresFocusWrap(role)) {
50
50
  return;
51
51
  }
52
- const unbind = bind(el, {
52
+ const unbind = bind(element, {
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: el,
64
+ container: element,
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: el
76
+ container: element
77
77
  }) : getLastFocusable({
78
- container: el
78
+ container: element
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 el = ownRef.current;
119
+ const element = ownRef.current;
120
120
  if (event.newState === 'open') {
121
- if (el) {
121
+ if (element) {
122
122
  onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
123
123
  isOpen: true,
124
- element: el
124
+ element: element
125
125
  });
126
126
  }
127
127
  return;
128
128
  }
129
129
  if (event.newState === 'closed') {
130
- if (el) {
130
+ if (element) {
131
131
  onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange({
132
132
  isOpen: false,
133
- element: el
133
+ element: element
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 el = ownRef.current;
152
- if (!el) {
151
+ const element = ownRef.current;
152
+ if (!element) {
153
153
  return;
154
154
  }
155
155
 
156
156
  // Capture-phase: tag Escape before the browser processes light dismiss.
157
- const unbindEscape = bind(el, {
157
+ const unbindEscape = bind(element, {
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(el, {
168
+ const unbindToggle = bind(element, {
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 won't restore
91
+ // have shouldRestoreFocus=false, so the browser will not 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
- // doesn't need isOpen in its dependency array (which would recreate
37
+ // does not 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 doesn't re-bind on every render.
24
+ // Keep a stable ref to onClose so the effect does not 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,7 +119,12 @@ 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,
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",
123
128
  "aria-label": label,
124
129
  "aria-labelledby": label ? undefined : labelledBy,
125
130
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
@@ -0,0 +1,4 @@
1
+ export { OpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer/open-layer-observer';
2
+ export { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/use-notify-open-layer-observer';
3
+ export { useOpenLayerObserver } from '@atlaskit/layering/experimental/use-open-layer-observer';
4
+ export { OpenLayerObserverNamespaceProvider } from '@atlaskit/layering/experimental/open-layer-observer-namespace-provider';
@@ -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 (el) {
42
- return el instanceof HTMLElement;
43
- }).filter(function (el) {
44
- return !filter || filter(el, container);
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);
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 (fn) {
20
- return fn === null || fn === void 0 ? void 0 : fn();
19
+ cleanupFns.forEach(function (callback) {
20
+ return callback === null || callback === void 0 ? void 0 : callback();
21
21
  });
22
22
  };
23
23
  }
@@ -1,3 +1,5 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/createClass";
1
3
  /**
2
4
  * Anchor positioning for top-layer popovers. See
3
5
  * `notes/architecture/positioning.md` for the full model.
@@ -459,7 +461,29 @@ export function useAnchorPosition(_ref5) {
459
461
  // ResizeObserver fires once the browser has real dimensions.
460
462
  // Self-disconnects after one valid measurement; ongoing
461
463
  // scroll/resize is handled by the window listeners below.
462
- var resizeObserver = new ResizeObserver(function () {
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 () {
463
487
  if (popover.offsetWidth > 0 && popover.offsetHeight > 0) {
464
488
  update();
465
489
  resizeObserver.disconnect();
@@ -107,8 +107,8 @@ export function useAnimatedVisibility(_ref) {
107
107
  if (isOpen || !showChildren || !willAnimate) {
108
108
  return;
109
109
  }
110
- var el = elementRef.current;
111
- if (!el) {
110
+ var element = elementRef.current;
111
+ if (!element) {
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(el, {
125
+ var unbind = bind(element, {
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 el = elementRef.current;
48
- if (!el || !roleRequiresFocusWrap(role)) {
47
+ var element = elementRef.current;
48
+ if (!element || !roleRequiresFocusWrap(role)) {
49
49
  return;
50
50
  }
51
- var unbind = bind(el, {
51
+ var unbind = bind(element, {
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: el,
63
+ container: element,
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: el
75
+ container: element
76
76
  }) : getLastFocusable({
77
- container: el
77
+ container: element
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 el = ownRef.current;
120
+ var element = ownRef.current;
121
121
  if (event.newState === 'open') {
122
- if (el) {
122
+ if (element) {
123
123
  onOpenChange === null || onOpenChange === void 0 || onOpenChange({
124
124
  isOpen: true,
125
- element: el
125
+ element: element
126
126
  });
127
127
  }
128
128
  return;
129
129
  }
130
130
  if (event.newState === 'closed') {
131
- if (el) {
131
+ if (element) {
132
132
  onOpenChange === null || onOpenChange === void 0 || onOpenChange({
133
133
  isOpen: false,
134
- element: el
134
+ element: element
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 el = ownRef.current;
153
- if (!el) {
152
+ var element = ownRef.current;
153
+ if (!element) {
154
154
  return;
155
155
  }
156
156
 
157
157
  // Capture-phase: tag Escape before the browser processes light dismiss.
158
- var unbindEscape = bind(el, {
158
+ var unbindEscape = bind(element, {
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(el, {
169
+ var unbindToggle = bind(element, {
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 won't restore
91
+ // have shouldRestoreFocus=false, so the browser will not 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
- // doesn't need isOpen in its dependency array (which would recreate
35
+ // does not 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 doesn't re-bind on every render.
23
+ // Keep a stable ref to onClose so the effect does not re-bind on every render.
24
24
  var onCloseRef = useRef(onClose);
25
25
  onCloseRef.current = onClose;
26
26
  useEffect(function () {
@@ -0,0 +1,5 @@
1
+ export { OpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer/open-layer-observer';
2
+ export { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/use-notify-open-layer-observer';
3
+ export { useOpenLayerObserver } from '@atlaskit/layering/experimental/use-open-layer-observer';
4
+ export { OpenLayerObserverNamespaceProvider } from '@atlaskit/layering/experimental/open-layer-observer-namespace-provider';
5
+ export type { LayerType } from '@atlaskit/layering/experimental/types';
@@ -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;
@@ -118,7 +118,7 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, fo
118
118
  * the preset's named `@position-try` rules (which update both
119
119
  * `position-area` and `margin` on flip) and sets `--ds-arrow-size`.
120
120
  *
121
- * Pass `null` to disable. Has no effect in the JS fallback path —
121
+ * Pass `null` to disable. Has no effect in the JS fallback path -
122
122
  * arrows are CSS-only.
123
123
  */
124
124
  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: {
@@ -0,0 +1,5 @@
1
+ export { OpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer/open-layer-observer';
2
+ export { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/use-notify-open-layer-observer';
3
+ export { useOpenLayerObserver } from '@atlaskit/layering/experimental/use-open-layer-observer';
4
+ export { OpenLayerObserverNamespaceProvider } from '@atlaskit/layering/experimental/open-layer-observer-namespace-provider';
5
+ export type { LayerType } from '@atlaskit/layering/experimental/types';
@@ -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;
@@ -118,7 +118,7 @@ export declare function useAnchorPosition({ anchorRef, popoverRef, placement, fo
118
118
  * the preset's named `@position-try` rules (which update both
119
119
  * `position-area` and `margin` on flip) and sets `--ds-arrow-size`.
120
120
  *
121
- * Pass `null` to disable. Has no effect in the JS fallback path —
121
+ * Pass `null` to disable. Has no effect in the JS fallback path -
122
122
  * arrows are CSS-only.
123
123
  */
124
124
  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: {
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@atlaskit/top-layer/open-layer-observer",
3
+ "main": "../dist/cjs/entry-points/open-layer-observer.js",
4
+ "module": "../dist/esm/entry-points/open-layer-observer.js",
5
+ "module:es2019": "../dist/es2019/entry-points/open-layer-observer.js",
6
+ "sideEffects": [
7
+ "*.compiled.css"
8
+ ],
9
+ "types": "../dist/types/entry-points/open-layer-observer.d.ts",
10
+ "typesVersions": {
11
+ ">=4.5 <5.9": {
12
+ "*": [
13
+ "../dist/types-ts4.5/entry-points/open-layer-observer.d.ts"
14
+ ]
15
+ }
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/top-layer",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
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",
@@ -37,6 +37,7 @@
37
37
  "@atlaskit/browser-apis": "^0.0.1",
38
38
  "@atlaskit/css": "^0.19.0",
39
39
  "@atlaskit/ds-lib": "^7.0.0",
40
+ "@atlaskit/layering": "^3.7.0",
40
41
  "@atlaskit/tokens": "^13.0.0",
41
42
  "@babel/runtime": "^7.0.0",
42
43
  "@compiled/react": "^0.20.0",