mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-11 17:53:59 +02:00
add rendering of components from schema
This commit is contained in:
@@ -9,48 +9,6 @@ import initialState from './state.json'
|
|||||||
* @type {Object}
|
* @type {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const schema = {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
match: { type: 'block-quote' },
|
|
||||||
component: props => <blockquote {...props.attributes}>{props.children}</blockquote>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: { type: 'bulleted-list' },
|
|
||||||
component: props => <ul {...props.attributes}>{props.children}</ul>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: { type: 'heading-one' },
|
|
||||||
component: props => <h1 {...props.attributes}>{props.children}</h1>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: { type: 'heading-two' },
|
|
||||||
component: props => <h2 {...props.attributes}>{props.children}</h2>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: { type: 'heading-three' },
|
|
||||||
component: props => <h3 {...props.attributes}>{props.children}</h3>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: { type: 'heading-four' },
|
|
||||||
component: props => <h4 {...props.attributes}>{props.children}</h4>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: { type: 'heading-five' },
|
|
||||||
component: props => <h5 {...props.attributes}>{props.children}</h5>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: { type: 'heading-six' },
|
|
||||||
component: props => <h6 {...props.attributes}>{props.children}</h6>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
match: { type: 'list-item' },
|
|
||||||
component: props => <li {...props.attributes}>{props.children}</li>,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const NODES = {
|
const NODES = {
|
||||||
'block-quote': props => <blockquote>{props.children}</blockquote>,
|
'block-quote': props => <blockquote>{props.children}</blockquote>,
|
||||||
'bulleted-list': props => <ul>{props.children}</ul>,
|
'bulleted-list': props => <ul>{props.children}</ul>,
|
||||||
|
@@ -10,18 +10,20 @@ import initialState from './state.json'
|
|||||||
const DEFAULT_NODE = 'paragraph'
|
const DEFAULT_NODE = 'paragraph'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a set of node renderers.
|
* Define a schema.
|
||||||
*
|
*
|
||||||
* @type {Object}
|
* @type {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const NODES = {
|
const schema = {
|
||||||
'block-quote': (props) => <blockquote {...props.attributes}>{props.children}</blockquote>,
|
nodes: {
|
||||||
|
'block-quote': props => <blockquote {...props.attributes}>{props.children}</blockquote>,
|
||||||
'bulleted-list': props => <ul {...props.attributes}>{props.children}</ul>,
|
'bulleted-list': props => <ul {...props.attributes}>{props.children}</ul>,
|
||||||
'heading-one': props => <h1 {...props.attributes}>{props.children}</h1>,
|
'heading-one': props => <h1 {...props.attributes}>{props.children}</h1>,
|
||||||
'heading-two': props => <h2 {...props.attributes}>{props.children}</h2>,
|
'heading-two': props => <h2 {...props.attributes}>{props.children}</h2>,
|
||||||
'list-item': props => <li {...props.attributes}>{props.children}</li>,
|
'list-item': props => <li {...props.attributes}>{props.children}</li>,
|
||||||
'numbered-list': props => <ol {...props.attributes}>{props.children}</ol>
|
'numbered-list': props => <ol {...props.attributes}>{props.children}</ol>,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -302,8 +304,8 @@ class RichText extends React.Component {
|
|||||||
<div className="editor">
|
<div className="editor">
|
||||||
<Editor
|
<Editor
|
||||||
placeholder={'Enter some rich text...'}
|
placeholder={'Enter some rich text...'}
|
||||||
|
schema={schema}
|
||||||
state={this.state.state}
|
state={this.state.state}
|
||||||
renderNode={this.renderNode}
|
|
||||||
renderMark={this.renderMark}
|
renderMark={this.renderMark}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
@@ -312,17 +314,6 @@ class RichText extends React.Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a node renderer for a Slate `node`.
|
|
||||||
*
|
|
||||||
* @param {Node} node
|
|
||||||
* @return {Component or Void}
|
|
||||||
*/
|
|
||||||
|
|
||||||
renderNode = (node) => {
|
|
||||||
return NODES[node.type]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a mark renderer for a Slate `mark`.
|
* Return a mark renderer for a Slate `mark`.
|
||||||
*
|
*
|
||||||
|
@@ -57,7 +57,7 @@ class Content extends React.Component {
|
|||||||
readOnly: React.PropTypes.bool.isRequired,
|
readOnly: React.PropTypes.bool.isRequired,
|
||||||
renderDecorations: React.PropTypes.func.isRequired,
|
renderDecorations: React.PropTypes.func.isRequired,
|
||||||
renderMark: React.PropTypes.func.isRequired,
|
renderMark: React.PropTypes.func.isRequired,
|
||||||
renderNode: React.PropTypes.func.isRequired,
|
schema: React.PropTypes.object,
|
||||||
spellCheck: React.PropTypes.bool.isRequired,
|
spellCheck: React.PropTypes.bool.isRequired,
|
||||||
state: React.PropTypes.object.isRequired,
|
state: React.PropTypes.object.isRequired,
|
||||||
style: React.PropTypes.object
|
style: React.PropTypes.object
|
||||||
@@ -102,6 +102,7 @@ class Content extends React.Component {
|
|||||||
return (
|
return (
|
||||||
props.className != this.props.className ||
|
props.className != this.props.className ||
|
||||||
props.readOnly != this.props.readOnly ||
|
props.readOnly != this.props.readOnly ||
|
||||||
|
props.schema != this.props.schema ||
|
||||||
props.spellCheck != this.props.spellCheck ||
|
props.spellCheck != this.props.spellCheck ||
|
||||||
props.state != this.props.state ||
|
props.state != this.props.state ||
|
||||||
props.style != this.props.style
|
props.style != this.props.style
|
||||||
@@ -683,17 +684,17 @@ class Content extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (node) => {
|
renderNode = (node) => {
|
||||||
const { editor, renderDecorations, renderMark, renderNode, state } = this.props
|
const { editor, renderDecorations, renderMark, schema, state } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Node
|
<Node
|
||||||
key={node.key}
|
key={node.key}
|
||||||
node={node}
|
node={node}
|
||||||
|
schema={schema}
|
||||||
state={state}
|
state={state}
|
||||||
editor={editor}
|
editor={editor}
|
||||||
renderDecorations={renderDecorations}
|
renderDecorations={renderDecorations}
|
||||||
renderMark={renderMark}
|
renderMark={renderMark}
|
||||||
renderNode={renderNode}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -65,6 +65,7 @@ class Editor extends React.Component {
|
|||||||
renderDecorations: React.PropTypes.func,
|
renderDecorations: React.PropTypes.func,
|
||||||
renderMark: React.PropTypes.func,
|
renderMark: React.PropTypes.func,
|
||||||
renderNode: React.PropTypes.func,
|
renderNode: React.PropTypes.func,
|
||||||
|
schema: React.PropTypes.object,
|
||||||
spellCheck: React.PropTypes.bool,
|
spellCheck: React.PropTypes.bool,
|
||||||
state: React.PropTypes.object.isRequired,
|
state: React.PropTypes.object.isRequired,
|
||||||
style: React.PropTypes.object
|
style: React.PropTypes.object
|
||||||
@@ -118,6 +119,11 @@ class Editor extends React.Component {
|
|||||||
this.setState({ plugins, schema })
|
this.setState({ plugins, schema })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (props.schema != this.props.schema) {
|
||||||
|
const schema = this.resolveSchema(this.state.plugins)
|
||||||
|
this.setState({ schema })
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
state: this.onBeforeChange(props.state)
|
state: this.onBeforeChange(props.state)
|
||||||
})
|
})
|
||||||
@@ -262,7 +268,6 @@ class Editor extends React.Component {
|
|||||||
readOnly={this.props.readOnly}
|
readOnly={this.props.readOnly}
|
||||||
renderDecorations={this.renderDecorations}
|
renderDecorations={this.renderDecorations}
|
||||||
renderMark={this.renderMark}
|
renderMark={this.renderMark}
|
||||||
renderNode={this.renderNode}
|
|
||||||
schema={this.state.schema}
|
schema={this.state.schema}
|
||||||
spellCheck={this.props.spellCheck}
|
spellCheck={this.props.spellCheck}
|
||||||
state={this.state.state}
|
state={this.state.state}
|
||||||
@@ -317,21 +322,6 @@ class Editor extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a `node`, cascading through the plugins.
|
|
||||||
*
|
|
||||||
* @param {Node} node
|
|
||||||
* @return {Element}
|
|
||||||
*/
|
|
||||||
|
|
||||||
renderNode = (node) => {
|
|
||||||
for (const plugin of this.state.plugins) {
|
|
||||||
if (!plugin.renderNode) continue
|
|
||||||
const component = plugin.renderNode(node, this.state.state, this)
|
|
||||||
if (component) return component
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the editor's current plugins from `props` when they change.
|
* Resolve the editor's current plugins from `props` when they change.
|
||||||
*
|
*
|
||||||
|
@@ -36,20 +36,10 @@ class Node extends React.Component {
|
|||||||
node: React.PropTypes.object.isRequired,
|
node: React.PropTypes.object.isRequired,
|
||||||
renderDecorations: React.PropTypes.func.isRequired,
|
renderDecorations: React.PropTypes.func.isRequired,
|
||||||
renderMark: React.PropTypes.func.isRequired,
|
renderMark: React.PropTypes.func.isRequired,
|
||||||
renderNode: React.PropTypes.func.isRequired,
|
schema: React.PropTypes.object.isRequired,
|
||||||
state: React.PropTypes.object.isRequired
|
state: React.PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Default properties.
|
|
||||||
*
|
|
||||||
* @type {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
style: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
@@ -58,11 +48,9 @@ class Node extends React.Component {
|
|||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
const { node, schema } = props
|
||||||
this.state = {}
|
this.state = {}
|
||||||
|
this.state.Component = node.kind == 'text' ? null : node.getComponent(schema)
|
||||||
if (props.node.kind != 'text') {
|
|
||||||
this.state.Component = props.renderNode(props.node)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,10 +76,8 @@ class Node extends React.Component {
|
|||||||
componentWillReceiveProps = (props) => {
|
componentWillReceiveProps = (props) => {
|
||||||
if (props.node.kind == 'text') return
|
if (props.node.kind == 'text') return
|
||||||
if (props.node == this.props.node) return
|
if (props.node == this.props.node) return
|
||||||
|
const Component = props.node.getComponent(props.schema)
|
||||||
this.setState({
|
this.setState({ Component })
|
||||||
Component: props.renderNode(props.node)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -228,18 +214,18 @@ class Node extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (child) => {
|
renderNode = (child) => {
|
||||||
const { editor, node, renderDecorations, renderMark, renderNode, state } = this.props
|
const { editor, node, renderDecorations, renderMark, schema, state } = this.props
|
||||||
const block = node.kind == 'block' ? node : this.props.block
|
const block = node.kind == 'block' ? node : this.props.block
|
||||||
return (
|
return (
|
||||||
<Node
|
<Node
|
||||||
key={child.key}
|
key={child.key}
|
||||||
block={block}
|
block={block}
|
||||||
node={child}
|
node={child}
|
||||||
|
schema={schema}
|
||||||
state={state}
|
state={state}
|
||||||
editor={editor}
|
editor={editor}
|
||||||
renderDecorations={renderDecorations}
|
renderDecorations={renderDecorations}
|
||||||
renderMark={renderMark}
|
renderMark={renderMark}
|
||||||
renderNode={renderNode}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
import RULES from '../constants/rules'
|
import RULES from '../constants/rules'
|
||||||
import includes from 'lodash/includes'
|
import includes from 'lodash/includes'
|
||||||
import isReactComponent from '../utils/is-react-component'
|
|
||||||
import typeOf from 'type-of'
|
import typeOf from 'type-of'
|
||||||
import memoize from '../utils/memoize'
|
import memoize from '../utils/memoize'
|
||||||
import { Record } from 'immutable'
|
import { Record } from 'immutable'
|
||||||
@@ -201,20 +200,22 @@ function normalizeProperties(properties) {
|
|||||||
if (nodes) {
|
if (nodes) {
|
||||||
for (const key in nodes) {
|
for (const key in nodes) {
|
||||||
const value = nodes[key]
|
const value = nodes[key]
|
||||||
let rule
|
const match = {
|
||||||
|
|
||||||
if (isReactComponent(value)) {
|
|
||||||
rule.match = { type: key }
|
|
||||||
rule.component = value
|
|
||||||
} else {
|
|
||||||
rule = {
|
|
||||||
kinds: ['block', 'inline'],
|
kinds: ['block', 'inline'],
|
||||||
type: key,
|
type: key,
|
||||||
...value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rules.push(rule)
|
if (value.component) {
|
||||||
|
rules.push({
|
||||||
|
match,
|
||||||
|
...value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
rules.push({
|
||||||
|
match,
|
||||||
|
component: value
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,20 +223,22 @@ function normalizeProperties(properties) {
|
|||||||
if (marks) {
|
if (marks) {
|
||||||
for (const key in marks) {
|
for (const key in marks) {
|
||||||
const value = marks[key]
|
const value = marks[key]
|
||||||
let rule
|
const match = {
|
||||||
|
|
||||||
if (rule.match) {
|
|
||||||
rule = {
|
|
||||||
kind: 'mark',
|
kind: 'mark',
|
||||||
type: key,
|
type: key,
|
||||||
...value
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rule.match = { type: key }
|
|
||||||
rule.component = value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rules.push(rule)
|
if (value.component) {
|
||||||
|
rules.push({
|
||||||
|
match,
|
||||||
|
...value,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
rules.push({
|
||||||
|
match,
|
||||||
|
component: value
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,6 +256,7 @@ function normalizeProperties(properties) {
|
|||||||
|
|
||||||
function normalizeRule(rule) {
|
function normalizeRule(rule) {
|
||||||
return {
|
return {
|
||||||
|
...rule,
|
||||||
match: normalizeMatch(rule.match),
|
match: normalizeMatch(rule.match),
|
||||||
validate: normalizeValidate(rule.validate),
|
validate: normalizeValidate(rule.validate),
|
||||||
transform: normalizeTransform(rule.transform),
|
transform: normalizeTransform(rule.transform),
|
||||||
|
Reference in New Issue
Block a user