From e3e4e1d9d350b8a34b6392d69f10c4489c95627e Mon Sep 17 00:00:00 2001 From: Algorithm5838 <108630393+Algorithm5838@users.noreply.github.com> Date: Tue, 10 Feb 2026 01:15:08 +0300 Subject: [PATCH] fix: handle Gboard clipboard strip multi-line paste via beforeinput (#21265) Gboard's clipboard suggestion strip sends multi-line pastes as 'insertText' in beforeinput rather than a standard paste event, causing ProseMirror to drop the text content and insert only a newline. Add a beforeinput handler that intercepts multi-line insertText events on Android and manually inserts with hard breaks to preserve the formatting. --- .../components/common/RichTextInput.svelte | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index f7447551f..28221cd39 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -897,6 +897,34 @@ oncompositionend(event); return false; }, + beforeinput: (view, event) => { + // Workaround for Gboard's clipboard suggestion strip which sends + // multi-line pastes as 'insertText' rather than a standard paste event. + // Manually insert with hard breaks to preserve multi-line formatting. + const isAndroid = /Android/i.test(navigator.userAgent); + if (isAndroid && event.inputType === 'insertText' && event.data?.includes('\n')) { + event.preventDefault(); + + const { state, dispatch } = view; + const { from, to } = state.selection; + const lines = event.data.split('\n'); + const nodes = []; + + lines.forEach((line, index) => { + if (index > 0) { + nodes.push(state.schema.nodes.hardBreak.create()); + } + if (line.length > 0) { + nodes.push(state.schema.text(line)); + } + }); + + const fragment = Fragment.fromArray(nodes); + dispatch(state.tr.replaceWith(from, to, fragment).scrollIntoView()); + return true; + } + return false; + }, focus: (view, event) => { eventDispatch('focus', { event }); return false;