Note

IME Input Workaround for Slate 0.47

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);
}}

'25, Jan 26