diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index 39dd8d963..78cc5bf9b 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -91,6 +91,7 @@ export type EditableProps = { renderElement?: (props: RenderElementProps) => JSX.Element renderLeaf?: (props: RenderLeafProps) => JSX.Element renderPlaceholder?: (props: RenderPlaceholderProps) => JSX.Element + scrollSelectionIntoView?: (editor: ReactEditor, domRange: DOMRange) => void as?: React.ElementType } & React.TextareaHTMLAttributes @@ -108,6 +109,7 @@ export const Editable = (props: EditableProps) => { renderElement, renderLeaf, renderPlaceholder = props => , + scrollSelectionIntoView = defaultScrollSelectionIntoView, style = {}, as: Component = 'div', ...attributes @@ -192,7 +194,6 @@ export const Editable = (props: EditableProps) => { } // Otherwise the DOM selection is out of sync, so update it. - const el = ReactEditor.toDOMNode(editor, editor) state.isUpdatingSelection = true const newDomRange = selection && ReactEditor.toDOMRange(editor, selection) @@ -213,15 +214,7 @@ export const Editable = (props: EditableProps) => { newDomRange.endOffset ) } - const leafEl = newDomRange.startContainer.parentElement! - leafEl.getBoundingClientRect = newDomRange.getBoundingClientRect.bind( - newDomRange - ) - scrollIntoView(leafEl, { - scrollMode: 'if-needed', - }) - // @ts-ignore - delete leafEl.getBoundingClientRect + scrollSelectionIntoView(editor, newDomRange) } else { domSelection.removeAllRanges() } @@ -230,6 +223,7 @@ export const Editable = (props: EditableProps) => { // COMPAT: In Firefox, it's not enough to create a range, you also need // to focus the contenteditable element too. (2016/11/16) if (newDomRange && IS_FIREFOX) { + const el = ReactEditor.toDOMNode(editor, editor) el.focus() } @@ -1169,6 +1163,22 @@ export const DefaultPlaceholder = ({ export const defaultDecorate: (entry: NodeEntry) => Range[] = () => [] +/** + * A default implement to scroll dom range into view. + */ + +const defaultScrollSelectionIntoView = ( + editor: ReactEditor, + domRange: DOMRange +) => { + const leafEl = domRange.startContainer.parentElement! + leafEl.getBoundingClientRect = domRange.getBoundingClientRect.bind(domRange) + scrollIntoView(leafEl, { + scrollMode: 'if-needed', + }) + delete leafEl.getBoundingClientRect +} + /** * Check if two DOM range objects are equal. */