mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-19 09:50:15 +01:00
📝 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:
parent
de0cee3f56
commit
c52ea9490b
3 changed files with 91 additions and 36 deletions
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue