📝 feat: Improved Textarea Functionality (#1942)

* feat: paste plain text from apps with rich paste data, improved edit message textarea, improved height resizing for long text

* feat(EditMessage): autofocus

* chore: retain user text color when entering edit mode
This commit is contained in:
Danny Avila 2024-03-01 12:46:15 -05:00 committed by GitHub
parent de0cee3f56
commit c52ea9490b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 91 additions and 36 deletions

View file

@ -1,9 +1,11 @@
import { useRef } from 'react';
import { useState, useRef, useEffect } from 'react';
import TextareaAutosize from 'react-textarea-autosize';
import { EModelEndpoint } from 'librechat-data-provider';
import { useUpdateMessageMutation } from 'librechat-data-provider/react-query';
import Container from '~/components/Messages/Content/Container';
import { useChatContext } from '~/Providers';
import type { TEditProps } from '~/common';
import Container from '~/components/Messages/Content/Container';
import { cn, removeFocusOutlines } from '~/utils';
import { useChatContext } from '~/Providers';
import { useLocalize } from '~/hooks';
const EditMessage = ({
@ -17,18 +19,28 @@ const EditMessage = ({
}: TEditProps) => {
const { getMessages, setMessages, conversation } = useChatContext();
const textEditor = useRef<HTMLDivElement | null>(null);
const [editedText, setEditedText] = useState<string>(text ?? '');
const textAreaRef = useRef<HTMLTextAreaElement | null>(null);
const { conversationId, parentMessageId, messageId } = message;
const { endpoint: _endpoint, endpointType } = conversation ?? { endpoint: null };
const endpoint = endpointType ?? _endpoint;
const updateMessageMutation = useUpdateMessageMutation(conversationId ?? '');
const localize = useLocalize();
useEffect(() => {
const textArea = textAreaRef.current;
if (textArea) {
const length = textArea.value.length;
textArea.focus();
textArea.setSelectionRange(length, length);
}
}, []);
const resubmitMessage = () => {
const text = textEditor?.current?.innerText ?? '';
if (message.isCreatedByUser) {
ask({
text,
text: editedText,
parentMessageId,
conversationId,
});
@ -44,7 +56,7 @@ const EditMessage = ({
ask(
{ ...parentMessage },
{
editedText: text,
editedText,
editedMessageId: messageId,
isRegenerate: true,
isEdited: true,
@ -62,19 +74,18 @@ const EditMessage = ({
if (!messages) {
return;
}
const text = textEditor?.current?.innerText ?? '';
updateMessageMutation.mutate({
conversationId: conversationId ?? '',
model: conversation?.model ?? 'gpt-3.5-turbo',
text: editedText,
messageId,
text,
});
setMessages(
messages.map((msg) =>
msg.messageId === messageId
? {
...msg,
text,
text: editedText,
isEdited: true,
}
: msg,
@ -85,15 +96,33 @@ const EditMessage = ({
return (
<Container>
<div
<TextareaAutosize
ref={textAreaRef}
onChange={(e) => {
setEditedText(e.target.value);
}}
data-testid="message-text-editor"
className="markdown prose dark:prose-invert light w-full whitespace-pre-wrap break-words border-none focus:outline-none"
className={cn(
'markdown prose dark:prose-invert light whitespace-pre-wrap break-words dark:text-gray-20',
'm-0 w-full resize-none border-0 bg-transparent p-0',
removeFocusOutlines,
)}
onPaste={(e) => {
const pastedData = e.clipboardData.getData('text/plain');
const textArea = textAreaRef.current;
if (!textArea) {
return;
}
const start = textArea.selectionStart;
const end = textArea.selectionEnd;
const newValue =
textArea.value.substring(0, start) + pastedData + textArea.value.substring(end);
setEditedText(newValue);
}}
contentEditable={true}
ref={textEditor}
value={editedText}
suppressContentEditableWarning={true}
>
{text}
</div>
/>
<div className="mt-2 flex w-full justify-center text-center">
<button
className="btn btn-primary relative mr-2"