mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-11 09:43:58 +02:00
rename plugin.render to renderPortal, and add plugin.render
This commit is contained in:
11
History.md
11
History.md
@@ -4,6 +4,17 @@ This document maintains a list of changes to Slate with each new version. Until
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
### `0.18.0` — March 2, 2017
|
||||||
|
|
||||||
|
###### BREAKING CHANGES
|
||||||
|
|
||||||
|
- **The `plugin.render` property is now called `plugin.renderPortal`.** This is to make way for the new `plugin.render` property that offers HOC-like behavior, so that plugins can augment the editor however they choose.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
### `0.17.0` — February 27, 2017
|
### `0.17.0` — February 27, 2017
|
||||||
|
|
||||||
###### DEPRECATION CHANGES
|
###### DEPRECATION CHANGES
|
||||||
|
@@ -43,6 +43,10 @@ When the user pastes content into the editor, the core plugin handles all pastes
|
|||||||
|
|
||||||
When the user makes a new selection in the DOM, the core plugin updates that selection in Slate's internal data model, re-rendering if it needs to.
|
When the user makes a new selection in the DOM, the core plugin updates that selection in Slate's internal data model, re-rendering if it needs to.
|
||||||
|
|
||||||
|
### `render`
|
||||||
|
|
||||||
|
Renders all of the default contents of the editor!
|
||||||
|
|
||||||
### `schema`
|
### `schema`
|
||||||
|
|
||||||
The core plugin defines a schema that enforces a few constraints on the content and defines default block and inline node renderer components—wrapping in a `<div>` and `<span>`, respectively. Each of these components contains `shouldComponentUpdate` logic that prevents unnecessary re-renders.
|
The core plugin defines a schema that enforces a few constraints on the content and defines default block and inline node renderer components—wrapping in a `<div>` and `<span>`, respectively. Each of these components contains `shouldComponentUpdate` logic that prevents unnecessary re-renders.
|
||||||
|
@@ -20,6 +20,8 @@ When the editor needs to resolve a plugin-related handler, it will loop through
|
|||||||
- [Other Properties](#other-properties)
|
- [Other Properties](#other-properties)
|
||||||
- [`onChange`](#onchange)
|
- [`onChange`](#onchange)
|
||||||
- [`onBeforeChange`](#onbeforechange)
|
- [`onBeforeChange`](#onbeforechange)
|
||||||
|
- [`render`](#render)
|
||||||
|
- [`renderPortal`](#renderportal)
|
||||||
- [`schema`](#schema)
|
- [`schema`](#schema)
|
||||||
|
|
||||||
|
|
||||||
@@ -181,7 +183,7 @@ The `data` object is a convenience object created to standardize the paste metad
|
|||||||
If no other plugin handles this event, it will be handled by the [Core plugin](./core.md).
|
If no other plugin handles this event, it will be handled by the [Core plugin](./core.md).
|
||||||
|
|
||||||
### `onSelect`
|
### `onSelect`
|
||||||
`Function onSelect(event: Event, data: Object, state: State, editor: Editor => State || Void`
|
`Function onSelect(event: Event, data: Object, state: State, editor: Editor) => State || Void`
|
||||||
|
|
||||||
This handler is called whenever the native DOM selection changes.
|
This handler is called whenever the native DOM selection changes.
|
||||||
|
|
||||||
@@ -216,6 +218,16 @@ The `onBeforeChange` handler isn't a native browser event handler. Instead, it i
|
|||||||
|
|
||||||
Like `onChange`, `onBeforeChange` is cummulative.
|
Like `onChange`, `onBeforeChange` is cummulative.
|
||||||
|
|
||||||
|
### `render`
|
||||||
|
`Function render(props: Object, state: State, editor: Editor) => Object || Void`
|
||||||
|
|
||||||
|
The `render` property allows you to define higher-order-component-like behavior. It is passed all of the properties of the editor, including `props.children`. You can then choose to wrap the existing `children` in any custom elements or proxy the properties however you choose. This can be useful for rendering toolbars, styling the editor, rendering validation, etc.
|
||||||
|
|
||||||
|
### `renderPortal`
|
||||||
|
`Function renderPortal(state: State, editor: Editor) => Object || Void`
|
||||||
|
|
||||||
|
The `renderPortal` property allows you to define extra elements that will render outside of the editor, in a separate [portal](). This is useful for rendering hovering menus, or other cases where you don't need to render inside the editor, but want to add elements to the DOM.
|
||||||
|
|
||||||
### `schema`
|
### `schema`
|
||||||
`Object`
|
`Object`
|
||||||
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
|
|
||||||
import Content from './content'
|
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import Portal from 'react-portal'
|
import Portal from 'react-portal'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -47,23 +46,6 @@ const PLUGINS_PROPS = [
|
|||||||
'schema',
|
'schema',
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass-through properties of the editor.
|
|
||||||
*
|
|
||||||
* @type {Array}
|
|
||||||
*/
|
|
||||||
|
|
||||||
const PASS_THROUGH_PROPS = [
|
|
||||||
'autoCorrect',
|
|
||||||
'autoFocus',
|
|
||||||
'className',
|
|
||||||
'readOnly',
|
|
||||||
'role',
|
|
||||||
'spellCheck',
|
|
||||||
'style',
|
|
||||||
'tabIndex',
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editor.
|
* Editor.
|
||||||
*
|
*
|
||||||
@@ -258,32 +240,14 @@ class Editor extends React.Component {
|
|||||||
render = () => {
|
render = () => {
|
||||||
const { props, state } = this
|
const { props, state } = this
|
||||||
const { stack } = state
|
const { stack } = state
|
||||||
const handlers = {}
|
const children = stack
|
||||||
const passes = {}
|
.renderPortal(state.state, this)
|
||||||
const children = stack.render(state.state, this)
|
.map((child, i) => <Portal key={i} isOpened>{child}</Portal>)
|
||||||
|
|
||||||
for (const property of EVENT_HANDLERS) {
|
|
||||||
handlers[property] = this[property]
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const property of PASS_THROUGH_PROPS) {
|
|
||||||
passes[property] = this.props[property]
|
|
||||||
}
|
|
||||||
|
|
||||||
debug('render', { props, state })
|
debug('render', { props, state })
|
||||||
|
|
||||||
return (
|
const tree = stack.render(state.state, this, { ...props, children })
|
||||||
<Content
|
return tree
|
||||||
{...handlers}
|
|
||||||
{...passes}
|
|
||||||
editor={this}
|
|
||||||
onChange={this.onChange}
|
|
||||||
schema={this.getSchema()}
|
|
||||||
state={this.getState()}
|
|
||||||
>
|
|
||||||
{children.map((child, i) => <Portal key={i} isOpened>{child}</Portal>)}
|
|
||||||
</Content>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -41,16 +41,6 @@ const STATE_ACCUMULATOR_METHODS = [
|
|||||||
'onChange',
|
'onChange',
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
|
||||||
* Methods that accumulate an array.
|
|
||||||
*
|
|
||||||
* @type {Array}
|
|
||||||
*/
|
|
||||||
|
|
||||||
const ARRAY_ACCUMULATOR_METHODS = [
|
|
||||||
'render'
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default properties.
|
* Default properties.
|
||||||
*
|
*
|
||||||
@@ -95,6 +85,53 @@ class Stack extends new Record(DEFAULTS) {
|
|||||||
return 'stack'
|
return 'stack'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke `render` on all of the plugins in reverse, building up a tree of
|
||||||
|
* higher-order components.
|
||||||
|
*
|
||||||
|
* @param {State} state
|
||||||
|
* @param {Editor} editor
|
||||||
|
* @param {Object} children
|
||||||
|
* @param {Object} props
|
||||||
|
* @return {Component}
|
||||||
|
*/
|
||||||
|
|
||||||
|
render = (state, editor, props) => {
|
||||||
|
debug('render')
|
||||||
|
const plugins = this.plugins.slice().reverse()
|
||||||
|
let children
|
||||||
|
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
if (!plugin.render) continue
|
||||||
|
children = plugin.render(props, state, editor)
|
||||||
|
props.children = children
|
||||||
|
}
|
||||||
|
|
||||||
|
return children
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke `renderPortal` on all of the plugins, building a list of portals.
|
||||||
|
*
|
||||||
|
* @param {State} state
|
||||||
|
* @param {Editor} editor
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
|
||||||
|
renderPortal = (state, editor) => {
|
||||||
|
debug('renderPortal')
|
||||||
|
const portals = []
|
||||||
|
|
||||||
|
for (const plugin of this.plugins) {
|
||||||
|
if (!plugin.renderPortal) continue
|
||||||
|
const portal = plugin.renderPortal(state, editor)
|
||||||
|
if (portal == null) continue
|
||||||
|
portals.push(portal)
|
||||||
|
}
|
||||||
|
|
||||||
|
return portals
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,31 +188,6 @@ for (const method of STATE_ACCUMULATOR_METHODS) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* Assert that a `value` is a state object.
|
||||||
*
|
*
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import Base64 from '../serializers/base-64'
|
import Base64 from '../serializers/base-64'
|
||||||
|
import Content from '../components/content'
|
||||||
import Character from '../models/character'
|
import Character from '../models/character'
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import Placeholder from '../components/placeholder'
|
import Placeholder from '../components/placeholder'
|
||||||
@@ -814,6 +815,43 @@ function Plugin(options = {}) {
|
|||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render.
|
||||||
|
*
|
||||||
|
* @param {Object} props
|
||||||
|
* @param {State} state
|
||||||
|
* @param {Editor} editor
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function render(props, state, editor) {
|
||||||
|
return (
|
||||||
|
<Content
|
||||||
|
autoCorrect={props.autoCorrect}
|
||||||
|
autoFocus={props.autoFocus}
|
||||||
|
className={props.className}
|
||||||
|
children={props.children}
|
||||||
|
editor={editor}
|
||||||
|
onBeforeInput={editor.onBeforeInput}
|
||||||
|
onBlur={editor.onBlur}
|
||||||
|
onChange={editor.onChange}
|
||||||
|
onCopy={editor.onCopy}
|
||||||
|
onCut={editor.onCut}
|
||||||
|
onDrop={editor.onDrop}
|
||||||
|
onKeyDown={editor.onKeyDown}
|
||||||
|
onPaste={editor.onPaste}
|
||||||
|
onSelect={editor.onSelect}
|
||||||
|
readOnly={props.readOnly}
|
||||||
|
role={props.role}
|
||||||
|
schema={editor.getSchema()}
|
||||||
|
spellCheck={props.spellCheck}
|
||||||
|
state={state}
|
||||||
|
style={props.style}
|
||||||
|
tabIndex={props.tabIndex}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A default schema rule to render block nodes.
|
* A default schema rule to render block nodes.
|
||||||
*
|
*
|
||||||
@@ -892,6 +930,7 @@ function Plugin(options = {}) {
|
|||||||
onKeyDown,
|
onKeyDown,
|
||||||
onPaste,
|
onPaste,
|
||||||
onSelect,
|
onSelect,
|
||||||
|
render,
|
||||||
schema,
|
schema,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user