diff --git a/src/components/ChatEditor/ChatEditor.tsx b/src/components/ChatEditor/ChatEditor.tsx index 9a8a368de..3fe5284f7 100644 --- a/src/components/ChatEditor/ChatEditor.tsx +++ b/src/components/ChatEditor/ChatEditor.tsx @@ -1,12 +1,21 @@ import './ChatEditor.css'; -import { EditorContent, useEditor } from '@tiptap/react'; +import { + Editor, + EditorContent, + useEditor, + type JSONContent, +} from '@tiptap/react'; import DocumentExtension from '@tiptap/extension-document'; import ParagraphExtension from '@tiptap/extension-paragraph'; import TextExtension from '@tiptap/extension-text'; import Placeholder from '@tiptap/extension-placeholder'; import { VariableExtension } from './VariableExtension/VariableExtension'; import { variableSuggestion } from './VariableExtension/VariableSuggestion'; +import { queryClient } from '../../stores/query-client'; +import { roadmapTreeMappingOptions } from '../../queries/roadmap-tree'; +import { useQuery } from '@tanstack/react-query'; +import { useEffect, type RefObject } from 'react'; const extensions = [ DocumentExtension, @@ -22,7 +31,20 @@ const extensions = [ const content = '

'; -export function ChatEditor() { +type ChatEditorProps = { + editorRef: RefObject; + roadmapId: string; + onSubmit: (content: JSONContent) => void; +}; + +export function ChatEditor(props: ChatEditorProps) { + const { roadmapId, onSubmit, editorRef } = props; + + const { data: roadmapTreeData } = useQuery( + roadmapTreeMappingOptions(roadmapId), + queryClient, + ); + const editor = useEditor({ extensions, content, @@ -36,21 +58,53 @@ export function ChatEditor() { } if (event.key === 'Enter' && !event.shiftKey) { + // check if the variable suggestion list is focused + // if it is, return false so the default behavior is not triggered + const variableSuggestionList = document.getElementById( + 'variable-suggestion-list', + ); + if (variableSuggestionList) { + return false; + } + event.preventDefault(); + onSubmit(editor.getJSON()); return true; } if (event.key === 'Enter' && event.shiftKey) { event.preventDefault(); - editor.commands.insertContent('

'); + editor.commands.insertContent([ + { type: 'text', text: ' ' }, + { type: 'paragraph' }, + ]); return true; } return false; }, }, + onUpdate: ({ editor }) => { + editorRef.current = editor; + }, + onDestroy: () => { + editorRef.current = null; + }, }); + useEffect(() => { + if (!editor || !roadmapTreeData) { + return; + } + + editor.storage.variable.variables = roadmapTreeData.map((mapping) => { + return { + id: mapping._id, + label: mapping.text, + }; + }); + }, [editor, roadmapTreeData]); + return (
diff --git a/src/components/ChatEditor/VariableExtension/VariableSuggestion.tsx b/src/components/ChatEditor/VariableExtension/VariableSuggestion.tsx index 6be201511..d49a8178b 100644 --- a/src/components/ChatEditor/VariableExtension/VariableSuggestion.tsx +++ b/src/components/ChatEditor/VariableExtension/VariableSuggestion.tsx @@ -25,34 +25,24 @@ export const VariableList = forwardRef((props: VariableListProps, ref) => { command(item); }; - const upHandler = () => { - setSelectedIndex((selectedIndex + items.length - 1) % items.length); - }; - - const downHandler = () => { - setSelectedIndex((selectedIndex + 1) % items.length); - }; - - const enterHandler = () => { - selectItem(selectedIndex); - }; - - useEffect(() => setSelectedIndex(0), [items]); + useEffect(() => { + setSelectedIndex(0); + }, [items]); useImperativeHandle(ref, () => ({ onKeyDown: ({ event }: { event: KeyboardEvent }) => { if (event.key === 'ArrowUp') { - upHandler(); + setSelectedIndex((selectedIndex + items.length - 1) % items.length); return true; } if (event.key === 'ArrowDown') { - downHandler(); + setSelectedIndex((selectedIndex + 1) % items.length); return true; } if (event.key === 'Enter') { - enterHandler(); + selectItem(selectedIndex); return true; } @@ -61,12 +51,15 @@ export const VariableList = forwardRef((props: VariableListProps, ref) => { })); return ( -
+
{items.length ? ( items.map((item, index) => (