1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-28 17:39:57 +02:00

add plugins example, fix soft break handling

This commit is contained in:
Ian Storm Taylor
2016-07-26 12:15:21 -07:00
parent 8916ee0891
commit b506098a29
6 changed files with 124 additions and 15 deletions

View File

@@ -14,6 +14,7 @@ import Images from './images'
import Links from './links'
import PasteHtml from './paste-html'
import PlainText from './plain-text'
import Plugins from './plugins'
import ReadOnly from './read-only'
import RichText from './rich-text'
import Tables from './tables'
@@ -69,7 +70,8 @@ class App extends React.Component {
{this.renderTab('Tables', 'tables')}
{this.renderTab('Code Highlighting', 'code-highlighting')}
{this.renderTab('Paste HTML', 'paste-html')}
{this.renderTab('Read Only', 'read-only')}
{this.renderTab('Read-only', 'read-only')}
{this.renderTab('Plugins', 'plugins')}
</div>
)
}
@@ -120,6 +122,7 @@ const router = (
<Route path="links" component={Links} />
<Route path="paste-html" component={PasteHtml} />
<Route path="plain-text" component={PlainText} />
<Route path="plugins" component={Plugins} />
<Route path="read-only" component={ReadOnly} />
<Route path="rich-text" component={RichText} />
<Route path="tables" component={Tables} />

View File

@@ -0,0 +1,8 @@
# Plain Text Example
![](../../docs/images/plain-text-example.png)
This is the most basic Slate example. It's basically a glorified `<textarea>`. But it gives you a sense for the absolute basics of Slate.
Check out the [Examples readme](..) to see how to run it!

77
examples/plugins/index.js Normal file
View File

@@ -0,0 +1,77 @@
import { Editor, Plain } from '../..'
import React from 'react'
import AutoReplaceText from 'slate-auto-replace-text'
import CollapseOnEscape from 'slate-collapse-on-escape'
import SoftBreak from 'slate-soft-break'
/**
* Plugins.
*/
const plugins = [
AutoReplaceText('(c)', '©'),
AutoReplaceText('(r)', '®'),
AutoReplaceText('(tm)', '™'),
CollapseOnEscape(),
SoftBreak()
]
/**
* The plugins example.
*
* @type {Component}
*/
class Plugins extends React.Component {
/**
* Deserialize the initial editor state.
*
* @type {Object}
*/
state = {
state: Plain.deserialize(`This example shows how you can extend Slate with plugins! It uses three fairly simple plugins, but you can use any plugins you want, or write your own!
The first is an "auto replacer". Try typing "(c)" and you'll see it turn into a copyright symbol automatically!
The second is a simple plugin to collapse the selection whenever the escape key is pressed. Try selecting some text and pressing escape.
And the third is another simple plugin that inserts a "soft" break when enter is pressed instead of creating a new block. Try pressing enter!`)
};
/**
* On change.
*
* @param {State} state
*/
onChange = (state) => {
this.setState({ state })
}
/**
* Render the editor.
*
* @return {Component} component
*/
render = () => {
return (
<Editor
placeholder={'Enter some text...'}
plugins={plugins}
state={this.state.state}
onChange={this.onChange}
/>
)
}
}
/**
* Export.
*/
export default Plugins

View File

@@ -422,13 +422,19 @@ class Content extends React.Component {
const { selection } = state
const native = window.getSelection()
const { anchorNode, anchorOffset, focusOffset } = native
const { textContent } = anchorNode
let { textContent } = anchorNode
const offsetKey = OffsetKey.findKey(anchorNode)
const { key, index } = OffsetKey.parse(offsetKey)
const { start, end } = OffsetKey.findBounds(key, index, state)
const range = OffsetKey.findRange(anchorNode, state)
const { text, marks } = range
// COMPAT: If the DOM text ends in a new line, we will have added one to
// account for browsers collapsing a single one, so remove it.
if (textContent.charAt(textContent.length - 1) == '\n') {
textContent = textContent.slice(0, -1)
}
// If the text is no different, abort.
if (textContent == text) return

View File

@@ -133,22 +133,12 @@ class Leaf extends React.Component {
}
render() {
const { node, index, text, marks, renderMark } = this.props
const { node, index } = this.props
const offsetKey = OffsetKey.stringify({
key: node.key,
index
})
const style = marks.reduce((memo, mark) => {
const styles = renderMark(mark, marks)
for (const key in styles) {
memo[key] = styles[key]
}
return memo
}, {})
// Increment the renders key, which forces a re-render whenever this
// component is told it should update. This is required because "native"
// renders where we don't update the leaves cause React's internal state to
@@ -159,13 +149,35 @@ class Leaf extends React.Component {
<span
key={this.tmp.renders}
data-offset-key={offsetKey}
style={style}
style={this.renderStyle()}
>
{text || <br />}
{this.renderText()}
</span>
)
}
renderText() {
const { text } = this.props
if (!text) return <br />
if (text.charAt(text.length - 1) == '\n') return `${text}\n`
return text
}
renderStyle() {
const { marks, renderMark } = this.props
const style = marks.reduce((memo, mark) => {
const styles = renderMark(mark, marks)
for (const key in styles) {
memo[key] = styles[key]
}
return memo
}, {})
return style
}
}
/**

View File

@@ -49,6 +49,9 @@
"react-router": "^2.5.1",
"read-metadata": "^1.0.0",
"selection-position": "^1.0.0",
"slate-auto-replace-text": "^0.2.0",
"slate-collapse-on-escape": "^0.1.0",
"slate-soft-break": "^0.1.0",
"source-map-support": "^0.4.0",
"to-camel-case": "^1.0.0",
"to-title-case": "^1.0.0",