1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-04-20 13:22:04 +02:00

first stab at plugin rendering (#629)

This commit is contained in:
Ian Storm Taylor 2017-02-25 13:40:22 -08:00 committed by GitHub
parent 8f92ec6a6d
commit 2ebfb24234
4 changed files with 85 additions and 32 deletions

View File

@ -15,6 +15,7 @@
"immutable": "^3.8.1",
"is-empty": "^1.0.0",
"keycode": "^2.1.2",
"react-portal": "^3.0.0",
"type-of": "^2.0.1"
},
"peerDependencies": {
@ -59,7 +60,6 @@
"react-dom": "^15.4.2",
"react-frame-aware-selection-plugin": "^1.0.0",
"react-frame-component": "^0.6.2",
"react-portal": "^3.0.0",
"react-router": "^2.5.1",
"read-metadata": "^1.0.0",
"read-yaml-promise": "^1.0.2",

View File

@ -36,6 +36,7 @@ class Content extends React.Component {
static propTypes = {
autoCorrect: React.PropTypes.bool.isRequired,
children: React.PropTypes.object.isRequired,
className: React.PropTypes.string,
editor: React.PropTypes.object.isRequired,
onBeforeInput: React.PropTypes.func.isRequired,
@ -755,6 +756,7 @@ class Content extends React.Component {
tabIndex={tabIndex}
>
{children}
{this.props.children}
</div>
)
}

View File

@ -1,6 +1,7 @@
import Content from './content'
import Debug from 'debug'
import Portal from 'react-portal'
import React from 'react'
import Stack from '../models/stack'
import State from '../models/state'
@ -238,7 +239,9 @@ class Editor extends React.Component {
render = () => {
const { props, state } = this
const { stack } = state
const handlers = {}
const children = stack.render(state.state, this)
for (const property of EVENT_HANDLERS) {
handlers[property] = this[property]
@ -260,7 +263,9 @@ class Editor extends React.Component {
style={props.style}
tabIndex={props.tabIndex}
role={props.role}
/>
>
{children.map((child, i) => <Portal key={i} isOpened>{child}</Portal>)}
</Content>
)
}

View File

@ -19,7 +19,7 @@ const debug = Debug('slate:stack')
* @type {Array}
*/
const EVENT_METHODS = [
const EVENT_HANDLER_METHODS = [
'onBeforeInput',
'onBlur',
'onCopy',
@ -36,20 +36,20 @@ const EVENT_METHODS = [
* @type {Array}
*/
const ACCUMULATOR_METHODS = [
const STATE_ACCUMULATOR_METHODS = [
'onBeforeChange',
'onChange',
]
/**
* All the runnable methods.
* Methods that accumulate an array.
*
* @type {Array}
*/
const RUNNABLE_METHODS = []
.concat(EVENT_METHODS)
.concat(ACCUMULATOR_METHODS)
const ARRAY_ACCUMULATOR_METHODS = [
'render'
]
/**
* Default properties.
@ -95,17 +95,19 @@ class Stack extends new Record(DEFAULTS) {
return 'stack'
}
/**
* Run a `method` in the stack with `state`.
*
* @param {String} method
* @param {State} state
* @param {Editor} editor
* @param {Mixed} ...args
* @return {State}
*/
}
run(method, state, editor, ...args) {
/**
* Mix in the event handler methods.
*
* @param {State} state
* @param {Editor} editor
* @param {Mixed} ...args
* @return {State|Null}
*/
for (const method of EVENT_HANDLER_METHODS) {
Stack.prototype[method] = function (state, editor, ...args) {
debug(method)
if (method == 'onChange') {
@ -115,32 +117,76 @@ class Stack extends new Record(DEFAULTS) {
for (const plugin of this.plugins) {
if (!plugin[method]) continue
const next = plugin[method](...args, state, editor)
if (next == null) {
continue
} else if (next instanceof State) {
state = next
if (!ACCUMULATOR_METHODS.includes(method)) break
} else {
throw new Error(`A plugin returned an unexpected state value: ${next}`)
}
if (next == null) continue
assertState(next)
return next
}
return state
}
}
/**
* Mix in the runnable methods.
* Mix in the state accumulator methods.
*
* @param {State} state
* @param {Editor} editor
* @param {Mixed} ...args
* @return {State|Null}
*/
for (const method of RUNNABLE_METHODS) {
Stack.prototype[method] = function (...args) {
return this.run(method, ...args)
for (const method of STATE_ACCUMULATOR_METHODS) {
Stack.prototype[method] = function (state, editor, ...args) {
debug(method)
for (const plugin of this.plugins) {
if (!plugin[method]) continue
const next = plugin[method](...args, state, editor)
if (next == null) continue
assertState(next)
state = next
}
return state
}
}
/**
* Mix in the array accumulator methods.
*
* @param {State} state
* @param {Editor} editor
* @param {Mixed} ...args
* @return {Array}
*/
for (const method of ARRAY_ACCUMULATOR_METHODS) {
Stack.prototype[method] = function (state, editor, ...args) {
debug(method)
const array = []
for (const plugin of this.plugins) {
if (!plugin[method]) continue
const next = plugin[method](...args, state, editor)
if (next == null) continue
array.push(next)
}
return array
}
}
/**
* Assert that a `value` is a state object.
*
* @param {Mixed} value
*/
function assertState(value) {
if (value instanceof State) return
throw new Error(`A plugin returned an unexpected state value: ${value}`)
}
/**
* Resolve a schema from a set of `plugins`.
*