feat: Quality-of-Life Chat/Edit-Message Enhancements (#5194)

* fix: rendering error for mermaid flowchart syntax

* feat: add submit button ref and enable submit on Ctrl+Enter in EditMessage component

* feat: add save button and keyboard shortcuts for saving and canceling in EditMessage component

* feat: collapse chat on max height

* refactor: implement scrollable detection for textarea on key down events and initial render

* feat: add regenerate button for error handling in HoverButtons, closes #3658

* feat: add functionality to edit latest user message with the up arrow key when the input is empty
This commit is contained in:
Danny Avila 2025-01-06 22:47:24 -05:00 committed by GitHub
parent b01c744eb8
commit 8aa1e731ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 242 additions and 66 deletions

View file

@ -54,6 +54,7 @@ const useHandleKeyUp = ({
permissionType: PermissionTypes.MULTI_CONVO,
permission: Permissions.USE,
});
const latestMessage = useRecoilValue(store.latestMessageFamily(index));
const setShowPromptsPopover = useSetRecoilState(store.showPromptsPopoverFamily(index));
// Get the current state of command toggles
@ -94,12 +95,32 @@ const useHandleKeyUp = ({
[handleAtCommand, handlePlusCommand, handlePromptsCommand],
);
const handleUpArrow = useCallback(
(event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (!latestMessage) {
return;
}
const element = document.getElementById(`edit-${latestMessage.parentMessageId}`);
if (!element) {
return;
}
event.preventDefault();
element.click();
},
[latestMessage],
);
/**
* Main key up handler.
*/
const handleKeyUp = useCallback(
(event: React.KeyboardEvent<HTMLTextAreaElement>) => {
const text = textAreaRef.current?.value;
if (event.key === 'ArrowUp' && text?.length === 0) {
handleUpArrow(event);
return;
}
if (typeof text !== 'string' || text.length === 0) {
return;
}
@ -115,7 +136,7 @@ const useHandleKeyUp = ({
handler();
}
},
[textAreaRef, commandHandlers],
[textAreaRef, commandHandlers, handleUpArrow],
);
return handleKeyUp;

View file

@ -4,7 +4,13 @@ import { useRecoilValue, useRecoilState } from 'recoil';
import { Constants } from 'librechat-data-provider';
import type { TEndpointOption } from 'librechat-data-provider';
import type { KeyboardEvent } from 'react';
import { forceResize, insertTextAtCursor, getEntityName, getEntity } from '~/utils';
import {
forceResize,
insertTextAtCursor,
getEntityName,
getEntity,
checkIfScrollable,
} from '~/utils';
import { useAssistantsMapContext } from '~/Providers/AssistantsMapContext';
import { useAgentsMapContext } from '~/Providers/AgentsMapContext';
import useGetSender from '~/hooks/Conversations/useGetSender';
@ -20,10 +26,12 @@ type KeyEvent = KeyboardEvent<HTMLTextAreaElement>;
export default function useTextarea({
textAreaRef,
submitButtonRef,
setIsScrollable,
disabled = false,
}: {
textAreaRef: React.RefObject<HTMLTextAreaElement>;
submitButtonRef: React.RefObject<HTMLButtonElement>;
setIsScrollable: React.Dispatch<React.SetStateAction<boolean>>;
disabled?: boolean;
}) {
const localize = useLocalize();
@ -170,6 +178,10 @@ export default function useTextarea({
const handleKeyDown = useCallback(
(e: KeyEvent) => {
if (textAreaRef.current && checkIfScrollable(textAreaRef.current)) {
const scrollable = checkIfScrollable(textAreaRef.current);
scrollable && setIsScrollable(scrollable);
}
if (e.key === 'Enter' && isSubmitting) {
return;
}
@ -209,7 +221,15 @@ export default function useTextarea({
submitButtonRef.current?.click();
}
},
[isSubmitting, checkHealth, filesLoading, enterToSend, textAreaRef, submitButtonRef],
[
isSubmitting,
checkHealth,
filesLoading,
enterToSend,
setIsScrollable,
textAreaRef,
submitButtonRef,
],
);
const handleCompositionStart = () => {