1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-26 00:27:28 +02:00

fix add support for rendering components as marks

This commit is contained in:
Ian Storm Taylor
2016-07-29 11:20:00 -07:00
parent 4d58c0035c
commit fb97c50c4c
19 changed files with 147 additions and 65 deletions

View File

@@ -3,6 +3,7 @@ import Content from './content'
import CorePlugin from '../plugins/core' import CorePlugin from '../plugins/core'
import React from 'react' import React from 'react'
import State from '../models/state' import State from '../models/state'
import typeOf from 'type-of'
/** /**
* Noop. * Noop.
@@ -242,21 +243,26 @@ class Editor extends React.Component {
* *
* @param {Mark} mark * @param {Mark} mark
* @param {Set} marks * @param {Set} marks
* @return {Element} * @return {Component or Object or String}
*/ */
renderMark = (mark, marks) => { renderMark = (mark, marks) => {
for (const plugin of this.state.plugins) { for (const plugin of this.state.plugins) {
if (!plugin.renderMark) continue if (!plugin.renderMark) continue
let component = plugin.renderMark(mark, marks, this.state.state, this) let ret = plugin.renderMark(mark, marks, this.state.state, this)
// plugin.renderMak can return a map of style // Handle React components that aren't stateless functions.
if (component && !(typeof component === 'function')) { if (ret && ret.prototype && ret.prototype.isReactComponent) return ret
const style = component
component = (props => <span style={style}>{props.children}</span>) // Handle all other types...
switch (typeOf(ret)) {
case 'function':
return ret
case 'object':
return props => <span style={ret}>{props.children}</span>
case 'string':
return props => <span className={ret}>{props.children}</span>
} }
if (component) return component
} }
} }

View File

@@ -3,22 +3,6 @@ import OffsetKey from '../utils/offset-key'
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' 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. * Leaf.
*/ */
@@ -168,7 +152,7 @@ class Leaf extends React.Component {
key={this.tmp.renders} key={this.tmp.renders}
data-offset-key={offsetKey} data-offset-key={offsetKey}
> >
{this.renderWithMarks()} {this.renderMarks()}
</span> </span>
) )
} }
@@ -187,33 +171,29 @@ class Leaf extends React.Component {
return text return text
} }
renderMark(inner, mark) { renderMarks() {
const { node, index, renderMark, marks } = this.props const { marks, renderMark } = this.props
const offsetKey = OffsetKey.stringify({ const text = this.renderText()
key: node.key,
index
})
const MarkComponent = renderMark(mark, marks) return marks.reduce((children, mark) => {
if (!MarkComponent) { const Component = renderMark(mark, marks)
return inner if (!Component) return children
} return <Component mark={mark} marks={marks}>{children}</Component>
}, text)
return (
<MarkComponent
mark={mark}
>
{inner}
</MarkComponent>
)
} }
}
renderWithMarks() { /**
const { marks, renderMark } = this.props * Find the deepest descendant of a DOM `element`.
const element = marks.reduce(this.renderMark, this.renderText(), this) *
* @param {Element} node
* @return {Element}
*/
return element function findDeepestNode(element) {
} return element.firstChild
? findDeepestNode(element.firstChild)
: element
} }
/** /**

View File

@@ -7,6 +7,14 @@ import ReactDOM from 'react-dom'
import keycode from 'keycode' import keycode from 'keycode'
import { IS_FIREFOX } from '../utils/environment' import { IS_FIREFOX } from '../utils/environment'
/**
* Noop.
*
* @type {Function}
*/
function noop() {}
/** /**
* Void. * Void.
* *
@@ -156,7 +164,7 @@ class Void extends React.Component {
return ( return (
<Leaf <Leaf
renderMark={this.renderLeafMark} renderMark={noop}
key={offsetKey} key={offsetKey}
state={state} state={state}
node={child} node={child}
@@ -168,16 +176,6 @@ class Void extends React.Component {
) )
} }
/**
* Render a fake leaf mark.
*
* @return {Object}
*/
renderLeafMark = (mark) => {
return
}
} }
/** /**

View File

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

View File

@@ -0,0 +1,12 @@
import React from 'react'
class Bold extends React.Component {
render() {
return <strong>{this.props.children}</strong>
}
}
export function renderMark(mark) {
if (mark.type == 'bold') return Bold
}

View File

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

View File

@@ -1,8 +1,8 @@
import React from 'react' import React from 'react'
const BOLD = { function BOLD(props) {
fontWeight: 'bold' return <strong>{props.children}</strong>
} }
export function renderMark(mark) { export function renderMark(mark) {

View File

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

View File

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

View File

@@ -5,7 +5,9 @@ const BOLD = {
fontWeight: 'bold' fontWeight: 'bold'
} }
const ITALIC = (props => <i>{props.children}</i>) function ITALIC(props) {
return <i>{props.children}</i>
}
export function renderMark(mark, marks) { export function renderMark(mark, marks) {
if (mark.type == 'bold') return BOLD if (mark.type == 'bold') return BOLD

View File

@@ -0,0 +1,10 @@
import React from 'react'
export function renderMark(mark) {
if (mark.type == 'bold') {
return {
fontWeight: 'bold'
}
}
}

View File

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

View File

@@ -0,0 +1,6 @@
import React from 'react'
export function renderMark(mark) {
if (mark.type == 'bold') return 'bold'
}

View File

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

View File

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