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:
@@ -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} />
|
||||
|
8
examples/plugins/Readme.md
Normal file
8
examples/plugins/Readme.md
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
# Plain Text Example
|
||||
|
||||

|
||||
|
||||
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
77
examples/plugins/index.js
Normal 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
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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",
|
||||
|
Reference in New Issue
Block a user