Life is hard
Condition: No Slate upgrade
Problem 0: IME input breaks Solution: Fix problematic pattern
const onChange: OnChangeFn = (change) => {
// it's a workaround to fix typing issue in slate
if (
change.operations.size === 4 &&
// focus
change.operations.get(0).type === "set_selection" &&
// move to next one (offset +1)
// should be in the end, not here
change.operations.get(1).type === "set_selection" &&
// remove current text
change.operations.get(2).type === "remove_text" &&
// insert new text with typed charter
change.operations.get(3).type === "insert_text"
) {
articleStore.editor.applyOperation(change.operations.get(1));
}
// console.log("onChange updateActiveArticleValue");
articleStore.updateActiveArticleValue(change.value);
};
Problem 1: IME input anchor always at beginning
Solution: Disable Slate handlers for onKeyDown
, onChange
, onCompositionStart
, onCompositionEnd
, then manually insert value on onCompositionEnd
const onChange: OnChangeFn = (change) => {
if (isComposingRef.current) {
bufferedChange.current = change;
// console.log("onChange isComposing");
return;
}
// console.log("onChange updateActiveArticleValue");
articleStore.updateActiveArticleValue(change.value);
};
const onKeyDown: EventHook<React.KeyboardEvent> = async (
event,
editor,
next,
) => {
if (isComposingRef.current) {
// console.log("onKeyDown isComposing");
event.preventDefault();
return;
}
return next();
};
onCompositionStart={(event, editor, next) => {
// console.log("onCompositionStart", event);
event.preventDefault();
isComposingRef.current = true;
// next();
}}
onCompositionEnd={(event, editor, next) => {
// console.log("onCompositionEnd", event);
event.preventDefault();
// next();
setTimeout(() => {
isComposingRef.current = false;
}, 50);
}}
Problem 2: After fixing Problem 1, duplicate IME input occurs (e.g. “你好” becomes “你好你好” after pressing enter) Solution: Delete duplicates
onCompositionEnd={(event, editor, next) => {
// console.log("onCompositionEnd", event);
event.preventDefault();
if (event.data && event.data.length > 0) {
const composingText = event.data;
// console.log("composingText", composingText);
// 你好
const { selection } = editor.value;
editor.applyOperation({
type: "insert_text",
path: selection.anchor.path,
offset: selection.anchor.offset,
text: composingText,
});
// editor.value here would be "你好你好"
// workaround
editor.deleteBackward(composingText.length);
articleStore.updateActiveArticleValue(editor.value);
}
// next();
// timeout here to disable onChange
setTimeout(() => {
isComposingRef.current = false;
}, 50);
}}