@atlaskit/top-layer 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/entry-points/focus.js +6 -4
  3. package/dist/cjs/entry-points/use-anchor-position-at-point.js +12 -0
  4. package/dist/cjs/focus/get-first-focusable.js +19 -0
  5. package/dist/cjs/focus/get-focusables.js +30 -0
  6. package/dist/cjs/focus/get-last-focusable.js +19 -0
  7. package/dist/cjs/focus/get-next-focusable.js +43 -0
  8. package/dist/cjs/focus/is-in-same-layer.js +23 -0
  9. package/dist/cjs/focus/is-nested-layer-focused.js +32 -0
  10. package/dist/cjs/focus/selectors.js +19 -0
  11. package/dist/cjs/focus/types.js +1 -0
  12. package/dist/cjs/internal/role-to-aria-has-popup.js +37 -0
  13. package/dist/cjs/internal/role-types.js +1 -97
  14. package/dist/cjs/internal/should-focus-into-popover.js +19 -0
  15. package/dist/cjs/internal/use-anchor-position-at-point.js +127 -0
  16. package/dist/cjs/internal/use-anchor-position.js +7 -3
  17. package/dist/cjs/internal/use-focus-wrap.js +8 -5
  18. package/dist/cjs/internal/use-initial-focus.js +4 -4
  19. package/dist/cjs/placement-map/index.js +2 -2
  20. package/dist/cjs/placement-map/legacy-placements.js +2 -101
  21. package/dist/cjs/placement-map/placement-mapping.js +103 -0
  22. package/dist/cjs/popup/popup-content.js +4 -3
  23. package/dist/cjs/use-arrow-navigation/use-arrow-navigation.js +7 -5
  24. package/dist/es2019/entry-points/focus.js +3 -1
  25. package/dist/es2019/entry-points/use-anchor-position-at-point.js +1 -0
  26. package/dist/es2019/focus/get-first-focusable.js +14 -0
  27. package/dist/es2019/focus/get-focusables.js +19 -0
  28. package/dist/es2019/focus/get-last-focusable.js +14 -0
  29. package/dist/es2019/focus/get-next-focusable.js +38 -0
  30. package/dist/es2019/focus/is-in-same-layer.js +18 -0
  31. package/dist/es2019/focus/is-nested-layer-focused.js +28 -0
  32. package/dist/es2019/focus/selectors.js +11 -0
  33. package/dist/es2019/focus/types.js +0 -0
  34. package/dist/es2019/internal/role-to-aria-has-popup.js +32 -0
  35. package/dist/es2019/internal/role-types.js +0 -92
  36. package/dist/es2019/internal/should-focus-into-popover.js +14 -0
  37. package/dist/es2019/internal/use-anchor-position-at-point.js +122 -0
  38. package/dist/es2019/internal/use-anchor-position.js +6 -3
  39. package/dist/es2019/internal/use-focus-wrap.js +4 -1
  40. package/dist/es2019/internal/use-initial-focus.js +1 -1
  41. package/dist/es2019/placement-map/index.js +1 -1
  42. package/dist/es2019/placement-map/legacy-placements.js +1 -100
  43. package/dist/es2019/placement-map/placement-mapping.js +97 -0
  44. package/dist/es2019/popup/popup-content.js +2 -1
  45. package/dist/es2019/use-arrow-navigation/use-arrow-navigation.js +3 -1
  46. package/dist/esm/entry-points/focus.js +3 -1
  47. package/dist/esm/entry-points/use-anchor-position-at-point.js +1 -0
  48. package/dist/esm/focus/get-first-focusable.js +13 -0
  49. package/dist/esm/focus/get-focusables.js +24 -0
  50. package/dist/esm/focus/get-last-focusable.js +13 -0
  51. package/dist/esm/focus/get-next-focusable.js +37 -0
  52. package/dist/esm/focus/is-in-same-layer.js +17 -0
  53. package/dist/esm/focus/is-nested-layer-focused.js +27 -0
  54. package/dist/esm/focus/selectors.js +13 -0
  55. package/dist/esm/focus/types.js +0 -0
  56. package/dist/esm/internal/role-to-aria-has-popup.js +31 -0
  57. package/dist/esm/internal/role-types.js +0 -90
  58. package/dist/esm/internal/should-focus-into-popover.js +13 -0
  59. package/dist/esm/internal/use-anchor-position-at-point.js +122 -0
  60. package/dist/esm/internal/use-anchor-position.js +7 -3
  61. package/dist/esm/internal/use-focus-wrap.js +4 -1
  62. package/dist/esm/internal/use-initial-focus.js +1 -1
  63. package/dist/esm/placement-map/index.js +1 -1
  64. package/dist/esm/placement-map/legacy-placements.js +1 -100
  65. package/dist/esm/placement-map/placement-mapping.js +97 -0
  66. package/dist/esm/popup/popup-content.js +2 -1
  67. package/dist/esm/use-arrow-navigation/use-arrow-navigation.js +3 -1
  68. package/dist/types/entry-points/focus.d.ts +4 -2
  69. package/dist/types/entry-points/use-anchor-position-at-point.d.ts +1 -0
  70. package/dist/types/focus/get-first-focusable.d.ts +8 -0
  71. package/dist/types/focus/get-focusables.d.ts +13 -0
  72. package/dist/types/focus/get-last-focusable.d.ts +8 -0
  73. package/dist/types/focus/get-next-focusable.d.ts +13 -0
  74. package/dist/types/focus/is-in-same-layer.d.ts +8 -0
  75. package/dist/types/focus/is-nested-layer-focused.d.ts +8 -0
  76. package/dist/types/focus/selectors.d.ts +4 -0
  77. package/dist/types/focus/types.d.ts +5 -0
  78. package/dist/types/internal/role-to-aria-has-popup.d.ts +13 -0
  79. package/dist/types/internal/role-types.d.ts +0 -19
  80. package/dist/types/internal/should-focus-into-popover.d.ts +8 -0
  81. package/dist/types/internal/use-anchor-position-at-point.d.ts +62 -0
  82. package/dist/types/internal/use-anchor-position.d.ts +6 -1
  83. package/dist/types/placement-map/index.d.ts +1 -1
  84. package/dist/types/placement-map/legacy-placements.d.ts +0 -12
  85. package/dist/types/placement-map/placement-mapping.d.ts +13 -0
  86. package/dist/types/use-arrow-navigation/use-arrow-navigation.d.ts +1 -1
  87. package/dist/types-ts4.5/entry-points/focus.d.ts +4 -2
  88. package/dist/types-ts4.5/entry-points/use-anchor-position-at-point.d.ts +1 -0
  89. package/dist/types-ts4.5/focus/get-first-focusable.d.ts +8 -0
  90. package/dist/types-ts4.5/focus/get-focusables.d.ts +13 -0
  91. package/dist/types-ts4.5/focus/get-last-focusable.d.ts +8 -0
  92. package/dist/types-ts4.5/focus/get-next-focusable.d.ts +13 -0
  93. package/dist/types-ts4.5/focus/is-in-same-layer.d.ts +8 -0
  94. package/dist/types-ts4.5/focus/is-nested-layer-focused.d.ts +8 -0
  95. package/dist/types-ts4.5/focus/selectors.d.ts +4 -0
  96. package/dist/types-ts4.5/focus/types.d.ts +5 -0
  97. package/dist/types-ts4.5/internal/role-to-aria-has-popup.d.ts +13 -0
  98. package/dist/types-ts4.5/internal/role-types.d.ts +0 -19
  99. package/dist/types-ts4.5/internal/should-focus-into-popover.d.ts +8 -0
  100. package/dist/types-ts4.5/internal/use-anchor-position-at-point.d.ts +62 -0
  101. package/dist/types-ts4.5/internal/use-anchor-position.d.ts +6 -1
  102. package/dist/types-ts4.5/placement-map/index.d.ts +1 -1
  103. package/dist/types-ts4.5/placement-map/legacy-placements.d.ts +0 -12
  104. package/dist/types-ts4.5/placement-map/placement-mapping.d.ts +13 -0
  105. package/dist/types-ts4.5/use-arrow-navigation/use-arrow-navigation.d.ts +1 -1
  106. package/package.json +1 -1
  107. package/use-anchor-position-at-point/package.json +17 -0
  108. package/dist/cjs/focus/focus.js +0 -169
  109. package/dist/cjs/focus/index.js +0 -24
  110. package/dist/es2019/focus/focus.js +0 -158
  111. package/dist/es2019/focus/index.js +0 -1
  112. package/dist/esm/focus/focus.js +0 -160
  113. package/dist/esm/focus/index.js +0 -1
  114. package/dist/types/focus/focus.d.ts +0 -50
  115. package/dist/types/focus/index.d.ts +0 -2
  116. package/dist/types-ts4.5/focus/focus.d.ts +0 -50
  117. package/dist/types-ts4.5/focus/index.d.ts +0 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`cf4af9aa9a2fe`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/cf4af9aa9a2fe) -
8
+ Fix tooltip with `position="mouse-x"` / `position="mouse-y"` not respecting the `mousePosition`
9
+ prop when the `platform-dst-top-layer` feature flag is enabled.
10
+
11
+ The cursor-anchored tooltip is now positioned via a new `useAnchorPositionAtPoint` hook in
12
+ `@atlaskit/top-layer`, which delegates to `useAnchorPosition` against a hidden anchor element
13
+ placed once at the cursor location at show time. The popover stays anchored at that location and
14
+ does not follow subsequent pointer movement.
15
+
16
+ `useAnchorPosition` now also accepts an optional `isEnabled` prop (defaults to `true`); when
17
+ `false`, the hook is a no-op.
18
+
3
19
  ## 0.12.2
4
20
 
5
21
  ### Patch Changes
@@ -6,19 +6,21 @@ Object.defineProperty(exports, "__esModule", {
6
6
  Object.defineProperty(exports, "getFirstFocusable", {
7
7
  enumerable: true,
8
8
  get: function get() {
9
- return _focus.getFirstFocusable;
9
+ return _getFirstFocusable.getFirstFocusable;
10
10
  }
11
11
  });
12
12
  Object.defineProperty(exports, "getLastFocusable", {
13
13
  enumerable: true,
14
14
  get: function get() {
15
- return _focus.getLastFocusable;
15
+ return _getLastFocusable.getLastFocusable;
16
16
  }
17
17
  });
18
18
  Object.defineProperty(exports, "getNextFocusable", {
19
19
  enumerable: true,
20
20
  get: function get() {
21
- return _focus.getNextFocusable;
21
+ return _getNextFocusable.getNextFocusable;
22
22
  }
23
23
  });
24
- var _focus = require("../focus");
24
+ var _getFirstFocusable = require("../focus/get-first-focusable");
25
+ var _getLastFocusable = require("../focus/get-last-focusable");
26
+ var _getNextFocusable = require("../focus/get-next-focusable");
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "useAnchorPositionAtPoint", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _useAnchorPositionAtPoint.useAnchorPositionAtPoint;
10
+ }
11
+ });
12
+ var _useAnchorPositionAtPoint = require("../internal/use-anchor-position-at-point");
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getFirstFocusable = getFirstFocusable;
7
+ var _getFocusables = require("./get-focusables");
8
+ /**
9
+ * Returns the first focusable element within the container.
10
+ */
11
+ function getFirstFocusable(_ref) {
12
+ var container = _ref.container,
13
+ filter = _ref.filter;
14
+ var items = (0, _getFocusables.getFocusables)({
15
+ container: container,
16
+ filter: filter
17
+ });
18
+ return items.length > 0 ? items[0] : null;
19
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getFocusables = getFocusables;
7
+ var _isInSameLayer = require("./is-in-same-layer");
8
+ var _selectors = require("./selectors");
9
+ /**
10
+ * Returns all focusable HTMLElements within the container, optionally filtered.
11
+ *
12
+ * Focusables that belong to a nested top-layer scope (a `[popover]` or
13
+ * `<dialog>` descendant of the container) are excluded - those elements
14
+ * are owned by the inner layer's focus management. The container itself
15
+ * is allowed to be a popover/dialog; only nested ones are filtered.
16
+ */
17
+ function getFocusables(_ref) {
18
+ var container = _ref.container,
19
+ filter = _ref.filter;
20
+ return Array.from(container.querySelectorAll(_selectors.selectors.focusable)).filter(function (element) {
21
+ return element instanceof HTMLElement;
22
+ }).filter(function (element) {
23
+ return (0, _isInSameLayer.isInSameLayer)({
24
+ element: element,
25
+ container: container
26
+ });
27
+ }).filter(function (element) {
28
+ return !filter || filter(element, container);
29
+ });
30
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getLastFocusable = getLastFocusable;
7
+ var _getFocusables = require("./get-focusables");
8
+ /**
9
+ * Returns the last focusable element within the container.
10
+ */
11
+ function getLastFocusable(_ref) {
12
+ var container = _ref.container,
13
+ filter = _ref.filter;
14
+ var items = (0, _getFocusables.getFocusables)({
15
+ container: container,
16
+ filter: filter
17
+ });
18
+ return items.length > 0 ? items[items.length - 1] : null;
19
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getNextFocusable = getNextFocusable;
7
+ var _getFocusables = require("./get-focusables");
8
+ var _selectors = require("./selectors");
9
+ /**
10
+ * Returns the next focusable element in the given direction relative to the
11
+ * currently focused element within the container. Wraps around at both ends.
12
+ *
13
+ * Returns `null` if there is no focused element within the container or if
14
+ * the focused element is not in the list of focusable elements.
15
+ */
16
+
17
+ function getNextFocusable(_ref) {
18
+ var _all$nextIndex;
19
+ var container = _ref.container,
20
+ direction = _ref.direction,
21
+ filter = _ref.filter;
22
+ var all = (0, _getFocusables.getFocusables)({
23
+ container: container,
24
+ filter: filter
25
+ });
26
+ var current = container.querySelector(_selectors.selectors.focused);
27
+ if (!(current instanceof HTMLElement)) {
28
+ return null;
29
+ }
30
+ var index = all.indexOf(current);
31
+ if (index === -1) {
32
+ return null;
33
+ }
34
+ var nextIndex = function () {
35
+ if (direction === 'forwards') {
36
+ return (index + 1) % all.length;
37
+ }
38
+ var proposed = index - 1;
39
+ // if going into negative numbers, loop back to the last item
40
+ return proposed < 0 ? all.length - 1 : proposed;
41
+ }();
42
+ return (_all$nextIndex = all[nextIndex]) !== null && _all$nextIndex !== void 0 ? _all$nextIndex : null;
43
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isInSameLayer = isInSameLayer;
7
+ var topLayerSelector = '[popover], dialog, [role="dialog"], [role="alertdialog"]';
8
+
9
+ /**
10
+ * Returns true when `element` and `container` resolve to the same nearest
11
+ * top-layer host (or both resolve to `null`, meaning the document layer).
12
+ */
13
+ function isInSameLayer(_ref) {
14
+ var element = _ref.element,
15
+ container = _ref.container;
16
+ var elementLayer = element.closest(topLayerSelector);
17
+ var containerLayer = container.closest(topLayerSelector);
18
+ // Both elements are in the "document" layer
19
+ if (!elementLayer && !containerLayer) {
20
+ return true;
21
+ }
22
+ return elementLayer === containerLayer;
23
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isNestedLayerFocused = isNestedLayerFocused;
7
+ var _browserApis = require("@atlaskit/browser-apis");
8
+ var _isInSameLayer = require("./is-in-same-layer");
9
+ /**
10
+ * Returns `true` when `document.activeElement` is inside a nested top-layer
11
+ * descendant of `container` (a `[popover]`, `<dialog>`, `[role="dialog"]` or
12
+ * `[role="alertdialog"]` that is itself a descendant of `container`).
13
+ */
14
+ function isNestedLayerFocused(_ref) {
15
+ var _getDocument;
16
+ var container = _ref.container;
17
+ var focused = (_getDocument = (0, _browserApis.getDocument)()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement;
18
+ if (!(focused instanceof HTMLElement)) {
19
+ return false;
20
+ }
21
+
22
+ // Cannot be in a nested layer if it is not in the container
23
+ if (!container.contains(focused)) {
24
+ return false;
25
+ }
26
+
27
+ // If not in the same layer, must be in a nested layer
28
+ return !(0, _isInSameLayer.isInSameLayer)({
29
+ element: focused,
30
+ container: container
31
+ });
32
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.selectors = void 0;
7
+ var selectors = exports.selectors = function () {
8
+ // Common exclusion filter applied to every selector.
9
+ var not = ':not([tabindex="-1"]):not([aria-disabled="true"]):not([aria-hidden="true"])';
10
+ var notDisabled = ":not([disabled])".concat(not);
11
+ var focusable = ["a[href]".concat(not), "area[href]".concat(not), "input".concat(notDisabled, ":not([type=\"hidden\"])"), "select".concat(notDisabled), "textarea".concat(notDisabled), "button".concat(notDisabled), "iframe".concat(not), "audio[controls]".concat(not), "video[controls]".concat(not), "[contenteditable]:not([contenteditable=\"false\"])".concat(not), "[tabindex]".concat(notDisabled).concat(not)];
12
+ return {
13
+ focusable: focusable.join(','),
14
+ // Build the `:focus` selector
15
+ focused: focusable.map(function (selector) {
16
+ return "".concat(selector, ":focus");
17
+ }).join(',')
18
+ };
19
+ }();
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.roleToAriaHasPopup = roleToAriaHasPopup;
7
+ /**
8
+ * Maps a popover content role to the correct `aria-haspopup` value
9
+ * for its trigger element.
10
+ *
11
+ * Returns `undefined` for roles that are not popups in the ARIA sense
12
+ * (`tooltip`, `note`, `status`, `alert`, `log`). Triggers for those roles
13
+ * should not announce a popup at all - emitting `aria-haspopup="dialog"`
14
+ * on a tooltip trigger would mislead assistive technology.
15
+ */
16
+ function roleToAriaHasPopup(_ref) {
17
+ var role = _ref.role;
18
+ if (role === 'menu') {
19
+ return 'menu';
20
+ }
21
+ if (role === 'listbox') {
22
+ return 'listbox';
23
+ }
24
+ if (role === 'tree') {
25
+ return 'tree';
26
+ }
27
+ if (role === 'grid') {
28
+ return 'grid';
29
+ }
30
+ if (role === 'dialog' || role === 'alertdialog') {
31
+ return 'dialog';
32
+ }
33
+ // Non-popup roles (tooltip, note, status, alert, log) and the
34
+ // no-role case: omit `aria-haspopup` entirely. React drops the
35
+ // attribute when the value is `undefined`.
36
+ return undefined;
37
+ }
@@ -1,97 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.roleToAriaHasPopup = roleToAriaHasPopup;
7
- exports.shouldFocusIntoPopover = shouldFocusIntoPopover;
8
- /**
9
- * Valid values for the `aria-haspopup` attribute.
10
- *
11
- * Derived from the HTML spec - maps popover roles to what the trigger
12
- * announces. `undefined` means the attribute is omitted entirely (used for
13
- * non-popup roles like `tooltip`/`status`/`alert`/`note`/`log` where
14
- * `aria-haspopup` would be misleading).
15
- *
16
- * `true` is intentionally NOT in the union - the runtime only ever produces
17
- * the explicit string forms, so widening the type would invite consumers to
18
- * pass `true` and get an `aria-haspopup="true"` serialisation that the
19
- * runtime no longer emits.
20
- */
21
-
22
- /**
23
- * Roles that require an accessible name (`label` or `labelledBy`) per WCAG 4.1.2.
24
- * Without a name, assistive technology cannot identify these landmarks.
25
- */
26
-
27
- /**
28
- * Roles where the accessible name is derived from content or provided externally
29
- * (e.g. a combobox labels its listbox, tooltip content IS the accessible name).
30
- */
31
-
32
- // Shared ARIA role discrimination types
33
- //
34
- // These encode the WCAG 4.1.2 constraint: roles like `dialog`, `alertdialog`,
35
- // and `menu` MUST have an accessible name (either `label` or `labelledBy`).
36
- // TypeScript enforces this at compile time via discriminated unions.
37
-
38
- /**
39
- * ARIA role props where a role is always required.
40
- *
41
- * Used by `TPopupContentProps`. Popup content must always declare
42
- * its role so assistive technology can identify the layer.
43
- */
44
-
45
- /**
46
- * ARIA role props where a role is optional.
47
- *
48
- * Used by `TPopoverProps`. The low-level primitive allows omitting
49
- * the role for cases where it is set externally or not needed.
50
- */
51
-
52
- /**
53
- * Maps a popover content role to the correct `aria-haspopup` value
54
- * for its trigger element.
55
- *
56
- * Returns `undefined` for roles that are not popups in the ARIA sense
57
- * (`tooltip`, `note`, `status`, `alert`, `log`). Triggers for those roles
58
- * should not announce a popup at all - emitting `aria-haspopup="dialog"`
59
- * on a tooltip trigger would mislead assistive technology.
60
- */
61
- // eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
62
- function roleToAriaHasPopup(_ref) {
63
- var role = _ref.role;
64
- if (role === 'menu') {
65
- return 'menu';
66
- }
67
- if (role === 'listbox') {
68
- return 'listbox';
69
- }
70
- if (role === 'tree') {
71
- return 'tree';
72
- }
73
- if (role === 'grid') {
74
- return 'grid';
75
- }
76
- if (role === 'dialog' || role === 'alertdialog') {
77
- return 'dialog';
78
- }
79
- // Non-popup roles (tooltip, note, status, alert, log) and the
80
- // no-role case: omit `aria-haspopup` entirely. React drops the
81
- // attribute when the value is `undefined`.
82
- return undefined;
83
- }
84
- var rolesThatMoveFocus = new Set(['dialog', 'alertdialog', 'menu', 'listbox', 'tree', 'grid']);
85
-
86
- /**
87
- * Returns `true` when the given popover role moves focus into the popover
88
- * on open, and `false` otherwise (including when `role` is `undefined`).
89
- */
90
- // eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
91
- function shouldFocusIntoPopover(_ref2) {
92
- var role = _ref2.role;
93
- if (!role) {
94
- return false;
95
- }
96
- return rolesThatMoveFocus.has(role);
97
- }
1
+ "use strict";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.shouldFocusIntoPopover = shouldFocusIntoPopover;
7
+ var rolesThatMoveFocus = new Set(['dialog', 'alertdialog', 'menu', 'listbox', 'tree', 'grid']);
8
+
9
+ /**
10
+ * Returns `true` when the given popover role moves focus into the popover
11
+ * on open, and `false` otherwise (including when `role` is `undefined`).
12
+ */
13
+ function shouldFocusIntoPopover(_ref) {
14
+ var role = _ref.role;
15
+ if (!role) {
16
+ return false;
17
+ }
18
+ return rolesThatMoveFocus.has(role);
19
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useAnchorPositionAtPoint = useAnchorPositionAtPoint;
7
+ var _react = require("react");
8
+ var _useAnchorPosition = require("./use-anchor-position");
9
+ /**
10
+ * A point in viewport coordinates (CSS pixels) at which the synthetic
11
+ * anchor should be placed.
12
+ *
13
+ * Axis-named (`x`/`y`) rather than edge-named (`left`/`top`) so the
14
+ * shape is unambiguous in RTL writing modes — there is no ambiguity
15
+ * about whether a coordinate is logical (`inline-start`/`block-start`)
16
+ * or physical (`left`/`top`). Viewport coordinates are always
17
+ * physical, so we name them with the physical axis labels.
18
+ */
19
+
20
+ /**
21
+ * Styles the synthetic anchor as an invisible, zero-size point.
22
+ * Dynamic `inset-*` overrides are written by the positioning effect.
23
+ *
24
+ * Uses `Object.assign` rather than Compiled CSS (element is outside the React tree)
25
+ * or the internal `setStyle` helper (we own this element entirely — it is created
26
+ * and removed by this hook — so the snapshot/restore semantics `setStyle`
27
+ * provides for caller-owned elements would be dead work here).
28
+ */
29
+ function applyStaticAnchorStyles(el) {
30
+ Object.assign(el.style, {
31
+ position: 'fixed',
32
+ // `top`/`left` rather than `inset-block-start`/`inset-inline-start`
33
+ // for consistency with the dynamic positioning effect below, which
34
+ // uses physical properties (see comment there for the rationale).
35
+ top: '0',
36
+ left: '0',
37
+ // Zero size — placement decides which side the popover sits on.
38
+ width: '0',
39
+ height: '0',
40
+ // Prevent the overlay from intercepting pointer events.
41
+ pointerEvents: 'none'
42
+ });
43
+ }
44
+
45
+ // `useAnchorPosition` requires a real DOM element. When the caller only
46
+ // has a viewport coordinate (e.g. cursor at hover time), this hook
47
+ // manages a hidden `<div>` at that point and delegates the rest.
48
+ //
49
+ // The `<div>` is appended directly to `document.body` to escape any
50
+ // transformed ancestor, which would otherwise break `position: fixed`
51
+ // viewport-relative resolution.
52
+
53
+ /**
54
+ * Positions a popover at a consumer-supplied viewport coordinate using a
55
+ * hidden synthetic anchor.
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * function PointPositionedPopover({ popoverRef, placement, mousePos }) {
60
+ * useAnchorPositionAtPoint({
61
+ * popoverRef,
62
+ * placement,
63
+ * isEnabled: Boolean(mousePos),
64
+ * getPoint: () => {
65
+ * if (!mousePos) return null;
66
+ * return { x: mousePos.clientX, y: mousePos.clientY };
67
+ * },
68
+ * });
69
+ * return <Popover ref={popoverRef}>...</Popover>;
70
+ * }
71
+ * ```
72
+ */
73
+ function useAnchorPositionAtPoint(_ref) {
74
+ var popoverRef = _ref.popoverRef,
75
+ placement = _ref.placement,
76
+ getPoint = _ref.getPoint,
77
+ _ref$isEnabled = _ref.isEnabled,
78
+ isEnabled = _ref$isEnabled === void 0 ? true : _ref$isEnabled;
79
+ var syntheticAnchorRef = (0, _react.useRef)(null);
80
+
81
+ // `getPoint` is kept in a ref so the layout effect can call the
82
+ // latest version without listing it as a dep — that would re-fire
83
+ // on every render and re-latch the point.
84
+ var getPointRef = (0, _react.useRef)(getPoint);
85
+ getPointRef.current = getPoint;
86
+
87
+ // Lazy element creation: the `<div>` is only created when both
88
+ // `isEnabled` is true AND `getPoint()` returns a non-null point.
89
+ // `useLayoutEffect` ensures the element exists before the inner
90
+ // `useAnchorPosition` (also a layout effect) reads the ref.
91
+ (0, _react.useLayoutEffect)(function () {
92
+ if (!isEnabled) {
93
+ return;
94
+ }
95
+ var point = getPointRef.current();
96
+ if (!point) {
97
+ return;
98
+ }
99
+ var anchor = document.createElement('div');
100
+ anchor.setAttribute('aria-hidden', 'true');
101
+ applyStaticAnchorStyles(anchor);
102
+ // `point.x`/`y` are physical viewport coordinates (from
103
+ // `MouseEvent.clientX/Y`), so map directly onto physical
104
+ // `left`/`top`. This is RTL-safe: `position: fixed` + physical
105
+ // insets is direction-independent. Using logical
106
+ // `inset-inline-start` would need `viewportWidth - point.x` in
107
+ // RTL to land at the same physical pixel.
108
+ anchor.style.top = "".concat(point.y, "px");
109
+ anchor.style.left = "".concat(point.x, "px");
110
+ document.body.appendChild(anchor);
111
+ syntheticAnchorRef.current = anchor;
112
+ return function cleanup() {
113
+ anchor.remove();
114
+ syntheticAnchorRef.current = null;
115
+ };
116
+ }, [isEnabled]);
117
+
118
+ // Mirror `isEnabled` so both hooks stay in sync — when disabled,
119
+ // neither this hook nor the inner one touches the popover, leaving
120
+ // any other positioning the consumer has set up free to take effect.
121
+ (0, _useAnchorPosition.useAnchorPosition)({
122
+ anchorRef: syntheticAnchorRef,
123
+ popoverRef: popoverRef,
124
+ placement: placement,
125
+ isEnabled: isEnabled
126
+ });
127
+ }
@@ -200,19 +200,23 @@ function useStablePlacement(placement) {
200
200
  * comparison is used internally so re-runs are skipped when the resolved
201
201
  * placement shape is unchanged.
202
202
  */
203
- // eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
204
203
  function useAnchorPosition(_ref3) {
205
204
  var anchorRef = _ref3.anchorRef,
206
205
  popoverRef = _ref3.popoverRef,
207
206
  _ref3$placement = _ref3.placement,
208
207
  placement = _ref3$placement === void 0 ? {} : _ref3$placement,
209
208
  _ref3$forceFallbackPo = _ref3.forceFallbackPositioning,
210
- forceFallbackPositioning = _ref3$forceFallbackPo === void 0 ? false : _ref3$forceFallbackPo;
209
+ forceFallbackPositioning = _ref3$forceFallbackPo === void 0 ? false : _ref3$forceFallbackPo,
210
+ _ref3$isEnabled = _ref3.isEnabled,
211
+ isEnabled = _ref3$isEnabled === void 0 ? true : _ref3$isEnabled;
211
212
  var id = (0, _react.useId)();
212
213
  // Stabilize `placement` object so the same object literal
213
214
  // value returns an object with the same reference
214
215
  var stablePlacement = useStablePlacement(placement);
215
216
  (0, _react.useLayoutEffect)(function () {
217
+ if (!isEnabled) {
218
+ return;
219
+ }
216
220
  var trigger = anchorRef.current;
217
221
  var popover = popoverRef.current;
218
222
  if (!trigger || !popover) {
@@ -461,5 +465,5 @@ function useAnchorPosition(_ref3) {
461
465
  popover.style.removeProperty('opacity');
462
466
  });
463
467
  return undoPositioning;
464
- }, [anchorRef, popoverRef, stablePlacement, forceFallbackPositioning, id]);
468
+ }, [anchorRef, popoverRef, stablePlacement, forceFallbackPositioning, isEnabled, id]);
465
469
  }
@@ -6,7 +6,10 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useFocusWrap = useFocusWrap;
7
7
  var _react = require("react");
8
8
  var _bindEventListener = require("bind-event-listener");
9
- var _focus = require("../focus/focus");
9
+ var _getFirstFocusable = require("../focus/get-first-focusable");
10
+ var _getLastFocusable = require("../focus/get-last-focusable");
11
+ var _getNextFocusable = require("../focus/get-next-focusable");
12
+ var _isNestedLayerFocused = require("../focus/is-nested-layer-focused");
10
13
  /**
11
14
  * Roles that require focus wrapping per WAI-ARIA APG.
12
15
  *
@@ -62,7 +65,7 @@ function useFocusWrap(_ref) {
62
65
 
63
66
  // If focus is already in a nested layer, then
64
67
  // we continue to let that nested layer own focus
65
- if ((0, _focus.isNestedLayerFocused)({
68
+ if ((0, _isNestedLayerFocused.isNestedLayerFocused)({
66
69
  container: element
67
70
  })) {
68
71
  return;
@@ -75,7 +78,7 @@ function useFocusWrap(_ref) {
75
78
 
76
79
  // Try to move to the next/previous focusable element relative
77
80
  // to the currently focused element within the container.
78
- var next = (0, _focus.getNextFocusable)({
81
+ var next = (0, _getNextFocusable.getNextFocusable)({
79
82
  container: element,
80
83
  direction: direction
81
84
  });
@@ -87,9 +90,9 @@ function useFocusWrap(_ref) {
87
90
  // Nothing is currently focused inside the container (or the
88
91
  // focused element is not in the focusable list). Fall back to
89
92
  // the first or last focusable element depending on direction.
90
- var fallback = direction === 'forwards' ? (0, _focus.getFirstFocusable)({
93
+ var fallback = direction === 'forwards' ? (0, _getFirstFocusable.getFirstFocusable)({
91
94
  container: element
92
- }) : (0, _focus.getLastFocusable)({
95
+ }) : (0, _getLastFocusable.getLastFocusable)({
93
96
  container: element
94
97
  });
95
98
  if (fallback) {
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.useInitialFocus = useInitialFocus;
7
7
  var _react = require("react");
8
- var _focus = require("../focus/focus");
8
+ var _getFirstFocusable = require("../focus/get-first-focusable");
9
9
  /**
10
10
  * Determines the correct element to receive initial focus within a popover,
11
11
  * based on its ARIA role.
@@ -33,7 +33,7 @@ function getInitialFocusTarget(_ref) {
33
33
  return autofocusEl;
34
34
  }
35
35
  // Fall back to first focusable element
36
- return (0, _focus.getFirstFocusable)({
36
+ return (0, _getFirstFocusable.getFirstFocusable)({
37
37
  container: container
38
38
  });
39
39
  }
@@ -44,7 +44,7 @@ function getInitialFocusTarget(_ref) {
44
44
  // of the consumer component (e.g. dropdown-menu), because menu keyboard
45
45
  // behavior varies by context (orientation, nesting, item type, control
46
46
  // pattern). See: notes/outputs/menu-keyboard-decision.md
47
- return (0, _focus.getFirstFocusable)({
47
+ return (0, _getFirstFocusable.getFirstFocusable)({
48
48
  container: container
49
49
  });
50
50
  }
@@ -54,7 +54,7 @@ function getInitialFocusTarget(_ref) {
54
54
  if (selectedOption) {
55
55
  return selectedOption;
56
56
  }
57
- return (0, _focus.getFirstFocusable)({
57
+ return (0, _getFirstFocusable.getFirstFocusable)({
58
58
  container: container
59
59
  });
60
60
  }
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.fromLegacyPlacement = fromLegacyPlacement;
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
- var _legacyPlacements = require("./legacy-placements");
10
+ var _placementMapping = require("./placement-mapping");
11
11
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
12
12
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
13
13
  /**
@@ -54,7 +54,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
54
54
  function fromLegacyPlacement(_ref) {
55
55
  var legacy = _ref.legacy,
56
56
  offset = _ref.offset;
57
- var basePlacement = _legacyPlacements.placementMapping[legacy];
57
+ var basePlacement = _placementMapping.placementMapping[legacy];
58
58
  if (!offset) {
59
59
  return basePlacement;
60
60
  }