diff --git a/.changeset/thirty-starfishes-knock.md b/.changeset/thirty-starfishes-knock.md new file mode 100644 index 0000000000..33348d9d0a --- /dev/null +++ b/.changeset/thirty-starfishes-knock.md @@ -0,0 +1,5 @@ +--- +'slate-react': major +--- + +Firefox: fix wrong text highlighting with double-click diff --git a/packages/slate-react/src/plugin/react-editor.ts b/packages/slate-react/src/plugin/react-editor.ts index c47a2fd8c3..783b99e28a 100644 --- a/packages/slate-react/src/plugin/react-editor.ts +++ b/packages/slate-react/src/plugin/react-editor.ts @@ -534,7 +534,7 @@ export const ReactEditor = { editor: ReactEditor, domPoint: DOMPoint, options: { - exactMatch: T + exactMatch: boolean suppressThrow: T } ): T extends true ? Point | null : Point { @@ -703,7 +703,7 @@ export const ReactEditor = { editor: ReactEditor, domRange: DOMRange | DOMStaticRange | DOMSelection, options: { - exactMatch: T + exactMatch: boolean suppressThrow: T } ): T extends true ? Range | null : Range { @@ -754,16 +754,15 @@ export const ReactEditor = { ) } - const anchor = ReactEditor.toSlatePoint( - editor, - [anchorNode, anchorOffset], - { exactMatch, suppressThrow } - ) + let anchor = ReactEditor.toSlatePoint(editor, [anchorNode, anchorOffset], { + exactMatch, + suppressThrow, + }) if (!anchor) { return null as T extends true ? Range | null : Range } - const focus = isCollapsed + let focus = isCollapsed ? anchor : ReactEditor.toSlatePoint(editor, [focusNode, focusOffset], { exactMatch, @@ -773,6 +772,46 @@ export const ReactEditor = { return null as T extends true ? Range | null : Range } + /** + * suppose we have this document: + * + * { type: 'paragraph', + * children: [ + * { text: 'foo ' }, + * { text: 'bar' }, + * { text: ' baz' } + * ] + * } + * + * a double click on "bar" on chrome will create this range: + * + * anchor -> [0,1] offset 0 + * focus -> [0,1] offset 3 + * + * while on firefox will create this range: + * + * anchor -> [0,0] offset 4 + * focus -> [0,2] offset 0 + * + * let's try to fix it... + */ + + if (IS_FIREFOX && !isCollapsed && anchorNode !== focusNode) { + const isEnd = Editor.isEnd(editor, anchor!, anchor.path) + const isStart = Editor.isStart(editor, focus!, focus.path) + + if (isEnd) { + const after = Editor.after(editor, anchor as Point) + // Editor.after() might return undefined + anchor = (after || anchor!) as T extends true ? Point | null : Point + } + + if (isStart) { + const before = Editor.before(editor, focus as Point) + focus = (before || focus!) as T extends true ? Point | null : Point + } + } + let range: Range = { anchor: anchor as Point, focus: focus as Point } // if the selection is a hanging range that ends in a void // and the DOM focus is an Element