UNPKG

@chayns-components/emoji-input

Version:
666 lines (643 loc) • 28.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _core = require("@chayns-components/core"); var _react = require("motion/react"); var _react2 = _interopRequireWildcard(require("react")); var _emoji = require("../../utils/emoji"); var _insert = require("../../utils/insert"); var _selection = require("../../utils/selection"); var _text = require("../../utils/text"); var _EmojiPickerPopup = _interopRequireDefault(require("../emoji-picker-popup/EmojiPickerPopup")); var _EmojiInput = require("./EmojiInput.styles"); var _PrefixElement = _interopRequireDefault(require("./prefix-element/PrefixElement")); var _asyncEmojiData = require("../../utils/asyncEmojiData"); var _scroll = require("../../utils/scroll"); var _cursor = require("../../hooks/cursor"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } const MODIFIER_KEYS = new Set(['Shift', 'Control', 'Alt', 'Meta', 'CapsLock']); const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? _react2.useLayoutEffect : _react2.useEffect; const EmojiInput = /*#__PURE__*/(0, _react2.forwardRef)(({ accessToken, container, height, inputId, isDisabled, maxHeight = '190px', onBlur, onFocus, onInput, onKeyDown, onPrefixElementRemove, onPopupVisibilityChange, personId, placeholder, popupAlignment, prefixElement, rightElement, shouldHidePlaceholderOnFocus = false, shouldRevertAsciiSmileyConversionOnBackspace = false, shouldPreventEmojiPicker, value, onCursorPositionChange }, ref) => { const isTouch = (0, _core.useIsTouch)(); const [plainTextValue, setPlainTextValue] = (0, _react2.useState)(value); const [hasFocus, setHasFocus] = (0, _react2.useState)(false); const [progressDuration, setProgressDuration] = (0, _react2.useState)(0); const [labelWidth, setLabelWidth] = (0, _react2.useState)(0); const [isPopupVisible, setIsPopupVisible] = (0, _react2.useState)(false); const [isPrefixAnimationFinished, setIsPrefixAnimationFinished] = (0, _react2.useState)(!prefixElement); const [prefixElementWidth, setPrefixElementWidth] = (0, _react2.useState)(); const [emojiShortNames, setEmojiShortNames] = (0, _react2.useState)({}); const [emojiRegShortNames, setEmojiRegShortNames] = (0, _react2.useState)(/./); const areaProvider = (0, _react2.useContext)(_core.AreaContext); const editorRef = (0, _react2.useRef)(null); const prefixElementRef = (0, _react2.useRef)(null); const hasPrefixRendered = (0, _react2.useRef)(false); const hasPrefixChanged = (0, _react2.useRef)(false); const shouldDeleteOneMoreBackwards = (0, _react2.useRef)(false); const shouldDeleteOneMoreForwards = (0, _react2.useRef)(false); /** * Tracks the most recently auto-converted ASCII smiley so the next * Backspace keystroke can revert it (Word/IntelliJ-style autocorrect undo). * The ref is invalidated as soon as the user presses any non-modifier key * other than Backspace (see `handleKeyDown`). */ const lastAsciiConversionRef = (0, _react2.useRef)(null); const savedCursorPositionRef = (0, _react2.useRef)(0); const valueRef = (0, _react2.useRef)(value); (0, _cursor.useCursorPosition)(editorRef, (0, _react2.useCallback)(position => { savedCursorPositionRef.current = position; if (typeof onCursorPositionChange === 'function') { onCursorPositionChange(position); } }, [onCursorPositionChange]), { isDisabled }); const shouldChangeColor = (0, _react2.useMemo)(() => areaProvider.shouldChangeColor ?? false, [areaProvider.shouldChangeColor]); (0, _react2.useEffect)(() => { void (0, _asyncEmojiData.loadEmojiShortList)().then(({ shortNameList, regShortnames }) => { setEmojiShortNames(shortNameList); setEmojiRegShortNames(regShortnames); }); }, []); /** * This function updates the content of the 'contentEditable' element if the new text is * different from the previous content. So this is only true if, for example, a text like ":-)" * has been replaced to the corresponding emoji. * * When updating the HTML, the current cursor position is saved before replacing the content, so * that it can be set again afterward. */ const handleUpdateHTML = (0, _react2.useCallback)(html => { if (!editorRef.current) { return; } const conversions = []; let newInnerHTML = (0, _emoji.convertEmojisToUnicode)(html, emojiRegShortNames, emojiShortNames, { onAsciiConversion: conv => conversions.push(conv) }); newInnerHTML = (0, _text.convertTextToHTML)(newInnerHTML); newInnerHTML = (0, _text.cleanupEmptyIgnoreEmojiSpans)(newInnerHTML); if (newInnerHTML !== editorRef.current.innerHTML) { (0, _selection.saveSelection)(editorRef.current, { shouldIgnoreEmptyTextNodes: true }); editorRef.current.innerHTML = newInnerHTML; (0, _selection.restoreSelection)(editorRef.current); // Remember the LAST ASCII conversion so Backspace can revert it. // Older conversions are dropped on purpose: only the smiley the // user just produced should be undoable. if (shouldRevertAsciiSmileyConversionOnBackspace && conversions.length > 0) { const lastConv = conversions[conversions.length - 1]; const pos = (0, _selection.getCurrentCursorPosition)(editorRef.current); if (pos !== null) { lastAsciiConversionRef.current = { original: lastConv.original, emoji: lastConv.emoji, plainTextCursorPos: pos }; } } else { lastAsciiConversionRef.current = null; } } }, [emojiRegShortNames, emojiShortNames, shouldRevertAsciiSmileyConversionOnBackspace]); const handleBeforeInput = (0, _react2.useCallback)(event => { if (!editorRef.current) { return; } if (isDisabled) { event.preventDefault(); event.stopPropagation(); return; } const { data, type } = event.nativeEvent; if (type === 'textInput' && data && data.includes('\n')) { event.preventDefault(); event.stopPropagation(); const text = (0, _emoji.convertEmojisToUnicode)(data, emojiRegShortNames, emojiShortNames); (0, _insert.insertTextAtCursorPosition)({ editorElement: editorRef.current, text }); const newEvent = new Event('input', { bubbles: true }); editorRef.current.dispatchEvent(newEvent); } }, [emojiRegShortNames, emojiShortNames, isDisabled]); /** * This function handles the 'input' events of the 'contentEditable' element and also passes the * respective event up accordingly if the 'onInput' property is a function. */ const handleInput = (0, _react2.useCallback)(event => { if (!editorRef.current) { return; } // If the user is typing inside a no-emoji-convert span, unwrap it first // This prevents text from getting stuck inside the protection span (0, _selection.unwrapIgnoreEmojiSpanAtCursor)(editorRef.current); if (isDisabled) { event.stopPropagation(); event.preventDefault(); } if (shouldDeleteOneMoreBackwards.current) { shouldDeleteOneMoreBackwards.current = false; shouldDeleteOneMoreForwards.current = false; event.preventDefault(); event.stopPropagation(); // Remove content and set cursor to the right position (0, _selection.insertInvisibleCursorMarker)(); return; } if (shouldDeleteOneMoreForwards.current) { shouldDeleteOneMoreBackwards.current = false; shouldDeleteOneMoreForwards.current = false; event.preventDefault(); event.stopPropagation(); // noinspection JSDeprecatedSymbols document.execCommand('forwardDelete', false); return; } let cleanedHTML = (0, _text.cleanupEmptyIgnoreEmojiSpans)(editorRef.current.innerHTML); handleUpdateHTML(cleanedHTML); // After handleUpdateHTML, the DOM has been updated with emojis // We need to read the text from the updated DOM, not from pre-update HTML // convertHTMLToText will convert no-emoji-convert spans to [ignoreEmoji] BBCode const text = (0, _text.convertHTMLToText)(editorRef.current.innerHTML); setPlainTextValue(text); if (typeof onInput === 'function') { onInput(event, text); } (0, _selection.insertCursorAtMarker)(editorRef); (0, _selection.moveCursorOutOfIgnoreEmojiSpan)(editorRef.current); }, [handleUpdateHTML, isDisabled, onInput]); const handleKeyDown = (0, _react2.useCallback)(event => { if (isDisabled) { event.preventDefault(); event.stopPropagation(); return; } // --- Backspace-revert for the most recent auto-conversion --- // If the user presses Backspace immediately after an ASCII smiley // was auto-converted (and the cursor is still at the post-conversion // position), we revert the emoji back to the original text and wrap // it in a protection span so it does not get re-converted. if (shouldRevertAsciiSmileyConversionOnBackspace && event.key === 'Backspace' && !event.ctrlKey && !event.metaKey && lastAsciiConversionRef.current && editorRef.current) { const { original, emoji, plainTextCursorPos } = lastAsciiConversionRef.current; const currentPos = (0, _selection.getCurrentCursorPosition)(editorRef.current); if (currentPos === plainTextCursorPos) { event.preventDefault(); event.stopPropagation(); const didRevert = (0, _insert.revertAsciiSmileyConversion)({ editorElement: editorRef.current, original, emoji }); lastAsciiConversionRef.current = null; if (didRevert) { // Notify React + downstream consumers via a synthetic input event const newEvent = new Event('input', { bubbles: true }); editorRef.current.dispatchEvent(newEvent); return; } } else { // Cursor moved away from the just-converted emoji -> drop tracker lastAsciiConversionRef.current = null; } } else if (shouldRevertAsciiSmileyConversionOnBackspace && !MODIFIER_KEYS.has(event.key)) { // Any other actual keystroke invalidates the revert window lastAsciiConversionRef.current = null; } if (event.key === 'Enter' && isPopupVisible) { event.preventDefault(); return; } if (typeof onKeyDown === 'function') { onKeyDown(event); } if (event.key === 'Enter' && !event.isPropagationStopped() && editorRef.current) { event.preventDefault(); // noinspection JSDeprecatedSymbols document.execCommand('insertLineBreak', false); } if (event.key === 'Enter') { requestAnimationFrame(() => { if (editorRef.current) (0, _scroll.scrollCursorIntoView)(editorRef.current); }); } if (event.key === 'Backspace' || event.key === 'Delete' || event.key === 'Unidentified') { const charCodeThatWillBeDeleted = (0, _selection.getCharCodeThatWillBeDeleted)(event); if (charCodeThatWillBeDeleted === 8203) { if (event.key === 'Backspace' || event.key === 'Unidentified') { shouldDeleteOneMoreBackwards.current = true; } else { shouldDeleteOneMoreForwards.current = true; } } } }, [isDisabled, isPopupVisible, onKeyDown, shouldRevertAsciiSmileyConversionOnBackspace]); const handlePopupVisibility = (0, _react2.useCallback)(isVisible => { setIsPopupVisible(isVisible); if (editorRef.current && isVisible) { (0, _selection.saveSelection)(editorRef.current); } if (typeof onPopupVisibilityChange === 'function') { onPopupVisibilityChange(isVisible); } }, [onPopupVisibilityChange]); /** * This function prevents formatting from being adopted when texts are inserted. To do this, the * plain text is read from the event after the default behavior has been prevented. The plain * text is then inserted at the correct position in the input field using document.execCommand('insertHTML') */ const handlePaste = (0, _react2.useCallback)(event => { if (editorRef.current) { event.preventDefault(); if (isDisabled) { event.stopPropagation(); return; } // This ensures, that only the copied text is inserted and not its HTML formatting. let text = event.clipboardData.getData('text/plain'); text = (0, _emoji.convertEmojisToUnicode)(text, emojiRegShortNames, emojiShortNames); /* This ensures, that valid HTML in the inserted text is not interpreted as such. e.g. if the user pasted the text '<b>test</b>' (not as formatted html), the <b> tags need to be escaped, to prevent it from being interpreted as html. */ text = (0, _emoji.escapeHTML)(text); // Insert an invisible control character at the end of the text to place the cursor in the correct position after insertion. if (text.includes('\n')) { text += '\u200C'; } // This deprecated function is used, because it causes the inserted content to be added to the undo stack. // If the text were to be inserted directly into the 'innerHTML' of the editor element, the undo stack would not be updated. // In that case on CTRL+Z the inserted text would not be removed. document.execCommand('insertHTML', false, text); const newEvent = new Event('input', { bubbles: true }); editorRef.current.dispatchEvent(newEvent); } }, [emojiRegShortNames, emojiShortNames, isDisabled]); /** * This function prevents formatting from being adopted when texts are dropped. To do this, the * plain text is read from the event after the default behavior has been prevented. The plain * text is then inserted at the correct position in the input field using document.execCommand('insertHTML') */ const handleDrop = (0, _react2.useCallback)(event => { if (editorRef.current) { var _event$dataTransfer; event.preventDefault(); if (isDisabled) { event.stopPropagation(); return; } // This ensures, that only the dropped text is inserted and not its HTML formatting. let text = (_event$dataTransfer = event.dataTransfer) === null || _event$dataTransfer === void 0 ? void 0 : _event$dataTransfer.getData('text'); if (!text) { return; } text = (0, _emoji.convertEmojisToUnicode)(text, emojiRegShortNames, emojiShortNames); /* This ensures, that valid HTML in the inserted text is not interpreted as such. e.g. if the user drops the text '<b>test</b>' (not as formatted html), the <b> tags need to be escaped, to prevent it from being interpreted as html. */ text = (0, _emoji.escapeHTML)(text); // This deprecated function is used, because it causes the inserted content to be added to the undo stack. // If the text were to be inserted directly into the 'innerHTML' of the editor element, the undo stack would not be updated. // In that case on CTRL+Z the inserted text would not be removed. document.execCommand('insertHTML', false, text); const newEvent = new Event('input', { bubbles: true }); editorRef.current.dispatchEvent(newEvent); } }, [emojiRegShortNames, emojiShortNames, isDisabled]); /** * This function uses the 'insertTextAtCursorPosition' function to insert the emoji at the * correct position in the editor element. * * At the end an 'input' event is dispatched, so that the function 'handleInput' is triggered, * which in turn executes the 'onInput' function from the props. So this serves to ensure that * the event is also passed through to the top when inserting via the popup. */ const handlePopupSelect = (0, _react2.useCallback)(emoji => { if (editorRef.current) { (0, _insert.insertTextAtCursorPosition)({ editorElement: editorRef.current, text: emoji, shouldUseSavedSelection: true }); const event = new Event('input', { bubbles: true }); editorRef.current.dispatchEvent(event); } }, []); (0, _react2.useEffect)(() => { if (!shouldRevertAsciiSmileyConversionOnBackspace) { lastAsciiConversionRef.current = null; } }, [shouldRevertAsciiSmileyConversionOnBackspace]); (0, _react2.useEffect)(() => { var _editorRef$current; if (typeof onPrefixElementRemove !== 'function') { return; } if (!hasPrefixRendered.current) { return; } const convertedText = (0, _text.convertHTMLToText)(((_editorRef$current = editorRef.current) === null || _editorRef$current === void 0 ? void 0 : _editorRef$current.innerHTML) ?? '').replace('&nbsp;', ' '); const convertedPrefix = prefixElement && prefixElement.replace('&nbsp;', ' '); if (convertedPrefix && convertedText.includes(convertedPrefix) && convertedText.length > convertedPrefix.length || convertedPrefix === convertedText) { return; } if (hasPrefixChanged.current) { hasPrefixChanged.current = false; return; } onPrefixElementRemove(); hasPrefixRendered.current = false; }, [onPrefixElementRemove, plainTextValue.length, prefixElement]); (0, _react2.useEffect)(() => { if (typeof prefixElement === 'string') { hasPrefixChanged.current = true; } }, [prefixElement]); (0, _react2.useEffect)(() => { if (value !== plainTextValue) { setPlainTextValue(value); handleUpdateHTML(value); } }, [handleUpdateHTML, plainTextValue, value]); // After every input, ensure the cursor is not stuck inside a no-emoji-convert span (0, _react2.useEffect)(() => { (0, _selection.moveCursorOutOfIgnoreEmojiSpan)(editorRef.current); }, [plainTextValue]); // This effect is used to call the 'handleUpdateHTML' function once after the component has been // rendered. This is necessary because the 'contentEditable' element otherwise does not display // the HTML content correctly when the component is rendered for the first time. useIsomorphicLayoutEffect(() => { handleUpdateHTML(valueRef.current); }, [handleUpdateHTML]); const handleInsertTextAtCursorPosition = (0, _react2.useCallback)(text => { if (editorRef.current) { (0, _insert.insertTextAtCursorPosition)({ editorElement: editorRef.current, text }); const newEvent = new Event('input', { bubbles: true }); editorRef.current.dispatchEvent(newEvent); } }, []); const handleReplaceText = (0, _react2.useCallback)((searchText, pasteText, options) => { if (editorRef.current) { (0, _insert.replaceText)({ editorElement: editorRef.current, searchText, pasteText, options }); (0, _selection.insertPseudoMarker)(); const newEvent = new Event('input', { bubbles: true }); editorRef.current.dispatchEvent(newEvent); } }, []); const handleStartProgress = (0, _react2.useCallback)(duration => { setProgressDuration(duration); }, []); const handleStopProgress = (0, _react2.useCallback)(() => { setProgressDuration(0); }, []); const handleSetCursorPosition = (0, _react2.useCallback)(position => { if (!editorRef.current) { return; } const resolvedPosition = position ?? savedCursorPositionRef.current; savedCursorPositionRef.current = resolvedPosition; editorRef.current.focus(); (0, _selection.setCursorPositionByAbsIndex)({ editorElement: editorRef.current, position: resolvedPosition }); const updatedPosition = (0, _selection.getCurrentCursorPosition)(editorRef.current); if (typeof updatedPosition === 'number') { savedCursorPositionRef.current = updatedPosition; } }, []); (0, _react2.useImperativeHandle)(ref, () => ({ insertTextAtCursorPosition: handleInsertTextAtCursorPosition, replaceText: handleReplaceText, startProgress: handleStartProgress, stopProgress: handleStopProgress, focus: () => { var _editorRef$current2; return (_editorRef$current2 = editorRef.current) === null || _editorRef$current2 === void 0 ? void 0 : _editorRef$current2.focus(); }, blur: () => { var _editorRef$current3; return (_editorRef$current3 = editorRef.current) === null || _editorRef$current3 === void 0 ? void 0 : _editorRef$current3.blur(); }, setCursorPosition: handleSetCursorPosition }), [handleInsertTextAtCursorPosition, handleReplaceText, handleStartProgress, handleStopProgress, handleSetCursorPosition]); (0, _react2.useEffect)(() => { /** * This function ensures that the input field does not lose focus when the popup is opened * or an emoji is selected in it. For this purpose the corresponding elements get the class * 'prevent-lose-focus'. * * The class can also be set to any other elements that should also not cause the input * field to lose focus. */ const handlePreventLoseFocus = event => { var _element$parentElemen, _element$parentElemen2; const element = event.target; if (element.classList.contains('prevent-lose-focus') || (_element$parentElemen = element.parentElement) !== null && _element$parentElemen !== void 0 && _element$parentElemen.classList.contains('prevent-lose-focus') || (_element$parentElemen2 = element.parentElement) !== null && _element$parentElemen2 !== void 0 && (_element$parentElemen2 = _element$parentElemen2.parentElement) !== null && _element$parentElemen2 !== void 0 && _element$parentElemen2.classList.contains('prevent-lose-focus')) { event.preventDefault(); event.stopPropagation(); } }; document.body.addEventListener('mousedown', handlePreventLoseFocus); return () => { document.body.removeEventListener('mousedown', handlePreventLoseFocus); }; }, []); const shouldShowPlaceholder = (0, _react2.useMemo)(() => { var _editorRef$current4; if (!isPrefixAnimationFinished) { return false; } const isJustPrefixElement = prefixElement && (0, _text.convertTextToHTML)(prefixElement) === ((_editorRef$current4 = editorRef.current) === null || _editorRef$current4 === void 0 ? void 0 : _editorRef$current4.innerHTML); const shouldRenderPlaceholder = prefixElement && !plainTextValue || (prefixElement ? prefixElementWidth && prefixElementWidth > 0 : true); switch (true) { case (!plainTextValue || isJustPrefixElement) && shouldHidePlaceholderOnFocus && !hasFocus: case (!plainTextValue || isJustPrefixElement) && !shouldHidePlaceholderOnFocus: return shouldRenderPlaceholder; case (!plainTextValue || isJustPrefixElement) && shouldHidePlaceholderOnFocus && hasFocus: return false; default: return false; } }, [isPrefixAnimationFinished, hasFocus, plainTextValue, prefixElement, shouldHidePlaceholderOnFocus, prefixElementWidth]); (0, _react2.useEffect)(() => { if (prefixElement) { setIsPrefixAnimationFinished(false); } }, [prefixElement]); const handleFocus = event => { if (typeof onFocus === 'function' && !isDisabled) { onFocus(event); } setHasFocus(true); }; const handleBlur = event => { if (typeof onBlur === 'function' && !isDisabled) { onBlur(event); } setHasFocus(false); }; (0, _react2.useEffect)(() => { if (editorRef.current && prefixElement) { const text = (0, _emoji.convertEmojisToUnicode)(prefixElement, emojiRegShortNames, emojiShortNames); (0, _insert.insertTextAtCursorPosition)({ editorElement: editorRef.current, text }); handleUpdateHTML(prefixElement); hasPrefixRendered.current = true; } }, [emojiRegShortNames, emojiShortNames, handleUpdateHTML, prefixElement]); (0, _react2.useEffect)(() => { var _editorRef$current5; if (prefixElementRef.current && prefixElement && (0, _text.convertTextToHTML)(prefixElement) === ((_editorRef$current5 = editorRef.current) === null || _editorRef$current5 === void 0 ? void 0 : _editorRef$current5.innerHTML)) { setPrefixElementWidth(prefixElementRef.current.offsetWidth + 2); } else { setPrefixElementWidth(undefined); } }, [plainTextValue, prefixElement]); (0, _react2.useEffect)(() => { const handleResize = () => { if (editorRef.current) { setLabelWidth(editorRef.current.offsetWidth); } }; const resizeObserver = new ResizeObserver(handleResize); if (editorRef.current) { resizeObserver.observe(editorRef.current); } return () => { resizeObserver.disconnect(); }; }, []); (0, _react2.useEffect)(() => { const blurElement = () => { if (editorRef.current && document.activeElement === editorRef.current && isDisabled) { editorRef.current.blur(); } }; document.addEventListener('focus', blurElement, true); return () => { document.removeEventListener('focus', blurElement, true); }; }, [isDisabled]); return /*#__PURE__*/_react2.default.createElement(_EmojiInput.StyledEmojiInput, { $isDisabled: isDisabled, $shouldChangeColor: shouldChangeColor }, /*#__PURE__*/_react2.default.createElement(_react.AnimatePresence, { initial: true }, progressDuration > 0 && /*#__PURE__*/_react2.default.createElement(_EmojiInput.StyledMotionEmojiInputProgress, { animate: { width: '100%' }, exit: { opacity: 0 }, initial: { opacity: 1, width: '0%' }, transition: { width: { ease: 'linear', duration: progressDuration }, opacity: { type: 'tween', duration: 0.3 } } })), /*#__PURE__*/_react2.default.createElement(_EmojiInput.StyledEmojiInputContent, null, prefixElement && /*#__PURE__*/_react2.default.createElement(_PrefixElement.default, { key: prefixElement, element: prefixElement, prefixElementRef: prefixElementRef, setIsPrefixAnimationFinished: setIsPrefixAnimationFinished }), /*#__PURE__*/_react2.default.createElement(_EmojiInput.StyledMotionEmojiInputEditor, { className: "chayns-scrollbar", animate: { maxHeight: height ?? maxHeight, minHeight: height ?? '26px' }, contentEditable: true, id: inputId, onBeforeInput: handleBeforeInput, onBlur: handleBlur, onFocus: handleFocus, onInput: handleInput, onKeyDown: handleKeyDown, onPaste: handlePaste, onDrop: handleDrop, ref: editorRef, $shouldShowContent: isPrefixAnimationFinished, transition: { type: 'tween', duration: 0.2 } }), shouldShowPlaceholder && /*#__PURE__*/_react2.default.createElement(_EmojiInput.StyledEmojiInputLabel, { $maxWidth: labelWidth, $offsetWidth: prefixElementWidth }, placeholder), !isTouch && !shouldPreventEmojiPicker && /*#__PURE__*/_react2.default.createElement(_EmojiPickerPopup.default, { accessToken: accessToken, container: container, onSelect: handlePopupSelect, onPopupVisibilityChange: handlePopupVisibility, personId: personId })), rightElement && /*#__PURE__*/_react2.default.createElement(_EmojiInput.StyledEmojiInputRightWrapper, null, rightElement)); }); EmojiInput.displayName = 'EmojiInput'; var _default = exports.default = EmojiInput; //# sourceMappingURL=EmojiInput.js.map