import TextareaAutosize from 'react-textarea-autosize'; import { EModelEndpoint } from 'librechat-data-provider'; import { useState, useRef, useEffect, useCallback } from 'react'; import { useUpdateMessageMutation } from 'librechat-data-provider/react-query'; import type { TEditProps } from '~/common'; import { cn, removeFocusRings } from '~/utils'; import { useChatContext } from '~/Providers'; import { useLocalize } from '~/hooks'; import Container from './Container'; const EditMessage = ({ text, message, isSubmitting, ask, enterEdit, siblingIdx, setSiblingIdx, }: TEditProps) => { const { getMessages, setMessages, conversation } = useChatContext(); const [editedText, setEditedText] = useState(text ?? ''); const textAreaRef = useRef(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 = () => { if (message.isCreatedByUser) { ask( { text: editedText, parentMessageId, conversationId, }, { resubmitFiles: true, }, ); setSiblingIdx((siblingIdx ?? 0) - 1); } else { const messages = getMessages(); const parentMessage = messages?.find((msg) => msg.messageId === parentMessageId); if (!parentMessage) { return; } ask( { ...parentMessage }, { editedText, editedMessageId: messageId, isRegenerate: true, isEdited: true, }, ); setSiblingIdx((siblingIdx ?? 0) - 1); } enterEdit(true); }; const updateMessage = () => { const messages = getMessages(); if (!messages) { return; } updateMessageMutation.mutate({ conversationId: conversationId ?? '', model: conversation?.model ?? 'gpt-3.5-turbo', text: editedText, messageId, }); setMessages( messages.map((msg) => msg.messageId === messageId ? { ...msg, text: editedText, isEdited: true, } : msg, ), ); enterEdit(true); }; const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (e.key === 'Escape') { e.preventDefault(); enterEdit(true); } }, [enterEdit], ); return (
{ setEditedText(e.target.value); }} onKeyDown={handleKeyDown} data-testid="message-text-editor" className={cn( 'markdown prose dark:prose-invert light whitespace-pre-wrap break-words', 'pl-3 md:pl-4', 'm-0 w-full resize-none border-0 bg-transparent py-[10px]', 'placeholder-black/50 focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:placeholder-white/50 md:py-3.5 ', 'pr-3 md:pr-4', 'max-h-[65vh] md:max-h-[75vh]', removeFocusRings, )} onPaste={(e) => { e.preventDefault(); 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} value={editedText} suppressContentEditableWarning={true} />
); }; export default EditMessage;