1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-17 04:34:00 +02:00

Add Prettier with ESLint integration (#1589)

* Add Prettier, with basic config and ESLint integration

* Apply Prettier to all files using `yarn lint --fix`

* Tell Prettier to ignore an empty text in a test output.

* Run Prettier on JS files not handled by ESLint, and lint them too
This commit is contained in:
Renaud Chaput
2018-02-06 23:12:00 +00:00
committed by Ian Storm Taylor
parent f28c59a26e
commit 3339d088e1
637 changed files with 4432 additions and 4281 deletions

View File

@@ -1,8 +1,6 @@
{
"plugins": [
"import",
"react"
],
"extends": ["prettier", "prettier/react"],
"plugins": ["import", "react", "prettier"],
"settings": {
"import/extensions": [".js"]
},
@@ -18,19 +16,8 @@
"node": true
},
"rules": {
"arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }],
"arrow-spacing": "error",
"block-spacing": "error",
"comma-dangle": ["error", "only-multiline"],
"comma-spacing": ["error", { "before": false, "after": true }],
"comma-style": ["error", "last"],
"computed-property-spacing": ["error", "never"],
"constructor-super": "error",
"curly": ["error", "multi-line"],
"dot-location": ["error", "property"],
"dot-notation": ["error", { "allowKeywords": true }],
"eol-last": "error",
"func-call-spacing": ["error", "never"],
"import/default": "error",
"import/export": "error",
"import/first": "error",
@@ -38,18 +25,25 @@
"import/namespace": "error",
"import/newline-after-import": "error",
"import/no-deprecated": "error",
"import/no-extraneous-dependencies": ["error", { "peerDependencies": true }],
"import/no-extraneous-dependencies": [
"error",
{ "peerDependencies": true }
],
"import/no-mutable-exports": "error",
"import/no-named-as-default": "error",
"import/no-named-as-default-member": "error",
"import/no-unresolved": "error",
"indent": ["error", 2, { "SwitchCase": 1, "MemberExpression": 1 }],
"jsx-quotes": ["error", "prefer-double"],
"key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
"keyword-spacing": ["error", { "before": true, "after": true }],
"linebreak-style": "error",
"lines-around-comment": ["error", { "beforeBlockComment": true, "afterBlockComment": true, "allowBlockStart": true, "allowObjectStart": true, "allowArrayStart": true }],
"new-parens": "error",
"lines-around-comment": [
"error",
{
"beforeBlockComment": true,
"afterBlockComment": true,
"allowBlockStart": true,
"allowObjectStart": true,
"allowArrayStart": true
}
],
"no-array-constructor": "error",
"no-class-assign": "error",
"no-console": "error",
@@ -68,9 +62,6 @@
"no-func-assign": "error",
"no-invalid-regexp": "error",
"no-lonely-if": "error",
"no-mixed-spaces-and-tabs": ["error", false],
"no-multi-spaces": "error",
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
"no-native-reassign": "error",
"no-negated-in-lhs": "error",
"no-new-object": "error",
@@ -78,15 +69,29 @@
"no-path-concat": "error",
"no-redeclare": "error",
"no-regex-spaces": "error",
"no-restricted-globals": ["error", "Debug", "document", "Document", "event", "history", "History", "length", "Map", "Node", "parent", "Range", "Selection", "Set", "Text"],
"no-restricted-globals": [
"error",
"Debug",
"document",
"Document",
"event",
"history",
"History",
"length",
"Map",
"Node",
"parent",
"Range",
"Selection",
"Set",
"Text"
],
"no-sequences": "error",
"no-shadow": "error",
"no-shadow-restricted-names": "error",
"no-spaced-func": "error",
"no-tabs": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-undef": "error",
"no-unneeded-ternary": "error",
"no-unreachable": "error",
@@ -100,31 +105,24 @@
"no-useless-rename": "error",
"no-var": "error",
"no-void": "error",
"no-whitespace-before-property": "error",
"no-with": "error",
"object-curly-spacing": ["error", "always", { "objectsInObjects": false }],
"object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }],
"object-shorthand": ["error", "always"],
"operator-linebreak": ["error", "after", { "overrides": { "?": "ignore", ":": "ignore" }}],
"padded-blocks": ["error", { "blocks": "never", "classes": "always" }],
"prefer-arrow-callback": "error",
"prefer-const": ["error", { "destructuring": "all", "ignoreReadBeforeAssign": true }],
"prefer-const": [
"error",
{ "destructuring": "all", "ignoreReadBeforeAssign": true }
],
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
"prettier/prettier": "error",
"radix": "error",
"react/jsx-boolean-value": ["error", "never"],
"react/jsx-closing-bracket-location": "error",
"react/jsx-curly-spacing": ["error", "never"],
"react/jsx-equals-spacing": "error",
"react/jsx-first-prop-new-line": ["error", "multiline"],
"react/jsx-key": "error",
"react/jsx-no-bind": "error",
"react/jsx-no-duplicate-props": "error",
"react/jsx-no-target-blank": "error",
"react/jsx-no-undef": "error",
"react/jsx-tag-spacing": ["error", { "beforeSelfClosing": "always" }],
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/jsx-wrap-multilines": "error",
@@ -136,19 +134,12 @@
"react/react-in-jsx-scope": "error",
"react/self-closing-comp": "error",
"react/sort-prop-types": "error",
"rest-spread-spacing": ["error", "never"],
"semi": ["error", "never"],
"space-before-blocks": "error",
"space-before-function-paren": ["error", { "anonymous": "always", "named": "never" }],
"space-in-parens": "error",
"space-infix-ops": "error",
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
"spaced-comment": ["error", "always", { "exceptions": ["-"] }],
"template-curly-spacing": "error",
"template-tag-spacing": ["error", "never"],
"unicode-bom": ["error", "never"],
"use-isnan": "error",
"valid-jsdoc": ["error", { "prefer": { "return": "returns" }, "requireReturn": false }],
"valid-jsdoc": [
"error",
{ "prefer": { "return": "returns" }, "requireReturn": false }
],
"valid-typeof": "error",
"yield-star-spacing": ["error", "after"],
"yoda": ["error", "never"]

5
.prettierignore Normal file
View File

@@ -0,0 +1,5 @@
examples/build.prod.js
package.json
packages/*/dist/
packages/*/lib/
tmp/

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -12,14 +11,13 @@ import initialValue from './value.json'
*/
class CheckListItem extends React.Component {
/**
* On change, set the new checked value on the block.
*
* @param {Event} event
*/
onChange = (event) => {
onChange = event => {
const checked = event.target.checked
const { editor, node } = this.props
editor.change(c => c.setNodeByKey(node.key, { data: { checked } }))
@@ -42,11 +40,7 @@ class CheckListItem extends React.Component {
{...attributes}
>
<span>
<input
type="checkbox"
checked={checked}
onChange={this.onChange}
/>
<input type="checkbox" checked={checked} onChange={this.onChange} />
</span>
<span contentEditable suppressContentEditableWarning>
{children}
@@ -54,7 +48,6 @@ class CheckListItem extends React.Component {
</div>
)
}
}
/**
@@ -64,7 +57,6 @@ class CheckListItem extends React.Component {
*/
class CheckLists extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -72,7 +64,7 @@ class CheckLists extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -102,10 +94,7 @@ class CheckLists extends React.Component {
onKeyDown = (event, change) => {
const { value } = change
if (
event.key == 'Enter' &&
value.startBlock.type == 'check-list-item'
) {
if (event.key == 'Enter' && value.startBlock.type == 'check-list-item') {
change.splitBlock().setBlock({ data: { checked: false } })
return true
}
@@ -151,12 +140,12 @@ class CheckLists extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
switch (props.node.type) {
case 'check-list-item': return <CheckListItem {...props} />
case 'check-list-item':
return <CheckListItem {...props} />
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -18,7 +17,9 @@ function CodeBlock(props) {
const language = node.data.get('language')
function onChange(event) {
editor.change(c => c.setNodeByKey(node.key, { data: { language: event.target.value }}))
editor.change(c =>
c.setNodeByKey(node.key, { data: { language: event.target.value } })
)
}
return (
@@ -41,9 +42,7 @@ function CodeBlock(props) {
}
function CodeBlockLine(props) {
return (
<div {...props.attributes}>{props.children}</div>
)
return <div {...props.attributes}>{props.children}</div>
}
/**
@@ -53,7 +52,6 @@ function CodeBlockLine(props) {
*/
class CodeHighlighting extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -61,7 +59,7 @@ class CodeHighlighting extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -121,10 +119,12 @@ class CodeHighlighting extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
switch (props.node.type) {
case 'code': return <CodeBlock {...props} />
case 'code_line': return <CodeBlockLine {...props} />
case 'code':
return <CodeBlock {...props} />
case 'code_line':
return <CodeBlockLine {...props} />
}
}
@@ -135,17 +135,21 @@ class CodeHighlighting extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'comment': return <span style={{ opacity: '0.33' }}>{children}</span>
case 'keyword': return <span style={{ fontWeight: 'bold' }}>{children}</span>
case 'tag': return <span style={{ fontWeight: 'bold' }}>{children}</span>
case 'punctuation': return <span style={{ opacity: '0.75' }}>{children}</span>
case 'comment':
return <span style={{ opacity: '0.33' }}>{children}</span>
case 'keyword':
return <span style={{ fontWeight: 'bold' }}>{children}</span>
case 'tag':
return <span style={{ fontWeight: 'bold' }}>{children}</span>
case 'punctuation':
return <span style={{ opacity: '0.75' }}>{children}</span>
}
}
tokenToContent = (token) => {
tokenToContent = token => {
if (typeof token == 'string') {
return token
} else if (typeof token.content == 'string') {
@@ -162,7 +166,7 @@ class CodeHighlighting extends React.Component {
* @return {Array}
*/
decorateNode = (node) => {
decorateNode = node => {
if (node.type != 'code') return
const language = node.data.get('language')
@@ -215,7 +219,6 @@ class CodeHighlighting extends React.Component {
return decorations
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -13,7 +12,6 @@ import initialValue from './value.json'
*/
class Embeds extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -21,7 +19,7 @@ class Embeds extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -60,12 +58,12 @@ class Embeds extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
switch (props.node.type) {
case 'video': return <Video {...props} />
case 'video':
return <Video {...props} />
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import React from 'react'
/**
@@ -8,14 +7,13 @@ import React from 'react'
*/
class Video extends React.Component {
/**
* When the input text changes, update the `video` data on the node.
*
* @param {Event} e
*/
onChange = (e) => {
onChange = e => {
const video = e.target.value
const { node, editor } = this.props
editor.change(c => c.setNodeByKey(node.key, { data: { video } }))
@@ -28,7 +26,7 @@ class Video extends React.Component {
* @type {Event} e
*/
onClick = (e) => {
onClick = e => {
e.stopPropagation()
}
@@ -74,7 +72,7 @@ class Video extends React.Component {
}
const iframeStyle = {
display: 'block'
display: 'block',
}
return (
@@ -104,7 +102,7 @@ class Video extends React.Component {
const video = node.data.get('video')
const style = {
marginTop: '5px',
boxSizing: 'border-box'
boxSizing: 'border-box',
}
return (
@@ -116,7 +114,6 @@ class Video extends React.Component {
/>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -12,9 +11,24 @@ import initialValue from './value.json'
*/
const EMOJIS = [
'😃', '😬', '😂', '😅', '😆', '😍',
'😱', '👋', '👏', '👍', '🙌', '👌',
'🙏', '👻', '🍔', '🍑', '🍆', '🔑',
'😃',
'😬',
'😂',
'😅',
'😆',
'😍',
'😱',
'👋',
'👏',
'👍',
'🙌',
'👌',
'🙏',
'👻',
'🍔',
'🍑',
'🍆',
'🔑',
]
/**
@@ -32,7 +46,6 @@ const noop = e => e.preventDefault()
*/
class Emojis extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -40,7 +53,7 @@ class Emojis extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -67,7 +80,7 @@ class Emojis extends React.Component {
change.insertInline({
type: 'emoji',
isVoid: true,
data: { code }
data: { code },
})
this.onChange(change)
@@ -136,7 +149,7 @@ class Emojis extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node, isSelected } = props
switch (node.type) {
case 'paragraph': {
@@ -158,7 +171,6 @@ class Emojis extends React.Component {
}
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Block, Value } from 'slate'
import { CHILD_REQUIRED, CHILD_TYPE_INVALID } from 'slate-schema-violations'
@@ -21,15 +20,18 @@ const schema = {
normalize: (change, violation, { node, child, index }) => {
switch (violation) {
case CHILD_TYPE_INVALID: {
return change.setNodeByKey(child.key, index == 0 ? 'title' : 'paragraph')
return change.setNodeByKey(
child.key,
index == 0 ? 'title' : 'paragraph'
)
}
case CHILD_REQUIRED: {
const block = Block.create(index == 0 ? 'title' : 'paragraph')
return change.insertNodeByKey(node.key, index, block)
}
}
}
}
},
},
}
/**
@@ -39,7 +41,6 @@ const schema = {
*/
class ForcedLayout extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -87,14 +88,15 @@ class ForcedLayout extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node } = props
switch (node.type) {
case 'title': return <h2 {...attributes}>{children}</h2>
case 'paragraph': return <p {...attributes}>{children}</p>
case 'title':
return <h2 {...attributes}>{children}</h2>
case 'paragraph':
return <p {...attributes}>{children}</p>
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Value } from 'slate'
import { Editor } from 'slate-react'
@@ -24,7 +23,6 @@ const ToolbarButton = props => (
*/
class History extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -32,7 +30,7 @@ class History extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -50,7 +48,7 @@ class History extends React.Component {
*
*/
onClickRedo = (event) => {
onClickRedo = event => {
event.preventDefault()
const { value } = this.state
const change = value.change().redo()
@@ -62,7 +60,7 @@ class History extends React.Component {
*
*/
onClickUndo = (event) => {
onClickUndo = event => {
event.preventDefault()
const { value } = this.state
const change = value.change().undo()
@@ -96,12 +94,8 @@ class History extends React.Component {
<div className="menu toolbar-menu">
<ToolbarButton icon="undo" onMouseDown={this.onClickUndo} />
<ToolbarButton icon="redo" onMouseDown={this.onClickRedo} />
<span className="button">
Undos: {value.history.undos.size}
</span>
<span className="button">
Redos: {value.history.redos.size}
</span>
<span className="button">Undos: {value.history.undos.size}</span>
<span className="button">Redos: {value.history.redos.size}</span>
</div>
)
}
@@ -123,7 +117,6 @@ class History extends React.Component {
</div>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -15,7 +14,6 @@ const root = window.document.querySelector('main')
*/
class Menu extends React.Component {
/**
* Check if the current selection has a mark with `type` in it.
*
@@ -69,8 +67,7 @@ class Menu extends React.Component {
*/
render() {
return (
ReactDOM.createPortal(
return ReactDOM.createPortal(
<div className="menu hover-menu" ref={this.props.menuRef}>
{this.renderMarkButton('bold', 'format_bold')}
{this.renderMarkButton('italic', 'format_italic')}
@@ -79,12 +76,9 @@ class Menu extends React.Component {
</div>,
root
)
)
}
}
/**
* The hovering menu example.
*
@@ -92,7 +86,6 @@ class Menu extends React.Component {
*/
class HoveringMenu extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -100,7 +93,7 @@ class HoveringMenu extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -134,7 +127,10 @@ class HoveringMenu extends React.Component {
const rect = range.getBoundingClientRect()
menu.style.opacity = 1
menu.style.top = `${rect.top + window.scrollY - menu.offsetHeight}px`
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`
}
/**
@@ -153,7 +149,7 @@ class HoveringMenu extends React.Component {
* @param {Menu} menu
*/
menuRef = (menu) => {
menuRef = menu => {
this.menu = menu
}
@@ -190,16 +186,19 @@ class HoveringMenu extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'bold': return <strong>{children}</strong>
case 'code': return <code>{children}</code>
case 'italic': return <em>{children}</em>
case 'underlined': return <u>{children}</u>
case 'bold':
return <strong>{children}</strong>
case 'code':
return <code>{children}</code>
case 'italic':
return <em>{children}</em>
case 'underlined':
return <u>{children}</u>
}
}
}
/**

View File

@@ -16,21 +16,21 @@ const HEADINGS = 100
const PARAGRAPHS = 8 // Paragraphs per heading
const nodes = []
const json = {
document: { nodes }
document: { nodes },
}
for (let h = 0; h < HEADINGS; h++) {
nodes.push({
object: 'block',
type: 'heading',
nodes: [{ object: 'text', leaves: [{ text: faker.lorem.sentence() }] }]
nodes: [{ object: 'text', leaves: [{ text: faker.lorem.sentence() }] }],
})
for (let p = 0; p < PARAGRAPHS; p++) {
nodes.push({
object: 'block',
type: 'paragraph',
nodes: [{ object: 'text', leaves: [{ text: faker.lorem.paragraph() }] }]
nodes: [{ object: 'text', leaves: [{ text: faker.lorem.paragraph() }] }],
})
}
}
@@ -42,7 +42,6 @@ for (let h = 0; h < HEADINGS; h++) {
*/
class HugeDocument extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -95,10 +94,11 @@ class HugeDocument extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node } = props
switch (node.type) {
case 'heading': return <h1 {...attributes}>{children}</h1>
case 'heading':
return <h1 {...attributes}>{children}</h1>
}
}
@@ -109,16 +109,19 @@ class HugeDocument extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'bold': return <strong>{children}</strong>
case 'code': return <code>{children}</code>
case 'italic': return <em>{children}</em>
case 'underlined': return <u>{children}</u>
case 'bold':
return <strong>{children}</strong>
case 'code':
return <code>{children}</code>
case 'italic':
return <em>{children}</em>
case 'underlined':
return <u>{children}</u>
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor, getEventRange, getEventTransfer } from 'slate-react'
import { Block, Value } from 'slate'
import { LAST_CHILD_TYPE_INVALID } from 'slate-schema-violations'
@@ -35,7 +34,7 @@ function insertImage(change, src, target) {
change.insertBlock({
type: 'image',
isVoid: true,
data: { src }
data: { src },
})
}
@@ -55,8 +54,8 @@ const schema = {
return change.insertNodeByKey(node.key, node.nodes.size, paragraph)
}
}
}
}
},
},
}
/**
@@ -66,7 +65,6 @@ const schema = {
*/
class Images extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -74,7 +72,7 @@ class Images extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -137,7 +135,7 @@ class Images extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, node, isSelected } = props
switch (node.type) {
case 'image': {
@@ -167,14 +165,12 @@ class Images extends React.Component {
* @param {Event} event
*/
onClickImage = (event) => {
onClickImage = event => {
event.preventDefault()
const src = window.prompt('Enter the URL of the image:')
if (!src) return
const change = this.state.value
.change()
.call(insertImage, src)
const change = this.state.value.change().call(insertImage, src)
this.onChange(change)
}
@@ -201,7 +197,7 @@ class Images extends React.Component {
if (mime != 'image') continue
reader.addEventListener('load', () => {
editor.change((c) => {
editor.change(c => {
c.call(insertImage, reader.result, target)
})
})
@@ -216,7 +212,6 @@ class Images extends React.Component {
change.call(insertImage, text, target)
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { HashRouter, NavLink, Route, Redirect, Switch } from 'react-router-dom'
@@ -62,7 +61,6 @@ const EXAMPLES = [
*/
class App extends React.Component {
state = {
error: null,
info: null,
@@ -78,20 +76,30 @@ class App extends React.Component {
<div className="nav">
<span className="nav-title">Slate Examples</span>
<div className="nav-links">
<a className="nav-link" href="https://github.com/ianstormtaylor/slate">GitHub</a>
<a className="nav-link" href="https://docs.slatejs.org/">Docs</a>
<a
className="nav-link"
href="https://github.com/ianstormtaylor/slate"
>
GitHub
</a>
<a className="nav-link" href="https://docs.slatejs.org/">
Docs
</a>
</div>
</div>
<div className="tabs">
{EXAMPLES.map(([name, Component, path]) => (
<NavLink key={path} to={path} className="tab"activeClassName="active">
<NavLink
key={path}
to={path}
className="tab"
activeClassName="active"
>
{name}
</NavLink>
))}
</div>
{this.state.error
? this.renderError()
: this.renderExample()}
{this.state.error ? this.renderError() : this.renderExample()}
</div>
)
}
@@ -112,9 +120,7 @@ class App extends React.Component {
renderError() {
return (
<div className="error">
<p>
An error was thrown by one of the example's React components!
</p>
<p>An error was thrown by one of the example's React components!</p>
<pre className="info">
<code>
{this.state.error.stack}
@@ -125,7 +131,6 @@ class App extends React.Component {
</div>
)
}
}
/**
@@ -134,7 +139,11 @@ class App extends React.Component {
* @type {Element} router
*/
const router = <HashRouter><App /></HashRouter>
const router = (
<HashRouter>
<App />
</HashRouter>
)
/**
* Mount the router.

View File

@@ -1,4 +1,3 @@
import { Editor, getEventTransfer } from 'slate-react'
import { Value } from 'slate'
@@ -16,7 +15,7 @@ import isUrl from 'is-url'
function wrapLink(change, href) {
change.wrapInline({
type: 'link',
data: { href }
data: { href },
})
change.collapseToEnd()
@@ -39,7 +38,6 @@ function unwrapLink(change) {
*/
class Links extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -47,7 +45,7 @@ class Links extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -78,7 +76,7 @@ class Links extends React.Component {
* @param {Event} event
*/
onClickLink = (event) => {
onClickLink = event => {
event.preventDefault()
const { value } = this.state
const hasLinks = this.hasLinks()
@@ -86,14 +84,10 @@ class Links extends React.Component {
if (hasLinks) {
change.call(unwrapLink)
}
else if (value.isExpanded) {
} else if (value.isExpanded) {
const href = window.prompt('Enter the URL of the link:')
change.call(wrapLink, href)
}
else {
} else {
const href = window.prompt('Enter the URL of the link:')
const text = window.prompt('Enter the text for the link:')
change
@@ -153,7 +147,11 @@ class Links extends React.Component {
const hasLinks = this.hasLinks()
return (
<div className="menu toolbar-menu">
<span className="button" onMouseDown={this.onClickLink} data-active={hasLinks}>
<span
className="button"
onMouseDown={this.onClickLink}
data-active={hasLinks}
>
<span className="material-icons">link</span>
</span>
</div>
@@ -187,17 +185,20 @@ class Links extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node } = props
switch (node.type) {
case 'link': {
const { data } = node
const href = data.get('href')
return <a {...attributes} href={href}>{children}</a>
return (
<a {...attributes} href={href}>
{children}
</a>
)
}
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import Plain from 'slate-plain-serializer'
import { Editor } from 'slate-react'
@@ -10,7 +9,7 @@ import React from 'react'
*/
// eslint-disable-next-line
Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},code:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold);
;Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},code:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold); // prettier-ignore
/**
* The markdown preview example.
@@ -19,7 +18,6 @@ Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.ins
*/
class MarkdownPreview extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -27,7 +25,9 @@ class MarkdownPreview extends React.Component {
*/
state = {
value: Plain.deserialize('Slate is flexible enough to add **decorators** that can format text based on its content. For example, this editor has **Markdown** preview decorators on it, to make it _dead_ simple to make an editor with built-in Markdown previewing.\n## Try it out!\nTry it out for yourself!')
value: Plain.deserialize(
'Slate is flexible enough to add **decorators** that can format text based on its content. For example, this editor has **Markdown** preview decorators on it, to make it _dead_ simple to make an editor with built-in Markdown previewing.\n## Try it out!\nTry it out for yourself!'
),
}
/**
@@ -68,37 +68,56 @@ class MarkdownPreview extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'bold': return <strong>{children}</strong>
case 'code': return <code>{children}</code>
case 'italic': return <em>{children}</em>
case 'underlined': return <u>{children}</u>
case 'bold':
return <strong>{children}</strong>
case 'code':
return <code>{children}</code>
case 'italic':
return <em>{children}</em>
case 'underlined':
return <u>{children}</u>
case 'title': {
return (
<span style={{ fontWeight: 'bold', fontSize: '20px', margin: '20px 0 10px 0', display: 'inline-block' }}>
<span
style={{
fontWeight: 'bold',
fontSize: '20px',
margin: '20px 0 10px 0',
display: 'inline-block',
}}
>
{children}
</span>
)
}
case 'punctuation': {
return (
<span style={{ opacity: 0.2 }}>
{children}
</span>
)
return <span style={{ opacity: 0.2 }}>{children}</span>
}
case 'list': {
return (
<span style={{ paddingLeft: '10px', lineHeight: '10px', fontSize: '20px' }}>
<span
style={{
paddingLeft: '10px',
lineHeight: '10px',
fontSize: '20px',
}}
>
{children}
</span>
)
}
case 'hr': {
return (
<span style={{ borderBottom: '2px solid #000', display: 'block', opacity: 0.2 }}>
<span
style={{
borderBottom: '2px solid #000',
display: 'block',
opacity: 0.2,
}}
>
{children}
</span>
)
@@ -168,13 +187,11 @@ class MarkdownPreview extends React.Component {
decorations.push(range)
}
start = end
}
return decorations
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -12,7 +11,6 @@ import initialValue from './value.json'
*/
class MarkdownShortcuts extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -20,7 +18,7 @@ class MarkdownShortcuts extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -30,19 +28,28 @@ class MarkdownShortcuts extends React.Component {
* @return {String} block
*/
getType = (chars) => {
getType = chars => {
switch (chars) {
case '*':
case '-':
case '+': return 'list-item'
case '>': return 'block-quote'
case '#': return 'heading-one'
case '##': return 'heading-two'
case '###': return 'heading-three'
case '####': return 'heading-four'
case '#####': return 'heading-five'
case '######': return 'heading-six'
default: return null
case '+':
return 'list-item'
case '>':
return 'block-quote'
case '#':
return 'heading-one'
case '##':
return 'heading-two'
case '###':
return 'heading-three'
case '####':
return 'heading-four'
case '#####':
return 'heading-five'
case '######':
return 'heading-six'
default:
return null
}
}
@@ -74,18 +81,27 @@ class MarkdownShortcuts extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node } = props
switch (node.type) {
case 'block-quote': return <blockquote {...attributes}>{children}</blockquote>
case 'bulleted-list': return <ul {...attributes}>{children}</ul>
case 'heading-one': return <h1 {...attributes}>{children}</h1>
case 'heading-two': return <h2 {...attributes}>{children}</h2>
case 'heading-three': return <h3 {...attributes}>{children}</h3>
case 'heading-four': return <h4 {...attributes}>{children}</h4>
case 'heading-five': return <h5 {...attributes}>{children}</h5>
case 'heading-six': return <h6 {...attributes}>{children}</h6>
case 'list-item': return <li {...attributes}>{children}</li>
case 'block-quote':
return <blockquote {...attributes}>{children}</blockquote>
case 'bulleted-list':
return <ul {...attributes}>{children}</ul>
case 'heading-one':
return <h1 {...attributes}>{children}</h1>
case 'heading-two':
return <h2 {...attributes}>{children}</h2>
case 'heading-three':
return <h3 {...attributes}>{children}</h3>
case 'heading-four':
return <h4 {...attributes}>{children}</h4>
case 'heading-five':
return <h5 {...attributes}>{children}</h5>
case 'heading-six':
return <h6 {...attributes}>{children}</h6>
case 'list-item':
return <li {...attributes}>{children}</li>
}
}
@@ -108,9 +124,12 @@ class MarkdownShortcuts extends React.Component {
onKeyDown = (event, change) => {
switch (event.key) {
case ' ': return this.onSpace(event, change)
case 'Backspace': return this.onBackspace(event, change)
case 'Enter': return this.onEnter(event, change)
case ' ':
return this.onSpace(event, change)
case 'Backspace':
return this.onBackspace(event, change)
case 'Enter':
return this.onEnter(event, change)
}
}
@@ -183,7 +202,8 @@ class MarkdownShortcuts extends React.Component {
if (value.isExpanded) return
const { startBlock, startOffset, endOffset } = value
if (startOffset == 0 && startBlock.text.length == 0) return this.onBackspace(event, change)
if (startOffset == 0 && startBlock.text.length == 0)
return this.onBackspace(event, change)
if (endOffset != startBlock.text.length) return
if (
@@ -202,7 +222,6 @@ class MarkdownShortcuts extends React.Component {
change.splitBlock().setBlock('paragraph')
return true
}
}
/**

View File

@@ -1,4 +1,3 @@
import Html from 'slate-html-serializer'
import { Editor, getEventTransfer } from 'slate-react'
import { Value } from 'slate'
@@ -24,7 +23,7 @@ const BLOCK_TAGS = {
h3: 'heading-three',
h4: 'heading-four',
h5: 'heading-five',
h6: 'heading-six'
h6: 'heading-six',
}
/**
@@ -38,7 +37,7 @@ const MARK_TAGS = {
em: 'italic',
u: 'underline',
s: 'strikethrough',
code: 'code'
code: 'code',
}
/**
@@ -55,10 +54,10 @@ const RULES = [
return {
object: 'block',
type: block,
nodes: next(el.childNodes)
}
nodes: next(el.childNodes),
}
},
},
{
deserialize(el, next) {
const mark = MARK_TAGS[el.tagName.toLowerCase()]
@@ -66,26 +65,27 @@ const RULES = [
return {
object: 'mark',
type: mark,
nodes: next(el.childNodes)
}
nodes: next(el.childNodes),
}
},
},
{
// Special case for code blocks, which need to grab the nested childNodes.
deserialize(el, next) {
if (el.tagName.toLowerCase() != 'pre') return
const code = el.childNodes[0]
const childNodes = code && code.tagName.toLowerCase() == 'code'
const childNodes =
code && code.tagName.toLowerCase() == 'code'
? code.childNodes
: el.childNodes
return {
object: 'block',
type: 'code',
nodes: next(childNodes)
}
nodes: next(childNodes),
}
},
},
{
// Special case for images, to grab their src.
deserialize(el, next) {
@@ -96,11 +96,11 @@ const RULES = [
isVoid: true,
nodes: next(el.childNodes),
data: {
src: el.getAttribute('src')
}
}
src: el.getAttribute('src'),
},
}
},
},
{
// Special case for links, to grab their href.
deserialize(el, next) {
@@ -110,11 +110,11 @@ const RULES = [
type: 'link',
nodes: next(el.childNodes),
data: {
href: el.getAttribute('href')
}
}
}
href: el.getAttribute('href'),
},
}
},
},
]
/**
@@ -132,7 +132,6 @@ const serializer = new Html({ rules: RULES })
*/
class PasteHtml extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -140,7 +139,7 @@ class PasteHtml extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -196,24 +195,43 @@ class PasteHtml extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node, isSelected } = props
switch (node.type) {
case 'quote': return <blockquote {...attributes}>{children}</blockquote>
case 'code': return <pre><code {...attributes}>{children}</code></pre>
case 'bulleted-list': return <ul {...attributes}>{children}</ul>
case 'heading-one': return <h1 {...attributes}>{children}</h1>
case 'heading-two': return <h2 {...attributes}>{children}</h2>
case 'heading-three': return <h3 {...attributes}>{children}</h3>
case 'heading-four': return <h4 {...attributes}>{children}</h4>
case 'heading-five': return <h5 {...attributes}>{children}</h5>
case 'heading-six': return <h6 {...attributes}>{children}</h6>
case 'list-item': return <li {...attributes}>{children}</li>
case 'numbered-list': return <ol {...attributes}>{children}</ol>
case 'quote':
return <blockquote {...attributes}>{children}</blockquote>
case 'code':
return (
<pre>
<code {...attributes}>{children}</code>
</pre>
)
case 'bulleted-list':
return <ul {...attributes}>{children}</ul>
case 'heading-one':
return <h1 {...attributes}>{children}</h1>
case 'heading-two':
return <h2 {...attributes}>{children}</h2>
case 'heading-three':
return <h3 {...attributes}>{children}</h3>
case 'heading-four':
return <h4 {...attributes}>{children}</h4>
case 'heading-five':
return <h5 {...attributes}>{children}</h5>
case 'heading-six':
return <h6 {...attributes}>{children}</h6>
case 'list-item':
return <li {...attributes}>{children}</li>
case 'numbered-list':
return <ol {...attributes}>{children}</ol>
case 'link': {
const { data } = node
const href = data.get('href')
return <a href={href} {...attributes}>{children}</a>
return (
<a href={href} {...attributes}>
{children}
</a>
)
}
case 'image': {
const src = node.data.get('src')
@@ -233,16 +251,19 @@ class PasteHtml extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'bold': return <strong>{children}</strong>
case 'code': return <code>{children}</code>
case 'italic': return <em>{children}</em>
case 'underlined': return <u>{children}</u>
case 'bold':
return <strong>{children}</strong>
case 'code':
return <code>{children}</code>
case 'italic':
return <em>{children}</em>
case 'underlined':
return <u>{children}</u>
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import Plain from 'slate-plain-serializer'
import { Editor } from 'slate-react'
@@ -11,7 +10,6 @@ import React from 'react'
*/
class PlainText extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -19,7 +17,9 @@ class PlainText extends React.Component {
*/
state = {
value: Plain.deserialize('This is editable plain text, just like a <textarea>!')
value: Plain.deserialize(
'This is editable plain text, just like a <textarea>!'
),
}
/**
@@ -49,7 +49,6 @@ class PlainText extends React.Component {
</div>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import Plain from 'slate-plain-serializer'
import { Editor } from 'slate-react'
@@ -18,15 +17,13 @@ function WordCount(options) {
renderEditor(props) {
return (
<div>
<div>
{props.children}
</div>
<div>{props.children}</div>
<span className="word-counter">
Word Count: {props.value.document.text.split(' ').length}
</span>
</div>
)
}
},
}
}
@@ -34,11 +31,7 @@ function WordCount(options) {
* Plugins.
*/
const plugins = [
CollapseOnEscape(),
SoftBreak(),
WordCount()
]
const plugins = [CollapseOnEscape(), SoftBreak(), WordCount()]
/**
* The plugins example.
@@ -47,7 +40,6 @@ const plugins = [
*/
class Plugins extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -58,7 +50,7 @@ class Plugins extends React.Component {
value: Plain.deserialize(`This example shows how you can extend Slate with plugins! It uses four fairly simple plugins, but you can use any plugins you want, or write your own!
The first is a simple plugin to collapse the selection whenever the escape key is pressed. Try selecting some text and pressing escape.
The second is another simple plugin that inserts a "soft" break when enter is pressed instead of creating a new block. Try pressing enter!
The third is an example of using the plugin.render property to create a higher-order-component.`)
The third is an example of using the plugin.render property to create a higher-order-component.`),
}
/**
@@ -89,7 +81,6 @@ The third is an example of using the plugin.render property to create a higher-o
</div>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import Plain from 'slate-plain-serializer'
import { Editor } from 'slate-react'
@@ -11,7 +10,6 @@ import React from 'react'
*/
class ReadOnly extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -19,7 +17,9 @@ class ReadOnly extends React.Component {
*/
state = {
value: Plain.deserialize('This is read-only text. You should not be able to edit it, which is useful for scenarios where you want to render via Slate, without giving the user editing permissions.')
value: Plain.deserialize(
'This is read-only text. You should not be able to edit it, which is useful for scenarios where you want to render via Slate, without giving the user editing permissions.'
),
}
/**
@@ -50,7 +50,6 @@ class ReadOnly extends React.Component {
</div>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -32,7 +31,6 @@ const isCodeHotkey = isKeyHotkey('mod+`')
*/
class RichTextExample extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -50,7 +48,7 @@ class RichTextExample extends React.Component {
* @return {Boolean}
*/
hasMark = (type) => {
hasMark = type => {
const { value } = this.state
return value.activeMarks.some(mark => mark.type == type)
}
@@ -62,7 +60,7 @@ class RichTextExample extends React.Component {
* @return {Boolean}
*/
hasBlock = (type) => {
hasBlock = type => {
const { value } = this.state
return value.blocks.some(node => node.type == type)
}
@@ -142,18 +140,13 @@ class RichTextExample extends React.Component {
.setBlock(isActive ? DEFAULT_NODE : type)
.unwrapBlock('bulleted-list')
.unwrapBlock('numbered-list')
} else {
change.setBlock(isActive ? DEFAULT_NODE : type)
}
else {
change
.setBlock(isActive ? DEFAULT_NODE : type)
}
}
} else {
// Handle the extra wrapping required for list buttons.
else {
const isList = this.hasBlock('list-item')
const isType = value.blocks.some((block) => {
const isType = value.blocks.some(block => {
return !!document.getClosest(block.key, parent => parent.type == type)
})
@@ -164,12 +157,12 @@ class RichTextExample extends React.Component {
.unwrapBlock('numbered-list')
} else if (isList) {
change
.unwrapBlock(type == 'bulleted-list' ? 'numbered-list' : 'bulleted-list')
.unwrapBlock(
type == 'bulleted-list' ? 'numbered-list' : 'bulleted-list'
)
.wrapBlock(type)
} else {
change
.setBlock('list-item')
.wrapBlock(type)
change.setBlock('list-item').wrapBlock(type)
}
}
@@ -282,15 +275,21 @@ class RichTextExample extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node } = props
switch (node.type) {
case 'block-quote': return <blockquote {...attributes}>{children}</blockquote>
case 'bulleted-list': return <ul {...attributes}>{children}</ul>
case 'heading-one': return <h1 {...attributes}>{children}</h1>
case 'heading-two': return <h2 {...attributes}>{children}</h2>
case 'list-item': return <li {...attributes}>{children}</li>
case 'numbered-list': return <ol {...attributes}>{children}</ol>
case 'block-quote':
return <blockquote {...attributes}>{children}</blockquote>
case 'bulleted-list':
return <ul {...attributes}>{children}</ul>
case 'heading-one':
return <h1 {...attributes}>{children}</h1>
case 'heading-two':
return <h2 {...attributes}>{children}</h2>
case 'list-item':
return <li {...attributes}>{children}</li>
case 'numbered-list':
return <ol {...attributes}>{children}</ol>
}
}
@@ -301,16 +300,19 @@ class RichTextExample extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'bold': return <strong>{children}</strong>
case 'code': return <code>{children}</code>
case 'italic': return <em>{children}</em>
case 'underlined': return <u>{children}</u>
case 'bold':
return <strong>{children}</strong>
case 'code':
return <code>{children}</code>
case 'italic':
return <em>{children}</em>
case 'underlined':
return <u>{children}</u>
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -12,7 +11,6 @@ import initialValue from './value.json'
*/
class RTL extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -20,7 +18,7 @@ class RTL extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -75,13 +73,13 @@ class RTL extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node } = props
switch (node.type) {
case 'block-quote': return <blockquote {...attributes}>{children}</blockquote>
case 'block-quote':
return <blockquote {...attributes}>{children}</blockquote>
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -12,7 +11,6 @@ import initialValue from './value.json'
*/
class SearchHighlighting extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -39,13 +37,13 @@ class SearchHighlighting extends React.Component {
* @param {Event} event
*/
onInputChange = (event) => {
onInputChange = event => {
const { value } = this.state
const string = event.target.value
const texts = value.document.getTexts()
const decorations = []
texts.forEach((node) => {
texts.forEach(node => {
const { key, text } = node
const parts = text.split(string)
let offset = 0
@@ -69,7 +67,8 @@ class SearchHighlighting extends React.Component {
// to the undo/redo stack and clearing the redo stack if the user has undone
// changes.
const change = value.change()
const change = value
.change()
.setOperationFlag('save', false)
.setValue({ decorations })
.setOperationFlag('save', true)
@@ -140,13 +139,13 @@ class SearchHighlighting extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'highlight': return <span style={{ backgroundColor: '#ffeeba' }}>{children}</span>
case 'highlight':
return <span style={{ backgroundColor: '#ffeeba' }}>{children}</span>
}
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -24,7 +23,6 @@ const isCodeHotkey = isKeyHotkey('mod+`')
*/
class SyncingEditor extends React.Component {
/**
* Deserialize the initial editor value.
*
@@ -42,7 +40,7 @@ class SyncingEditor extends React.Component {
* @param {Array} operations
*/
applyOperations = (operations) => {
applyOperations = operations => {
const { value } = this.state
const change = value.change().applyOperations(operations)
this.onChange(change, { remote: true })
@@ -55,7 +53,7 @@ class SyncingEditor extends React.Component {
* @return {Boolean}
*/
hasMark = (type) => {
hasMark = type => {
const { value } = this.state
return value.activeMarks.some(mark => mark.type == type)
}
@@ -198,16 +196,19 @@ class SyncingEditor extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'bold': return <strong>{children}</strong>
case 'code': return <code>{children}</code>
case 'italic': return <em>{children}</em>
case 'underlined': return <u>{children}</u>
case 'bold':
return <strong>{children}</strong>
case 'code':
return <code>{children}</code>
case 'italic':
return <em>{children}</em>
case 'underlined':
return <u>{children}</u>
}
}
}
/**
@@ -217,14 +218,13 @@ class SyncingEditor extends React.Component {
*/
class SyncingOperationsExample extends React.Component {
/**
* Save a reference to editor `one`.
*
* @param {SyncingEditor} one
*/
oneRef = (one) => {
oneRef = one => {
this.one = one
}
@@ -234,7 +234,7 @@ class SyncingOperationsExample extends React.Component {
* @param {SyncingEditor} two
*/
twoRef = (two) => {
twoRef = two => {
this.two = two
}
@@ -244,7 +244,7 @@ class SyncingOperationsExample extends React.Component {
* @param {Array} operations
*/
onOneChange = (change) => {
onOneChange = change => {
const ops = change.operations
.filter(o => o.type != 'set_selection' && o.type != 'set_value')
.toJS()
@@ -260,7 +260,7 @@ class SyncingOperationsExample extends React.Component {
* @param {Array} operations
*/
onTwoChange = (change) => {
onTwoChange = change => {
const ops = change.operations
.filter(o => o.type != 'set_selection' && o.type != 'set_value')
.toJS()
@@ -279,10 +279,7 @@ class SyncingOperationsExample extends React.Component {
render() {
return (
<div>
<SyncingEditor
ref={this.oneRef}
onChange={this.onOneChange}
/>
<SyncingEditor ref={this.oneRef} onChange={this.onOneChange} />
<div
style={{
height: '20px',
@@ -290,14 +287,10 @@ class SyncingOperationsExample extends React.Component {
margin: '20px -20px',
}}
/>
<SyncingEditor
ref={this.twoRef}
onChange={this.onTwoChange}
/>
<SyncingEditor ref={this.twoRef} onChange={this.onTwoChange} />
</div>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import { Editor } from 'slate-react'
import { Value } from 'slate'
@@ -12,7 +11,6 @@ import initialValue from './value.json'
*/
class Tables extends React.Component {
/**
* Deserialize the raw initial value.
*
@@ -20,7 +18,7 @@ class Tables extends React.Component {
*/
state = {
value: Value.fromJSON(initialValue)
value: Value.fromJSON(initialValue),
}
/**
@@ -101,9 +99,12 @@ class Tables extends React.Component {
}
switch (event.key) {
case 'Backspace': return this.onBackspace(event, change)
case 'Delete': return this.onDelete(event, change)
case 'Enter': return this.onEnter(event, change)
case 'Backspace':
return this.onBackspace(event, change)
case 'Delete':
return this.onDelete(event, change)
case 'Enter':
return this.onEnter(event, change)
}
}
@@ -135,12 +136,19 @@ class Tables extends React.Component {
* @return {Element}
*/
renderNode = (props) => {
renderNode = props => {
const { attributes, children, node } = props
switch (node.type) {
case 'table': return <table><tbody {...attributes}>{children}</tbody></table>
case 'table-row': return <tr {...attributes}>{children}</tr>
case 'table-cell': return <td {...attributes}>{children}</td>
case 'table':
return (
<table>
<tbody {...attributes}>{children}</tbody>
</table>
)
case 'table-row':
return <tr {...attributes}>{children}</tr>
case 'table-cell':
return <td {...attributes}>{children}</td>
}
}
@@ -151,13 +159,13 @@ class Tables extends React.Component {
* @return {Element}
*/
renderMark = (props) => {
renderMark = props => {
const { children, mark } = props
switch (mark.type) {
case 'bold': return <strong>{children}</strong>
case 'bold':
return <strong>{children}</strong>
}
}
}
/**

View File

@@ -19,7 +19,9 @@
"cross-env": "^5.1.3",
"disc": "^1.3.2",
"eslint": "^4.16.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-prettier": "^2.5.0",
"eslint-plugin-react": "^7.6.0",
"faker": "^3.1.0",
"fbjs": "^0.8.3",
@@ -36,6 +38,7 @@
"matcha": "^0.7.0",
"mocha": "^2.5.3",
"npm-run-all": "^4.1.1",
"prettier": "^1.10.2",
"prismjs": "^1.5.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
@@ -77,13 +80,19 @@
"build": "cross-env NODE_ENV=production rollup --config",
"clean": "lerna run clean && rm -rf ./node_modules ./dist ./examples/build.*.js",
"gh-pages": "yarn build && gh-pages --dist ./examples",
"lint": "eslint packages/*/src packages/*/test examples/*/*.js examples/dev/*/*.js",
"lint": "eslint packages/*/src packages/*/test examples/*/*.js examples/dev/*/*.js && prettier --list-different '**/*.{js,jsx}'",
"open": "open http://localhost:8080/dev.html",
"prettier": "prettier --write '**/*.{js,jsx}'",
"release": "yarn test && yarn lint && lerna publish && yarn gh-pages",
"server": "http-server ./examples",
"start": "npm-run-all --parallel --print-label watch server",
"test": "cross-env BABEL_ENV=test mocha --require babel-core/register ./packages/*/test/index.js",
"watch": "rollup --config --watch",
"watch:packages": "cross-env SKIP_EXAMPLES=true yarn watch"
},
"prettier": {
"singleQuote": true,
"semi": false,
"trailingComma": "es5"
}
}

View File

@@ -1,4 +1,3 @@
import { Value } from 'slate'
import { atob, btoa } from 'isomorphic-base64'
@@ -91,5 +90,5 @@ export default {
deserialize,
deserializeNode,
serialize,
serializeNode
serializeNode,
}

View File

@@ -6,11 +6,10 @@
* @type {Boolean}
*/
const IS_DEV = (
const IS_DEV =
typeof process !== 'undefined' &&
process.env &&
process.env.NODE_ENV !== 'production'
)
/**
* Has console?
@@ -18,12 +17,11 @@ const IS_DEV = (
* @type {Boolean}
*/
const HAS_CONSOLE = (
const HAS_CONSOLE =
typeof console != 'undefined' &&
typeof console.log == 'function' &&
typeof console.warn == 'function' &&
typeof console.error == 'function'
)
/**
* Log a `message` at `level`.
@@ -50,7 +48,6 @@ function log(level, message, ...args) {
* @param {Any} ...args
*/
function error(message, ...args) {
if (HAS_CONSOLE) {
console.error(message, ...args)

View File

@@ -13,20 +13,24 @@ const html = new Html({
switch (obj.object) {
case 'block': {
switch (obj.type) {
case 'paragraph': return React.createElement('p', {}, children)
case 'quote': return React.createElement('blockquote', {}, children)
case 'paragraph':
return React.createElement('p', {}, children)
case 'quote':
return React.createElement('blockquote', {}, children)
}
}
case 'mark': {
switch (obj.type) {
case 'bold': return React.createElement('strong', {}, children)
case 'italic': return React.createElement('em', {}, children)
case 'bold':
return React.createElement('strong', {}, children)
case 'italic':
return React.createElement('em', {}, children)
}
}
}
}
}
]
},
},
],
})
export default function(string) {
@@ -39,4 +43,6 @@ export const input = `
This is editable <strong>rich</strong> text, <em>much</em> better than a textarea!
</p>
</blockquote>
`.trim().repeat(10)
`
.trim()
.repeat(10)

View File

@@ -14,20 +14,24 @@ const html = new Html({
switch (obj.object) {
case 'block': {
switch (obj.type) {
case 'paragraph': return React.createElement('p', {}, children)
case 'quote': return React.createElement('blockquote', {}, children)
case 'paragraph':
return React.createElement('p', {}, children)
case 'quote':
return React.createElement('blockquote', {}, children)
}
}
case 'mark': {
switch (obj.type) {
case 'bold': return React.createElement('strong', {}, children)
case 'italic': return React.createElement('em', {}, children)
case 'bold':
return React.createElement('strong', {}, children)
case 'italic':
return React.createElement('em', {}, children)
}
}
}
}
}
]
},
},
],
})
export default function(state) {
@@ -40,7 +44,8 @@ export const input = (
{Array.from(Array(10)).map(() => (
<quote>
<paragraph>
This is editable <b>rich</b> text, <i>much</i> better than a textarea!
This is editable <b>rich</b> text, <i>much</i> better than a
textarea!
</paragraph>
</quote>
))}

View File

@@ -9,9 +9,11 @@ import { __clear } from '../../slate/lib/utils/memoize'
*/
const categoryDir = resolve(__dirname)
const categories = fs.readdirSync(categoryDir).filter(c => c[0] != '.' && c != 'index.js')
const categories = fs
.readdirSync(categoryDir)
.filter(c => c[0] != '.' && c != 'index.js')
categories.forEach((category) => {
categories.forEach(category => {
suite(category, () => {
set('iterations', 50)
set('mintime', 1000)
@@ -23,9 +25,12 @@ categories.forEach((category) => {
}
const benchmarkDir = resolve(categoryDir, category)
const benchmarks = fs.readdirSync(benchmarkDir).filter(b => b[0] != '.' && !!~b.indexOf('.js')).map(b => basename(b, extname(b)))
const benchmarks = fs
.readdirSync(benchmarkDir)
.filter(b => b[0] != '.' && !!~b.indexOf('.js'))
.map(b => basename(b, extname(b)))
benchmarks.forEach((benchmark) => {
benchmarks.forEach(benchmark => {
const dir = resolve(benchmarkDir, benchmark)
const module = require(dir)
const fn = module.default

View File

@@ -1,4 +1,3 @@
import React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import typeOf from 'type-of'
@@ -13,7 +12,7 @@ import { Record } from 'immutable'
const String = new Record({
object: 'string',
text: ''
text: '',
})
/**
@@ -24,15 +23,16 @@ const String = new Record({
*/
const TEXT_RULE = {
deserialize(el) {
if (el.tagName && el.tagName.toLowerCase() === 'br') {
return {
object: 'text',
leaves: [{
leaves: [
{
object: 'leaf',
text: '\n'
}]
text: '\n',
},
],
}
}
@@ -41,26 +41,25 @@ const TEXT_RULE = {
return {
object: 'text',
leaves: [{
leaves: [
{
object: 'leaf',
text: el.nodeValue
}]
text: el.nodeValue,
},
],
}
}
},
serialize(obj, children) {
if (obj.object === 'string') {
return children
.split('\n')
.reduce((array, text, i) => {
return children.split('\n').reduce((array, text, i) => {
if (i != 0) array.push(<br />)
array.push(text)
return array
}, [])
}
}
},
}
/**
@@ -72,7 +71,9 @@ const TEXT_RULE = {
function defaultParseHtml(html) {
if (typeof DOMParser === 'undefined') {
throw new Error('The native `DOMParser` global which the `Html` serializer uses by default is not present in this environment. You must supply the `options.parseHtml` function instead.')
throw new Error(
'The native `DOMParser` global which the `Html` serializer uses by default is not present in this environment. You must supply the `options.parseHtml` function instead.'
)
}
const parsed = new DOMParser().parseFromString(html, 'text/html')
@@ -87,7 +88,6 @@ function defaultParseHtml(html) {
*/
class Html {
/**
* Create a new serializer with `rules`.
*
@@ -154,7 +154,8 @@ class Html {
// TODO: pretty sure this is no longer needed.
if (nodes.length == 0) {
nodes = [{
nodes = [
{
object: 'block',
data: {},
isVoid: false,
@@ -167,11 +168,12 @@ class Html {
object: 'leaf',
text: '',
marks: [],
}
]
}
},
],
}]
},
],
},
]
}
const json = {
@@ -180,7 +182,7 @@ class Html {
object: 'document',
data: {},
nodes,
}
},
}
const ret = toJSON ? json : Value.fromJSON(json)
@@ -197,7 +199,7 @@ class Html {
deserializeElements = (elements = []) => {
let nodes = []
elements.filter(this.cruftNewline).forEach((element) => {
elements.filter(this.cruftNewline).forEach(element => {
const node = this.deserializeElement(element)
switch (typeOf(node)) {
case 'array':
@@ -219,14 +221,14 @@ class Html {
* @return {Any}
*/
deserializeElement = (element) => {
deserializeElement = element => {
let node
if (!element.tagName) {
element.tagName = ''
}
const next = (elements) => {
const next = elements => {
if (Object.prototype.toString.call(elements) == '[object NodeList]') {
elements = Array.from(elements)
}
@@ -240,7 +242,9 @@ class Html {
case 'undefined':
return
default:
throw new Error(`The \`next\` argument was called with invalid children: "${elements}".`)
throw new Error(
`The \`next\` argument was called with invalid children: "${elements}".`
)
}
}
@@ -249,8 +253,15 @@ class Html {
const ret = rule.deserialize(element, next)
const type = typeOf(ret)
if (type != 'array' && type != 'object' && type != 'null' && type != 'undefined') {
throw new Error(`A rule returned an invalid deserialized representation: "${node}".`)
if (
type != 'array' &&
type != 'object' &&
type != 'null' &&
type != 'undefined'
) {
throw new Error(
`A rule returned an invalid deserialized representation: "${node}".`
)
}
if (ret === undefined) {
@@ -276,23 +287,19 @@ class Html {
* @return {Array}
*/
deserializeMark = (mark) => {
deserializeMark = mark => {
const { type, data } = mark
const applyMark = (node) => {
const applyMark = node => {
if (node.object == 'mark') {
return this.deserializeMark(node)
}
else if (node.object == 'text') {
node.leaves = node.leaves.map((leaf) => {
} else if (node.object == 'text') {
node.leaves = node.leaves.map(leaf => {
leaf.marks = leaf.marks || []
leaf.marks.push({ type, data })
return leaf
})
}
else {
} else {
node.nodes = node.nodes.map(applyMark)
}
@@ -333,7 +340,7 @@ class Html {
* @return {String}
*/
serializeNode = (node) => {
serializeNode = node => {
if (node.object === 'text') {
const leaves = node.getLeaves()
return leaves.map(this.serializeLeaf)
@@ -357,7 +364,7 @@ class Html {
* @return {String}
*/
serializeLeaf = (leaf) => {
serializeLeaf = leaf => {
const string = new String({ text: leaf.text })
const text = this.serializeString(string)
@@ -379,7 +386,7 @@ class Html {
* @return {String}
*/
serializeString = (string) => {
serializeString = string => {
for (const rule of this.rules) {
if (!rule.serialize) continue
const ret = rule.serialize(string, string.text)
@@ -394,10 +401,9 @@ class Html {
* @return {Boolean}
*/
cruftNewline = (element) => {
cruftNewline = element => {
return !(element.nodeName === '#text' && element.nodeValue == '\n')
}
}
/**

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -23,9 +22,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -36,9 +35,7 @@ export const output = (
<value>
<document>
<quote>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
</quote>
</document>
</value>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -16,9 +15,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -17,9 +16,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -29,9 +28,7 @@ export const input = `
export const output = (
<value>
<document>
<paragraph thing="value">
one
</paragraph>
<paragraph thing="value">one</paragraph>
</document>
</value>
)

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -16,9 +15,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -16,9 +15,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -28,9 +27,7 @@ export const input = `
export const output = (
<value>
<document>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
</document>
</value>
)

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -16,15 +15,15 @@ export const config = {
}
}
}
}
}
},
},
],
defaultBlock: {
type: 'default',
data: {
thing: 'value'
}
}
thing: 'value',
},
},
}
export const input = `
@@ -35,9 +34,7 @@ export const input = `
export const output = (
<value>
<document>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
<block type="default" data={{ thing: 'value' }}>
two
</block>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -16,9 +15,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -29,9 +28,7 @@ export const input = `
export const output = (
<value>
<document>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
</document>
</value>
)

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -30,9 +29,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -44,9 +43,7 @@ export const output = (
<document>
<paragraph>
<link>
<hashtag>
one
</hashtag>
<hashtag>one</hashtag>
</link>
</paragraph>
</document>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -23,9 +22,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -24,9 +23,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -37,9 +36,7 @@ export const output = (
<value>
<document>
<paragraph>
<link thing="value">
one
</link>
<link thing="value">one</link>
</paragraph>
</document>
</value>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -24,9 +23,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -23,9 +22,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -36,9 +35,7 @@ export const output = (
<value>
<document>
<paragraph>
<link>
one
</link>
<link>one</link>
</paragraph>
</document>
</value>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -30,9 +29,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -30,9 +29,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -43,7 +42,9 @@ export const output = (
<value>
<document>
<paragraph>
o<i>n<b>e</b></i>
o<i>
n<b>e</b>
</i>
</paragraph>
</document>
</value>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -24,9 +23,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -23,9 +22,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -11,7 +10,7 @@ export const config = {
object: 'block',
type: 'paragraph',
}
}
},
},
{
deserialize(el, next) {
@@ -19,9 +18,9 @@ export const config = {
object: 'block',
type: 'quote',
}
}
},
]
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -16,9 +15,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import h from '../helpers/h'
@@ -26,9 +25,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `

View File

@@ -1,4 +1,3 @@
export const config = {
rules: [
{
@@ -12,9 +11,9 @@ export const config = {
}
}
}
}
}
]
},
},
],
}
export const input = `
@@ -37,13 +36,13 @@ export const output = {
{
object: 'leaf',
text: 'one',
}
]
}
]
}
]
}
},
],
},
],
},
],
},
}
export const options = {

View File

@@ -1,4 +1,3 @@
import { createHyperscript } from 'slate-hyperscript'
/**
@@ -16,7 +15,7 @@ const h = createHyperscript({
image: {
type: 'image',
isVoid: true,
}
},
},
inlines: {
link: 'link',
@@ -25,7 +24,7 @@ const h = createHyperscript({
emoji: {
type: 'emoji',
isVoid: true,
}
},
},
marks: {
b: 'bold',

View File

@@ -1,4 +1,3 @@
/**
* Dependencies.
*/
@@ -25,7 +24,10 @@ beforeEach(() => {
describe('slate-html-serializer', () => {
describe('deserialize()', () => {
const dir = resolve(__dirname, './deserialize')
const tests = fs.readdirSync(dir).filter(t => t[0] != '.').map(t => basename(t, extname(t)))
const tests = fs
.readdirSync(dir)
.filter(t => t[0] != '.')
.map(t => basename(t, extname(t)))
for (const test of tests) {
it(test, async () => {
@@ -42,7 +44,10 @@ describe('slate-html-serializer', () => {
describe('serialize()', () => {
const dir = resolve(__dirname, './serialize')
const tests = fs.readdirSync(dir).filter(t => t[0] != '.').map(t => basename(t, extname(t)))
const tests = fs
.readdirSync(dir)
.filter(t => t[0] != '.')
.map(t => basename(t, extname(t)))
for (const test of tests) {
it(test, async () => {

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -9,20 +8,20 @@ export const rules = [
serialize(obj, children) {
if (obj.object != 'block') return
switch (obj.type) {
case 'paragraph': return React.createElement('p', {}, children)
case 'quote': return React.createElement('blockquote', {}, children)
}
}
case 'paragraph':
return React.createElement('p', {}, children)
case 'quote':
return React.createElement('blockquote', {}, children)
}
},
},
]
export const input = (
<value>
<document>
<quote>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
</quote>
</document>
</value>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -8,18 +7,20 @@ export const rules = [
{
serialize(obj, children) {
if (obj.object == 'block' && obj.type == 'paragraph') {
return React.createElement('p', { 'data-thing': obj.data.get('thing') }, children)
}
}
return React.createElement(
'p',
{ 'data-thing': obj.data.get('thing') },
children
)
}
},
},
]
export const input = (
<value>
<document>
<paragraph thing="value">
one
</paragraph>
<paragraph thing="value">one</paragraph>
</document>
</value>
)

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -10,8 +9,8 @@ export const rules = [
if (obj.object == 'block' && obj.type == 'image') {
return React.createElement('img')
}
}
}
},
},
]
export const input = (

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -14,8 +13,8 @@ export const rules = [
if (obj.object == 'mark' && obj.type == 'bold') {
return React.createElement('strong', {}, children)
}
}
}
},
},
]
export const input = (

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -10,16 +9,14 @@ export const rules = [
if (obj.object == 'block' && obj.type == 'paragraph') {
return React.createElement('p', {}, children)
}
}
}
},
},
]
export const input = (
<value>
<document>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
</document>
</value>
)

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -18,8 +17,8 @@ export const rules = [
if (obj.object == 'inline' && obj.type == 'hashtag') {
return React.createElement('span', {}, children)
}
}
}
},
},
]
export const input = (
@@ -27,9 +26,7 @@ export const input = (
<document>
<paragraph>
<link>
<hashtag>
one
</hashtag>
<hashtag>one</hashtag>
</link>
</paragraph>
</document>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -12,19 +11,21 @@ export const rules = [
}
if (obj.object == 'inline' && obj.type == 'link') {
return React.createElement('a', { href: obj.data.get('href') }, children)
}
}
return React.createElement(
'a',
{ href: obj.data.get('href') },
children
)
}
},
},
]
export const input = (
<value>
<document>
<paragraph>
<link href="https://google.com">
one
</link>
<link href="https://google.com">one</link>
</paragraph>
</document>
</value>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -14,8 +13,8 @@ export const rules = [
if (obj.object == 'inline' && obj.type == 'emoji') {
return React.createElement('img')
}
}
}
},
},
]
export const input = (

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -18,8 +17,8 @@ export const rules = [
if (obj.object == 'mark' && obj.type == 'bold') {
return React.createElement('strong', {}, children)
}
}
}
},
},
]
export const input = (

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -14,17 +13,15 @@ export const rules = [
if (obj.object == 'inline' && obj.type == 'link') {
return React.createElement('a', {}, children)
}
}
}
},
},
]
export const input = (
<value>
<document>
<paragraph>
<link>
one
</link>
<link>one</link>
</paragraph>
</document>
</value>

View File

@@ -1,4 +1,3 @@
/** @jsx h */
import React from 'react'
@@ -7,23 +6,21 @@ import h from '../helpers/h'
export const rules = [
{},
{
serialize(obj, children) {}
serialize(obj, children) {},
},
{
serialize(obj, children) {
if (obj.object == 'block' && obj.type == 'paragraph') {
return React.createElement('p', {}, children)
}
}
}
},
},
]
export const input = (
<value>
<document>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
</document>
</value>
)

View File

@@ -1,17 +1,7 @@
import isEmpty from 'is-empty'
import isPlainObject from 'is-plain-object'
import {
Block,
Document,
Inline,
Mark,
Node,
Range,
Text,
Value,
} from 'slate'
import { Block, Document, Inline, Mark, Node, Range, Text, Value } from 'slate'
/**
* Create selection point constants, for comparison by reference.
@@ -30,7 +20,6 @@ const FOCUS = {}
*/
const CREATORS = {
anchor(tagName, attributes, children) {
return ANCHOR
},
@@ -83,7 +72,7 @@ const CREATORS = {
// Search the document's texts to see if any of them have the anchor or
// focus information saved, so we can set the selection.
if (document) {
document.getTexts().forEach((text) => {
document.getTexts().forEach(text => {
if (text.__anchor != null) {
props.anchorKey = text.key
props.anchorOffset = text.__anchor
@@ -99,11 +88,15 @@ const CREATORS = {
}
if (props.anchorKey && !props.focusKey) {
throw new Error(`Slate hyperscript must have both \`<anchor/>\` and \`<focus/>\` defined if one is defined, but you only defined \`<anchor/>\`. For collapsed selections, use \`<cursor/>\`.`)
throw new Error(
`Slate hyperscript must have both \`<anchor/>\` and \`<focus/>\` defined if one is defined, but you only defined \`<anchor/>\`. For collapsed selections, use \`<cursor/>\`.`
)
}
if (!props.anchorKey && props.focusKey) {
throw new Error(`Slate hyperscript must have both \`<anchor/>\` and \`<focus/>\` defined if one is defined, but you only defined \`<focus/>\`. For collapsed selections, use \`<cursor/>\`.`)
throw new Error(
`Slate hyperscript must have both \`<anchor/>\` and \`<focus/>\` defined if one is defined, but you only defined \`<focus/>\`. For collapsed selections, use \`<cursor/>\`.`
)
}
if (!isEmpty(props)) {
@@ -118,7 +111,6 @@ const CREATORS = {
const nodes = createChildren(children, { key: attributes.key })
return nodes
},
}
/**
@@ -184,11 +176,12 @@ function createChildren(children, options = {}) {
node = next
}
children.forEach((child) => {
children.forEach(child => {
// If the child is a non-text node, push the current node and the new child
// onto the array, then creating a new node for future selection tracking.
if (Node.isNode(child) && !Text.isText(child)) {
if (node.text.length || node.__anchor != null || node.__focus != null) array.push(node)
if (node.text.length || node.__anchor != null || node.__focus != null)
array.push(node)
array.push(child)
node = Text.create()
length = 0
@@ -211,7 +204,7 @@ function createChildren(children, options = {}) {
setNode(node.set('key', child.key))
}
child.getLeaves().forEach((leaf) => {
child.getLeaves().forEach(leaf => {
let { marks } = leaf
if (options.marks) marks = marks.union(options.marks)
setNode(node.insertText(i, leaf.text, marks))
@@ -243,26 +236,22 @@ function createChildren(children, options = {}) {
*/
function resolveCreators(options) {
const {
blocks = {},
inlines = {},
marks = {},
} = options
const { blocks = {}, inlines = {}, marks = {} } = options
const creators = {
...CREATORS,
...(options.creators || {}),
}
Object.keys(blocks).map((key) => {
Object.keys(blocks).map(key => {
creators[key] = normalizeNode(key, blocks[key], 'block')
})
Object.keys(inlines).map((key) => {
Object.keys(inlines).map(key => {
creators[key] = normalizeNode(key, inlines[key], 'inline')
})
Object.keys(marks).map((key) => {
Object.keys(marks).map(key => {
creators[key] = normalizeMark(key, marks[key])
})
@@ -297,14 +286,16 @@ function normalizeNode(key, value, object) {
data: {
...(value.data || {}),
...rest,
}
},
}
return CREATORS[object](tagName, attrs, children)
}
}
throw new Error(`Slate hyperscript ${object} creators can be either functions, objects or strings, but you passed: ${value}`)
throw new Error(
`Slate hyperscript ${object} creators can be either functions, objects or strings, but you passed: ${value}`
)
}
/**
@@ -331,14 +322,16 @@ function normalizeMark(key, value) {
data: {
...(value.data || {}),
...attributes,
}
},
}
return CREATORS.mark(tagName, attrs, children)
}
}
throw new Error(`Slate hyperscript mark creators can be either functions, objects or strings, but you passed: ${value}`)
throw new Error(
`Slate hyperscript mark creators can be either functions, objects or strings, but you passed: ${value}`
)
}
/**

View File

@@ -9,9 +9,11 @@ import { __clear } from '../../slate/lib/utils/memoize'
*/
const categoryDir = resolve(__dirname)
const categories = fs.readdirSync(categoryDir).filter(c => c[0] != '.' && c != 'index.js')
const categories = fs
.readdirSync(categoryDir)
.filter(c => c[0] != '.' && c != 'index.js')
categories.forEach((category) => {
categories.forEach(category => {
suite(category, () => {
set('iterations', 50)
set('mintime', 1000)
@@ -23,9 +25,12 @@ categories.forEach((category) => {
}
const benchmarkDir = resolve(categoryDir, category)
const benchmarks = fs.readdirSync(benchmarkDir).filter(b => b[0] != '.' && !!~b.indexOf('.js')).map(b => basename(b, extname(b)))
const benchmarks = fs
.readdirSync(benchmarkDir)
.filter(b => b[0] != '.' && !!~b.indexOf('.js'))
.map(b => basename(b, extname(b)))
benchmarks.forEach((benchmark) => {
benchmarks.forEach(benchmark => {
const dir = resolve(benchmarkDir, benchmark)
const module = require(dir)
const fn = module.default

View File

@@ -9,4 +9,6 @@ export default function (string) {
export const input = `
This is editable plain text, just like a text area.
`.trim().repeat(10)
`
.trim()
.repeat(10)

View File

@@ -15,7 +15,8 @@ export const input = (
<quote>
<paragraph>
<paragraph>
This is editable <b>rich</b> text, <i>much</i> better than a textarea!
This is editable <b>rich</b> text, <i>much</i> better than a
textarea!
</paragraph>
</paragraph>
</quote>

View File

@@ -1,4 +1,3 @@
import { Block, Mark, Node, Value } from 'slate'
import { Set } from 'immutable'
@@ -14,11 +13,7 @@ import { Set } from 'immutable'
*/
function deserialize(string, options = {}) {
let {
defaultBlock = 'line',
defaultMarks = [],
toJSON = false,
} = options
let { defaultBlock = 'line', defaultMarks = [], toJSON = false } = options
if (Set.isSet(defaultMarks)) {
defaultMarks = defaultMarks.toArray()
@@ -32,7 +27,7 @@ function deserialize(string, options = {}) {
document: {
object: 'document',
data: {},
nodes: string.split('\n').map((line) => {
nodes: string.split('\n').map(line => {
return {
...defaultBlock,
object: 'block',
@@ -46,13 +41,13 @@ function deserialize(string, options = {}) {
object: 'leaf',
text: line,
marks: defaultMarks,
}
]
}
]
},
],
},
],
}
}),
}
},
}
const ret = toJSON ? json : Value.fromJSON(json)
@@ -79,7 +74,7 @@ function serialize(value) {
function serializeNode(node) {
if (
(node.object == 'document') ||
node.object == 'document' ||
(node.object == 'block' && Block.isBlockList(node.nodes))
) {
return node.nodes.map(serializeNode).join('\n')
@@ -96,5 +91,5 @@ function serializeNode(node) {
export default {
deserialize,
serialize
serialize,
}

View File

@@ -10,12 +10,8 @@ two
export const output = (
<value>
<document>
<line>
one
</line>
<line>
two
</line>
<line>one</line>
<line>two</line>
</document>
</value>
)

View File

@@ -9,9 +9,7 @@ one
export const output = (
<value>
<document>
<line>
one
</line>
<line>one</line>
</document>
</value>
)

View File

@@ -1,4 +1,3 @@
export const input = `
one
`.trim()
@@ -22,15 +21,15 @@ export const output = {
object: 'leaf',
text: 'one',
marks: [],
}
]
}
]
}
]
}
},
],
},
],
},
],
},
}
export const options = {
toJSON: true
toJSON: true,
}

View File

@@ -1,4 +1,3 @@
import { createHyperscript } from 'slate-hyperscript'
/**
@@ -16,7 +15,7 @@ const h = createHyperscript({
image: {
type: 'image',
isVoid: true,
}
},
},
inlines: {
link: 'link',
@@ -25,7 +24,7 @@ const h = createHyperscript({
emoji: {
type: 'emoji',
isVoid: true,
}
},
},
marks: {
b: 'bold',

View File

@@ -1,4 +1,3 @@
/**
* Dependencies.
*/
@@ -24,7 +23,10 @@ beforeEach(() => {
describe('slate-plain-serializer', () => {
describe('deserialize()', () => {
const dir = resolve(__dirname, './deserialize')
const tests = fs.readdirSync(dir).filter(t => t[0] != '.').map(t => basename(t, extname(t)))
const tests = fs
.readdirSync(dir)
.filter(t => t[0] != '.')
.map(t => basename(t, extname(t)))
for (const test of tests) {
it(test, async () => {
@@ -40,7 +42,10 @@ describe('slate-plain-serializer', () => {
describe('serialize()', () => {
const dir = resolve(__dirname, './serialize')
const tests = fs.readdirSync(dir).filter(t => t[0] != '.').map(t => basename(t, extname(t)))
const tests = fs
.readdirSync(dir)
.filter(t => t[0] != '.')
.map(t => basename(t, extname(t)))
for (const test of tests) {
it(test, async () => {

View File

@@ -5,13 +5,9 @@ import h from '../helpers/h'
export const input = (
<value>
<document>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
<paragraph />
<paragraph>
three
</paragraph>
<paragraph>three</paragraph>
</document>
</value>
)

View File

@@ -5,15 +5,9 @@ import h from '../helpers/h'
export const input = (
<value>
<document>
<paragraph>
one
</paragraph>
<paragraph>
two
</paragraph>
<paragraph>
three
</paragraph>
<paragraph>one</paragraph>
<paragraph>two</paragraph>
<paragraph>three</paragraph>
</document>
</value>
)

View File

@@ -6,18 +6,12 @@ export const input = (
<value>
<document>
<quote>
<paragraph>
one
</paragraph>
<paragraph>
two
</paragraph>
<paragraph>one</paragraph>
<paragraph>two</paragraph>
</quote>
<quote>
<paragraph />
<paragraph>
four
</paragraph>
<paragraph>four</paragraph>
</quote>
</document>
</value>

View File

@@ -6,20 +6,12 @@ export const input = (
<value>
<document>
<quote>
<paragraph>
one
</paragraph>
<paragraph>
two
</paragraph>
<paragraph>one</paragraph>
<paragraph>two</paragraph>
</quote>
<quote>
<paragraph>
three
</paragraph>
<paragraph>
four
</paragraph>
<paragraph>three</paragraph>
<paragraph>four</paragraph>
</quote>
</document>
</value>

View File

@@ -7,20 +7,12 @@ export const input = (
<document>
<quote>
<quote>
<paragraph>
one
</paragraph>
<paragraph>
two
</paragraph>
<paragraph>one</paragraph>
<paragraph>two</paragraph>
</quote>
<quote>
<paragraph>
three
</paragraph>
<paragraph>
four
</paragraph>
<paragraph>three</paragraph>
<paragraph>four</paragraph>
</quote>
</quote>
</document>

View File

@@ -6,14 +6,10 @@ export const input = (
<value>
<document>
<quote>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
<paragraph>
<link>
<hashtag>
two
</hashtag>
<hashtag>two</hashtag>
</link>
</paragraph>
</quote>

View File

@@ -7,14 +7,10 @@ export const input = (
<document>
<quote>
<paragraph>
<link>
one
</link>
<link>one</link>
</paragraph>
<paragraph>
<link>
two
</link>
<link>two</link>
</paragraph>
</quote>
</document>

View File

@@ -5,9 +5,7 @@ import h from '../helpers/h'
export const input = (
<value>
<document>
<paragraph thing="value">
one
</paragraph>
<paragraph thing="value">one</paragraph>
</document>
</value>
)

View File

@@ -5,9 +5,7 @@ import h from '../helpers/h'
export const input = (
<value>
<document>
<paragraph>
one
</paragraph>
<paragraph>one</paragraph>
</document>
</value>
)

View File

@@ -7,9 +7,7 @@ export const input = (
<document>
<paragraph>
<link>
<hashtag>
one
</hashtag>
<hashtag>one</hashtag>
</link>
</paragraph>
</document>

View File

@@ -6,9 +6,7 @@ export const input = (
<value>
<document>
<paragraph>
<link thing="value">
one
</link>
<link thing="value">one</link>
</paragraph>
</document>
</value>

View File

@@ -6,9 +6,7 @@ export const input = (
<value>
<document>
<paragraph>
<link>
one
</link>
<link>one</link>
</paragraph>
</document>
</value>

View File

@@ -1,4 +1,3 @@
import {
Block,
Change,
@@ -29,9 +28,14 @@ function create(name, validate) {
function check(isRequired, props, propName, componentName, location) {
const value = props[propName]
if (value == null && !isRequired) return null
if (value == null && isRequired) return new Error(`The ${location} \`${propName}\` is marked as required in \`${componentName}\`, but it was not supplied.`)
if (value == null && isRequired)
return new Error(
`The ${location} \`${propName}\` is marked as required in \`${componentName}\`, but it was not supplied.`
)
if (validate(value)) return null
return new Error(`Invalid ${location} \`${propName}\` supplied to \`${componentName}\`, expected a Slate \`${name}\` but received: ${value}`)
return new Error(
`Invalid ${location} \`${propName}\` supplied to \`${componentName}\`, expected a Slate \`${name}\` but received: ${value}`
)
}
function propType(...args) {

View File

@@ -8,17 +8,22 @@ import { basename, extname, resolve } from 'path'
*/
const categoryDir = resolve(__dirname)
const categories = fs.readdirSync(categoryDir).filter(c => c[0] != '.' && c != 'index.js')
const categories = fs
.readdirSync(categoryDir)
.filter(c => c[0] != '.' && c != 'index.js')
categories.forEach((category) => {
categories.forEach(category => {
suite(category, () => {
set('iterations', 50)
set('mintime', 1000)
const benchmarkDir = resolve(categoryDir, category)
const benchmarks = fs.readdirSync(benchmarkDir).filter(b => b[0] != '.' && !!~b.indexOf('.js')).map(b => basename(b, extname(b)))
const benchmarks = fs
.readdirSync(benchmarkDir)
.filter(b => b[0] != '.' && !!~b.indexOf('.js'))
.map(b => basename(b, extname(b)))
benchmarks.forEach((benchmark) => {
benchmarks.forEach(benchmark => {
const dir = resolve(benchmarkDir, benchmark)
const module = require(dir)
const fn = module.default

View File

@@ -18,7 +18,8 @@ export const input = (
<quote>
<paragraph>
<paragraph>
This is editable <b>rich</b> text, <i>much</i> better than a textarea!
This is editable <b>rich</b> text, <i>much</i> better than a
textarea!
</paragraph>
</paragraph>
</quote>

View File

@@ -1,4 +1,3 @@
import Debug from 'debug'
import React from 'react'
import Types from 'prop-types'
@@ -15,7 +14,7 @@ import {
IS_FIREFOX,
IS_IOS,
IS_ANDROID,
SUPPORTED_EVENTS
SUPPORTED_EVENTS,
} from '../constants/environment'
/**
@@ -33,7 +32,6 @@ const debug = Debug('slate:content')
*/
class Content extends React.Component {
/**
* Property types.
*
@@ -77,8 +75,8 @@ class Content extends React.Component {
this.tmp.key = 0
this.tmp.isUpdatingSelection = false
EVENT_HANDLERS.forEach((handler) => {
this[handler] = (event) => {
EVENT_HANDLERS.forEach(handler => {
this[handler] = event => {
this.onEvent(handler, event)
}
})
@@ -96,7 +94,10 @@ class Content extends React.Component {
const { editor } = this.props
const window = getWindow(this.element)
window.document.addEventListener('selectionchange', this.onNativeSelectionChange)
window.document.addEventListener(
'selectionchange',
this.onNativeSelectionChange
)
// COMPAT: Restrict scope of `beforeinput` to mobile.
if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) {
@@ -118,7 +119,10 @@ class Content extends React.Component {
const window = getWindow(this.element)
if (window) {
window.document.removeEventListener('selectionchange', this.onNativeSelectionChange)
window.document.removeEventListener(
'selectionchange',
this.onNativeSelectionChange
)
}
// COMPAT: Restrict scope of `beforeinput` to mobile.
@@ -169,16 +173,14 @@ class Content extends React.Component {
const range = findDOMRange(selection, window)
if (!range) {
logger.error('Unable to find a native DOM range from the current selection.', { selection })
logger.error(
'Unable to find a native DOM range from the current selection.',
{ selection }
)
return
}
const {
startContainer,
startOffset,
endContainer,
endOffset,
} = range
const { startContainer, startOffset, endContainer, endOffset } = range
// If the new range matches the current selection, there is nothing to fix.
// COMPAT: The native `Range` object always has it's "start" first and "end"
@@ -186,18 +188,14 @@ class Content extends React.Component {
// to check both orientations here. (2017/10/31)
if (current) {
if (
(
startContainer == current.startContainer &&
(startContainer == current.startContainer &&
startOffset == current.startOffset &&
endContainer == current.endContainer &&
endOffset == current.endOffset
) ||
(
startContainer == current.endContainer &&
endOffset == current.endOffset) ||
(startContainer == current.endContainer &&
startOffset == current.endOffset &&
endContainer == current.startContainer &&
endOffset == current.startOffset
)
endOffset == current.startOffset)
) {
return
}
@@ -251,7 +249,7 @@ class Content extends React.Component {
* @param {Element} element
*/
ref = (element) => {
ref = element => {
this.element = element
}
@@ -264,13 +262,13 @@ class Content extends React.Component {
* @return {Boolean}
*/
isInEditor = (target) => {
isInEditor = target => {
const { element } = this
// COMPAT: Text nodes don't have `isContentEditable` property. So, when
// `target` is a text node use its parent node for check.
const el = target.nodeType === 3 ? target.parentNode : target
return (
(el.isContentEditable) &&
el.isContentEditable &&
(el === element || el.closest('[data-slate-editor]') === element)
)
}
@@ -295,11 +293,7 @@ class Content extends React.Component {
// programmatically while updating selection.
if (
this.tmp.isUpdatingSelection &&
(
handler == 'onSelect' ||
handler == 'onBlur' ||
handler == 'onFocus'
)
(handler == 'onSelect' || handler == 'onBlur' || handler == 'onFocus')
) {
return
}
@@ -368,7 +362,7 @@ class Content extends React.Component {
* @param {InputEvent} event
*/
onNativeBeforeInput = (event) => {
onNativeBeforeInput = event => {
if (this.props.readOnly) return
if (!this.isInEditor(event.target)) return
@@ -391,7 +385,7 @@ class Content extends React.Component {
event.preventDefault()
const range = findRange(targetRange, editor.value)
editor.change((change) => {
editor.change(change => {
if (change.value.isInVoid) {
change.collapseToStartOfNextText()
} else {
@@ -407,7 +401,8 @@ class Content extends React.Component {
// `dataTransfer` should have the text for the `insertReplacementText`
// input type, but Safari uses `insertText` for spell check replacements
// and sets `data` to `null`.
const text = event.data == null
const text =
event.data == null
? event.dataTransfer.getData('text/plain')
: event.data
@@ -419,7 +414,7 @@ class Content extends React.Component {
const { selection } = value
const range = findRange(targetRange, value)
editor.change((change) => {
editor.change(change => {
change.insertTextAtRange(range, text, selection.marks)
// If the text was successfully inserted, and the selection had marks
@@ -443,7 +438,7 @@ class Content extends React.Component {
* @param {Event} event
*/
onNativeSelectionChange = throttle((event) => {
onNativeSelectionChange = throttle(event => {
if (this.props.readOnly) return
const window = getWindow(event.target)
@@ -526,7 +521,7 @@ class Content extends React.Component {
autoCorrect={props.autoCorrect ? 'on' : 'off'}
spellCheck={spellCheck}
style={style}
role={readOnly ? null : (role || 'textbox')}
role={readOnly ? null : role || 'textbox'}
tabIndex={tabIndex}
// COMPAT: The Grammarly Chrome extension works by changing the DOM out
// from under `contenteditable` elements, which leads to weird behaviors
@@ -567,14 +562,13 @@ class Content extends React.Component {
/>
)
}
}
/**
* Mix in handler prop types.
*/
EVENT_HANDLERS.forEach((handler) => {
EVENT_HANDLERS.forEach(handler => {
Content.propTypes[handler] = Types.func.isRequired
})

View File

@@ -1,4 +1,3 @@
import Debug from 'debug'
import Portal from 'react-portal'
import React from 'react'
@@ -28,7 +27,6 @@ const debug = Debug('slate:editor')
*/
class Editor extends React.Component {
/**
* Property types.
*
@@ -95,7 +93,7 @@ class Editor extends React.Component {
this.state.value = change.value
// Create a bound event handler for each event.
EVENT_HANDLERS.forEach((handler) => {
EVENT_HANDLERS.forEach(handler => {
this[handler] = (...args) => {
this.onEvent(handler, ...args)
}
@@ -109,7 +107,7 @@ class Editor extends React.Component {
* @param {Object} props
*/
componentWillReceiveProps = (props) => {
componentWillReceiveProps = props => {
let { schema, stack } = this
// Increment the updates counter as a baseline.
@@ -117,7 +115,10 @@ class Editor extends React.Component {
// If the plugins or the schema have changed, we need to re-resolve the
// plugins, since it will result in a new stack and new validations.
if (props.plugins != this.props.plugins || props.schema != this.props.schema) {
if (
props.plugins != this.props.plugins ||
props.schema != this.props.schema
) {
const plugins = this.resolvePlugins(props.plugins, props.schema)
stack = Stack.create({ plugins })
schema = Schema.create({ plugins })
@@ -129,7 +130,9 @@ class Editor extends React.Component {
// If we've resolved a few times already, and it's exactly in line with
// the updates, then warn the user that they may be doing something wrong.
if (this.tmp.resolves > 5 && this.tmp.resolves == this.tmp.updates) {
logger.warn('A Slate <Editor> is re-resolving `props.plugins` or `props.schema` on each update, which leads to poor performance. This is often due to passing in a new `schema` or `plugins` prop with each render by declaring them inline in your render function. Do not do this!')
logger.warn(
'A Slate <Editor> is re-resolving `props.plugins` or `props.schema` on each update, which leads to poor performance. This is often due to passing in a new `schema` or `plugins` prop with each render by declaring them inline in your render function. Do not do this!'
)
}
}
@@ -166,7 +169,7 @@ class Editor extends React.Component {
* @param {Change} change
*/
queueChange = (change) => {
queueChange = change => {
if (change.operations.size) {
debug('queueChange', { change })
this.tmp.change = change
@@ -239,7 +242,7 @@ class Editor extends React.Component {
*/
onEvent = (handler, event) => {
this.change((change) => {
this.change(change => {
this.stack.run(handler, event, change, this)
})
}
@@ -250,7 +253,7 @@ class Editor extends React.Component {
* @param {Change} change
*/
onChange = (change) => {
onChange = change => {
debug('onChange', { change })
this.stack.run('onChange', change, this)
@@ -271,7 +274,11 @@ class Editor extends React.Component {
const children = this.stack
.map('renderPortal', this.value, this)
.map((child, i) => <Portal key={i} isOpened>{child}</Portal>)
.map((child, i) => (
<Portal key={i} isOpened>
{child}
</Portal>
))
const props = { ...this.props, children }
const tree = this.stack.render('renderEditor', props, this)
@@ -296,7 +303,7 @@ class Editor extends React.Component {
const beforePlugin = BeforePlugin()
const afterPlugin = AfterPlugin()
const editorPlugin = {
schema: schema || {}
schema: schema || {},
}
for (const prop of PLUGINS_PROPS) {
@@ -313,17 +320,10 @@ class Editor extends React.Component {
}
}
return [
beforePlugin,
editorPlugin,
...(plugins || []),
afterPlugin
]
return [beforePlugin, editorPlugin, ...(plugins || []), afterPlugin]
}
}
/**
* Mix in the property types for the event handlers.
*/

View File

@@ -1,4 +1,3 @@
import Debug from 'debug'
import React from 'react'
import Types from 'prop-types'
@@ -21,7 +20,6 @@ const debug = Debug('slate:leaves')
*/
class Leaf extends React.Component {
/**
* Property types.
*
@@ -85,14 +83,10 @@ class Leaf extends React.Component {
const { node, index } = this.props
const offsetKey = OffsetKey.stringify({
key: node.key,
index
index,
})
return (
<span data-offset-key={offsetKey}>
{this.renderMarks()}
</span>
)
return <span data-offset-key={offsetKey}>{this.renderMarks()}</span>
}
/**
@@ -142,7 +136,6 @@ class Leaf extends React.Component {
// Otherwise, just return the text.
return text
}
}
/**

View File

@@ -1,4 +1,3 @@
import Debug from 'debug'
import ImmutableTypes from 'react-immutable-proptypes'
import React from 'react'
@@ -24,7 +23,6 @@ const debug = Debug('slate:node')
*/
class Node extends React.Component {
/**
* Property types.
*
@@ -62,10 +60,14 @@ class Node extends React.Component {
* @return {Boolean}
*/
shouldComponentUpdate = (nextProps) => {
shouldComponentUpdate = nextProps => {
const { props } = this
const { stack } = props.editor
const shouldUpdate = stack.find('shouldNodeComponentUpdate', props, nextProps)
const shouldUpdate = stack.find(
'shouldNodeComponentUpdate',
props,
nextProps
)
const n = nextProps
const p = props
@@ -78,7 +80,9 @@ class Node extends React.Component {
}
if (shouldUpdate === false) {
logger.warn('Returning false in `shouldNodeComponentUpdate` does not disable Slate\'s internal `shouldComponentUpdate` logic. If you want to prevent updates, use React\'s `shouldComponentUpdate` instead.')
logger.warn(
"Returning false in `shouldNodeComponentUpdate` does not disable Slate's internal `shouldComponentUpdate` logic. If you want to prevent updates, use React's `shouldComponentUpdate` instead."
)
}
}
@@ -148,15 +152,19 @@ class Node extends React.Component {
let placeholder = stack.find('renderPlaceholder', props)
if (placeholder) {
placeholder = React.cloneElement(placeholder, { key: `${node.key}-placeholder` })
placeholder = React.cloneElement(placeholder, {
key: `${node.key}-placeholder`,
})
children = [placeholder, ...children]
}
const element = stack.find('renderNode', { ...props, attributes, children })
const element = stack.find('renderNode', {
...props,
attributes,
children,
})
return node.isVoid
? <Void {...this.props}>{element}</Void>
: element
return node.isVoid ? <Void {...this.props}>{element}</Void> : element
}
/**
@@ -185,7 +193,6 @@ class Node extends React.Component {
/>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import Debug from 'debug'
import ImmutableTypes from 'react-immutable-proptypes'
import React from 'react'
@@ -22,7 +21,6 @@ const debug = Debug('slate:node')
*/
class Text extends React.Component {
/**
* Property types.
*
@@ -69,7 +67,7 @@ class Text extends React.Component {
* @return {Boolean}
*/
shouldComponentUpdate = (nextProps) => {
shouldComponentUpdate = nextProps => {
const { props } = this
const n = nextProps
const p = props
@@ -109,7 +107,7 @@ class Text extends React.Component {
const { document } = value
const { key } = node
const decs = decorations.filter((d) => {
const decs = decorations.filter(d => {
const { startKey, endKey } = d
if (startKey == key || endKey == key) return true
const startsBefore = document.areDescendantsSorted(startKey, key)
@@ -162,7 +160,6 @@ class Text extends React.Component {
/>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import Debug from 'debug'
import React from 'react'
import SlateTypes from 'slate-prop-types'
@@ -21,7 +20,6 @@ const debug = Debug('slate:void')
*/
class Void extends React.Component {
/**
* Property types.
*
@@ -78,11 +76,7 @@ class Void extends React.Component {
</Tag>
)
const content = (
<Tag draggable={readOnly ? null : true}>
{children}
</Tag>
)
const content = <Tag draggable={readOnly ? null : true}>{children}</Tag>
this.debug('render', { props })
@@ -110,7 +104,14 @@ class Void extends React.Component {
*/
renderText = () => {
const { block, decorations, isSelected, node, readOnly, editor } = this.props
const {
block,
decorations,
isSelected,
node,
readOnly,
editor,
} = this.props
const child = node.getFirstText()
return (
<Text
@@ -125,7 +126,6 @@ class Void extends React.Component {
/>
)
}
}
/**

View File

@@ -1,4 +1,3 @@
import browser from 'is-in-browser'
/**
@@ -26,9 +25,7 @@ const BROWSER_RULES = [
* @type {Array}
*/
const EVENT_RULES = [
['beforeinput', el => 'onbeforeinput' in el]
]
const EVENT_RULES = [['beforeinput', el => 'onbeforeinput' in el]]
/**
* Operating system matching rules.

View File

@@ -1,4 +1,3 @@
/**
* Event handlers used by Slate plugins.
*

View File

@@ -1,4 +1,3 @@
import { isKeyHotkey } from 'is-hotkey'
import { IS_IOS, IS_MAC } from './environment'
@@ -33,8 +32,10 @@ const DELETE_FORWARD = e => DELETE(e) || SHIFT_DELETE(e)
const DELETE_CHAR_BACKWARD_MAC = isKeyHotkey('ctrl+h')
const DELETE_CHAR_FORWARD_MAC = isKeyHotkey('ctrl+d')
const DELETE_CHAR_BACKWARD = e => DELETE_BACKWARD(e) || (IS_APPLE && DELETE_CHAR_BACKWARD_MAC(e))
const DELETE_CHAR_FORWARD = e => DELETE_FORWARD(e) || (IS_APPLE && DELETE_CHAR_FORWARD_MAC(e))
const DELETE_CHAR_BACKWARD = e =>
DELETE_BACKWARD(e) || (IS_APPLE && DELETE_CHAR_BACKWARD_MAC(e))
const DELETE_CHAR_FORWARD = e =>
DELETE_FORWARD(e) || (IS_APPLE && DELETE_CHAR_FORWARD_MAC(e))
const DELETE_LINE_BACKWARD_MAC = isKeyHotkey('cmd+backspace')
const DELETE_LINE_FORWARD_MAC = isKeyHotkey('ctrl+k')
@@ -45,8 +46,10 @@ const DELETE_WORD_BACKWARD_MAC = isKeyHotkey('option+backspace')
const DELETE_WORD_BACKWARD_PC = isKeyHotkey('ctrl+backspace')
const DELETE_WORD_FORWARD_MAC = isKeyHotkey('option+delete')
const DELETE_WORD_FORWARD_PC = isKeyHotkey('ctrl+delete')
const DELETE_WORD_BACKWARD = e => IS_APPLE ? DELETE_WORD_BACKWARD_MAC(e) : DELETE_WORD_BACKWARD_PC(e)
const DELETE_WORD_FORWARD = e => IS_APPLE ? DELETE_WORD_FORWARD_MAC(e) : DELETE_WORD_FORWARD_PC(e)
const DELETE_WORD_BACKWARD = e =>
IS_APPLE ? DELETE_WORD_BACKWARD_MAC(e) : DELETE_WORD_BACKWARD_PC(e)
const DELETE_WORD_FORWARD = e =>
IS_APPLE ? DELETE_WORD_FORWARD_MAC(e) : DELETE_WORD_FORWARD_PC(e)
const RIGHT_ARROW = isKeyHotkey('right')
const LEFT_ARROW = isKeyHotkey('left')
@@ -69,12 +72,12 @@ const EXTEND_LINE_FORWARD = e => IS_APPLE && EXTEND_LINE_FORWARD_MAC(e)
const UNDO = isKeyHotkey('mod+z')
const REDO_MAC = isKeyHotkey('mod+shift+z')
const REDO_PC = isKeyHotkey('mod+y')
const REDO = e => IS_APPLE ? REDO_MAC(e) : REDO_PC(e)
const REDO = e => (IS_APPLE ? REDO_MAC(e) : REDO_PC(e))
const TRANSPOSE_CHARACTER_MAC = isKeyHotkey('ctrl+t')
const TRANSPOSE_CHARACTER = e => IS_APPLE && TRANSPOSE_CHARACTER_MAC(e)
const CONTENTEDITABLE = e => (
const CONTENTEDITABLE = e =>
BOLD(e) ||
DELETE_CHAR_BACKWARD(e) ||
DELETE_CHAR_FORWARD(e) ||
@@ -87,16 +90,14 @@ const CONTENTEDITABLE = e => (
SPLIT_BLOCK(e) ||
TRANSPOSE_CHARACTER(e) ||
UNDO(e)
)
const COMPOSING = e => (
const COMPOSING = e =>
e.key == 'ArrowDown' ||
e.key == 'ArrowLeft' ||
e.key == 'ArrowRight' ||
e.key == 'ArrowUp' ||
e.key == 'Backspace' ||
e.key == 'Enter'
)
/**
* Export.

Some files were not shown because too many files have changed in this diff Show More