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:
parent
788627d2db
commit
4d58c0035c
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,7 +175,7 @@ class Void extends React.Component {
|
||||
*/
|
||||
|
||||
renderLeafMark = (mark) => {
|
||||
return {}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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>
|
||||
|
13
test/rendering/fixtures/custom-mark-combine/index.js
Normal file
13
test/rendering/fixtures/custom-mark-combine/index.js
Normal 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
|
||||
}
|
17
test/rendering/fixtures/custom-mark-combine/input.yaml
Normal file
17
test/rendering/fixtures/custom-mark-combine/input.yaml
Normal 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
|
10
test/rendering/fixtures/custom-mark-combine/output.html
Normal file
10
test/rendering/fixtures/custom-mark-combine/output.html
Normal 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>
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user