UNPKG

choerodon-ui

Version:

An enterprise-class UI design language and React-based implementation

458 lines (390 loc) 15.2 kB
import _objectSpread from "@babel/runtime/helpers/objectSpread2"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _get from "@babel/runtime/helpers/get"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/inherits"; import _createSuper from "@babel/runtime/helpers/createSuper"; import { __decorate } from "tslib"; import React from 'react'; import { observer } from 'mobx-react'; import { action, observable, runInAction } from 'mobx'; import isNil from 'lodash/isNil'; import Spin from '../../../es/spin'; import KeyCode from '../../../es/_util/KeyCode'; import { FieldTrim } from '../data-set/enum'; import TextArea from '../text-area'; import autobind from '../_util/autobind'; import KeywordTrigger from './KeywordTrigger'; import { MentionsContextProvider } from './MentionsContext'; import Option from './Option'; import { filterOption as defaultFilterOption, getBeforeSelectionText, getLastMeasureIndex, replaceWithMeasure, setInputSelection, validateSearch as defaultValidateSearch, toArray } from './utils'; var Mentions = /*#__PURE__*/function (_TextArea) { _inherits(Mentions, _TextArea); var _super = _createSuper(Mentions); function Mentions(props, context) { var _this; _classCallCheck(this, Mentions); _this = _super.call(this, props, context); _this.focusId = undefined; _this.selectionLocation = -1; _this.initObservableObj(); return _this; } _createClass(Mentions, [{ key: "initObservableObj", value: function initObservableObj() { this.measuring = false; this.measureLocation = 0; this.measureText = null; this.measurePrefix = ''; this.activeIndex = 0; } }, { key: "componentDidUpdate", value: function componentDidUpdate() { // Sync measure div top with textarea for trigger usage if (this.measuring && this.measure && this.element) { this.measure.scrollTop = this.element.scrollTop; } // 选择选项后设置输入框光标位置 if (this.selectionLocation !== -1 && this.element) { setInputSelection(this.element, this.selectionLocation); this.selectionLocation = -1; } } }, { key: "getNotFoundContent", value: function getNotFoundContent() { if ('notFoundContent' in this.props) { return this.props.notFoundContent; } return this.getContextConfig('renderEmpty')('Select'); } }, { key: "getOtherProps", value: function getOtherProps() { var otherProps = _get(_getPrototypeOf(Mentions.prototype), "getOtherProps", this).call(this); otherProps.onKeyUp = this.handleKeyUp; return otherProps; } }, { key: "getOmitPropsKeys", value: function getOmitPropsKeys() { return _get(_getPrototypeOf(Mentions.prototype), "getOmitPropsKeys", this).call(this).concat(['notFoundContent', 'split', 'transitionName', 'placement', 'prefix', 'validateSearch', 'filterOption', 'onSelect', 'onSearch', 'getPopupContainer', 'loading', 'mentionsKey']); } }, { key: "select", value: function select() {// noop } // Check if hit the measure keyword }, { key: "handleKeyDown", value: function handleKeyDown(event) { var _this2 = this; var which = event.which; var activeIndex = this.activeIndex, measuring = this.measuring; // Skip if not measuring if (!measuring) { _get(_getPrototypeOf(Mentions.prototype), "handleKeyDown", this).call(this, event); return; } if (which === KeyCode.UP || which === KeyCode.DOWN) { // Control arrow function var optionLen = this.getOptions().length; var offset = which === KeyCode.UP ? -1 : 1; var newActiveIndex = (activeIndex + offset + optionLen) % optionLen; runInAction(function () { _this2.activeIndex = newActiveIndex; }); event.preventDefault(); } else if (which === KeyCode.ESC) { this.stopMeasure(); } else if (which === KeyCode.ENTER) { // Measure hit event.preventDefault(); var options = this.getOptions(); if (!options.length) { this.stopMeasure(); _get(_getPrototypeOf(Mentions.prototype), "handleKeyDown", this).call(this, event); return; } var option = options[activeIndex]; this.selectOption(option); } _get(_getPrototypeOf(Mentions.prototype), "handleKeyDown", this).call(this, event); } /** * When to start measure: * 1. When user press `mentionsKey` * 2. When measureText !== prevMeasureText * - If measure hit * - If measuring * * When to stop measure: * 1. Selection is out of range * 2. Contains `space` * 3. ESC or select one */ }, { key: "handleKeyUp", value: function handleKeyUp(event) { var key = event.key, which = event.which; var prevMeasureText = this.measureText, measuring = this.measuring; var _this$props = this.props, _this$props$mentionsK = _this$props.mentionsKey, mentionsKey = _this$props$mentionsK === void 0 ? '' : _this$props$mentionsK, clientOnKeyUp = _this$props.onKeyUp, onSearch = _this$props.onSearch, validateSearch = _this$props.validateSearch; var target = event.target; var selectionStartText = getBeforeSelectionText(target); var _getLastMeasureIndex = getLastMeasureIndex(selectionStartText, mentionsKey), measureIndex = _getLastMeasureIndex.location, measurePrefix = _getLastMeasureIndex.mentionsKey; // If the client implements an onKeyUp handler, call it if (clientOnKeyUp) { clientOnKeyUp(event); } // Skip if match the white key list if ([KeyCode.ESC, KeyCode.UP, KeyCode.DOWN, KeyCode.ENTER].indexOf(which) !== -1) { return; } if (measureIndex !== -1) { var measureText = selectionStartText.slice(measureIndex + measurePrefix.length); var validateMeasure = validateSearch ? validateSearch(measureText, this.props) : false; var matchOption = !!this.getOptions(measureText).length; if (validateMeasure) { if (key === measurePrefix || key === 'Shift' || measuring || measureText !== prevMeasureText && matchOption) { this.startMeasure(measureText, measurePrefix, measureIndex); } } else if (measuring) { // Stop if measureText is invalidate this.stopMeasure(); } /** * We will trigger `onSearch` to developer since they may use for async update. * If met `space` means user finished searching. */ if (onSearch && validateMeasure) { onSearch(measureText, measurePrefix); } } else if (measuring) { this.stopMeasure(); } } }, { key: "onDropdownFocus", value: function onDropdownFocus() { this.handleFocus(); } }, { key: "onDropdownBlur", value: function onDropdownBlur() { this.handleBlur(); } }, { key: "handleFocus", value: function handleFocus(event) { window.clearTimeout(this.focusId); if (event) { _get(_getPrototypeOf(Mentions.prototype), "handleFocus", this).call(this, event); } } }, { key: "handleBlur", value: function handleBlur(event) { var _this3 = this; this.focusId = window.setTimeout(function () { _this3.stopMeasure(); }, 0); if (event) { _get(_getPrototypeOf(Mentions.prototype), "handleBlur", this).call(this, event); } } }, { key: "selectOption", value: function selectOption(option) { var measureLocation = this.measureLocation, measurePrefix = this.measurePrefix; var value = isNil(this.text) ? this.getValue() : this.text; value = isNil(value) ? '' : value; var _this$props2 = this.props, split = _this$props2.split, onSelect = _this$props2.onSelect; var _option$value = option.value, mentionValue = _option$value === void 0 ? '' : _option$value; var _replaceWithMeasure = replaceWithMeasure(value, { measureLocation: measureLocation, targetText: mentionValue, mentionsKey: measurePrefix, selectionStart: this.element ? this.element.selectionStart : -1, split: String(split || '') }), text = _replaceWithMeasure.text, selectionLocation = _replaceWithMeasure.selectionLocation; this.selectionLocation = selectionLocation; this.prepareSetValue(text); this.stopMeasure(); if (onSelect) { onSelect(option, measurePrefix); } } }, { key: "setActiveIndex", value: function setActiveIndex(activeIndex) { this.activeIndex = activeIndex; } }, { key: "setMeasureRef", value: function setMeasureRef(element) { this.measure = element; } }, { key: "getOptions", value: function getOptions(measureText) { var targetMeasureText = measureText || this.measureText || ''; var _this$props3 = this.props, children = _this$props3.children, filterOption = _this$props3.filterOption, loading = _this$props3.loading; if (loading) { return [{ key: 'loading', children: /*#__PURE__*/React.createElement(Spin, null), disabled: true, style: { minWidth: '0.8rem', display: 'flex', justifyContent: 'center' } }]; } var list = toArray(children).map(function (_ref) { var props = _ref.props, key = _ref.key; return _objectSpread(_objectSpread({}, props), {}, { key: key || props.value }); }).filter(function (option) { /** Return all result if `filterOption` is false. */ if (filterOption === false) { return true; } return filterOption ? filterOption(targetMeasureText, option) : true; }); return list; } }, { key: "startMeasure", value: function startMeasure(measureText, measurePrefix, measureLocation) { this.measuring = true; this.measureText = measureText; this.measurePrefix = measurePrefix; this.measureLocation = measureLocation; this.activeIndex = 0; } }, { key: "stopMeasure", value: function stopMeasure() { this.measuring = false; this.measureLocation = 0; this.measureText = null; } }, { key: "wrapperInputNode", value: function wrapperInputNode() { var measureLocation = this.measureLocation, measurePrefix = this.measurePrefix, measuring = this.measuring, activeIndex = this.activeIndex, prefixCls = this.prefixCls; var value = isNil(this.text) ? this.getValue() : this.text; var _this$props4 = this.props, placement = _this$props4.placement, transitionName = _this$props4.transitionName, getPopupContainer = _this$props4.getPopupContainer; var options = measuring ? this.getOptions() : []; return /*#__PURE__*/React.createElement(React.Fragment, null, _get(_getPrototypeOf(Mentions.prototype), "wrapperInputNode", this).call(this), measuring && /*#__PURE__*/React.createElement("div", { ref: this.setMeasureRef, className: "".concat(prefixCls, "-measure") }, value.slice(0, measureLocation), /*#__PURE__*/React.createElement(MentionsContextProvider, { value: { notFoundContent: this.getNotFoundContent(), activeIndex: activeIndex, setActiveIndex: this.setActiveIndex, selectOption: this.selectOption, onFocus: this.onDropdownFocus, onBlur: this.onDropdownBlur } }, /*#__PURE__*/React.createElement(KeywordTrigger, { prefixCls: prefixCls, transitionName: transitionName, placement: placement, options: options, visible: true, getPopupContainer: getPopupContainer }, /*#__PURE__*/React.createElement("span", null, measurePrefix))), value.slice(measureLocation + measurePrefix.length))); } }]); return Mentions; }(TextArea); Mentions.displayName = 'Mentions'; Mentions.Option = Option; Mentions.defaultProps = _objectSpread(_objectSpread({}, TextArea.defaultProps), {}, { suffixCls: 'mentions', rows: 1, trim: FieldTrim.left, mentionsKey: '@', split: ' ', validateSearch: defaultValidateSearch, filterOption: defaultFilterOption }); __decorate([observable], Mentions.prototype, "measuring", void 0); __decorate([observable], Mentions.prototype, "measureText", void 0); __decorate([observable], Mentions.prototype, "measurePrefix", void 0); __decorate([observable], Mentions.prototype, "measureLocation", void 0); __decorate([observable], Mentions.prototype, "activeIndex", void 0); __decorate([action], Mentions.prototype, "initObservableObj", null); __decorate([autobind], Mentions.prototype, "handleKeyDown", null); __decorate([autobind], Mentions.prototype, "handleKeyUp", null); __decorate([autobind], Mentions.prototype, "onDropdownFocus", null); __decorate([autobind], Mentions.prototype, "onDropdownBlur", null); __decorate([autobind], Mentions.prototype, "handleFocus", null); __decorate([autobind], Mentions.prototype, "handleBlur", null); __decorate([autobind], Mentions.prototype, "selectOption", null); __decorate([autobind, action], Mentions.prototype, "setActiveIndex", null); __decorate([autobind], Mentions.prototype, "setMeasureRef", null); __decorate([action], Mentions.prototype, "startMeasure", null); __decorate([action], Mentions.prototype, "stopMeasure", null); Mentions = __decorate([observer], Mentions); Mentions.getMentions = function () { var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var _config$mentionsKey = config.mentionsKey, mentionsKey = _config$mentionsKey === void 0 ? '@' : _config$mentionsKey, _config$split = config.split, split = _config$split === void 0 ? ' ' : _config$split; var prefixList = Array.isArray(mentionsKey) ? mentionsKey : [mentionsKey]; return value.split(split).map(function () { var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var hitPrefix = null; prefixList.some(function (prefixStr) { var startStr = str.slice(0, prefixStr.length); if (startStr === prefixStr) { hitPrefix = prefixStr; return true; } return false; }); if (hitPrefix !== null) { return { mentionsKey: hitPrefix, value: str.slice(hitPrefix.length) }; } return null; }).filter(function (entity) { return !!entity && !!entity.value; }); }; export default Mentions; //# sourceMappingURL=Mentions.js.map