mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-29 09:59:48 +02:00
add table example
This commit is contained in:
8
Makefile
8
Makefile
@@ -39,6 +39,10 @@ example-plain-text:
|
|||||||
example-rich-text:
|
example-rich-text:
|
||||||
@ $(browserify) --debug --transform babelify --outfile ./examples/rich-text/build.js ./examples/rich-text/index.js
|
@ $(browserify) --debug --transform babelify --outfile ./examples/rich-text/build.js ./examples/rich-text/index.js
|
||||||
|
|
||||||
|
# Build the table example.
|
||||||
|
example-table:
|
||||||
|
@ $(browserify) --debug --transform babelify --outfile ./examples/table/build.js ./examples/table/index.js
|
||||||
|
|
||||||
# Install the dependencies.
|
# Install the dependencies.
|
||||||
install:
|
install:
|
||||||
@ npm install
|
@ npm install
|
||||||
@@ -74,6 +78,10 @@ watch-example-plain-text:
|
|||||||
watch-example-rich-text:
|
watch-example-rich-text:
|
||||||
@ $(MAKE) example-rich-text browserify=$(watchify)
|
@ $(MAKE) example-rich-text browserify=$(watchify)
|
||||||
|
|
||||||
|
# Watch the table example.
|
||||||
|
watch-example-table:
|
||||||
|
@ $(MAKE) example-table browserify=$(watchify)
|
||||||
|
|
||||||
# Phony targets.
|
# Phony targets.
|
||||||
.PHONY: examples
|
.PHONY: examples
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
|
66
examples/table/index.css
Normal file
66
examples/table/index.css
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
html {
|
||||||
|
background: #eee;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
max-width: 40em;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 10px;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 2px solid #ddd;
|
||||||
|
margin-left: 0;
|
||||||
|
padding-left: 10px;
|
||||||
|
color: #aaa;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor > * > * + * {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
margin: 0 -10px;
|
||||||
|
padding: 1px 0 9px 8px;
|
||||||
|
border-bottom: 2px solid #eee;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu > * {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu > * + * {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
color: #ccc;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button[data-active="true"] {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
12
examples/table/index.html
Normal file
12
examples/table/index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Editor | Auto-markdown Example</title>
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||||
|
<link rel="stylesheet" href="index.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main></main>
|
||||||
|
<script src="build.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
165
examples/table/index.js
Normal file
165
examples/table/index.js
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
|
||||||
|
import Editor, { Raw } from '../..'
|
||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import keycode from 'keycode'
|
||||||
|
import state from './state.json'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define our example app.
|
||||||
|
*
|
||||||
|
* @type {Component} App
|
||||||
|
*/
|
||||||
|
|
||||||
|
class App extends React.Component {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize the raw initial state.
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
state = {
|
||||||
|
state: Raw.deserialize(state)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the example.
|
||||||
|
*
|
||||||
|
* @return {Component} component
|
||||||
|
*/
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="editor">
|
||||||
|
<Editor
|
||||||
|
state={this.state.state}
|
||||||
|
renderNode={node => this.renderNode(node)}
|
||||||
|
renderMark={mark => this.renderMark(mark)}
|
||||||
|
onKeyDown={(e, state) => this.onKeyDown(e, state)}
|
||||||
|
onChange={(state) => {
|
||||||
|
console.groupCollapsed('Change!')
|
||||||
|
console.log('Document:', state.document.toJS())
|
||||||
|
console.log('Selection:', state.selection.toJS())
|
||||||
|
console.log('Content:', Raw.serialize(state))
|
||||||
|
console.groupEnd()
|
||||||
|
this.setState({ state })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render each of our custom `mark` types.
|
||||||
|
*
|
||||||
|
* @param {Mark} mark
|
||||||
|
* @return {Component} component
|
||||||
|
*/
|
||||||
|
|
||||||
|
renderMark(mark) {
|
||||||
|
switch (mark.type) {
|
||||||
|
case 'bold': {
|
||||||
|
return {
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render each of our custom `node` types.
|
||||||
|
*
|
||||||
|
* @param {Node} node
|
||||||
|
* @return {Component} component
|
||||||
|
*/
|
||||||
|
|
||||||
|
renderNode(node) {
|
||||||
|
switch (node.type) {
|
||||||
|
case 'paragraph': {
|
||||||
|
return (props) => <p>{props.children}</p>
|
||||||
|
}
|
||||||
|
case 'table': {
|
||||||
|
return (props) => <table border="2px"><tbody>{props.children}</tbody></table>
|
||||||
|
}
|
||||||
|
case 'table-row': {
|
||||||
|
return (props) => <tr>{props.children}</tr>
|
||||||
|
}
|
||||||
|
case 'table-cell': {
|
||||||
|
return (props) => <td>{props.children}</td>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On key down, check for our specific key shortcuts.
|
||||||
|
*
|
||||||
|
* @param {Event} e
|
||||||
|
* @param {State} state
|
||||||
|
* @return {State or Null} state
|
||||||
|
*/
|
||||||
|
|
||||||
|
onKeyDown(e, state) {
|
||||||
|
if (state.isCurrentlyExpanded) return
|
||||||
|
const node = state.currentBlockNodes.first()
|
||||||
|
if (node.type != 'table-cell') return
|
||||||
|
|
||||||
|
const key = keycode(e.which)
|
||||||
|
switch (key) {
|
||||||
|
case 'backspace': return this.onBackspace(e, state)
|
||||||
|
case 'delete': return this.onDelete(e, state)
|
||||||
|
case 'enter': return this.onEnter(e, state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On backspace, do nothing if at the start of a table cell.
|
||||||
|
*
|
||||||
|
* @param {Event} e
|
||||||
|
* @param {State} state
|
||||||
|
* @return {State or Null} state
|
||||||
|
*/
|
||||||
|
|
||||||
|
onBackspace(e, state) {
|
||||||
|
if (state.currentStartOffset != 0) return
|
||||||
|
e.preventDefault()
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On delete, do nothing if at the end of a table cell.
|
||||||
|
*
|
||||||
|
* @param {Event} e
|
||||||
|
* @param {State} state
|
||||||
|
* @return {State or Null} state
|
||||||
|
*/
|
||||||
|
|
||||||
|
onDelete(e, state) {
|
||||||
|
const node = state.currentBlockNodes.first()
|
||||||
|
if (state.currentEndOffset != node.length) return
|
||||||
|
e.preventDefault()
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On return, do nothing if inside a table cell.
|
||||||
|
*
|
||||||
|
* @param {Event} e
|
||||||
|
* @param {State} state
|
||||||
|
* @return {State or Null} state
|
||||||
|
*/
|
||||||
|
|
||||||
|
onEnter(e, state) {
|
||||||
|
e.preventDefault()
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mount the app.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const app = <App />
|
||||||
|
const root = document.body.querySelector('main')
|
||||||
|
ReactDOM.render(app, root)
|
249
examples/table/state.json
Normal file
249
examples/table/state.json
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "paragraph",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "Since the editor is based on a recursive tree model, similar to an HTML document, you can create complex nested structures, like tables:"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-row",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "Human",
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "bold"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "Dog",
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "bold"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "Cat",
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "bold"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-row",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "# of Feet",
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "bold"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-row",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "# of Lives",
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "bold"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "table-cell",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "9"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "block",
|
||||||
|
"type": "paragraph",
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"kind": "text",
|
||||||
|
"ranges": [
|
||||||
|
{
|
||||||
|
"text": "This table is just a basic example, but you could augment it to add support for table headers, adding column and rows, or even formulas if you wanted to get really crazy..."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Reference in New Issue
Block a user