mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-21 13:51:59 +02:00
add rendering of components from schema
This commit is contained in:
parent
1008a2fb14
commit
eeb97c0611
@ -9,48 +9,6 @@ import initialState from './state.json'
|
||||
* @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 = {
|
||||
'block-quote': props => <blockquote>{props.children}</blockquote>,
|
||||
'bulleted-list': props => <ul>{props.children}</ul>,
|
||||
|
@ -10,18 +10,20 @@ import initialState from './state.json'
|
||||
const DEFAULT_NODE = 'paragraph'
|
||||
|
||||
/**
|
||||
* Define a set of node renderers.
|
||||
* Define a schema.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
const NODES = {
|
||||
'block-quote': (props) => <blockquote {...props.attributes}>{props.children}</blockquote>,
|
||||
'bulleted-list': props => <ul {...props.attributes}>{props.children}</ul>,
|
||||
'heading-one': props => <h1 {...props.attributes}>{props.children}</h1>,
|
||||
'heading-two': props => <h2 {...props.attributes}>{props.children}</h2>,
|
||||
'list-item': props => <li {...props.attributes}>{props.children}</li>,
|
||||
'numbered-list': props => <ol {...props.attributes}>{props.children}</ol>
|
||||
const schema = {
|
||||
nodes: {
|
||||
'block-quote': props => <blockquote {...props.attributes}>{props.children}</blockquote>,
|
||||
'bulleted-list': props => <ul {...props.attributes}>{props.children}</ul>,
|
||||
'heading-one': props => <h1 {...props.attributes}>{props.children}</h1>,
|
||||
'heading-two': props => <h2 {...props.attributes}>{props.children}</h2>,
|
||||
'list-item': props => <li {...props.attributes}>{props.children}</li>,
|
||||
'numbered-list': props => <ol {...props.attributes}>{props.children}</ol>,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -302,8 +304,8 @@ class RichText extends React.Component {
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder={'Enter some rich text...'}
|
||||
schema={schema}
|
||||
state={this.state.state}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
onChange={this.onChange}
|
||||
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`.
|
||||
*
|
||||
|
@ -57,7 +57,7 @@ class Content extends React.Component {
|
||||
readOnly: React.PropTypes.bool.isRequired,
|
||||
renderDecorations: React.PropTypes.func.isRequired,
|
||||
renderMark: React.PropTypes.func.isRequired,
|
||||
renderNode: React.PropTypes.func.isRequired,
|
||||
schema: React.PropTypes.object,
|
||||
spellCheck: React.PropTypes.bool.isRequired,
|
||||
state: React.PropTypes.object.isRequired,
|
||||
style: React.PropTypes.object
|
||||
@ -102,6 +102,7 @@ class Content extends React.Component {
|
||||
return (
|
||||
props.className != this.props.className ||
|
||||
props.readOnly != this.props.readOnly ||
|
||||
props.schema != this.props.schema ||
|
||||
props.spellCheck != this.props.spellCheck ||
|
||||
props.state != this.props.state ||
|
||||
props.style != this.props.style
|
||||
@ -683,17 +684,17 @@ class Content extends React.Component {
|
||||
*/
|
||||
|
||||
renderNode = (node) => {
|
||||
const { editor, renderDecorations, renderMark, renderNode, state } = this.props
|
||||
const { editor, renderDecorations, renderMark, schema, state } = this.props
|
||||
|
||||
return (
|
||||
<Node
|
||||
key={node.key}
|
||||
node={node}
|
||||
schema={schema}
|
||||
state={state}
|
||||
editor={editor}
|
||||
renderDecorations={renderDecorations}
|
||||
renderMark={renderMark}
|
||||
renderNode={renderNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ class Editor extends React.Component {
|
||||
renderDecorations: React.PropTypes.func,
|
||||
renderMark: React.PropTypes.func,
|
||||
renderNode: React.PropTypes.func,
|
||||
schema: React.PropTypes.object,
|
||||
spellCheck: React.PropTypes.bool,
|
||||
state: React.PropTypes.object.isRequired,
|
||||
style: React.PropTypes.object
|
||||
@ -118,6 +119,11 @@ class Editor extends React.Component {
|
||||
this.setState({ plugins, schema })
|
||||
}
|
||||
|
||||
else if (props.schema != this.props.schema) {
|
||||
const schema = this.resolveSchema(this.state.plugins)
|
||||
this.setState({ schema })
|
||||
}
|
||||
|
||||
this.setState({
|
||||
state: this.onBeforeChange(props.state)
|
||||
})
|
||||
@ -262,7 +268,6 @@ class Editor extends React.Component {
|
||||
readOnly={this.props.readOnly}
|
||||
renderDecorations={this.renderDecorations}
|
||||
renderMark={this.renderMark}
|
||||
renderNode={this.renderNode}
|
||||
schema={this.state.schema}
|
||||
spellCheck={this.props.spellCheck}
|
||||
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.
|
||||
*
|
||||
|
@ -36,20 +36,10 @@ class Node extends React.Component {
|
||||
node: React.PropTypes.object.isRequired,
|
||||
renderDecorations: React.PropTypes.func.isRequired,
|
||||
renderMark: React.PropTypes.func.isRequired,
|
||||
renderNode: React.PropTypes.func.isRequired,
|
||||
schema: React.PropTypes.object.isRequired,
|
||||
state: React.PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
/**
|
||||
* Default properties.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
static defaultProps = {
|
||||
style: {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@ -58,11 +48,9 @@ class Node extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
const { node, schema } = props
|
||||
this.state = {}
|
||||
|
||||
if (props.node.kind != 'text') {
|
||||
this.state.Component = props.renderNode(props.node)
|
||||
}
|
||||
this.state.Component = node.kind == 'text' ? null : node.getComponent(schema)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,10 +76,8 @@ class Node extends React.Component {
|
||||
componentWillReceiveProps = (props) => {
|
||||
if (props.node.kind == 'text') return
|
||||
if (props.node == this.props.node) return
|
||||
|
||||
this.setState({
|
||||
Component: props.renderNode(props.node)
|
||||
})
|
||||
const Component = props.node.getComponent(props.schema)
|
||||
this.setState({ Component })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,18 +214,18 @@ class Node extends React.Component {
|
||||
*/
|
||||
|
||||
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
|
||||
return (
|
||||
<Node
|
||||
key={child.key}
|
||||
block={block}
|
||||
node={child}
|
||||
schema={schema}
|
||||
state={state}
|
||||
editor={editor}
|
||||
renderDecorations={renderDecorations}
|
||||
renderMark={renderMark}
|
||||
renderNode={renderNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
import RULES from '../constants/rules'
|
||||
import includes from 'lodash/includes'
|
||||
import isReactComponent from '../utils/is-react-component'
|
||||
import typeOf from 'type-of'
|
||||
import memoize from '../utils/memoize'
|
||||
import { Record } from 'immutable'
|
||||
@ -201,20 +200,22 @@ function normalizeProperties(properties) {
|
||||
if (nodes) {
|
||||
for (const key in nodes) {
|
||||
const value = nodes[key]
|
||||
let rule
|
||||
|
||||
if (isReactComponent(value)) {
|
||||
rule.match = { type: key }
|
||||
rule.component = value
|
||||
} else {
|
||||
rule = {
|
||||
kinds: ['block', 'inline'],
|
||||
type: key,
|
||||
...value
|
||||
}
|
||||
const match = {
|
||||
kinds: ['block', 'inline'],
|
||||
type: key,
|
||||
}
|
||||
|
||||
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) {
|
||||
for (const key in marks) {
|
||||
const value = marks[key]
|
||||
let rule
|
||||
|
||||
if (rule.match) {
|
||||
rule = {
|
||||
kind: 'mark',
|
||||
type: key,
|
||||
...value
|
||||
}
|
||||
} else {
|
||||
rule.match = { type: key }
|
||||
rule.component = value
|
||||
const match = {
|
||||
kind: 'mark',
|
||||
type: key,
|
||||
}
|
||||
|
||||
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) {
|
||||
return {
|
||||
...rule,
|
||||
match: normalizeMatch(rule.match),
|
||||
validate: normalizeValidate(rule.validate),
|
||||
transform: normalizeTransform(rule.transform),
|
||||
|
Loading…
x
Reference in New Issue
Block a user