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:
@@ -3,6 +3,7 @@ import Content from './content'
|
||||
import CorePlugin from '../plugins/core'
|
||||
import React from 'react'
|
||||
import State from '../models/state'
|
||||
import typeOf from 'type-of'
|
||||
|
||||
/**
|
||||
* Noop.
|
||||
@@ -242,21 +243,26 @@ class Editor extends React.Component {
|
||||
*
|
||||
* @param {Mark} mark
|
||||
* @param {Set} marks
|
||||
* @return {Element}
|
||||
* @return {Component or Object or String}
|
||||
*/
|
||||
|
||||
renderMark = (mark, marks) => {
|
||||
for (const plugin of this.state.plugins) {
|
||||
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
|
||||
if (component && !(typeof component === 'function')) {
|
||||
const style = component
|
||||
component = (props => <span style={style}>{props.children}</span>)
|
||||
// Handle React components that aren't stateless functions.
|
||||
if (ret && ret.prototype && ret.prototype.isReactComponent) return ret
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,22 +3,6 @@ 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.
|
||||
*/
|
||||
@@ -168,7 +152,7 @@ class Leaf extends React.Component {
|
||||
key={this.tmp.renders}
|
||||
data-offset-key={offsetKey}
|
||||
>
|
||||
{this.renderWithMarks()}
|
||||
{this.renderMarks()}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -187,35 +171,31 @@ class Leaf extends React.Component {
|
||||
return text
|
||||
}
|
||||
|
||||
renderMark(inner, mark) {
|
||||
const { node, index, renderMark, marks } = this.props
|
||||
const offsetKey = OffsetKey.stringify({
|
||||
key: node.key,
|
||||
index
|
||||
})
|
||||
|
||||
const MarkComponent = renderMark(mark, marks)
|
||||
if (!MarkComponent) {
|
||||
return inner
|
||||
}
|
||||
|
||||
return (
|
||||
<MarkComponent
|
||||
mark={mark}
|
||||
>
|
||||
{inner}
|
||||
</MarkComponent>
|
||||
)
|
||||
}
|
||||
|
||||
renderWithMarks() {
|
||||
renderMarks() {
|
||||
const { marks, renderMark } = this.props
|
||||
const element = marks.reduce(this.renderMark, this.renderText(), this)
|
||||
const text = this.renderText()
|
||||
|
||||
return element
|
||||
return marks.reduce((children, mark) => {
|
||||
const Component = renderMark(mark, marks)
|
||||
if (!Component) return children
|
||||
return <Component mark={mark} marks={marks}>{children}</Component>
|
||||
}, text)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the deepest descendant of a DOM `element`.
|
||||
*
|
||||
* @param {Element} node
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
function findDeepestNode(element) {
|
||||
return element.firstChild
|
||||
? findDeepestNode(element.firstChild)
|
||||
: element
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
@@ -7,6 +7,14 @@ import ReactDOM from 'react-dom'
|
||||
import keycode from 'keycode'
|
||||
import { IS_FIREFOX } from '../utils/environment'
|
||||
|
||||
/**
|
||||
* Noop.
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
function noop() {}
|
||||
|
||||
/**
|
||||
* Void.
|
||||
*
|
||||
@@ -156,7 +164,7 @@ class Void extends React.Component {
|
||||
|
||||
return (
|
||||
<Leaf
|
||||
renderMark={this.renderLeafMark}
|
||||
renderMark={noop}
|
||||
key={offsetKey}
|
||||
state={state}
|
||||
node={child}
|
||||
@@ -168,16 +176,6 @@ class Void extends React.Component {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a fake leaf mark.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
|
||||
renderLeafMark = (mark) => {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -16,10 +16,12 @@ const BOLD_ITALIC = {
|
||||
export function renderMark(mark, marks) {
|
||||
if (
|
||||
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
|
||||
|
12
test/rendering/fixtures/custom-mark-with-component/index.js
Normal file
12
test/rendering/fixtures/custom-mark-with-component/index.js
Normal 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
|
||||
}
|
@@ -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>
|
@@ -1,8 +1,8 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
const BOLD = {
|
||||
fontWeight: 'bold'
|
||||
function BOLD(props) {
|
||||
return <strong>{props.children}</strong>
|
||||
}
|
||||
|
||||
export function renderMark(mark) {
|
12
test/rendering/fixtures/custom-mark-with-function/input.yaml
Normal file
12
test/rendering/fixtures/custom-mark-with-function/input.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: one
|
||||
- text: two
|
||||
marks:
|
||||
- type: bold
|
||||
- text: three
|
@@ -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>
|
@@ -5,7 +5,9 @@ const BOLD = {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
|
||||
const ITALIC = (props => <i>{props.children}</i>)
|
||||
function ITALIC(props) {
|
||||
return <i>{props.children}</i>
|
||||
}
|
||||
|
||||
export function renderMark(mark, marks) {
|
||||
if (mark.type == 'bold') return BOLD
|
10
test/rendering/fixtures/custom-mark-with-object/index.js
Normal file
10
test/rendering/fixtures/custom-mark-with-object/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
export function renderMark(mark) {
|
||||
if (mark.type == 'bold') {
|
||||
return {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
}
|
||||
}
|
12
test/rendering/fixtures/custom-mark-with-object/input.yaml
Normal file
12
test/rendering/fixtures/custom-mark-with-object/input.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: one
|
||||
- text: two
|
||||
marks:
|
||||
- type: bold
|
||||
- text: three
|
6
test/rendering/fixtures/custom-mark-with-string/index.js
Normal file
6
test/rendering/fixtures/custom-mark-with-string/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
import React from 'react'
|
||||
|
||||
export function renderMark(mark) {
|
||||
if (mark.type == 'bold') return 'bold'
|
||||
}
|
12
test/rendering/fixtures/custom-mark-with-string/input.yaml
Normal file
12
test/rendering/fixtures/custom-mark-with-string/input.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
nodes:
|
||||
- kind: block
|
||||
type: default
|
||||
nodes:
|
||||
- kind: text
|
||||
ranges:
|
||||
- text: one
|
||||
- text: two
|
||||
marks:
|
||||
- type: bold
|
||||
- text: three
|
10
test/rendering/fixtures/custom-mark-with-string/output.html
Normal file
10
test/rendering/fixtures/custom-mark-with-string/output.html
Normal 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>
|
Reference in New Issue
Block a user