From b42fd1849c9dd53041ea55645e33590c01ddc51f Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Tue, 21 Jun 2016 19:34:51 -0700 Subject: [PATCH] add table example --- Makefile | 8 ++ examples/table/index.css | 66 ++++++++++ examples/table/index.html | 12 ++ examples/table/index.js | 165 +++++++++++++++++++++++++ examples/table/state.json | 249 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 500 insertions(+) create mode 100644 examples/table/index.css create mode 100644 examples/table/index.html create mode 100644 examples/table/index.js create mode 100644 examples/table/state.json diff --git a/Makefile b/Makefile index 45ad6a1f7..e3c666ad0 100644 --- a/Makefile +++ b/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 diff --git a/examples/table/index.css b/examples/table/index.css new file mode 100644 index 000000000..e9da1b93d --- /dev/null +++ b/examples/table/index.css @@ -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; +} diff --git a/examples/table/index.html b/examples/table/index.html new file mode 100644 index 000000000..2ee7e77dd --- /dev/null +++ b/examples/table/index.html @@ -0,0 +1,12 @@ + + + + Editor | Auto-markdown Example + + + + +
+ + + diff --git a/examples/table/index.js b/examples/table/index.js new file mode 100644 index 000000000..38451003d --- /dev/null +++ b/examples/table/index.js @@ -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 ( +
+ 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 }) + }} + /> +
+ ) + } + + /** + * 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) =>

{props.children}

+ } + case 'table': { + return (props) => {props.children}
+ } + case 'table-row': { + return (props) => {props.children} + } + case 'table-cell': { + return (props) => {props.children} + } + } + } + + /** + * 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 = +const root = document.body.querySelector('main') +ReactDOM.render(app, root) diff --git a/examples/table/state.json b/examples/table/state.json new file mode 100644 index 000000000..f0f86100f --- /dev/null +++ b/examples/table/state.json @@ -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..." + } + ] + } + ] + } + ] +}