diff --git a/components/custom/canvas.tsx b/components/custom/canvas.tsx index b33b259..f2e7288 100644 --- a/components/custom/canvas.tsx +++ b/components/custom/canvas.tsx @@ -180,13 +180,18 @@ export function Canvas({ ); const handleEditorChange = useCallback( - (updatedContent: string) => { + (updatedContent: string, debounce: boolean) => { if (document && updatedContent !== document.content) { - debouncedHandleEditorChange(updatedContent); + if (debounce) { + debouncedHandleEditorChange(updatedContent); + } else { + handleContentChange(updatedContent); + } + setIsContentDirty(true); } }, - [document, debouncedHandleEditorChange] + [document, debouncedHandleEditorChange, handleContentChange] ); function getDocumentContentById(index: number) { diff --git a/components/custom/editor.tsx b/components/custom/editor.tsx index 8700268..ff5421d 100644 --- a/components/custom/editor.tsx +++ b/components/custom/editor.tsx @@ -44,7 +44,7 @@ interface WidgetRoot { type EditorProps = { content: string; - onChange: (updatedContent: string) => void; + onChange: (updatedContent: string, debounce: boolean) => void; status: 'streaming' | 'idle'; currentVersionIndex: number; suggestions: Array; @@ -95,7 +95,12 @@ function PureEditor({ if (transaction.docChanged) { const content = defaultMarkdownSerializer.serialize(newState.doc); - onChange(content); + + if (transaction.getMeta('no-debounce')) { + onChange(content, false); + } else { + onChange(content, true); + } } }, }); @@ -137,19 +142,34 @@ function PureEditor({ suggestions.forEach((suggestion) => { decorations.push( - Decoration.inline(suggestion.selectionStart, suggestion.selectionEnd, { - class: - 'suggestion-highlight bg-yellow-100 hover:bg-yellow-200 dark:hover:bg-yellow-400/50 dark:text-yellow-50 dark:bg-yellow-400/40', - }) + Decoration.inline( + suggestion.selectionStart, + suggestion.selectionEnd, + { + class: + 'suggestion-highlight bg-yellow-100 hover:bg-yellow-200 dark:hover:bg-yellow-400/50 dark:text-yellow-50 dark:bg-yellow-400/40', + }, + { + suggestionId: suggestion.id, + type: 'highlight', + } + ) ); decorations.push( - Decoration.widget(suggestion.selectionStart, (view) => { - const { dom, destroy } = createSuggestionWidget(suggestion, view); - const key = `widget-${suggestion.id}`; - widgetRootsRef.current.set(key, { destroy }); - return dom; - }) + Decoration.widget( + suggestion.selectionStart, + (view) => { + const { dom, destroy } = createSuggestionWidget(suggestion, view); + const key = `widget-${suggestion.id}`; + widgetRootsRef.current.set(key, { destroy }); + return dom; + }, + { + suggestionId: suggestion.id, + type: 'widget', + } + ) ); }); diff --git a/components/custom/suggestion.tsx b/components/custom/suggestion.tsx index ad125ae..13f9954 100644 --- a/components/custom/suggestion.tsx +++ b/components/custom/suggestion.tsx @@ -6,6 +6,7 @@ import { useState } from 'react'; import { UISuggestion } from '@/lib/editor/suggestions'; import { CrossIcon, MessageIcon } from './icons'; +import useWindowSize from './use-window-size'; import { Button } from '../ui/button'; export const Suggestion = ({ @@ -16,15 +17,16 @@ export const Suggestion = ({ onApply: () => void; }) => { const [isExpanded, setIsExpanded] = useState(false); + const { width: windowWidth } = useWindowSize(); return !isExpanded ? (
{ setIsExpanded(true); }} > - +
) : ( { + event.preventDefault(); + view.dom.blur(); + }); + const onApply = () => { const { state, dispatch } = view; - const tr = state.tr.replaceWith( + + let decorationTransaction = state.tr; + const currentState = suggestionsPluginKey.getState(state); + const currentDecorations = currentState?.decorations; + + if (currentDecorations) { + const newDecorations = DecorationSet.create( + state.doc, + currentDecorations.find().filter((decoration: Decoration) => { + return decoration.spec.suggestionId !== suggestion.id; + }) + ); + + decorationTransaction.setMeta(suggestionsPluginKey, { + decorations: newDecorations, + selected: null, + }); + dispatch(decorationTransaction); + } + + const textTransaction = view.state.tr.replaceWith( suggestion.selectionStart, suggestion.selectionEnd, state.schema.text(suggestion.suggestedText) ); - dispatch(tr); + textTransaction.setMeta('no-debounce', true); + + dispatch(textTransaction); }; root.render();