mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-07-31 20:40:19 +02:00
change selection updating logic to happen at the top-level, closes #662
This commit is contained in:
@@ -41,13 +41,13 @@ class CheckListItem extends React.Component {
|
|||||||
const checked = node.data.get('checked')
|
const checked = node.data.get('checked')
|
||||||
return (
|
return (
|
||||||
<div {...attributes} className="check-list-item">
|
<div {...attributes} className="check-list-item">
|
||||||
<div contentEditable={false}>
|
<span contentEditable={false}>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@@ -29,9 +29,9 @@ const schema = {
|
|||||||
nodes: {
|
nodes: {
|
||||||
image: (props) => {
|
image: (props) => {
|
||||||
const { node, state } = props
|
const { node, state } = props
|
||||||
const isFocused = state.selection.hasEdgeIn(node)
|
const active = state.isFocused && state.selection.hasEdgeIn(node)
|
||||||
const src = node.data.get('src')
|
const src = node.data.get('src')
|
||||||
const className = isFocused ? 'active' : null
|
const className = active ? 'active' : null
|
||||||
return (
|
return (
|
||||||
<img src={src} className={className} {...props.attributes} />
|
<img src={src} className={className} {...props.attributes} />
|
||||||
)
|
)
|
||||||
|
@@ -79,7 +79,7 @@ class Content extends React.Component {
|
|||||||
super(props)
|
super(props)
|
||||||
this.tmp = {}
|
this.tmp = {}
|
||||||
this.tmp.compositions = 0
|
this.tmp.compositions = 0
|
||||||
this.forces = 0
|
this.tmp.forces = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,10 +110,12 @@ class Content extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On mount, if `autoFocus` is set, focus the editor.
|
* On mount, update the selection, and focus the editor if `autoFocus` is set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
|
this.updateSelection()
|
||||||
|
|
||||||
if (this.props.autoFocus) {
|
if (this.props.autoFocus) {
|
||||||
const el = ReactDOM.findDOMNode(this)
|
const el = ReactDOM.findDOMNode(this)
|
||||||
el.focus()
|
el.focus()
|
||||||
@@ -121,22 +123,99 @@ class Content extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On update, if the state is blurred now, but was focused before, and the
|
* On update, update the selection.
|
||||||
* DOM still has a node inside the editor selected, we need to blur it.
|
|
||||||
*
|
|
||||||
* @param {Object} prevProps
|
|
||||||
* @param {Object} prevState
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
componentDidUpdate = (prevProps, prevState) => {
|
componentDidUpdate = () => {
|
||||||
if (this.props.state.isBlurred && prevProps.state.isFocused) {
|
this.updateSelection()
|
||||||
const el = ReactDOM.findDOMNode(this)
|
}
|
||||||
const window = getWindow(el)
|
|
||||||
const native = window.getSelection()
|
/**
|
||||||
|
* Update the native DOM selection to reflect the internal model.
|
||||||
|
*/
|
||||||
|
|
||||||
|
updateSelection = () => {
|
||||||
|
const { state } = this.props
|
||||||
|
const { selection } = state
|
||||||
|
const el = ReactDOM.findDOMNode(this)
|
||||||
|
const window = getWindow(el)
|
||||||
|
const native = window.getSelection()
|
||||||
|
|
||||||
|
// If both selections are blurred, do nothing.
|
||||||
|
if (!native.rangeCount && selection.isBlurred) return
|
||||||
|
|
||||||
|
// If the selection has been blurred, but hasn't been updated in the DOM,
|
||||||
|
// blur the DOM selection.
|
||||||
|
if (selection.isBlurred) {
|
||||||
if (!el.contains(native.anchorNode)) return
|
if (!el.contains(native.anchorNode)) return
|
||||||
native.removeAllRanges()
|
native.removeAllRanges()
|
||||||
el.blur()
|
el.blur()
|
||||||
|
debug('updateSelection', { selection, native })
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, figure out which DOM nodes should be selected...
|
||||||
|
const { anchorText, focusText } = state
|
||||||
|
const { anchorKey, anchorOffset, focusKey, focusOffset } = selection
|
||||||
|
const anchorRanges = anchorText.getRanges()
|
||||||
|
const focusRanges = focusText.getRanges()
|
||||||
|
let a = 0
|
||||||
|
let f = 0
|
||||||
|
let anchorIndex
|
||||||
|
let focusIndex
|
||||||
|
let anchorOff
|
||||||
|
let focusOff
|
||||||
|
|
||||||
|
anchorRanges.forEach((range, i, ranges) => {
|
||||||
|
const { length } = range.text
|
||||||
|
a += length
|
||||||
|
if (a < anchorOffset) return
|
||||||
|
anchorIndex = i
|
||||||
|
anchorOff = anchorOffset - (a - length)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
focusRanges.forEach((range, i, ranges) => {
|
||||||
|
const { length } = range.text
|
||||||
|
f += length
|
||||||
|
if (f < focusOffset) return
|
||||||
|
focusIndex = i
|
||||||
|
focusOff = focusOffset - (f - length)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
const anchorSpan = el.querySelector(`[data-offset-key="${anchorKey}-${anchorIndex}"]`)
|
||||||
|
const focusSpan = el.querySelector(`[data-offset-key="${focusKey}-${focusIndex}"]`)
|
||||||
|
const anchorEl = anchorSpan.firstChild
|
||||||
|
const focusEl = focusSpan.firstChild
|
||||||
|
|
||||||
|
// If they are already selected, do nothing.
|
||||||
|
if (
|
||||||
|
anchorEl == native.anchorNode &&
|
||||||
|
anchorOff == native.anchorOffset &&
|
||||||
|
focusEl == native.focusNode &&
|
||||||
|
focusOff == native.focusOffset
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, set the `isSelecting` flag and update the selection.
|
||||||
|
this.tmp.isSelecting = true
|
||||||
|
native.removeAllRanges()
|
||||||
|
const range = window.document.createRange()
|
||||||
|
range.setStart(anchorEl, anchorOff)
|
||||||
|
native.addRange(range)
|
||||||
|
native.extend(focusEl, focusOff)
|
||||||
|
|
||||||
|
// Then unset the `isSelecting` flag after a delay.
|
||||||
|
setTimeout(() => {
|
||||||
|
// COMPAT: In Firefox, it's not enough to create a range, you also need to
|
||||||
|
// focus the contenteditable element too. (2016/11/16)
|
||||||
|
if (IS_FIREFOX) el.focus()
|
||||||
|
this.tmp.isSelecting = false
|
||||||
|
})
|
||||||
|
|
||||||
|
debug('updateSelection', { selection, native })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -254,7 +333,7 @@ class Content extends React.Component {
|
|||||||
onCompositionEnd = (event) => {
|
onCompositionEnd = (event) => {
|
||||||
if (!this.isInContentEditable(event)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
this.forces++
|
this.tmp.forces++
|
||||||
const count = this.tmp.compositions
|
const count = this.tmp.compositions
|
||||||
|
|
||||||
// The `count` check here ensures that if another composition starts
|
// The `count` check here ensures that if another composition starts
|
||||||
@@ -619,6 +698,7 @@ class Content extends React.Component {
|
|||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (this.tmp.isCopying) return
|
if (this.tmp.isCopying) return
|
||||||
if (this.tmp.isComposing) return
|
if (this.tmp.isComposing) return
|
||||||
|
if (this.tmp.isSelecting) return
|
||||||
if (!this.isInContentEditable(event)) return
|
if (!this.isInContentEditable(event)) return
|
||||||
|
|
||||||
const window = getWindow(event.target)
|
const window = getWindow(event.target)
|
||||||
@@ -640,10 +720,11 @@ class Content extends React.Component {
|
|||||||
const focus = getPoint(focusNode, focusOffset, state, editor)
|
const focus = getPoint(focusNode, focusOffset, state, editor)
|
||||||
if (!anchor || !focus) return
|
if (!anchor || !focus) return
|
||||||
|
|
||||||
// There are valid situations where a select event will fire when we're
|
// There are situations where a select event will fire with a new native
|
||||||
// already at that position (for example when entering a character), since
|
// selection that resolves to the same internal position. In those cases
|
||||||
// our `insertText` transform already updates the selection. In those
|
// we don't need to trigger any changes, since our internal model is
|
||||||
// cases we can safely ignore the event.
|
// already up to date, but we do want to update the native selection again
|
||||||
|
// to make sure it is in sync.
|
||||||
if (
|
if (
|
||||||
anchor.key == selection.anchorKey &&
|
anchor.key == selection.anchorKey &&
|
||||||
anchor.offset == selection.anchorOffset &&
|
anchor.offset == selection.anchorOffset &&
|
||||||
@@ -651,6 +732,7 @@ class Content extends React.Component {
|
|||||||
focus.offset == selection.focusOffset &&
|
focus.offset == selection.focusOffset &&
|
||||||
selection.isFocused
|
selection.isFocused
|
||||||
) {
|
) {
|
||||||
|
this.updateSelection()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,7 +818,7 @@ class Content extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slate-editor
|
data-slate-editor
|
||||||
key={this.forces}
|
key={this.tmp.forces}
|
||||||
ref={this.ref}
|
ref={this.ref}
|
||||||
contentEditable={!readOnly}
|
contentEditable={!readOnly}
|
||||||
suppressContentEditableWarning
|
suppressContentEditableWarning
|
||||||
|
@@ -3,7 +3,6 @@ import Debug from 'debug'
|
|||||||
import OffsetKey from '../utils/offset-key'
|
import OffsetKey from '../utils/offset-key'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import getWindow from 'get-window'
|
|
||||||
import { IS_FIREFOX } from '../constants/environment'
|
import { IS_FIREFOX } from '../constants/environment'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,123 +87,10 @@ class Leaf extends React.Component {
|
|||||||
const text = this.renderText(props)
|
const text = this.renderText(props)
|
||||||
if (el.textContent != text) return true
|
if (el.textContent != text) return true
|
||||||
|
|
||||||
// If the selection was previously focused, and now it isn't, re-render so
|
|
||||||
// that the selection will be properly removed.
|
|
||||||
if (this.props.state.isFocused && props.state.isBlurred) {
|
|
||||||
const { index, node, ranges, state } = this.props
|
|
||||||
const { start, end } = OffsetKey.findBounds(index, ranges)
|
|
||||||
if (state.selection.hasEdgeBetween(node, start, end)) return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the selection will be focused, only re-render if this leaf contains
|
|
||||||
// one or both of the selection's edges.
|
|
||||||
if (props.state.isFocused) {
|
|
||||||
const { index, node, ranges, state } = props
|
|
||||||
const { start, end } = OffsetKey.findBounds(index, ranges)
|
|
||||||
if (state.selection.hasEdgeBetween(node, start, end)) return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, don't update.
|
// Otherwise, don't update.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* When the DOM updates, try updating the selection.
|
|
||||||
*/
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.updateSelection()
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
this.updateSelection()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the DOM selection if it's inside the leaf.
|
|
||||||
*/
|
|
||||||
|
|
||||||
updateSelection() {
|
|
||||||
const { state, ranges } = this.props
|
|
||||||
const { selection } = state
|
|
||||||
|
|
||||||
// If the selection is blurred we have nothing to do.
|
|
||||||
if (selection.isBlurred) return
|
|
||||||
|
|
||||||
const { node, index } = this.props
|
|
||||||
const { start, end } = OffsetKey.findBounds(index, ranges)
|
|
||||||
const anchorOffset = selection.anchorOffset - start
|
|
||||||
const focusOffset = selection.focusOffset - start
|
|
||||||
|
|
||||||
// If neither matches, the selection doesn't start or end here, so exit.
|
|
||||||
const hasAnchor = selection.hasAnchorBetween(node, start, end)
|
|
||||||
const hasFocus = selection.hasFocusBetween(node, start, end)
|
|
||||||
if (!hasAnchor && !hasFocus) return
|
|
||||||
|
|
||||||
// We have a selection to render, so prepare a few things...
|
|
||||||
const ref = ReactDOM.findDOMNode(this)
|
|
||||||
const el = findDeepestNode(ref)
|
|
||||||
const window = getWindow(el)
|
|
||||||
const native = window.getSelection()
|
|
||||||
const parent = ref.closest('[contenteditable]')
|
|
||||||
|
|
||||||
// COMPAT: In Firefox, it's not enough to create a range, you also need to
|
|
||||||
// focus the contenteditable element. (2016/11/16)
|
|
||||||
function focus() {
|
|
||||||
if (!IS_FIREFOX) return
|
|
||||||
if (parent) setTimeout(() => parent.focus())
|
|
||||||
}
|
|
||||||
|
|
||||||
// If both the start and end are here, set the selection all at once.
|
|
||||||
if (hasAnchor && hasFocus) {
|
|
||||||
native.removeAllRanges()
|
|
||||||
const range = window.document.createRange()
|
|
||||||
range.setStart(el, anchorOffset)
|
|
||||||
native.addRange(range)
|
|
||||||
native.extend(el, focusOffset)
|
|
||||||
focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise we need to set the selection across two different leaves.
|
|
||||||
// If the selection is forward, we can set things in sequence. In the
|
|
||||||
// first leaf to render, reset the selection and set the new start. And
|
|
||||||
// then in the second leaf to render, extend to the new end.
|
|
||||||
else if (selection.isForward) {
|
|
||||||
if (hasAnchor) {
|
|
||||||
native.removeAllRanges()
|
|
||||||
const range = window.document.createRange()
|
|
||||||
range.setStart(el, anchorOffset)
|
|
||||||
native.addRange(range)
|
|
||||||
} else if (hasFocus) {
|
|
||||||
native.extend(el, focusOffset)
|
|
||||||
focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, if the selection is backward, we need to hack the order a bit.
|
|
||||||
// In the first leaf to render, set a phony start anchor to store the true
|
|
||||||
// end position. And then in the second leaf to render, set the start and
|
|
||||||
// extend the end to the stored value.
|
|
||||||
else if (hasFocus) {
|
|
||||||
native.removeAllRanges()
|
|
||||||
const range = window.document.createRange()
|
|
||||||
range.setStart(el, focusOffset)
|
|
||||||
native.addRange(range)
|
|
||||||
}
|
|
||||||
else if (hasAnchor) {
|
|
||||||
const endNode = native.focusNode
|
|
||||||
const endOffset = native.focusOffset
|
|
||||||
native.removeAllRanges()
|
|
||||||
const range = window.document.createRange()
|
|
||||||
range.setStart(el, anchorOffset)
|
|
||||||
native.addRange(range)
|
|
||||||
native.extend(endNode, endOffset)
|
|
||||||
focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.debug('updateSelection', { selection })
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the leaf.
|
* Render the leaf.
|
||||||
*
|
*
|
||||||
@@ -225,7 +111,6 @@ class Leaf extends React.Component {
|
|||||||
// get out of sync, causing it to not realize the DOM needs updating.
|
// get out of sync, causing it to not realize the DOM needs updating.
|
||||||
this.tmp.renders++
|
this.tmp.renders++
|
||||||
|
|
||||||
|
|
||||||
this.debug('render', { props })
|
this.debug('render', { props })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@@ -89,80 +89,42 @@ class Node extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
shouldComponentUpdate = (nextProps) => {
|
shouldComponentUpdate = (nextProps) => {
|
||||||
|
const { props } = this
|
||||||
const { Component } = this.state
|
const { Component } = this.state
|
||||||
|
|
||||||
// If the node is rendered with a `Component` that has enabled suppression
|
// If the `Component` has enabled suppression of update checking, always
|
||||||
// of update checking, always return true so that it can deal with update
|
// return true so that it can deal with update checking itself.
|
||||||
// checking itself.
|
if (Component && Component.suppressShouldComponentUpdate) return true
|
||||||
if (Component && Component.suppressShouldComponentUpdate) {
|
|
||||||
return true
|
// If the `readOnly` status has changed, re-render in case there is any
|
||||||
|
// user-land logic that depends on it, like nested editable contents.
|
||||||
|
if (nextProps.readOnly != props.readOnly) return true
|
||||||
|
|
||||||
|
// If the node has changed, update. PERF: There are cases where it will have
|
||||||
|
// changed, but it's properties will be exactly the same (eg. copy-paste)
|
||||||
|
// which this won't catch. But that's rare and not a drag on performance, so
|
||||||
|
// for simplicity we just let them through.
|
||||||
|
if (nextProps.node != props.node) return true
|
||||||
|
|
||||||
|
// If the node is a block or inline, which can have custom renderers, we
|
||||||
|
// include an extra check to re-render if the node's focus changes, to make
|
||||||
|
// it simple for users to show a node's "selected" state.
|
||||||
|
if (props.node.kind != 'text') {
|
||||||
|
const hasEdgeIn = props.state.selection.hasEdgeIn(props.node)
|
||||||
|
const nextHasEdgeIn = nextProps.state.selection.hasEdgeIn(nextProps.node)
|
||||||
|
const hasFocus = props.state.isFocused || nextProps.state.isFocused
|
||||||
|
const hasEdge = hasEdgeIn || nextHasEdgeIn
|
||||||
|
if (hasFocus && hasEdge) return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the `readOnly` status has changed, we need to re-render in case there is
|
// If the node is a text node, re-render if the current decorations have
|
||||||
// any user-land logic that depends on it, like nested editable contents.
|
// changed, even if the content of the text node itself hasn't.
|
||||||
if (nextProps.readOnly !== this.props.readOnly) return true
|
|
||||||
|
|
||||||
// If the node has changed, update. PERF: There are certain cases where the
|
|
||||||
// node instance will have changed, but it's properties will be exactly the
|
|
||||||
// same (copy-paste, delete backwards, etc.) in which case this will not
|
|
||||||
// catch a potentially avoidable re-render. But those cases are rare enough
|
|
||||||
// that they aren't really a drag on performance, so for simplicity we just
|
|
||||||
// let them through.
|
|
||||||
if (nextProps.node != this.props.node) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextHasEdgeIn = nextProps.state.selection.hasEdgeIn(nextProps.node)
|
|
||||||
|
|
||||||
// If the selection is focused and is inside the node, we need to update so
|
|
||||||
// that the selection will be set by one of the <Leaf> components.
|
|
||||||
if (
|
|
||||||
nextProps.state.isFocused &&
|
|
||||||
nextHasEdgeIn
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasEdgeIn = this.props.state.selection.hasEdgeIn(nextProps.node)
|
|
||||||
// If the selection is blurred but was previously focused (or vice versa) inside the node,
|
|
||||||
// we need to update to ensure the selection gets updated by re-rendering.
|
|
||||||
if (
|
|
||||||
this.props.state.isFocused != nextProps.state.isFocused &&
|
|
||||||
(
|
|
||||||
hasEdgeIn || nextHasEdgeIn
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// For block and inline nodes, which can have custom renderers, we need to
|
|
||||||
// include another check for whether the previous selection had an edge in
|
|
||||||
// the node, to allow for intuitive selection-based rendering.
|
|
||||||
if (
|
|
||||||
this.props.node.kind != 'text' &&
|
|
||||||
hasEdgeIn != nextHasEdgeIn
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// For text nodes, which can have custom decorations, we need to check to
|
|
||||||
// see if the block has changed, which has caused the decorations to change.
|
|
||||||
if (nextProps.node.kind == 'text' && nextProps.schema.hasDecorators) {
|
if (nextProps.node.kind == 'text' && nextProps.schema.hasDecorators) {
|
||||||
const { node, schema, state } = nextProps
|
const nextDecorators = nextProps.state.document.getDescendantDecorators(nextProps.node.key, nextProps.schema)
|
||||||
|
const decorators = props.state.document.getDescendantDecorators(props.node.key, props.schema)
|
||||||
const { document } = state
|
const nextRanges = nextProps.node.getRanges(nextDecorators)
|
||||||
const decorators = document.getDescendantDecorators(node.key, schema)
|
const ranges = props.node.getRanges(decorators)
|
||||||
const ranges = node.getRanges(decorators)
|
if (!nextRanges.equals(ranges)) return true
|
||||||
|
|
||||||
const prevNode = this.props.node
|
|
||||||
const prevSchema = this.props.schema
|
|
||||||
const prevDocument = this.props.state.document
|
|
||||||
const prevDecorators = prevDocument.getDescendantDecorators(prevNode.key, prevSchema)
|
|
||||||
const prevRanges = prevNode.getRanges(prevDecorators)
|
|
||||||
|
|
||||||
if (!ranges.equals(prevRanges)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, don't update.
|
// Otherwise, don't update.
|
||||||
|
@@ -187,34 +187,11 @@ function Plugin(options = {}) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function onBlur(e, data, state) {
|
function onBlur(e, data, state) {
|
||||||
const isNative = true
|
debug('onBlur', { data })
|
||||||
|
|
||||||
debug('onBlur', { data, isNative })
|
|
||||||
|
|
||||||
return state
|
return state
|
||||||
.transform()
|
.transform()
|
||||||
.blur()
|
.blur()
|
||||||
.apply({ isNative })
|
.apply()
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On focus.
|
|
||||||
*
|
|
||||||
* @param {Event} e
|
|
||||||
* @param {Object} data
|
|
||||||
* @param {State} state
|
|
||||||
* @return {State}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function onFocus(e, data, state) {
|
|
||||||
const isNative = true
|
|
||||||
|
|
||||||
debug('onFocus', { data, isNative })
|
|
||||||
|
|
||||||
return state
|
|
||||||
.transform()
|
|
||||||
.focus()
|
|
||||||
.apply({ isNative })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -975,7 +952,6 @@ function Plugin(options = {}) {
|
|||||||
onBeforeChange,
|
onBeforeChange,
|
||||||
onBeforeInput,
|
onBeforeInput,
|
||||||
onBlur,
|
onBlur,
|
||||||
onFocus,
|
|
||||||
onCopy,
|
onCopy,
|
||||||
onCut,
|
onCut,
|
||||||
onDrop,
|
onDrop,
|
||||||
|
Reference in New Issue
Block a user