@atlaskit/avatar-group
Version:
An avatar group displays a number of avatars grouped together in a stack or grid.
168 lines (165 loc) • 8.17 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MoreDropdownTopLayer = MoreDropdownTopLayer;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _bindEventListener = require("bind-event-listener");
var _keycodes = require("@atlaskit/ds-lib/keycodes");
var _menuGroup = _interopRequireDefault(require("@atlaskit/menu/menu-group"));
var _section = _interopRequireDefault(require("@atlaskit/menu/section"));
var _getAriaForTrigger = require("@atlaskit/top-layer/get-aria-for-trigger");
var _index = require("@atlaskit/top-layer/placement-map/index");
var _popoverSurface = require("@atlaskit/top-layer/popover-surface");
var _popover = require("@atlaskit/top-layer/popover/popover");
var _useAnchoredPopover = require("@atlaskit/top-layer/use-anchored-popover");
var _useArrowNavigation = require("@atlaskit/top-layer/use-arrow-navigation/use-arrow-navigation");
var _usePopoverId = require("@atlaskit/top-layer/use-popover-id");
var _avatarGroupItem = _interopRequireDefault(require("./avatar-group-item"));
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
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; }
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; }
var topLayerPlacement = (0, _index.fromLegacyPlacement)({
legacy: 'bottom-end'
});
function getOverrides(overrides) {
return {
AvatarGroupItem: _objectSpread({
render: function render(Component, props, index) {
return /*#__PURE__*/_react.default.createElement(Component, (0, _extends2.default)({
key: index
}, props));
}
}, overrides === null || overrides === void 0 ? void 0 : overrides.AvatarGroupItem),
Avatar: _objectSpread({
render: function render(Component, props, index) {
return /*#__PURE__*/_react.default.createElement(Component, (0, _extends2.default)({
key: index
}, props));
}
}, overrides === null || overrides === void 0 ? void 0 : overrides.Avatar),
MoreIndicator: _objectSpread({
render: function render(Component, props) {
return /*#__PURE__*/_react.default.createElement(Component, props);
}
}, overrides === null || overrides === void 0 ? void 0 : overrides.MoreIndicator)
};
}
/**
* Top-layer implementation of the avatar group overflow dropdown.
*
* Replaces the legacy `@atlaskit/popup` rendering pipeline
* (Popper.js + Portal + focus-trap + @atlaskit/layering)
* with the native Popover API + CSS Anchor Positioning via `@atlaskit/top-layer`.
*
* Uses `role="menu"` with arrow key navigation for correct menu semantics.
*
* Gated behind the `platform-dst-top-layer` feature flag.
*
* Legacy props that are no-ops in the top-layer path (not accepted here):
* - zIndex: stacking managed by browser top layer
* - shouldRenderToParent: always renders in top layer
* - boundary / rootBoundary: viewport is the natural boundary
* - shouldFlip: CSS Anchor Positioning handles flipping
*/
function MoreDropdownTopLayer(_ref) {
var isOpen = _ref.isOpen,
onClose = _ref.onClose,
_isTriggeredUsingKeyboard = _ref.isTriggeredUsingKeyboard,
data = _ref.data,
max = _ref.max,
overrides = _ref.overrides,
onAvatarClick = _ref.onAvatarClick,
testId = _ref.testId,
labelId = _ref.labelId,
renderMoreButton = _ref.renderMoreButton,
handleTriggerClicked = _ref.handleTriggerClicked,
_bindFocus = _ref.bindFocus;
var handleOnClose = (0, _react.useCallback)(function (_ref2) {
var _reason = _ref2.reason;
onClose();
}, [onClose]);
var triggerRef = (0, _react.useRef)(null);
var popoverRef = (0, _react.useRef)(null);
var menuRef = (0, _react.useRef)(null);
var overflowMenuTestId = testId ? "".concat(testId, "--overflow-menu") : undefined;
var popoverId = (0, _usePopoverId.usePopoverId)();
(0, _useAnchoredPopover.useAnchoredPopover)({
anchorRef: triggerRef,
popoverRef: popoverRef,
placement: topLayerPlacement,
isOpen: isOpen
});
// Arrow key navigation inside the open menu
(0, _useArrowNavigation.useArrowNavigation)({
containerRef: menuRef,
onClose: onClose,
isEnabled: isOpen
});
// ArrowDown-to-open: when the trigger is focused and the menu is closed,
// pressing ArrowDown opens the menu (WAI-ARIA menu button pattern).
//
// Bind the keydown listener directly to the trigger element via its ref so
// that opening the menu does not trigger a focus-driven re-render of the
// host component, which would unmount and remount the menu items and drop
// menuitem focus.
(0, _react.useEffect)(function () {
var trigger = triggerRef.current;
if (!trigger || isOpen) {
return;
}
return (0, _bindEventListener.bind)(trigger, {
type: 'keydown',
listener: function openOnArrowDown(event) {
if (event.key === _keycodes.KEY_DOWN) {
// Prevent page scroll when opening the menu via ArrowDown.
event.preventDefault();
handleTriggerClicked(event);
}
}
});
}, [isOpen, handleTriggerClicked]);
var triggerAria = (0, _getAriaForTrigger.getAriaForTrigger)({
role: 'menu',
isOpen: isOpen,
popoverId: popoverId
});
var setTriggerRef = (0, _react.useCallback)(function (node) {
triggerRef.current = node;
}, []);
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, renderMoreButton(_objectSpread(_objectSpread({
ref: setTriggerRef
}, triggerAria), {}, {
onClick: handleTriggerClicked
})), /*#__PURE__*/_react.default.createElement(_popover.Popover, {
ref: popoverRef,
id: popoverId,
role: "menu",
label: "avatar group",
isOpen: isOpen,
onClose: handleOnClose,
shouldAnimate: true,
placement: topLayerPlacement,
testId: overflowMenuTestId ? "".concat(overflowMenuTestId, "--content") : undefined
}, /*#__PURE__*/_react.default.createElement(_popoverSurface.PopoverSurface, null, /*#__PURE__*/_react.default.createElement("div", {
ref: menuRef
}, /*#__PURE__*/_react.default.createElement(_menuGroup.default, {
minWidth: 250,
maxHeight: 300
}, /*#__PURE__*/_react.default.createElement(_section.default, {
titleId: labelId,
testId: testId ? "".concat(testId, "--section") : undefined
}, data.slice(max).map(function (avatar, index) {
return getOverrides(overrides).AvatarGroupItem.render(_avatarGroupItem.default, {
avatar: avatar,
onAvatarClick: onAvatarClick,
testId: testId ? "".concat(testId, "--avatar-group-item-").concat(index + max) : undefined,
index: index + max,
role: 'menuitem'
}, index + max);
})))))));
}