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 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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
|
||||||
|
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'
|
import React from 'react'
|
||||||
|
|
||||||
const BOLD = {
|
function BOLD(props) {
|
||||||
fontWeight: 'bold'
|
return <strong>{props.children}</strong>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderMark(mark) {
|
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'
|
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
|
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