@atlaskit/mention
Version:
A React component used to display user profiles in a list for 'Mention' functionality
238 lines (234 loc) • 9.26 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _logger = _interopRequireDefault(require("../../util/logger"));
var _mouse = require("../../util/mouse");
var _MentionItem = _interopRequireDefault(require("../MentionItem"));
var _MentionListError = _interopRequireDefault(require("../MentionListError"));
var _MessagesIntlProvider = _interopRequireDefault(require("../MessagesIntlProvider"));
var _Scrollable = _interopRequireDefault(require("../Scrollable"));
var _styles = require("./styles");
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function wrapIndex(mentions, index) {
var len = mentions.length;
var newIndex = index;
while (newIndex < 0 && len > 0) {
newIndex += len;
}
return newIndex % len;
}
function getKey(index, mentions) {
return mentions && mentions[index] && mentions[index].id;
}
function getIndex(key, mentions) {
var index;
if (mentions) {
index = 0;
while (index < mentions.length && mentions[index].id !== key) {
index++;
}
if (index === mentions.length) {
index = undefined;
}
}
return index;
}
var MentionList = exports.default = /*#__PURE__*/function (_React$PureComponent) {
function MentionList(props) {
var _this;
(0, _classCallCheck2.default)(this, MentionList);
_this = _callSuper(this, MentionList, [props]);
// API
(0, _defineProperty2.default)(_this, "selectNext", function () {
var newIndex = wrapIndex(_this.props.mentions, _this.state.selectedIndex + 1);
_this.selectIndex(newIndex);
});
(0, _defineProperty2.default)(_this, "selectPrevious", function () {
var newIndex = wrapIndex(_this.props.mentions, _this.state.selectedIndex - 1);
_this.selectIndex(newIndex);
});
(0, _defineProperty2.default)(_this, "selectIndex", function (index, callback) {
var mentions = _this.props.mentions;
_this.setState({
selectedIndex: index,
selectedKey: getKey(index, mentions)
}, callback);
});
(0, _defineProperty2.default)(_this, "selectId", function (id, callback) {
var mentions = _this.props.mentions;
var index = getIndex(id, mentions);
if (index !== undefined) {
_this.setState({
selectedIndex: index,
selectedKey: id
}, callback);
}
});
(0, _defineProperty2.default)(_this, "chooseCurrentSelection", function () {
var _this$props = _this.props,
mentions = _this$props.mentions,
onSelection = _this$props.onSelection;
var selectedIndex = _this.state.selectedIndex;
var selectedMention = mentions && mentions[selectedIndex || 0];
(0, _logger.default)('ak-mention-list.chooseCurrentSelection', selectedMention);
if (onSelection && selectedMention) {
onSelection(selectedMention);
}
});
(0, _defineProperty2.default)(_this, "mentionsCount", function () {
var mentions = _this.props.mentions;
return mentions && mentions.length || 0;
});
(0, _defineProperty2.default)(_this, "selectIndexOnHover", function (mention, event) {
if (!event) {
return;
}
var mousePosition = (0, _mouse.mouseLocation)(event);
if ((0, _mouse.actualMouseMove)(_this.lastMousePosition, mousePosition)) {
_this.selectId(mention.id);
}
_this.lastMousePosition = mousePosition;
});
(0, _defineProperty2.default)(_this, "itemSelected", function (mention) {
_this.selectId(mention.id, function () {
_this.chooseCurrentSelection();
});
});
(0, _defineProperty2.default)(_this, "handleScrollableRef", function (ref) {
_this.scrollable = ref;
});
_this.setDefaultSelectionState();
return _this;
}
(0, _inherits2.default)(MentionList, _React$PureComponent);
return (0, _createClass2.default)(MentionList, [{
key: "UNSAFE_componentWillReceiveProps",
value: function UNSAFE_componentWillReceiveProps(nextProps) {
// adjust selection
var mentions = nextProps.mentions;
var selectedKey = this.state.selectedKey;
if (mentions) {
if (!selectedKey) {
// don't explicitly set any selected index and go with default behaviour
return;
}
for (var i = 0; i < mentions.length; i++) {
if (selectedKey === mentions[i].id) {
this.setState({
selectedIndex: i
});
return;
}
}
// existing selection not in results so clear any current selection state and go with default behaviour
this.setDefaultSelectionState();
}
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate() {
var mentions = this.props.mentions;
var selectedIndex = this.state.selectedIndex;
if (mentions && mentions[selectedIndex]) {
this.revealItem(mentions[selectedIndex].id);
}
// FIXME - a React version of this _may_ be required for Confluence
// integration tests. Will remove / fix once known
// emit(elem, mentionListRenderedEvent);
}
}, {
key: "revealItem",
value:
// Internal
function revealItem(key) {
var item = this.items[key];
if (item && this.scrollable) {
this.scrollable.reveal(item);
}
}
/**
* The default selection state is to chose index 0 and not have any particular key selected
*/
}, {
key: "setDefaultSelectionState",
value: function setDefaultSelectionState() {
this.state = {
selectedIndex: 0,
selectedKey: undefined
};
}
}, {
key: "renderItems",
value: function renderItems() {
var _this2 = this;
var mentions = this.props.mentions;
if (mentions && mentions.length) {
this.items = {};
return /*#__PURE__*/_react.default.createElement("div", null, this.props.initialHighlightElement, mentions.map(function (mention, idx) {
var key = mention.id;
var item = /*#__PURE__*/_react.default.createElement(_MentionItem.default, {
mention: mention,
selected: _this2.isSelectedMention(mention, idx),
key: key,
onMouseMove: _this2.selectIndexOnHover
/* Cannot use onclick, as onblur will close the element, and prevent
* onClick from firing.
*/,
onSelection: _this2.itemSelected,
ref: function ref(_ref) {
if (_ref) {
_this2.items[key] = _ref;
} else {
delete _this2.items[key];
}
}
});
return item;
}));
}
return null;
}
}, {
key: "isSelectedMention",
value: function isSelectedMention(mention, index) {
var selectedKey = this.state.selectedKey;
return selectedKey ? selectedKey === mention.id : index === 0;
}
}, {
key: "render",
value: function render() {
var _this$props2 = this.props,
mentions = _this$props2.mentions,
resourceError = _this$props2.resourceError;
var hasMentions = mentions && mentions.length;
// If we get an error, but existing mentions are displayed, lets
// just continue to show the existing mentions we have
var mustShowError = resourceError && !hasMentions;
var errorSection;
var resultSection;
if (mustShowError) {
errorSection = /*#__PURE__*/_react.default.createElement(_MentionListError.default, {
error: resourceError
});
} else if (hasMentions) {
resultSection = /*#__PURE__*/_react.default.createElement(_Scrollable.default, {
ref: this.handleScrollableRef
}, this.renderItems());
}
return /*#__PURE__*/_react.default.createElement(_MessagesIntlProvider.default, null, /*#__PURE__*/_react.default.createElement(_styles.MentionListStyle, {
empty: !hasMentions && !resourceError
}, errorSection, resultSection));
}
}]);
}(_react.default.PureComponent);