1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-02-18 22:24:38 +01:00

Add ability for renderMark to return a React component (#202)

* Switch rendering of leaf to use mark as component

* Backward compatibility with renderMark

Don’t fail on null marks

* Adapt tests for new rendering of marks

* Fix selection with new rendered marks

* Adapt rendering test for custom-mark-multiple

Don’t add span when renderMark return undefined
This commit is contained in:
Samy Pessé 2016-07-29 19:46:56 +02:00 committed by Ian Storm Taylor
parent 788627d2db
commit 4d58c0035c
10 changed files with 99 additions and 27 deletions

View File

@ -242,17 +242,22 @@ class Editor extends React.Component {
*
* @param {Mark} mark
* @param {Set} marks
* @return {Object}
* @return {Element}
*/
renderMark = (mark, marks) => {
for (const plugin of this.state.plugins) {
if (!plugin.renderMark) continue
const style = plugin.renderMark(mark, marks, this.state.state, this)
if (style) return style
}
let component = plugin.renderMark(mark, marks, this.state.state, this)
return {}
// plugin.renderMak can return a map of style
if (component && !(typeof component === 'function')) {
const style = component
component = (props => <span style={style}>{props.children}</span>)
}
if (component) return component
}
}
/**

View File

@ -3,6 +3,22 @@ import OffsetKey from '../utils/offset-key'
import React from 'react'
import ReactDOM from 'react-dom'
/**
* Find the deepest child (text node) of a DOM node
* @param {DOMNode} node
* @return {DOMNode}
*/
function findDeepestNode(node) {
let child = node.firstChild
if (child) {
return findDeepestNode(child)
}
return node
}
/**
* Leaf.
*/
@ -86,7 +102,7 @@ class Leaf extends React.Component {
// We have a selection to render, so prepare a few things...
const native = window.getSelection()
const el = ReactDOM.findDOMNode(this).firstChild
const el = findDeepestNode(ReactDOM.findDOMNode(this))
// If both the start and end are here, set the selection all at once.
if (hasAnchor && hasFocus) {
@ -151,9 +167,8 @@ class Leaf extends React.Component {
<span
key={this.tmp.renders}
data-offset-key={offsetKey}
style={this.renderStyle()}
>
{this.renderText()}
{this.renderWithMarks()}
</span>
)
}
@ -172,21 +187,33 @@ class Leaf extends React.Component {
return text
}
renderStyle() {
const { marks, renderMark } = this.props
const style = marks.reduce((memo, mark) => {
const styles = renderMark(mark, marks)
renderMark(inner, mark) {
const { node, index, renderMark, marks } = this.props
const offsetKey = OffsetKey.stringify({
key: node.key,
index
})
for (const key in styles) {
memo[key] = styles[key]
const MarkComponent = renderMark(mark, marks)
if (!MarkComponent) {
return inner
}
return memo
}, {})
return style
return (
<MarkComponent
mark={mark}
>
{inner}
</MarkComponent>
)
}
renderWithMarks() {
const { marks, renderMark } = this.props
const element = marks.reduce(this.renderMark, this.renderText(), this)
return element
}
}
/**

View File

@ -175,7 +175,7 @@ class Void extends React.Component {
*/
renderLeafMark = (mark) => {
return {}
return
}
}

View File

@ -3,7 +3,7 @@
<div style="position:relative;">
<span>
<span>o</span>
<span style="font-weight:bold;">n</span>
<span><span style="font-weight:bold;">n</span></span>
<span>e</span>
</span>
</div>

View File

@ -0,0 +1,13 @@
import React from 'react'
const BOLD = {
fontWeight: 'bold'
}
const ITALIC = (props => <i>{props.children}</i>)
export function renderMark(mark, marks) {
if (mark.type == 'bold') return BOLD
if (mark.type == 'italic') return ITALIC
}

View File

@ -0,0 +1,17 @@
nodes:
- kind: block
type: default
nodes:
- kind: text
ranges:
- text: one
marks:
- type: bold
- text: two
marks:
- type: italic
- text: three
marks:
- type: bold
- type: italic

View File

@ -0,0 +1,10 @@
<div contenteditable="true">
<div style="position:relative;">
<span>
<span><span style="font-weight:bold;">one</span></span>
<span><i>two</i></span>
<span><i><span style="font-weight:bold;">three</span></i></span>
</span>
</div>
</div>

View File

@ -16,10 +16,10 @@ const BOLD_ITALIC = {
export function renderMark(mark, marks) {
if (
marks.size > 1 &&
marks.some(m => m.type == 'bold') &&
marks.some(m => m.type == 'italic')
marks.some(m => m.type == 'italic') &&
marks.some(m => m.type == 'bold')
) {
return BOLD_ITALIC
return mark.type == 'bold' ? BOLD_ITALIC : undefined
}
if (mark.type == 'bold') return BOLD

View File

@ -2,9 +2,9 @@
<div contenteditable="true">
<div style="position:relative;">
<span>
<span style="font-weight:bold;">one</span>
<span style="font-style:italic;">two</span>
<span style="font-family:bold-italic;">three</span>
<span><span style="font-weight:bold;">one</span></span>
<span><span style="font-style:italic;">two</span></span>
<span><span style="font-family:bold-italic;">three</span></span>
</span>
</div>
</div>

View File

@ -3,7 +3,7 @@
<div style="position:relative;">
<span>
<span>one</span>
<span style="font-weight:bold;">two</span>
<span><span style="font-weight:bold;">two</span></span>
<span>three</span>
</span>
</div>