@atlaskit/mention
Version:
A React component used to display user profiles in a list for 'Mention' functionality
189 lines (187 loc) • 6.29 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import React from 'react';
import { withAnalyticsEvents } from '@atlaskit/analytics-next';
import uniqueId from '../../util/id';
import debug from '../../util/logger';
import MentionList from '../MentionList';
import { fireSliAnalyticsEvent, SLI_EVENT_TYPE } from '../../util/analytics';
function applyPresence(mentions, presences) {
const updatedMentions = [];
for (let i = 0; i < mentions.length; i++) {
// Shallow copy
const mention = {
...mentions[i]
};
const presence = presences[mention.id];
if (presence) {
mention.presence = presence;
}
updatedMentions.push(mention);
}
return updatedMentions;
}
function extractPresences(mentions) {
const presences = {};
for (let i = 0; i < mentions.length; i++) {
const mention = mentions[i];
if (mention.presence) {
presences[mention.id] = mention.presence;
}
}
return presences;
}
export class ResourcedMentionListWithoutAnalytics extends React.PureComponent {
constructor(props) {
super(props);
// API
_defineProperty(this, "selectNext", () => {
if (this.mentionListRef) {
this.mentionListRef.selectNext();
}
});
_defineProperty(this, "selectPrevious", () => {
if (this.mentionListRef) {
this.mentionListRef.selectPrevious();
}
});
_defineProperty(this, "selectIndex", (index, callback) => {
if (this.mentionListRef) {
this.mentionListRef.selectIndex(index, callback);
}
});
_defineProperty(this, "selectId", (id, callback) => {
if (this.mentionListRef) {
this.mentionListRef.selectId(id, callback);
}
});
_defineProperty(this, "chooseCurrentSelection", () => {
if (this.mentionListRef) {
this.mentionListRef.chooseCurrentSelection();
}
});
_defineProperty(this, "mentionsCount", () => {
if (this.mentionListRef) {
return this.mentionListRef.mentionsCount();
}
return 0;
});
// internal, used for callbacks
_defineProperty(this, "filterChange", mentions => {
// Retain known presence
const currentPresences = extractPresences(this.state.mentions);
this.setState({
resourceError: undefined,
mentions: applyPresence(mentions, currentPresences)
});
this.refreshPresences(mentions);
});
_defineProperty(this, "sendAnalytics", (event, actionSubject, action) => {
if (event === SLI_EVENT_TYPE) {
fireSliAnalyticsEvent(this.props)(actionSubject, action);
}
});
_defineProperty(this, "filterError", error => {
debug('ak-resourced-mentions-list._filterError', error);
this.setState({
resourceError: error
});
});
_defineProperty(this, "presenceUpdate", presences => {
this.setState({
mentions: applyPresence(this.state.mentions, presences)
});
});
_defineProperty(this, "notifySelection", mention => {
this.props.resourceProvider.recordMentionSelection(mention);
if (this.props.onSelection) {
this.props.onSelection(mention);
}
});
_defineProperty(this, "handleMentionListRef", ref => {
this.mentionListRef = ref;
});
this.subscriberKey = uniqueId('ak-resourced-mention-list');
this.state = {
resourceError: undefined,
mentions: []
};
this.applyPropChanges({}, props);
}
componentDidMount() {
this.subscribeMentionProvider(this.props.resourceProvider);
this.subscribePresenceProvider(this.props.presenceProvider);
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.applyPropChanges(this.props, nextProps);
}
componentWillUnmount() {
this.unsubscribeMentionProvider(this.props.resourceProvider);
this.unsubscribePresenceProvider(this.props.presenceProvider);
}
// internal
subscribeMentionProvider(mentionProvider) {
if (mentionProvider) {
mentionProvider.subscribe(this.subscriberKey, this.filterChange, this.filterError, undefined, undefined, this.sendAnalytics);
}
}
subscribePresenceProvider(presenceProvider) {
if (presenceProvider) {
presenceProvider.subscribe(this.subscriberKey, this.presenceUpdate);
}
}
unsubscribeMentionProvider(mentionProvider) {
if (mentionProvider) {
mentionProvider.unsubscribe(this.subscriberKey);
}
}
unsubscribePresenceProvider(presenceProvider) {
if (presenceProvider) {
presenceProvider.unsubscribe(this.subscriberKey);
}
}
applyPropChanges(prevProps, nextProps) {
const oldResourceProvider = prevProps.resourceProvider;
const oldPresenceProvider = prevProps.presenceProvider;
const oldQuery = prevProps.query;
const newResourceProvider = nextProps.resourceProvider;
const newPresenceProvider = nextProps.presenceProvider;
const newQuery = nextProps.query;
const resourceProviderChanged = oldResourceProvider !== newResourceProvider;
const queryChanged = oldQuery !== newQuery;
const canFilter = !!(typeof newQuery === 'string' && newResourceProvider);
const shouldFilter = canFilter && (queryChanged || resourceProviderChanged);
// resource provider
if (resourceProviderChanged) {
this.unsubscribeMentionProvider(oldResourceProvider);
this.subscribeMentionProvider(newResourceProvider);
}
// presence provider
if (oldPresenceProvider !== newPresenceProvider) {
this.unsubscribePresenceProvider(oldPresenceProvider);
this.subscribePresenceProvider(newPresenceProvider);
}
if (shouldFilter) {
newResourceProvider.filter(newQuery);
}
}
refreshPresences(mentions) {
if (this.props.presenceProvider) {
const ids = mentions.map(mention => mention.id);
this.props.presenceProvider.refreshPresence(ids);
}
}
render() {
const {
mentions,
resourceError
} = this.state;
return /*#__PURE__*/React.createElement(MentionList, {
mentions: mentions,
resourceError: resourceError,
onSelection: this.notifySelection,
ref: this.handleMentionListRef
});
}
}
const ResourcedMentionList = withAnalyticsEvents({})(ResourcedMentionListWithoutAnalytics);
export default ResourcedMentionList;