@chayns-components/emoji-input
Version:
Input field that supports HTML elements and emojis
666 lines (643 loc) • 28.1 kB
JavaScript
"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(' ', ' ');
const convertedPrefix = prefixElement && prefixElement.replace(' ', ' ');
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