@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.
- package/CHANGELOG.md +16 -0
- package/dist/cjs/entry-points/focus.js +6 -4
- package/dist/cjs/entry-points/use-anchor-position-at-point.js +12 -0
- package/dist/cjs/focus/get-first-focusable.js +19 -0
- package/dist/cjs/focus/get-focusables.js +30 -0
- package/dist/cjs/focus/get-last-focusable.js +19 -0
- package/dist/cjs/focus/get-next-focusable.js +43 -0
- package/dist/cjs/focus/is-in-same-layer.js +23 -0
- package/dist/cjs/focus/is-nested-layer-focused.js +32 -0
- package/dist/cjs/focus/selectors.js +19 -0
- package/dist/cjs/focus/types.js +1 -0
- package/dist/cjs/internal/role-to-aria-has-popup.js +37 -0
- package/dist/cjs/internal/role-types.js +1 -97
- package/dist/cjs/internal/should-focus-into-popover.js +19 -0
- package/dist/cjs/internal/use-anchor-position-at-point.js +127 -0
- package/dist/cjs/internal/use-anchor-position.js +7 -3
- package/dist/cjs/internal/use-focus-wrap.js +8 -5
- package/dist/cjs/internal/use-initial-focus.js +4 -4
- package/dist/cjs/placement-map/index.js +2 -2
- package/dist/cjs/placement-map/legacy-placements.js +2 -101
- package/dist/cjs/placement-map/placement-mapping.js +103 -0
- package/dist/cjs/popup/popup-content.js +4 -3
- package/dist/cjs/use-arrow-navigation/use-arrow-navigation.js +7 -5
- package/dist/es2019/entry-points/focus.js +3 -1
- package/dist/es2019/entry-points/use-anchor-position-at-point.js +1 -0
- package/dist/es2019/focus/get-first-focusable.js +14 -0
- package/dist/es2019/focus/get-focusables.js +19 -0
- package/dist/es2019/focus/get-last-focusable.js +14 -0
- package/dist/es2019/focus/get-next-focusable.js +38 -0
- package/dist/es2019/focus/is-in-same-layer.js +18 -0
- package/dist/es2019/focus/is-nested-layer-focused.js +28 -0
- package/dist/es2019/focus/selectors.js +11 -0
- package/dist/es2019/focus/types.js +0 -0
- package/dist/es2019/internal/role-to-aria-has-popup.js +32 -0
- package/dist/es2019/internal/role-types.js +0 -92
- package/dist/es2019/internal/should-focus-into-popover.js +14 -0
- package/dist/es2019/internal/use-anchor-position-at-point.js +122 -0
- package/dist/es2019/internal/use-anchor-position.js +6 -3
- package/dist/es2019/internal/use-focus-wrap.js +4 -1
- package/dist/es2019/internal/use-initial-focus.js +1 -1
- package/dist/es2019/placement-map/index.js +1 -1
- package/dist/es2019/placement-map/legacy-placements.js +1 -100
- package/dist/es2019/placement-map/placement-mapping.js +97 -0
- package/dist/es2019/popup/popup-content.js +2 -1
- package/dist/es2019/use-arrow-navigation/use-arrow-navigation.js +3 -1
- package/dist/esm/entry-points/focus.js +3 -1
- package/dist/esm/entry-points/use-anchor-position-at-point.js +1 -0
- package/dist/esm/focus/get-first-focusable.js +13 -0
- package/dist/esm/focus/get-focusables.js +24 -0
- package/dist/esm/focus/get-last-focusable.js +13 -0
- package/dist/esm/focus/get-next-focusable.js +37 -0
- package/dist/esm/focus/is-in-same-layer.js +17 -0
- package/dist/esm/focus/is-nested-layer-focused.js +27 -0
- package/dist/esm/focus/selectors.js +13 -0
- package/dist/esm/focus/types.js +0 -0
- package/dist/esm/internal/role-to-aria-has-popup.js +31 -0
- package/dist/esm/internal/role-types.js +0 -90
- package/dist/esm/internal/should-focus-into-popover.js +13 -0
- package/dist/esm/internal/use-anchor-position-at-point.js +122 -0
- package/dist/esm/internal/use-anchor-position.js +7 -3
- package/dist/esm/internal/use-focus-wrap.js +4 -1
- package/dist/esm/internal/use-initial-focus.js +1 -1
- package/dist/esm/placement-map/index.js +1 -1
- package/dist/esm/placement-map/legacy-placements.js +1 -100
- package/dist/esm/placement-map/placement-mapping.js +97 -0
- package/dist/esm/popup/popup-content.js +2 -1
- package/dist/esm/use-arrow-navigation/use-arrow-navigation.js +3 -1
- package/dist/types/entry-points/focus.d.ts +4 -2
- package/dist/types/entry-points/use-anchor-position-at-point.d.ts +1 -0
- package/dist/types/focus/get-first-focusable.d.ts +8 -0
- package/dist/types/focus/get-focusables.d.ts +13 -0
- package/dist/types/focus/get-last-focusable.d.ts +8 -0
- package/dist/types/focus/get-next-focusable.d.ts +13 -0
- package/dist/types/focus/is-in-same-layer.d.ts +8 -0
- package/dist/types/focus/is-nested-layer-focused.d.ts +8 -0
- package/dist/types/focus/selectors.d.ts +4 -0
- package/dist/types/focus/types.d.ts +5 -0
- package/dist/types/internal/role-to-aria-has-popup.d.ts +13 -0
- package/dist/types/internal/role-types.d.ts +0 -19
- package/dist/types/internal/should-focus-into-popover.d.ts +8 -0
- package/dist/types/internal/use-anchor-position-at-point.d.ts +62 -0
- package/dist/types/internal/use-anchor-position.d.ts +6 -1
- package/dist/types/placement-map/index.d.ts +1 -1
- package/dist/types/placement-map/legacy-placements.d.ts +0 -12
- package/dist/types/placement-map/placement-mapping.d.ts +13 -0
- package/dist/types/use-arrow-navigation/use-arrow-navigation.d.ts +1 -1
- package/dist/types-ts4.5/entry-points/focus.d.ts +4 -2
- package/dist/types-ts4.5/entry-points/use-anchor-position-at-point.d.ts +1 -0
- package/dist/types-ts4.5/focus/get-first-focusable.d.ts +8 -0
- package/dist/types-ts4.5/focus/get-focusables.d.ts +13 -0
- package/dist/types-ts4.5/focus/get-last-focusable.d.ts +8 -0
- package/dist/types-ts4.5/focus/get-next-focusable.d.ts +13 -0
- package/dist/types-ts4.5/focus/is-in-same-layer.d.ts +8 -0
- package/dist/types-ts4.5/focus/is-nested-layer-focused.d.ts +8 -0
- package/dist/types-ts4.5/focus/selectors.d.ts +4 -0
- package/dist/types-ts4.5/focus/types.d.ts +5 -0
- package/dist/types-ts4.5/internal/role-to-aria-has-popup.d.ts +13 -0
- package/dist/types-ts4.5/internal/role-types.d.ts +0 -19
- package/dist/types-ts4.5/internal/should-focus-into-popover.d.ts +8 -0
- package/dist/types-ts4.5/internal/use-anchor-position-at-point.d.ts +62 -0
- package/dist/types-ts4.5/internal/use-anchor-position.d.ts +6 -1
- package/dist/types-ts4.5/placement-map/index.d.ts +1 -1
- package/dist/types-ts4.5/placement-map/legacy-placements.d.ts +0 -12
- package/dist/types-ts4.5/placement-map/placement-mapping.d.ts +13 -0
- package/dist/types-ts4.5/use-arrow-navigation/use-arrow-navigation.d.ts +1 -1
- package/package.json +1 -1
- package/use-anchor-position-at-point/package.json +17 -0
- package/dist/cjs/focus/focus.js +0 -169
- package/dist/cjs/focus/index.js +0 -24
- package/dist/es2019/focus/focus.js +0 -158
- package/dist/es2019/focus/index.js +0 -1
- package/dist/esm/focus/focus.js +0 -160
- package/dist/esm/focus/index.js +0 -1
- package/dist/types/focus/focus.d.ts +0 -50
- package/dist/types/focus/index.d.ts +0 -2
- package/dist/types-ts4.5/focus/focus.d.ts +0 -50
- package/dist/types-ts4.5/focus/index.d.ts +0 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.LEGACY_PLACEMENTS = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* Legacy Popper.js placement values (used by `@atlaskit/popper`,
|
|
9
9
|
* `@atlaskit/popup`, `@atlaskit/tooltip`, etc.). Re-exported from
|
|
@@ -11,103 +11,4 @@ exports.placementMapping = exports.LEGACY_PLACEMENTS = void 0;
|
|
|
11
11
|
* to enumerate every placement (e.g. for a settings dropdown). New code
|
|
12
12
|
* should use the object-based `TPlacementOptions` directly.
|
|
13
13
|
*/
|
|
14
|
-
|
|
15
|
-
var LEGACY_PLACEMENTS = exports.LEGACY_PLACEMENTS = ['auto', 'auto-start', 'auto-end', 'top', 'top-start', 'top-center', 'top-end', 'bottom', 'bottom-start', 'bottom-center', 'bottom-end', 'right', 'right-start', 'right-end', 'left', 'left-start', 'left-end'];
|
|
16
|
-
/**
|
|
17
|
-
* The full mapping record. Internal - use `fromLegacyPlacement` from the
|
|
18
|
-
* public entry-point so the offset-tuple translation is applied consistently.
|
|
19
|
-
*
|
|
20
|
-
* Note: `auto`, `auto-start`, `auto-end` map to `block-end` placements. This
|
|
21
|
-
* is a reduction in expressiveness vs Popper.js (which picked the best
|
|
22
|
-
* placement at runtime). CSS `position-try-fallbacks` flips at the edge but
|
|
23
|
-
* the initial placement is fixed. Migration consumers who relied on Popper's
|
|
24
|
-
* dynamic auto-flip should pick an explicit placement instead.
|
|
25
|
-
*/
|
|
26
|
-
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
|
|
27
|
-
var placementMapping = exports.placementMapping = {
|
|
28
|
-
top: {
|
|
29
|
-
axis: 'block',
|
|
30
|
-
edge: 'start',
|
|
31
|
-
align: 'center'
|
|
32
|
-
},
|
|
33
|
-
'top-start': {
|
|
34
|
-
axis: 'block',
|
|
35
|
-
edge: 'start',
|
|
36
|
-
align: 'start'
|
|
37
|
-
},
|
|
38
|
-
'top-center': {
|
|
39
|
-
axis: 'block',
|
|
40
|
-
edge: 'start',
|
|
41
|
-
align: 'center'
|
|
42
|
-
},
|
|
43
|
-
'top-end': {
|
|
44
|
-
axis: 'block',
|
|
45
|
-
edge: 'start',
|
|
46
|
-
align: 'end'
|
|
47
|
-
},
|
|
48
|
-
bottom: {
|
|
49
|
-
axis: 'block',
|
|
50
|
-
edge: 'end',
|
|
51
|
-
align: 'center'
|
|
52
|
-
},
|
|
53
|
-
'bottom-start': {
|
|
54
|
-
axis: 'block',
|
|
55
|
-
edge: 'end',
|
|
56
|
-
align: 'start'
|
|
57
|
-
},
|
|
58
|
-
'bottom-center': {
|
|
59
|
-
axis: 'block',
|
|
60
|
-
edge: 'end',
|
|
61
|
-
align: 'center'
|
|
62
|
-
},
|
|
63
|
-
'bottom-end': {
|
|
64
|
-
axis: 'block',
|
|
65
|
-
edge: 'end',
|
|
66
|
-
align: 'end'
|
|
67
|
-
},
|
|
68
|
-
right: {
|
|
69
|
-
axis: 'inline',
|
|
70
|
-
edge: 'end',
|
|
71
|
-
align: 'center'
|
|
72
|
-
},
|
|
73
|
-
'right-start': {
|
|
74
|
-
axis: 'inline',
|
|
75
|
-
edge: 'end',
|
|
76
|
-
align: 'start'
|
|
77
|
-
},
|
|
78
|
-
'right-end': {
|
|
79
|
-
axis: 'inline',
|
|
80
|
-
edge: 'end',
|
|
81
|
-
align: 'end'
|
|
82
|
-
},
|
|
83
|
-
left: {
|
|
84
|
-
axis: 'inline',
|
|
85
|
-
edge: 'start',
|
|
86
|
-
align: 'center'
|
|
87
|
-
},
|
|
88
|
-
'left-start': {
|
|
89
|
-
axis: 'inline',
|
|
90
|
-
edge: 'start',
|
|
91
|
-
align: 'start'
|
|
92
|
-
},
|
|
93
|
-
'left-end': {
|
|
94
|
-
axis: 'inline',
|
|
95
|
-
edge: 'start',
|
|
96
|
-
align: 'end'
|
|
97
|
-
},
|
|
98
|
-
auto: {
|
|
99
|
-
axis: 'block',
|
|
100
|
-
edge: 'end',
|
|
101
|
-
align: 'center'
|
|
102
|
-
},
|
|
103
|
-
'auto-start': {
|
|
104
|
-
axis: 'block',
|
|
105
|
-
edge: 'end',
|
|
106
|
-
align: 'start'
|
|
107
|
-
},
|
|
108
|
-
'auto-end': {
|
|
109
|
-
axis: 'block',
|
|
110
|
-
edge: 'end',
|
|
111
|
-
align: 'end'
|
|
112
|
-
}
|
|
113
|
-
};
|
|
14
|
+
var LEGACY_PLACEMENTS = exports.LEGACY_PLACEMENTS = ['auto', 'auto-start', 'auto-end', 'top', 'top-start', 'top-center', 'top-end', 'bottom', 'bottom-start', 'bottom-center', 'bottom-end', 'right', 'right-start', 'right-end', 'left', 'left-start', 'left-end'];
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.placementMapping = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* The full mapping record. Internal - use `fromLegacyPlacement` from the
|
|
9
|
+
* public entry-point so the offset-tuple translation is applied consistently.
|
|
10
|
+
*
|
|
11
|
+
* Note: `auto`, `auto-start`, `auto-end` map to `block-end` placements. This
|
|
12
|
+
* is a reduction in expressiveness vs Popper.js (which picked the best
|
|
13
|
+
* placement at runtime). CSS `position-try-fallbacks` flips at the edge but
|
|
14
|
+
* the initial placement is fixed. Migration consumers who relied on Popper's
|
|
15
|
+
* dynamic auto-flip should pick an explicit placement instead.
|
|
16
|
+
*/
|
|
17
|
+
var placementMapping = exports.placementMapping = {
|
|
18
|
+
top: {
|
|
19
|
+
axis: 'block',
|
|
20
|
+
edge: 'start',
|
|
21
|
+
align: 'center'
|
|
22
|
+
},
|
|
23
|
+
'top-start': {
|
|
24
|
+
axis: 'block',
|
|
25
|
+
edge: 'start',
|
|
26
|
+
align: 'start'
|
|
27
|
+
},
|
|
28
|
+
'top-center': {
|
|
29
|
+
axis: 'block',
|
|
30
|
+
edge: 'start',
|
|
31
|
+
align: 'center'
|
|
32
|
+
},
|
|
33
|
+
'top-end': {
|
|
34
|
+
axis: 'block',
|
|
35
|
+
edge: 'start',
|
|
36
|
+
align: 'end'
|
|
37
|
+
},
|
|
38
|
+
bottom: {
|
|
39
|
+
axis: 'block',
|
|
40
|
+
edge: 'end',
|
|
41
|
+
align: 'center'
|
|
42
|
+
},
|
|
43
|
+
'bottom-start': {
|
|
44
|
+
axis: 'block',
|
|
45
|
+
edge: 'end',
|
|
46
|
+
align: 'start'
|
|
47
|
+
},
|
|
48
|
+
'bottom-center': {
|
|
49
|
+
axis: 'block',
|
|
50
|
+
edge: 'end',
|
|
51
|
+
align: 'center'
|
|
52
|
+
},
|
|
53
|
+
'bottom-end': {
|
|
54
|
+
axis: 'block',
|
|
55
|
+
edge: 'end',
|
|
56
|
+
align: 'end'
|
|
57
|
+
},
|
|
58
|
+
right: {
|
|
59
|
+
axis: 'inline',
|
|
60
|
+
edge: 'end',
|
|
61
|
+
align: 'center'
|
|
62
|
+
},
|
|
63
|
+
'right-start': {
|
|
64
|
+
axis: 'inline',
|
|
65
|
+
edge: 'end',
|
|
66
|
+
align: 'start'
|
|
67
|
+
},
|
|
68
|
+
'right-end': {
|
|
69
|
+
axis: 'inline',
|
|
70
|
+
edge: 'end',
|
|
71
|
+
align: 'end'
|
|
72
|
+
},
|
|
73
|
+
left: {
|
|
74
|
+
axis: 'inline',
|
|
75
|
+
edge: 'start',
|
|
76
|
+
align: 'center'
|
|
77
|
+
},
|
|
78
|
+
'left-start': {
|
|
79
|
+
axis: 'inline',
|
|
80
|
+
edge: 'start',
|
|
81
|
+
align: 'start'
|
|
82
|
+
},
|
|
83
|
+
'left-end': {
|
|
84
|
+
axis: 'inline',
|
|
85
|
+
edge: 'start',
|
|
86
|
+
align: 'end'
|
|
87
|
+
},
|
|
88
|
+
auto: {
|
|
89
|
+
axis: 'block',
|
|
90
|
+
edge: 'end',
|
|
91
|
+
align: 'center'
|
|
92
|
+
},
|
|
93
|
+
'auto-start': {
|
|
94
|
+
axis: 'block',
|
|
95
|
+
edge: 'end',
|
|
96
|
+
align: 'start'
|
|
97
|
+
},
|
|
98
|
+
'auto-end': {
|
|
99
|
+
axis: 'block',
|
|
100
|
+
edge: 'end',
|
|
101
|
+
align: 'end'
|
|
102
|
+
}
|
|
103
|
+
};
|
|
@@ -12,7 +12,8 @@ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")
|
|
|
12
12
|
var _react = _interopRequireWildcard(require("react"));
|
|
13
13
|
var _mergeRefs = _interopRequireDefault(require("@atlaskit/ds-lib/merge-refs"));
|
|
14
14
|
var _reducedMotion = require("../internal/reduced-motion");
|
|
15
|
-
var
|
|
15
|
+
var _roleToAriaHasPopup = require("../internal/role-to-aria-has-popup");
|
|
16
|
+
var _shouldFocusIntoPopover = require("../internal/should-focus-into-popover");
|
|
16
17
|
var _useAnchorPosition = require("../internal/use-anchor-position");
|
|
17
18
|
var _useWidthFromAnchor = require("../internal/use-width-from-anchor");
|
|
18
19
|
var _popover = require("../popover/popover");
|
|
@@ -100,7 +101,7 @@ var PopupContent = exports.PopupContent = /*#__PURE__*/(0, _react.forwardRef)(fu
|
|
|
100
101
|
// Sync aria-haspopup on the trigger with the content's role
|
|
101
102
|
var setAriaHasPopup = ctx === null || ctx === void 0 ? void 0 : ctx.setAriaHasPopup;
|
|
102
103
|
(0, _react.useLayoutEffect)(function () {
|
|
103
|
-
setAriaHasPopup === null || setAriaHasPopup === void 0 || setAriaHasPopup((0,
|
|
104
|
+
setAriaHasPopup === null || setAriaHasPopup === void 0 || setAriaHasPopup((0, _roleToAriaHasPopup.roleToAriaHasPopup)({
|
|
104
105
|
role: role
|
|
105
106
|
}));
|
|
106
107
|
}, [role, setAriaHasPopup]);
|
|
@@ -151,7 +152,7 @@ var PopupContent = exports.PopupContent = /*#__PURE__*/(0, _react.forwardRef)(fu
|
|
|
151
152
|
// Single source of truth for "this role moves focus on open
|
|
152
153
|
// and therefore needs to be restored on close" - see
|
|
153
154
|
// `shouldFocusIntoPopover` in `internal/role-types.tsx`.
|
|
154
|
-
if (focusStillInPopover && (0,
|
|
155
|
+
if (focusStillInPopover && (0, _shouldFocusIntoPopover.shouldFocusIntoPopover)({
|
|
155
156
|
role: role
|
|
156
157
|
})) {
|
|
157
158
|
trigger.focus({
|
|
@@ -8,7 +8,9 @@ var _react = require("react");
|
|
|
8
8
|
var _bindEventListener = require("bind-event-listener");
|
|
9
9
|
var _browserApis = require("@atlaskit/browser-apis");
|
|
10
10
|
var _keycodes = require("@atlaskit/ds-lib/keycodes");
|
|
11
|
-
var
|
|
11
|
+
var _getFirstFocusable2 = require("../focus/get-first-focusable");
|
|
12
|
+
var _getLastFocusable2 = require("../focus/get-last-focusable");
|
|
13
|
+
var _getNextFocusable3 = require("../focus/get-next-focusable");
|
|
12
14
|
var menuScope = '[role="menu"]';
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -96,7 +98,7 @@ function useArrowNavigation(_ref) {
|
|
|
96
98
|
var _getNextFocusable;
|
|
97
99
|
// Prevent page scroll while navigating menu items.
|
|
98
100
|
event.preventDefault();
|
|
99
|
-
(_getNextFocusable = (0,
|
|
101
|
+
(_getNextFocusable = (0, _getNextFocusable3.getNextFocusable)({
|
|
100
102
|
container: container,
|
|
101
103
|
direction: 'forwards',
|
|
102
104
|
filter: filter
|
|
@@ -107,7 +109,7 @@ function useArrowNavigation(_ref) {
|
|
|
107
109
|
var _getNextFocusable2;
|
|
108
110
|
// Prevent page scroll while navigating menu items.
|
|
109
111
|
event.preventDefault();
|
|
110
|
-
(_getNextFocusable2 = (0,
|
|
112
|
+
(_getNextFocusable2 = (0, _getNextFocusable3.getNextFocusable)({
|
|
111
113
|
container: container,
|
|
112
114
|
direction: 'backwards',
|
|
113
115
|
filter: filter
|
|
@@ -118,7 +120,7 @@ function useArrowNavigation(_ref) {
|
|
|
118
120
|
var _getFirstFocusable;
|
|
119
121
|
// Prevent browser default (e.g. scrolling to top of page).
|
|
120
122
|
event.preventDefault();
|
|
121
|
-
(_getFirstFocusable = (0,
|
|
123
|
+
(_getFirstFocusable = (0, _getFirstFocusable2.getFirstFocusable)({
|
|
122
124
|
container: container,
|
|
123
125
|
filter: filter
|
|
124
126
|
})) === null || _getFirstFocusable === void 0 || _getFirstFocusable.focus();
|
|
@@ -128,7 +130,7 @@ function useArrowNavigation(_ref) {
|
|
|
128
130
|
var _getLastFocusable;
|
|
129
131
|
// Prevent browser default (e.g. scrolling to bottom of page).
|
|
130
132
|
event.preventDefault();
|
|
131
|
-
(_getLastFocusable = (0,
|
|
133
|
+
(_getLastFocusable = (0, _getLastFocusable2.getLastFocusable)({
|
|
132
134
|
container: container,
|
|
133
135
|
filter: filter
|
|
134
136
|
})) === null || _getLastFocusable === void 0 || _getLastFocusable.focus();
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
export { getFirstFocusable
|
|
1
|
+
export { getFirstFocusable } from '../focus/get-first-focusable';
|
|
2
|
+
export { getLastFocusable } from '../focus/get-last-focusable';
|
|
3
|
+
export { getNextFocusable } from '../focus/get-next-focusable';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useAnchorPositionAtPoint } from '../internal/use-anchor-position-at-point';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getFocusables } from './get-focusables';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the first focusable element within the container.
|
|
4
|
+
*/
|
|
5
|
+
export function getFirstFocusable({
|
|
6
|
+
container,
|
|
7
|
+
filter
|
|
8
|
+
}) {
|
|
9
|
+
const items = getFocusables({
|
|
10
|
+
container,
|
|
11
|
+
filter
|
|
12
|
+
});
|
|
13
|
+
return items.length > 0 ? items[0] : null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isInSameLayer } from './is-in-same-layer';
|
|
2
|
+
import { selectors } from './selectors';
|
|
3
|
+
/**
|
|
4
|
+
* Returns all focusable HTMLElements within the container, optionally filtered.
|
|
5
|
+
*
|
|
6
|
+
* Focusables that belong to a nested top-layer scope (a `[popover]` or
|
|
7
|
+
* `<dialog>` descendant of the container) are excluded - those elements
|
|
8
|
+
* are owned by the inner layer's focus management. The container itself
|
|
9
|
+
* is allowed to be a popover/dialog; only nested ones are filtered.
|
|
10
|
+
*/
|
|
11
|
+
export function getFocusables({
|
|
12
|
+
container,
|
|
13
|
+
filter
|
|
14
|
+
}) {
|
|
15
|
+
return Array.from(container.querySelectorAll(selectors.focusable)).filter(element => element instanceof HTMLElement).filter(element => isInSameLayer({
|
|
16
|
+
element,
|
|
17
|
+
container
|
|
18
|
+
})).filter(element => !filter || filter(element, container));
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getFocusables } from './get-focusables';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the last focusable element within the container.
|
|
4
|
+
*/
|
|
5
|
+
export function getLastFocusable({
|
|
6
|
+
container,
|
|
7
|
+
filter
|
|
8
|
+
}) {
|
|
9
|
+
const items = getFocusables({
|
|
10
|
+
container,
|
|
11
|
+
filter
|
|
12
|
+
});
|
|
13
|
+
return items.length > 0 ? items[items.length - 1] : null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the next focusable element in the given direction relative to the
|
|
3
|
+
* currently focused element within the container. Wraps around at both ends.
|
|
4
|
+
*
|
|
5
|
+
* Returns `null` if there is no focused element within the container or if
|
|
6
|
+
* the focused element is not in the list of focusable elements.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { getFocusables } from './get-focusables';
|
|
10
|
+
import { selectors } from './selectors';
|
|
11
|
+
export function getNextFocusable({
|
|
12
|
+
container,
|
|
13
|
+
direction,
|
|
14
|
+
filter
|
|
15
|
+
}) {
|
|
16
|
+
var _all$nextIndex;
|
|
17
|
+
const all = getFocusables({
|
|
18
|
+
container,
|
|
19
|
+
filter
|
|
20
|
+
});
|
|
21
|
+
const current = container.querySelector(selectors.focused);
|
|
22
|
+
if (!(current instanceof HTMLElement)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const index = all.indexOf(current);
|
|
26
|
+
if (index === -1) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const nextIndex = (() => {
|
|
30
|
+
if (direction === 'forwards') {
|
|
31
|
+
return (index + 1) % all.length;
|
|
32
|
+
}
|
|
33
|
+
const proposed = index - 1;
|
|
34
|
+
// if going into negative numbers, loop back to the last item
|
|
35
|
+
return proposed < 0 ? all.length - 1 : proposed;
|
|
36
|
+
})();
|
|
37
|
+
return (_all$nextIndex = all[nextIndex]) !== null && _all$nextIndex !== void 0 ? _all$nextIndex : null;
|
|
38
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const topLayerSelector = '[popover], dialog, [role="dialog"], [role="alertdialog"]';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns true when `element` and `container` resolve to the same nearest
|
|
5
|
+
* top-layer host (or both resolve to `null`, meaning the document layer).
|
|
6
|
+
*/
|
|
7
|
+
export function isInSameLayer({
|
|
8
|
+
element,
|
|
9
|
+
container
|
|
10
|
+
}) {
|
|
11
|
+
const elementLayer = element.closest(topLayerSelector);
|
|
12
|
+
const containerLayer = container.closest(topLayerSelector);
|
|
13
|
+
// Both elements are in the "document" layer
|
|
14
|
+
if (!elementLayer && !containerLayer) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return elementLayer === containerLayer;
|
|
18
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { getDocument } from '@atlaskit/browser-apis';
|
|
2
|
+
import { isInSameLayer } from './is-in-same-layer';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns `true` when `document.activeElement` is inside a nested top-layer
|
|
6
|
+
* descendant of `container` (a `[popover]`, `<dialog>`, `[role="dialog"]` or
|
|
7
|
+
* `[role="alertdialog"]` that is itself a descendant of `container`).
|
|
8
|
+
*/
|
|
9
|
+
export function isNestedLayerFocused({
|
|
10
|
+
container
|
|
11
|
+
}) {
|
|
12
|
+
var _getDocument;
|
|
13
|
+
const focused = (_getDocument = getDocument()) === null || _getDocument === void 0 ? void 0 : _getDocument.activeElement;
|
|
14
|
+
if (!(focused instanceof HTMLElement)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Cannot be in a nested layer if it is not in the container
|
|
19
|
+
if (!container.contains(focused)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// If not in the same layer, must be in a nested layer
|
|
24
|
+
return !isInSameLayer({
|
|
25
|
+
element: focused,
|
|
26
|
+
container
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const selectors = (() => {
|
|
2
|
+
// Common exclusion filter applied to every selector.
|
|
3
|
+
const not = ':not([tabindex="-1"]):not([aria-disabled="true"]):not([aria-hidden="true"])';
|
|
4
|
+
const notDisabled = `:not([disabled])${not}`;
|
|
5
|
+
const focusable = [`a[href]${not}`, `area[href]${not}`, `input${notDisabled}:not([type="hidden"])`, `select${notDisabled}`, `textarea${notDisabled}`, `button${notDisabled}`, `iframe${not}`, `audio[controls]${not}`, `video[controls]${not}`, `[contenteditable]:not([contenteditable="false"])${not}`, `[tabindex]${notDisabled}${not}`];
|
|
6
|
+
return {
|
|
7
|
+
focusable: focusable.join(','),
|
|
8
|
+
// Build the `:focus` selector
|
|
9
|
+
focused: focusable.map(selector => `${selector}:focus`).join(',')
|
|
10
|
+
};
|
|
11
|
+
})();
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps a popover content role to the correct `aria-haspopup` value
|
|
3
|
+
* for its trigger element.
|
|
4
|
+
*
|
|
5
|
+
* Returns `undefined` for roles that are not popups in the ARIA sense
|
|
6
|
+
* (`tooltip`, `note`, `status`, `alert`, `log`). Triggers for those roles
|
|
7
|
+
* should not announce a popup at all - emitting `aria-haspopup="dialog"`
|
|
8
|
+
* on a tooltip trigger would mislead assistive technology.
|
|
9
|
+
*/
|
|
10
|
+
export function roleToAriaHasPopup({
|
|
11
|
+
role
|
|
12
|
+
}) {
|
|
13
|
+
if (role === 'menu') {
|
|
14
|
+
return 'menu';
|
|
15
|
+
}
|
|
16
|
+
if (role === 'listbox') {
|
|
17
|
+
return 'listbox';
|
|
18
|
+
}
|
|
19
|
+
if (role === 'tree') {
|
|
20
|
+
return 'tree';
|
|
21
|
+
}
|
|
22
|
+
if (role === 'grid') {
|
|
23
|
+
return 'grid';
|
|
24
|
+
}
|
|
25
|
+
if (role === 'dialog' || role === 'alertdialog') {
|
|
26
|
+
return 'dialog';
|
|
27
|
+
}
|
|
28
|
+
// Non-popup roles (tooltip, note, status, alert, log) and the
|
|
29
|
+
// no-role case: omit `aria-haspopup` entirely. React drops the
|
|
30
|
+
// attribute when the value is `undefined`.
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Valid values for the `aria-haspopup` attribute.
|
|
3
|
-
*
|
|
4
|
-
* Derived from the HTML spec - maps popover roles to what the trigger
|
|
5
|
-
* announces. `undefined` means the attribute is omitted entirely (used for
|
|
6
|
-
* non-popup roles like `tooltip`/`status`/`alert`/`note`/`log` where
|
|
7
|
-
* `aria-haspopup` would be misleading).
|
|
8
|
-
*
|
|
9
|
-
* `true` is intentionally NOT in the union - the runtime only ever produces
|
|
10
|
-
* the explicit string forms, so widening the type would invite consumers to
|
|
11
|
-
* pass `true` and get an `aria-haspopup="true"` serialisation that the
|
|
12
|
-
* runtime no longer emits.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Roles that require an accessible name (`label` or `labelledBy`) per WCAG 4.1.2.
|
|
17
|
-
* Without a name, assistive technology cannot identify these landmarks.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Roles where the accessible name is derived from content or provided externally
|
|
22
|
-
* (e.g. a combobox labels its listbox, tooltip content IS the accessible name).
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
// Shared ARIA role discrimination types
|
|
26
|
-
//
|
|
27
|
-
// These encode the WCAG 4.1.2 constraint: roles like `dialog`, `alertdialog`,
|
|
28
|
-
// and `menu` MUST have an accessible name (either `label` or `labelledBy`).
|
|
29
|
-
// TypeScript enforces this at compile time via discriminated unions.
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* ARIA role props where a role is always required.
|
|
33
|
-
*
|
|
34
|
-
* Used by `TPopupContentProps`. Popup content must always declare
|
|
35
|
-
* its role so assistive technology can identify the layer.
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* ARIA role props where a role is optional.
|
|
40
|
-
*
|
|
41
|
-
* Used by `TPopoverProps`. The low-level primitive allows omitting
|
|
42
|
-
* the role for cases where it is set externally or not needed.
|
|
43
|
-
*/
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Maps a popover content role to the correct `aria-haspopup` value
|
|
47
|
-
* for its trigger element.
|
|
48
|
-
*
|
|
49
|
-
* Returns `undefined` for roles that are not popups in the ARIA sense
|
|
50
|
-
* (`tooltip`, `note`, `status`, `alert`, `log`). Triggers for those roles
|
|
51
|
-
* should not announce a popup at all - emitting `aria-haspopup="dialog"`
|
|
52
|
-
* on a tooltip trigger would mislead assistive technology.
|
|
53
|
-
*/
|
|
54
|
-
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
|
|
55
|
-
export function roleToAriaHasPopup({
|
|
56
|
-
role
|
|
57
|
-
}) {
|
|
58
|
-
if (role === 'menu') {
|
|
59
|
-
return 'menu';
|
|
60
|
-
}
|
|
61
|
-
if (role === 'listbox') {
|
|
62
|
-
return 'listbox';
|
|
63
|
-
}
|
|
64
|
-
if (role === 'tree') {
|
|
65
|
-
return 'tree';
|
|
66
|
-
}
|
|
67
|
-
if (role === 'grid') {
|
|
68
|
-
return 'grid';
|
|
69
|
-
}
|
|
70
|
-
if (role === 'dialog' || role === 'alertdialog') {
|
|
71
|
-
return 'dialog';
|
|
72
|
-
}
|
|
73
|
-
// Non-popup roles (tooltip, note, status, alert, log) and the
|
|
74
|
-
// no-role case: omit `aria-haspopup` entirely. React drops the
|
|
75
|
-
// attribute when the value is `undefined`.
|
|
76
|
-
return undefined;
|
|
77
|
-
}
|
|
78
|
-
const rolesThatMoveFocus = new Set(['dialog', 'alertdialog', 'menu', 'listbox', 'tree', 'grid']);
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Returns `true` when the given popover role moves focus into the popover
|
|
82
|
-
* on open, and `false` otherwise (including when `role` is `undefined`).
|
|
83
|
-
*/
|
|
84
|
-
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
|
|
85
|
-
export function shouldFocusIntoPopover({
|
|
86
|
-
role
|
|
87
|
-
}) {
|
|
88
|
-
if (!role) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
return rolesThatMoveFocus.has(role);
|
|
92
|
-
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const rolesThatMoveFocus = new Set(['dialog', 'alertdialog', 'menu', 'listbox', 'tree', 'grid']);
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns `true` when the given popover role moves focus into the popover
|
|
5
|
+
* on open, and `false` otherwise (including when `role` is `undefined`).
|
|
6
|
+
*/
|
|
7
|
+
export function shouldFocusIntoPopover({
|
|
8
|
+
role
|
|
9
|
+
}) {
|
|
10
|
+
if (!role) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return rolesThatMoveFocus.has(role);
|
|
14
|
+
}
|