mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-31 02:49:56 +02:00
add linting to examples
This commit is contained in:
20
.eslintrc
20
.eslintrc
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
"plugins": [
|
||||
"import",
|
||||
"react"
|
||||
],
|
||||
"settings": {
|
||||
"import/extensions": [".js"]
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
@@ -9,10 +12,10 @@
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"plugins": [
|
||||
"import",
|
||||
"react"
|
||||
],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
"block-spacing": "error",
|
||||
"comma-dangle": ["error", "only-multiline"],
|
||||
@@ -25,9 +28,7 @@
|
||||
"dot-notation": ["error", { "allowKeywords": true }],
|
||||
"eol-last": "error",
|
||||
"func-style": ["error", "declaration"],
|
||||
"import/default": "error",
|
||||
"import/export": "error",
|
||||
"import/named": "error",
|
||||
"import/namespace": "error",
|
||||
"import/newline-after-import": "error",
|
||||
"import/no-deprecated": "error",
|
||||
@@ -41,7 +42,6 @@
|
||||
"new-parens": "error",
|
||||
"no-array-constructor": "error",
|
||||
"no-class-assign": "error",
|
||||
"no-console": "warn",
|
||||
"no-const-assign": "error",
|
||||
"no-debugger": "warn",
|
||||
"no-dupe-args": "error",
|
||||
|
11
Makefile
11
Makefile
@@ -47,16 +47,19 @@ examples:
|
||||
install:
|
||||
@ npm install
|
||||
|
||||
# Lint the sources files with Standard JS.
|
||||
# Lint the source files.
|
||||
lint:
|
||||
@ $(eslint) "lib/**/*.js"
|
||||
@ $(eslint) \
|
||||
"lib/**/*.js" \
|
||||
"examples/**/*.js" --ignore-pattern "build.js"
|
||||
|
||||
# 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) \
|
||||
./test/browser.js \
|
||||
--debug \
|
||||
--transform babelify \
|
||||
--outfile ./test/support/build.js ./test/browser.js
|
||||
--outfile ./test/support/build.js
|
||||
|
||||
# Run the tests.
|
||||
test: test-browser test-server
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import { Editor, Raw } from '../..'
|
||||
import React from 'react'
|
||||
import keycode from 'keycode'
|
||||
import state from './state.json'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
* Node renderers.
|
||||
@@ -38,7 +38,7 @@ class AutoMarkdown extends React.Component {
|
||||
*/
|
||||
|
||||
state = {
|
||||
state: Raw.deserialize(state)
|
||||
state: Raw.deserialize(initialState)
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -48,7 +48,7 @@ class AutoMarkdown extends React.Component {
|
||||
* @return {String} block
|
||||
*/
|
||||
|
||||
getType(chars) {
|
||||
getType = (chars) => {
|
||||
switch (chars) {
|
||||
case '*':
|
||||
case '-':
|
||||
@@ -71,26 +71,45 @@ class AutoMarkdown extends React.Component {
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
state={this.state.state}
|
||||
renderNode={node => NODES[node.type]}
|
||||
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 })
|
||||
}}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</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.
|
||||
*
|
||||
@@ -99,7 +118,7 @@ class AutoMarkdown extends React.Component {
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onKeyDown(e, state) {
|
||||
onKeyDown = (e, state) => {
|
||||
const key = keycode(e.which)
|
||||
switch (key) {
|
||||
case 'space': return this.onSpace(e, state)
|
||||
@@ -117,7 +136,7 @@ class AutoMarkdown extends React.Component {
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onSpace(e, state) {
|
||||
onSpace = (e, state) => {
|
||||
if (state.isExpanded) return
|
||||
let { selection } = state
|
||||
const { startText, startBlock, startOffset } = state
|
||||
@@ -151,7 +170,7 @@ class AutoMarkdown extends React.Component {
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onBackspace(e, state) {
|
||||
onBackspace = (e, state) => {
|
||||
if (state.isExpanded) return
|
||||
if (state.startOffset != 0) return
|
||||
const { startBlock } = state
|
||||
@@ -178,7 +197,7 @@ class AutoMarkdown extends React.Component {
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onEnter(e, state) {
|
||||
onEnter = (e, state) => {
|
||||
if (state.isExpanded) return
|
||||
const { startBlock, startOffset, endOffset } = state
|
||||
if (startOffset == 0 && startBlock.length == 0) return this.onBackspace(e, state)
|
||||
|
@@ -3,7 +3,7 @@ import { Editor, Mark, Raw, Selection } from '../..'
|
||||
import Prism from 'prismjs'
|
||||
import React from 'react'
|
||||
import keycode from 'keycode'
|
||||
import state from './state.json'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
* Node renderers.
|
||||
@@ -43,10 +43,19 @@ const MARKS = {
|
||||
class CodeHighlighting extends React.Component {
|
||||
|
||||
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)
|
||||
if (key != 'enter') return
|
||||
const { startBlock } = state
|
||||
@@ -59,29 +68,30 @@ class CodeHighlighting extends React.Component {
|
||||
return transform.apply()
|
||||
}
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
state={this.state.state}
|
||||
renderNode={node => NODES[node.type]}
|
||||
renderMark={mark => MARKS[mark.type] || {}}
|
||||
renderDecorations={(...args) => this.renderDecorations(...args)}
|
||||
onKeyDown={(...args) => this.onKeyDown(...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 })
|
||||
}}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
renderDecorations={this.renderDecorations}
|
||||
onKeyDown={this.onKeyDown}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</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
|
||||
const { document } = state
|
||||
const block = document.getClosestBlock(text)
|
||||
|
@@ -3,7 +3,7 @@ import { Editor, Mark, Raw } from '../..'
|
||||
import Portal from 'react-portal'
|
||||
import React from 'react'
|
||||
import position from 'selection-position'
|
||||
import state from './state.json'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
* Node renderers.
|
||||
@@ -48,37 +48,74 @@ const MARKS = {
|
||||
class HoveringMenu extends React.Component {
|
||||
|
||||
state = {
|
||||
state: Raw.deserialize(state)
|
||||
state: Raw.deserialize(initialState)
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
componentDidMount = () => {
|
||||
this.updateMenu()
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
componentDidUpdate = () => {
|
||||
this.updateMenu()
|
||||
}
|
||||
|
||||
hasMark(type) {
|
||||
render = () => {
|
||||
return (
|
||||
<div>
|
||||
{this.renderMenu()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderMenu = () => {
|
||||
const { state } = this.state
|
||||
const { marks } = state
|
||||
return marks.some(mark => mark.type == type)
|
||||
const isOpen = state.isExpanded && state.isFocused
|
||||
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) {
|
||||
e.preventDefault()
|
||||
renderMarkButton = (type, icon) => {
|
||||
const isActive = this.hasMark(type)
|
||||
let { state } = this.state
|
||||
const onMouseDown = e => this.onClickMark(e, type)
|
||||
|
||||
state = state
|
||||
.transform()
|
||||
[isActive ? 'unmark' : 'mark'](type)
|
||||
.apply()
|
||||
|
||||
this.setState({ state })
|
||||
return (
|
||||
<span className="button" onMouseDown={onMouseDown} data-active={isActive}>
|
||||
<span className="material-icons">{icon}</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
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`
|
||||
}
|
||||
|
||||
onOpen(el) {
|
||||
this.setState({ menu: el.firstChild })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.renderMenu()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderMenu() {
|
||||
hasMark = (type) => {
|
||||
const { state } = this.state
|
||||
const isOpen = state.isExpanded && state.isFocused
|
||||
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>
|
||||
)
|
||||
return state.marks.some(mark => mark.type == type)
|
||||
}
|
||||
|
||||
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)
|
||||
return (
|
||||
<span className="button" onMouseDown={e => this.onClickMark(e, type)} data-active={isActive}>
|
||||
<span className="material-icons">{icon}</span>
|
||||
</span>
|
||||
)
|
||||
let { state } = this.state
|
||||
|
||||
state = state
|
||||
.transform()
|
||||
[isActive ? 'unmark' : 'mark'](type)
|
||||
.apply()
|
||||
|
||||
this.setState({ state })
|
||||
}
|
||||
|
||||
renderEditor() {
|
||||
return (
|
||||
<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>
|
||||
)
|
||||
onOpen = (el) => {
|
||||
this.setState({ menu: el.firstChild })
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import { Editor, Mark, Raw } from '../..'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import state from './state.json'
|
||||
import initialState from './state.json'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
/**
|
||||
@@ -31,16 +31,104 @@ const NODES = {
|
||||
class Images extends React.Component {
|
||||
|
||||
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.
|
||||
*
|
||||
* @param {String} src
|
||||
*/
|
||||
|
||||
insertImage(src) {
|
||||
insertImage = (src) => {
|
||||
let { state } = this.state
|
||||
|
||||
if (state.isExpanded) {
|
||||
@@ -74,75 +162,6 @@ class Images extends React.Component {
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import { Editor, Mark, Raw } from '../..'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import state from './state.json'
|
||||
import initialState from './state.json'
|
||||
import { Map } from 'immutable'
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ const NODES = {
|
||||
class Links extends React.Component {
|
||||
|
||||
state = {
|
||||
state: Raw.deserialize(state)
|
||||
state: Raw.deserialize(initialState)
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -38,10 +38,9 @@ class Links extends React.Component {
|
||||
* @return {Boolean} hasLinks
|
||||
*/
|
||||
|
||||
hasLinks() {
|
||||
hasLinks = () => {
|
||||
const { state } = this.state
|
||||
const { inlines } = state
|
||||
return inlines.some(inline => inline.type == 'link')
|
||||
return state.inlines.some(inline => inline.type == 'link')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +50,7 @@ class Links extends React.Component {
|
||||
* @param {Event} e
|
||||
*/
|
||||
|
||||
onClickLink(e) {
|
||||
onClickLink = (e) => {
|
||||
e.preventDefault()
|
||||
let { state } = this.state
|
||||
const hasLinks = this.hasLinks()
|
||||
@@ -92,7 +91,7 @@ class Links extends React.Component {
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
return (
|
||||
<div>
|
||||
{this.renderToolbar()}
|
||||
@@ -107,11 +106,11 @@ class Links extends React.Component {
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
renderToolbar() {
|
||||
renderToolbar = () => {
|
||||
const hasLinks = this.hasLinks()
|
||||
return (
|
||||
<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>
|
||||
</div>
|
||||
@@ -124,25 +123,44 @@ class Links extends React.Component {
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
renderEditor() {
|
||||
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 })
|
||||
}}
|
||||
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 })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
import { Editor, Html, Raw } from '../..'
|
||||
import React from 'react'
|
||||
import state from './state.json'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
* Node renderers.
|
||||
@@ -166,10 +166,41 @@ const serializer = new Html(RULES)
|
||||
class PasteHtml extends React.Component {
|
||||
|
||||
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
|
||||
const { html } = paste
|
||||
const { document } = serializer.deserialize(html)
|
||||
@@ -180,27 +211,6 @@ class PasteHtml extends React.Component {
|
||||
.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>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
import { Block, Character, Document, Editor, State, Text } from '../..'
|
||||
import React from 'react'
|
||||
import state from './state.json'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
* A helper to deserialize a string into an editor state.
|
||||
@@ -54,7 +54,7 @@ class PlainText extends React.Component {
|
||||
*/
|
||||
|
||||
state = {
|
||||
state: deserialize(state)
|
||||
state: deserialize(initialState)
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -63,22 +63,30 @@ class PlainText extends React.Component {
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
return (
|
||||
<Editor
|
||||
state={this.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 })
|
||||
}}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
import { Editor, Mark, Raw } from '../..'
|
||||
import React from 'react'
|
||||
import state from './state.json'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
* Node renderers.
|
||||
@@ -52,22 +52,20 @@ const MARKS = {
|
||||
class RichText extends React.Component {
|
||||
|
||||
state = {
|
||||
state: Raw.deserialize(state)
|
||||
state: Raw.deserialize(initialState)
|
||||
};
|
||||
|
||||
hasMark(type) {
|
||||
hasMark = (type) => {
|
||||
const { state } = this.state
|
||||
const { marks } = state
|
||||
return marks.some(mark => mark.type == type)
|
||||
return state.marks.some(mark => mark.type == type)
|
||||
}
|
||||
|
||||
hasBlock(type) {
|
||||
hasBlock = (type) => {
|
||||
const { state } = this.state
|
||||
const { blocks } = state
|
||||
return blocks.some(node => node.type == type)
|
||||
return state.blocks.some(node => node.type == type)
|
||||
}
|
||||
|
||||
onClickMark(e, type) {
|
||||
onClickMark = (e, type) => {
|
||||
e.preventDefault()
|
||||
const isActive = this.hasMark(type)
|
||||
let { state } = this.state
|
||||
@@ -80,7 +78,7 @@ class RichText extends React.Component {
|
||||
this.setState({ state })
|
||||
}
|
||||
|
||||
onClickBlock(e, type) {
|
||||
onClickBlock = (e, type) => {
|
||||
e.preventDefault()
|
||||
const isActive = this.hasBlock(type)
|
||||
let { state } = this.state
|
||||
@@ -93,7 +91,7 @@ class RichText extends React.Component {
|
||||
this.setState({ state })
|
||||
}
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
return (
|
||||
<div>
|
||||
{this.renderToolbar()}
|
||||
@@ -102,7 +100,7 @@ class RichText extends React.Component {
|
||||
)
|
||||
}
|
||||
|
||||
renderToolbar() {
|
||||
renderToolbar = () => {
|
||||
return (
|
||||
<div className="menu toolbar-menu">
|
||||
{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 onMouseDown = e => this.onClickMark(e, type)
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
renderBlockButton(type, icon) {
|
||||
renderBlockButton = (type, icon) => {
|
||||
const isActive = this.hasBlock(type)
|
||||
const onMouseDown = e => this.onClickBlock(e, type)
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
||||
renderEditor() {
|
||||
renderEditor = () => {
|
||||
return (
|
||||
<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 })
|
||||
}}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
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 })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,8 +1,8 @@
|
||||
|
||||
import { Editor, Raw } from '../..'
|
||||
import React from 'react'
|
||||
import initialState from './state.json'
|
||||
import keycode from 'keycode'
|
||||
import state from './state.json'
|
||||
|
||||
/**
|
||||
* Node renderers.
|
||||
@@ -44,7 +44,7 @@ class Tables extends React.Component {
|
||||
*/
|
||||
|
||||
state = {
|
||||
state: Raw.deserialize(state)
|
||||
state: Raw.deserialize(initialState)
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -53,27 +53,57 @@ class Tables extends React.Component {
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
state={this.state.state}
|
||||
renderNode={node => NODES[node.type]}
|
||||
renderMark={mark => MARKS[mark.type]}
|
||||
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 })
|
||||
}}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
onKeyDown={this.onKeyDown}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</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.
|
||||
*
|
||||
@@ -82,11 +112,9 @@ class Tables extends React.Component {
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onKeyDown(e, state) {
|
||||
onKeyDown = (e, state) => {
|
||||
if (state.startBlock.type != 'table-cell') return
|
||||
|
||||
const key = keycode(e.which)
|
||||
switch (key) {
|
||||
switch (keycode(e.which)) {
|
||||
case 'backspace': return this.onBackspace(e, state)
|
||||
case 'delete': return this.onDelete(e, state)
|
||||
case 'enter': return this.onEnter(e, state)
|
||||
@@ -101,7 +129,7 @@ class Tables extends React.Component {
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onBackspace(e, state) {
|
||||
onBackspace = (e, state) => {
|
||||
if (state.startOffset != 0) return
|
||||
e.preventDefault()
|
||||
return state
|
||||
@@ -115,7 +143,7 @@ class Tables extends React.Component {
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onDelete(e, state) {
|
||||
onDelete = (e, state) => {
|
||||
if (state.endOffset != state.startText.length) return
|
||||
e.preventDefault()
|
||||
return state
|
||||
@@ -129,7 +157,7 @@ class Tables extends React.Component {
|
||||
* @return {State or Null} state
|
||||
*/
|
||||
|
||||
onEnter(e, state) {
|
||||
onEnter = (e, state) => {
|
||||
e.preventDefault()
|
||||
return state
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
"main": "./dist/index.js",
|
||||
"scripts": {
|
||||
"prepublish": "make dist",
|
||||
"test": "make test"
|
||||
"test": "make check"
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "^0.20.0",
|
||||
|
Reference in New Issue
Block a user