mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-23 15:32:59 +02:00
feat: delete current line when deleting backward with line unit (#3364)
* feat: delete current line when deleting backward with line unit * Apply BrentFarase suggestions from code review Co-authored-by: Brent Farese <25846953+BrentFarese@users.noreply.github.com> * Update prettier formats and rebase on master Co-authored-by: Brent Farese <25846953+BrentFarese@users.noreply.github.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { ReactEditor } from './react-editor'
|
||||
import { Key } from '../utils/key'
|
||||
import { EDITOR_TO_ON_CHANGE, NODE_TO_KEY } from '../utils/weak-maps'
|
||||
import { isDOMText, getPlainText } from '../utils/dom'
|
||||
import { findCurrentLineRange } from '../utils/lines'
|
||||
|
||||
/**
|
||||
* `withReact` adds React and DOM specific behaviors to the editor.
|
||||
@@ -17,7 +18,35 @@ import { isDOMText, getPlainText } from '../utils/dom'
|
||||
|
||||
export const withReact = <T extends Editor>(editor: T) => {
|
||||
const e = editor as T & ReactEditor
|
||||
const { apply, onChange } = e
|
||||
const { apply, onChange, deleteBackward } = e
|
||||
|
||||
e.deleteBackward = unit => {
|
||||
if (unit !== 'line') {
|
||||
return deleteBackward(unit)
|
||||
}
|
||||
|
||||
if (editor.selection && Range.isCollapsed(editor.selection)) {
|
||||
const parentBlockEntry = Editor.above(editor, {
|
||||
match: n => Editor.isBlock(editor, n),
|
||||
at: editor.selection,
|
||||
})
|
||||
|
||||
if (parentBlockEntry) {
|
||||
const [, parentBlockPath] = parentBlockEntry
|
||||
const parentElementRange = Editor.range(
|
||||
editor,
|
||||
parentBlockPath,
|
||||
editor.selection.anchor
|
||||
)
|
||||
|
||||
const currentLineRange = findCurrentLineRange(e, parentElementRange)
|
||||
|
||||
if (!Range.isCollapsed(currentLineRange)) {
|
||||
Transforms.delete(editor, { at: currentLineRange })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e.apply = (op: Operation) => {
|
||||
const matches: [Path, Key][] = []
|
||||
|
79
packages/slate-react/src/utils/lines.ts
Normal file
79
packages/slate-react/src/utils/lines.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Utilities for single-line deletion
|
||||
*/
|
||||
|
||||
import { Range, Editor } from 'slate'
|
||||
import { ReactEditor } from '..'
|
||||
|
||||
const doRectsIntersect = (rect: DOMRect, compareRect: DOMRect) => {
|
||||
const middle = (compareRect.top + compareRect.bottom) / 2
|
||||
|
||||
return rect.top <= middle && rect.bottom >= middle
|
||||
}
|
||||
|
||||
const areRangesSameLine = (
|
||||
editor: ReactEditor,
|
||||
range1: Range,
|
||||
range2: Range
|
||||
) => {
|
||||
const rect1 = ReactEditor.toDOMRange(editor, range1).getBoundingClientRect()
|
||||
const rect2 = ReactEditor.toDOMRange(editor, range2).getBoundingClientRect()
|
||||
|
||||
return doRectsIntersect(rect1, rect2) && doRectsIntersect(rect2, rect1)
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper utility that returns the end portion of a `Range`
|
||||
* which is located on a single line.
|
||||
*
|
||||
* @param {Editor} editor The editor object to compare against
|
||||
* @param {Range} parentRange The parent range to compare against
|
||||
* @returns {Range} A valid portion of the parentRange which is one a single line
|
||||
*/
|
||||
export const findCurrentLineRange = (
|
||||
editor: ReactEditor,
|
||||
parentRange: Range
|
||||
): Range => {
|
||||
const parentRangeBoundary = Editor.range(editor, Range.end(parentRange))
|
||||
const positions = Array.from(Editor.positions(editor, { at: parentRange }))
|
||||
|
||||
let left = 0
|
||||
let right = positions.length
|
||||
let middle = Math.floor(right / 2)
|
||||
|
||||
if (
|
||||
areRangesSameLine(
|
||||
editor,
|
||||
Editor.range(editor, positions[left]),
|
||||
parentRangeBoundary
|
||||
)
|
||||
) {
|
||||
return Editor.range(editor, positions[left], parentRangeBoundary)
|
||||
}
|
||||
|
||||
if (positions.length < 2) {
|
||||
return Editor.range(
|
||||
editor,
|
||||
positions[positions.length - 1],
|
||||
parentRangeBoundary
|
||||
)
|
||||
}
|
||||
|
||||
while (middle !== positions.length && middle !== left) {
|
||||
if (
|
||||
areRangesSameLine(
|
||||
editor,
|
||||
Editor.range(editor, positions[middle]),
|
||||
parentRangeBoundary
|
||||
)
|
||||
) {
|
||||
right = middle
|
||||
} else {
|
||||
left = middle
|
||||
}
|
||||
|
||||
middle = Math.floor((left + right) / 2)
|
||||
}
|
||||
|
||||
return Editor.range(editor, positions[right], parentRangeBoundary)
|
||||
}
|
Reference in New Issue
Block a user