mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-13 02:34:05 +02:00
Restore dom (#2782)
* Working version of restore dom * Fix linting errors
This commit is contained in:
@@ -27,6 +27,7 @@ import PlainText from './plain-text'
|
||||
import Plugins from './plugins'
|
||||
import RTL from './rtl'
|
||||
import ReadOnly from './read-only'
|
||||
import RestoreDOM from './restore-dom'
|
||||
import RichText from './rich-text'
|
||||
import SearchHighlighting from './search-highlighting'
|
||||
import Composition from './composition'
|
||||
@@ -63,6 +64,7 @@ const EXAMPLES = [
|
||||
['Plain Text', PlainText, '/plain-text'],
|
||||
['Plugins', Plugins, '/plugins'],
|
||||
['Read-only', ReadOnly, '/read-only'],
|
||||
['Restore DOM', RestoreDOM, '/restore-dom'],
|
||||
['Rich Text', RichText, '/rich-text'],
|
||||
['RTL', RTL, '/rtl'],
|
||||
['Search Highlighting', SearchHighlighting, '/search-highlighting'],
|
||||
|
146
examples/restore-dom/index.js
Normal file
146
examples/restore-dom/index.js
Normal file
@@ -0,0 +1,146 @@
|
||||
import { Editor } from 'slate-react'
|
||||
import { Value } from 'slate'
|
||||
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
|
||||
/**
|
||||
* The Restore DOM example.
|
||||
*
|
||||
* This shows the usage of the `restoreDOM` command to rebuild the editor from
|
||||
* scratch causing all the nodes to force render even if there are no changes
|
||||
* to the DOM.
|
||||
*
|
||||
* The `onClickHighlight` method changes the internal state but normally the
|
||||
* change is not rendered because there is no change to Slate's internal
|
||||
* `value`.
|
||||
*
|
||||
* RestoreDOM also blows away the old render which makes it safe if the DOM
|
||||
* has been altered outside of React.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
class RestoreDOMExample extends React.Component {
|
||||
/**
|
||||
* Deserialize the initial editor value and set an initial highlight color.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
state = {
|
||||
value: Value.fromJSON(initialValue),
|
||||
bgcolor: '#ffffff',
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a reference to the `editor`.
|
||||
*
|
||||
* @param {Editor} editor
|
||||
*/
|
||||
|
||||
ref = editor => {
|
||||
this.editor = editor
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Toolbar>
|
||||
{this.renderHighlightButton('#ffffff')}
|
||||
{this.renderHighlightButton('#ffeecc')}
|
||||
{this.renderHighlightButton('#ffffcc')}
|
||||
{this.renderHighlightButton('#ccffcc')}
|
||||
{this.renderHighlightButton('#ccffff')}
|
||||
</Toolbar>
|
||||
<Editor
|
||||
spellCheck
|
||||
autoFocus
|
||||
placeholder="Enter some text..."
|
||||
ref={this.ref}
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderBlock={this.renderBlock}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a highlight button
|
||||
*
|
||||
* @param {String} bgcolor
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderHighlightButton = bgcolor => {
|
||||
const isActive = this.state.bgcolor === bgcolor
|
||||
return (
|
||||
<Button
|
||||
active={isActive}
|
||||
onMouseDown={event => this.onClickHighlight(bgcolor)}
|
||||
style={{ backgroundColor: bgcolor }}
|
||||
>
|
||||
<Icon>format_paint</Icon>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight every block with a given background color
|
||||
*
|
||||
* @param {String} bgcolor
|
||||
*/
|
||||
|
||||
onClickHighlight = bgcolor => {
|
||||
const { editor } = this
|
||||
this.setState({ bgcolor })
|
||||
editor.restoreDOM()
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate block.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderBlock = (props, editor, next) => {
|
||||
const { attributes, children, node } = props
|
||||
const style = { backgroundColor: this.state.bgcolor }
|
||||
|
||||
switch (node.type) {
|
||||
case 'paragraph':
|
||||
return (
|
||||
<p {...attributes} style={style}>
|
||||
{children}
|
||||
</p>
|
||||
)
|
||||
default:
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change, save the new `value`.
|
||||
*
|
||||
* @param {Editor} editor
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
||||
export default RestoreDOMExample
|
38
examples/restore-dom/value.json
Normal file
38
examples/restore-dom/value.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"object": "value",
|
||||
"document": {
|
||||
"object": "document",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "block",
|
||||
"type": "paragraph",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"text": "First block of text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "block",
|
||||
"type": "paragraph",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"text": "Second block of text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"object": "block",
|
||||
"type": "paragraph",
|
||||
"nodes": [
|
||||
{
|
||||
"object": "text",
|
||||
"text": "Third block of text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@@ -53,6 +53,7 @@ class Content extends React.Component {
|
||||
static propTypes = {
|
||||
autoCorrect: Types.bool.isRequired,
|
||||
className: Types.string,
|
||||
contentKey: Types.number,
|
||||
editor: Types.object.isRequired,
|
||||
id: Types.string,
|
||||
readOnly: Types.bool.isRequired,
|
||||
@@ -486,6 +487,7 @@ class Content extends React.Component {
|
||||
|
||||
return (
|
||||
<Container
|
||||
key={this.props.contentKey}
|
||||
{...handlers}
|
||||
{...data}
|
||||
ref={this.ref}
|
||||
|
@@ -79,7 +79,7 @@ class Editor extends React.Component {
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
state = { value: this.props.defaultValue }
|
||||
state = { value: this.props.defaultValue, contentKey: 0 }
|
||||
|
||||
/**
|
||||
* Temporary values.
|
||||
@@ -151,6 +151,7 @@ class Editor extends React.Component {
|
||||
const { options, readOnly, value: valueFromProps } = this.props
|
||||
const { value: valueFromState } = this.state
|
||||
const value = valueFromProps || valueFromState
|
||||
const { contentKey } = this.state
|
||||
this.controller.setReadOnly(readOnly)
|
||||
this.controller.setValue(value, options)
|
||||
|
||||
@@ -170,6 +171,7 @@ class Editor extends React.Component {
|
||||
ref={this.tmp.contentRef}
|
||||
autoCorrect={autoCorrect}
|
||||
className={className}
|
||||
contentKey={contentKey}
|
||||
editor={this}
|
||||
id={id}
|
||||
onEvent={(handler, event) => this.run(handler, event)}
|
||||
|
@@ -4,6 +4,7 @@ import EditorPropsPlugin from './editor-props'
|
||||
import RenderingPlugin from './rendering'
|
||||
import QueriesPlugin from './queries'
|
||||
import DOMPlugin from '../dom'
|
||||
import RestoreDOMPlugin from './restore-dom'
|
||||
|
||||
/**
|
||||
* A plugin that adds the React-specific rendering logic to the editor.
|
||||
@@ -20,7 +21,7 @@ function ReactPlugin(options = {}) {
|
||||
const domPlugin = DOMPlugin({
|
||||
plugins: [editorPropsPlugin, ...plugins],
|
||||
})
|
||||
|
||||
const restoreDomPlugin = RestoreDOMPlugin()
|
||||
const placeholderPlugin = PlaceholderPlugin({
|
||||
placeholder,
|
||||
when: (editor, node) =>
|
||||
@@ -30,7 +31,13 @@ function ReactPlugin(options = {}) {
|
||||
Array.from(node.texts()).length === 1,
|
||||
})
|
||||
|
||||
return [domPlugin, placeholderPlugin, renderingPlugin, queriesPlugin]
|
||||
return [
|
||||
domPlugin,
|
||||
restoreDomPlugin,
|
||||
placeholderPlugin,
|
||||
renderingPlugin,
|
||||
queriesPlugin,
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
|
21
packages/slate-react/src/plugins/react/restore-dom.js
Normal file
21
packages/slate-react/src/plugins/react/restore-dom.js
Normal file
@@ -0,0 +1,21 @@
|
||||
function RestoreDOMPlugin() {
|
||||
/**
|
||||
* Makes sure that on the next Content `render` the DOM is restored.
|
||||
* This gets us around issues where the DOM is in a different state than
|
||||
* React's virtual DOM and would crash.
|
||||
*
|
||||
* @param {Editor} editor
|
||||
*/
|
||||
|
||||
function restoreDOM(editor) {
|
||||
editor.setState({ contentKey: editor.state.contentKey + 1 })
|
||||
}
|
||||
|
||||
return {
|
||||
commands: {
|
||||
restoreDOM,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default RestoreDOMPlugin
|
Reference in New Issue
Block a user