1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-30 18:39:51 +02:00

fix scrolling to selection

This commit is contained in:
Ian Storm Taylor
2017-02-28 14:51:51 -08:00
parent 7a6bd25aa9
commit d7962240e1
5 changed files with 46 additions and 63 deletions

View File

@@ -3,7 +3,6 @@ import { Editor, Raw } from '../..'
import Portal from 'react-portal'
import React from 'react'
import initialState from './state.json'
import position from 'selection-position'
/**
* Define a schema.
@@ -185,7 +184,9 @@ class HoveringMenu extends React.Component {
return
}
const rect = position()
const selection = window.getSelection()
const range = selection.getRangeAt(0)
const rect = range.getBoundingClientRect()
menu.style.opacity = 1
menu.style.top = `${rect.top + window.scrollY - menu.offsetHeight}px`
menu.style.left = `${rect.left + window.scrollX - menu.offsetWidth / 2 + rect.width / 2}px`

View File

@@ -16,6 +16,7 @@
"is-empty": "^1.0.0",
"keycode": "^2.1.2",
"react-portal": "^3.0.0",
"selection-is-backward": "^1.0.0",
"type-of": "^2.0.1"
},
"peerDependencies": {
@@ -63,7 +64,6 @@
"react-router": "^2.5.1",
"read-metadata": "^1.0.0",
"read-yaml-promise": "^1.0.2",
"selection-position": "^1.0.0",
"slate-auto-replace-text": "^0.3.0",
"slate-collapse-on-escape": "^0.2.0",
"slate-soft-break": "^0.2.0",

View File

@@ -6,7 +6,8 @@ import ReactDOM from 'react-dom'
import TYPES from '../constants/types'
import Leaf from './leaf'
import Void from './void'
import scrollTo from '../utils/scroll-to'
import getWindow from 'get-window'
import scrollToSelection from '../utils/scroll-to-selection'
/**
* Debug.
@@ -207,7 +208,9 @@ class Node extends React.Component {
if (!selection.hasEndIn(node)) return
const el = ReactDOM.findDOMNode(this)
scrollTo(el)
const window = getWindow(el)
const native = window.getSelection()
scrollToSelection(native)
this.debug('updateScroll', el)
}

View File

@@ -0,0 +1,37 @@
import getWindow from 'get-window'
import isBackward from 'selection-is-backward'
/**
* Scroll the current selection's focus point into view if needed.
*
* @param {Selection} selection
*/
function scrollToSelection(selection) {
const window = getWindow(selection.anchorNode)
const backward = isBackward(selection)
const range = selection.getRangeAt(0)
const rect = range.getBoundingClientRect()
const { innerWidth, innerHeight, scrollY, scrollX } = window
const top = (backward ? rect.top : rect.bottom) + scrollY
const left = (backward ? rect.left : rect.right) + scrollX
const x = left < scrollX || innerWidth + scrollX < left
? left - innerWidth / 2
: scrollX
const y = top < scrollY || innerHeight + scrollY < top
? top - innerHeight / 2
: scrollY
window.scrollTo(x, y)
}
/**
* Export.
*
* @type {Function}
*/
export default scrollToSelection

View File

@@ -1,58 +0,0 @@
/**
* Helps scroll the cursor into the middle of view if it isn't in view
*/
import getWindow from 'get-window'
function scrollWindow(window, cursorTop, cursorLeft, cursorHeight) {
let scrollX = window.scrollX
let scrollY = window.scrollY
const cursorBottom = cursorTop + cursorHeight
if (cursorTop < 0 || cursorBottom > window.innerHeight) {
scrollY += cursorTop - window.innerHeight / 2 + cursorHeight / 2
}
if (cursorLeft < 0 || cursorLeft > window.innerWidth) {
scrollX += cursorLeft - window.innerWidth / 2
}
window.scrollTo(scrollX, scrollY)
}
function scrollTo(element) {
const window = getWindow(element)
const s = window.getSelection()
if (s.rangeCount > 0) {
const selectionRect = s.getRangeAt(0).getBoundingClientRect()
let innerRect = selectionRect
let wrapper = element
const cursorHeight = innerRect.height
let cursorTop = innerRect.top
let cursorLeft = innerRect.left
while (wrapper != window.document.body) {
const wrapperRect = wrapper.getBoundingClientRect()
const currentY = cursorTop
const cursorBottom = cursorTop + cursorHeight
if (cursorTop < wrapperRect.top || cursorBottom > wrapperRect.top + wrapper.offsetHeight) {
cursorTop = wrapperRect.top + wrapperRect.height / 2 - cursorHeight / 2
wrapper.scrollTop += currentY - cursorTop
}
const currentLeft = cursorLeft
if (cursorLeft < wrapperRect.left || cursorLeft > wrapperRect.right) {
cursorLeft = wrapperRect.left + wrapperRect.width / 2
wrapper.scrollLeft += currentLeft - cursorLeft
}
innerRect = wrapperRect
wrapper = wrapper.parentNode
}
scrollWindow(window, cursorTop, cursorLeft, cursorHeight)
}
}
export default scrollTo