Skip to content

Commit

Permalink
Fix pasting content with newlines on Android (#5359)
Browse files Browse the repository at this point in the history
* Improve InputEvent data type

* Fix insertion of content with newlines on Android

* Slice the trailing newline off of pasted text

* Add changeset
  • Loading branch information
jason0x43 authored Mar 16, 2023
1 parent 4399935 commit 9825d29
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/rude-bikes-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'slate-react': patch
---

Fix an issue on Android where content containing a newline wouldn't be pasted properly
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const FLUSH_DELAY = 200
// Replace with `const debug = console.log` to debug
const debug = (..._: unknown[]) => {}

// Type guard to check if a value is a DataTransfer
const isDataTransfer = (value: any): value is DataTransfer =>
value?.constructor.name === 'DataTransfer'

export type CreateAndroidInputManagerOptions = {
editor: ReactEditor

Expand Down Expand Up @@ -343,7 +347,8 @@ export function createAndroidInputManager({

const { inputType: type } = event
let targetRange: Range | null = null
const data = (event as any).dataTransfer || event.data || undefined
const data: DataTransfer | string | undefined =
(event as any).dataTransfer || event.data || undefined

if (
insertPositionHint !== false &&
Expand Down Expand Up @@ -577,18 +582,12 @@ export function createAndroidInputManager({
case 'insertFromYank':
case 'insertReplacementText':
case 'insertText': {
if (data?.constructor.name === 'DataTransfer') {
if (isDataTransfer(data)) {
return scheduleAction(() => ReactEditor.insertData(editor, data), {
at: targetRange,
})
}

if (typeof data === 'string' && data.includes('\n')) {
return scheduleAction(() => Editor.insertSoftBreak(editor), {
at: Range.end(targetRange),
})
}

let text = data ?? ''

// COMPAT: If we are writing inside a placeholder, the ime inserts the text inside
Expand All @@ -597,6 +596,34 @@ export function createAndroidInputManager({
text = text.replace('\uFEFF', '')
}

// Pastes from the Android clipboard will generate `insertText` events.
// If the copied text contains any newlines, Android will append an
// extra newline to the end of the copied text.
if (type === 'insertText' && /.*\n.*\n$/.test(text)) {
text = text.slice(0, -1)
}

// If the text includes a newline, split it at newlines and paste each component
// string, with soft breaks in between each.
if (text.includes('\n')) {
return scheduleAction(
() => {
const parts = text.split('\n')
parts.forEach((line, i) => {
if (line) {
Editor.insertText(editor, line)
}
if (i !== parts.length - 1) {
Editor.insertSoftBreak(editor)
}
})
},
{
at: targetRange,
}
)
}

if (Path.equals(targetRange.anchor.path, targetRange.focus.path)) {
const [start, end] = Range.edges(targetRange)

Expand Down

0 comments on commit 9825d29

Please sign in to comment.