fix(chat): simplify emoji + char count handling. Closes #3120
This commit is contained in:
@@ -67,7 +67,6 @@ function setCaretPosition(editableDiv, position) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, focusInput }) => {
|
export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, focusInput }) => {
|
||||||
const [showEmojis, setShowEmojis] = useState(false);
|
|
||||||
const [characterCount, setCharacterCount] = useState(defaultText?.length);
|
const [characterCount, setCharacterCount] = useState(defaultText?.length);
|
||||||
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
|
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
|
||||||
const text = useRef(defaultText || '');
|
const text = useRef(defaultText || '');
|
||||||
@@ -97,33 +96,21 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, fo
|
|||||||
forceUpdate();
|
forceUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
const insertTextAtCursor = (textToInsert: string) => {
|
const insertTextAtEnd = (textToInsert: string) => {
|
||||||
let cursorLocation;
|
const output = text.current + textToInsert;
|
||||||
if (savedCursorLocation > 0) {
|
|
||||||
cursorLocation = savedCursorLocation;
|
|
||||||
} else {
|
|
||||||
cursorLocation = getCaretPosition(document.getElementById('chat-input'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = [
|
|
||||||
text.current.slice(0, cursorLocation),
|
|
||||||
textToInsert,
|
|
||||||
text.current.slice(cursorLocation),
|
|
||||||
].join('');
|
|
||||||
|
|
||||||
text.current = output;
|
text.current = output;
|
||||||
forceUpdate();
|
forceUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Native emoji
|
// Native emoji
|
||||||
const onEmojiSelect = (emoji: string) => {
|
const onEmojiSelect = (emoji: string) => {
|
||||||
insertTextAtCursor(emoji);
|
insertTextAtEnd(emoji);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Custom emoji images
|
// Custom emoji images
|
||||||
const onCustomEmojiSelect = (name: string, emoji: string) => {
|
const onCustomEmojiSelect = (name: string, emoji: string) => {
|
||||||
const html = `<img src="${emoji}" alt="${name}" title="${name}" class="emoji" />`;
|
const html = `<img src="${emoji}" alt="${name}" title="${name}" class="emoji" />`;
|
||||||
insertTextAtCursor(html);
|
insertTextAtEnd(html);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyDown = (e: React.KeyboardEvent) => {
|
const onKeyDown = (e: React.KeyboardEvent) => {
|
||||||
@@ -136,13 +123,11 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, fo
|
|||||||
|
|
||||||
// Always allow backspace.
|
// Always allow backspace.
|
||||||
if (e.key === 'Backspace') {
|
if (e.key === 'Backspace') {
|
||||||
setCharacterCount(charCount - 1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always allow delete.
|
// Always allow delete.
|
||||||
if (e.key === 'Delete') {
|
if (e.key === 'Delete') {
|
||||||
setCharacterCount(charCount - 1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +139,7 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, fo
|
|||||||
// Limit the number of characters.
|
// Limit the number of characters.
|
||||||
if (charCount + 1 > characterLimit) {
|
if (charCount + 1 > characterLimit) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the message when hitting enter.
|
// Send the message when hitting enter.
|
||||||
@@ -182,6 +168,10 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, fo
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
text.current = sanitized;
|
text.current = sanitized;
|
||||||
|
|
||||||
|
const charCountString = sanitized.replace(/<\/?[^>]+(>|$)/g, '');
|
||||||
|
setCharacterCount(charCountString.length);
|
||||||
|
|
||||||
setSavedCursorLocation(
|
setSavedCursorLocation(
|
||||||
getCaretPosition(document.getElementById('chat-input-content-editable')),
|
getCaretPosition(document.getElementById('chat-input-content-editable')),
|
||||||
);
|
);
|
||||||
@@ -242,19 +232,6 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, fo
|
|||||||
characterCount >= characterLimit && styles.maxCharacters,
|
characterCount >= characterLimit && styles.maxCharacters,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Popover
|
|
||||||
content={
|
|
||||||
<EmojiPicker
|
|
||||||
customEmoji={customEmoji}
|
|
||||||
onEmojiSelect={onEmojiSelect}
|
|
||||||
onCustomEmojiSelect={onCustomEmojiSelect}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
trigger="click"
|
|
||||||
placement="topRight"
|
|
||||||
onOpenChange={open => setShowEmojis(open)}
|
|
||||||
open={showEmojis}
|
|
||||||
/>
|
|
||||||
<ContentEditable
|
<ContentEditable
|
||||||
id="chat-input-content-editable"
|
id="chat-input-content-editable"
|
||||||
html={text.current}
|
html={text.current}
|
||||||
@@ -270,14 +247,21 @@ export const ChatTextField: FC<ChatTextFieldProps> = ({ defaultText, enabled, fo
|
|||||||
/>
|
/>
|
||||||
{enabled && (
|
{enabled && (
|
||||||
<div style={{ display: 'flex', paddingLeft: '5px' }}>
|
<div style={{ display: 'flex', paddingLeft: '5px' }}>
|
||||||
<button
|
<Popover
|
||||||
type="button"
|
content={
|
||||||
className={styles.emojiButton}
|
<EmojiPicker
|
||||||
title="Emoji picker button"
|
customEmoji={customEmoji}
|
||||||
onClick={() => setShowEmojis(!showEmojis)}
|
onEmojiSelect={onEmojiSelect}
|
||||||
|
onCustomEmojiSelect={onCustomEmojiSelect}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
trigger="click"
|
||||||
|
placement="topRight"
|
||||||
>
|
>
|
||||||
|
<button type="button" className={styles.emojiButton} title="Emoji picker button">
|
||||||
<SmileOutlined />
|
<SmileOutlined />
|
||||||
</button>
|
</button>
|
||||||
|
</Popover>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.sendButton}
|
className={styles.sendButton}
|
||||||
|
|||||||
Reference in New Issue
Block a user