UNPKG

@gzued/antd-compiled

Version:

Pre-bundled Ant Design 4.x and related dependencies for @gzued packages

359 lines 14.9 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; var _excluded = ["prefixCls", "className", "style", "prefix", "split", "notFoundContent", "value", "defaultValue", "children", "options", "open", "validateSearch", "filterOption", "onChange", "onKeyDown", "onKeyUp", "onPressEnter", "onSearch", "onSelect", "onFocus", "onBlur", "transitionName", "placement", "direction", "getPopupContainer", "dropdownClassName"]; import classNames from 'classnames'; import useMergedState from "rc-util/es/hooks/useMergedState"; import toArray from "rc-util/es/Children/toArray"; import KeyCode from "rc-util/es/KeyCode"; import warning from "rc-util/es/warning"; import React, { useEffect, useRef, useState } from 'react'; import TextArea from 'rc-textarea'; import KeywordTrigger from './KeywordTrigger'; import MentionsContext from './MentionsContext'; import Option from './Option'; import { filterOption as defaultFilterOption, getBeforeSelectionText, getLastMeasureIndex, replaceWithMeasure, setInputSelection, validateSearch as defaultValidateSearch } from './util'; import useEffectState from './hooks/useEffectState'; var Mentions = /*#__PURE__*/React.forwardRef(function (props, ref) { var prefixCls = props.prefixCls, className = props.className, style = props.style, prefix = props.prefix, split = props.split, notFoundContent = props.notFoundContent, value = props.value, defaultValue = props.defaultValue, children = props.children, options = props.options, open = props.open, validateSearch = props.validateSearch, filterOption = props.filterOption, onChange = props.onChange, onKeyDown = props.onKeyDown, onKeyUp = props.onKeyUp, onPressEnter = props.onPressEnter, onSearch = props.onSearch, onSelect = props.onSelect, onFocus = props.onFocus, onBlur = props.onBlur, transitionName = props.transitionName, placement = props.placement, direction = props.direction, getPopupContainer = props.getPopupContainer, dropdownClassName = props.dropdownClassName, restProps = _objectWithoutProperties(props, _excluded); var mergedPrefix = Array.isArray(prefix) ? prefix : [prefix]; var mergedProps = _objectSpread(_objectSpread({}, props), {}, { prefix: mergedPrefix }); // =============================== Refs =============================== var textareaRef = useRef(null); var measureRef = useRef(null); var getTextArea = function getTextArea() { var _textareaRef$current, _textareaRef$current$; return (_textareaRef$current = textareaRef.current) === null || _textareaRef$current === void 0 ? void 0 : (_textareaRef$current$ = _textareaRef$current.resizableTextArea) === null || _textareaRef$current$ === void 0 ? void 0 : _textareaRef$current$.textArea; }; React.useImperativeHandle(ref, function () { var _textareaRef$current4, _textareaRef$current5; return { focus: function focus() { var _textareaRef$current2; return (_textareaRef$current2 = textareaRef.current) === null || _textareaRef$current2 === void 0 ? void 0 : _textareaRef$current2.focus(); }, blur: function blur() { var _textareaRef$current3; return (_textareaRef$current3 = textareaRef.current) === null || _textareaRef$current3 === void 0 ? void 0 : _textareaRef$current3.blur(); }, textarea: (_textareaRef$current4 = textareaRef.current) === null || _textareaRef$current4 === void 0 ? void 0 : (_textareaRef$current5 = _textareaRef$current4.resizableTextArea) === null || _textareaRef$current5 === void 0 ? void 0 : _textareaRef$current5.textArea }; }); // ============================== State =============================== var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), measuring = _useState2[0], setMeasuring = _useState2[1]; var _useState3 = useState(''), _useState4 = _slicedToArray(_useState3, 2), measureText = _useState4[0], setMeasureText = _useState4[1]; var _useState5 = useState(''), _useState6 = _slicedToArray(_useState5, 2), measurePrefix = _useState6[0], setMeasurePrefix = _useState6[1]; var _useState7 = useState(0), _useState8 = _slicedToArray(_useState7, 2), measureLocation = _useState8[0], setMeasureLocation = _useState8[1]; var _useState9 = useState(0), _useState10 = _slicedToArray(_useState9, 2), activeIndex = _useState10[0], setActiveIndex = _useState10[1]; var _useState11 = useState(false), _useState12 = _slicedToArray(_useState11, 2), isFocus = _useState12[0], setIsFocus = _useState12[1]; // ============================== Value =============================== var _useMergedState = useMergedState('', { defaultValue: defaultValue, value: value }), _useMergedState2 = _slicedToArray(_useMergedState, 2), mergedValue = _useMergedState2[0], setMergedValue = _useMergedState2[1]; // =============================== Open =============================== useEffect(function () { // Sync measure div top with textarea for rc-trigger usage if (measuring && measureRef.current) { measureRef.current.scrollTop = getTextArea().scrollTop; } }, [measuring]); var _React$useMemo = React.useMemo(function () { if (open) { if (process.env.NODE_ENV !== 'production') { warning(false, '`open` of Mentions is only used for debug usage. Do not use in you production.'); } for (var i = 0; i < mergedPrefix.length; i += 1) { var curPrefix = mergedPrefix[i]; var index = mergedValue.lastIndexOf(curPrefix); if (index >= 0) { return [true, '', curPrefix, index]; } } } return [measuring, measureText, measurePrefix, measureLocation]; }, [open, measuring, mergedPrefix, mergedValue, measureText, measurePrefix, measureLocation]), _React$useMemo2 = _slicedToArray(_React$useMemo, 4), mergedMeasuring = _React$useMemo2[0], mergedMeasureText = _React$useMemo2[1], mergedMeasurePrefix = _React$useMemo2[2], mergedMeasureLocation = _React$useMemo2[3]; // ============================== Option ============================== var getOptions = React.useCallback(function (targetMeasureText) { var list; if (options && options.length > 0) { list = options.map(function (item) { var _item$key; return _objectSpread(_objectSpread({}, item), {}, { key: (_item$key = item === null || item === void 0 ? void 0 : item.key) !== null && _item$key !== void 0 ? _item$key : item.value }); }); } else { list = toArray(children).map(function (_ref) { var optionProps = _ref.props, key = _ref.key; return _objectSpread(_objectSpread({}, optionProps), {}, { label: optionProps.children, key: key || optionProps.value }); }); } return list.filter(function (option) { /** Return all result if `filterOption` is false. */ if (filterOption === false) { return true; } return filterOption(targetMeasureText, option); }); }, [children, options, filterOption]); var mergedOptions = React.useMemo(function () { return getOptions(mergedMeasureText); }, [getOptions, mergedMeasureText]); // ============================= Measure ============================== // Mark that we will reset input selection to target position when user select option var onSelectionEffect = useEffectState(); var startMeasure = function startMeasure(nextMeasureText, nextMeasurePrefix, nextMeasureLocation) { setMeasuring(true); setMeasureText(nextMeasureText); setMeasurePrefix(nextMeasurePrefix); setMeasureLocation(nextMeasureLocation); setActiveIndex(0); }; var stopMeasure = function stopMeasure(callback) { setMeasuring(false); setMeasureLocation(0); setMeasureText(''); onSelectionEffect(callback); }; // ============================== Change ============================== var triggerChange = function triggerChange(nextValue) { setMergedValue(nextValue); onChange === null || onChange === void 0 ? void 0 : onChange(nextValue); }; var onInternalChange = function onInternalChange(_ref2) { var nextValue = _ref2.target.value; triggerChange(nextValue); }; var selectOption = function selectOption(option) { var _getTextArea; var _option$value = option.value, mentionValue = _option$value === void 0 ? '' : _option$value; var _replaceWithMeasure = replaceWithMeasure(mergedValue, { measureLocation: mergedMeasureLocation, targetText: mentionValue, prefix: mergedMeasurePrefix, selectionStart: (_getTextArea = getTextArea()) === null || _getTextArea === void 0 ? void 0 : _getTextArea.selectionStart, split: split }), text = _replaceWithMeasure.text, selectionLocation = _replaceWithMeasure.selectionLocation; triggerChange(text); stopMeasure(function () { // We need restore the selection position setInputSelection(getTextArea(), selectionLocation); }); onSelect === null || onSelect === void 0 ? void 0 : onSelect(option, mergedMeasurePrefix); }; // ============================= KeyEvent ============================= // Check if hit the measure keyword var onInternalKeyDown = function onInternalKeyDown(event) { var which = event.which; onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event); // Skip if not measuring if (!mergedMeasuring) { return; } if (which === KeyCode.UP || which === KeyCode.DOWN) { // Control arrow function var optionLen = mergedOptions.length; var offset = which === KeyCode.UP ? -1 : 1; var newActiveIndex = (activeIndex + offset + optionLen) % optionLen; setActiveIndex(newActiveIndex); event.preventDefault(); } else if (which === KeyCode.ESC) { stopMeasure(); } else if (which === KeyCode.ENTER) { // Measure hit event.preventDefault(); if (!mergedOptions.length) { stopMeasure(); return; } var option = mergedOptions[activeIndex]; selectOption(option); } }; /** * When to start measure: * 1. When user press `prefix` * 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 */ var onInternalKeyUp = function onInternalKeyUp(event) { var key = event.key, which = event.which; var target = event.target; var selectionStartText = getBeforeSelectionText(target); var _getLastMeasureIndex = getLastMeasureIndex(selectionStartText, mergedPrefix), measureIndex = _getLastMeasureIndex.location, nextMeasurePrefix = _getLastMeasureIndex.prefix; // If the client implements an onKeyUp handler, call it onKeyUp === null || onKeyUp === void 0 ? void 0 : onKeyUp(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 nextMeasureText = selectionStartText.slice(measureIndex + nextMeasurePrefix.length); var validateMeasure = validateSearch(nextMeasureText, mergedProps); var matchOption = !!getOptions(nextMeasureText).length; if (validateMeasure) { if (key === nextMeasurePrefix || key === 'Shift' || mergedMeasuring || nextMeasureText !== mergedMeasureText && matchOption) { startMeasure(nextMeasureText, nextMeasurePrefix, measureIndex); } } else if (mergedMeasuring) { // Stop if measureText is invalidate 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(nextMeasureText, nextMeasurePrefix); } } else if (mergedMeasuring) { stopMeasure(); } }; var onInternalPressEnter = function onInternalPressEnter(event) { if (!mergedMeasuring && onPressEnter) { onPressEnter(event); } }; // ============================ Focus Blur ============================ var focusRef = useRef(); var onInternalFocus = function onInternalFocus(event) { window.clearTimeout(focusRef.current); if (!isFocus && event && onFocus) { onFocus(event); } setIsFocus(true); }; var onInternalBlur = function onInternalBlur(event) { focusRef.current = window.setTimeout(function () { setIsFocus(false); stopMeasure(); onBlur === null || onBlur === void 0 ? void 0 : onBlur(event); }, 0); }; var onDropdownFocus = function onDropdownFocus() { onInternalFocus(); }; var onDropdownBlur = function onDropdownBlur() { onInternalBlur(); }; // ============================== Render ============================== return /*#__PURE__*/React.createElement("div", { className: classNames(prefixCls, className), style: style }, /*#__PURE__*/React.createElement(TextArea, _extends({ ref: textareaRef, value: mergedValue }, restProps, { onChange: onInternalChange, onKeyDown: onInternalKeyDown, onKeyUp: onInternalKeyUp, onPressEnter: onInternalPressEnter, onFocus: onInternalFocus, onBlur: onInternalBlur })), mergedMeasuring && /*#__PURE__*/React.createElement("div", { ref: measureRef, className: "".concat(prefixCls, "-measure") }, mergedValue.slice(0, mergedMeasureLocation), /*#__PURE__*/React.createElement(MentionsContext.Provider, { value: { notFoundContent: notFoundContent, activeIndex: activeIndex, setActiveIndex: setActiveIndex, selectOption: selectOption, onFocus: onDropdownFocus, onBlur: onDropdownBlur } }, /*#__PURE__*/React.createElement(KeywordTrigger, { prefixCls: prefixCls, transitionName: transitionName, placement: placement, direction: direction, options: mergedOptions, visible: true, getPopupContainer: getPopupContainer, dropdownClassName: dropdownClassName }, /*#__PURE__*/React.createElement("span", null, mergedMeasurePrefix))), mergedValue.slice(mergedMeasureLocation + mergedMeasurePrefix.length))); }); Mentions.defaultProps = { prefixCls: 'rc-mentions', prefix: '@', split: ' ', validateSearch: defaultValidateSearch, filterOption: defaultFilterOption, notFoundContent: 'Not Found', rows: 1 }; Mentions.Option = Option; export default Mentions;