mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-12 02:03:59 +02:00
Fix selection handling with slow flush in mark placeholders on android, fix auto-capitalize after placeholder (#5084)
* Fix selection handling with slow flush in mark placeholders on android, fix auto-capitalize after placeholder * Add changeset * Correct typos
This commit is contained in:
5
.changeset/friendly-oranges-remain.md
Normal file
5
.changeset/friendly-oranges-remain.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'slate-react': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix selection handling with slow flush in mark placeholders on android, fix auto-capitalize after placeholder
|
@@ -222,7 +222,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
if (range) {
|
if (range) {
|
||||||
if (
|
if (
|
||||||
!ReactEditor.isComposing(editor) &&
|
!ReactEditor.isComposing(editor) &&
|
||||||
!androidInputManager?.hasPendingDiffs() &&
|
!androidInputManager?.hasPendingChanges() &&
|
||||||
!androidInputManager?.isFlushing()
|
!androidInputManager?.isFlushing()
|
||||||
) {
|
) {
|
||||||
Transforms.select(editor, range)
|
Transforms.select(editor, range)
|
||||||
@@ -784,11 +784,17 @@ export const Editable = (props: EditableProps) => {
|
|||||||
// before we receive the composition end event.
|
// before we receive the composition end event.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (marks) {
|
const { selection } = editor
|
||||||
EDITOR_TO_PENDING_INSERTION_MARKS.set(editor, marks)
|
if (selection) {
|
||||||
} else {
|
const { anchor } = selection
|
||||||
EDITOR_TO_PENDING_INSERTION_MARKS.delete(editor)
|
const { text, ...rest } = Node.leaf(editor, anchor.path)
|
||||||
|
if (!Text.equals(rest as Text, marks as Text, { loose: true })) {
|
||||||
|
EDITOR_TO_PENDING_INSERTION_MARKS.set(editor, marks)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EDITOR_TO_PENDING_INSERTION_MARKS.delete(editor)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1616,7 +1622,14 @@ export type RenderPlaceholderProps = {
|
|||||||
export const DefaultPlaceholder = ({
|
export const DefaultPlaceholder = ({
|
||||||
attributes,
|
attributes,
|
||||||
children,
|
children,
|
||||||
}: RenderPlaceholderProps) => <span {...attributes}>{children}</span>
|
}: RenderPlaceholderProps) => (
|
||||||
|
// COMPAT: Artificially add a line-break to the end on the placeholder element
|
||||||
|
// to prevent Android IMEs to pick up its content in autocorrect and to auto-capitalize the first letter
|
||||||
|
<span {...attributes}>
|
||||||
|
{children}
|
||||||
|
{IS_ANDROID && <br />}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A default memoized decorate function.
|
* A default memoized decorate function.
|
||||||
|
@@ -23,7 +23,7 @@ import {
|
|||||||
IS_COMPOSING,
|
IS_COMPOSING,
|
||||||
} from '../../utils/weak-maps'
|
} from '../../utils/weak-maps'
|
||||||
|
|
||||||
export type Action = { at: Point | Range; run: () => void }
|
export type Action = { at?: Point | Range; run: () => void }
|
||||||
|
|
||||||
// https://github.com/facebook/draft-js/blob/main/src/component/handlers/composition/DraftEditorCompositionHandler.js#L41
|
// https://github.com/facebook/draft-js/blob/main/src/component/handlers/composition/DraftEditorCompositionHandler.js#L41
|
||||||
// When using keyboard English association function, conpositionEnd triggered too fast, resulting in after `insertText` still maintain association state.
|
// When using keyboard English association function, conpositionEnd triggered too fast, resulting in after `insertText` still maintain association state.
|
||||||
@@ -48,6 +48,7 @@ export type AndroidInputManager = {
|
|||||||
|
|
||||||
hasPendingDiffs: () => boolean
|
hasPendingDiffs: () => boolean
|
||||||
hasPendingAction: () => boolean
|
hasPendingAction: () => boolean
|
||||||
|
hasPendingChanges: () => boolean
|
||||||
isFlushing: () => boolean | 'action'
|
isFlushing: () => boolean | 'action'
|
||||||
|
|
||||||
handleUserSelect: (range: Range | null) => void
|
handleUserSelect: (range: Range | null) => void
|
||||||
@@ -62,30 +63,6 @@ export type AndroidInputManager = {
|
|||||||
handleInput: () => void
|
handleInput: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function forceSwiftKeyUpdate(editor: ReactEditor) {
|
|
||||||
const { document } = ReactEditor.getWindow(editor)
|
|
||||||
debug('force ime update')
|
|
||||||
|
|
||||||
const div = document.createElement('div')
|
|
||||||
div.setAttribute('contenteditable', 'true')
|
|
||||||
div.setAttribute('display', 'none')
|
|
||||||
div.setAttribute('position', 'absolute')
|
|
||||||
div.setAttribute('top', '0')
|
|
||||||
div.setAttribute('left', '0')
|
|
||||||
div.textContent = ' '
|
|
||||||
|
|
||||||
document.body.appendChild(div)
|
|
||||||
const range = document.createRange()
|
|
||||||
range.selectNodeContents(div)
|
|
||||||
const selection = window.getSelection()
|
|
||||||
|
|
||||||
selection?.removeAllRanges()
|
|
||||||
selection?.addRange(range)
|
|
||||||
div.parentElement?.removeChild(div)
|
|
||||||
|
|
||||||
ReactEditor.focus(editor)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createAndroidInputManager({
|
export function createAndroidInputManager({
|
||||||
editor,
|
editor,
|
||||||
scheduleOnDOMSelectionChange,
|
scheduleOnDOMSelectionChange,
|
||||||
@@ -95,8 +72,9 @@ export function createAndroidInputManager({
|
|||||||
let compositionEndTimeoutId: ReturnType<typeof setTimeout> | null = null
|
let compositionEndTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||||
let flushTimeoutId: ReturnType<typeof setTimeout> | null = null
|
let flushTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||||
let actionTimeoutId: ReturnType<typeof setTimeout> | null = null
|
let actionTimeoutId: ReturnType<typeof setTimeout> | null = null
|
||||||
|
|
||||||
let idCounter = 0
|
let idCounter = 0
|
||||||
let isInsertAfterMarkPlaceholder = false
|
let insertPositionHint: StringDiff | null | false = false
|
||||||
|
|
||||||
const applyPendingSelection = () => {
|
const applyPendingSelection = () => {
|
||||||
const pendingSelection = EDITOR_TO_PENDING_SELECTION.get(editor)
|
const pendingSelection = EDITOR_TO_PENDING_SELECTION.get(editor)
|
||||||
@@ -121,17 +99,19 @@ export function createAndroidInputManager({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const target = Point.isPoint(action.at)
|
if (action.at) {
|
||||||
? normalizePoint(editor, action.at)
|
const target = Point.isPoint(action.at)
|
||||||
: normalizeRange(editor, action.at)
|
? normalizePoint(editor, action.at)
|
||||||
|
: normalizeRange(editor, action.at)
|
||||||
|
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetRange = Editor.range(editor, target)
|
const targetRange = Editor.range(editor, target)
|
||||||
if (!editor.selection || !Range.equals(editor.selection, targetRange)) {
|
if (!editor.selection || !Range.equals(editor.selection, targetRange)) {
|
||||||
Transforms.select(editor, target)
|
Transforms.select(editor, target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
action.run()
|
action.run()
|
||||||
@@ -142,6 +122,7 @@ export function createAndroidInputManager({
|
|||||||
clearTimeout(flushTimeoutId)
|
clearTimeout(flushTimeoutId)
|
||||||
flushTimeoutId = null
|
flushTimeoutId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actionTimeoutId) {
|
if (actionTimeoutId) {
|
||||||
clearTimeout(actionTimeoutId)
|
clearTimeout(actionTimeoutId)
|
||||||
actionTimeoutId = null
|
actionTimeoutId = null
|
||||||
@@ -156,6 +137,7 @@ export function createAndroidInputManager({
|
|||||||
flushing = true
|
flushing = true
|
||||||
setTimeout(() => (flushing = false))
|
setTimeout(() => (flushing = false))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasPendingAction()) {
|
if (hasPendingAction()) {
|
||||||
flushing = 'action'
|
flushing = 'action'
|
||||||
}
|
}
|
||||||
@@ -182,8 +164,9 @@ export function createAndroidInputManager({
|
|||||||
editor.marks = pendingMarks
|
editor.marks = pendingMarks
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pendingMarks) {
|
if (pendingMarks && insertPositionHint === false) {
|
||||||
isInsertAfterMarkPlaceholder = true
|
insertPositionHint = null
|
||||||
|
debug('insert after mark placeholder')
|
||||||
}
|
}
|
||||||
|
|
||||||
const range = targetRange(diff)
|
const range = targetRange(diff)
|
||||||
@@ -225,6 +208,7 @@ export function createAndroidInputManager({
|
|||||||
const selection = selectionRef?.unref()
|
const selection = selectionRef?.unref()
|
||||||
if (
|
if (
|
||||||
selection &&
|
selection &&
|
||||||
|
!EDITOR_TO_PENDING_SELECTION.get(editor) &&
|
||||||
(!editor.selection || !Range.equals(selection, editor.selection))
|
(!editor.selection || !Range.equals(selection, editor.selection))
|
||||||
) {
|
) {
|
||||||
Transforms.select(editor, selection)
|
Transforms.select(editor, selection)
|
||||||
@@ -252,6 +236,7 @@ export function createAndroidInputManager({
|
|||||||
EDITOR_TO_USER_MARKS.delete(editor)
|
EDITOR_TO_USER_MARKS.delete(editor)
|
||||||
if (userMarks !== undefined) {
|
if (userMarks !== undefined) {
|
||||||
editor.marks = userMarks
|
editor.marks = userMarks
|
||||||
|
editor.onChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +311,11 @@ export function createAndroidInputManager({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const scheduleAction = (at: Point | Range, run: () => void): void => {
|
const scheduleAction = (
|
||||||
|
run: () => void,
|
||||||
|
{ at }: { at?: Point | Range } = {}
|
||||||
|
): void => {
|
||||||
|
insertPositionHint = false
|
||||||
debug('scheduleAction', { at, run })
|
debug('scheduleAction', { at, run })
|
||||||
|
|
||||||
EDITOR_TO_PENDING_SELECTION.delete(editor)
|
EDITOR_TO_PENDING_SELECTION.delete(editor)
|
||||||
@@ -355,6 +344,14 @@ export function createAndroidInputManager({
|
|||||||
let targetRange: Range | null = null
|
let targetRange: Range | null = null
|
||||||
const data = (event as any).dataTransfer || event.data || undefined
|
const data = (event as any).dataTransfer || event.data || undefined
|
||||||
|
|
||||||
|
if (
|
||||||
|
insertPositionHint !== false &&
|
||||||
|
type !== 'insertText' &&
|
||||||
|
type !== 'insertCompositionText'
|
||||||
|
) {
|
||||||
|
insertPositionHint = false
|
||||||
|
}
|
||||||
|
|
||||||
let [nativeTargetRange] = (event as any).getTargetRanges()
|
let [nativeTargetRange] = (event as any).getTargetRanges()
|
||||||
if (nativeTargetRange) {
|
if (nativeTargetRange) {
|
||||||
targetRange = ReactEditor.toSlateRange(editor, nativeTargetRange, {
|
targetRange = ReactEditor.toSlateRange(editor, nativeTargetRange, {
|
||||||
@@ -403,8 +400,9 @@ export function createAndroidInputManager({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const direction = type.endsWith('Backward') ? 'backward' : 'forward'
|
const direction = type.endsWith('Backward') ? 'backward' : 'forward'
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(
|
||||||
Editor.deleteFragment(editor, { direction })
|
() => Editor.deleteFragment(editor, { direction }),
|
||||||
|
{ at: targetRange }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +410,9 @@ export function createAndroidInputManager({
|
|||||||
case 'deleteByComposition':
|
case 'deleteByComposition':
|
||||||
case 'deleteByCut':
|
case 'deleteByCut':
|
||||||
case 'deleteByDrag': {
|
case 'deleteByDrag': {
|
||||||
return scheduleAction(targetRange, () => Editor.deleteFragment(editor))
|
return scheduleAction(() => Editor.deleteFragment(editor), {
|
||||||
|
at: targetRange,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleteContent':
|
case 'deleteContent':
|
||||||
@@ -430,7 +430,9 @@ export function createAndroidInputManager({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return scheduleAction(targetRange, () => Editor.deleteForward(editor))
|
return scheduleAction(() => Editor.deleteForward(editor), {
|
||||||
|
at: targetRange,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleteContentBackward': {
|
case 'deleteContentBackward': {
|
||||||
@@ -455,58 +457,73 @@ export function createAndroidInputManager({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return scheduleAction(targetRange, () => Editor.deleteBackward(editor))
|
return scheduleAction(() => Editor.deleteBackward(editor), {
|
||||||
}
|
at: targetRange,
|
||||||
|
|
||||||
case 'deleteEntireSoftLine': {
|
|
||||||
return scheduleAction(targetRange, () => {
|
|
||||||
Editor.deleteBackward(editor, { unit: 'line' })
|
|
||||||
Editor.deleteForward(editor, { unit: 'line' })
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'deleteEntireSoftLine': {
|
||||||
|
return scheduleAction(
|
||||||
|
() => {
|
||||||
|
Editor.deleteBackward(editor, { unit: 'line' })
|
||||||
|
Editor.deleteForward(editor, { unit: 'line' })
|
||||||
|
},
|
||||||
|
{ at: targetRange }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
case 'deleteHardLineBackward': {
|
case 'deleteHardLineBackward': {
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(
|
||||||
Editor.deleteBackward(editor, { unit: 'block' })
|
() => Editor.deleteBackward(editor, { unit: 'block' }),
|
||||||
|
{ at: targetRange }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleteSoftLineBackward': {
|
case 'deleteSoftLineBackward': {
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(
|
||||||
Editor.deleteBackward(editor, { unit: 'line' })
|
() => Editor.deleteBackward(editor, { unit: 'line' }),
|
||||||
|
{ at: targetRange }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleteHardLineForward': {
|
case 'deleteHardLineForward': {
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(
|
||||||
Editor.deleteForward(editor, { unit: 'block' })
|
() => Editor.deleteForward(editor, { unit: 'block' }),
|
||||||
|
{ at: targetRange }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleteSoftLineForward': {
|
case 'deleteSoftLineForward': {
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(
|
||||||
Editor.deleteForward(editor, { unit: 'line' })
|
() => Editor.deleteForward(editor, { unit: 'line' }),
|
||||||
|
{ at: targetRange }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleteWordBackward': {
|
case 'deleteWordBackward': {
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(
|
||||||
Editor.deleteBackward(editor, { unit: 'word' })
|
() => Editor.deleteBackward(editor, { unit: 'word' }),
|
||||||
|
{ at: targetRange }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleteWordForward': {
|
case 'deleteWordForward': {
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(
|
||||||
Editor.deleteForward(editor, { unit: 'word' })
|
() => Editor.deleteForward(editor, { unit: 'word' }),
|
||||||
|
{ at: targetRange }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'insertLineBreak': {
|
case 'insertLineBreak': {
|
||||||
return scheduleAction(targetRange, () => Editor.insertSoftBreak(editor))
|
return scheduleAction(() => Editor.insertSoftBreak(editor), {
|
||||||
|
at: targetRange,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'insertParagraph': {
|
case 'insertParagraph': {
|
||||||
return scheduleAction(targetRange, () => Editor.insertBreak(editor))
|
return scheduleAction(() => Editor.insertBreak(editor), {
|
||||||
|
at: targetRange,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
case 'insertCompositionText':
|
case 'insertCompositionText':
|
||||||
case 'deleteCompositionText':
|
case 'deleteCompositionText':
|
||||||
@@ -517,15 +534,15 @@ export function createAndroidInputManager({
|
|||||||
case 'insertReplacementText':
|
case 'insertReplacementText':
|
||||||
case 'insertText': {
|
case 'insertText': {
|
||||||
if (data?.constructor.name === 'DataTransfer') {
|
if (data?.constructor.name === 'DataTransfer') {
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(() => ReactEditor.insertData(editor, data), {
|
||||||
ReactEditor.insertData(editor, data)
|
at: targetRange,
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof data === 'string' && data.includes('\n')) {
|
if (typeof data === 'string' && data.includes('\n')) {
|
||||||
return scheduleAction(Range.end(targetRange), () =>
|
return scheduleAction(() => Editor.insertSoftBreak(editor), {
|
||||||
Editor.insertSoftBreak(editor)
|
at: Range.end(targetRange),
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = data ?? ''
|
let text = data ?? ''
|
||||||
@@ -537,41 +554,80 @@ export function createAndroidInputManager({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Path.equals(targetRange.anchor.path, targetRange.focus.path)) {
|
if (Path.equals(targetRange.anchor.path, targetRange.focus.path)) {
|
||||||
// COMPAT: Swiftkey has a weird bug where the target range of the 2nd word
|
|
||||||
// inserted after a mark placeholder is inserted with a anchor offset off by 1.
|
|
||||||
// So writing 'some text' will result in 'some ttext'. If we force a IME update
|
|
||||||
// after inserting the first word, swiftkey will insert with the correct offset
|
|
||||||
if (text.endsWith(' ') && isInsertAfterMarkPlaceholder) {
|
|
||||||
isInsertAfterMarkPlaceholder = false
|
|
||||||
forceSwiftKeyUpdate(editor)
|
|
||||||
return scheduleAction(targetRange, () =>
|
|
||||||
Editor.insertText(editor, text)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const [start, end] = Range.edges(targetRange)
|
const [start, end] = Range.edges(targetRange)
|
||||||
return storeDiff(start.path, {
|
|
||||||
|
const diff = {
|
||||||
start: start.offset,
|
start: start.offset,
|
||||||
end: end.offset,
|
end: end.offset,
|
||||||
text,
|
text,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// COMPAT: Swiftkey has a weird bug where the target range of the 2nd word
|
||||||
|
// inserted after a mark placeholder is inserted with an anchor offset off by 1.
|
||||||
|
// So writing 'some text' will result in 'some ttext'. Luckily all 'normal' insert
|
||||||
|
// text events are fired with the correct target ranges, only the final 'insertComposition'
|
||||||
|
// isn't, so we can adjust the target range start offset if we are confident this is the
|
||||||
|
// swiftkey insert causing the issue.
|
||||||
|
if (text && insertPositionHint && type === 'insertCompositionText') {
|
||||||
|
const hintPosition =
|
||||||
|
insertPositionHint.start + insertPositionHint.text.search(/\S|$/)
|
||||||
|
const diffPosition = diff.start + diff.text.search(/\S|$/)
|
||||||
|
|
||||||
|
if (
|
||||||
|
diffPosition === hintPosition + 1 &&
|
||||||
|
diff.end ===
|
||||||
|
insertPositionHint.start + insertPositionHint.text.length
|
||||||
|
) {
|
||||||
|
debug('adjusting swiftKey insert position using hint')
|
||||||
|
diff.start -= 1
|
||||||
|
insertPositionHint = null
|
||||||
|
scheduleFlush()
|
||||||
|
} else {
|
||||||
|
insertPositionHint = false
|
||||||
|
}
|
||||||
|
} else if (type === 'insertText') {
|
||||||
|
if (insertPositionHint === null) {
|
||||||
|
insertPositionHint = diff
|
||||||
|
} else if (
|
||||||
|
insertPositionHint &&
|
||||||
|
Range.isCollapsed(targetRange) &&
|
||||||
|
insertPositionHint.end + insertPositionHint.text.length ===
|
||||||
|
start.offset
|
||||||
|
) {
|
||||||
|
insertPositionHint = {
|
||||||
|
...insertPositionHint,
|
||||||
|
text: insertPositionHint.text + text,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
insertPositionHint = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
insertPositionHint = false
|
||||||
|
}
|
||||||
|
|
||||||
|
storeDiff(start.path, diff)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return scheduleAction(targetRange, () =>
|
return scheduleAction(() => Editor.insertText(editor, text), {
|
||||||
Editor.insertText(editor, text)
|
at: targetRange,
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasPendingAction = () => {
|
const hasPendingAction = () => {
|
||||||
return !!EDITOR_TO_PENDING_ACTION.get(editor) || !!actionTimeoutId
|
return !!EDITOR_TO_PENDING_ACTION.get(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasPendingDiffs = () => {
|
const hasPendingDiffs = () => {
|
||||||
return !!EDITOR_TO_PENDING_DIFFS.get(editor)?.length
|
return !!EDITOR_TO_PENDING_DIFFS.get(editor)?.length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasPendingChanges = () => {
|
||||||
|
return hasPendingAction() || hasPendingDiffs()
|
||||||
|
}
|
||||||
|
|
||||||
const isFlushing = () => {
|
const isFlushing = () => {
|
||||||
return flushing
|
return flushing
|
||||||
}
|
}
|
||||||
@@ -584,13 +640,22 @@ export function createAndroidInputManager({
|
|||||||
flushTimeoutId = null
|
flushTimeoutId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathChanged =
|
const { selection } = editor
|
||||||
range &&
|
if (!range) {
|
||||||
(!editor.selection ||
|
return
|
||||||
!Path.equals(editor.selection.anchor.path, range?.anchor.path))
|
}
|
||||||
|
|
||||||
if (pathChanged) {
|
const pathChanged =
|
||||||
isInsertAfterMarkPlaceholder = false
|
!selection || !Path.equals(selection.anchor.path, range.anchor.path)
|
||||||
|
const parentPathChanged =
|
||||||
|
!selection ||
|
||||||
|
!Path.equals(
|
||||||
|
selection.anchor.path.slice(0, -1),
|
||||||
|
range.anchor.path.slice(0, -1)
|
||||||
|
)
|
||||||
|
|
||||||
|
if ((pathChanged && insertPositionHint) || parentPathChanged) {
|
||||||
|
insertPositionHint = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pathChanged || !hasPendingDiffs()) {
|
if (pathChanged || !hasPendingDiffs()) {
|
||||||
@@ -643,6 +708,8 @@ export function createAndroidInputManager({
|
|||||||
|
|
||||||
hasPendingDiffs,
|
hasPendingDiffs,
|
||||||
hasPendingAction,
|
hasPendingAction,
|
||||||
|
hasPendingChanges,
|
||||||
|
|
||||||
isFlushing,
|
isFlushing,
|
||||||
|
|
||||||
handleUserSelect,
|
handleUserSelect,
|
||||||
|
@@ -124,8 +124,9 @@ export const withReact = <T extends Editor>(editor: T) => {
|
|||||||
transformPendingRange(editor, pendingSelection, op)
|
transformPendingRange(editor, pendingSelection, op)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const pendingAction = EDITOR_TO_PENDING_ACTION.get(editor)
|
const pendingAction = EDITOR_TO_PENDING_ACTION.get(editor)
|
||||||
if (pendingAction) {
|
if (pendingAction?.at) {
|
||||||
const at = Point.isPoint(pendingAction?.at)
|
const at = Point.isPoint(pendingAction?.at)
|
||||||
? transformPendingPoint(editor, pendingAction.at, op)
|
? transformPendingPoint(editor, pendingAction.at, op)
|
||||||
: transformPendingRange(editor, pendingAction.at, op)
|
: transformPendingRange(editor, pendingAction.at, op)
|
||||||
|
Reference in New Issue
Block a user