Skip to content

Commit 1fa54c7

Browse files
committed
fix: handle Gboard clipboard strip multi-line paste via beforeinput
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.
1 parent 547c587 commit 1fa54c7

1 file changed

Lines changed: 28 additions & 0 deletions

File tree

src/lib/components/common/RichTextInput.svelte

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,34 @@
897897
oncompositionend(event);
898898
return false;
899899
},
900+
beforeinput: (view, event) => {
901+
// Workaround for Gboard's clipboard suggestion strip which sends
902+
// multi-line pastes as 'insertText' rather than a standard paste event.
903+
// Manually insert with hard breaks to preserve multi-line formatting.
904+
const isAndroid = /Android/i.test(navigator.userAgent);
905+
if (isAndroid && event.inputType === 'insertText' && event.data?.includes('\n')) {
906+
event.preventDefault();
907+
908+
const { state, dispatch } = view;
909+
const { from, to } = state.selection;
910+
const lines = event.data.split('\n');
911+
const nodes = [];
912+
913+
lines.forEach((line, index) => {
914+
if (index > 0) {
915+
nodes.push(state.schema.nodes.hardBreak.create());
916+
}
917+
if (line.length > 0) {
918+
nodes.push(state.schema.text(line));
919+
}
920+
});
921+
922+
const fragment = Fragment.fromArray(nodes);
923+
dispatch(state.tr.replaceWith(from, to, fragment).scrollIntoView());
924+
return true;
925+
}
926+
return false;
927+
},
900928
focus: (view, event) => {
901929
eventDispatch('focus', { event });
902930
return false;

0 commit comments

Comments
 (0)