diff --git a/packages/slate-react/src/components/node.js b/packages/slate-react/src/components/node.js
index 163509ce3..4c0df2856 100644
--- a/packages/slate-react/src/components/node.js
+++ b/packages/slate-react/src/components/node.js
@@ -7,8 +7,8 @@ import logger from 'slate-dev-logger'
import Types from 'prop-types'
import TRANSFER_TYPES from '../constants/transfer-types'
-import Leaf from './leaf'
import Void from './void'
+import Text from './text'
import setTransferData from '../utils/set-transfer-data'
/**
@@ -54,7 +54,7 @@ class Node extends React.Component {
super(props)
const { node, schema } = props
this.state = {}
- this.state.Component = node.kind == 'text' ? null : node.getComponent(schema)
+ this.state.Component = node.getComponent(schema)
}
/**
@@ -66,9 +66,8 @@ class Node extends React.Component {
debug = (message, ...args) => {
const { node } = this.props
- const { key, kind, type } = node
- const id = kind == 'text' ? `${key} (${kind})` : `${key} (${type})`
- debug(message, `${id}`, ...args)
+ const { key, type } = node
+ debug(message, `${key} (${type})`, ...args)
}
/**
@@ -78,7 +77,6 @@ class Node extends React.Component {
*/
componentWillReceiveProps = (props) => {
- if (props.node.kind == 'text') return
if (props.node == this.props.node) return
const Component = props.node.getComponent(props.schema)
this.setState({ Component })
@@ -138,24 +136,6 @@ class Node extends React.Component {
// need to be rendered again.
if (n.isSelected || p.isSelected) return true
- // If the node is a text node, re-render if the current decorations have
- // changed, even if the content of the text node itself hasn't.
- if (n.node.kind == 'text' && n.schema.hasDecorators) {
- const nDecorators = n.state.document.getDescendantDecorators(n.node.key, n.schema)
- const pDecorators = p.state.document.getDescendantDecorators(p.node.key, p.schema)
- const nRanges = n.node.getRanges(nDecorators)
- const pRanges = p.node.getRanges(pDecorators)
- if (!nRanges.equals(pRanges)) return true
- }
-
- // If the node is a text node, and its parent is a block node, and it was
- // the last child of the block, re-render to cleanup extra `
` or `\n`.
- if (n.node.kind == 'text' && n.parent.kind == 'block') {
- const pLast = p.parent.nodes.last()
- const nLast = n.parent.nodes.last()
- if (p.node == pLast && n.node != nLast) return true
- }
-
// Otherwise, don't update.
return false
}
@@ -190,48 +170,10 @@ class Node extends React.Component {
render() {
const { props } = this
- const { node } = this.props
this.debug('render', { props })
- return node.kind == 'text'
- ? this.renderText()
- : this.renderElement()
- }
-
- /**
- * Render a `child` node.
- *
- * @param {Node} child
- * @param {Boolean} isSelected
- * @return {Element}
- */
-
- renderNode = (child, isSelected) => {
- const { block, editor, node, readOnly, schema, state } = this.props
- return (
-
- )
- }
-
- /**
- * Render an element `node`.
- *
- * @return {Element}
- */
-
- renderElement = () => {
- const { editor, isSelected, node, parent, readOnly, state } = this.props
+ const { editor, isSelected, node, parent, readOnly, state } = props
const { Component } = this.state
const { selection } = state
const indexes = node.getSelectionIndexes(selection, isSelected)
@@ -275,59 +217,27 @@ class Node extends React.Component {
}
/**
- * Render a text node.
+ * Render a `child` node.
*
+ * @param {Node} child
+ * @param {Boolean} isSelected
* @return {Element}
*/
- renderText = () => {
- const { node, schema, state } = this.props
- const { document } = state
- const decorators = schema.hasDecorators ? document.getDescendantDecorators(node.key, schema) : []
- const ranges = node.getRanges(decorators)
- let offset = 0
-
- const leaves = ranges.map((range, i) => {
- const leaf = this.renderLeaf(ranges, range, i, offset)
- offset += range.text.length
- return leaf
- })
-
+ renderNode = (child, isSelected) => {
+ const { block, editor, node, readOnly, schema, state } = this.props
+ const Component = child.kind === 'text' ? Text : Node
return (
-
- {leaves}
-
- )
- }
-
- /**
- * Render a single leaf node given a `range` and `offset`.
- *
- * @param {List} ranges
- * @param {Range} range
- * @param {Number} index
- * @param {Number} offset
- * @return {Element} leaf
- */
-
- renderLeaf = (ranges, range, index, offset) => {
- const { block, node, parent, schema, state, editor } = this.props
- const { text, marks } = range
-
- return (
-
)
}
diff --git a/packages/slate-react/src/components/text.js b/packages/slate-react/src/components/text.js
new file mode 100644
index 000000000..901601569
--- /dev/null
+++ b/packages/slate-react/src/components/text.js
@@ -0,0 +1,157 @@
+
+import Debug from 'debug'
+import React from 'react'
+import SlateTypes from 'slate-prop-types'
+import Types from 'prop-types'
+
+import Leaf from './leaf'
+
+/**
+ * Debug.
+ *
+ * @type {Function}
+ */
+
+const debug = Debug('slate:node')
+
+class Text extends React.Component {
+
+ /**
+ * Property types.
+ *
+ * @type {Object}
+ */
+
+ static propTypes = {
+ block: SlateTypes.block,
+ editor: Types.object.isRequired,
+ node: SlateTypes.node.isRequired,
+ parent: SlateTypes.node.isRequired,
+ schema: SlateTypes.schema.isRequired,
+ state: SlateTypes.state.isRequired,
+ }
+
+ /**
+ * Debug.
+ *
+ * @param {String} message
+ * @param {Mixed} ...args
+ */
+
+ debug = (message, ...args) => {
+ const { node } = this.props
+ const { key } = node
+ debug(message, `${key} (text)`, ...args)
+ }
+
+ /**
+ * Should the node update?
+ *
+ * @param {Object} nextProps
+ * @param {Object} state
+ * @return {Boolean}
+ */
+
+ shouldComponentUpdate = (nextProps) => {
+ const { props } = this
+ const n = nextProps
+ const p = props
+
+ // 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 (n.node != p.node) return true
+
+ // Re-render if the current decorations have changed, even if the content of
+ // the text node itself hasn't.
+ if (n.schema.hasDecorators) {
+ const nDecorators = n.state.document.getDescendantDecorators(n.node.key, n.schema)
+ const pDecorators = p.state.document.getDescendantDecorators(p.node.key, p.schema)
+ const nRanges = n.node.getRanges(nDecorators)
+ const pRanges = p.node.getRanges(pDecorators)
+ if (!nRanges.equals(pRanges)) return true
+ }
+
+ // If the node parent is a block node, and it was the last child of the
+ // block, re-render to cleanup extra `
` or `\n`.
+ if (n.parent.kind == 'block') {
+ const pLast = p.parent.nodes.last()
+ const nLast = n.parent.nodes.last()
+ if (p.node == pLast && n.node != nLast) return true
+ }
+
+ // Otherwise, don't update.
+ return false
+ }
+
+ /**
+ * Render.
+ *
+ * @return {Element}
+ */
+
+ render() {
+ const { props } = this
+ this.debug('render', { props })
+
+ const { node, schema, state } = props
+ const { document } = state
+ const decorators = schema.hasDecorators ? document.getDescendantDecorators(node.key, schema) : []
+ const ranges = node.getRanges(decorators)
+ let offset = 0
+
+ const leaves = ranges.map((range, i) => {
+ const leaf = this.renderLeaf(ranges, range, i, offset)
+ offset += range.text.length
+ return leaf
+ })
+
+ return (
+
+ {leaves}
+
+ )
+ }
+
+ /**
+ * Render a single leaf node given a `range` and `offset`.
+ *
+ * @param {List} ranges
+ * @param {Range} range
+ * @param {Number} index
+ * @param {Number} offset
+ * @return {Element} leaf
+ */
+
+ renderLeaf = (ranges, range, index, offset) => {
+ const { block, node, parent, schema, state, editor } = this.props
+ const { text, marks } = range
+
+ return (
+
+ )
+ }
+
+}
+
+/**
+ * Export.
+ *
+ * @type {Component}
+ */
+
+export default Text