mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-21 22:02:05 +02:00
Fix bug: setting selection from contentEditable:false element causes crash (#4584)
* Fix bug: setting selection from contentEditable:false element causes crash Fixes https://github.com/ianstormtaylor/slate/issues/4583 When clicking some text in a `contentEditable:false` element, if the handler for this sets the selection, Slate crashes. Slate tries to find a Slate range for the text that was clicked on, but there is no such range, because the text is inside a `contentEditable:false` element. Slate seems to be making a bad assumption that the current DOM selection necessarily corresponds to a Slate range, but this is not the case if the user just clicked into an element with `contentEditable: false`. To fix this, I changed `exactMatch: false` to `exactMatch: true`, which seems to mean "fail gracefully if there is no exact match". * changeset * Revert "Fix bug: setting selection from contentEditable:false element causes crash" This reverts commit 71234284cd454993b139ce065a9ab2db431abce8. * Unconflate exactMatch flag: add suppressThrow flag for separate behavior * Fix bug: setting selection from contentEditable:false element causes crash Fixes #4583 When clicking some text in a `contentEditable:false` element, if the handler for this sets the selection, Slate crashes. Slate tries to find a Slate range for the text that was clicked on, but there is no such range, because the text is inside a `contentEditable:false` element. Slate seems to be making a bad assumption that the current DOM selection necessarily corresponds to a Slate range, but this is not the case if the user just clicked into an element with `contentEditable: false`.
This commit is contained in:
parent
43e740c88d
commit
f40e515dc7
5
.changeset/shy-brooms-notice.md
Normal file
5
.changeset/shy-brooms-notice.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'slate-react': patch
|
||||
---
|
||||
|
||||
Fixed bug: setting selection from `contentEditable:false` element causes crash
|
@ -124,6 +124,7 @@ export const AndroidEditable = (props: EditableProps): JSX.Element => {
|
||||
if (hasDomSelection && hasDomSelectionInEditor && selection) {
|
||||
const slateRange = ReactEditor.toSlateRange(editor, domSelection, {
|
||||
exactMatch: true,
|
||||
suppressThrow: true,
|
||||
})
|
||||
if (slateRange && Range.equals(slateRange, selection)) {
|
||||
return
|
||||
@ -137,6 +138,7 @@ export const AndroidEditable = (props: EditableProps): JSX.Element => {
|
||||
if (selection && !ReactEditor.hasRange(editor, selection)) {
|
||||
editor.selection = ReactEditor.toSlateRange(editor, domSelection, {
|
||||
exactMatch: false,
|
||||
suppressThrow: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -266,6 +268,7 @@ export const AndroidEditable = (props: EditableProps): JSX.Element => {
|
||||
if (anchorNodeSelectable && focusNodeSelectable) {
|
||||
const range = ReactEditor.toSlateRange(editor, domSelection, {
|
||||
exactMatch: false,
|
||||
suppressThrow: false,
|
||||
})
|
||||
Transforms.select(editor, range)
|
||||
} else {
|
||||
|
@ -183,6 +183,10 @@ export const Editable = (props: EditableProps) => {
|
||||
if (hasDomSelection && hasDomSelectionInEditor && selection) {
|
||||
const slateRange = ReactEditor.toSlateRange(editor, domSelection, {
|
||||
exactMatch: false,
|
||||
|
||||
// domSelection is not necessarily a valid Slate range
|
||||
// (e.g. when clicking on contentEditable:false element)
|
||||
suppressThrow: true,
|
||||
})
|
||||
if (slateRange && Range.equals(slateRange, selection)) {
|
||||
return
|
||||
@ -196,6 +200,7 @@ export const Editable = (props: EditableProps) => {
|
||||
if (selection && !ReactEditor.hasRange(editor, selection)) {
|
||||
editor.selection = ReactEditor.toSlateRange(editor, domSelection, {
|
||||
exactMatch: false,
|
||||
suppressThrow: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -323,6 +328,7 @@ export const Editable = (props: EditableProps) => {
|
||||
if (targetRange) {
|
||||
const range = ReactEditor.toSlateRange(editor, targetRange, {
|
||||
exactMatch: false,
|
||||
suppressThrow: false,
|
||||
})
|
||||
|
||||
if (!selection || !Range.equals(selection, range)) {
|
||||
@ -503,6 +509,7 @@ export const Editable = (props: EditableProps) => {
|
||||
if (anchorNodeSelectable && focusNodeSelectable) {
|
||||
const range = ReactEditor.toSlateRange(editor, domSelection, {
|
||||
exactMatch: false,
|
||||
suppressThrow: false,
|
||||
})
|
||||
Transforms.select(editor, range)
|
||||
}
|
||||
|
@ -430,6 +430,7 @@ export const ReactEditor = {
|
||||
// Resolve a Slate range from the DOM range.
|
||||
const range = ReactEditor.toSlateRange(editor, domRange, {
|
||||
exactMatch: false,
|
||||
suppressThrow: false,
|
||||
})
|
||||
return range
|
||||
},
|
||||
@ -441,8 +442,12 @@ export const ReactEditor = {
|
||||
toSlatePoint<T extends boolean>(
|
||||
editor: ReactEditor,
|
||||
domPoint: DOMPoint,
|
||||
exactMatch: T
|
||||
options: {
|
||||
exactMatch: T
|
||||
suppressThrow: T
|
||||
}
|
||||
): T extends true ? Point | null : Point {
|
||||
const { exactMatch, suppressThrow } = options
|
||||
const [nearestNode, nearestOffset] = exactMatch
|
||||
? domPoint
|
||||
: normalizeDOMPoint(domPoint)
|
||||
@ -522,7 +527,7 @@ export const ReactEditor = {
|
||||
}
|
||||
|
||||
if (!textNode) {
|
||||
if (exactMatch) {
|
||||
if (suppressThrow) {
|
||||
return null as T extends true ? Point | null : Point
|
||||
}
|
||||
throw new Error(
|
||||
@ -547,9 +552,10 @@ export const ReactEditor = {
|
||||
domRange: DOMRange | DOMStaticRange | DOMSelection,
|
||||
options: {
|
||||
exactMatch: T
|
||||
suppressThrow: T
|
||||
}
|
||||
): T extends true ? Range | null : Range {
|
||||
const { exactMatch } = options
|
||||
const { exactMatch, suppressThrow } = options
|
||||
const el = isDOMSelection(domRange)
|
||||
? domRange.anchorNode
|
||||
: domRange.startContainer
|
||||
@ -599,7 +605,7 @@ export const ReactEditor = {
|
||||
const anchor = ReactEditor.toSlatePoint(
|
||||
editor,
|
||||
[anchorNode, anchorOffset],
|
||||
exactMatch
|
||||
{ exactMatch, suppressThrow }
|
||||
)
|
||||
if (!anchor) {
|
||||
return null as T extends true ? Range | null : Range
|
||||
@ -607,7 +613,10 @@ export const ReactEditor = {
|
||||
|
||||
const focus = isCollapsed
|
||||
? anchor
|
||||
: ReactEditor.toSlatePoint(editor, [focusNode, focusOffset], exactMatch)
|
||||
: ReactEditor.toSlatePoint(editor, [focusNode, focusOffset], {
|
||||
exactMatch,
|
||||
suppressThrow,
|
||||
})
|
||||
if (!focus) {
|
||||
return null as T extends true ? Range | null : Range
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user