@atlaskit/avatar-group 9.3.3 → 9.3.4
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 +6 -0
- package/dist/cjs/components/avatar-group-item.js +18 -10
- package/dist/cjs/components/avatar-group.js +3 -2
- package/dist/cjs/components/internal/components/focus-manager.js +64 -0
- package/dist/cjs/components/internal/hooks/use-register-item-with-focus-manager.js +23 -0
- package/dist/cjs/components/internal/utiles/handle-focus.js +82 -0
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/components/avatar-group-item.js +14 -8
- package/dist/es2019/components/avatar-group.js +3 -2
- package/dist/es2019/components/internal/components/focus-manager.js +54 -0
- package/dist/es2019/components/internal/hooks/use-register-item-with-focus-manager.js +18 -0
- package/dist/es2019/components/internal/utiles/handle-focus.js +78 -0
- package/dist/es2019/version.json +1 -1
- package/dist/esm/components/avatar-group-item.js +15 -10
- package/dist/esm/components/avatar-group.js +3 -2
- package/dist/esm/components/internal/components/focus-manager.js +53 -0
- package/dist/esm/components/internal/hooks/use-register-item-with-focus-manager.js +17 -0
- package/dist/esm/components/internal/utiles/handle-focus.js +75 -0
- package/dist/esm/version.json +1 -1
- package/dist/types/components/avatar-group-item.d.ts +2 -2
- package/dist/types/components/internal/components/focus-manager.d.ts +21 -0
- package/dist/types/components/internal/hooks/use-register-item-with-focus-manager.d.ts +4 -0
- package/dist/types/components/internal/utiles/handle-focus.d.ts +2 -0
- package/dist/types/components/types.d.ts +2 -0
- package/dist/types-ts4.5/components/avatar-group-item.d.ts +2 -2
- package/dist/types-ts4.5/components/internal/components/focus-manager.d.ts +21 -0
- package/dist/types-ts4.5/components/internal/hooks/use-register-item-with-focus-manager.d.ts +4 -0
- package/dist/types-ts4.5/components/internal/utiles/handle-focus.d.ts +2 -0
- package/dist/types-ts4.5/components/types.d.ts +2 -0
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @atlaskit/avatar-group
|
|
2
2
|
|
|
3
|
+
## 9.3.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`cb7033c5b72`](https://bitbucket.org/atlassian/atlassian-frontend/commits/cb7033c5b72) - keyboard arrow (UP and DOWN) support in avatar-group popup component
|
|
8
|
+
|
|
3
9
|
## 9.3.3
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
4
5
|
Object.defineProperty(exports, "__esModule", {
|
|
5
6
|
value: true
|
|
6
7
|
});
|
|
7
8
|
exports.default = void 0;
|
|
8
9
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
9
10
|
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
10
|
-
var _react =
|
|
11
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
11
12
|
var _avatar = _interopRequireDefault(require("@atlaskit/avatar"));
|
|
13
|
+
var _mergeRefs = _interopRequireDefault(require("@atlaskit/ds-lib/merge-refs"));
|
|
12
14
|
var _menu = require("@atlaskit/menu");
|
|
15
|
+
var _useRegisterItemWithFocusManager = _interopRequireDefault(require("./internal/hooks/use-register-item-with-focus-manager"));
|
|
13
16
|
var _excluded = ["href", "onClick"],
|
|
14
17
|
_excluded2 = ["children"];
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
19
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
20
|
+
var AvatarGroupItem = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
|
|
21
|
+
var avatar = props.avatar,
|
|
22
|
+
onAvatarClick = props.onAvatarClick,
|
|
23
|
+
testId = props.testId,
|
|
24
|
+
index = props.index;
|
|
20
25
|
var href = avatar.href,
|
|
21
26
|
onClick = avatar.onClick,
|
|
22
27
|
rest = (0, _objectWithoutProperties2.default)(avatar, _excluded);
|
|
23
|
-
var
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
var itemRef = (0, _useRegisterItemWithFocusManager.default)();
|
|
29
|
+
var CustomComponent = function CustomComponent(_ref) {
|
|
30
|
+
var children = _ref.children,
|
|
31
|
+
props = (0, _objectWithoutProperties2.default)(_ref, _excluded2);
|
|
26
32
|
// eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
|
|
27
33
|
return /*#__PURE__*/_react.default.createElement("span", props, children);
|
|
28
34
|
};
|
|
@@ -37,6 +43,7 @@ var AvatarGroupItem = function AvatarGroupItem(_ref) {
|
|
|
37
43
|
var callback = onClick || onAvatarClick;
|
|
38
44
|
if (href) {
|
|
39
45
|
return /*#__PURE__*/_react.default.createElement(_menu.LinkItem, {
|
|
46
|
+
ref: (0, _mergeRefs.default)([ref, itemRef]),
|
|
40
47
|
href: href,
|
|
41
48
|
target: avatar.target,
|
|
42
49
|
rel: avatar.target === '_blank' ? 'noopener noreferrer' : undefined,
|
|
@@ -49,6 +56,7 @@ var AvatarGroupItem = function AvatarGroupItem(_ref) {
|
|
|
49
56
|
}
|
|
50
57
|
if (typeof callback === 'function') {
|
|
51
58
|
return /*#__PURE__*/_react.default.createElement(_menu.ButtonItem, {
|
|
59
|
+
ref: (0, _mergeRefs.default)([ref, itemRef]),
|
|
52
60
|
onClick: function onClick(event) {
|
|
53
61
|
return callback && callback(event, undefined, index);
|
|
54
62
|
},
|
|
@@ -61,7 +69,7 @@ var AvatarGroupItem = function AvatarGroupItem(_ref) {
|
|
|
61
69
|
component: CustomComponent,
|
|
62
70
|
testId: testId
|
|
63
71
|
}, avatar.name);
|
|
64
|
-
};
|
|
72
|
+
});
|
|
65
73
|
|
|
66
74
|
// eslint-disable-next-line @repo/internal/react/require-jsdoc
|
|
67
75
|
var _default = AvatarGroupItem;
|
|
@@ -17,6 +17,7 @@ var _constants = require("@atlaskit/theme/constants");
|
|
|
17
17
|
var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
|
|
18
18
|
var _avatarGroupItem = _interopRequireDefault(require("./avatar-group-item"));
|
|
19
19
|
var _grid = _interopRequireDefault(require("./grid"));
|
|
20
|
+
var _focusManager = _interopRequireDefault(require("./internal/components/focus-manager"));
|
|
20
21
|
var _moreIndicator = _interopRequireDefault(require("./more-indicator"));
|
|
21
22
|
var _stack = _interopRequireDefault(require("./stack"));
|
|
22
23
|
var _utils = require("./utils");
|
|
@@ -122,7 +123,7 @@ var AvatarGroup = function AvatarGroup(_ref) {
|
|
|
122
123
|
shouldFlip: true,
|
|
123
124
|
zIndex: _constants.layers.modal(),
|
|
124
125
|
content: function content() {
|
|
125
|
-
return (0, _react2.jsx)(_menu.PopupMenuGroup, {
|
|
126
|
+
return (0, _react2.jsx)(_focusManager.default, null, (0, _react2.jsx)(_menu.PopupMenuGroup, {
|
|
126
127
|
onClick: function onClick(e) {
|
|
127
128
|
return e.stopPropagation();
|
|
128
129
|
},
|
|
@@ -138,7 +139,7 @@ var AvatarGroup = function AvatarGroup(_ref) {
|
|
|
138
139
|
// This index holds the true index,
|
|
139
140
|
// adding up the index of non-overflowed avatars and overflowed avatars.
|
|
140
141
|
index + max);
|
|
141
|
-
})));
|
|
142
|
+
}))));
|
|
142
143
|
},
|
|
143
144
|
trigger: function trigger(triggerProps) {
|
|
144
145
|
return renderMoreButton(_objectSpread(_objectSpread({}, triggerProps), {}, {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = exports.FocusManagerContext = void 0;
|
|
9
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
10
|
+
var _bindEventListener = require("bind-event-listener");
|
|
11
|
+
var _noop = _interopRequireDefault(require("@atlaskit/ds-lib/noop"));
|
|
12
|
+
var _handleFocus = _interopRequireDefault(require("../utiles/handle-focus"));
|
|
13
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
14
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
*
|
|
18
|
+
* Context provider which maintains the list of focusable elements and a method to
|
|
19
|
+
* register new menu items.
|
|
20
|
+
* This list drives the keyboard navgation of the menu.
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
var FocusManagerContext = /*#__PURE__*/(0, _react.createContext)({
|
|
24
|
+
menuItemRefs: [],
|
|
25
|
+
registerRef: _noop.default
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Focus manager logic
|
|
30
|
+
*/
|
|
31
|
+
exports.FocusManagerContext = FocusManagerContext;
|
|
32
|
+
var FocusManager = function FocusManager(_ref) {
|
|
33
|
+
var children = _ref.children;
|
|
34
|
+
var menuItemRefs = (0, _react.useRef)([]);
|
|
35
|
+
var registerRef = (0, _react.useCallback)(function (ref) {
|
|
36
|
+
if (ref && !menuItemRefs.current.includes(ref)) {
|
|
37
|
+
menuItemRefs.current.push(ref);
|
|
38
|
+
}
|
|
39
|
+
}, []);
|
|
40
|
+
|
|
41
|
+
// set focus and intentionally rebinding listener and clean up listener on each render
|
|
42
|
+
(0, _react.useEffect)(function () {
|
|
43
|
+
(0, _bindEventListener.bind)(window, {
|
|
44
|
+
type: 'keydown',
|
|
45
|
+
listener: (0, _handleFocus.default)(menuItemRefs.current)
|
|
46
|
+
});
|
|
47
|
+
var unbind = function unbind() {
|
|
48
|
+
(0, _bindEventListener.bind)(window, {
|
|
49
|
+
type: 'keydown',
|
|
50
|
+
listener: (0, _handleFocus.default)(menuItemRefs.current)
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
return unbind;
|
|
54
|
+
}, []);
|
|
55
|
+
var contextValue = {
|
|
56
|
+
menuItemRefs: menuItemRefs.current,
|
|
57
|
+
registerRef: registerRef
|
|
58
|
+
};
|
|
59
|
+
return /*#__PURE__*/_react.default.createElement(FocusManagerContext.Provider, {
|
|
60
|
+
value: contextValue
|
|
61
|
+
}, children);
|
|
62
|
+
};
|
|
63
|
+
var _default = FocusManager;
|
|
64
|
+
exports.default = _default;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _focusManager = require("../components/focus-manager");
|
|
9
|
+
// The refs stored in the context are used to programatically
|
|
10
|
+
// control focus on a user navigates using the keyboard.
|
|
11
|
+
function useRegisterItemWithFocusManager() {
|
|
12
|
+
var _useContext = (0, _react.useContext)(_focusManager.FocusManagerContext),
|
|
13
|
+
registerRef = _useContext.registerRef;
|
|
14
|
+
var itemRef = (0, _react.useRef)(null);
|
|
15
|
+
(0, _react.useEffect)(function () {
|
|
16
|
+
if (itemRef.current !== null) {
|
|
17
|
+
registerRef(itemRef.current);
|
|
18
|
+
}
|
|
19
|
+
}, [registerRef]);
|
|
20
|
+
return itemRef;
|
|
21
|
+
}
|
|
22
|
+
var _default = useRegisterItemWithFocusManager;
|
|
23
|
+
exports.default = _default;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = handleFocus;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _keycodes = require("@atlaskit/ds-lib/keycodes");
|
|
10
|
+
var _actionMap;
|
|
11
|
+
var actionMap = (_actionMap = {}, (0, _defineProperty2.default)(_actionMap, _keycodes.KEY_DOWN, 'next'), (0, _defineProperty2.default)(_actionMap, _keycodes.KEY_UP, 'prev'), (0, _defineProperty2.default)(_actionMap, _keycodes.KEY_HOME, 'first'), (0, _defineProperty2.default)(_actionMap, _keycodes.KEY_END, 'last'), _actionMap);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* currentFocusedIdx + 1 will not work if the next focusable element
|
|
15
|
+
* is disabled. So, we need to iterate through the following menu items
|
|
16
|
+
* to find one that isn't disabled. If all following elements are disabled,
|
|
17
|
+
* return undefined.
|
|
18
|
+
*/
|
|
19
|
+
var getNextFocusableElement = function getNextFocusableElement(refs, currentFocusedIdx) {
|
|
20
|
+
while (currentFocusedIdx + 1 < refs.length) {
|
|
21
|
+
var isDisabled = refs[currentFocusedIdx + 1].getAttribute('disabled') !== null;
|
|
22
|
+
if (!isDisabled) {
|
|
23
|
+
return refs[currentFocusedIdx + 1];
|
|
24
|
+
}
|
|
25
|
+
currentFocusedIdx++;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* currentFocusedIdx - 1 will not work if the prev focusable element
|
|
31
|
+
* is disabled. So, we need to iterate through the previous menu items
|
|
32
|
+
* to find one that isn't disabled. If all previous elements are disabled,
|
|
33
|
+
* return undefined.
|
|
34
|
+
*/
|
|
35
|
+
var getPrevFocusableElement = function getPrevFocusableElement(refs, currentFocusedIdx) {
|
|
36
|
+
while (currentFocusedIdx > 0) {
|
|
37
|
+
var isDisabled = refs[currentFocusedIdx - 1].getAttribute('disabled') !== null;
|
|
38
|
+
if (!isDisabled) {
|
|
39
|
+
return refs[currentFocusedIdx - 1];
|
|
40
|
+
}
|
|
41
|
+
currentFocusedIdx--;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
function handleFocus(refs) {
|
|
45
|
+
return function (e) {
|
|
46
|
+
var currentFocusedIdx = refs.findIndex(function (el) {
|
|
47
|
+
var _document$activeEleme;
|
|
48
|
+
return (_document$activeEleme = document.activeElement) === null || _document$activeEleme === void 0 ? void 0 : _document$activeEleme.isSameNode(el);
|
|
49
|
+
});
|
|
50
|
+
var action = actionMap[e.key];
|
|
51
|
+
switch (action) {
|
|
52
|
+
case 'next':
|
|
53
|
+
if (currentFocusedIdx < refs.length - 1) {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
var _nextFocusableElement = getNextFocusableElement(refs, currentFocusedIdx);
|
|
56
|
+
_nextFocusableElement && _nextFocusableElement.focus();
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case 'prev':
|
|
60
|
+
if (currentFocusedIdx > 0) {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
var _prevFocusableElement = getPrevFocusableElement(refs, currentFocusedIdx);
|
|
63
|
+
_prevFocusableElement && _prevFocusableElement.focus();
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
case 'first':
|
|
67
|
+
e.preventDefault();
|
|
68
|
+
// Search for first non-disabled element if first element is disabled
|
|
69
|
+
var nextFocusableElement = getNextFocusableElement(refs, -1);
|
|
70
|
+
nextFocusableElement && nextFocusableElement.focus();
|
|
71
|
+
break;
|
|
72
|
+
case 'last':
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
// Search for last non-disabled element if last element is disabled
|
|
75
|
+
var prevFocusableElement = getPrevFocusableElement(refs, refs.length);
|
|
76
|
+
prevFocusableElement && prevFocusableElement.focus();
|
|
77
|
+
break;
|
|
78
|
+
default:
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
package/dist/cjs/version.json
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
3
|
import Avatar from '@atlaskit/avatar';
|
|
4
|
+
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
4
5
|
import { ButtonItem, CustomItem, LinkItem } from '@atlaskit/menu';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
import useRegisterItemWithFocusManager from './internal/hooks/use-register-item-with-focus-manager';
|
|
7
|
+
const AvatarGroupItem = /*#__PURE__*/forwardRef((props, ref) => {
|
|
8
|
+
const {
|
|
9
|
+
avatar,
|
|
10
|
+
onAvatarClick,
|
|
11
|
+
testId,
|
|
12
|
+
index
|
|
13
|
+
} = props;
|
|
11
14
|
const {
|
|
12
15
|
href,
|
|
13
16
|
onClick,
|
|
14
17
|
...rest
|
|
15
18
|
} = avatar;
|
|
19
|
+
const itemRef = useRegisterItemWithFocusManager();
|
|
16
20
|
const CustomComponent = ({
|
|
17
21
|
children,
|
|
18
22
|
...props
|
|
@@ -31,6 +35,7 @@ const AvatarGroupItem = ({
|
|
|
31
35
|
const callback = onClick || onAvatarClick;
|
|
32
36
|
if (href) {
|
|
33
37
|
return /*#__PURE__*/React.createElement(LinkItem, {
|
|
38
|
+
ref: mergeRefs([ref, itemRef]),
|
|
34
39
|
href: href,
|
|
35
40
|
target: avatar.target,
|
|
36
41
|
rel: avatar.target === '_blank' ? 'noopener noreferrer' : undefined,
|
|
@@ -41,6 +46,7 @@ const AvatarGroupItem = ({
|
|
|
41
46
|
}
|
|
42
47
|
if (typeof callback === 'function') {
|
|
43
48
|
return /*#__PURE__*/React.createElement(ButtonItem, {
|
|
49
|
+
ref: mergeRefs([ref, itemRef]),
|
|
44
50
|
onClick: event => callback && callback(event, undefined, index),
|
|
45
51
|
iconBefore: AvatarIcon,
|
|
46
52
|
testId: testId
|
|
@@ -51,7 +57,7 @@ const AvatarGroupItem = ({
|
|
|
51
57
|
component: CustomComponent,
|
|
52
58
|
testId: testId
|
|
53
59
|
}, avatar.name);
|
|
54
|
-
};
|
|
60
|
+
});
|
|
55
61
|
|
|
56
62
|
// eslint-disable-next-line @repo/internal/react/require-jsdoc
|
|
57
63
|
export default AvatarGroupItem;
|
|
@@ -9,6 +9,7 @@ import { layers } from '@atlaskit/theme/constants';
|
|
|
9
9
|
import Tooltip from '@atlaskit/tooltip';
|
|
10
10
|
import AvatarGroupItem from './avatar-group-item';
|
|
11
11
|
import Grid from './grid';
|
|
12
|
+
import FocusManager from './internal/components/focus-manager';
|
|
12
13
|
import MoreIndicator from './more-indicator';
|
|
13
14
|
import Stack from './stack';
|
|
14
15
|
import { composeUniqueKey } from './utils';
|
|
@@ -97,7 +98,7 @@ const AvatarGroup = ({
|
|
|
97
98
|
rootBoundary: rootBoundary,
|
|
98
99
|
shouldFlip: true,
|
|
99
100
|
zIndex: layers.modal(),
|
|
100
|
-
content: () => jsx(PopupMenuGroup, {
|
|
101
|
+
content: () => jsx(FocusManager, null, jsx(PopupMenuGroup, {
|
|
101
102
|
onClick: e => e.stopPropagation(),
|
|
102
103
|
minWidth: 250,
|
|
103
104
|
maxHeight: 300
|
|
@@ -109,7 +110,7 @@ const AvatarGroup = ({
|
|
|
109
110
|
},
|
|
110
111
|
// This index holds the true index,
|
|
111
112
|
// adding up the index of non-overflowed avatars and overflowed avatars.
|
|
112
|
-
index + max)))),
|
|
113
|
+
index + max))))),
|
|
113
114
|
trigger: triggerProps => renderMoreButton({
|
|
114
115
|
...triggerProps,
|
|
115
116
|
onClick: () => setIsOpen(!isOpen)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React, { createContext, useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { bind } from 'bind-event-listener';
|
|
3
|
+
import __noop from '@atlaskit/ds-lib/noop';
|
|
4
|
+
import handleFocus from '../utiles/handle-focus';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* Context provider which maintains the list of focusable elements and a method to
|
|
10
|
+
* register new menu items.
|
|
11
|
+
* This list drives the keyboard navgation of the menu.
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
export const FocusManagerContext = /*#__PURE__*/createContext({
|
|
15
|
+
menuItemRefs: [],
|
|
16
|
+
registerRef: __noop
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Focus manager logic
|
|
21
|
+
*/
|
|
22
|
+
const FocusManager = ({
|
|
23
|
+
children
|
|
24
|
+
}) => {
|
|
25
|
+
const menuItemRefs = useRef([]);
|
|
26
|
+
const registerRef = useCallback(ref => {
|
|
27
|
+
if (ref && !menuItemRefs.current.includes(ref)) {
|
|
28
|
+
menuItemRefs.current.push(ref);
|
|
29
|
+
}
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
// set focus and intentionally rebinding listener and clean up listener on each render
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
bind(window, {
|
|
35
|
+
type: 'keydown',
|
|
36
|
+
listener: handleFocus(menuItemRefs.current)
|
|
37
|
+
});
|
|
38
|
+
const unbind = () => {
|
|
39
|
+
bind(window, {
|
|
40
|
+
type: 'keydown',
|
|
41
|
+
listener: handleFocus(menuItemRefs.current)
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
return unbind;
|
|
45
|
+
}, []);
|
|
46
|
+
const contextValue = {
|
|
47
|
+
menuItemRefs: menuItemRefs.current,
|
|
48
|
+
registerRef
|
|
49
|
+
};
|
|
50
|
+
return /*#__PURE__*/React.createElement(FocusManagerContext.Provider, {
|
|
51
|
+
value: contextValue
|
|
52
|
+
}, children);
|
|
53
|
+
};
|
|
54
|
+
export default FocusManager;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useContext, useEffect, useRef } from 'react';
|
|
2
|
+
import { FocusManagerContext } from '../components/focus-manager';
|
|
3
|
+
|
|
4
|
+
// The refs stored in the context are used to programatically
|
|
5
|
+
// control focus on a user navigates using the keyboard.
|
|
6
|
+
function useRegisterItemWithFocusManager() {
|
|
7
|
+
const {
|
|
8
|
+
registerRef
|
|
9
|
+
} = useContext(FocusManagerContext);
|
|
10
|
+
const itemRef = useRef(null);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (itemRef.current !== null) {
|
|
13
|
+
registerRef(itemRef.current);
|
|
14
|
+
}
|
|
15
|
+
}, [registerRef]);
|
|
16
|
+
return itemRef;
|
|
17
|
+
}
|
|
18
|
+
export default useRegisterItemWithFocusManager;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { KEY_DOWN, KEY_END, KEY_HOME, KEY_UP } from '@atlaskit/ds-lib/keycodes';
|
|
2
|
+
const actionMap = {
|
|
3
|
+
[KEY_DOWN]: 'next',
|
|
4
|
+
[KEY_UP]: 'prev',
|
|
5
|
+
[KEY_HOME]: 'first',
|
|
6
|
+
[KEY_END]: 'last'
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* currentFocusedIdx + 1 will not work if the next focusable element
|
|
11
|
+
* is disabled. So, we need to iterate through the following menu items
|
|
12
|
+
* to find one that isn't disabled. If all following elements are disabled,
|
|
13
|
+
* return undefined.
|
|
14
|
+
*/
|
|
15
|
+
const getNextFocusableElement = (refs, currentFocusedIdx) => {
|
|
16
|
+
while (currentFocusedIdx + 1 < refs.length) {
|
|
17
|
+
const isDisabled = refs[currentFocusedIdx + 1].getAttribute('disabled') !== null;
|
|
18
|
+
if (!isDisabled) {
|
|
19
|
+
return refs[currentFocusedIdx + 1];
|
|
20
|
+
}
|
|
21
|
+
currentFocusedIdx++;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* currentFocusedIdx - 1 will not work if the prev focusable element
|
|
27
|
+
* is disabled. So, we need to iterate through the previous menu items
|
|
28
|
+
* to find one that isn't disabled. If all previous elements are disabled,
|
|
29
|
+
* return undefined.
|
|
30
|
+
*/
|
|
31
|
+
const getPrevFocusableElement = (refs, currentFocusedIdx) => {
|
|
32
|
+
while (currentFocusedIdx > 0) {
|
|
33
|
+
const isDisabled = refs[currentFocusedIdx - 1].getAttribute('disabled') !== null;
|
|
34
|
+
if (!isDisabled) {
|
|
35
|
+
return refs[currentFocusedIdx - 1];
|
|
36
|
+
}
|
|
37
|
+
currentFocusedIdx--;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
export default function handleFocus(refs) {
|
|
41
|
+
return e => {
|
|
42
|
+
const currentFocusedIdx = refs.findIndex(el => {
|
|
43
|
+
var _document$activeEleme;
|
|
44
|
+
return (_document$activeEleme = document.activeElement) === null || _document$activeEleme === void 0 ? void 0 : _document$activeEleme.isSameNode(el);
|
|
45
|
+
});
|
|
46
|
+
const action = actionMap[e.key];
|
|
47
|
+
switch (action) {
|
|
48
|
+
case 'next':
|
|
49
|
+
if (currentFocusedIdx < refs.length - 1) {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
const nextFocusableElement = getNextFocusableElement(refs, currentFocusedIdx);
|
|
52
|
+
nextFocusableElement && nextFocusableElement.focus();
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
case 'prev':
|
|
56
|
+
if (currentFocusedIdx > 0) {
|
|
57
|
+
e.preventDefault();
|
|
58
|
+
const prevFocusableElement = getPrevFocusableElement(refs, currentFocusedIdx);
|
|
59
|
+
prevFocusableElement && prevFocusableElement.focus();
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
case 'first':
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
// Search for first non-disabled element if first element is disabled
|
|
65
|
+
const nextFocusableElement = getNextFocusableElement(refs, -1);
|
|
66
|
+
nextFocusableElement && nextFocusableElement.focus();
|
|
67
|
+
break;
|
|
68
|
+
case 'last':
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
// Search for last non-disabled element if last element is disabled
|
|
71
|
+
const prevFocusableElement = getPrevFocusableElement(refs, refs.length);
|
|
72
|
+
prevFocusableElement && prevFocusableElement.focus();
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
package/dist/es2019/version.json
CHANGED
|
@@ -2,20 +2,23 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
2
2
|
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
3
3
|
var _excluded = ["href", "onClick"],
|
|
4
4
|
_excluded2 = ["children"];
|
|
5
|
-
import React from 'react';
|
|
5
|
+
import React, { forwardRef } from 'react';
|
|
6
6
|
import Avatar from '@atlaskit/avatar';
|
|
7
|
+
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
7
8
|
import { ButtonItem, CustomItem, LinkItem } from '@atlaskit/menu';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
import useRegisterItemWithFocusManager from './internal/hooks/use-register-item-with-focus-manager';
|
|
10
|
+
var AvatarGroupItem = /*#__PURE__*/forwardRef(function (props, ref) {
|
|
11
|
+
var avatar = props.avatar,
|
|
12
|
+
onAvatarClick = props.onAvatarClick,
|
|
13
|
+
testId = props.testId,
|
|
14
|
+
index = props.index;
|
|
13
15
|
var href = avatar.href,
|
|
14
16
|
onClick = avatar.onClick,
|
|
15
17
|
rest = _objectWithoutProperties(avatar, _excluded);
|
|
16
|
-
var
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
var itemRef = useRegisterItemWithFocusManager();
|
|
19
|
+
var CustomComponent = function CustomComponent(_ref) {
|
|
20
|
+
var children = _ref.children,
|
|
21
|
+
props = _objectWithoutProperties(_ref, _excluded2);
|
|
19
22
|
// eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
|
|
20
23
|
return /*#__PURE__*/React.createElement("span", props, children);
|
|
21
24
|
};
|
|
@@ -30,6 +33,7 @@ var AvatarGroupItem = function AvatarGroupItem(_ref) {
|
|
|
30
33
|
var callback = onClick || onAvatarClick;
|
|
31
34
|
if (href) {
|
|
32
35
|
return /*#__PURE__*/React.createElement(LinkItem, {
|
|
36
|
+
ref: mergeRefs([ref, itemRef]),
|
|
33
37
|
href: href,
|
|
34
38
|
target: avatar.target,
|
|
35
39
|
rel: avatar.target === '_blank' ? 'noopener noreferrer' : undefined,
|
|
@@ -42,6 +46,7 @@ var AvatarGroupItem = function AvatarGroupItem(_ref) {
|
|
|
42
46
|
}
|
|
43
47
|
if (typeof callback === 'function') {
|
|
44
48
|
return /*#__PURE__*/React.createElement(ButtonItem, {
|
|
49
|
+
ref: mergeRefs([ref, itemRef]),
|
|
45
50
|
onClick: function onClick(event) {
|
|
46
51
|
return callback && callback(event, undefined, index);
|
|
47
52
|
},
|
|
@@ -54,7 +59,7 @@ var AvatarGroupItem = function AvatarGroupItem(_ref) {
|
|
|
54
59
|
component: CustomComponent,
|
|
55
60
|
testId: testId
|
|
56
61
|
}, avatar.name);
|
|
57
|
-
};
|
|
62
|
+
});
|
|
58
63
|
|
|
59
64
|
// eslint-disable-next-line @repo/internal/react/require-jsdoc
|
|
60
65
|
export default AvatarGroupItem;
|
|
@@ -13,6 +13,7 @@ import { layers } from '@atlaskit/theme/constants';
|
|
|
13
13
|
import Tooltip from '@atlaskit/tooltip';
|
|
14
14
|
import AvatarGroupItem from './avatar-group-item';
|
|
15
15
|
import Grid from './grid';
|
|
16
|
+
import FocusManager from './internal/components/focus-manager';
|
|
16
17
|
import MoreIndicator from './more-indicator';
|
|
17
18
|
import Stack from './stack';
|
|
18
19
|
import { composeUniqueKey } from './utils';
|
|
@@ -116,7 +117,7 @@ var AvatarGroup = function AvatarGroup(_ref) {
|
|
|
116
117
|
shouldFlip: true,
|
|
117
118
|
zIndex: layers.modal(),
|
|
118
119
|
content: function content() {
|
|
119
|
-
return jsx(PopupMenuGroup, {
|
|
120
|
+
return jsx(FocusManager, null, jsx(PopupMenuGroup, {
|
|
120
121
|
onClick: function onClick(e) {
|
|
121
122
|
return e.stopPropagation();
|
|
122
123
|
},
|
|
@@ -132,7 +133,7 @@ var AvatarGroup = function AvatarGroup(_ref) {
|
|
|
132
133
|
// This index holds the true index,
|
|
133
134
|
// adding up the index of non-overflowed avatars and overflowed avatars.
|
|
134
135
|
index + max);
|
|
135
|
-
})));
|
|
136
|
+
}))));
|
|
136
137
|
},
|
|
137
138
|
trigger: function trigger(triggerProps) {
|
|
138
139
|
return renderMoreButton(_objectSpread(_objectSpread({}, triggerProps), {}, {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { createContext, useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { bind } from 'bind-event-listener';
|
|
3
|
+
import __noop from '@atlaskit/ds-lib/noop';
|
|
4
|
+
import handleFocus from '../utiles/handle-focus';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* Context provider which maintains the list of focusable elements and a method to
|
|
10
|
+
* register new menu items.
|
|
11
|
+
* This list drives the keyboard navgation of the menu.
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
export var FocusManagerContext = /*#__PURE__*/createContext({
|
|
15
|
+
menuItemRefs: [],
|
|
16
|
+
registerRef: __noop
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Focus manager logic
|
|
21
|
+
*/
|
|
22
|
+
var FocusManager = function FocusManager(_ref) {
|
|
23
|
+
var children = _ref.children;
|
|
24
|
+
var menuItemRefs = useRef([]);
|
|
25
|
+
var registerRef = useCallback(function (ref) {
|
|
26
|
+
if (ref && !menuItemRefs.current.includes(ref)) {
|
|
27
|
+
menuItemRefs.current.push(ref);
|
|
28
|
+
}
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
// set focus and intentionally rebinding listener and clean up listener on each render
|
|
32
|
+
useEffect(function () {
|
|
33
|
+
bind(window, {
|
|
34
|
+
type: 'keydown',
|
|
35
|
+
listener: handleFocus(menuItemRefs.current)
|
|
36
|
+
});
|
|
37
|
+
var unbind = function unbind() {
|
|
38
|
+
bind(window, {
|
|
39
|
+
type: 'keydown',
|
|
40
|
+
listener: handleFocus(menuItemRefs.current)
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
return unbind;
|
|
44
|
+
}, []);
|
|
45
|
+
var contextValue = {
|
|
46
|
+
menuItemRefs: menuItemRefs.current,
|
|
47
|
+
registerRef: registerRef
|
|
48
|
+
};
|
|
49
|
+
return /*#__PURE__*/React.createElement(FocusManagerContext.Provider, {
|
|
50
|
+
value: contextValue
|
|
51
|
+
}, children);
|
|
52
|
+
};
|
|
53
|
+
export default FocusManager;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useContext, useEffect, useRef } from 'react';
|
|
2
|
+
import { FocusManagerContext } from '../components/focus-manager';
|
|
3
|
+
|
|
4
|
+
// The refs stored in the context are used to programatically
|
|
5
|
+
// control focus on a user navigates using the keyboard.
|
|
6
|
+
function useRegisterItemWithFocusManager() {
|
|
7
|
+
var _useContext = useContext(FocusManagerContext),
|
|
8
|
+
registerRef = _useContext.registerRef;
|
|
9
|
+
var itemRef = useRef(null);
|
|
10
|
+
useEffect(function () {
|
|
11
|
+
if (itemRef.current !== null) {
|
|
12
|
+
registerRef(itemRef.current);
|
|
13
|
+
}
|
|
14
|
+
}, [registerRef]);
|
|
15
|
+
return itemRef;
|
|
16
|
+
}
|
|
17
|
+
export default useRegisterItemWithFocusManager;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
var _actionMap;
|
|
3
|
+
import { KEY_DOWN, KEY_END, KEY_HOME, KEY_UP } from '@atlaskit/ds-lib/keycodes';
|
|
4
|
+
var actionMap = (_actionMap = {}, _defineProperty(_actionMap, KEY_DOWN, 'next'), _defineProperty(_actionMap, KEY_UP, 'prev'), _defineProperty(_actionMap, KEY_HOME, 'first'), _defineProperty(_actionMap, KEY_END, 'last'), _actionMap);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* currentFocusedIdx + 1 will not work if the next focusable element
|
|
8
|
+
* is disabled. So, we need to iterate through the following menu items
|
|
9
|
+
* to find one that isn't disabled. If all following elements are disabled,
|
|
10
|
+
* return undefined.
|
|
11
|
+
*/
|
|
12
|
+
var getNextFocusableElement = function getNextFocusableElement(refs, currentFocusedIdx) {
|
|
13
|
+
while (currentFocusedIdx + 1 < refs.length) {
|
|
14
|
+
var isDisabled = refs[currentFocusedIdx + 1].getAttribute('disabled') !== null;
|
|
15
|
+
if (!isDisabled) {
|
|
16
|
+
return refs[currentFocusedIdx + 1];
|
|
17
|
+
}
|
|
18
|
+
currentFocusedIdx++;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* currentFocusedIdx - 1 will not work if the prev focusable element
|
|
24
|
+
* is disabled. So, we need to iterate through the previous menu items
|
|
25
|
+
* to find one that isn't disabled. If all previous elements are disabled,
|
|
26
|
+
* return undefined.
|
|
27
|
+
*/
|
|
28
|
+
var getPrevFocusableElement = function getPrevFocusableElement(refs, currentFocusedIdx) {
|
|
29
|
+
while (currentFocusedIdx > 0) {
|
|
30
|
+
var isDisabled = refs[currentFocusedIdx - 1].getAttribute('disabled') !== null;
|
|
31
|
+
if (!isDisabled) {
|
|
32
|
+
return refs[currentFocusedIdx - 1];
|
|
33
|
+
}
|
|
34
|
+
currentFocusedIdx--;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
export default function handleFocus(refs) {
|
|
38
|
+
return function (e) {
|
|
39
|
+
var currentFocusedIdx = refs.findIndex(function (el) {
|
|
40
|
+
var _document$activeEleme;
|
|
41
|
+
return (_document$activeEleme = document.activeElement) === null || _document$activeEleme === void 0 ? void 0 : _document$activeEleme.isSameNode(el);
|
|
42
|
+
});
|
|
43
|
+
var action = actionMap[e.key];
|
|
44
|
+
switch (action) {
|
|
45
|
+
case 'next':
|
|
46
|
+
if (currentFocusedIdx < refs.length - 1) {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
var _nextFocusableElement = getNextFocusableElement(refs, currentFocusedIdx);
|
|
49
|
+
_nextFocusableElement && _nextFocusableElement.focus();
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case 'prev':
|
|
53
|
+
if (currentFocusedIdx > 0) {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
var _prevFocusableElement = getPrevFocusableElement(refs, currentFocusedIdx);
|
|
56
|
+
_prevFocusableElement && _prevFocusableElement.focus();
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case 'first':
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
// Search for first non-disabled element if first element is disabled
|
|
62
|
+
var nextFocusableElement = getNextFocusableElement(refs, -1);
|
|
63
|
+
nextFocusableElement && nextFocusableElement.focus();
|
|
64
|
+
break;
|
|
65
|
+
case 'last':
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
// Search for last non-disabled element if last element is disabled
|
|
68
|
+
var prevFocusableElement = getPrevFocusableElement(refs, refs.length);
|
|
69
|
+
prevFocusableElement && prevFocusableElement.focus();
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
package/dist/esm/version.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { AvatarProps, onAvatarClickHandler } from './types';
|
|
3
3
|
export interface AvatarGroupItemProps {
|
|
4
4
|
avatar: AvatarProps;
|
|
@@ -8,5 +8,5 @@ export interface AvatarGroupItemProps {
|
|
|
8
8
|
onAvatarClick?: onAvatarClickHandler;
|
|
9
9
|
testId?: string;
|
|
10
10
|
}
|
|
11
|
-
declare const AvatarGroupItem:
|
|
11
|
+
declare const AvatarGroupItem: React.ForwardRefExoticComponent<AvatarGroupItemProps & React.RefAttributes<HTMLElement>>;
|
|
12
12
|
export default AvatarGroupItem;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React, { FC, ReactNode } from 'react';
|
|
2
|
+
import { FocusableElement } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* Context provider which maintains the list of focusable elements and a method to
|
|
7
|
+
* register new menu items.
|
|
8
|
+
* This list drives the keyboard navgation of the menu.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
export declare const FocusManagerContext: React.Context<{
|
|
12
|
+
menuItemRefs: FocusableElement[];
|
|
13
|
+
registerRef: (ref: FocusableElement) => void;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Focus manager logic
|
|
17
|
+
*/
|
|
18
|
+
declare const FocusManager: FC<{
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
}>;
|
|
21
|
+
export default FocusManager;
|
|
@@ -18,3 +18,5 @@ export interface AvatarGroupOverrides {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
export type onAvatarClickHandler = (event: React.MouseEvent, analyticsEvent: AnalyticsEvent | undefined, index: number) => void;
|
|
21
|
+
export type FocusableElement = HTMLAnchorElement | HTMLButtonElement;
|
|
22
|
+
export type Action = 'next' | 'prev' | 'first' | 'last';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { AvatarProps, onAvatarClickHandler } from './types';
|
|
3
3
|
export interface AvatarGroupItemProps {
|
|
4
4
|
avatar: AvatarProps;
|
|
@@ -8,5 +8,5 @@ export interface AvatarGroupItemProps {
|
|
|
8
8
|
onAvatarClick?: onAvatarClickHandler;
|
|
9
9
|
testId?: string;
|
|
10
10
|
}
|
|
11
|
-
declare const AvatarGroupItem:
|
|
11
|
+
declare const AvatarGroupItem: React.ForwardRefExoticComponent<AvatarGroupItemProps & React.RefAttributes<HTMLElement>>;
|
|
12
12
|
export default AvatarGroupItem;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React, { FC, ReactNode } from 'react';
|
|
2
|
+
import { FocusableElement } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* Context provider which maintains the list of focusable elements and a method to
|
|
7
|
+
* register new menu items.
|
|
8
|
+
* This list drives the keyboard navgation of the menu.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
export declare const FocusManagerContext: React.Context<{
|
|
12
|
+
menuItemRefs: FocusableElement[];
|
|
13
|
+
registerRef: (ref: FocusableElement) => void;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Focus manager logic
|
|
17
|
+
*/
|
|
18
|
+
declare const FocusManager: FC<{
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
}>;
|
|
21
|
+
export default FocusManager;
|
|
@@ -18,3 +18,5 @@ export interface AvatarGroupOverrides {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
export type onAvatarClickHandler = (event: React.MouseEvent, analyticsEvent: AnalyticsEvent | undefined, index: number) => void;
|
|
21
|
+
export type FocusableElement = HTMLAnchorElement | HTMLButtonElement;
|
|
22
|
+
export type Action = 'next' | 'prev' | 'first' | 'last';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/avatar-group",
|
|
3
|
-
"version": "9.3.
|
|
3
|
+
"version": "9.3.4",
|
|
4
4
|
"description": "An avatar group displays a number of avatars grouped together in a stack or grid.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -35,13 +35,15 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@atlaskit/avatar": "^21.3.0",
|
|
38
|
+
"@atlaskit/ds-lib": "^2.1.0",
|
|
38
39
|
"@atlaskit/menu": "^1.7.0",
|
|
39
40
|
"@atlaskit/popup": "^1.6.0",
|
|
40
41
|
"@atlaskit/theme": "^12.5.0",
|
|
41
42
|
"@atlaskit/tokens": "^1.5.0",
|
|
42
43
|
"@atlaskit/tooltip": "^17.8.0",
|
|
43
44
|
"@babel/runtime": "^7.0.0",
|
|
44
|
-
"@emotion/react": "^11.7.1"
|
|
45
|
+
"@emotion/react": "^11.7.1",
|
|
46
|
+
"bind-event-listener": "^2.1.1"
|
|
45
47
|
},
|
|
46
48
|
"peerDependencies": {
|
|
47
49
|
"react": "^16.8.0"
|
|
@@ -54,7 +56,7 @@
|
|
|
54
56
|
"@atlaskit/ds-lib": "^2.2.0",
|
|
55
57
|
"@atlaskit/form": "^8.11.0",
|
|
56
58
|
"@atlaskit/icon": "^21.12.0",
|
|
57
|
-
"@atlaskit/modal-dialog": "^12.
|
|
59
|
+
"@atlaskit/modal-dialog": "^12.6.0",
|
|
58
60
|
"@atlaskit/section-message": "^6.4.0",
|
|
59
61
|
"@atlaskit/ssr": "*",
|
|
60
62
|
"@atlaskit/toggle": "^12.6.0",
|