diff --git a/lib/components/leaf.js b/lib/components/leaf.js index 069c3761d..68d6c9834 100644 --- a/lib/components/leaf.js +++ b/lib/components/leaf.js @@ -22,6 +22,18 @@ class Leaf extends React.Component { text: React.PropTypes.string.isRequired }; + /** + * Constructor. + * + * @param {Object} props + */ + + constructor(props) { + super(props) + this.tmp = {} + this.tmp.renders = 0 + } + /** * Should component update? * @@ -35,8 +47,9 @@ class Leaf extends React.Component { if ( props.index != this.props.index || - props.text != this.props.text || - props.marks != this.props.marks + props.marks != this.props.marks || + props.renderMark != this.props.renderMark || + props.text != this.props.text ) { return true } @@ -136,8 +149,15 @@ class Leaf extends React.Component { return memo }, {}) + // Increment the renders key, which forces a re-render whenever this + // component is told it should update. This is required because "native" + // renders where we don't update the leaves cause React's internal state to + // get out of sync, causing it to not realize the DOM needs updating. + this.tmp.renders++ + return ( diff --git a/lib/models/transform.js b/lib/models/transform.js index a0f244865..e185b84c0 100644 --- a/lib/models/transform.js +++ b/lib/models/transform.js @@ -338,7 +338,13 @@ class Transform extends new Record(DEFAULT_PROPERTIES) { // Return the previous state, with the updated history. let { document, selection } = previous history = history.merge({ undos, redos }) - state = state.merge({ document, selection, history }) + state = state.merge({ + document, + selection, + history, + isNative: false + }) + return state } @@ -368,7 +374,13 @@ class Transform extends new Record(DEFAULT_PROPERTIES) { // Return the next state, with the updated history. let { document, selection } = next history = history.merge({ undos, redos }) - state = state.merge({ document, selection, history }) + state = state.merge({ + document, + selection, + history, + isNative: false + }) + return state } diff --git a/lib/plugins/core.js b/lib/plugins/core.js index c961142bd..5fca0b0a4 100644 --- a/lib/plugins/core.js +++ b/lib/plugins/core.js @@ -31,21 +31,6 @@ function Plugin(options = {}) { */ class DEFAULT_BLOCK extends React.Component { - - static propTypes = { - attributes: React.PropTypes.object.isRequired, - children: React.PropTypes.any.isRequired, - node: React.PropTypes.object.isRequired, - state: React.PropTypes.object.isRequired - }; - - shouldComponentUpdate = (props, state) => { - return ( - props.node != this.props.node || - props.state.selection.hasEdgeIn(props.node) - ) - } - render = () => { const { attributes, children } = this.props return ( @@ -80,26 +65,10 @@ function Plugin(options = {}) { */ class DEFAULT_INLINE extends React.Component { - - static propTypes = { - attributes: React.PropTypes.object.isRequired, - children: React.PropTypes.any.isRequired, - node: React.PropTypes.object.isRequired, - state: React.PropTypes.object.isRequired - }; - - shouldComponentUpdate = (props, state) => { - return ( - props.node != this.props.node || - props.state.selection.hasEdgeIn(props.node) - ) - } - render = () => { const { attributes, children } = this.props return {children} } - } /** @@ -123,11 +92,12 @@ function Plugin(options = {}) { const resolved = editor.resolveState(synthetic) // We do not have to re-render if the current selection is collapsed, the - // current node is not empty, and the new state has the same decorations - // as the current one. + // current node is not empty, there are no marks on the cursor, and the + // new state has the same decorations as the current one. const isNative = ( state.isCollapsed && state.startText.text != '' && + state.cursorMarks == null && resolved.equals(synthetic) )