UNPKG

zent

Version:

一套前端设计语言和基于React的实现

216 lines (215 loc) 10.2 kB
import { __assign, __extends, __rest } from "tslib"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { Component } from 'react'; import { findDOMNode } from 'react-dom'; import cx from 'classnames'; import isEqual from '../utils/isEqual'; import Input from '../input'; import Popover from '../popover'; import getCaretCoordinates from '../utils/dom/getCaretCoordinates'; import isFirefox from '../utils/isFirefox'; import SelectMenu from '../select-menu'; import { I18nReceiver as Receiver } from '../i18n'; import { findMentionAtCaretPosition } from './findMentionAtCaretPosition'; import * as SelectionChangeEventHub from './SelectionChangeEventHub'; import * as Utils from './utils'; import { getPopoverBottomPosition, getPopoverTopPosition } from './position'; import { MENTION_FOUND } from './constants'; import defer from '../utils/defer'; import { runOnceInNextFrame } from '../utils/nextFrame'; var NAV_KEYS = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight']; var DEFAULT_STATE = { suggestionVisible: false, search: null, }; var Mention = (function (_super) { __extends(Mention, _super); function Mention() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.input = null; _this.suggestionList = null; _this.state = __assign(__assign({}, DEFAULT_STATE), { position: undefined, placeholder: null }); _this.BottomPosition = getPopoverBottomPosition(_this); _this.TopPosition = getPopoverTopPosition(_this); _this.onSuggestionVisibleChange = function (visible) { if (!visible) { _this.setStateIfChange(_this.getDefaultState()); } }; _this.onCloseMenuList = function () { _this.onSuggestionVisibleChange(false); }; _this.onSelectSuggestion = function (val) { _this.onCloseMenuList(); var _a = _this.props, value = _a.value, onChange = _a.onChange; var placeholder = _this.state.placeholder; var newValue = Utils.replaceSubstring(value, placeholder.start, placeholder.end, val); onChange(newValue.value); defer(function () { if (_this.input) { _this.input.setSelectionRange(newValue.caret, newValue.caret); _this.input.blur(); _this.input.focus(); } }); }; _this.onInputChange = function (evt) { _this.props.onChange(evt.target.value); }; _this.onInputScroll = runOnceInNextFrame(function () { if (_this.state.suggestionVisible) { _this.setSuggestionVisible(); } }); _this.onInputCompositionStart = function () { _this._compositing = true; }; _this.onInputCompositionEnd = function () { _this._compositing = false; }; _this.onInputBlur = function (evt) { if (!_this.state.suggestionVisible) { _this.setStateIfChange(_this.getDefaultState()); } _this.triggerEventCallback('onBlur', evt); }; _this.onInputKeyUp = function (evt) { if (isFirefox && (evt.altKey || evt.ctrlKey || evt.metaKey || NAV_KEYS.indexOf(evt.key) !== -1)) { defer(_this.setSuggestionVisible, _this.props.value); } _this.triggerEventCallback('onKeyUp', evt); }; _this.onInputKeyDown = function (evt) { if (_this.state.suggestionVisible && _this.suggestionList) { var key = evt.key; if (key === 'ArrowUp') { _this.suggestionList.moveFocusIndexUp(); evt.preventDefault(); } else if (key === 'ArrowDown') { _this.suggestionList.moveFocusIndexDown(); evt.preventDefault(); } else if (key === 'Enter') { _this.suggestionList.selectCurrentFocusIndex(evt); evt.preventDefault(); } else if (key === 'Escape') { _this.setStateIfChange(_this.getDefaultState()); } } _this.triggerEventCallback('onKeyDown', evt); }; _this.onSelectionChange = function () { _this.setSuggestionVisible(_this.props.value); }; _this.saveInputRef = function (instance) { if (_this.input) { SelectionChangeEventHub.uninstall({ node: _this.input, callback: _this.onSelectionChange, }); } if (!instance) { return; } var inputNode = Utils.getInputNodeForTrigger(findDOMNode(instance)); _this.input = inputNode; if (_this.input) { SelectionChangeEventHub.install({ node: _this.input, callback: _this.onSelectionChange, }); } }; _this.onSuggestionListRefChange = function (instance) { _this.suggestionList = instance; }; _this.setSuggestionVisible = function (value) { if (!_this.input || _this._compositing) { return; } value = value !== undefined ? value : _this.props.value; var triggerText = _this.props.triggerText; var mention = findMentionAtCaretPosition({ input: _this.input, value: value, triggerText: triggerText, }); var newState = _this.getDefaultState(); if (mention.code === MENTION_FOUND) { newState.suggestionVisible = true; newState.search = Utils.substring(value, mention.searchStart, mention.searchEnd + 1); newState.position = _this.getCaretCoordinates(mention.caretMeasureStart); newState.placeholder = { start: mention.placeholderStart, end: mention.placeholderEnd, }; } _this.setStateIfChange(newState); }; return _this; } Mention.prototype.render = function () { var _this = this; var _a = this.props, multiLine = _a.multiLine, position = _a.position, suggestions = _a.suggestions, onSearchChange = _a.onSearchChange, suggestionNotFoundContent = _a.suggestionNotFoundContent, loading = _a.loading, triggerText = _a.triggerText, onChange = _a.onChange, onBlur = _a.onBlur, onKeyUp = _a.onKeyUp, onKeyDown = _a.onKeyDown, type = _a.type, className = _a.className, inline = _a.inline, passThroughProps = __rest(_a, ["multiLine", "position", "suggestions", "onSearchChange", "suggestionNotFoundContent", "loading", "triggerText", "onChange", "onBlur", "onKeyUp", "onKeyDown", "type", "className", "inline"]); var inputType = multiLine ? 'textarea' : 'text'; var suggestionVisible = this.state.suggestionVisible; return (_jsx(Receiver, __assign({ componentName: "Mention" }, { children: function (i18n) { return (_jsxs(Popover, __assign({ visible: suggestionVisible, onVisibleChange: _this.onSuggestionVisibleChange, position: position === 'bottom' ? _this.BottomPosition : _this.TopPosition }, { children: [_jsx(Popover.Trigger.Click, __assign({ getElement: Utils.getInputNodeForTrigger }, { children: _jsx(Input, __assign({ type: inputType, ref: _this.saveInputRef, className: cx('zent-mention', className), onChange: _this.onInputChange, onBlur: _this.onInputBlur, onKeyUp: _this.onInputKeyUp, onKeyDown: _this.onInputKeyDown, onScroll: _this.onInputScroll, onWheel: _this.onInputScroll, onCompositionStart: _this.onInputCompositionStart, onCompositionEnd: _this.onInputCompositionEnd, inline: inline }, passThroughProps), void 0) }), void 0), _jsx(Popover.Content, { children: _jsx(SelectMenu, { ref: _this.onSuggestionListRefChange, items: Utils.getMenuListItems(suggestions, i18n.noContent), onRequestClose: _this.onCloseMenuList, onSelect: _this.onSelectSuggestion }, void 0) }, void 0)] }), void 0)); } }), void 0)); }; Mention.prototype.componentDidUpdate = function (prevProps) { if (prevProps.value !== this.props.value) { this.setSuggestionVisible(this.props.value); } }; Mention.prototype.componentDidMount = function () { this.setSuggestionVisible(this.props.value); }; Mention.prototype.triggerEventCallback = function (eventName, evt) { var fn = this.props[eventName]; if (typeof fn === 'function') { fn(evt); } }; Mention.prototype.setStateIfChange = function (state) { var isSearchChanged = state.search !== this.state.search; if (!isEqual(this.state, state)) { var onSearchChange = this.props.onSearchChange; if (isSearchChanged && typeof onSearchChange === 'function') { onSearchChange(state.search); } this.setState(state); } }; Mention.prototype.getCaretCoordinates = function (start) { var position = getCaretCoordinates(this.input, start, { debug: false }); var _a = this.input, scrollLeft = _a.scrollLeft, scrollTop = _a.scrollTop; if (scrollLeft) { position.left = position.left - scrollLeft; } if (scrollTop) { position.top = position.top - scrollTop; } return position; }; Mention.prototype.getDefaultState = function () { return __assign(__assign({}, this.state), DEFAULT_STATE); }; Mention.defaultProps = { multiLine: false, position: 'bottom', suggestionNotFoundContent: '', suggestions: [], triggerText: '@', inline: true, }; return Mention; }(Component)); export { Mention }; export default Mention;