1
0
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:
Ian Storm Taylor 2016-08-13 16:48:21 -07:00
parent 1008a2fb14
commit eeb97c0611
6 changed files with 57 additions and 127 deletions
examples
auto-markdown
rich-text
lib

@ -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),