From 83b1319c63ccc8058fde08870c11bc7b30630790 Mon Sep 17 00:00:00 2001 From: Marcin Grzywaczewski Date: Sat, 22 Feb 2020 16:57:50 +0100 Subject: [PATCH] Fix Paste without Formatting / Paste and Match Style producing uneditable text nodes. (#3415) * handle plaintext-only pastes using onPaste handler, regardless of browser * remove extra console.log; merge code paths in onPaste - they contain the same code --- packages/slate-react/src/components/editable.tsx | 6 +++++- packages/slate-react/src/utils/dom.ts | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) 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. */