diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index ad3738e1d..6720297dc 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -26,6 +26,7 @@ import { isDOMNode, isDOMText, DOMStaticRange, + isPlainTextOnlyPaste, } from '../utils/dom' import { EDITOR_TO_ELEMENT, @@ -888,8 +889,11 @@ export const Editable = (props: EditableProps) => { (event: React.ClipboardEvent) => { // COMPAT: Firefox doesn't support the `beforeinput` event, so we // fall back to React's `onPaste` here instead. + // COMPAT: Firefox, Chrome and Safari are not emitting `beforeinput` events + // when "paste without formatting" option is used. + // This unfortunately needs to be handled with paste events instead. if ( - IS_FIREFOX && + (IS_FIREFOX || isPlainTextOnlyPaste(event.nativeEvent)) && !readOnly && hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onPaste) diff --git a/packages/slate-react/src/utils/dom.ts b/packages/slate-react/src/utils/dom.ts index 862deb437..e4b0490e4 100644 --- a/packages/slate-react/src/utils/dom.ts +++ b/packages/slate-react/src/utils/dom.ts @@ -56,6 +56,18 @@ export const isDOMText = (value: any): value is DOMText => { return isDOMNode(value) && value.nodeType === 3 } +/** + * Checks whether a paste event is a plaintext-only event. + */ + +export const isPlainTextOnlyPaste = (event: ClipboardEvent) => { + return ( + event.clipboardData && + event.clipboardData.getData('text/plain') !== '' && + event.clipboardData.types.length === 1 + ) +} + /** * Normalize a DOM point so that it always refers to a text node. */