fix: handle Ctrl/Cmd+Enter directly in suggestion onKeyDown handlers

The TipTap suggestion plugin intercepts key events at the plugin level,
which runs before extension keyboard shortcuts. Even returning false
from the suggestion's onKeyDown didn't properly propagate events.

Now the suggestion handlers directly handle Ctrl/Cmd+Enter by:
1. Capturing the editor reference from onStart (where it's available)
2. Checking for Ctrl/Cmd+Enter in onKeyDown
3. Closing the popup and calling handleSubmitRef.current()

Also moved handleSubmitRef to the top of the component so it can be
accessed from within the suggestion config closures.
This commit is contained in:
Claude
2026-01-12 10:51:15 +00:00
parent ae461c60c9
commit c6589bf30f

View File

@@ -157,6 +157,9 @@ export const MentionEditor = forwardRef<
},
ref,
) => {
// Ref to access handleSubmit from suggestion plugins (defined early so useMemo can access it)
const handleSubmitRef = useRef<(editor: any) => void>(() => {});
// Create mention suggestion configuration for @ mentions
const mentionSuggestion: Omit<SuggestionOptions, "editor"> = useMemo(
() => ({
@@ -168,9 +171,11 @@ export const MentionEditor = forwardRef<
render: () => {
let component: ReactRenderer<ProfileSuggestionListHandle>;
let popup: TippyInstance[];
let editorRef: any;
return {
onStart: (props) => {
editorRef = props.editor;
component = new ReactRenderer(ProfileSuggestionList, {
props: {
items: props.items,
@@ -218,6 +223,16 @@ export const MentionEditor = forwardRef<
return true;
}
// Ctrl/Cmd+Enter submits the message
if (
props.event.key === "Enter" &&
(props.event.ctrlKey || props.event.metaKey)
) {
popup[0]?.hide();
handleSubmitRef.current(editorRef);
return true;
}
return component.ref?.onKeyDown(props.event) ?? false;
},
@@ -244,9 +259,11 @@ export const MentionEditor = forwardRef<
render: () => {
let component: ReactRenderer<EmojiSuggestionListHandle>;
let popup: TippyInstance[];
let editorRef: any;
return {
onStart: (props) => {
editorRef = props.editor;
component = new ReactRenderer(EmojiSuggestionList, {
props: {
items: props.items,
@@ -294,6 +311,16 @@ export const MentionEditor = forwardRef<
return true;
}
// Ctrl/Cmd+Enter submits the message
if (
props.event.key === "Enter" &&
(props.event.ctrlKey || props.event.metaKey)
) {
popup[0]?.hide();
handleSubmitRef.current(editorRef);
return true;
}
return component.ref?.onKeyDown(props.event) ?? false;
},
@@ -377,8 +404,7 @@ export const MentionEditor = forwardRef<
[onSubmit, serializeContent],
);
// Ref to access handleSubmit from keyboard extension without recreating it
const handleSubmitRef = useRef(handleSubmit);
// Keep ref updated with latest handleSubmit
handleSubmitRef.current = handleSubmit;
// Build extensions array