Skip to content

Commit ad1c4f4

Browse files
committed
fix: keep suggestion menus open during IME composition
1 parent dac995c commit ad1c4f4

4 files changed

Lines changed: 55 additions & 3 deletions

File tree

packages/react/src/components/SuggestionMenu/GridSuggestionMenu/GridSuggestionMenuWrapper.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FC, useCallback, useEffect } from "react";
44
import { useBlockNoteContext } from "../../../editor/BlockNoteContext.js";
55
import { useBlockNoteEditor } from "../../../hooks/useBlockNoteEditor.js";
66
import { useCloseSuggestionMenuNoItems } from "../hooks/useCloseSuggestionMenuNoItems.js";
7+
import { useEditorCompositionState } from "../hooks/useEditorCompositionState.js";
78
import { useLoadSuggestionMenuItems } from "../hooks/useLoadSuggestionMenuItems.js";
89
import { useGridSuggestionMenuKeyboardNavigation } from "./hooks/useGridSuggestionMenuKeyboardNavigation.js";
910
import { GridSuggestionMenuProps } from "./types.js";
@@ -48,8 +49,9 @@ export function GridSuggestionMenuWrapper<Item>(props: {
4849
query,
4950
getItems,
5051
);
52+
const isComposing = useEditorCompositionState(editor);
5153

52-
useCloseSuggestionMenuNoItems(items, usedQuery, closeMenu);
54+
useCloseSuggestionMenuNoItems(items, usedQuery, closeMenu, 3, isComposing);
5355

5456
const { selectedIndex } = useGridSuggestionMenuKeyboardNavigation(
5557
editor,

packages/react/src/components/SuggestionMenu/SuggestionMenuWrapper.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FC, useCallback, useEffect } from "react";
44
import { useBlockNoteContext } from "../../editor/BlockNoteContext.js";
55
import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js";
66
import { useCloseSuggestionMenuNoItems } from "./hooks/useCloseSuggestionMenuNoItems.js";
7+
import { useEditorCompositionState } from "./hooks/useEditorCompositionState.js";
78
import { useLoadSuggestionMenuItems } from "./hooks/useLoadSuggestionMenuItems.js";
89
import { useSuggestionMenuKeyboardNavigation } from "./hooks/useSuggestionMenuKeyboardNavigation.js";
910
import { SuggestionMenuProps } from "./types.js";
@@ -46,8 +47,9 @@ export function SuggestionMenuWrapper<Item>(props: {
4647
query,
4748
getItems,
4849
);
50+
const isComposing = useEditorCompositionState(editor);
4951

50-
useCloseSuggestionMenuNoItems(items, usedQuery, closeMenu);
52+
useCloseSuggestionMenuNoItems(items, usedQuery, closeMenu, 3, isComposing);
5153

5254
const { selectedIndex } = useSuggestionMenuKeyboardNavigation(
5355
editor,

packages/react/src/components/SuggestionMenu/hooks/useCloseSuggestionMenuNoItems.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export function useCloseSuggestionMenuNoItems<Item>(
88
usedQuery: string | undefined,
99
closeMenu: () => void,
1010
invalidQueries = 3,
11+
disabled = false,
1112
) {
1213
const lastUsefulQueryLength = useRef(0);
1314

@@ -16,6 +17,11 @@ export function useCloseSuggestionMenuNoItems<Item>(
1617
return;
1718
}
1819

20+
if (disabled) {
21+
lastUsefulQueryLength.current = usedQuery.length;
22+
return;
23+
}
24+
1925
if (items.length > 0) {
2026
lastUsefulQueryLength.current = usedQuery.length;
2127
} else if (
@@ -24,5 +30,5 @@ export function useCloseSuggestionMenuNoItems<Item>(
2430
) {
2531
closeMenu();
2632
}
27-
}, [closeMenu, invalidQueries, items.length, usedQuery]);
33+
}, [closeMenu, disabled, invalidQueries, items.length, usedQuery]);
2834
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { BlockNoteEditor } from "@blocknote/core";
2+
import { useEffect, useState } from "react";
3+
4+
import { useEditorDOMElement } from "../../../hooks/useEditorDomElement.js";
5+
6+
export function useEditorCompositionState(
7+
editor: BlockNoteEditor<any, any, any>,
8+
) {
9+
const editorDOMElement = useEditorDOMElement(editor);
10+
const [isComposing, setIsComposing] = useState(false);
11+
12+
useEffect(() => {
13+
const handleCompositionStart = () => setIsComposing(true);
14+
const handleCompositionEnd = () => setIsComposing(false);
15+
16+
editorDOMElement?.addEventListener(
17+
"compositionstart",
18+
handleCompositionStart,
19+
true,
20+
);
21+
editorDOMElement?.addEventListener(
22+
"compositionend",
23+
handleCompositionEnd,
24+
true,
25+
);
26+
27+
return () => {
28+
editorDOMElement?.removeEventListener(
29+
"compositionstart",
30+
handleCompositionStart,
31+
true,
32+
);
33+
editorDOMElement?.removeEventListener(
34+
"compositionend",
35+
handleCompositionEnd,
36+
true,
37+
);
38+
};
39+
}, [editorDOMElement]);
40+
41+
return isComposing;
42+
}

0 commit comments

Comments
 (0)