UNPKG

choerodon-ui

Version:

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

470 lines (376 loc) 16.9 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _objectSpread3 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _propTypes = _interopRequireDefault(require("prop-types")); var _DraftOffsetKey = require("draft-js/lib/DraftOffsetKey"); var _classnames = _interopRequireDefault(require("classnames")); var _domScrollIntoView = _interopRequireDefault(require("dom-scroll-into-view")); var _animate = _interopRequireDefault(require("../../../animate")); var _Nav = _interopRequireDefault(require("./Nav.react")); var _SuggestionWrapper = _interopRequireDefault(require("./SuggestionWrapper.react")); var _insertMention = _interopRequireDefault(require("../utils/insertMention")); var _clearMention = _interopRequireDefault(require("../utils/clearMention")); var _getOffset = _interopRequireDefault(require("../utils/getOffset")); var _getMentions = _interopRequireDefault(require("../utils/getMentions")); var _getSearchWord2 = _interopRequireDefault(require("../utils/getSearchWord")); function _createSuper(Derived) { function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } return function () { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (isNativeReflectConstruct()) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; } var isNotFalse = function isNotFalse(i) { return i !== false; }; var Suggestions = /*#__PURE__*/ function (_Component) { (0, _inherits2["default"])(Suggestions, _Component); var _super = _createSuper(Suggestions); function Suggestions(props) { var _this; (0, _classCallCheck2["default"])(this, Suggestions); _this = _super.call(this, props); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onEditorStateChange", function (editorState) { var offset = _this.props.store.getOffset(); if (offset.size === 0) { _this.closeDropDown(); return editorState; } var selection = editorState.getSelection(); // 修复: 焦点移出再移入时, dropdown 会闪动一下 // 原因: https://github.com/facebook/draft-js/blob/67c5e69499e3b0c149ce83b004872afdf4180463/src/component/handlers/edit/editOnFocus.js#L33 // 此处强制 update 了一下,因此 onEditorStateChange 会 call 两次 if (!_this.props.callbacks.getEditorState().getSelection().getHasFocus() && selection.getHasFocus()) { return editorState; } var _getSearchWord = (0, _getSearchWord2["default"])(editorState, selection), word = _getSearchWord.word; if (!word) { _this.closeDropDown(); return editorState; } var selectionInsideMention = offset.map(function (_ref) { var offsetKey = _ref.offsetKey; var _decode = (0, _DraftOffsetKey.decode)(offsetKey), blockKey = _decode.blockKey, decoratorKey = _decode.decoratorKey, leafKey = _decode.leafKey; if (blockKey !== selection.anchorKey) { return false; } var leaf = editorState.getBlockTree(blockKey).getIn([decoratorKey, 'leaves', leafKey]); if (!leaf) { return false; } var startKey = leaf.get('start'); var endKey = leaf.get('end'); // 处理只有一个 `@` 符号时的情况 if (!word) { return false; } if (startKey === endKey - 1) { return selection.anchorOffset >= startKey + 1 && selection.anchorOffset <= endKey ? offsetKey : false; } return selection.anchorOffset > startKey + 1 && selection.anchorOffset <= endKey ? offsetKey : false; }); var selectionInText = selectionInsideMention.some(isNotFalse); _this.activeOffsetKey = selectionInsideMention.find(isNotFalse); var trigger = _this.props.store.getTrigger(_this.activeOffsetKey); if (!selectionInText || !selection.getHasFocus()) { _this.closeDropDown(); return editorState; } var searchValue = word.substring(trigger.length, word.length); if (_this.lastSearchValue !== searchValue || _this.lastTrigger !== trigger) { _this.lastSearchValue = searchValue; _this.lastTrigger = trigger; _this.props.onSearchChange(searchValue, trigger); } if (!_this.state.active) { // 暂时没有更优雅的方法 if (!trigger || word.indexOf(trigger) !== -1) { _this.openDropDown(); } } return editorState; }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onUpArrow", function (ev) { ev.preventDefault(); if (_this.props.suggestions.length > 0) { var newIndex = _this.state.focusedIndex - 1; _this.setState({ focusedIndex: Math.max(newIndex, 0) }); } }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onBlur", function (ev) { ev.preventDefault(); _this.closeDropDown(); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onDownArrow", function (ev) { ev.preventDefault(); var newIndex = _this.state.focusedIndex + 1; _this.setState({ focusedIndex: newIndex >= _this.props.suggestions.length ? 0 : newIndex }); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getContainer", function () { var popupContainer = document.createElement('div'); var mountNode; if (_this.props.getSuggestionContainer) { mountNode = _this.props.getSuggestionContainer(); popupContainer.style.position = 'relative'; } else { mountNode = document.body; } mountNode.appendChild(popupContainer); return popupContainer; }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "handleKeyBinding", function (command) { return command === 'split-block'; }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "handleReturn", function (ev) { ev.preventDefault(); var selectedSuggestion = _this.props.suggestions[_this.state.focusedIndex]; if (selectedSuggestion) { if ((0, _react.isValidElement)(selectedSuggestion)) { _this.onMentionSelect(selectedSuggestion.props.value, selectedSuggestion.props.data); } else { _this.onMentionSelect(selectedSuggestion); } _this.lastSearchValue = null; _this.lastTrigger = null; return true; } return false; }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "renderReady", function () { var container = _this.dropdownContainer; if (!container) { return; } var active = _this.state.active; var _assertThisInitialize = (0, _assertThisInitialized2["default"])(_this), activeOffsetKey = _assertThisInitialize.activeOffsetKey; var offset = _this.props.store.getOffset(); var dropDownPosition = offset.get(activeOffsetKey); if (active && dropDownPosition) { var placement = _this.props.placement; var dropDownStyle = _this.getPositionStyle(true, dropDownPosition.position()); // Check if the above space is crowded var isTopCrowded = parseFloat(dropDownStyle.top) - window.scrollY - container.offsetHeight < 0; // Check if the under space is crowded var isBottomCrowded = (window.innerHeight || document.documentElement.clientHeight) - (parseFloat(dropDownStyle.top) - window.scrollY) - container.offsetHeight < 0; if (placement === 'top' && !isTopCrowded) { // The above space isn't crowded dropDownStyle.top = "".concat(parseFloat(dropDownStyle.top) - container.offsetHeight || 0, "px"); } if (placement === 'bottom' && isBottomCrowded && !isTopCrowded) { // The above space isn't crowded and the under space is crowded. dropDownStyle.top = "".concat(parseFloat(dropDownStyle.top) - container.offsetHeight || 0, "px"); } Object.keys(dropDownStyle).forEach(function (key) { container.style[key] = dropDownStyle[key]; }); } if (!_this.focusItem) { return; } (0, _domScrollIntoView["default"])(_reactDom["default"].findDOMNode(_this.focusItem), container, { onlyScrollIfNeeded: true }); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getNavigations", function () { var _this$props = _this.props, prefixCls = _this$props.prefixCls, suggestions = _this$props.suggestions; var focusedIndex = _this.state.focusedIndex; return suggestions.length ? _react.Children.map(suggestions, function (element, index) { var focusItem = index === focusedIndex; var ref = focusItem ? function (node) { _this.focusItem = node; } : null; var mentionClass = (0, _classnames["default"])("".concat(prefixCls, "-dropdown-item"), { focus: focusItem }); if ((0, _react.isValidElement)(element)) { return (0, _react.cloneElement)(element, { className: mentionClass, onMouseDown: function onMouseDown() { return _this.onMentionSelect(element.props.value, element.props.data); }, ref: ref }); } return _react["default"].createElement(_Nav["default"], { ref: ref, className: mentionClass, onMouseDown: function onMouseDown() { return _this.onMentionSelect(element); } }, element); }, (0, _assertThisInitialized2["default"])(_this)) : _react["default"].createElement("div", { className: "".concat(prefixCls, "-dropdown-notfound ").concat(prefixCls, "-dropdown-item") }, _this.props.notFoundContent); }); _this.state = { isActive: false, focusedIndex: 0, container: false }; return _this; } (0, _createClass2["default"])(Suggestions, [{ key: "componentDidMount", value: function componentDidMount() { this.props.callbacks.onChange = this.onEditorStateChange; } }, { key: "componentWillReceiveProps", value: function componentWillReceiveProps(nextProps) { if (nextProps.suggestions.length !== this.props.suggestions.length) { this.setState({ focusedIndex: 0 }); } } }, { key: "onMentionSelect", value: function onMentionSelect(mention, data) { var editorState = this.props.callbacks.getEditorState(); var _this$props2 = this.props, store = _this$props2.store, onSelect = _this$props2.onSelect; var trigger = store.getTrigger(this.activeOffsetKey); if (onSelect) { onSelect(mention, data || mention); } if (this.props.noRedup) { var mentions = (0, _getMentions["default"])(editorState.getCurrentContent(), trigger); if (mentions.indexOf("".concat(trigger).concat(mention)) !== -1) { // eslint-disable-next-line console.warn('you have specified `noRedup` props but have duplicated mentions.'); this.closeDropDown(); this.props.callbacks.setEditorState((0, _clearMention["default"])(editorState)); return; } } this.props.callbacks.setEditorState((0, _insertMention["default"])(editorState, "".concat(trigger).concat(mention), data, this.props.mode), true); this.closeDropDown(); } }, { key: "getPositionStyle", value: function getPositionStyle(isActive, position) { if (this.props.getSuggestionStyle) { return this.props.getSuggestionStyle(isActive, position); } var container = this.props.getSuggestionContainer ? this.state.container : document.body; var offset = (0, _getOffset["default"])(container); return position ? (0, _objectSpread3["default"])({ position: 'absolute', left: "".concat(position.left - offset.left, "px"), top: "".concat(position.top - offset.top, "px") }, this.props.style) : {}; } }, { key: "openDropDown", value: function openDropDown() { this.props.callbacks.onUpArrow = this.onUpArrow; this.props.callbacks.handleReturn = this.handleReturn; this.props.callbacks.handleKeyBinding = this.handleKeyBinding; this.props.callbacks.onDownArrow = this.onDownArrow; this.props.callbacks.onBlur = this.onBlur; this.setState({ active: true, container: this.state.container || this.getContainer() }); } }, { key: "closeDropDown", value: function closeDropDown() { this.props.callbacks.onUpArrow = null; this.props.callbacks.handleReturn = null; this.props.callbacks.handleKeyBinding = null; this.props.callbacks.onDownArrow = null; this.props.callbacks.onBlur = null; this.setState({ active: false }); } }, { key: "render", value: function render() { var _objectSpread2, _this2 = this; var _this$props3 = this.props, prefixCls = _this$props3.prefixCls, className = _this$props3.className, placement = _this$props3.placement; var _this$state = this.state, container = _this$state.container, active = _this$state.active; var cls = (0, _classnames["default"])((0, _objectSpread3["default"])((_objectSpread2 = {}, (0, _defineProperty2["default"])(_objectSpread2, "".concat(prefixCls, "-dropdown"), true), (0, _defineProperty2["default"])(_objectSpread2, "".concat(prefixCls, "-dropdown-placement-").concat(placement), true), _objectSpread2), className)); var transitionName = placement === 'top' ? 'slide-down' : 'slide-up'; var navigations = this.getNavigations(); return container ? _react["default"].createElement(_SuggestionWrapper["default"], { renderReady: this.renderReady, container: container }, _react["default"].createElement(_animate["default"], { transitionName: transitionName }, active ? _react["default"].createElement("div", { className: cls, ref: function ref(node) { _this2.dropdownContainer = node; } }, navigations) : null)) : null; } }]); return Suggestions; }(_react.Component); exports["default"] = Suggestions; (0, _defineProperty2["default"])(Suggestions, "propTypes", { callbacks: _propTypes["default"].object, suggestions: _propTypes["default"].array, store: _propTypes["default"].object, onSearchChange: _propTypes["default"].func, prefixCls: _propTypes["default"].string, mode: _propTypes["default"].string, style: _propTypes["default"].object, onSelect: _propTypes["default"].func, getSuggestionContainer: _propTypes["default"].func, notFoundContent: _propTypes["default"].any, getSuggestionStyle: _propTypes["default"].func, className: _propTypes["default"].string, noRedup: _propTypes["default"].bool, placement: _propTypes["default"].string }); //# sourceMappingURL=Suggestions.react.js.map