UNPKG

@atlaskit/avatar-group

Version:

An avatar group displays a number of avatars grouped together in a stack or grid.

269 lines (262 loc) 12.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); 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 _avatar = _interopRequireDefault(require("@atlaskit/avatar")); var _keycodes = require("@atlaskit/ds-lib/keycodes"); var _noop = _interopRequireDefault(require("@atlaskit/ds-lib/noop")); var _useFocusEvent = _interopRequireDefault(require("@atlaskit/ds-lib/use-focus-event")); var _menu = require("@atlaskit/menu"); var _popup = _interopRequireDefault(require("@atlaskit/popup")); var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip")); var _avatarGroupItem = _interopRequireDefault(require("./avatar-group-item")); var _grid = _interopRequireDefault(require("./grid")); var _focusManager = _interopRequireDefault(require("./internal/components/focus-manager")); var _popupAvatarGroup = _interopRequireDefault(require("./internal/components/popup-avatar-group")); var _moreIndicator = _interopRequireDefault(require("./more-indicator")); var _stack = _interopRequireDefault(require("./stack")); var _utils = require("./utils"); var _excluded = ["aria-controls", "aria-expanded", "aria-haspopup", "onClick"]; 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 MAX_COUNT = { grid: 11, stack: 5 }; function getOverrides(overrides) { return { AvatarGroupItem: _objectSpread({ render: function render(Component, props, index) { return /*#__PURE__*/_react.default.createElement(Component, (0, _extends2.default)({}, props, { key: (0, _utils.composeUniqueKey)(props.avatar, index) })); } }, overrides && overrides.AvatarGroupItem), Avatar: _objectSpread({ render: function render(Component, props, index) { return /*#__PURE__*/_react.default.createElement(Component, (0, _extends2.default)({}, props, { key: (0, _utils.composeUniqueKey)(props, index) })); } }, overrides && overrides.Avatar), MoreIndicator: _objectSpread({ render: function render(Component, props) { return /*#__PURE__*/_react.default.createElement(Component, props); } }, overrides && overrides.MoreIndicator) }; } /** * __Avatar group__ * * An avatar group displays a number of avatars grouped together in a stack or grid. * * - [Examples](https://atlassian.design/components/avatar-group/examples) * - [Code](https://atlassian.design/components/avatar-group/code) * - [Usage](https://atlassian.design/components/avatar-group/usage) */ var AvatarGroup = function AvatarGroup(_ref) { var _ref$appearance = _ref.appearance, appearance = _ref$appearance === void 0 ? 'stack' : _ref$appearance, _ref$avatar = _ref.avatar, avatar = _ref$avatar === void 0 ? _avatar.default : _ref$avatar, borderColor = _ref.borderColor, boundariesElement = _ref.boundariesElement, data = _ref.data, isTooltipDisabled = _ref.isTooltipDisabled, maxCount = _ref.maxCount, onAvatarClick = _ref.onAvatarClick, onMoreClick = _ref.onMoreClick, overrides = _ref.overrides, _ref$showMoreButtonPr = _ref.showMoreButtonProps, showMoreButtonProps = _ref$showMoreButtonPr === void 0 ? {} : _ref$showMoreButtonPr, _ref$size = _ref.size, size = _ref$size === void 0 ? 'medium' : _ref$size, testId = _ref.testId, _ref$label = _ref.label, label = _ref$label === void 0 ? 'avatar group' : _ref$label, moreIndicatorLabel = _ref.moreIndicatorLabel, _ref$tooltipPosition = _ref.tooltipPosition, tooltipPosition = _ref$tooltipPosition === void 0 ? 'bottom' : _ref$tooltipPosition, _ref$shouldPopupRende = _ref.shouldPopupRenderToParent, shouldPopupRenderToParent = _ref$shouldPopupRende === void 0 ? false : _ref$shouldPopupRende; var _useState = (0, _react.useState)(false), _useState2 = (0, _slicedToArray2.default)(_useState, 2), isTriggeredUsingKeyboard = _useState2[0], setTriggeredUsingKeyboard = _useState2[1]; var _useState3 = (0, _react.useState)(false), _useState4 = (0, _slicedToArray2.default)(_useState3, 2), isOpen = _useState4[0], setIsOpen = _useState4[1]; var onClose = (0, _react.useCallback)(function () { return setIsOpen(false); }, []); var handleTriggerClicked = (0, _react.useCallback)(function (event) { var _ref2 = event, clientX = _ref2.clientX, clientY = _ref2.clientY, type = _ref2.type; // Hitting enter/space is registered as a click with both clientX and clientY === 0 if (type === 'keydown' || clientX === 0 || clientY === 0) { setTriggeredUsingKeyboard(true); } setIsOpen(function (isOpen) { return !isOpen; }); }, []); var _useFocus = (0, _useFocusEvent.default)(), isFocused = _useFocus.isFocused, bindFocus = _useFocus.bindFocus; // When a trigger is focused, we want to open the popup // the user presses the DownArrow (0, _react.useEffect)(function () { // Set initial value if popup is closed if (!isOpen) { setTriggeredUsingKeyboard(false); } // Only need to listen for keydown when focused if (!isFocused) { return _noop.default; } // Being safe: we don't want to open the popup if it is already open // Note: This shouldn't happen as the trigger should not be able to get focus if (isOpen) { return _noop.default; } (0, _bindEventListener.bind)(window, { type: 'keydown', listener: function openOnKeyDown(e) { if (e.key === _keycodes.KEY_DOWN) { // prevent page scroll e.preventDefault(); handleTriggerClicked(e); } } }); var unbind = function unbind() { (0, _bindEventListener.bind)(window, { type: 'keydown', listener: function openOnKeyDown(e) { if (e.key === _keycodes.KEY_DOWN) { // prevent page scroll e.preventDefault(); handleTriggerClicked(e); } } }); }; return unbind; }, [isFocused, isOpen, handleTriggerClicked]); function renderMoreDropdown(max, total) { if (total <= max) { return null; } var renderMoreButton = function renderMoreButton(_ref3) { var ariaControls = _ref3['aria-controls'], ariaExpanded = _ref3['aria-expanded'], ariaHasPopup = _ref3['aria-haspopup'], onClick = _ref3.onClick, props = (0, _objectWithoutProperties2.default)(_ref3, _excluded); return getOverrides(overrides).MoreIndicator.render(_moreIndicator.default, _objectSpread({ buttonProps: showMoreButtonProps, borderColor: borderColor, count: total - max, size: size, testId: testId && "".concat(testId, "--overflow-menu--trigger"), isActive: isOpen, moreIndicatorLabel: moreIndicatorLabel, 'aria-controls': ariaControls, 'aria-expanded': ariaExpanded, 'aria-haspopup': ariaHasPopup, onClick: onClick }, props)); }; // bail if the consumer wants to handle onClick if (typeof onMoreClick === 'function') { return renderMoreButton({ onClick: onMoreClick }); } // split boundariesElement into `boundary` and `rootBoundary` props for Popup var boundary = boundariesElement === 'scrollParent' ? 'clippingParents' : undefined; var rootBoundary = function () { if (boundariesElement === 'scrollParent') { return undefined; } return boundariesElement === 'window' ? 'document' : 'viewport'; }(); return /*#__PURE__*/_react.default.createElement(_popup.default, { isOpen: isOpen, onClose: onClose, placement: "bottom-end", boundary: boundary, rootBoundary: rootBoundary, shouldFlip: true, zIndex: 510, shouldRenderToParent: shouldPopupRenderToParent, content: function content(_ref4) { var setInitialFocusRef = _ref4.setInitialFocusRef; return /*#__PURE__*/_react.default.createElement(_focusManager.default, null, /*#__PURE__*/_react.default.createElement(_popupAvatarGroup.default, { onClick: function onClick(e) { return e.stopPropagation(); }, minWidth: 250, maxHeight: 300, setInitialFocusRef: isTriggeredUsingKeyboard ? setInitialFocusRef : undefined }, /*#__PURE__*/_react.default.createElement(_menu.Section, null, 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), index: index + max }, // This index holds the true index, // adding up the index of non-overflowed avatars and overflowed avatars. index + max); })))); }, trigger: function trigger(triggerProps) { return renderMoreButton(_objectSpread(_objectSpread(_objectSpread({}, triggerProps), bindFocus), {}, { onClick: handleTriggerClicked })); }, testId: testId && "".concat(testId, "--overflow-menu") }); } var max = maxCount === undefined || maxCount === 0 ? MAX_COUNT[appearance] : maxCount; var total = data.length; var maxAvatar = total > max ? max - 1 : max; var Group = appearance === 'stack' ? _stack.default : _grid.default; return /*#__PURE__*/_react.default.createElement(Group, { testId: testId && "".concat(testId, "--avatar-group"), "aria-label": label }, data.slice(0, maxAvatar).map(function (avatarData, idx) { var callback = avatarData.onClick || onAvatarClick; var finalAvatar = getOverrides(overrides).Avatar.render(avatar, _objectSpread(_objectSpread({}, avatarData), {}, { size: size, borderColor: borderColor || avatarData.borderColor, testId: testId && "".concat(testId, "--avatar-").concat(idx), onClick: callback ? function (event, analyticsEvent) { callback(event, analyticsEvent, idx); } : undefined, stackIndex: max - idx }), idx); return !isTooltipDisabled && !avatarData.isDisabled ? /*#__PURE__*/_react.default.createElement(_tooltip.default, { key: (0, _utils.composeUniqueKey)(avatarData, idx), content: avatarData.name, testId: testId && "".concat(testId, "--tooltip-").concat(idx), position: tooltipPosition }, finalAvatar) : finalAvatar; }), renderMoreDropdown(+maxAvatar, total)); }; var _default = exports.default = AvatarGroup;