diff --git a/.changeset/android-text-mutations.md b/.changeset/android-text-mutations.md new file mode 100644 index 000000000..406d268c1 --- /dev/null +++ b/.changeset/android-text-mutations.md @@ -0,0 +1,5 @@ +--- +'slate-react': patch +--- + +The `RestoreDOM` manager that is used Android no longer restores the DOM to its previous state for text mutations. This allows the editor state to be reconciled during a composition without interrupting the composition, as programatically updating the `textContent` of a text node ends the current composition. diff --git a/.changeset/consumer-oninput-event.md b/.changeset/consumer-oninput-event.md new file mode 100644 index 000000000..8059004cd --- /dev/null +++ b/.changeset/consumer-oninput-event.md @@ -0,0 +1,5 @@ +--- +'slate-react': patch +--- + +Fixed consumer defined `onInput` event handler not being invoked when passed to the `` component. diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index 31375dc71..57f06c5fc 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -894,7 +894,11 @@ export const Editable = (props: EditableProps) => { }, [readOnly] )} - onInput={useCallback((event: React.SyntheticEvent) => { + onInput={useCallback((event: React.FormEvent) => { + if (isEventHandled(event, attributes.onInput)) { + return + } + if (androidInputManager) { androidInputManager.handleInput() return diff --git a/packages/slate-react/src/components/restore-dom/restore-dom-manager.ts b/packages/slate-react/src/components/restore-dom/restore-dom-manager.ts index 37285dd67..bfcd25cfc 100644 --- a/packages/slate-react/src/components/restore-dom/restore-dom-manager.ts +++ b/packages/slate-react/src/components/restore-dom/restore-dom-manager.ts @@ -31,23 +31,26 @@ export const createRestoreDomManager = ( } function restoreDOM() { - bufferedMutations.reverse().forEach(mutation => { - if (mutation.type === 'characterData') { - mutation.target.textContent = mutation.oldValue - return - } + if (bufferedMutations.length > 0) { + bufferedMutations.reverse().forEach(mutation => { + if (mutation.type === 'characterData') { + // We don't want to restore the DOM for characterData mutations + // because this interrupts the composition. + return + } - mutation.removedNodes.forEach(node => { - mutation.target.insertBefore(node, mutation.nextSibling) + mutation.removedNodes.forEach(node => { + mutation.target.insertBefore(node, mutation.nextSibling) + }) + + mutation.addedNodes.forEach(node => { + mutation.target.removeChild(node) + }) }) - mutation.addedNodes.forEach(node => { - mutation.target.removeChild(node) - }) - }) - - // Clear buffered mutations to ensure we don't undo them twice - clear() + // Clear buffered mutations to ensure we don't undo them twice + clear() + } } return {