1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-31 19:01:54 +02:00

add linting to examples

This commit is contained in:
Ian Storm Taylor
2016-07-07 08:35:13 -07:00
parent 226b6592dc
commit db1151bd15
12 changed files with 429 additions and 290 deletions

View File

@@ -1,7 +1,10 @@
{ {
"env": { "plugins": [
"browser": true, "import",
"node": true "react"
],
"settings": {
"import/extensions": [".js"]
}, },
"parser": "babel-eslint", "parser": "babel-eslint",
"parserOptions": { "parserOptions": {
@@ -9,10 +12,10 @@
"jsx": true "jsx": true
} }
}, },
"plugins": [ "env": {
"import", "browser": true,
"react" "node": true
], },
"rules": { "rules": {
"block-spacing": "error", "block-spacing": "error",
"comma-dangle": ["error", "only-multiline"], "comma-dangle": ["error", "only-multiline"],
@@ -25,9 +28,7 @@
"dot-notation": ["error", { "allowKeywords": true }], "dot-notation": ["error", { "allowKeywords": true }],
"eol-last": "error", "eol-last": "error",
"func-style": ["error", "declaration"], "func-style": ["error", "declaration"],
"import/default": "error",
"import/export": "error", "import/export": "error",
"import/named": "error",
"import/namespace": "error", "import/namespace": "error",
"import/newline-after-import": "error", "import/newline-after-import": "error",
"import/no-deprecated": "error", "import/no-deprecated": "error",
@@ -41,7 +42,6 @@
"new-parens": "error", "new-parens": "error",
"no-array-constructor": "error", "no-array-constructor": "error",
"no-class-assign": "error", "no-class-assign": "error",
"no-console": "warn",
"no-const-assign": "error", "no-const-assign": "error",
"no-debugger": "warn", "no-debugger": "warn",
"no-dupe-args": "error", "no-dupe-args": "error",

View File

@@ -47,16 +47,19 @@ examples:
install: install:
@ npm install @ npm install
# Lint the sources files with Standard JS. # Lint the source files.
lint: lint:
@ $(eslint) "lib/**/*.js" @ $(eslint) \
"lib/**/*.js" \
"examples/**/*.js" --ignore-pattern "build.js"
# Build the test source. # Build the test source.
test/browser/support/build.js: $(shell find ./lib) ./test/browser.js test/support/build.js: $(shell find ./lib) ./test/browser.js
@ $(browserify) \ @ $(browserify) \
./test/browser.js \
--debug \ --debug \
--transform babelify \ --transform babelify \
--outfile ./test/support/build.js ./test/browser.js --outfile ./test/support/build.js
# Run the tests. # Run the tests.
test: test-browser test-server test: test-browser test-server

View File

@@ -2,7 +2,7 @@
import { Editor, Raw } from '../..' import { Editor, Raw } from '../..'
import React from 'react' import React from 'react'
import keycode from 'keycode' import keycode from 'keycode'
import state from './state.json' import initialState from './state.json'
/** /**
* Node renderers. * Node renderers.
@@ -38,7 +38,7 @@ class AutoMarkdown extends React.Component {
*/ */
state = { state = {
state: Raw.deserialize(state) state: Raw.deserialize(initialState)
}; };
/** /**
@@ -48,7 +48,7 @@ class AutoMarkdown extends React.Component {
* @return {String} block * @return {String} block
*/ */
getType(chars) { getType = (chars) => {
switch (chars) { switch (chars) {
case '*': case '*':
case '-': case '-':
@@ -71,26 +71,45 @@ class AutoMarkdown extends React.Component {
* @return {Component} component * @return {Component} component
*/ */
render() { render = () => {
return ( return (
<div className="editor"> <div className="editor">
<Editor <Editor
state={this.state.state} state={this.state.state}
renderNode={node => NODES[node.type]} onChange={this.onChange}
onKeyDown={(e, state) => this.onKeyDown(e, state)} onKeyDown={this.onKeyDown}
onChange={(state) => { renderNode={this.renderNode}
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> </div>
) )
} }
/**
* Render a `node`.
*
* @param {Node} node
* @return {Element}
*/
renderNode = (node) => {
return NODES[node.type]
}
/**
* On change.
*
* @param {State} 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 })
}
/** /**
* On key down, check for our specific key shortcuts. * On key down, check for our specific key shortcuts.
* *
@@ -99,7 +118,7 @@ class AutoMarkdown extends React.Component {
* @return {State or Null} state * @return {State or Null} state
*/ */
onKeyDown(e, state) { onKeyDown = (e, state) => {
const key = keycode(e.which) const key = keycode(e.which)
switch (key) { switch (key) {
case 'space': return this.onSpace(e, state) case 'space': return this.onSpace(e, state)
@@ -117,7 +136,7 @@ class AutoMarkdown extends React.Component {
* @return {State or Null} state * @return {State or Null} state
*/ */
onSpace(e, state) { onSpace = (e, state) => {
if (state.isExpanded) return if (state.isExpanded) return
let { selection } = state let { selection } = state
const { startText, startBlock, startOffset } = state const { startText, startBlock, startOffset } = state
@@ -151,7 +170,7 @@ class AutoMarkdown extends React.Component {
* @return {State or Null} state * @return {State or Null} state
*/ */
onBackspace(e, state) { onBackspace = (e, state) => {
if (state.isExpanded) return if (state.isExpanded) return
if (state.startOffset != 0) return if (state.startOffset != 0) return
const { startBlock } = state const { startBlock } = state
@@ -178,7 +197,7 @@ class AutoMarkdown extends React.Component {
* @return {State or Null} state * @return {State or Null} state
*/ */
onEnter(e, state) { onEnter = (e, state) => {
if (state.isExpanded) return if (state.isExpanded) return
const { startBlock, startOffset, endOffset } = state const { startBlock, startOffset, endOffset } = state
if (startOffset == 0 && startBlock.length == 0) return this.onBackspace(e, state) if (startOffset == 0 && startBlock.length == 0) return this.onBackspace(e, state)

View File

@@ -3,7 +3,7 @@ import { Editor, Mark, Raw, Selection } from '../..'
import Prism from 'prismjs' import Prism from 'prismjs'
import React from 'react' import React from 'react'
import keycode from 'keycode' import keycode from 'keycode'
import state from './state.json' import initialState from './state.json'
/** /**
* Node renderers. * Node renderers.
@@ -43,10 +43,19 @@ const MARKS = {
class CodeHighlighting extends React.Component { class CodeHighlighting extends React.Component {
state = { state = {
state: Raw.deserialize(state) state: Raw.deserialize(initialState)
}; };
onKeyDown(e, state, editor) { 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 })
}
onKeyDown = (e, state, editor) => {
const key = keycode(e.which) const key = keycode(e.which)
if (key != 'enter') return if (key != 'enter') return
const { startBlock } = state const { startBlock } = state
@@ -59,29 +68,30 @@ class CodeHighlighting extends React.Component {
return transform.apply() return transform.apply()
} }
render() { render = () => {
return ( return (
<div className="editor"> <div className="editor">
<Editor <Editor
state={this.state.state} state={this.state.state}
renderNode={node => NODES[node.type]} renderNode={this.renderNode}
renderMark={mark => MARKS[mark.type] || {}} renderMark={this.renderMark}
renderDecorations={(...args) => this.renderDecorations(...args)} renderDecorations={this.renderDecorations}
onKeyDown={(...args) => this.onKeyDown(...args)} onKeyDown={this.onKeyDown}
onChange={(state) => { onChange={this.onChange}
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> </div>
) )
} }
renderDecorations(text, state, editor) { renderNode = (node) => {
return NODES[node.type]
}
renderMark = (mark) => {
return MARKS[mark.type] || {}
}
renderDecorations = (text, state, editor) => {
let characters = text.characters let characters = text.characters
const { document } = state const { document } = state
const block = document.getClosestBlock(text) const block = document.getClosestBlock(text)

View File

@@ -3,7 +3,7 @@ import { Editor, Mark, Raw } from '../..'
import Portal from 'react-portal' import Portal from 'react-portal'
import React from 'react' import React from 'react'
import position from 'selection-position' import position from 'selection-position'
import state from './state.json' import initialState from './state.json'
/** /**
* Node renderers. * Node renderers.
@@ -48,37 +48,74 @@ const MARKS = {
class HoveringMenu extends React.Component { class HoveringMenu extends React.Component {
state = { state = {
state: Raw.deserialize(state) state: Raw.deserialize(initialState)
}; };
componentDidMount() { componentDidMount = () => {
this.updateMenu() this.updateMenu()
} }
componentDidUpdate() { componentDidUpdate = () => {
this.updateMenu() this.updateMenu()
} }
hasMark(type) { render = () => {
return (
<div>
{this.renderMenu()}
{this.renderEditor()}
</div>
)
}
renderMenu = () => {
const { state } = this.state const { state } = this.state
const { marks } = state const isOpen = state.isExpanded && state.isFocused
return marks.some(mark => mark.type == type) return (
<Portal isOpened onOpen={this.onOpen}>
<div className="menu hover-menu">
{this.renderMarkButton('bold', 'format_bold')}
{this.renderMarkButton('italic', 'format_italic')}
{this.renderMarkButton('underlined', 'format_underlined')}
{this.renderMarkButton('code', 'code')}
</div>
</Portal>
)
} }
onClickMark(e, type) { renderMarkButton = (type, icon) => {
e.preventDefault()
const isActive = this.hasMark(type) const isActive = this.hasMark(type)
let { state } = this.state const onMouseDown = e => this.onClickMark(e, type)
state = state return (
.transform() <span className="button" onMouseDown={onMouseDown} data-active={isActive}>
[isActive ? 'unmark' : 'mark'](type) <span className="material-icons">{icon}</span>
.apply() </span>
)
this.setState({ state })
} }
updateMenu() { renderEditor = () => {
return (
<div className="editor">
<Editor
state={this.state.state}
renderNode={this.renderNode}
renderMark={this.renderMark}
onChange={this.onChange}
/>
</div>
)
}
renderNode = (node) => {
return NODES[node.type]
}
renderMark = (mark) => {
return MARKS[mark.type]
}
updateMenu = () => {
const { menu, state } = this.state const { menu, state } = this.state
if (!menu) return if (!menu) return
@@ -93,61 +130,35 @@ class HoveringMenu extends React.Component {
menu.style.left = `${rect.left + window.scrollX - menu.offsetWidth / 2 + rect.width / 2}px` menu.style.left = `${rect.left + window.scrollX - menu.offsetWidth / 2 + rect.width / 2}px`
} }
onOpen(el) { hasMark = (type) => {
this.setState({ menu: el.firstChild })
}
render() {
return (
<div>
{this.renderMenu()}
{this.renderEditor()}
</div>
)
}
renderMenu() {
const { state } = this.state const { state } = this.state
const isOpen = state.isExpanded && state.isFocused return state.marks.some(mark => mark.type == type)
return (
<Portal isOpened={true} onOpen={el => this.onOpen(el)} >
<div className="menu hover-menu">
{this.renderMarkButton('bold', 'format_bold')}
{this.renderMarkButton('italic', 'format_italic')}
{this.renderMarkButton('underlined', 'format_underlined')}
{this.renderMarkButton('code', 'code')}
</div>
</Portal>
)
} }
renderMarkButton(type, icon) { 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 })
}
onClickMark = (e, type) => {
e.preventDefault()
const isActive = this.hasMark(type) const isActive = this.hasMark(type)
return ( let { state } = this.state
<span className="button" onMouseDown={e => this.onClickMark(e, type)} data-active={isActive}>
<span className="material-icons">{icon}</span> state = state
</span> .transform()
) [isActive ? 'unmark' : 'mark'](type)
.apply()
this.setState({ state })
} }
renderEditor() { onOpen = (el) => {
return ( this.setState({ menu: el.firstChild })
<div className="editor">
<Editor
state={this.state.state}
renderNode={node => NODES[node.type]}
renderMark={mark => MARKS[mark.type]}
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>
)
} }
} }

View File

@@ -2,7 +2,7 @@
import { Editor, Mark, Raw } from '../..' import { Editor, Mark, Raw } from '../..'
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import state from './state.json' import initialState from './state.json'
import { Map } from 'immutable' import { Map } from 'immutable'
/** /**
@@ -31,16 +31,104 @@ const NODES = {
class Images extends React.Component { class Images extends React.Component {
state = { state = {
state: Raw.deserialize(state) state: Raw.deserialize(initialState)
}; };
/**
* Render the app.
*
* @return {Element} element
*/
render = () => {
return (
<div>
{this.renderToolbar()}
{this.renderEditor()}
</div>
)
}
/**
* Render the toolbar.
*
* @return {Element} element
*/
renderToolbar = () => {
return (
<div className="menu toolbar-menu">
<span className="button" onMouseDown={this.onClickImage}>
<span className="material-icons">image</span>
</span>
</div>
)
}
/**
* Render the editor.
*
* @return {Element} element
*/
renderEditor = () => {
return (
<div className="editor">
<Editor
state={this.state.state}
renderNode={this.renderNode}
onChange={this.onChange}
/>
</div>
)
}
/**
* Render a `node`.
*
* @param {Node} node
* @return {Element}
*/
renderNode = (node) => {
return NODES[node.type]
}
/**
* On change.
*
* @param {State} 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 })
}
/**
* On clicking the image button, prompt for an image and insert it.
*
* @param {Event} e
*/
onClickImage = (e) => {
e.preventDefault()
const src = window.prompt('Enter the URL of the image:')
if (!src) return
this.insertImage(src)
}
/** /**
* Insert an image with `src` at the current selection. * Insert an image with `src` at the current selection.
* *
* @param {String} src * @param {String} src
*/ */
insertImage(src) { insertImage = (src) => {
let { state } = this.state let { state } = this.state
if (state.isExpanded) { if (state.isExpanded) {
@@ -74,75 +162,6 @@ class Images extends React.Component {
this.setState({ state }) this.setState({ state })
} }
/**
* On clicking the image button, prompt for an image and insert it.
*
* @param {Event} e
*/
onClickImage(e) {
e.preventDefault()
const src = window.prompt('Enter the URL of the image:')
if (!src) return
this.insertImage(src)
}
/**
* Render the app.
*
* @return {Element} element
*/
render() {
return (
<div>
{this.renderToolbar()}
{this.renderEditor()}
</div>
)
}
/**
* Render the toolbar.
*
* @return {Element} element
*/
renderToolbar() {
return (
<div className="menu toolbar-menu">
<span className="button" onMouseDown={e => this.onClickImage(e)}>
<span className="material-icons">image</span>
</span>
</div>
)
}
/**
* Render the editor.
*
* @return {Element} element
*/
renderEditor() {
return (
<div className="editor">
<Editor
state={this.state.state}
renderNode={node => NODES[node.type]}
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>
)
}
} }
/** /**

View File

@@ -2,7 +2,7 @@
import { Editor, Mark, Raw } from '../..' import { Editor, Mark, Raw } from '../..'
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import state from './state.json' import initialState from './state.json'
import { Map } from 'immutable' import { Map } from 'immutable'
/** /**
@@ -29,7 +29,7 @@ const NODES = {
class Links extends React.Component { class Links extends React.Component {
state = { state = {
state: Raw.deserialize(state) state: Raw.deserialize(initialState)
}; };
/** /**
@@ -38,10 +38,9 @@ class Links extends React.Component {
* @return {Boolean} hasLinks * @return {Boolean} hasLinks
*/ */
hasLinks() { hasLinks = () => {
const { state } = this.state const { state } = this.state
const { inlines } = state return state.inlines.some(inline => inline.type == 'link')
return inlines.some(inline => inline.type == 'link')
} }
/** /**
@@ -51,7 +50,7 @@ class Links extends React.Component {
* @param {Event} e * @param {Event} e
*/ */
onClickLink(e) { onClickLink = (e) => {
e.preventDefault() e.preventDefault()
let { state } = this.state let { state } = this.state
const hasLinks = this.hasLinks() const hasLinks = this.hasLinks()
@@ -92,7 +91,7 @@ class Links extends React.Component {
* @return {Element} element * @return {Element} element
*/ */
render() { render = () => {
return ( return (
<div> <div>
{this.renderToolbar()} {this.renderToolbar()}
@@ -107,11 +106,11 @@ class Links extends React.Component {
* @return {Element} element * @return {Element} element
*/ */
renderToolbar() { renderToolbar = () => {
const hasLinks = this.hasLinks() const hasLinks = this.hasLinks()
return ( return (
<div className="menu toolbar-menu"> <div className="menu toolbar-menu">
<span className="button" onMouseDown={e => this.onClickLink(e)} data-active={hasLinks}> <span className="button" onMouseDown={this.onClickLink} data-active={hasLinks}>
<span className="material-icons">link</span> <span className="material-icons">link</span>
</span> </span>
</div> </div>
@@ -124,25 +123,44 @@ class Links extends React.Component {
* @return {Element} element * @return {Element} element
*/ */
renderEditor() { renderEditor = () => {
return ( return (
<div className="editor"> <div className="editor">
<Editor <Editor
state={this.state.state} state={this.state.state}
renderNode={node => NODES[node.type]} renderNode={this.renderNode}
onChange={(state) => { onChange={this.onChange}
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> </div>
) )
} }
/**
* Render a `node`.
*
* @param {Node} node
* @return {Element}
*/
renderNode = (node) => {
return NODES[node.type]
}
/**
* On change.
*
* @param {State} 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 })
}
} }
/** /**

View File

@@ -1,7 +1,7 @@
import { Editor, Html, Raw } from '../..' import { Editor, Html, Raw } from '../..'
import React from 'react' import React from 'react'
import state from './state.json' import initialState from './state.json'
/** /**
* Node renderers. * Node renderers.
@@ -166,10 +166,41 @@ const serializer = new Html(RULES)
class PasteHtml extends React.Component { class PasteHtml extends React.Component {
state = { state = {
state: Raw.deserialize(state) state: Raw.deserialize(initialState)
}; };
onPaste(e, paste, state, editor) { render = () => {
return (
<div className="editor">
<Editor
state={this.state.state}
renderNode={this.renderNode}
renderMark={this.renderMark}
onPaste={this.onPaste}
onChange={this.onChange}
/>
</div>
)
}
renderNode = (node) => {
return NODES[node.type]
}
renderMark = (mark) => {
return MARKS[mark.type]
}
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 })
}
onPaste = (e, paste, state, editor) => {
if (paste.type != 'html') return if (paste.type != 'html') return
const { html } = paste const { html } = paste
const { document } = serializer.deserialize(html) const { document } = serializer.deserialize(html)
@@ -180,27 +211,6 @@ class PasteHtml extends React.Component {
.apply() .apply()
} }
render() {
return (
<div className="editor">
<Editor
state={this.state.state}
renderNode={node => NODES[node.type]}
renderMark={mark => MARKS[mark.type]}
onPaste={(...args) => this.onPaste(...args)}
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>
)
}
} }
/** /**

View File

@@ -1,7 +1,7 @@
import { Block, Character, Document, Editor, State, Text } from '../..' import { Block, Character, Document, Editor, State, Text } from '../..'
import React from 'react' import React from 'react'
import state from './state.json' import initialState from './state.json'
/** /**
* A helper to deserialize a string into an editor state. * A helper to deserialize a string into an editor state.
@@ -54,7 +54,7 @@ class PlainText extends React.Component {
*/ */
state = { state = {
state: deserialize(state) state: deserialize(initialState)
}; };
/** /**
@@ -63,22 +63,30 @@ class PlainText extends React.Component {
* @return {Component} component * @return {Component} component
*/ */
render() { render = () => {
return ( return (
<Editor <Editor
state={this.state.state} state={this.state.state}
onChange={(state) => { onChange={this.onChange}
console.groupCollapsed('Change!')
console.log('Document:', state.document.toJS())
console.log('Selection:', state.selection.toJS())
console.log('Content:', serialize(state))
console.groupEnd()
this.setState({ state })
}}
/> />
) )
} }
/**
* On change.
*
* @param {State} state
*/
onChange = (state) => {
console.groupCollapsed('Change!')
console.log('Document:', state.document.toJS())
console.log('Selection:', state.selection.toJS())
console.log('Content:', serialize(state))
console.groupEnd()
this.setState({ state })
}
} }
/** /**

View File

@@ -1,7 +1,7 @@
import { Editor, Mark, Raw } from '../..' import { Editor, Mark, Raw } from '../..'
import React from 'react' import React from 'react'
import state from './state.json' import initialState from './state.json'
/** /**
* Node renderers. * Node renderers.
@@ -52,22 +52,20 @@ const MARKS = {
class RichText extends React.Component { class RichText extends React.Component {
state = { state = {
state: Raw.deserialize(state) state: Raw.deserialize(initialState)
}; };
hasMark(type) { hasMark = (type) => {
const { state } = this.state const { state } = this.state
const { marks } = state return state.marks.some(mark => mark.type == type)
return marks.some(mark => mark.type == type)
} }
hasBlock(type) { hasBlock = (type) => {
const { state } = this.state const { state } = this.state
const { blocks } = state return state.blocks.some(node => node.type == type)
return blocks.some(node => node.type == type)
} }
onClickMark(e, type) { onClickMark = (e, type) => {
e.preventDefault() e.preventDefault()
const isActive = this.hasMark(type) const isActive = this.hasMark(type)
let { state } = this.state let { state } = this.state
@@ -80,7 +78,7 @@ class RichText extends React.Component {
this.setState({ state }) this.setState({ state })
} }
onClickBlock(e, type) { onClickBlock = (e, type) => {
e.preventDefault() e.preventDefault()
const isActive = this.hasBlock(type) const isActive = this.hasBlock(type)
let { state } = this.state let { state } = this.state
@@ -93,7 +91,7 @@ class RichText extends React.Component {
this.setState({ state }) this.setState({ state })
} }
render() { render = () => {
return ( return (
<div> <div>
{this.renderToolbar()} {this.renderToolbar()}
@@ -102,7 +100,7 @@ class RichText extends React.Component {
) )
} }
renderToolbar() { renderToolbar = () => {
return ( return (
<div className="menu toolbar-menu"> <div className="menu toolbar-menu">
{this.renderMarkButton('bold', 'format_bold')} {this.renderMarkButton('bold', 'format_bold')}
@@ -118,43 +116,58 @@ class RichText extends React.Component {
) )
} }
renderMarkButton(type, icon) { renderMarkButton = (type, icon) => {
const isActive = this.hasMark(type) const isActive = this.hasMark(type)
const onMouseDown = e => this.onClickMark(e, type)
return ( return (
<span className="button" onMouseDown={e => this.onClickMark(e, type)} data-active={isActive}> <span className="button" onMouseDown={onMouseDown} data-active={isActive}>
<span className="material-icons">{icon}</span> <span className="material-icons">{icon}</span>
</span> </span>
) )
} }
renderBlockButton(type, icon) { renderBlockButton = (type, icon) => {
const isActive = this.hasBlock(type) const isActive = this.hasBlock(type)
const onMouseDown = e => this.onClickBlock(e, type)
return ( return (
<span className="button" onMouseDown={e => this.onClickBlock(e, type)} data-active={isActive}> <span className="button" onMouseDown={onMouseDown} data-active={isActive}>
<span className="material-icons">{icon}</span> <span className="material-icons">{icon}</span>
</span> </span>
) )
} }
renderEditor() { renderEditor = () => {
return ( return (
<div className="editor"> <div className="editor">
<Editor <Editor
state={this.state.state} state={this.state.state}
renderNode={node => NODES[node.type]} renderNode={this.renderNode}
renderMark={mark => MARKS[mark.type]} renderMark={this.renderMark}
onChange={(state) => { onChange={this.onChange}
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> </div>
) )
} }
renderNode = (node) => {
return NODES[node.type]
}
renderMark = (mark) => {
return MARKS[mark.type]
}
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 })
}
} }
/** /**

View File

@@ -1,8 +1,8 @@
import { Editor, Raw } from '../..' import { Editor, Raw } from '../..'
import React from 'react' import React from 'react'
import initialState from './state.json'
import keycode from 'keycode' import keycode from 'keycode'
import state from './state.json'
/** /**
* Node renderers. * Node renderers.
@@ -44,7 +44,7 @@ class Tables extends React.Component {
*/ */
state = { state = {
state: Raw.deserialize(state) state: Raw.deserialize(initialState)
}; };
/** /**
@@ -53,27 +53,57 @@ class Tables extends React.Component {
* @return {Component} component * @return {Component} component
*/ */
render() { render = () => {
return ( return (
<div className="editor"> <div className="editor">
<Editor <Editor
state={this.state.state} state={this.state.state}
renderNode={node => NODES[node.type]} renderNode={this.renderNode}
renderMark={mark => MARKS[mark.type]} renderMark={this.renderMark}
onKeyDown={(e, state) => this.onKeyDown(e, state)} onKeyDown={this.onKeyDown}
onChange={(state) => { onChange={this.onChange}
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> </div>
) )
} }
/**
* Render a `node`.
*
* @param {Node} node
* @return {Element}
*/
renderNode = (node) => {
return NODES[node.type]
}
/**
* Render a `mark`.
*
* @param {Mark} mark
* @return {Element}
*/
renderMark = (mark) => {
return MARKS[mark.type]
}
/**
* On change.
*
* @param {State} 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 })
}
/** /**
* On key down, check for our specific key shortcuts. * On key down, check for our specific key shortcuts.
* *
@@ -82,11 +112,9 @@ class Tables extends React.Component {
* @return {State or Null} state * @return {State or Null} state
*/ */
onKeyDown(e, state) { onKeyDown = (e, state) => {
if (state.startBlock.type != 'table-cell') return if (state.startBlock.type != 'table-cell') return
switch (keycode(e.which)) {
const key = keycode(e.which)
switch (key) {
case 'backspace': return this.onBackspace(e, state) case 'backspace': return this.onBackspace(e, state)
case 'delete': return this.onDelete(e, state) case 'delete': return this.onDelete(e, state)
case 'enter': return this.onEnter(e, state) case 'enter': return this.onEnter(e, state)
@@ -101,7 +129,7 @@ class Tables extends React.Component {
* @return {State or Null} state * @return {State or Null} state
*/ */
onBackspace(e, state) { onBackspace = (e, state) => {
if (state.startOffset != 0) return if (state.startOffset != 0) return
e.preventDefault() e.preventDefault()
return state return state
@@ -115,7 +143,7 @@ class Tables extends React.Component {
* @return {State or Null} state * @return {State or Null} state
*/ */
onDelete(e, state) { onDelete = (e, state) => {
if (state.endOffset != state.startText.length) return if (state.endOffset != state.startText.length) return
e.preventDefault() e.preventDefault()
return state return state
@@ -129,7 +157,7 @@ class Tables extends React.Component {
* @return {State or Null} state * @return {State or Null} state
*/ */
onEnter(e, state) { onEnter = (e, state) => {
e.preventDefault() e.preventDefault()
return state return state
} }

View File

@@ -6,7 +6,7 @@
"main": "./dist/index.js", "main": "./dist/index.js",
"scripts": { "scripts": {
"prepublish": "make dist", "prepublish": "make dist",
"test": "make test" "test": "make check"
}, },
"dependencies": { "dependencies": {
"cheerio": "^0.20.0", "cheerio": "^0.20.0",