From cb8a551508c023346fd3aa0af1a5a80ffd6a37cd Mon Sep 17 00:00:00 2001 From: Eric Meier Date: Mon, 2 May 2022 15:09:42 -0400 Subject: [PATCH] Add ReactEditor.isComposing(editor) (#4981) * Add ReactEditor.isComposing(editor) * Upate changeset from patch to minor --- .changeset/odd-cats-tie.md | 5 +++ docs/libraries/slate-react.md | 4 ++ .../android/android-input-manager.ts | 3 +- .../slate-react/src/components/editable.tsx | 39 ++++++++++++------- .../slate-react/src/plugin/react-editor.ts | 9 +++++ 5 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 .changeset/odd-cats-tie.md diff --git a/.changeset/odd-cats-tie.md b/.changeset/odd-cats-tie.md new file mode 100644 index 0000000000..c92b987b4d --- /dev/null +++ b/.changeset/odd-cats-tie.md @@ -0,0 +1,5 @@ +--- +'slate-react': minor +--- + +Add `ReactEditor.isComposing(editor)` to get the current `isComposing` state diff --git a/docs/libraries/slate-react.md b/docs/libraries/slate-react.md index 55d0784ec0..5cdbbf91ab 100644 --- a/docs/libraries/slate-react.md +++ b/docs/libraries/slate-react.md @@ -104,6 +104,10 @@ Get the current editor object from the React context. A version of useSlate that A React and DOM-specific version of the `Editor` interface. All about translating between the DOM and Slate. +### `isComposing(editor: ReactEditor)` + +Check if the user is currently composing inside the editor. + ### `findKey(editor: ReactEditor, node: Node)` Find a key for a Slate node. diff --git a/packages/slate-react/src/components/android/android-input-manager.ts b/packages/slate-react/src/components/android/android-input-manager.ts index e9fe4fff72..90cd531619 100644 --- a/packages/slate-react/src/components/android/android-input-manager.ts +++ b/packages/slate-react/src/components/android/android-input-manager.ts @@ -1,7 +1,6 @@ import { ReactEditor } from '../../plugin/react-editor' import { Editor, Range, Transforms, Text } from 'slate' import { - IS_COMPOSING, IS_ON_COMPOSITION_END, EDITOR_ON_COMPOSITION_TEXT, } from '../../utils/weak-maps' @@ -113,7 +112,7 @@ export class AndroidInputManager { // If it is in composing or after `onCompositionend`, set `EDITOR_ON_COMPOSITION_TEXT` and return. // Text will be inserted on compositionend event. if ( - IS_COMPOSING.get(this.editor) || + ReactEditor.isComposing(this.editor) || IS_ON_COMPOSITION_END.get(this.editor) ) { EDITOR_ON_COMPOSITION_TEXT.set(this.editor, insertedText) diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index e015cd4779..31a7061126 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -54,6 +54,7 @@ import { PLACEHOLDER_SYMBOL, EDITOR_TO_WINDOW, EDITOR_TO_USER_SELECTION, + IS_COMPOSING, } from '../utils/weak-maps' import { TRIPLE_CLICK } from '../utils/constants' @@ -141,7 +142,6 @@ export const Editable = (props: EditableProps) => { // Keep track of some state for the event handler logic. const state = useMemo( () => ({ - isComposing: false, hasInsertPrefixInCompositon: false, isDraggingInternally: false, isUpdatingSelection: false, @@ -168,7 +168,11 @@ export const Editable = (props: EditableProps) => { const root = ReactEditor.findDocumentOrShadowRoot(editor) const domSelection = root.getSelection() - if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) { + if ( + ReactEditor.isComposing(editor) || + !domSelection || + !ReactEditor.isFocused(editor) + ) { return } @@ -268,7 +272,7 @@ export const Editable = (props: EditableProps) => { const onDOMSelectionChange = useCallback( throttle(() => { if ( - !state.isComposing && + !ReactEditor.isComposing(editor) && !state.isUpdatingSelection && !state.isDraggingInternally ) { @@ -516,8 +520,10 @@ export const Editable = (props: EditableProps) => { // then we will abort because we're still composing and the selection // won't be updated properly. // https://www.w3.org/TR/input-events-2/ - state.isComposing && setIsComposing(false) - state.isComposing = false + if (ReactEditor.isComposing(editor)) { + setIsComposing(false) + IS_COMPOSING.set(editor, false) + } } // use a weak comparison instead of 'instanceof' to allow @@ -674,7 +680,7 @@ export const Editable = (props: EditableProps) => { hasEditableTarget(editor, event.target) ) { event.preventDefault() - if (!state.isComposing) { + if (!ReactEditor.isComposing(editor)) { const text = (event as any).data as string Editor.insertText(editor, text) } @@ -822,8 +828,10 @@ export const Editable = (props: EditableProps) => { hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionEnd) ) { - state.isComposing && setIsComposing(false) - state.isComposing = false + if (ReactEditor.isComposing(editor)) { + setIsComposing(false) + IS_COMPOSING.set(editor, false) + } // COMPAT: In Chrome, `beforeinput` events for compositions // aren't correct and never fire the "insertFromComposition" @@ -867,8 +875,10 @@ export const Editable = (props: EditableProps) => { hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionUpdate) ) { - !state.isComposing && setIsComposing(true) - state.isComposing = true + if (!ReactEditor.isComposing(editor)) { + setIsComposing(true) + IS_COMPOSING.set(editor, true) + } } }, [attributes.onCompositionUpdate] @@ -1096,14 +1106,17 @@ export const Editable = (props: EditableProps) => { // COMPAT: The composition end event isn't fired reliably in all browsers, // so we sometimes might end up stuck in a composition state even though we // aren't composing any more. - if (state.isComposing && nativeEvent.isComposing === false) { - state.isComposing = false + if ( + ReactEditor.isComposing(editor) && + nativeEvent.isComposing === false + ) { + IS_COMPOSING.set(editor, false) setIsComposing(false) } if ( isEventHandled(event, attributes.onKeyDown) || - state.isComposing + ReactEditor.isComposing(editor) ) { return } diff --git a/packages/slate-react/src/plugin/react-editor.ts b/packages/slate-react/src/plugin/react-editor.ts index 83a429f99e..6780382496 100644 --- a/packages/slate-react/src/plugin/react-editor.ts +++ b/packages/slate-react/src/plugin/react-editor.ts @@ -11,6 +11,7 @@ import { NODE_TO_PARENT, EDITOR_TO_WINDOW, EDITOR_TO_KEY_TO_ELEMENT, + IS_COMPOSING, } from '../utils/weak-maps' import { DOMElement, @@ -42,6 +43,14 @@ export interface ReactEditor extends BaseEditor { } export const ReactEditor = { + /** + * Check if the user is currently composing inside the editor. + */ + + isComposing(editor: ReactEditor): boolean { + return !!IS_COMPOSING.get(editor) + }, + /** * Return the host window of the current editor. */