-
Notifications
You must be signed in to change notification settings - Fork 0
/
text.js
172 lines (144 loc) · 3.62 KB
/
text.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import Debug from 'debug'
import ImmutableTypes from 'react-immutable-proptypes'
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')
/**
* Text.
*
* @type {Component}
*/
class Text extends React.Component {
/**
* Property types.
*
* @type {Object}
*/
static propTypes = {
block: SlateTypes.block,
decorations: ImmutableTypes.list.isRequired,
editor: Types.object.isRequired,
node: SlateTypes.node.isRequired,
parent: SlateTypes.node.isRequired,
style: Types.object,
}
/**
* Default prop types.
*
* @type {Object}
*/
static defaultProps = {
style: null,
}
/**
* 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} value
* @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
// If the node parent is a block node, and it was the last child of the
// block, re-render to cleanup extra `\n`.
if (n.parent.object == 'block') {
const pLast = p.parent.nodes.last()
const nLast = n.parent.nodes.last()
if (p.node == pLast && n.node != nLast) return true
}
// Re-render if the current decorations have changed.
if (!n.decorations.equals(p.decorations)) return true
// Otherwise, don't update.
return false
}
/**
* Render.
*
* @return {Element}
*/
render() {
this.debug('render', this)
const { decorations, editor, node, style } = this.props
const { value } = editor
const { document } = value
const { key } = node
const decs = decorations.filter(d => {
const { startKey, endKey } = d
if (startKey == key || endKey == key) return true
const startsBefore = document.areDescendantsSorted(startKey, key)
const endsAfter = document.areDescendantsSorted(key, endKey)
return startsBefore && endsAfter
})
const leaves = node.getLeaves(decs)
let offset = 0
const children = leaves.map((leaf, i) => {
const child = this.renderLeaf(leaves, leaf, i, offset)
offset += leaf.text.length
return child
})
// Converts List to Array to support IE 11.
return (
<span data-key={key} style={style}>
{children.toArray()}
</span>
)
}
/**
* Render a single leaf given a `leaf` and `offset`.
*
* @param {List<Leaf>} leaves
* @param {Leaf} leaf
* @param {Number} index
* @param {Number} offset
* @return {Element} leaf
*/
renderLeaf = (leaves, leaf, index, offset) => {
const { block, node, parent, editor } = this.props
const { text, marks } = leaf
return (
<Leaf
key={`${node.key}-${index}`}
block={block}
editor={editor}
index={index}
marks={marks}
node={node}
offset={offset}
parent={parent}
leaves={leaves}
text={text}
/>
)
}
}
/**
* Export.
*
* @type {Component}
*/
export default Text