1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-03-07 14:30:04 +01:00

add check list example

This commit is contained in:
Ian Storm Taylor 2017-03-28 12:55:48 -04:00
parent 6333275aa0
commit 30c2b206fb
5 changed files with 301 additions and 0 deletions

@ -0,0 +1,8 @@
# Rich Text Example
![](../../docs/images/rich-text-example.png)
This example shows you can add a very different concepts together: key commands, toolbars, and custom formatting, to get the functionality you'd expect from a rich text editor. Of course this is just the beginning, you can layer in whatever other behaviors you want!
Check out the [Examples readme](..) to see how to run it!

@ -0,0 +1,147 @@
import { Editor, Raw } from '../..'
import React from 'react'
import initialState from './state.json'
/**
* Check list item.
*
* @type {Component}
*/
class CheckListItem extends React.Component {
/**
* On change, set the new checked value on the block.
*
* @param {Event} e
*/
onChange = (e) => {
const checked = e.target.checked
const { editor, node } = this.props
const state = editor
.getState()
.transform()
.setNodeByKey(node.key, { data: { checked }})
.apply()
editor.onChange(state)
}
/**
* Render a check list item, using `contenteditable="false"` to embed the
* checkbox right next to the block's text.
*
* @return {Element}
*/
render = () => {
const { attributes, children, node } = this.props
const checked = node.data.get('checked')
return (
<div {...attributes} className="check-list-item">
<div contentEditable={false}>
<input
type="checkbox"
checked={checked}
onChange={this.onChange}
/>
</div>
{children}
</div>
)
}
}
/**
* Define a schema.
*
* @type {Object}
*/
const schema = {
nodes: {
'check-list-item': CheckListItem,
},
}
/**
* The rich text example.
*
* @type {Component}
*/
class CheckLists extends React.Component {
/**
* Deserialize the initial editor state.
*
* @type {Object}
*/
state = {
state: Raw.deserialize(initialState, { terse: true })
}
/**
* On change, save the new state.
*
* @param {State} state
*/
onChange = (state) => {
this.setState({ state })
}
/**
* On key down, if enter is pressed inside of a check list item, make sure
* that when it is split the new item starts unchecked.
*
* @param {Event} e
* @param {Object} data
* @param {State} state
* @return {State|Void}
*/
onKeyDown = (e, data, state) => {
if (data.key != 'enter') return
if (state.startBlock.type != 'check-list-item') return
return state
.transform()
.splitBlock()
.setBlock({ data: { checked: false }})
.apply()
}
/**
* Render.
*
* @return {Element}
*/
render = () => {
return (
<div>
<div className="editor">
<Editor
spellCheck
placeholder={'Enter some text...'}
schema={schema}
state={this.state.state}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
/>
</div>
</div>
)
}
}
/**
* Export.
*/
export default CheckLists

@ -0,0 +1,134 @@
{
"nodes": [
{
"kind": "block",
"type": "paragraph",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "With Slate you can build complex block types that have their own embeded content and behaviors, like rendering checkboxes inside check list items!"
}
]
}
]
},
{
"kind": "block",
"type": "check-list-item",
"data": {
"checked": true,
},
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "Slide to the left."
}
]
}
]
},
{
"kind": "block",
"type": "check-list-item",
"data": {
"checked": true,
},
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "Slide to the right."
}
]
}
]
},
{
"kind": "block",
"type": "check-list-item",
"data": {
"checked": false,
},
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "Criss-cross."
}
]
}
]
},
{
"kind": "block",
"type": "check-list-item",
"data": {
"checked": true,
},
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "Criss-cross!"
}
]
}
]
},
{
"kind": "block",
"type": "check-list-item",
"data": {
"checked": false,
},
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "Cha cha real smooth…"
}
]
}
]
},
{
"kind": "block",
"type": "check-list-item",
"data": {
"checked": false,
},
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "Let's go to work!"
}
]
}
]
},
{
"kind": "block",
"type": "paragraph",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "Try it out for yourself!"
}
]
}
]
}
]
}

@ -203,3 +203,12 @@ input:focus {
.emoji.selected {
outline: 2px solid blue;
}
.check-list-item + .check-list-item {
margin-top: 0;
}
.check-list-item [contenteditable="false"] {
display: inline-block;
margin-right: 0.75em;
}

@ -8,6 +8,7 @@ import { Router, Route, Link, IndexRedirect, hashHistory } from 'react-router'
*/
import AutoMarkdown from './auto-markdown'
import CheckLists from './check-lists'
import CodeHighlighting from './code-highlighting'
import Embeds from './embeds'
import Emojis from './emojis'
@ -101,6 +102,7 @@ class App extends React.Component {
{this.renderTab('Embeds', 'embeds')}
{this.renderTab('Emojis', 'emojis')}
{this.renderTab('Tables', 'tables')}
{this.renderTab('Check Lists', 'check-lists')}
{this.renderTab('Code Highlighting', 'code-highlighting')}
{this.renderTab('Paste HTML', 'paste-html')}
{this.renderTab('Read-only', 'read-only')}
@ -153,6 +155,7 @@ const router = (
<IndexRedirect to="rich-text" />
<Route path="auto-markdown" component={AutoMarkdown} />
<Route path="check-lists" component={CheckLists} />
<Route path="code-highlighting" component={CodeHighlighting} />
<Route path="embeds" component={Embeds} />
<Route path="emojis" component={Emojis} />