UNPKG

@atlaskit/editor-plugin-avatar-group

Version:

Avatar Group plugin for @atlaskit/editor-core.

124 lines (120 loc) 5.49 kB
/** * @jsxRuntime classic * @jsx jsx */ import React from 'react'; // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports import { jsx } from '@emotion/react'; import { useIntl } from 'react-intl'; import AvatarGroup from '@atlaskit/avatar-group'; import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics'; import { Selection } from '@atlaskit/editor-prosemirror/state'; import { fg } from '@atlaskit/platform-feature-flags'; import { fetchUserNames } from '../services/fetch-user-names'; import { avatarContainerStyles } from './styles'; import toAvatar from './to-avatar'; const scrollToCollabCursor = (editorAPI, participants, sessionId, index, editorAnalyticsAPI) => { const selectedUser = participants[index]; const cursorPos = selectedUser.cursorPos; if (selectedUser && cursorPos !== undefined && selectedUser.sessionId !== sessionId) { var _editorAPI$core, _editorAPI$core$actio, _editorAPI$core2, _editorAPI$core2$acti; const analyticsPayload = { action: ACTION.MATCHED, actionSubject: ACTION_SUBJECT.SELECTION, eventType: EVENT_TYPE.TRACK }; editorAPI === null || editorAPI === void 0 ? void 0 : (_editorAPI$core = editorAPI.core) === null || _editorAPI$core === void 0 ? void 0 : (_editorAPI$core$actio = _editorAPI$core.actions) === null || _editorAPI$core$actio === void 0 ? void 0 : _editorAPI$core$actio.execute(({ tr }) => { tr.setSelection(Selection.near(tr.doc.resolve(cursorPos))); editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(analyticsPayload)(tr); tr.scrollIntoView(); return tr; }); editorAPI === null || editorAPI === void 0 ? void 0 : (_editorAPI$core2 = editorAPI.core) === null || _editorAPI$core2 === void 0 ? void 0 : (_editorAPI$core2$acti = _editorAPI$core2.actions) === null || _editorAPI$core2$acti === void 0 ? void 0 : _editorAPI$core2$acti.focus(); } }; const getMissingActingUserIdsKey = (participants, userNamesById) => { const participantUserIds = new Set(); const missingActingUserIds = new Set(); for (const participant of participants) { if (participant.userId) { participantUserIds.add(participant.userId); } } for (const participant of participants) { const actingUserId = participant.actingUserId; if (actingUserId && !participantUserIds.has(actingUserId) && !userNamesById[actingUserId]) { missingActingUserIds.add(actingUserId); } } let missingActingUserIdsKey = ''; for (const actingUserId of missingActingUserIds) { missingActingUserIdsKey = missingActingUserIdsKey ? `${missingActingUserIdsKey}|${actingUserId}` : actingUserId; } return missingActingUserIdsKey; }; export const Avatars = /*#__PURE__*/React.memo(props => { var _props$participants, _props$participants$t; const { sessionId, featureFlags, editorAPI } = props; const intl = useIntl(); const [userNamesById, setUserNamesById] = React.useState({}); // .slice() turns ReadonlyArray<CollabParticipant> into a mutable CollabParticipant[] const participants = (_props$participants = props.participants) === null || _props$participants === void 0 ? void 0 : (_props$participants$t = _props$participants.toArray()) === null || _props$participants$t === void 0 ? void 0 : _props$participants$t.slice(); const missingActingUserIdsKey = React.useMemo(() => { if (!participants || !fg('platform_move_presence_agents')) { return ''; } return getMissingActingUserIdsKey(participants, userNamesById); }, [participants, userNamesById]); React.useEffect(() => { if (!missingActingUserIdsKey) { return; } let cancelled = false; fetchUserNames(missingActingUserIdsKey.split('|')).then(namesById => { if (cancelled || !Object.keys(namesById).length) { return; } setUserNamesById(currentNamesById => ({ ...currentNamesById, ...namesById })); }); return () => { cancelled = true; }; }, [missingActingUserIdsKey]); if (!participants) { return null; } // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed) const avatars = participants.sort(p => p.sessionId === sessionId ? -1 : 1).map(participant => toAvatar(participant, editorAPI, intl.formatMessage, participants, userNamesById)); if (!avatars.length) { return null; } return ( // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage, @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 jsx("div", { css: avatarContainerStyles }, jsx(AvatarGroup, { appearance: "stack", size: "medium", data: avatars, maxCount: 3 // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onAvatarClick: (_event, _analytics, index) => { const allowCollabAvatarScroll = featureFlags === null || featureFlags === void 0 ? void 0 : featureFlags.collabAvatarScroll; // user does not need to scroll to their own position (index 0) if (allowCollabAvatarScroll && index > 0) { scrollToCollabCursor(editorAPI, participants, props.sessionId, index, props.editorAnalyticsAPI); } } }), props.children) ); });