mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-29 18:09:49 +02:00
add table example
This commit is contained in:
8
Makefile
8
Makefile
@@ -39,6 +39,10 @@ example-plain-text:
|
||||
example-rich-text:
|
||||
@ $(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:
|
||||
@ npm install
|
||||
@@ -74,6 +78,10 @@ watch-example-plain-text:
|
||||
watch-example-rich-text:
|
||||
@ $(MAKE) example-rich-text browserify=$(watchify)
|
||||
|
||||
# Watch the table example.
|
||||
watch-example-table:
|
||||
@ $(MAKE) example-table browserify=$(watchify)
|
||||
|
||||
# Phony targets.
|
||||
.PHONY: examples
|
||||
.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